diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index ce512e4173b6a..63438eb0845c1 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -206,8 +206,8 @@ static void put_into_vehicle( Character &c, item_drop_reason reason, const std:: if( items.empty() ) { return; } - - const tripoint where = veh.global_part_pos3( part ); + vehicle_part &vp = veh.part( part ); + const tripoint where = veh.global_part_pos3( vp ); map &here = get_map(); const std::string ter_name = here.name( where ); int fallen_count = 0; @@ -224,7 +224,7 @@ static void put_into_vehicle( Character &c, item_drop_reason reason, const std:: it.charges = 0; } - if( veh.add_item( part, it ) ) { + if( veh.add_item( vp, it ) ) { into_vehicle_count += it.count(); } else { if( it.count_by_charges() ) { @@ -239,7 +239,7 @@ static void put_into_vehicle( Character &c, item_drop_reason reason, const std:: it.handle_pickup_ownership( c ); } - const std::string part_name = veh.part_info( part ).name(); + const std::string part_name = vp.info().name(); if( same_type( items ) ) { const item &it = items.front(); @@ -2736,12 +2736,15 @@ static requirement_check_result generic_multi_activity_check_requirement( you.activity_vehicle_part_index = 1; return requirement_check_result::SKIP_LOCATION; } - const vpart_info &vpinfo = veh->part_info( you.activity_vehicle_part_index ); requirement_data reqs; - if( reason == do_activity_reason::NEEDS_VEH_DECONST ) { - reqs = vpinfo.removal_requirements(); - } else if( reason == do_activity_reason::NEEDS_VEH_REPAIR ) { - reqs = vpinfo.repair_requirements(); + if( you.activity_vehicle_part_index >= 0 && + you.activity_vehicle_part_index < static_cast( veh->part_count() ) ) { + const vpart_info &vpi = veh->part( you.activity_vehicle_part_index ).info(); + if( reason == do_activity_reason::NEEDS_VEH_DECONST ) { + reqs = vpi.removal_requirements(); + } else if( reason == do_activity_reason::NEEDS_VEH_REPAIR ) { + reqs = vpi.repair_requirements(); + } } const std::string ran_str = random_string( 10 ); const requirement_id req_id( ran_str ); diff --git a/src/lightmap.cpp b/src/lightmap.cpp index e87e3fa8beb42..c11182f320ecf 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -1094,13 +1094,15 @@ void map::build_seen_cache( const tripoint &origin, const int target_z, int exte } } - for( int mirror : mirrors ) { - bool is_camera = veh->part_info( mirror ).has_flag( "CAMERA" ); + for( const int mirror : mirrors ) { + const vehicle_part &vp_mirror = veh->part( mirror ); + const vpart_info &vpi_mirror = vp_mirror.info(); + const bool is_camera = vpi_mirror.has_flag( "CAMERA" ); if( is_camera && cam_control < 0 ) { continue; // Player not at camera control, so cameras don't work } - const tripoint mirror_pos = veh->global_part_pos3( mirror ); + const tripoint mirror_pos = veh->global_part_pos3( vp_mirror ); // Determine how far the light has already traveled so mirrors // don't cheat the light distance falloff. @@ -1109,8 +1111,7 @@ void map::build_seen_cache( const tripoint &origin, const int target_z, int exte if( !is_camera ) { offsetDistance = penalty + rl_dist( origin, mirror_pos ); } else { - offsetDistance = 60 - veh->part_info( mirror ).bonus * - veh->part( mirror ).hp() / veh->part_info( mirror ).durability; + offsetDistance = 60 - vpi_mirror.bonus * vp_mirror.hp() / vpi_mirror.durability; mocache = &camera_cache; ( *mocache )[mirror_pos.x][mirror_pos.y] = LIGHT_TRANSPARENCY_OPEN_AIR; } diff --git a/src/map.cpp b/src/map.cpp index be6e68b5c3964..692842f61d363 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -741,7 +741,7 @@ vehicle *map::move_vehicle( vehicle &veh, const tripoint &dp, const tileray &fac // Shock damage, if the target part is a rotor treat as an aimed hit. // don't try to deal damage to invalid part (probably removed or destroyed) if( part_num != -1 ) { - if( veh.part_info( part_num ).rotor_diameter() > 0 ) { + if( veh.part( part_num ).info().rotor_diameter() > 0 ) { veh.damage( *this, part_num, coll_dmg, damage_bash, true ); } else { impulse += coll_dmg; @@ -905,18 +905,30 @@ float map::vehicle_vehicle_collision( vehicle &veh, vehicle &veh2, const veh_collision &c = collisions[0]; const bool vertical = veh.sm_pos.z != veh2.sm_pos.z; + if( c.part < 0 || c.part >= static_cast( veh.part_count() ) ) { + debugmsg( "invalid c.part %d", c.part ); + return 0.0f; + } + + if( c.target_part < 0 || c.target_part >= static_cast( veh2.part_count() ) ) { + debugmsg( "invalid c.target_part %d", c.target_part ); + return 0.0f; + } + vehicle_part &vp1 = veh.part( c.part ); + vehicle_part &vp2 = veh2.part( c.target_part ); + // Check whether avatar sees the collision, and log a message if so const avatar &you = get_avatar(); - const tripoint part1_pos = veh.global_part_pos3( c.part ); - const tripoint part2_pos = veh2.global_part_pos3( c.target_part ); + const tripoint part1_pos = veh.global_part_pos3( vp1 ); + const tripoint part2_pos = veh2.global_part_pos3( vp2 ); if( you.sees( part1_pos ) || you.sees( part2_pos ) ) { //~ %1$s: first vehicle name (without "the") //~ %2$s: first part name //~ %3$s: second vehicle display name (with "the") //~ %4$s: second part name add_msg( m_bad, _( "The %1$s's %2$s collides with %3$s's %4$s." ), - veh.name, veh.part_info( c.part ).name(), - veh2.disp_name(), veh2.part_info( c.target_part ).name() ); + veh.name, vp1.info().name(), + veh2.disp_name(), vp2.info().name() ); } // Used to calculate the epicenter of the collision. @@ -5224,20 +5236,22 @@ static bool process_map_items( map &here, item_stack &items, safe_reference( time_left ) + 1; //~ %1$d: Number of minutes remaining, %2$s: Name of the vehicle @@ -5276,7 +5288,7 @@ static void process_vehicle_items( vehicle &cur_veh, int part ) break; } } - if( autoclave_finished && !cur_veh.part_flag( part, VPFLAG_APPLIANCE ) ) { + if( autoclave_finished && !vpi.has_flag( VPFLAG_APPLIANCE ) ) { add_msg( _( "The autoclave in the %s has finished its cycle." ), cur_veh.name ); } else if( autoclave_finished ) { add_msg( _( "The autoclave has finished its cycle." ) ); @@ -5285,8 +5297,8 @@ static void process_vehicle_items( vehicle &cur_veh, int part ) const int recharge_part_idx = cur_veh.part_with_feature( part, VPFLAG_RECHARGE, true ); if( recharge_part_idx >= 0 ) { - vehicle_part recharge_part = cur_veh.part( recharge_part_idx ); - if( !recharge_part.removed && !recharge_part.is_broken() && recharge_part.enabled ) { + const vehicle_part &recharge_part = cur_veh.part( recharge_part_idx ); + if( !recharge_part.removed && recharge_part.enabled ) { for( item &n : cur_veh.get_items( part ) ) { if( !n.has_flag( flag_RECHARGE ) && !n.has_flag( flag_USE_UPS ) ) { continue; diff --git a/src/pathfinding.cpp b/src/pathfinding.cpp index a08ed126ec730..1d14f37d485b6 100644 --- a/src/pathfinding.cpp +++ b/src/pathfinding.cpp @@ -351,7 +351,8 @@ std::vector map::route( const tripoint &f, const tripoint &t, newg += 2 * hp / bash + 8 + 4; } else if( part >= 0 ) { - if( !doors || !veh->part_flag( part, VPFLAG_OPENABLE ) ) { + const vehicle_part &vp = veh->part( part ); + if( !doors || !vp.info().has_flag( VPFLAG_OPENABLE ) ) { // Won't be openable, don't try from other sides layer.state[index] = ASL_CLOSED; } diff --git a/src/veh_appliance.cpp b/src/veh_appliance.cpp index d919373f92102..a8dcc58f761c1 100644 --- a/src/veh_appliance.cpp +++ b/src/veh_appliance.cpp @@ -354,7 +354,7 @@ bool veh_app_interact::can_unplug() { vehicle_part_range vpr = veh->get_all_parts(); return std::any_of( vpr.begin(), vpr.end(), []( const vpart_reference & ref ) { - return ref.vehicle().part_flag( static_cast( ref.part_index() ), "POWER_TRANSFER" ); + return ref.info().has_flag( "POWER_TRANSFER" ); } ); } diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index ff54a6c9334f6..bac9b0e242a33 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -844,10 +844,11 @@ bool veh_interact::update_part_requirements() int dif_steering = 0; if( sel_vpart_info->has_flag( "STEERABLE" ) ) { std::set axles; - for( int &p : veh->steering ) { - if( !veh->part_flag( p, "TRACKED" ) ) { + for( const int p : veh->steering ) { + const vehicle_part &vp = veh->part( p ); + if( !vp.info().has_flag( "TRACKED" ) ) { // tracked parts don't contribute to axle complexity - axles.insert( veh->part( p ).mount.x ); + axles.insert( vp.mount.x ); } } @@ -3096,12 +3097,16 @@ void act_vehicle_unload_fuel( vehicle *veh ) void veh_interact::complete_vehicle( Character &you ) { if( you.activity.values.size() < 7 ) { - debugmsg( "Invalid activity ACT_VEHICLE values:%d", you.activity.values.size() ); + debugmsg( "ACT_VEHICLE values.size() is %d", you.activity.values.size() ); + return; + } + if( you.activity.str_values.empty() ) { + debugmsg( "ACT_VEHICLE str_values is empty" ); return; } map &here = get_map(); - optional_vpart_position vp = here.veh_at( here.getlocal( tripoint( you.activity.values[0], - you.activity.values[1], you.posz() ) ) ); + const tripoint_abs_ms act_pos( you.activity.values[0], you.activity.values[1], you.posz() ); + optional_vpart_position vp = here.veh_at( act_pos ); if( !vp ) { // so the vehicle could have lost some of its parts from other NPCS works // during this player/NPCs activity. @@ -3118,24 +3123,19 @@ void veh_interact::complete_vehicle( Character &you ) return; } } - vehicle *const veh = &vp->vehicle(); - point d( you.activity.values[4], you.activity.values[5] ); - int vehicle_part = you.activity.values[6]; - cata_assert( !you.activity.str_values.empty() ); + vehicle &veh = vp->vehicle(); + const point d( you.activity.values[4], you.activity.values[5] ); const vpart_id part_id( you.activity.str_values[0] ); - const vpart_info &vpinfo = part_id.obj(); // cmd = Install Repair reFill remOve Siphon Unload reName relAbel switch( static_cast( you.activity.index ) ) { case 'i': { const inventory &inv = you.crafting_inventory(); - const requirement_data reqs = vpinfo.install_requirements(); if( !reqs.can_make_with_inventory( inv, is_crafting_component ) ) { - add_msg( m_info, _( "You don't meet the requirements to install the %s." ), - vpinfo.name() ); + add_msg( m_info, _( "You don't meet the requirements to install the %s." ), vpinfo.name() ); break; } @@ -3152,8 +3152,7 @@ void veh_interact::complete_vehicle( Character &you ) } if( base.is_null() ) { if( !you.has_trait( trait_DEBUG_HS ) ) { - add_msg( m_info, _( "Could not find base part in requirements for %s." ), - vpinfo.name() ); + add_msg( m_info, _( "Could not find base part in requirements for %s." ), vpinfo.name() ); break; } else { base = item( vpinfo.base_item ); @@ -3165,47 +3164,46 @@ void veh_interact::complete_vehicle( Character &you ) } you.invalidate_crafting_inventory(); - cata_assert( you.activity.str_values.size() >= 2 ); - const int partnum = veh->install_part( d, part_id, std::move( base ) ); + const int partnum = veh.install_part( d, part_id, std::move( base ) ); if( partnum < 0 ) { debugmsg( "complete_vehicle install part fails dx=%d dy=%d id=%s", d.x, d.y, part_id.c_str() ); break; } - ::vehicle_part &vp_new = veh->part( partnum ); + ::vehicle_part &vp_new = veh.part( partnum ); if( vp_new.info().variants.size() > 1 ) { do_change_shape_menu( vp_new ); } // Need map-relative coordinates to compare to output of look_around. // Need to call coord_translate() directly since it's a new part. - const point q = veh->coord_translate( d ); + const point q = veh.coord_translate( d ); if( vpinfo.has_flag( VPFLAG_CONE_LIGHT ) || vpinfo.has_flag( VPFLAG_WIDE_CONE_LIGHT ) || vpinfo.has_flag( VPFLAG_HALF_CIRCLE_LIGHT ) ) { - orient_part( veh, vpinfo, partnum, q ); + orient_part( &veh, vpinfo, partnum, q ); } - const tripoint vehp = veh->global_pos3() + tripoint( q, 0 ); + const tripoint vehp = veh.global_pos3() + tripoint( q, 0 ); // TODO: allow boarding for non-players as well. Character *const pl = get_creature_tracker().creature_at( vehp ); if( vpinfo.has_flag( VPFLAG_BOARDABLE ) && pl ) { here.board_vehicle( vehp, pl ); } - you.add_msg_if_player( m_good, _( "You install a %1$s into the %2$s." ), - vp_new.name(), veh->name ); + you.add_msg_if_player( m_good, _( "You install a %1$s into the %2$s." ), vp_new.name(), veh.name ); for( const auto &sk : vpinfo.install_skills ) { you.practice( sk.first, veh_utils::calc_xp_gain( vpinfo, sk.first, you ) ); } - here.add_vehicle_to_cache( veh ); + here.add_vehicle_to_cache( &veh ); break; } case 'r': { - veh_utils::repair_part( *veh, veh->part( vehicle_part ), you ); + vehicle_part &vp = veh.part( you.activity.values[6] ); + veh_utils::repair_part( veh, vp, you ); break; } @@ -3216,25 +3214,23 @@ void veh_interact::complete_vehicle( Character &you ) } item_location &src = you.activity.targets.front(); - struct vehicle_part &pt = veh->part( vehicle_part ); - if( pt.is_tank() && src->is_container() && !src->empty() ) { + vehicle_part &vp = veh.part( you.activity.values[6] ); + if( vp.is_tank() && src->is_container() && !src->empty() ) { item_location contained( src, &src->only_item() ); - contained->charges -= pt.base.fill_with( *contained, contained->charges ); + contained->charges -= vp.base.fill_with( *contained, contained->charges ); contents_change_handler handler; handler.unseal_pocket_containing( contained ); - // if code goes here, we can assume "pt" has already refilled with "contained" something. - int remaining_ammo_capacity = pt.ammo_capacity( contained->ammo_type() ) - pt.ammo_remaining(); + // if code goes here, we can assume "vp" has already refilled with "contained" something. + int remaining_ammo_capacity = vp.ammo_capacity( contained->ammo_type() ) - vp.ammo_remaining(); if( remaining_ammo_capacity ) { //~ 1$s vehicle name, 2$s tank name - you.add_msg_if_player( m_good, _( "You refill the %1$s's %2$s." ), - veh->name, pt.name() ); + you.add_msg_if_player( m_good, _( "You refill the %1$s's %2$s." ), veh.name, vp.name() ); } else { //~ 1$s vehicle name, 2$s tank name - you.add_msg_if_player( m_good, _( "You completely refill the %1$s's %2$s." ), - veh->name, pt.name() ); + you.add_msg_if_player( m_good, _( "You completely refill the %1$s's %2$s." ), veh.name, vp.name() ); } if( contained->charges == 0 ) { @@ -3244,16 +3240,15 @@ void veh_interact::complete_vehicle( Character &you ) } handler.handle_by( you ); - } else if( pt.is_fuel_store() ) { + } else if( vp.is_fuel_store() ) { contents_change_handler handler; handler.unseal_pocket_containing( src ); int qty = src->charges; - pt.base.reload( you, std::move( src ), qty ); + vp.base.reload( you, std::move( src ), qty ); //~ 1$s vehicle name, 2$s reactor name - you.add_msg_if_player( m_good, _( "You refuel the %1$s's %2$s." ), - veh->name, pt.name() ); + you.add_msg_if_player( m_good, _( "You refuel the %1$s's %2$s." ), veh.name, vp.name() ); handler.handle_by( you ); } else { @@ -3261,19 +3256,16 @@ void veh_interact::complete_vehicle( Character &you ) break; } - veh->invalidate_mass(); + veh.invalidate_mass(); break; } case 'O': // 'O' = remove appliance case 'o': { - const bool appliance_removal = static_cast( you.activity.index ) == 'O'; - const bool wall_wire_removal = appliance_removal && - veh->part( vehicle_part ).info().id == vpart_ap_wall_wiring; - const inventory &inv = you.crafting_inventory(); - if( vehicle_part >= veh->part_count() ) { - vehicle_part = veh->get_next_shifted_index( vehicle_part, you ); - if( vehicle_part == -1 ) { + int vp_index = you.activity.values[6]; + if( vp_index >= veh.part_count() ) { + vp_index = veh.get_next_shifted_index( vp_index, you ); + if( vp_index == -1 ) { you.add_msg_if_player( m_info, //~ 1$s is the vehicle part name _( "The %1$s has already been removed by someone else." ), @@ -3281,11 +3273,17 @@ void veh_interact::complete_vehicle( Character &you ) return; } } - const requirement_data reqs = vpinfo.removal_requirements(); + const vehicle_part &vp = veh.part( vp_index ); + const vpart_info &vpi = vp.info(); + const bool appliance_removal = static_cast( you.activity.index ) == 'O'; + const bool wall_wire_removal = appliance_removal && vpi.id == vpart_ap_wall_wiring; + const bool broken = vp.is_broken(); + const bool smash_remove = vpi.has_flag( "SMASH_REMOVE" ); + const inventory &inv = you.crafting_inventory(); + const requirement_data &reqs = vpi.removal_requirements(); if( !reqs.can_make_with_inventory( inv, is_crafting_component ) ) { //~ 1$s is the vehicle part name - add_msg( m_info, _( "You don't meet the requirements to remove the %1$s." ), - vpinfo.name() ); + add_msg( m_info, _( "You don't meet the requirements to remove the %1$s." ), vpi.name() ); break; } for( const auto &e : reqs.get_components() ) { @@ -3301,70 +3299,64 @@ void veh_interact::complete_vehicle( Character &you ) std::list resulting_items; // First we get all the contents of the part - vehicle_stack contents = veh->get_items( vehicle_part ); + vehicle_stack contents = veh.get_items( vp_index ); resulting_items.insert( resulting_items.end(), contents.begin(), contents.end() ); contents.clear(); // Power cables must remove parts from the target vehicle, too. - if( veh->part_flag( vehicle_part, "POWER_TRANSFER" ) ) { - veh->remove_remote_part( vehicle_part ); + if( vpi.has_flag( "POWER_TRANSFER" ) ) { + veh.remove_remote_part( vp_index ); } - bool broken = veh->part( vehicle_part ).is_broken(); - bool smash_remove = veh->part( vehicle_part ).info().has_flag( "SMASH_REMOVE" ); - if( broken ) { - you.add_msg_if_player( _( "You remove the broken %1$s from the %2$s." ), - veh->part( vehicle_part ).name(), veh->name ); + you.add_msg_if_player( _( "You remove the broken %1$s from the %2$s." ), vp.name(), veh.name ); } else if( smash_remove ) { you.add_msg_if_player( _( "You smash the %1$s to bits, removing it from the %2$s." ), - veh->part( vehicle_part ).name(), veh->name ); + vp.name(), veh.name ); } else { - you.add_msg_if_player( _( "You remove the %1$s from the %2$s." ), - veh->part( vehicle_part ).name(), veh->name ); + you.add_msg_if_player( _( "You remove the %1$s from the %2$s." ), vp.name(), veh.name ); } if( wall_wire_removal ) { - veh->part( vehicle_part ).properties_to_item(); - } else if( veh->part_flag( vehicle_part, "TOW_CABLE" ) ) { - veh->invalidate_towing( true, &you ); + vp.properties_to_item(); // what's going on here? this line isn't doing anything... + } else if( vpi.has_flag( "TOW_CABLE" ) ) { + veh.invalidate_towing( true, &you ); } else if( broken ) { - item_group::ItemList pieces = veh->part( vehicle_part ).pieces_for_broken_part(); + item_group::ItemList pieces = vp.pieces_for_broken_part(); resulting_items.insert( resulting_items.end(), pieces.begin(), pieces.end() ); } else { if( smash_remove ) { - item_group::ItemList pieces = veh->part( vehicle_part ).pieces_for_broken_part(); + item_group::ItemList pieces = vp.pieces_for_broken_part(); resulting_items.insert( resulting_items.end(), pieces.begin(), pieces.end() ); } else { - resulting_items.push_back( veh->part( vehicle_part ).properties_to_item() ); + resulting_items.push_back( vp.properties_to_item() ); } - for( const std::pair &sk : vpinfo.install_skills ) { + for( const std::pair &sk : vpi.install_skills ) { // removal is half as educational as installation - you.practice( sk.first, veh_utils::calc_xp_gain( vpinfo, sk.first, you ) / 2 ); + you.practice( sk.first, veh_utils::calc_xp_gain( vpi, sk.first, you ) / 2 ); } } // Remove any leftover power cords from the appliance - if( appliance_removal && veh->part_count() >= 2 ) { - veh->shed_loose_parts(); - veh->part_removal_cleanup(); + if( appliance_removal && veh.part_count() >= 2 ) { + veh.shed_loose_parts(); + veh.part_removal_cleanup(); //always stop after removing an appliance you.activity.set_to_null(); } - if( veh->part_count_real() <= 1 ) { - you.add_msg_if_player( _( "You completely dismantle the %s." ), veh->name ); + if( veh.part_count_real() <= 1 ) { + you.add_msg_if_player( _( "You completely dismantle the %s." ), veh.name ); you.activity.set_to_null(); // destroy vehicle clears the cache - here.destroy_vehicle( veh ); + here.destroy_vehicle( &veh ); } else { - point mount = veh->part( vehicle_part ).mount; - const tripoint part_pos = veh->global_part_pos3( vehicle_part ); - veh->remove_part( vehicle_part ); + const tripoint part_pos = veh.global_part_pos3( vp ); + veh.remove_part( vp_index ); // part_removal_cleanup calls refresh, so parts_at_relative is valid - veh->part_removal_cleanup(); - if( veh->parts_at_relative( mount, true ).empty() ) { - get_map().clear_vehicle_point_from_cache( veh, part_pos ); + veh.part_removal_cleanup(); + if( veh.parts_at_relative( vp.mount, true ).empty() ) { + get_map().clear_vehicle_point_from_cache( &veh, part_pos ); } } // This will be part of an NPC "job" where they need to clean up the activity @@ -3384,7 +3376,7 @@ void veh_interact::complete_vehicle( Character &you ) // Unplug action just sheds loose connections, // assuming vehicle::shed_loose_parts was already called so that // the removed parts have had time to be processed - you.add_msg_if_player( _( "You disconnect the %s's power connection." ), veh->name ); + you.add_msg_if_player( _( "You disconnect the %s's power connection." ), veh.name ); break; } } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 1c40c2c52bd25..6b6808b2db94c 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -174,9 +174,11 @@ void vehicle_stack::insert( const item &newitem ) units::volume vehicle_stack::max_volume() const { - if( myorigin->part_flag( part_num, "CARGO" ) && !myorigin->part( part_num ).is_broken() ) { + const vehicle_part &vp = myorigin->part( part_num ); + const vpart_info &vpi = vp.info(); + if( vpi.has_flag( VPFLAG_CARGO ) && !vp.is_broken() ) { // Set max volume for vehicle cargo to prevent integer overflow - return std::min( myorigin->part( part_num ).info().size, 10000_liter ); + return std::min( vpi.size, 10000_liter ); } return 0_ml; } @@ -829,8 +831,9 @@ void vehicle::smash( map &m, float hp_percent_loss_min, float hp_percent_loss_ma std::vector parts_in_square = parts_at_relative( part.mount, true ); int structures_found = 0; - for( int &square_part_index : parts_in_square ) { - if( part_info( square_part_index ).location == part_location_structure ) { + for( const int square_part_index : parts_in_square ) { + const vpart_info &vpi = parts[square_part_index].info(); + if( vpi.location == part_location_structure ) { structures_found++; } } @@ -872,8 +875,8 @@ void vehicle::smash( map &m, float hp_percent_loss_min, float hp_percent_loss_ma if( p == other_p ) { continue; } - const vpart_info &p_info = part_info( p ); - const vpart_info &other_p_info = part_info( other_p ); + const vpart_info &p_info = parts[p].info(); + const vpart_info &other_p_info = parts[other_p].info(); if( p_info.id == other_p_info.id || ( !p_info.location.empty() && p_info.location == other_p_info.location ) ) { @@ -996,16 +999,15 @@ bool vehicle::is_alternator_on( const vehicle_part &vp ) const bool vehicle::has_security_working() const { - bool found_security = false; if( fuel_left( fuel_type_battery ) > 0 ) { - for( int s : speciality ) { - if( part_flag( s, "SECURITY" ) && parts[ s ].is_available() ) { - found_security = true; - break; + for( const int s : speciality ) { + const vehicle_part &vp = part( s ); + if( vp.info().has_flag( "SECURITY" ) && vp.is_available() ) { + return true; } } } - return found_security; + return false; } void vehicle::unlock() @@ -1032,16 +1034,6 @@ void vehicle::backfire( const vehicle_part &vp ) const string_format( text, vp.name() ), true, "vehicle", "engine_backfire" ); } -const vpart_info &vehicle::part_info( int index, bool include_removed ) const -{ - if( index < static_cast( parts.size() ) ) { - if( !parts[index].removed || include_removed ) { - return parts[index].info(); - } - } - return vpart_id::NULL_ID().obj(); -} - // engines & alternators all have power. // engines provide, whilst alternators consume. units::power vehicle::part_vpower_w( const vehicle_part &vp, const bool at_full_hp ) const @@ -1270,10 +1262,11 @@ bool vehicle::can_unmount( const int p, std::string &reason ) const const std::vector parts_here = parts_at_relative( vp_to_remove.mount, false ); // make sure there are no parts which require flags from this part - for( const int &elem : parts_here ) { - for( const std::string &flag : part_info( elem ).get_flags() ) { + for( const int elem : parts_here ) { + const vehicle_part &vp_here = parts[elem]; + for( const std::string &flag : vp_here.info().get_flags() ) { if( vp_to_remove.info().has_flag( json_flag::get( flag ).requires_flag() ) ) { - reason = string_format( _( "Remove the attached %s first." ), part_info( elem ).name() ); + reason = string_format( _( "Remove the attached %s first." ), vp_here.name() ); return false; } } @@ -1300,8 +1293,9 @@ bool vehicle::can_unmount( const int p, std::string &reason ) const } // structure parts can only be removed when no non-structure parts are on tile - for( const int &elem : parts_here ) { - if( part_info( elem ).location != part_location_structure ) { + for( const int elem : parts_here ) { + const vehicle_part &vp_here = parts[elem]; + if( vp_here.info().location != part_location_structure ) { reason = _( "Remove all other attached parts first." ); return false; } @@ -1838,7 +1832,7 @@ bool vehicle::remove_part( const int p, RemovePartHandler &handler ) if( !handler.get_map_ref().inbounds( part_loc ) ) { debugmsg( "vehicle::remove_part part '%s' at mount %s bub pos %s is out of map " "bounds on vehicle '%s'(%s), vehicle::pos is %s, vehicle::sm_pos is %s", - vp.info().id.str(), vp.mount.to_string(), part_loc.to_string(), + vpi.id.str(), vp.mount.to_string(), part_loc.to_string(), name, type.str(), pos.to_string(), sm_pos.to_string() ); } @@ -1867,11 +1861,11 @@ bool vehicle::remove_part( const int p, RemovePartHandler &handler ) // if a windshield is removed (usually destroyed) also remove curtains // attached to it. - if( remove_dependent_part( "WINDOW", "CURTAIN" ) || part_flag( p, VPFLAG_OPAQUE ) ) { + if( remove_dependent_part( "WINDOW", "CURTAIN" ) || vpi.has_flag( VPFLAG_OPAQUE ) ) { handler.set_transparency_cache_dirty( sm_pos.z ); } - if( part_flag( p, VPFLAG_ROOF ) || part_flag( p, VPFLAG_OPAQUE ) ) { + if( vpi.has_flag( VPFLAG_ROOF ) || vpi.has_flag( VPFLAG_OPAQUE ) ) { handler.set_floor_cache_dirty( sm_pos.z + 1 ); } @@ -1880,20 +1874,20 @@ bool vehicle::remove_part( const int p, RemovePartHandler &handler ) remove_dependent_part( "HANDHELD_BATTERY_MOUNT", "NEEDS_HANDHELD_BATTERY_MOUNT" ); // Release any animal held by the part - if( parts[p].has_flag( vp_flag::animal_flag ) ) { - item base = parts[p].get_base(); + if( vp.has_flag( vp_flag::animal_flag ) ) { + item base = vp.get_base(); handler.spawn_animal_from_part( base, part_loc ); - parts[p].set_base( std::move( base ) ); - parts[p].remove_flag( vp_flag::animal_flag ); + vp.set_base( std::move( base ) ); + vp.remove_flag( vp_flag::animal_flag ); } // Update current engine configuration if needed - if( part_flag( p, "ENGINE" ) && engines.size() > 1 ) { + if( vpi.has_flag( VPFLAG_ENGINE ) && engines.size() > 1 ) { bool any_engine_on = false; for( const int e : engines ) { - const vehicle_part &vp = parts[e]; - if( e != p && vp.enabled ) { + const vehicle_part &vp_engine = parts[e]; + if( &vp != &vp_engine && vp_engine.enabled ) { any_engine_on = true; break; } @@ -1901,31 +1895,31 @@ bool vehicle::remove_part( const int p, RemovePartHandler &handler ) if( !any_engine_on ) { engine_on = false; - for( const int p : engines ) { - vehicle_part &vp = parts[p]; - vp.enabled = true; + for( const int e : engines ) { + vehicle_part &vp_engine = parts[e]; + vp_engine.enabled = true; } } } //Remove loot zone if Cargo was removed. - const auto lz_iter = loot_zones.find( parts[p].mount ); + const auto lz_iter = loot_zones.find( vp.mount ); const bool no_zone = lz_iter != loot_zones.end(); - if( no_zone && part_flag( p, "CARGO" ) ) { + if( no_zone && vpi.has_flag( VPFLAG_CARGO ) ) { // Using the key here (instead of the iterator) will remove all zones on // this mount points regardless of how many there are - loot_zones.erase( parts[p].mount ); + loot_zones.erase( vp.mount ); zones_dirty = true; } - parts[p].removed = true; - if( parts[p].has_fake && parts[p].fake_part_at < static_cast( parts.size() ) ) { - parts[parts[p].fake_part_at].removed = true; + vp.removed = true; + if( vp.has_fake && vp.fake_part_at < static_cast( parts.size() ) ) { + parts[vp.fake_part_at].removed = true; } handler.removed( *this, p ); - const point &vp_mount = parts[p].mount; + const point &vp_mount = vp.mount; const auto iter = labels.find( label( vp_mount ) ); if( iter != labels.end() && parts_at_relative( vp_mount, false ).empty() ) { labels.erase( iter ); @@ -2167,11 +2161,12 @@ bool vehicle::find_and_split_vehicles( map &here, std::set exclude ) const point dp = parts[test_part].mount + offset; std::vector all_neighbor_parts = parts_at_relative( dp, true ); int neighbor_struct_part = -1; - for( int p : all_neighbor_parts ) { - if( parts[p].removed ) { + for( const int p : all_neighbor_parts ) { + const vehicle_part &vp_neighbor = parts[p]; + if( vp_neighbor.removed ) { continue; } - if( part_info( p ).location == part_location_structure ) { + if( vp_neighbor.info().location == part_location_structure ) { neighbor_struct_part = p; break; } @@ -2244,9 +2239,8 @@ bool vehicle::split_vehicles( map &here, // make sure the split_part0 is a legal 0,0 part if( split_parts.size() > 1 ) { for( size_t sp = 0; sp < split_parts.size(); sp++ ) { - int p = split_parts[ sp ]; - if( part_info( p ).location == part_location_structure && - !part_info( p ).has_flag( "PROTRUSION" ) ) { + const vpart_info &vpi_split = parts[split_parts[sp]].info(); + if( vpi_split.location == part_location_structure && !vpi_split.has_flag( "PROTRUSION" ) ) { split_part0 = sp; break; } @@ -2277,8 +2271,10 @@ bool vehicle::split_vehicles( map &here, std::vector passengers; for( size_t new_part = 0; new_part < split_parts.size(); new_part++ ) { - int mov_part = split_parts[ new_part ]; - point cur_mount = parts[ mov_part ].mount; + const int mov_part = split_parts[ new_part ]; + vehicle_part &vp_mov = part( mov_part ); + const vpart_info &vpi_mov = vp_mov.info(); + point cur_mount = vp_mov.mount; point new_mount = cur_mount; if( !split_mounts.empty() ) { new_mount = split_mounts[ new_part ]; @@ -2288,14 +2284,14 @@ bool vehicle::split_vehicles( map &here, Character *passenger = nullptr; // Unboard any entities standing on any transferred part - if( part_flag( mov_part, "BOARDABLE" ) ) { + if( vpi_mov.has_flag( VPFLAG_BOARDABLE ) ) { passenger = get_passenger( mov_part ); if( passenger ) { passengers.push_back( passenger ); } } // if this part is a towing part, transfer the tow_data to the new vehicle. - if( part_flag( mov_part, "TOW_CABLE" ) ) { + if( vpi_mov.has_flag( "TOW_CABLE" ) ) { if( is_towed() ) { tow_data.get_towed_by()->tow_data.set_towing( tow_data.get_towed_by(), new_vehicle ); tow_data.clear_towing(); @@ -2305,7 +2301,7 @@ bool vehicle::split_vehicles( map &here, } } // transfer the vehicle_part to the new vehicle - new_vehicle->parts.emplace_back( parts[ mov_part ] ); + new_vehicle->parts.emplace_back( vp_mov ); new_vehicle->parts.back().mount = new_mount; // remove labels associated with the mov_part @@ -2331,11 +2327,11 @@ bool vehicle::split_vehicles( map &here, // remove the passenger from the old vehicle if( passenger ) { - parts[ mov_part ].remove_flag( vp_flag::passenger_flag ); - parts[ mov_part ].passenger_id = character_id(); + vp_mov.remove_flag( vp_flag::passenger_flag ); + vp_mov.passenger_id = character_id(); } // indicate the part needs to be removed from the old vehicle - parts[ mov_part].removed = true; + vp_mov.removed = true; } // We want to create the vehicle zones after we've setup the parts @@ -2729,11 +2725,10 @@ int vehicle::next_part_to_close( int p, bool outside ) const for( std::vector::reverse_iterator part_it = parts_here.rbegin(); part_it != parts_here.rend(); ++part_it ) { - - if( part_flag( *part_it, VPFLAG_OPENABLE ) - && parts[ *part_it ].is_available() - && parts[*part_it].open == 1 - && ( !outside || !part_flag( *part_it, "OPENCLOSE_INSIDE" ) ) ) { + const vehicle_part &vp = part( *part_it ); + const vpart_info &vpi = vp.info(); + if( vpi.has_flag( VPFLAG_OPENABLE ) && vp.is_available() && vp.open == 1 + && ( !outside || !vpi.has_flag( "OPENCLOSE_INSIDE" ) ) ) { return *part_it; } } @@ -2742,15 +2737,15 @@ int vehicle::next_part_to_close( int p, bool outside ) const int vehicle::next_part_to_open( int p, bool outside ) const { - - const std::vector parts_here = parts_at_relative( parts[p].mount, true, true ); const bool has_lock = part_has_lock( p ); // We want forwards, since we open the outermost thing first (curtains), and then the innermost thing (door) - for( const int &elem : parts_here ) { - if( part_flag( elem, VPFLAG_OPENABLE ) && parts[ elem ].is_available() && parts[elem].open == 0 && - !( part( elem ).locked && has_lock ) && - ( !outside || !part_flag( elem, "OPENCLOSE_INSIDE" ) ) ) { + for( const int elem : parts_at_relative( parts[p].mount, true, true ) ) { + const vehicle_part &vp = part( elem ); + const vpart_info &vpi = vp.info(); + if( vpi.has_flag( VPFLAG_OPENABLE ) && vp.is_available() && vp.open == 0 && + !( vp.locked && has_lock ) && + ( !outside || !vpi.has_flag( "OPENCLOSE_INSIDE" ) ) ) { return elem; } } @@ -2759,9 +2754,9 @@ int vehicle::next_part_to_open( int p, bool outside ) const bool vehicle::part_has_lock( int p ) const { - const std::vector parts_here = parts_at_relative( parts[p].mount, true, true ); - for( const int &elem : parts_here ) { - if( part_flag( elem, "DOOR_LOCKING" ) && parts[elem].is_available() ) { + for( const int elem : parts_at_relative( parts[p].mount, true, true ) ) { + const vehicle_part &vp = parts[elem]; + if( vp.info().has_flag( "DOOR_LOCKING" ) && vp.is_available() ) { return true; } } @@ -2770,17 +2765,17 @@ bool vehicle::part_has_lock( int p ) const int vehicle::next_part_to_lock( int p, bool outside ) const { - std::vector parts_here = parts_at_relative( parts[p].mount, true, true ); if( !part_has_lock( p ) ) { return -1; } + std::vector parts_here = parts_at_relative( parts[p].mount, true, true ); // We want reverse, since we lock the innermost thing first (door), and then the outermost thing for( std::vector::reverse_iterator part_it = parts_here.rbegin(); part_it != parts_here.rend(); ++part_it ) { - - if( part_flag( *part_it, "LOCKABLE_DOOR" ) && parts[*part_it].is_available() && - parts[*part_it].open == 0 && !part( *part_it ).locked && !outside ) { + const vehicle_part &vp = part( *part_it ); + if( vp.info().has_flag( "LOCKABLE_DOOR" ) && vp.is_available() && + vp.open == 0 && !vp.locked && !outside ) { return *part_it; } } @@ -2789,13 +2784,12 @@ int vehicle::next_part_to_lock( int p, bool outside ) const int vehicle::next_part_to_unlock( int p, bool outside ) const { - const std::vector parts_here = parts_at_relative( parts[p].mount, true, true ); if( !part_has_lock( p ) ) { return -1; } - for( const int &elem : parts_here ) { - if( part_flag( elem, "LOCKABLE_DOOR" ) && parts[elem].is_available() && - part( elem ).locked && !outside ) { + for( const int elem : parts_at_relative( parts[p].mount, true, true ) ) { + const vehicle_part &vp = part( elem ); + if( vp.info().has_flag( "LOCKABLE_DOOR" ) && vp.is_available() && vp.locked && !outside ) { return elem; } } @@ -2930,20 +2924,23 @@ std::vector> vehicle::find_lines_of_parts( // start from the real part, otherwise it fails in certain orientations part = get_non_fake_part( part ); - vpart_id part_id = part_info( part ).id; + const vehicle_part &vp = parts[part]; + const vpart_id &part_id = vp.info().id; + const point target = vp.mount; // create vectors of parts on the same X or Y axis - point target = parts[ part ].mount; - for( const vpart_reference &vp : possible_parts ) { - if( vp.part().is_unavailable() || - !vp.has_feature( "MULTISQUARE" ) || - vp.info().id != part_id ) { + for( const vpart_reference &vpr : possible_parts ) { + const vehicle_part &vp_other = vpr.part(); + const vpart_info &vpi_other = vp_other.info(); + if( vp_other.is_unavailable() || + !vpi_other.has_flag( "MULTISQUARE" ) || + vpi_other.id != part_id ) { continue; } - if( vp.mount().x == target.x ) { - x_parts.push_back( vp.part_index() ); + if( vp_other.mount.x == target.x ) { + x_parts.push_back( vpr.part_index() ); } - if( vp.mount().y == target.y ) { - y_parts.push_back( vp.part_index() ); + if( vp_other.mount.y == target.y ) { + y_parts.push_back( vpr.part_index() ); } } @@ -3006,24 +3003,6 @@ std::vector> vehicle::find_lines_of_parts( return ret_parts; } -bool vehicle::part_flag( int part, const std::string &flag ) const -{ - if( part < 0 || part >= static_cast( parts.size() ) || parts[part].removed ) { - return false; - } else { - return part_info( part ).has_flag( flag ); - } -} - -bool vehicle::part_flag( int part, const vpart_bitflags flag ) const -{ - if( part < 0 || part >= static_cast( parts.size() ) || parts[part].removed ) { - return false; - } else { - return part_info( part ).has_flag( flag ); - } -} - int vehicle::part_at( const point &dp ) const { for( const vpart_reference &vp : get_all_parts() ) { @@ -3102,13 +3081,12 @@ int vehicle::part_displayed_at( const point &dp, bool include_fake, bool below_r int vehicle::roof_at_part( const int part ) const { - std::vector parts_in_square = parts_at_relative( parts[part].mount, true ); - for( const int p : parts_in_square ) { - if( part_info( p ).location == "on_roof" || part_flag( p, "ROOF" ) ) { + for( const int p : parts_at_relative( parts[part].mount, true ) ) { + const vehicle_part &vp = parts[p]; + if( vp.info().location == "on_roof" || vp.info().has_flag( VPFLAG_ROOF ) ) { return p; } } - return -1; } @@ -4399,7 +4377,7 @@ bool vehicle::sufficient_wheel_config() const return false; } else if( wheelcache.size() == 1 ) { //Has to be a stable wheel, and one wheel can only support a 1-3 tile vehicle - if( !part_info( wheelcache.front() ).has_flag( "STABLE" ) || + if( !part( wheelcache[0] ).info().has_flag( "STABLE" ) || all_parts_at_location( part_location_structure ).size() > 3 ) { return false; } @@ -5942,7 +5920,7 @@ void vehicle::refresh( const bool remove_fakes ) struct sort_veh_part_vector { vehicle *veh; inline bool operator()( const int p1, const int p2 ) const { - return veh->part_info( p1 ).list_order < veh->part_info( p2 ).list_order; + return veh->part( p1 ).info().list_order < veh->part( p2 ).info().list_order; } } svpv = { this }; @@ -6664,16 +6642,13 @@ bool vehicle::no_towing_slack() const void vehicle::remove_remote_part( int part_num ) { vehicle *veh = find_vehicle( parts[part_num].target.second ); - // If the target vehicle is still there, ask it to remove its part if( veh != nullptr ) { const tripoint local_abs = get_map().getabs( global_part_pos3( part_num ) ); - for( size_t j = 0; j < veh->loose_parts.size(); j++ ) { - int remote_partnum = veh->loose_parts[j]; - const vehicle_part *remote_part = &veh->parts[remote_partnum]; - - if( veh->part_flag( remote_partnum, "POWER_TRANSFER" ) && remote_part->target.first == local_abs ) { + const int remote_partnum = veh->loose_parts[j]; + const vehicle_part &vp_remote = veh->parts[remote_partnum]; + if( vp_remote.info().has_flag( "POWER_TRANSFER" ) && vp_remote.target.first == local_abs ) { veh->remove_part( remote_partnum ); return; } @@ -6687,40 +6662,42 @@ void vehicle::shed_loose_parts( const tripoint_bub_ms *src, const tripoint_bub_m // remove_part rebuilds the loose_parts vector, so iterate over a copy to preserve // power transfer lines that still have some slack to them std::vector lp = loose_parts; - for( const int &elem : lp ) { + for( const int elem : lp ) { + vehicle_part &vp_loose = part( elem ); if( std::find( loose_parts.begin(), loose_parts.end(), elem ) == loose_parts.end() ) { // part was removed elsewhere continue; } - if( part_flag( elem, "POWER_TRANSFER" ) ) { - int distance = rl_dist( here.getabs( bub_part_pos( parts[elem] ) ), parts[elem].target.second ); - int max_dist = parts[elem].get_base().type->maximum_charges(); + if( vp_loose.info().has_flag( "POWER_TRANSFER" ) ) { + int distance = rl_dist( here.getabs( bub_part_pos( vp_loose ) ), vp_loose.target.second ); + int max_dist = vp_loose.get_base().type->maximum_charges(); if( src && ( max_dist - distance ) > 0 ) { // power line still has some slack to it, so keep it attached for now - vehicle *veh = find_vehicle( parts[elem].target.second ); + vehicle *veh = find_vehicle( vp_loose.target.second ); if( veh != nullptr ) { for( int remote_lp : veh->loose_parts ) { - if( veh->part_flag( remote_lp, "POWER_TRANSFER" ) && - veh->parts[remote_lp].target.first == here.getabs( *src ) ) { + vehicle_part &vp_remote = veh->part( remote_lp ); + if( vp_remote.info().has_flag( "POWER_TRANSFER" ) && + vp_remote.target.first == here.getabs( *src ) ) { // update remote part's target to new position - veh->parts[remote_lp].target.first = here.getabs( dst ? *dst : bub_part_pos( elem ) ); - veh->parts[remote_lp].target.second = veh->parts[remote_lp].target.first; + vp_remote.target.first = here.getabs( dst ? *dst : bub_part_pos( vp_loose ) ); + vp_remote.target.second = vp_remote.target.first; } } } continue; } - add_msg_if_player_sees( global_part_pos3( parts[elem] ), m_warning, + add_msg_if_player_sees( global_part_pos3( vp_loose ), m_warning, _( "The %s's power connection was detached!" ), name ); remove_remote_part( elem ); } - if( part_flag( elem, "TOW_CABLE" ) ) { + if( vp_loose.info().has_flag( "TOW_CABLE" ) ) { invalidate_towing( true ); continue; } - const item drop = part( elem ).properties_to_item(); + const item drop = vp_loose.properties_to_item(); if( !magic && !drop.has_flag( flag_AUTO_DELETE_CABLE ) ) { - here.add_item_or_charges( global_part_pos3( part( elem ) ), drop ); + here.add_item_or_charges( global_part_pos3( vp_loose ), drop ); } remove_part( elem ); @@ -6834,15 +6811,16 @@ int vehicle::damage( map &here, int p, int dmg, const damage_type_id &type, bool int target_part = vp_initial.info().rotor_diameter() ? p : random_entry( parts_here ); // Parts integrated inside a door or board are protected by boards and closed doors - if( part_flag( target_part, "BOARD_INTERNAL" ) ) { + if( part( target_part ).info().has_flag( "BOARD_INTERNAL" ) ) { int strongest_board_durability = INT_MIN; for( const int part : parts_here ) { - if( part_flag( part, "FULL_BOARD" ) || - part_flag( part, "HALF_BOARD" ) || - ( part_flag( part, "OPENABLE" ) && !parts[part].open ) ) { - if( part_info( part ).durability > strongest_board_durability ) { + const vehicle_part &vp_here = parts[part]; + const vpart_info &vpi_here = vp_here.info(); + if( vpi_here.has_flag( "FULL_BOARD" ) || vpi_here.has_flag( "HALF_BOARD" ) || + ( vpi_here.has_flag( "OPENABLE" ) && !vp_here.open ) ) { + if( vpi_here.durability > strongest_board_durability ) { target_part = part; - strongest_board_durability = part_info( part ).durability; + strongest_board_durability = vpi_here.durability; } } } @@ -6969,13 +6947,15 @@ bool vehicle::shift_if_needed( map &here ) int vehicle::break_off( map &here, int p, int dmg ) { + const vehicle_part &vp = parts[p]; + const vpart_info &vpi = vp.info(); /* Already-destroyed part - chance it could be torn off into pieces. * Chance increases with damage, and decreases with part max durability * (so lights, etc are easily removed; frames and plating not so much) */ - if( rng( 0, part_info( p ).durability / 10 ) >= dmg ) { + if( rng( 0, vpi.durability / 10 ) >= dmg ) { return dmg; } - const tripoint pos = global_part_pos3( p ); + const tripoint pos = global_part_pos3( vp ); const auto scatter_parts = [&]( const vehicle_part & pt ) { for( const item &piece : pt.pieces_for_broken_part() ) { // inside the loop, so each piece goes to a different place @@ -6995,80 +6975,75 @@ int vehicle::break_off( map &here, int p, int dmg ) } else { handler_ptr = std::make_unique( here ); } - if( part_info( p ).location == part_location_structure ) { + if( vpi.location == part_location_structure ) { // For structural parts, remove other parts first - std::vector parts_in_square = parts_at_relative( parts[p].mount, true ); + std::vector parts_in_square = parts_at_relative( vp.mount, true ); for( int index = parts_in_square.size() - 1; index >= 0; index-- ) { // Ignore the frame being destroyed if( parts_in_square[index] == p ) { continue; } + vehicle_part &vp_here = parts[parts_in_square[index]]; + const vpart_info &vpi_here = vp_here.info(); - if( part_flag( parts_in_square[ index ], "TOW_CABLE" ) ) { + if( vpi_here.has_flag( "TOW_CABLE" ) ) { // Tow cables - remove it in one piece, remove remote part, and remove towing data - add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, - parts[ parts_in_square[ index ] ].name() ); + add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, vp_here.name() ); invalidate_towing( true ); - } else if( part_flag( parts_in_square[ index ], "POWER_TRANSFER" ) ) { + } else if( vpi_here.has_flag( "POWER_TRANSFER" ) ) { // Electrical cables - remove it in one piece and remove remote part - add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, - parts[ parts_in_square[ index ] ].name() ); - item part_as_item = parts[parts_in_square[index]].properties_to_item(); - here.add_item_or_charges( pos, part_as_item ); + add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, vp_here.name() ); + here.add_item_or_charges( pos, vp_here.properties_to_item() ); remove_remote_part( parts_in_square[ index ] ); - } else if( parts[ parts_in_square[ index ] ].is_broken() ) { + } else if( vp_here.is_broken() ) { // Tearing off a broken part - break it up - add_msg_if_player_sees( pos, m_bad, _( "The %s's %s breaks into pieces!" ), name, - parts[ parts_in_square[ index ] ].name() ); - scatter_parts( parts[parts_in_square[index]] ); + add_msg_if_player_sees( pos, m_bad, _( "The %s's %s breaks into pieces!" ), name, vp_here.name() ); + scatter_parts( vp_here ); } else { // Intact (but possibly damaged) part - remove it in one piece - add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is torn off!" ), name, - parts[ parts_in_square[ index ] ].name() ); + add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is torn off!" ), name, vp_here.name() ); if( !magic ) { - item part_as_item = parts[parts_in_square[index]].properties_to_item(); - here.add_item_or_charges( pos, part_as_item ); + here.add_item_or_charges( pos, vp_here.properties_to_item() ); } } remove_part( parts_in_square[index], *handler_ptr ); } // After clearing the frame, remove it. - add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is destroyed!" ), name, parts[ p ].name() ); - scatter_parts( parts[p] ); + add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is destroyed!" ), name, vp.name() ); + scatter_parts( vp ); remove_part( p, *handler_ptr ); find_and_split_vehicles( here, { p } ); } else { - if( part_flag( p, "TOW_CABLE" ) ) { + if( vpi.has_flag( "TOW_CABLE" ) ) { // Tow cables - remove it in one piece, remove remote part, and remove towing data - add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, - parts[ p ].name() ); + add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, vp.name() ); invalidate_towing( true ); - } else if( part_flag( p, "POWER_TRANSFER" ) ) { + } else if( vpi.has_flag( "POWER_TRANSFER" ) ) { // Electrical cables - remove it in one piece and remove remote part - add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, - parts[ p ].name() ); - item part_as_item = parts[p].properties_to_item(); - here.add_item_or_charges( pos, part_as_item ); + add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, vp.name() ); + here.add_item_or_charges( pos, vp.properties_to_item() ); remove_remote_part( p ); } else { //Just break it off - add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is destroyed!" ), name, parts[ p ].name() ); - - scatter_parts( parts[p] ); + add_msg_if_player_sees( pos, m_bad, _( "The %1$s's %2$s is destroyed!" ), name, vp.name() ); + scatter_parts( vp ); } - const point position = parts[p].mount; + const point position = vp.mount; remove_part( p, *handler_ptr ); // remove parts for which required flags are not present anymore - if( !part_info( p ).get_flags().empty() ) { + if( !vpi.get_flags().empty() ) { const std::vector parts_here = parts_at_relative( position, false ); - for( const int &part : parts_here ) { + for( const int part : parts_here ) { + vehicle_part &vp_here = parts[part]; + const vpart_info &vpi_here = vp_here.info(); bool remove = false; - for( const std::string &flag : part_info( part ).get_flags() ) { - if( !json_flag::get( flag ).requires_flag().empty() ) { + for( const std::string &flag : vpi_here.get_flags() ) { + const std::string &required_flag = json_flag::get( flag ).requires_flag(); + if( !required_flag.empty() ) { remove = true; - for( const int &elem : parts_here ) { - if( part_info( elem ).has_flag( json_flag::get( flag ).requires_flag() ) ) { + for( const int elem : parts_here ) { + if( parts[elem].info().has_flag( required_flag ) ) { remove = false; continue; } @@ -7076,14 +7051,13 @@ int vehicle::break_off( map &here, int p, int dmg ) } } if( remove ) { - if( part_flag( part, "TOW_CABLE" ) ) { + if( vpi_here.has_flag( "TOW_CABLE" ) ) { invalidate_towing( true ); } else { - if( part_flag( p, "POWER_TRANSFER" ) ) { + if( vpi.has_flag( "POWER_TRANSFER" ) ) { remove_remote_part( part ); } - item part_as_item = parts[part].properties_to_item(); - here.add_item_or_charges( pos, part_as_item ); + here.add_item_or_charges( pos, vp_here.properties_to_item() ); remove_part( part, *handler_ptr ); } } @@ -7096,15 +7070,16 @@ int vehicle::break_off( map &here, int p, int dmg ) bool vehicle::explode_fuel( int p, const damage_type_id &type ) { - const itype_id &ft = part_info( p ).fuel_type; + vehicle_part &vp = part( p ); + const itype_id &ft = vp.info().fuel_type; item fuel = item( ft ); if( !fuel.has_explosion_data() ) { return false; } const fuel_explosion_data &data = fuel.get_explosion_data(); - if( parts[ p ].is_broken() ) { - leak_fuel( parts[ p ] ); + if( vp.is_broken() ) { + leak_fuel( vp ); } int explosion_chance = type == damage_heat ? data.explosion_chance_hot : @@ -7112,12 +7087,10 @@ bool vehicle::explode_fuel( int p, const damage_type_id &type ) if( one_in( explosion_chance ) ) { get_event_bus().send( name ); const int pow = 120 * ( 1 - std::exp( data.explosion_factor / -5000 * - ( parts[p].ammo_remaining() * data.fuel_size_factor ) ) ); - //debugmsg( "damage check dmg=%d pow=%d amount=%d", dmg, pow, parts[p].amount ); - - explosion_handler::explosion( nullptr, global_part_pos3( p ), pow, 0.7, data.fiery_explosion ); - mod_hp( parts[p], -parts[ p ].hp() ); - parts[p].ammo_unset(); + ( vp.ammo_remaining() * data.fuel_size_factor ) ) ); + explosion_handler::explosion( nullptr, global_part_pos3( vp ), pow, 0.7, data.fiery_explosion ); + mod_hp( vp, -vp.hp() ); + vp.ammo_unset(); } return true; @@ -7129,18 +7102,21 @@ int vehicle::damage_direct( map &here, int p, int dmg, const damage_type_id &typ if( ( static_cast( p ) >= parts.size() ) || parts[p].removed ) { return dmg; } + vehicle_part &vp = parts[p]; + const vpart_info &vpi = vp.info(); + const tripoint vppos = global_part_pos3( vp ); // If auto-driving and damage happens, bail out if( is_autodriving ) { stop_autodriving(); } - here.set_memory_seen_cache_dirty( global_part_pos3( p ) ); - if( parts[p].is_broken() ) { + here.set_memory_seen_cache_dirty( vppos ); + if( vp.is_broken() ) { return break_off( here, p, dmg ); } - int tsh = std::min( 20, part_info( p ).durability / 10 ); + int tsh = std::min( 20, vpi.durability / 10 ); if( dmg < tsh && type != damage_pure ) { - if( type == damage_heat && parts[p].is_fuel_store() ) { + if( type == damage_heat && vp.is_fuel_store() ) { explode_fuel( p, type ); } @@ -7148,11 +7124,11 @@ int vehicle::damage_direct( map &here, int p, int dmg, const damage_type_id &typ } if( !type->no_resist ) { - dmg -= std::min( dmg, part_info( p ).damage_reduction.at( type ) ); + dmg -= std::min( dmg, vpi.damage_reduction.at( type ) ); } - int dres = dmg - parts[p].hp(); - if( mod_hp( parts[ p ], -dmg ) ) { - if( is_flyable() && !rotors.empty() && !parts[p].info().has_flag( VPFLAG_SIMPLE_PART ) ) { + int dres = dmg - vp.hp(); + if( mod_hp( vp, -dmg ) ) { + if( is_flyable() && !rotors.empty() && !vpi.has_flag( VPFLAG_SIMPLE_PART ) ) { // If we break a part, we can no longer fly the vehicle. set_flyable( false ); } @@ -7161,12 +7137,12 @@ int vehicle::damage_direct( map &here, int p, int dmg, const damage_type_id &typ pivot_dirty = true; // destroyed parts lose any contained fuels, battery charges or ammo - leak_fuel( parts [ p ] ); + leak_fuel( vp ); - for( const item &e : parts[p].items ) { - here.add_item_or_charges( global_part_pos3( p ), e ); + for( const item &e : vp.items ) { + here.add_item_or_charges( vppos, e ); } - parts[p].items.clear(); + vp.items.clear(); invalidate_mass(); coeff_air_changed = true; @@ -7175,27 +7151,26 @@ int vehicle::damage_direct( map &here, int p, int dmg, const damage_type_id &typ refresh(); } - if( parts[p].is_fuel_store() ) { + if( vp.is_fuel_store() ) { explode_fuel( p, type ); - } else if( parts[ p ].is_broken() && part_flag( p, "UNMOUNT_ON_DAMAGE" ) ) { + } else if( vp.is_broken() && vpi.has_flag( "UNMOUNT_ON_DAMAGE" ) ) { monster *mon = get_monster( p ); if( mon != nullptr && mon->has_effect( effect_harnessed ) ) { mon->remove_effect( effect_harnessed ); } - if( part_flag( p, "TOW_CABLE" ) ) { + if( vpi.has_flag( "TOW_CABLE" ) ) { invalidate_towing( true ); } else { - item part_as_item = parts[p].properties_to_item(); - add_msg_if_player_sees( global_part_pos3( p ), m_bad, _( "The %1$s's %2$s is disconnected!" ), name, - parts[p].name() ); - if( part_flag( p, "POWER_TRANSFER" ) ) { + item part_as_item = vp.properties_to_item(); + add_msg_if_player_sees( vppos, m_bad, _( "The %1$s's %2$s is disconnected!" ), name, vp.name() ); + if( vpi.has_flag( "POWER_TRANSFER" ) ) { remove_remote_part( p ); part_as_item.set_damage( 0 ); } else { - part_as_item.set_damage( part_info( p ).base_item.obj().damage_max() - 1 ); + part_as_item.set_damage( vpi.base_item.obj().damage_max() - 1 ); } if( !magic && !part_as_item.has_flag( flag_AUTO_DELETE_CABLE ) ) { - here.add_item_or_charges( global_part_pos3( p ), part_as_item ); + here.add_item_or_charges( vppos, part_as_item ); } if( !g || &get_map() != &here ) { MapgenRemovePartHandler handler( here ); diff --git a/src/vehicle.h b/src/vehicle.h index 3135e50b5605e..566cf239538d2 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -737,8 +737,8 @@ class vpart_display * call `map::veh_at()`, and check vehicle type (`veh_null` * means there's no vehicle there). * - Vehicle consists of parts (represented by vector). Parts have some - * constant info: see veh_type.h, `vpart_info` structure and - * vpart_list array -- that is accessible through `part_info()` method. + * constant info: see veh_type.h, `vpart_info` structure that is accessible + * through `vehicle_part::info()` method. * The second part is variable info, see `vehicle_part` structure. * - Parts are mounted at some point relative to vehicle position (or starting part) * (`0, 0` in mount coordinates). There can be more than one part at @@ -1009,9 +1009,6 @@ class vehicle // Engine backfire, making a loud noise void backfire( const vehicle_part &vp ) const; - // get vpart type info for part number (part at given vector index) - const vpart_info &part_info( int index, bool include_removed = false ) const; - /** * @param dp The coordinate to mount at (in vehicle mount point coords) * @param vpi The part type to check @@ -1288,10 +1285,6 @@ class vehicle // with the same flag on the X and Y Axis std::vector> find_lines_of_parts( int part, const std::string &flag ) const; - // returns true if given flag is present for given part index - bool part_flag( int p, const std::string &f ) const; - bool part_flag( int p, vpart_bitflags f ) const; - // Translate mount coordinates "p" using current pivot direction and anchor and return tile coordinates point coord_translate( const point &p ) const; diff --git a/src/vehicle_display.cpp b/src/vehicle_display.cpp index 8837768a3f0f1..6e570d3230d27 100644 --- a/src/vehicle_display.cpp +++ b/src/vehicle_display.cpp @@ -149,7 +149,8 @@ int vehicle::print_part_list( const catacurses::window &win, int y1, const int m std::vector pl = this->parts_at_relative( parts[p].mount, true, include_fakes ); int y = y1; for( size_t i = 0; i < pl.size(); i++ ) { - const vehicle_part &vp = parts[ pl [ i ] ]; + const vehicle_part &vp = parts[pl[i]]; + const vpart_info &vpi = vp.info(); if( !vp.is_real_or_active_fake() ) { continue; } @@ -178,7 +179,7 @@ int vehicle::print_part_list( const catacurses::window &win, int y1, const int m } } - if( part_flag( pl[i], "CARGO" ) ) { + if( vpi.has_flag( VPFLAG_CARGO ) ) { //~ used/total volume of a cargo vehicle part partname += string_format( _( " (vol: %s/%s %s)" ), format_volume( stored_volume( pl[i] ) ), @@ -186,13 +187,13 @@ int vehicle::print_part_list( const catacurses::window &win, int y1, const int m volume_units_abbr() ); } - bool armor = part_flag( pl[i], "ARMOR" ); + const bool armor = vpi.has_flag( VPFLAG_ARMOR ); std::string left_sym; std::string right_sym; if( armor ) { left_sym = "("; right_sym = ")"; - } else if( part_info( pl[i] ).location == part_location_structure ) { + } else if( vpi.location == part_location_structure ) { left_sym = "["; right_sym = "]"; } else { diff --git a/src/vehicle_move.cpp b/src/vehicle_move.cpp index c86f3b753d52e..c29ab05d9308f 100644 --- a/src/vehicle_move.cpp +++ b/src/vehicle_move.cpp @@ -859,7 +859,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, // Typical rotor tip speed in MPH * 100. int rotor_velocity = 45600; // Non-vehicle collisions can't happen when the vehicle is not moving - int &coll_velocity = ( part_info( part ).rotor_diameter() == 0 ) ? + int &coll_velocity = ( parts[part].info().rotor_diameter() == 0 ) ? ( vert_coll ? vertical_velocity : velocity ) : rotor_velocity; if( !just_detect && coll_velocity == 0 ) { @@ -896,7 +896,7 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, if( armor_part >= 0 ) { ret.part = armor_part; } - const vehicle_part &vp = this->part( ret.part ); + vehicle_part &vp = this->part( ret.part ); const vpart_info &vpi = vp.info(); // Let's calculate type of collision & mass of object we hit float mass2 = 0.0f; @@ -950,11 +950,12 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, // Calculate mass AFTER checking for collision // because it involves iterating over all cargo // Rotors only use rotor mass in calculation. - const float mass = ( part_info( ret.part ).rotor_diameter() > 0 ) ? - to_kilogram( parts[ ret.part ].base.weight() ) : to_kilogram( total_mass() ); + const float mass = vpi.rotor_diameter() > 0 + ? to_kilogram( vp.base.weight() ) + : to_kilogram( total_mass() ); //Calculate damage resulting from d_E - const itype *type = item::find_type( part_info( ret.part ).base_item ); + const itype *type = item::find_type( vpi.base_item ); const auto &mats = type->materials; float mat_total = type->mat_portion_total == 0 ? 1 : type->mat_portion_total; float vpart_dens = 0.0f; @@ -1068,10 +1069,10 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, // No blood from hallucinations if( !critter->is_hallucination() ) { - if( part_flag( ret.part, "SHARP" ) ) { - parts[ret.part].blood += ( 20 + dam ) * 5; + if( vpi.has_flag( "SHARP" ) ) { + vp.blood += 100 + 5 * dam; } else if( dam > rng( 10, 30 ) ) { - parts[ret.part].blood += ( 10 + dam / 2 ) * 5; + vp.blood += 50 + dam / 2 * 5; } check_environmental_effects = true; @@ -1085,12 +1086,12 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, if( ph != nullptr ) { ph->hitall( dam, 40, driver ); } else { - const int armor = part_flag( ret.part, "SHARP" ) ? + const int armor = vpi.has_flag( "SHARP" ) ? critter->get_armor_type( damage_cut, bodypart_id( "torso" ) ) : critter->get_armor_type( damage_bash, bodypart_id( "torso" ) ); dam = std::max( 0, dam - armor ); critter->apply_damage( driver, bodypart_id( "torso" ), dam ); - if( part_flag( ret.part, "SHARP" ) ) { + if( vpi.has_flag( "SHARP" ) ) { critter->add_effect( effect_source( driver ), effect_bleed, 1_minutes * rng( 1, dam ), critter->get_random_body_part_of_type( body_part_type::type::torso ) ); } else if( dam > 18 && rng( 1, 20 ) > 15 ) { @@ -1144,15 +1145,15 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, if( time_stunned > 0_turns ) { //~ 1$s - vehicle name, 2$s - part name, 3$s - NPC or monster add_msg( m_warning, _( "Your %1$s's %2$s rams into %3$s and stuns it!" ), - name, parts[ ret.part ].name(), ret.target_name ); + name, vp.name(), ret.target_name ); } else { //~ 1$s - vehicle name, 2$s - part name, 3$s - NPC or monster add_msg( m_warning, _( "Your %1$s's %2$s rams into %3$s!" ), - name, parts[ ret.part ].name(), ret.target_name ); + name, vp.name(), ret.target_name ); } } - if( part_flag( ret.part, "SHARP" ) ) { + if( vpi.has_flag( "SHARP" ) ) { critter->bleed(); } else { sounds::sound( p, 20, sounds::sound_t::combat, snd, false, "smash_success", "hit_vehicle" ); @@ -1163,11 +1164,11 @@ veh_collision vehicle::part_collision( int part, const tripoint &p, if( !snd.empty() ) { //~ 1$s - vehicle name, 2$s - part name, 3$s - collision object name, 4$s - sound message add_msg( m_warning, _( "Your %1$s's %2$s rams into %3$s with a %4$s" ), - name, parts[ ret.part ].name(), ret.target_name, snd ); + name, vp.name(), ret.target_name, snd ); } else { //~ 1$s - vehicle name, 2$s - part name, 3$s - collision object name add_msg( m_warning, _( "Your %1$s's %2$s rams into %3$s." ), - name, parts[ ret.part ].name(), ret.target_name ); + name, vp.name(), ret.target_name ); } } @@ -2161,12 +2162,13 @@ units::angle map::shake_vehicle( vehicle &veh, const int velocity_before, } move_resist = std::max( 100, pet_resist ); } - if( veh.part_with_feature( ps, VPFLAG_SEATBELT, true ) == -1 ) { + const int belt_idx = veh.part_with_feature( ps, VPFLAG_SEATBELT, true ); + if( belt_idx == -1 ) { ///\EFFECT_STR reduces chance of being thrown from your seat when not wearing a seatbelt throw_from_seat = d_vel * rng( 80, 120 ) > move_resist; } else { // Reduce potential damage based on quality of seatbelt - dmg -= veh.part_info( veh.part_with_feature( ps, VPFLAG_SEATBELT, true ) ).bonus; + dmg -= veh.part( belt_idx ).info().bonus; } // Damage passengers if d_vel is too high diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index 330e799db07d5..d7e973111c848 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -144,7 +144,8 @@ void vehicle::control_doors() if( motorized_idx == -1 ) { continue; } - if( !require_flag.empty() && !part_flag( motorized_idx, require_flag ) ) { + vehicle_part &vp = part( motorized_idx ); + if( !require_flag.empty() && !vp.info().has_flag( require_flag ) ) { continue; } if( new_open || can_close( motorized_idx, get_player_character() ) ) { @@ -160,7 +161,8 @@ void vehicle::control_doors() if( motorized_idx == -1 ) { continue; } - if( !require_flag.empty() && !part_flag( motorized_idx, require_flag ) ) { + vehicle_part &vp = part( motorized_idx ); + if( !require_flag.empty() && !vp.info().has_flag( require_flag ) ) { continue; } lock_or_unlock( motorized_idx, new_lock ); @@ -1206,9 +1208,9 @@ void vehicle::alarm() */ void vehicle::open( int part_index ) { - if( !part_info( part_index ).has_flag( "OPENABLE" ) ) { - debugmsg( "Attempted to open non-openable part %d (%s) on a %s!", part_index, - parts[ part_index ].name(), name ); + vehicle_part &vp = part( part_index ); + if( !vp.info().has_flag( VPFLAG_OPENABLE ) ) { + debugmsg( "Attempted to open non-openable part %d (%s) on a %s!", part_index, vp.name(), name ); } else { open_or_close( part_index, true ); } @@ -1221,9 +1223,9 @@ void vehicle::open( int part_index ) */ void vehicle::close( int part_index ) { - if( !part_info( part_index ).has_flag( "OPENABLE" ) ) { - debugmsg( "Attempted to close non-closeable part %d (%s) on a %s!", part_index, - parts[ part_index ].name(), name ); + vehicle_part &vp = part( part_index ); + if( !vp.info().has_flag( VPFLAG_OPENABLE ) ) { + debugmsg( "Attempted to close non-closeable part %d (%s) on a %s!", part_index, vp.name(), name ); } else { open_or_close( part_index, false ); } @@ -1236,9 +1238,9 @@ void vehicle::close( int part_index ) */ void vehicle::unlock( int part_index ) { - if( !part_info( part_index ).has_flag( "LOCKABLE_DOOR" ) ) { - debugmsg( "Attempted to unlock non-lockable part %d (%s) on a %s!", part_index, - parts[part_index].name(), name ); + vehicle_part &vp = part( part_index ); + if( !vp.info().has_flag( "LOCKABLE_DOOR" ) ) { + debugmsg( "Attempted to unlock non-lockable part %d (%s) on a %s!", part_index, vp.name(), name ); } else { lock_or_unlock( part_index, false ); } @@ -1251,12 +1253,11 @@ void vehicle::unlock( int part_index ) */ void vehicle::lock( int part_index ) { - if( !part_info( part_index ).has_flag( "LOCKABLE_DOOR" ) ) { - debugmsg( "Attempted to lock non-lockable part %d (%s) on a %s!", part_index, - parts[part_index].name(), name ); - } else if( parts[part_index].open ) { - debugmsg( "Attempted to lock open part %d (%s) on a %s!", part_index, parts[part_index].name(), - name ); + vehicle_part &vp = part( part_index ); + if( !vp.info().has_flag( "LOCKABLE_DOOR" ) ) { + debugmsg( "Attempted to lock non-lockable part %d (%s) on a %s!", part_index, vp.name(), name ); + } else if( vp.open ) { + debugmsg( "Attempted to lock open part %d (%s) on a %s!", part_index, vp.name(), name ); } else { lock_or_unlock( part_index, true ); } @@ -1301,9 +1302,9 @@ bool vehicle::can_close( int part_index, Character &who ) void vehicle::open_all_at( int p ) { - std::vector parts_here = parts_at_relative( parts[p].mount, true, true ); - for( int &elem : parts_here ) { - if( part_flag( elem, VPFLAG_OPENABLE ) ) { + for( const int elem : parts_at_relative( parts[p].mount, true, true ) ) { + const vehicle_part &vp = parts[elem]; + if( vp.info().has_flag( VPFLAG_OPENABLE ) ) { // Note that this will open multi-square and non-multipart parts in the tile. This // means that adjacent open multi-square openables can still have closed stuff // on same tile after this function returns @@ -1589,7 +1590,11 @@ void vehicle::use_monster_capture( int part, const tripoint &pos ) void vehicle::use_harness( int part, const tripoint &pos ) { - if( parts[part].is_unavailable() || parts[part].removed ) { + const vehicle_part &vp = parts[part]; + const vpart_info &vpi = vp.info(); + + if( vp.is_unavailable() || vp.removed ) { + debugmsg( "use_harness called on invalid part" ); return; } if( !g->is_empty( pos ) ) { @@ -1628,7 +1633,7 @@ void vehicle::use_harness( int part, const tripoint &pos ) } else if( !m.has_flag( mon_flag_PET_MOUNTABLE ) && !m.has_flag( mon_flag_PET_HARNESSABLE ) ) { add_msg( m_info, _( "This creature cannot be harnessed." ) ); return; - } else if( !part_flag( part, Harness_Bodytype ) && !part_flag( part, "HARNESS_any" ) ) { + } else if( !vpi.has_flag( Harness_Bodytype ) && !vpi.has_flag( "HARNESS_any" ) ) { add_msg( m_info, _( "The harness is not adapted for this creature morphology." ) ); return; } diff --git a/src/visitable.cpp b/src/visitable.cpp index 564f8df0892c6..5ab450800df39 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -128,11 +128,11 @@ static int has_quality_from_vpart( const vehicle &veh, int part, const quality_i int qty = 0; point pos = veh.part( part ).mount; - for( const int &n : veh.parts_at_relative( pos, true ) ) { - + for( const int n : veh.parts_at_relative( pos, true ) ) { + const vehicle_part &vp = veh.part( n ); // only unbroken parts can provide tool qualities - if( !veh.part( n ).is_broken() ) { - auto tq = veh.part_info( n ).qualities; + if( !vp.is_broken() ) { + auto tq = vp.info().qualities; auto iter = tq.find( qual ); // does the part provide this quality? @@ -243,10 +243,11 @@ static int max_quality_from_vpart( const vehicle &veh, int part, const quality_i point pos = veh.part( part ).mount; for( const int &n : veh.parts_at_relative( pos, true ) ) { + const vehicle_part &vp = veh.part( n ); // only unbroken parts can provide tool qualities - if( !veh.part( n ).is_broken() ) { - auto tq = veh.part_info( n ).qualities; + if( !vp.is_broken() ) { + auto tq = vp.info().qualities; auto iter = tq.find( qual ); // does the part provide this quality?