diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 9bd8c41392e9e..44e7c1d9e59a5 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -6680,6 +6680,9 @@ std::unique_ptr map::add_vehicle_to_map( part != frame_indices.end(); part++ ) { const tripoint p = veh_to_add->global_part_pos3( *part ); + if( veh_to_add->part( *part ).is_fake ) { + continue; + } //Don't spawn anything in water if( has_flag_ter( ter_furn_flag::TFLAG_DEEP_WATER, p ) && !can_float ) { return nullptr; @@ -6715,45 +6718,65 @@ std::unique_ptr map::add_vehicle_to_map( * * the overlap span is still a mess, though. */ - + std::unique_ptr handler_ptr; + bool did_merge = false; for( const tripoint &map_pos : first_veh->get_points( true ) ) { std::vector parts_to_move = veh_to_add->get_parts_at( map_pos, "", part_status_flag::any ); if( !parts_to_move.empty() ) { // Store target_point by value because first_veh->parts may reallocate // to a different address after install_part() - const point target_point = first_veh->get_parts_at( map_pos, "", - part_status_flag:: any ).front()->mount; + std::vector first_veh_parts = first_veh->get_parts_at( map_pos, "", + part_status_flag:: any ); + // this happens of this location is occupied by a fake part. + if( first_veh_parts.empty() || first_veh_parts.front()->is_fake ) { + continue; + } + did_merge = true; + const point target_point = first_veh_parts.front()->mount; const point source_point = parts_to_move.front()->mount; for( const vehicle_part *vp : parts_to_move ) { // TODO: change mount points to be tripoint first_veh->install_part( target_point, *vp ); } + if( !handler_ptr ) { + // This is a heuristic: we just assume the default handler is good enough when called + // on the main game map. And assume that we run from some mapgen code if called on + // another instance. + if( !g || &get_map() != this ) { + handler_ptr = std::make_unique( *this ); + } + } + // Triggers fake part removal that causes problems otherwise. + veh_to_add->refresh( true ); // this couuld probably be done in a single loop with installing parts above - std::vector parts_in_square = veh_to_add->parts_at_relative( source_point, true ); + std::vector parts_in_square = veh_to_add->parts_at_relative( source_point, false ); std::set parts_to_check; for( int index = parts_in_square.size() - 1; index >= 0; index-- ) { - veh_to_add->remove_part( parts_in_square[index] ); + if( handler_ptr ) { + veh_to_add->remove_part( parts_in_square[index], *handler_ptr ); + } else { + veh_to_add->remove_part( parts_in_square[index] ); + } parts_to_check.insert( parts_in_square[index] ); } veh_to_add->find_and_split_vehicles( parts_to_check ); } } - // TODO: more targeted damage around the impact site - first_veh->smash( *this ); - first_veh->enable_refresh(); - - // TODO: entangle the old vehicle and the new vehicle somehow, perhaps with tow cables - // or something like them, to make them harder to separate - std::unique_ptr new_veh = add_vehicle_to_map( std::move( veh_to_add ), true ); - if( new_veh != nullptr ) { - new_veh->smash( *this ); - return new_veh; + if( did_merge ) { + // TODO: more targeted damage around the impact site + first_veh->smash( *this ); + // TODO: entangle the old vehicle and the new vehicle somehow, perhaps with tow cables + // or something like them, to make them harder to separate + std::unique_ptr new_veh = add_vehicle_to_map( std::move( veh_to_add ), true ); + if( new_veh != nullptr ) { + new_veh->smash( *this ); + return new_veh; + } + return nullptr; } - return nullptr; - } else if( impassable( p ) ) { if( !merge_wrecks ) { return nullptr; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index c9e59f32a49bd..ea8edfadb47a0 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1843,6 +1843,9 @@ bool vehicle::remove_part( const int p, RemovePartHandler &handler ) zones_dirty = true; } parts[p].removed = true; + if( parts[p].has_fake ) { + parts[parts[p].fake_part_at].removed = true; + } removed_part_count++; handler.removed( *this, p ); @@ -2788,7 +2791,7 @@ vehicle_part_with_feature_range vehicle::get_enabled_parts( std::vector vehicle::all_parts_at_location( const std::string &location ) const { std::vector parts_found; - auto all_parts = get_all_parts(); + vehicle_part_range all_parts = get_all_parts(); for( const vpart_reference &vpr : all_parts ) { if( vpr.info().location == location && !parts[vpr.part_index()].removed ) { parts_found.push_back( vpr.part_index() ); @@ -3311,7 +3314,7 @@ int vehicle::fuel_capacity( const itype_id &ftype ) const vehicle_part_range vpr = get_all_parts(); return std::accumulate( vpr.begin(), vpr.end(), 0, [&ftype]( const int &lhs, const vpart_reference & rhs ) { - cata::value_ptr a_val = item::find_type( ftype )->ammo; + cata::value_ptr a_val = item::find_type( ftype )->ammo; return lhs + ( rhs.part().ammo_current() == ftype ? rhs.part().ammo_capacity( !!a_val ? a_val->type : ammotype::NULL_ID() ) : 0 ); @@ -3325,9 +3328,8 @@ float vehicle::fuel_specific_energy( const itype_id &ftype ) const for( const vpart_reference &vpr : get_all_parts() ) { if( vpr.part().is_tank() && vpr.part().ammo_current() == ftype && vpr.part().base.only_item().made_of( phase_id::LIQUID ) ) { - float mass = to_gram( vpr.part().base.only_item().weight() ); - total_energy += vpr.part().base.only_item().specific_energy * mass; - total_mass += mass; + total_energy += vpr.part().base.only_item().get_item_thermal_energy(); + total_mass += to_gram( vpr.part().base.only_item().weight() ); } } return total_energy / total_mass; @@ -5885,11 +5887,6 @@ void vehicle::refresh( const bool remove_fakes ) std::set smzs = precalc_mounts( 0, pivot_rotation[0], pivot_anchor[0] ); // update the fakes, and then repopulate the cache update_active_fakes(); - map &here = get_map(); - here.add_vehicle_to_cache( this ); - for( const int dirty_z : smzs ) { - here.on_vehicle_moved( dirty_z ); - } check_environmental_effects = true; insides_dirty = true; zones_dirty = true; @@ -6516,6 +6513,10 @@ int vehicle::damage( int p, int dmg, damage_type type, bool aimed ) } p = get_non_fake_part( p ); + // If we're trying to hit a fake part with no associated real part, just cancel out. + if( p == -1 ) { + return dmg; + } std::vector pl = parts_at_relative( parts[p].mount, true ); if( pl.empty() ) { // We ran out of non removed parts at this location already. @@ -6599,7 +6600,6 @@ void vehicle::damage_all( int dmg1, int dmg2, damage_type type, const point &imp return; } - std::cout << "veh " << name << " has " << parts.size() << " parts."; for( const vpart_reference &vp : get_all_parts() ) { const size_t p = vp.part_index(); int distance = 1 + square_dist( vp.mount(), impact ); @@ -7387,7 +7387,7 @@ int vehicle::get_non_fake_part( const int part_num ) return part_num; } } - std::cout << "Returning -1 for get_non_fake_part."; + debugmsg( "Returning -1 for get_non_fake_part on part_num %d.", part_num ); return -1; }