diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index b718ce97601ae..c172882efb0b8 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -406,7 +406,7 @@ bool avatar_action::move( avatar &you, map &m, const tripoint_rel_ms &d ) } you.melee_attack( critter, true ); if( critter.is_hallucination() ) { - critter.die( &you ); + critter.die( &m, &you ); } g->draw_hit_mon( dest_loc, critter, critter.is_dead() ); return false; diff --git a/src/ballistics.cpp b/src/ballistics.cpp index 87ed373d2474a..2111c77d4d03b 100644 --- a/src/ballistics.cpp +++ b/src/ballistics.cpp @@ -523,7 +523,7 @@ void projectile_attack( dealt_projectile_attack &attack, const projectile &proj_ origin->check_avoid_friendly_fire() ) { continue; } - critter->deal_projectile_attack( null_source ? nullptr : origin, attack, cur_missed_by, + critter->deal_projectile_attack( &here, null_source ? nullptr : origin, attack, cur_missed_by, print_messages, wp_attack ); if( critter->is_npc() ) { diff --git a/src/character.cpp b/src/character.cpp index b157fdeae37c1..3eea6a98cfcc5 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1802,6 +1802,8 @@ bool Character::is_mounted() const void Character::forced_dismount() { + map &here = get_map(); + remove_effect( effect_riding ); remove_effect( effect_mech_recon_vision ); bool mech = false; @@ -1879,7 +1881,7 @@ void Character::forced_dismount() pgettext( "memorial_male", "Fell off a mount." ), pgettext( "memorial_female", "Fell off a mount." ) ); } - check_dead_state(); + check_dead_state( &here ); } add_effect( effect_downed, 5_turns, true ); } else { @@ -2378,6 +2380,7 @@ void Character::expose_to_disease( const diseasetype_id &dis_type ) void Character::process_turn() { + map &here = get_map(); // Has to happen before reset_stats clear_miss_reasons(); migrate_items_to_storage( false ); @@ -2405,7 +2408,7 @@ void Character::process_turn() if( leak_level_dirty ) { calculate_leak_level(); } - process_items(); + process_items( &here ); leak_items(); // Didn't just pick something up last_item = itype_id::NULL_ID(); @@ -3666,7 +3669,7 @@ void Character::normalize() } // Actual player death is mostly handled in game::is_game_over -void Character::die( Creature *nkiller ) +void Character::die( map *, Creature *nkiller ) { g->set_critter_died(); set_all_parts_hp_cur( 0 ); @@ -8091,10 +8094,10 @@ std::string Character::weapname_ammo() const } } -void Character::on_hit( Creature *source, bodypart_id bp_hit, +void Character::on_hit( map *here, Creature *source, bodypart_id bp_hit, float /*difficulty*/, dealt_projectile_attack const *const proj ) { - check_dead_state(); + check_dead_state( here ); if( source == nullptr || proj != nullptr ) { return; } @@ -8179,8 +8182,7 @@ void Character::on_hit( Creature *source, bodypart_id bp_hit, } } - map &here = get_map(); - const optional_vpart_position veh_part = here.veh_at( pos_bub() ); + const optional_vpart_position veh_part = here->veh_at( pos_abs() ); bool in_skater_vehicle = in_vehicle && veh_part.part_with_feature( "SEAT_REQUIRES_BALANCE", false ); if( ( worn_with_flag( flag_REQUIRES_BALANCE ) || in_skater_vehicle ) && !is_on_ground() ) { @@ -10438,7 +10440,7 @@ std::vector Character::run_cost_effects( float &movecost ) cons return effects; } -void Character::place_corpse() +void Character::place_corpse( map *here ) { //If the character/NPC is on a distant mission, don't drop their their gear when they die since they still have a local pos if( !death_drops ) { @@ -10447,7 +10449,6 @@ void Character::place_corpse() std::vector tmp = inv_dump(); item body = item::make_corpse( mtype_id::NULL_ID(), calendar::turn, get_name() ); body.set_item_temperature( units::from_celsius( 37 ) ); - map &here = get_map(); for( item *itm : tmp ) { body.force_insert_item( *itm, pocket_type::CONTAINER ); } @@ -10465,7 +10466,7 @@ void Character::place_corpse() } } - here.add_item_or_charges( pos_bub(), body ); + here->add_item_or_charges( here->get_bub( pos_abs() ), body ); } void Character::place_corpse( const tripoint_abs_omt &om_target ) @@ -11160,6 +11161,15 @@ void Character::gravity_check() } } +void Character::gravity_check( map *here ) +{ + const tripoint_bub_ms pos = here->get_bub( pos_abs() ); + if( here->is_open_air( pos ) && !in_vehicle && !has_effect_with_flag( json_flag_GLIDING ) && + here->try_fall( pos, this ) ) { + here->update_visibility_cache( pos.z() ); + } +} + void Character::stagger() { map &here = get_map(); @@ -12739,6 +12749,7 @@ bool Character::can_fly() // FIXME: Relies on hardcoded bash damage type void Character::knock_back_to( const tripoint_bub_ms &to ) { + map &here = get_map(); if( to == pos_bub() ) { return; } @@ -12758,7 +12769,7 @@ void Character::knock_back_to( const tripoint_bub_ms &to ) critter->apply_damage( this, bodypart_id( "torso" ), ( str_max - 6 ) / 4 ); critter->add_effect( effect_stunned, 1_turns ); } - critter->check_dead_state(); + critter->check_dead_state( &here ); add_msg_player_or_npc( _( "You bounce off a %s!" ), _( " bounces off a %s!" ), critter->name() ); @@ -12772,11 +12783,10 @@ void Character::knock_back_to( const tripoint_bub_ms &to ) np->deal_damage( this, bodypart_id( "torso" ), damage_instance( damage_bash, 3 ) ); add_msg_player_or_npc( _( "You bounce off %s!" ), _( " bounces off %s!" ), np->get_name() ); - np->check_dead_state(); + np->check_dead_state( &here ); return; } - map &here = get_map(); // If we're still in the function at this point, we're actually moving a tile! if( here.has_flag( ter_furn_flag::TFLAG_LIQUID, to ) && here.has_flag( ter_furn_flag::TFLAG_DEEP_WATER, to ) ) { @@ -12849,10 +12859,10 @@ void Character::leak_items() } } -void Character::process_items() +void Character::process_items( map *here ) { - if( weapon.process( get_map(), this, pos_bub() ) ) { - weapon.spill_contents( pos_bub() ); + if( weapon.process( *here, this, here->get_bub( pos_abs() ) ) ) { + weapon.spill_contents( here, here->get_bub( pos_abs() ) ); remove_weapon(); } @@ -12861,8 +12871,8 @@ void Character::process_items() if( !it ) { continue; } - if( it->process( get_map(), this, pos_bub() ) ) { - it->spill_contents( pos_bub() ); + if( it->process( *here, this, here->get_bub( pos_abs() ) ) ) { + it->spill_contents( here, here->get_bub( pos_abs() ) ); removed_items.push_back( it ); } } diff --git a/src/character.h b/src/character.h index 4d6efd1b2cd51..e7a0ed0d1c108 100644 --- a/src/character.h +++ b/src/character.h @@ -730,6 +730,7 @@ class Character : public Creature, public visitable public: void gravity_check() override; + void gravity_check( map *here ) override; void stagger(); void mod_stat( const std::string &stat, float modifier ) override; @@ -1271,7 +1272,7 @@ class Character : public Creature, public visitable // any side effects that might happen when the Character is hit /** Handles special defenses from melee attack that hit us (source can be null) */ - void on_hit( Creature *source, bodypart_id bp_hit, + void on_hit( map *here, Creature *source, bodypart_id bp_hit, float difficulty = INT_MIN, dealt_projectile_attack const *proj = nullptr ) override; // any side effects that might happen when the Character hits a Creature void did_hit( Creature &target ); @@ -1891,7 +1892,7 @@ class Character : public Creature, public visitable virtual item::reload_option select_ammo( const item_location &base, bool prompt = false, bool empty = true ) = 0; - void process_items(); + void process_items( map *here ); void leak_items(); /** Search surrounding squares for traps (and maybe other things in the future). */ void search_surroundings(); @@ -2569,7 +2570,7 @@ class Character : public Creature, public visitable * Should only be called through player::normalize(), not on it's own! */ void normalize() override; - void die( Creature *nkiller ) override; + void die( map *here, Creature *nkiller ) override; virtual void prevent_death(); std::string get_name() const override; @@ -3279,7 +3280,7 @@ class Character : public Creature, public visitable float speed_rating() const override; // Put corpse+inventory on map at the place where this is. - void place_corpse(); + void place_corpse( map *here ); // Put corpse+inventory on defined om tile void place_corpse( const tripoint_abs_omt &om_target ); diff --git a/src/computer_session.cpp b/src/computer_session.cpp index 44242c56a68c0..0f0ab9468e349 100644 --- a/src/computer_session.cpp +++ b/src/computer_session.cpp @@ -593,7 +593,7 @@ void computer_session::action_terminate() t_south == ter_t_concrete_wall ) || ( t_south == ter_t_reinforced_glass && t_north == ter_t_concrete_wall ) ) { - mon->die( &player_character ); + mon->die( &here, &player_character ); } } query_any( _( "Subjects terminated. Press any key…" ) ); diff --git a/src/creature.cpp b/src/creature.cpp index 44e1bcfacd795..f804e9c97b1b7 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -218,6 +218,16 @@ void Creature::setpos( const tripoint_bub_ms &p, bool check_gravity/* = true*/ ) } } +void Creature::setpos( map *here, const tripoint_bub_ms &p, bool check_gravity/* = true*/ ) +{ + const tripoint_abs_ms old_loc = pos_abs(); + set_pos_abs_only( here->get_abs( p ) ); + on_move( old_loc ); + if( check_gravity ) { + gravity_check( here ); + } +} + bool Creature::will_be_cramped_in_vehicle_tile( const tripoint_abs_ms &loc ) const { map &here = get_map(); @@ -313,6 +323,10 @@ void Creature::gravity_check() { } +void Creature::gravity_check( map * ) +{ +} + void Creature::normalize() { } @@ -914,6 +928,8 @@ void Creature::deal_melee_hit( Creature *source, int hit_spread, bool critical_h damage_instance dam, dealt_damage_instance &dealt_dam, const weakpoint_attack &attack, const bodypart_id *bp ) { + map &here = get_map(); + if( source == nullptr || source->is_hallucination() ) { dealt_dam.bp_hit = anatomy_human_anatomy->random_body_part(); return; @@ -942,7 +958,7 @@ void Creature::deal_melee_hit( Creature *source, int hit_spread, bool critical_h attack_copy.is_crit = critical_hit; attack_copy.type = weakpoint_attack::type_of_melee_attack( d ); - on_hit( source, bp_hit ); // trigger on-gethit events + on_hit( &here, source, bp_hit ); // trigger on-gethit events dam.onhit_effects( source, this ); // on-hit effects for inflicted damage types dealt_dam = deal_damage( source, bp_hit, d, attack_copy ); dealt_dam.bp_hit = bp_hit; @@ -1270,7 +1286,7 @@ void Creature::print_proj_avoid_msg( Creature *source, viewer &player_view ) con * @param attack A structure describing the attack and its results. * @param print_messages enables message printing by default. */ -void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack &attack, +void Creature::deal_projectile_attack( map *here, Creature *source, dealt_projectile_attack &attack, const double &missed_by, bool print_messages, const weakpoint_attack &wp_attack ) { @@ -1285,7 +1301,7 @@ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack if( mons && mons->mounted_player ) { if( !mons->has_flag( mon_flag_MECH_DEFENSIVE ) && one_in( std::max( 2, mons->get_size() - mons->mounted_player->get_size() ) ) ) { - mons->mounted_player->deal_projectile_attack( source, attack, missed_by, print_messages, + mons->mounted_player->deal_projectile_attack( here, source, attack, missed_by, print_messages, wp_attack ); return; } @@ -1367,7 +1383,7 @@ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack messaging_projectile_attack( source, hit_selection, total_dam ); } - check_dead_state(); + check_dead_state( here ); attack.last_hit_critter = this; attack.missed_by = goodhit; attack.headshot = hit_selection.is_headshot; @@ -2040,6 +2056,8 @@ int Creature::get_effect_int( const efftype_id &eff_id, const bodypart_id &bp ) } void Creature::process_effects() { + map &here = get_map(); + // id's and body_part's of all effects to be removed. If we ever get player or // monster specific removals these will need to be moved down to that level and then // passed in to this function. @@ -2079,7 +2097,7 @@ void Creature::process_effects() cata::event sent( e.death_event(), calendar::turn, std::move( event_data ) ); get_event_bus().send( sent ); } - die( e.get_source().resolve_creature() ); + die( &here, e.get_source().resolve_creature() ); } } } @@ -2228,7 +2246,7 @@ void Creature::decrement_summon_timer() return; } if( lifespan_end.value() <= calendar::turn ) { - die( nullptr ); + die( &get_map(), nullptr ); } } @@ -3296,10 +3314,10 @@ void Creature::process_damage_over_time() } } -void Creature::check_dead_state() +void Creature::check_dead_state( map *here ) { if( is_dead_state() ) { - die( killer ); + die( here, killer ); } } @@ -3345,11 +3363,13 @@ std::string Creature::replace_with_npc_name( std::string input ) const void Creature::knock_back_from( const tripoint_bub_ms &p ) { + map &here = get_map(); + if( p == pos_bub() ) { return; // No effect } if( is_hallucination() ) { - die( nullptr ); + die( &here, nullptr ); return; } tripoint_bub_ms to = pos_bub(); diff --git a/src/creature.h b/src/creature.h index 1ebb43b5718d3..1eb27e2ea6093 100644 --- a/src/creature.h +++ b/src/creature.h @@ -46,6 +46,7 @@ class effects_map; class field; class field_entry; class item; +class map; class monster; class nc_color; class npc; @@ -317,7 +318,9 @@ class Creature : public viewer return pos_abs().z(); } virtual void gravity_check(); + virtual void gravity_check( map *here ); void setpos( const tripoint_bub_ms &p, bool check_gravity = true ); + void setpos( map *here, const tripoint_bub_ms &p, bool check_gravity = true ); /** Checks if the creature fits confortably into a given tile. */ bool will_be_cramped_in_vehicle_tile( const tripoint_abs_ms &loc ) const; @@ -337,7 +340,7 @@ class Creature : public viewer /** Adds an appropriate blood splatter. */ virtual void bleed() const; /** Empty function. Should always be overwritten by the appropriate player/NPC/monster version. */ - virtual void die( Creature *killer ) = 0; + virtual void die( map *here, Creature *killer ) = 0; /** Should always be overwritten by the appropriate player/NPC/monster version. */ virtual float hit_roll() const = 0; @@ -469,7 +472,7 @@ class Creature : public viewer // Makes a ranged projectile attack against the creature // Sets relevant values in `attack`. - virtual void deal_projectile_attack( Creature *source, dealt_projectile_attack &attack, + virtual void deal_projectile_attack( map *here, Creature *source, dealt_projectile_attack &attack, const double &missed_by = 0, bool print_messages = true, const weakpoint_attack &wp_attack = weakpoint_attack() ); @@ -533,7 +536,7 @@ class Creature : public viewer * This creature just got hit by an attack - possibly special/ranged attack - from source. * Players should train dodge, possibly counter-attack somehow. */ - virtual void on_hit( Creature *source, bodypart_id bp_hit, + virtual void on_hit( map *here, Creature *source, bodypart_id bp_hit, float difficulty = INT_MIN, dealt_projectile_attack const *proj = nullptr ) = 0; /** Returns true if this monster has a gun-type attack or the RANGED_ATTACKER flag*/ @@ -605,7 +608,7 @@ class Creature : public viewer * much damage has been dealt, how the attack was performed, what has been blocked...), do * it *before* calling this function. */ - void check_dead_state(); + void check_dead_state( map *here ); /** Processes move stopping effects. Returns false if movement is stopped. */ virtual bool move_effects( bool attacking ) = 0; diff --git a/src/creature_tracker.cpp b/src/creature_tracker.cpp index 5212f5554196d..d9f99bebcb712 100644 --- a/src/creature_tracker.cpp +++ b/src/creature_tracker.cpp @@ -68,6 +68,7 @@ shared_ptr_fast creature_tracker::from_temporary_id( const int id ) bool creature_tracker::add( const shared_ptr_fast &critter_ptr ) { cata_assert( critter_ptr ); + map *here = &get_map(); monster &critter = *critter_ptr; if( critter.type->id.is_null() ) { // Don't want to spawn null monsters o.O @@ -77,7 +78,7 @@ bool creature_tracker::add( const shared_ptr_fast &critter_ptr ) if( const shared_ptr_fast existing_mon_ptr = find( critter.pos_abs() ) ) { // We can spawn stuff on hallucinations, but we need to kill them first if( existing_mon_ptr->is_hallucination() ) { - existing_mon_ptr->die( nullptr ); + existing_mon_ptr->die( here, nullptr ); // But don't remove - that would change the monster order and could segfault } else if( critter.is_hallucination() ) { return false; @@ -104,6 +105,8 @@ size_t creature_tracker::size() const bool creature_tracker::update_pos( const monster &critter, const tripoint_abs_ms &old_pos, const tripoint_abs_ms &new_pos ) { + map &here = get_map(); + if( critter.is_dead() ) { // find ignores dead critters anyway, changing their position in the // monsters_by_location map is useless. @@ -114,7 +117,7 @@ bool creature_tracker::update_pos( const monster &critter, const tripoint_abs_ms if( const shared_ptr_fast new_critter_ptr = find( new_pos ) ) { auto &othermon = *new_critter_ptr; if( othermon.is_hallucination() ) { - othermon.die( nullptr ); + othermon.die( &here, nullptr ); } else { debugmsg( "update_zombie_pos: wanted to move %s to %s, but new location already has %s", critter.disp_name(), new_pos.to_string_writable(), othermon.disp_name() ); @@ -257,6 +260,7 @@ void creature_tracker::swap_positions( monster &first, monster &second ) bool creature_tracker::kill_marked_for_death() { + map &here = get_map(); // Important: `Creature::die` must not be called after creature objects (NPCs, monsters) have // been removed, the dying creature could still have a pointer (the killer) to another creature. bool monster_is_dead = false; @@ -272,7 +276,7 @@ bool creature_tracker::kill_marked_for_death() dbg( D_INFO ) << string_format( "cleanup_dead: critter at %s hp:%d %s", critter.pos_abs().to_string_writable(), critter.get_hp(), critter.name() ); - critter.die( nullptr ); + critter.die( &here, nullptr ); monster_is_dead = true; } diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index 4dcb6361fb7a2..71f4cd68fed51 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -3398,7 +3398,7 @@ static void damage_self() if( query_int( dbg_damage, _( "Damage self for how much? HP: %s" ), part.id().c_str() ) ) { player_character.apply_damage( nullptr, part, dbg_damage ); if( player_character.is_dead_state() ) { - player_character.die( nullptr ); + player_character.die( &get_map(), nullptr ); } } } @@ -3492,6 +3492,7 @@ static void import_folower() static void kill_area() { + map &here = get_map(); static_popup popup; popup.on_top( true ); popup.message( "%s", _( "Select first point." ) ); @@ -3521,7 +3522,7 @@ static void kill_area() } ); for( Creature *critter : creatures ) { - critter->die( nullptr ); + critter->die( &here, nullptr ); } g->cleanup_dead(); @@ -4053,7 +4054,7 @@ void debug() // Use the normal death functions, useful for testing death // and for getting a corpse. if( critter.type->id != mon_generator ) { - critter.die( nullptr ); + critter.die( &here, nullptr ); } } g->cleanup_dead(); diff --git a/src/do_turn.cpp b/src/do_turn.cpp index 5c01daf866dd3..c8b1249ecdf22 100644 --- a/src/do_turn.cpp +++ b/src/do_turn.cpp @@ -267,6 +267,9 @@ void monmove() avatar &u = get_avatar(); for( monster &critter : g->all_monsters() ) { + if( !m.inbounds( critter.pos_abs() ) ) { + continue; + } // Critters in impassable tiles get pushed away, unless it's not impassable for them if( !critter.is_dead() && ( m.impassable( critter.pos_bub() ) && !m.get_impassable_field_at( critter.pos_bub() ).has_value() ) && @@ -288,7 +291,7 @@ void monmove() } if( !okay ) { // die of "natural" cause (overpopulation is natural) - critter.die( nullptr ); + critter.die( &m, nullptr ); } } diff --git a/src/explosion.cpp b/src/explosion.cpp index 77851621c3d4c..3c9550d0bf350 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -350,7 +350,7 @@ static void do_blast( map *m, const Creature *source, const tripoint_bub_ms &p, bodypart_id( "torso" ) ) / 2.0, 0.0 ); const int actual_dmg = rng_float( dmg * 2, dmg * 3 ); critter->apply_damage( mutable_source, bodypart_id( "torso" ), actual_dmg ); - critter->check_dead_state(); + critter->check_dead_state( m ); add_msg_debug( debugmode::DF_EXPLOSION, "Blast hits %s for %d damage", critter->disp_name(), actual_dmg ); continue; @@ -466,7 +466,7 @@ static std::vector shrapnel( map *m, const Creature *source, frag.proj.impact = damage_instance( damage_bullet, damage ); for( int i = 0; i < hits; ++i ) { frag.missed_by = rng_float( 0.05, 1.0 / critter->ranged_target_size() ); - critter->deal_projectile_attack( mutable_source, frag, frag.missed_by, false ); + critter->deal_projectile_attack( m, mutable_source, frag, frag.missed_by, false ); add_msg_debug( debugmode::DF_EXPLOSION, "Shrapnel hit %s at %d m/s at a distance of %d", critter->disp_name(), frag.proj.speed, rl_dist( src, target ) ); @@ -754,7 +754,7 @@ void emp_blast( const tripoint_bub_ms &p ) } int dam = dice( 10, 10 ); critter.apply_damage( nullptr, bodypart_id( "torso" ), dam ); - critter.check_dead_state(); + critter.check_dead_state( &here ); if( !critter.is_dead() && one_in( 6 ) ) { critter.make_friendly(); } @@ -774,7 +774,7 @@ void emp_blast( const tripoint_bub_ms &p ) } critter.add_effect( effect_emp, 1_minutes ); critter.apply_damage( nullptr, bodypart_id( "torso" ), dam ); - critter.check_dead_state(); + critter.check_dead_state( &here ); } } else if( sight ) { add_msg( _( "The %s is unaffected by the EMP blast." ), critter.name() ); @@ -952,6 +952,7 @@ void process_explosions() process_explosions_in_progress = true; m.load( origo, false, false ); m.spawn_monsters( true, true ); + g->load_npcs( &m ); process_explosions_in_progress = false; _make_explosion( &m, ex.source, m.get_bub( ex.pos ), ex.data ); } else { diff --git a/src/game.cpp b/src/game.cpp index 6762e6a4f1c5d..7bdb40cd3f38f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1240,8 +1240,9 @@ vehicle *game::place_vehicle_nearby( //Make any nearby overmap npcs active, and put them in the right location. void game::load_npcs() { + map &here = get_map(); const int radius = HALF_MAPSIZE - 1; - const tripoint_abs_sm abs_sub( get_map().get_abs_sub() ); + const tripoint_abs_sm abs_sub( here.get_abs_sub() ); const half_open_rectangle map_bounds( abs_sub.xy(), abs_sub.xy() + point( MAPSIZE, MAPSIZE ) ); // uses submap coordinates @@ -1272,14 +1273,71 @@ void game::load_npcs() add_msg_debug( debugmode::DF_NPC, "game::load_npcs: Spawning static NPC, %s %s", abs_sub.to_string_writable(), sm_loc.to_string_writable() ); - temp->place_on_map(); + temp->place_on_map( &here ); if( !m.inbounds( temp->pos_bub() ) ) { continue; } // In the rare case the npc was marked for death while // it was on the overmap. Kill it. if( temp->marked_for_death ) { - temp->die( nullptr ); + temp->die( &here, nullptr ); + } else { + critter_tracker->active_npc.push_back( temp ); + just_added.push_back( temp ); + } + } + + for( const auto &npc : just_added ) { + npc->on_load( &here ); + } + + npcs_dirty = false; +} + +void game::load_npcs( map *here ) +{ + const int mapsize = here->getmapsize(); + const int radius = mapsize / 2 - 1; + const tripoint_abs_sm abs_sub( here->get_abs_sub() ); + const tripoint_abs_sm center = abs_sub + point_rel_sm{radius, radius}; + const half_open_rectangle map_bounds( abs_sub.xy(), abs_sub.xy() + point( mapsize, + mapsize ) ); + // uses submap coordinates + std::vector> just_added; + for( const auto &temp : overmap_buffer.get_npcs_near( center, radius ) ) { + const character_id &id = temp->getID(); + const auto found = std::find_if( critter_tracker->active_npc.begin(), + critter_tracker->active_npc.end(), + [id]( const shared_ptr_fast &n ) { + return n->getID() == id; + } ); + if( found != critter_tracker->active_npc.end() ) { + continue; + } + if( temp->is_active() ) { + continue; + } + if( temp->has_companion_mission() ) { + continue; + } + + const tripoint_abs_sm sm_loc = temp->pos_abs_sm(); + // NPCs who are out of bounds before placement would be pushed into bounds + // This can cause NPCs to teleport around, so we don't want that + if( !map_bounds.contains( sm_loc.xy() ) ) { + continue; + } + + add_msg_debug( debugmode::DF_NPC, "game::load_npcs: Spawning static NPC, %s %s", + abs_sub.to_string_writable(), sm_loc.to_string_writable() ); + temp->place_on_map( here ); + if( !here->inbounds( temp->pos_abs() ) ) { + continue; + } + // In the rare case the npc was marked for death while + // it was on the overmap. Kill it. + if( temp->marked_for_death ) { + temp->die( here, nullptr ); } else { critter_tracker->active_npc.push_back( temp ); just_added.push_back( temp ); @@ -1287,7 +1345,7 @@ void game::load_npcs() } for( const auto &npc : just_added ) { - npc->on_load(); + npc->on_load( here ); } npcs_dirty = false; @@ -1502,6 +1560,8 @@ void game::set_driving_view_offset( const point_rel_ms &p ) void game::catch_a_monster( monster *fish, const tripoint_bub_ms &pos, Character *p, const time_duration &catch_duration ) // catching function { + map &here = get_map(); + //spawn the corpse, rotten by a part of the duration m.add_item_or_charges( pos, item::make_corpse( fish->type->id, calendar::turn + rng( 0_turns, catch_duration ) ) ); @@ -1510,7 +1570,7 @@ void game::catch_a_monster( monster *fish, const tripoint_bub_ms &pos, Character } //quietly kill the caught fish->no_corpse_quiet = true; - fish->die( p ); + fish->die( &here, p ); } static bool cancel_auto_move( Character &you, const std::string &text ) @@ -2871,6 +2931,8 @@ bool game::try_get_right_click_action( action_id &act, const tripoint_bub_ms &mo bool game::is_game_over() { + map &here = get_map(); + if( uquit == QUIT_DIED || uquit == QUIT_WATCH ) { Creature *player_killer = u.get_killer(); if( player_killer && player_killer->as_character() ) { @@ -2893,7 +2955,7 @@ bool game::is_game_over() if( u.in_vehicle ) { m.unboard_vehicle( u.pos_bub() ); } - u.place_corpse(); + u.place_corpse( &here ); return true; } if( uquit == QUIT_SUICIDE ) { @@ -4750,6 +4812,8 @@ void game::mon_info_update( ) void game::cleanup_dead() { + map &here = get_map(); + // Dead monsters need to stay in the tracker until everything else that needs to die does so // This is because dying monsters can still interact with other dying monsters (@ref Creature::killer) bool monster_is_dead = critter_tracker->kill_marked_for_death(); @@ -4758,7 +4822,7 @@ void game::cleanup_dead() // can't use all_npcs as that does not include dead ones for( const auto &n : critter_tracker->active_npc ) { if( n->is_dead() ) { - n->die( nullptr ); // make sure this has been called to create corpses etc. + n->die( &here, nullptr ); // make sure this has been called to create corpses etc. npc_is_dead = true; } } @@ -4811,6 +4875,7 @@ void game::knockback( std::vector &traj, int stun, int dam_mult // the header file says higher force causes more damage. // perhaps that is what it should do? tripoint_bub_ms tp = traj.front(); + map &here = get_map(); creature_tracker &creatures = get_creature_tracker(); if( !creatures.creature_at( tp ) ) { debugmsg( _( "Nothing at (%d,%d,%d) to knockback!" ), tp.x(), tp.y(), tp.z() ); @@ -4831,7 +4896,7 @@ void game::knockback( std::vector &traj, int stun, int dam_mult add_msg( _( "%s was stunned!" ), targ->name() ); add_msg( _( "%s slammed into an obstacle!" ), targ->name() ); targ->apply_damage( nullptr, bodypart_id( "torso" ), dam_mult * force_remaining ); - targ->check_dead_state(); + targ->check_dead_state( &here ); } m.bash( traj[i], 2 * dam_mult * force_remaining ); break; @@ -4863,7 +4928,7 @@ void game::knockback( std::vector &traj, int stun, int dam_mult targ->setpos( traj[i] ); if( m.has_flag( ter_furn_flag::TFLAG_LIQUID, targ->pos_bub() ) && !targ->can_drown() && !targ->is_dead() ) { - targ->die( nullptr ); + targ->die( &here, nullptr ); if( u.sees( *targ ) ) { add_msg( _( "The %s drowns!" ), targ->name() ); } @@ -4871,7 +4936,7 @@ void game::knockback( std::vector &traj, int stun, int dam_mult if( !m.has_flag( ter_furn_flag::TFLAG_LIQUID, targ->pos_bub() ) && targ->has_flag( mon_flag_AQUATIC ) && !targ->is_dead() ) { - targ->die( nullptr ); + targ->die( &here, nullptr ); if( u.sees( *targ ) ) { add_msg( _( "The %s flops around and dies!" ), targ->name() ); } @@ -4905,7 +4970,7 @@ void game::knockback( std::vector &traj, int stun, int dam_mult targ->deal_damage( nullptr, bp, damage_instance( damage_bash, force_remaining * dam_mult ) ); } } - targ->check_dead_state(); + targ->check_dead_state( &here ); } m.bash( traj[i], 2 * dam_mult * force_remaining ); break; @@ -4978,7 +5043,7 @@ void game::knockback( std::vector &traj, int stun, int dam_mult u.deal_damage( nullptr, bp, damage_instance( damage_bash, force_remaining * dam_mult ) ); } } - u.check_dead_state(); + u.check_dead_state( &here ); } m.bash( traj[i], 2 * dam_mult * force_remaining ); break; @@ -5520,6 +5585,13 @@ bool game::is_empty( const tripoint_bub_ms &p ) get_creature_tracker().creature_at( p ) == nullptr; } +bool game::is_empty( map *here, const tripoint_abs_ms &p ) +{ + const tripoint_bub_ms pos = here->get_bub( p ); + return ( here->passable( pos ) || here->has_flag( ter_furn_flag::TFLAG_LIQUID, pos ) ) && + get_creature_tracker().creature_at( p ) == nullptr; +} + bool game::is_in_sunlight( const tripoint_bub_ms &p ) { return !is_sheltered( p ) && @@ -11966,6 +12038,7 @@ void game::water_affect_items( Character &ch ) const bool game::fling_creature( Creature *c, const units::angle &dir, float flvel, bool controlled, bool intentional ) { + map &here = get_map(); if( c == nullptr ) { debugmsg( "game::fling_creature invoked on null target" ); return false; @@ -12047,7 +12120,7 @@ bool game::fling_creature( Creature *c, const units::angle &dir, float flvel, bo ( damage - critter.get_armor_type( damage_bash, bodypart_id( "torso" ) ) ) * 6 ); // TODO: Pass the "flinger" here - it's not the flung critter that deals damage critter.apply_damage( c, bodypart_id( "torso" ), zed_damage ); - critter.check_dead_state(); + critter.check_dead_state( &here ); if( !critter.is_dead() ) { thru = false; } diff --git a/src/game.h b/src/game.h index 90831f12d145a..c2a5cfcf7f4d7 100644 --- a/src/game.h +++ b/src/game.h @@ -501,6 +501,7 @@ class game /** Returns true if there is no player, NPC, or monster on the tile and move_cost > 0. */ bool is_empty( const tripoint_bub_ms &p ); + bool is_empty( map *here, const tripoint_abs_ms &p ); /** Returns true if p is outdoors and it is sunny. */ bool is_in_sunlight( const tripoint_bub_ms &p ); bool is_in_sunlight( map *here, const tripoint_bub_ms &p ); @@ -545,6 +546,7 @@ class game npc *find_npc_by_unique_id( const std::string &unique_id ); /** Makes any nearby NPCs on the overmap active. */ void load_npcs(); + void load_npcs( map *here ); /** NPCs who saw player interacting with their stuff (disassembling, cutting etc) * will notify the player that thievery was witnessed and make angry at the player. */ diff --git a/src/gates.cpp b/src/gates.cpp index c44c635b8e578..4698f5b91fd29 100644 --- a/src/gates.cpp +++ b/src/gates.cpp @@ -421,7 +421,7 @@ bool doors::forced_door_closing( const tripoint_bub_ms &p, critter.die_in_explosion( nullptr ); } else { critter.apply_damage( nullptr, bodypart_id( "torso" ), bash_dmg ); - critter.check_dead_state(); + critter.check_dead_state( &m ); } if( !critter.is_dead() && critter.get_size() >= creature_size::huge ) { // big critters simply prevent the gate from closing diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 8c2a3fa28d723..75e1715a2bedf 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1102,7 +1102,7 @@ avatar::smash_result avatar::smash( tripoint_bub_ms &smashp ) rng( 0, static_cast( vol * .5 ) ) ) ); } remove_weapon(); - check_dead_state(); + check_dead_state( &here ); } } } @@ -2235,6 +2235,8 @@ static std::map get_actions_disabled_mounted() bool game::do_regular_action( action_id &act, avatar &player_character, const std::optional &mouse_target ) { + map &here = get_map(); + item_location weapon = player_character.get_wielded_item(); const bool in_shell = player_character.has_active_mutation( trait_SHELL2 ) || player_character.has_active_mutation( trait_SHELL3 ); @@ -2824,7 +2826,7 @@ bool game::do_regular_action( action_id &act, avatar &player_character, if( query_yn( _( "Abandon this character?" ) ) ) { if( query_yn( _( "This will kill your character. Continue?" ) ) ) { player_character.set_moves( 0 ); - player_character.place_corpse(); + player_character.place_corpse( &here ); uquit = QUIT_SUICIDE; } } diff --git a/src/item.cpp b/src/item.cpp index 565c75307d774..a48af8552bf3a 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -10713,6 +10713,15 @@ bool item::spill_contents( const tripoint_bub_ms &pos ) return contents.spill_contents( pos ); } +bool item::spill_contents( map *here, const tripoint_bub_ms &pos ) +{ + if( ( !is_container() && !is_magazine() && !uses_magazine() ) || + is_container_empty() ) { + return true; + } + return contents.spill_contents( here, pos ); +} + bool item::spill_open_pockets( Character &guy, const item *avoid ) { return contents.spill_open_pockets( guy, avoid ); diff --git a/src/item.h b/src/item.h index 60db8900668e8..2c453a37671b0 100644 --- a/src/item.h +++ b/src/item.h @@ -1872,6 +1872,7 @@ class item : public visitable * @return If the item is now empty. */ bool spill_contents( const tripoint_bub_ms &pos ); + bool spill_contents( map *here, const tripoint_bub_ms &pos ); bool spill_open_pockets( Character &guy, const item *avoid = nullptr ); /** Spill items that don't fit in the container. */ void overflow( const tripoint_bub_ms &pos, const item_location &loc = item_location::nowhere ); diff --git a/src/item_contents.cpp b/src/item_contents.cpp index e2509c7381a3b..f56eb269d6a14 100644 --- a/src/item_contents.cpp +++ b/src/item_contents.cpp @@ -1225,6 +1225,17 @@ bool item_contents::spill_contents( const tripoint_bub_ms &pos ) return spilled; } +bool item_contents::spill_contents( map *here, const tripoint_bub_ms &pos ) +{ + bool spilled = false; + for( item_pocket &pocket : contents ) { + if( !pocket.get_pocket_data()->_no_unload ) { + spilled = pocket.spill_contents( here, pos ) || spilled; + } + } + return spilled; +} + void item_contents::overflow( const tripoint_bub_ms &pos, const item_location &loc ) { for( item_pocket &pocket : contents ) { diff --git a/src/item_contents.h b/src/item_contents.h index c06a70a84f29d..c74dc968d55bc 100644 --- a/src/item_contents.h +++ b/src/item_contents.h @@ -25,6 +25,7 @@ class JsonOut; class item; class item_location; class iteminfo_query; +class map; struct iteminfo; struct tripoint; @@ -305,6 +306,7 @@ class item_contents item_pocket *contained_where( const item &contained ); void on_pickup( Character &guy, item *avoid = nullptr ); bool spill_contents( const tripoint_bub_ms &pos ); + bool spill_contents( map *here, const tripoint_bub_ms &pos ); /** Spill items that don't fit in the container. */ void overflow( const tripoint_bub_ms &pos, const item_location &loc ); void clear_items(); diff --git a/src/item_pocket.cpp b/src/item_pocket.cpp index e2ff9e18deb2a..19bd7ffe8a219 100644 --- a/src/item_pocket.cpp +++ b/src/item_pocket.cpp @@ -1899,15 +1899,19 @@ void item_pocket::on_contents_changed() } bool item_pocket::spill_contents( const tripoint_bub_ms &pos ) +{ + return item_pocket::spill_contents( &get_map(), pos ); +} + +bool item_pocket::spill_contents( map *here, const tripoint_bub_ms &pos ) { if( is_type( pocket_type::E_FILE_STORAGE ) || is_type( pocket_type::CORPSE ) || is_type( pocket_type::CABLE ) ) { return false; } - map &here = get_map(); for( item &it : contents ) { - here.add_item_or_charges( pos, it ); + here->add_item_or_charges( pos, it ); } contents.clear(); diff --git a/src/item_pocket.h b/src/item_pocket.h index e670300eea852..0fb88717d098c 100644 --- a/src/item_pocket.h +++ b/src/item_pocket.h @@ -28,6 +28,7 @@ class JsonObject; class JsonOut; class item; class item_location; +class map; class pocket_data; struct iteminfo; struct itype; @@ -292,6 +293,7 @@ class item_pocket // spills any contents that can't fit into the pocket, largest items first void overflow( const tripoint_bub_ms &pos, const item_location &loc ); bool spill_contents( const tripoint_bub_ms &pos ); + bool spill_contents( map *here, const tripoint_bub_ms &pos ); void on_pickup( Character &guy, item *avoid = nullptr ); void on_contents_changed(); void handle_liquid_or_spill( Character &guy, const item *avoid = nullptr ); diff --git a/src/iuse.cpp b/src/iuse.cpp index 43555c0979d4b..3395ec5196d96 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -745,7 +745,7 @@ std::optional iuse::fungicide( Character *p, item *, const tripoint_bub_ms critter.name() ); } if( !critter.make_fungus() ) { - critter.die( p ); // counts as kill by player + critter.die( &here, p ); // counts as kill by player } } else { g->place_critter_at( mon_spore, dest ); @@ -1567,6 +1567,8 @@ std::optional iuse::mycus( Character *p, item *, const tripoint_bub_ms & ) std::optional iuse::petfood( Character *p, item *it, const tripoint_bub_ms & ) { + map &here = get_map(); + if( !it->is_comestible() ) { p->add_msg_if_player( _( "You doubt someone would want to eat %1$s." ), it->tname() ); return std::nullopt; @@ -1622,7 +1624,7 @@ std::optional iuse::petfood( Character *p, item *it, const tripoint_bub_ms if( halluc && one_in( 4 ) ) { p->add_msg_if_player( _( "You try to feed the %1$s some %2$s, but it vanishes!" ), mon->type->nname(), it->tname() ); - mon->die( nullptr ); + mon->die( &here, nullptr ); return std::nullopt; } @@ -4051,6 +4053,8 @@ std::optional iuse::solarpack( Character *p, item *it, const tripoint_bub_m std::optional iuse::solarpack_off( Character *p, item *it, const tripoint_bub_ms & ) { + map &here = get_map(); + if( !p ) { debugmsg( "%s called action solarpack_off that requires character but no character is present", it->typeId().str() ); @@ -4067,7 +4071,7 @@ std::optional iuse::solarpack_off( Character *p, item *it, const tripoint_b // 3 = "_on" it->convert( itype_id( it->typeId().str().substr( 0, it->typeId().str().size() - 3 ) ), p ).active = false; - p->process_items(); // Process carried items to disconnect any connected cables + p->process_items( &here ); // Process carried items to disconnect any connected cables return 0; } diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 61bdbd0f19503..d5305235b55d4 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -589,7 +589,7 @@ static void damage_targets( const spell &sp, Creature &caster, val.amount = roll_remainder( val.amount / multishot ); } for( int i = 0; i < multishot; ++i ) { - cr->deal_projectile_attack( cr, atk, atk.missed_by, true ); + cr->deal_projectile_attack( &here, cr, atk, atk.missed_by, true ); } } else if( sp.has_flag( spell_flag::SPLIT_DAMAGE ) ) { int amount_of_bp = target_bdpts.size(); @@ -607,7 +607,7 @@ static void damage_targets( const spell &sp, Creature &caster, } } } else { - cr->deal_projectile_attack( &caster, atk, atk.missed_by, true ); + cr->deal_projectile_attack( &here, &caster, atk, atk.missed_by, true ); } } @@ -617,7 +617,7 @@ static void damage_targets( const spell &sp, Creature &caster, val.amount = cr->get_hp() * sp.damage( caster ) / 100.0; } } - cr->deal_projectile_attack( &caster, atk, atk.missed_by, true ); + cr->deal_projectile_attack( &here, &caster, atk, atk.missed_by, true ); } } else if( sp.damage( caster ) < 0 ) { sp.heal( target, caster ); @@ -1821,6 +1821,7 @@ void spell_effect::dash( const spell &sp, Creature &caster, const tripoint_bub_m void spell_effect::banishment( const spell &sp, Creature &caster, const tripoint_bub_ms &target ) { + class map &here = get_map(); // "map" is overridden by a spell_effect operation... int total_dam = sp.damage( caster ); if( total_dam <= 0 ) { debugmsg( "ERROR: Banishment has negative or 0 damage value" ); @@ -1888,7 +1889,7 @@ void spell_effect::banishment( const spell &sp, Creature &caster, const tripoint caster.add_msg_if_player( m_good, string_format( _( "%s banished." ), mon->name() ) ); // banished monsters take their stuff with them mon->death_drops = false; - mon->die( &caster ); + mon->die( &here, &caster ); } } diff --git a/src/map.cpp b/src/map.cpp index 97928a9101e3f..504465f13aadf 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2986,18 +2986,18 @@ void map::drop_fields( const tripoint_bub_ms &p ) } } -void map::drop_creature( const tripoint_bub_ms &p ) const +void map::drop_creature( const tripoint_bub_ms &p ) { monster *mon_at_p = get_creature_tracker().creature_at( p ); if( mon_at_p ) { - mon_at_p->gravity_check(); + mon_at_p->gravity_check( this ); // Handle character potentially standing on monster ("zed walking") drop_creature( p + tripoint_rel_ms::above ); return; } Character *char_at_p = get_creature_tracker().creature_at( p ); if( char_at_p ) { - char_at_p->gravity_check(); + char_at_p->gravity_check( this ); } } @@ -3843,16 +3843,20 @@ void map::smash_items( const tripoint_bub_ms &p, int power, const std::string &c // Let the player know that the item was damaged if they can see it. if( items_destroyed > 1 ) { - add_msg_if_player_sees( p, m_bad, _( "The %s destroys several items!" ), cause_message ); + add_msg_if_player_sees( get_map().get_bub( get_abs( p ) ), m_bad, + _( "The %s destroys several items!" ), cause_message ); } else if( items_destroyed == 1 && items_damaged == 1 ) { //~ %1$s: the cause of destruction, %2$s: destroyed item name - add_msg_if_player_sees( p, m_bad, _( "The %1$s destroys the %2$s!" ), cause_message, + add_msg_if_player_sees( get_map().get_bub( get_abs( p ) ), m_bad, + _( "The %1$s destroys the %2$s!" ), cause_message, damaged_item_name ); } else if( items_damaged > 1 ) { - add_msg_if_player_sees( p, m_bad, _( "The %s damages several items." ), cause_message ); + add_msg_if_player_sees( get_map().get_bub( get_abs( p ) ), m_bad, + _( "The %s damages several items." ), cause_message ); } else if( items_damaged == 1 ) { //~ %1$s: the cause of damage, %2$s: damaged item name - add_msg_if_player_sees( p, m_bad, _( "The %1$s damages the %2$s." ), cause_message, + add_msg_if_player_sees( get_map().get_bub( get_abs( p ) ), m_bad, _( "The %1$s damages the %2$s." ), + cause_message, damaged_item_name ); } @@ -4392,7 +4396,7 @@ void map::crush( const tripoint_bub_ms &p ) // Pin whoever got hit crushed_player->add_effect( effect_crushed, 1_turns, true ); - crushed_player->check_dead_state(); + crushed_player->check_dead_state( this ); } } @@ -4403,7 +4407,7 @@ void map::crush( const tripoint_bub_ms &p ) // Pin whoever got hit monhit->add_effect( effect_crushed, 1_turns, true ); - monhit->check_dead_state(); + monhit->check_dead_state( this ); } if( const optional_vpart_position vp = veh_at( p ) ) { @@ -5062,7 +5066,7 @@ item_location map::add_item_ret_loc( const tripoint_bub_ms &pos, item obj, bool std::pair ret = _add_item_or_charges( pos, std::move( obj ), copies, overflow ); if( ret.first != nullptr && !ret.first->is_null() ) { - return item_location{ map_cursor{ tripoint_bub_ms( ret.second ) }, ret.first }; + return item_location{ map_cursor{ get_abs( ret.second ) }, ret.first }; } return {}; @@ -9320,8 +9324,8 @@ void map::build_obstacle_cache( } // Iterate over creatures and set them to block their squares relative to their size. for( Creature &critter : g->all_creatures() ) { - const tripoint_bub_ms loc = critter.pos_bub(); - if( loc.z() != start.z() ) { + const tripoint_bub_ms loc = get_bub( critter.pos_abs() ); + if( loc.z() != start.z() || !inbounds( loc ) ) { continue; } // TODO: scale this with expected creature "thickness". diff --git a/src/map.h b/src/map.h index bf953eff5670c..0f79891026aeb 100644 --- a/src/map.h +++ b/src/map.h @@ -1632,7 +1632,7 @@ class map void drop_items( const tripoint_bub_ms &p ); void drop_vehicle( const tripoint_bub_ms &p ); void drop_fields( const tripoint_bub_ms &p ); - void drop_creature( const tripoint_bub_ms &p ) const; + void drop_creature( const tripoint_bub_ms &p ); /*@}*/ public: /** diff --git a/src/map_field.cpp b/src/map_field.cpp index 88bc27b61afb7..9c38e0fd0f2e3 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -812,7 +812,7 @@ static void field_processor_fd_push_items( const tripoint_bub_ms &p, field_entry add_msg( m_bad, _( "A %s hits you!" ), tmp.tname() ); const bodypart_id hit = pd.player_character.get_random_body_part(); pd.player_character.deal_damage( nullptr, hit, damage_instance( damage_bash, 6 ) ); - pd.player_character.check_dead_state(); + pd.player_character.check_dead_state( &pd.here ); } if( npc *const n = creatures.creature_at( newp ) ) { @@ -820,12 +820,12 @@ static void field_processor_fd_push_items( const tripoint_bub_ms &p, field_entry const bodypart_id hit = pd.player_character.get_random_body_part(); n->deal_damage( nullptr, hit, damage_instance( damage_bash, 6 ) ); add_msg_if_player_sees( newp, _( "A %1$s hits %2$s!" ), tmp.tname(), n->get_name() ); - n->check_dead_state(); + n->check_dead_state( &pd.here ); } else if( monster *const mon = creatures.creature_at( newp ) ) { mon->apply_damage( nullptr, bodypart_id( "torso" ), 6 - mon->get_armor_type( damage_bash, bodypart_id( "torso" ) ) ); add_msg_if_player_sees( newp, _( "A %1$s hits the %2$s!" ), tmp.tname(), mon->name() ); - mon->check_dead_state(); + mon->check_dead_state( &pd.here ); } } else { pushee++; @@ -1446,13 +1446,13 @@ If you wish for a field effect to do something over time (propagate, interact wi void map::player_in_field( Character &you ) { // A copy of the current field for reference. Do not add fields to it, use map::add_field - field &curfield = get_field( you.pos_bub() ); + field &curfield = get_field( get_bub( you.pos_abs() ) ); // Are we inside? bool inside = false; // If we are in a vehicle figure out if we are inside (reduces effects usually) // and what part of the vehicle we need to deal with. if( you.in_vehicle ) { - if( const optional_vpart_position vp = veh_at( you.pos_bub() ) ) { + if( const optional_vpart_position vp = veh_at( you.pos_abs() ) ) { inside = vp->is_inside(); } } @@ -1507,14 +1507,14 @@ void map::player_in_field( Character &you ) you.add_msg_if_player( m_warning, _( "You're standing in a pool of acid!" ) ); } - you.check_dead_state(); + you.check_dead_state( this ); } } if( ft == fd_sap ) { // Sap does nothing to cars. if( !you.in_vehicle ) { // Use up sap. - mod_field_intensity( you.pos_bub(), ft, -1 ); + mod_field_intensity( get_bub( you.pos_abs() ), ft, -1 ); } } if( ft == fd_sludge ) { @@ -1608,7 +1608,7 @@ void map::player_in_field( Character &you ) } else { you.add_msg_if_player( m_warning, _( player_warn_msg[msg_num] ) ); } - you.check_dead_state(); + you.check_dead_state( this ); } } @@ -1655,7 +1655,7 @@ void map::player_in_field( Character &you ) you.deal_damage( nullptr, bodypart_id( "leg_l" ), damage_instance( damage_heat, rng( 2, 6 ) ) ); you.deal_damage( nullptr, bodypart_id( "leg_r" ), damage_instance( damage_heat, rng( 2, 6 ) ) ); you.deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( damage_heat, rng( 4, 9 ) ) ); - you.check_dead_state(); + you.check_dead_state( this ); } else { you.add_msg_player_or_npc( _( "These flames do not burn you." ), _( "Those flames do not burn ." ) ); @@ -1834,11 +1834,11 @@ void map::monster_in_field( monster &z ) // Digging monsters are immune to fields return; } - if( veh_at( z.pos_bub() ) ) { + if( veh_at( z.pos_abs() ) ) { // FIXME: Immune when in a vehicle for now. return; } - field &curfield = get_field( z.pos_bub() ); + field &curfield = get_field( get_bub( z.pos_abs() ) ); int dam = 0; // Iterate through all field effects on this tile. @@ -1854,13 +1854,13 @@ void map::monster_in_field( monster &z ) if( !z.flies() ) { const int d = rng( cur.get_field_intensity(), cur.get_field_intensity() * 3 ); z.deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( damage_acid, d ) ); - z.check_dead_state(); + z.check_dead_state( this ); } } if( cur_field_type == fd_sap ) { z.mod_moves( -cur.get_field_intensity() * 5 ); - mod_field_intensity( z.pos_bub(), cur.get_field_type(), -1 ); + mod_field_intensity( get_bub( z.pos_abs() ), cur.get_field_type(), -1 ); } if( cur_field_type == fd_sludge ) { if( !z.digs() && !z.flies() && @@ -2073,7 +2073,7 @@ void map::monster_in_field( monster &z ) if( dam > 0 ) { z.apply_damage( nullptr, bodypart_id( "torso" ), dam, true ); - z.check_dead_state(); + z.check_dead_state( this ); } } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index e6052d9ac1576..984af20c57bd1 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -5050,7 +5050,7 @@ bool jmapgen_setmap::apply( const mapgendata &dat, const tripoint_rel_ms &offset Creature *tmp_critter = get_creature_tracker().creature_at( m.get_abs( target_pos ), true ); if( tmp_critter && !tmp_critter->is_avatar() ) { - tmp_critter->die( nullptr ); + tmp_critter->die( &m, nullptr ); } } break; @@ -5152,7 +5152,7 @@ bool jmapgen_setmap::apply( const mapgendata &dat, const tripoint_rel_ms &offset tripoint_bub_ms( i.x(), i.y(), z_level ) ) ), true ); if( tmp_critter && !tmp_critter->is_avatar() ) { - tmp_critter->die( nullptr ); + tmp_critter->die( &m, nullptr ); } } } @@ -5235,7 +5235,7 @@ bool jmapgen_setmap::apply( const mapgendata &dat, const tripoint_rel_ms &offset tripoint_bub_ms( tx, ty, z_level ) ) ), true ); if( tmp_critter && !tmp_critter->is_avatar() ) { - tmp_critter->die( nullptr ); + tmp_critter->die( &m, nullptr ); } } } diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index fc67db5d89ec5..5d39a65e64e05 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -675,6 +675,8 @@ int melee_actor::do_grab( monster &z, Creature *target, bodypart_id bp_id ) cons bool melee_actor::call( monster &z ) const { + map &here = get_map(); + Creature *target = find_target( z ); if( target == nullptr ) { return false; @@ -854,7 +856,7 @@ bool melee_actor::call( monster &z ) const dealt_damage.bp_hit = bp_id; // On hit effects - target->on_hit( &z, bp_id ); + target->on_hit( &here, &z, bp_id ); // Apply onhit self effects for( const mon_effect_data &eff : self_effects_onhit ) { diff --git a/src/melee.cpp b/src/melee.cpp index 788695ecf163e..1be56074ab926 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -570,6 +570,8 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, const matec_id &force_technique, bool allow_unarmed, int forced_movecost ) { + map &here = get_map(); + if( !enough_working_legs() ) { if( !movement_mode_is( move_mode_prone ) ) { add_msg_if_player( m_bad, _( "Your broken legs cannot hold you and you fall down." ) ); @@ -903,7 +905,7 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, } - t.check_dead_state(); + t.check_dead_state( &here ); if( t.is_dead_state() ) { // trigger martial arts on-kill effects @@ -938,11 +940,11 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, // trigger martial arts on-attack effects martial_arts_data->ma_onattack_effects( *this ); // some things (shattering weapons) can harm the attacking creature. - check_dead_state(); + check_dead_state( &here ); did_hit( t ); if( t.as_character() ) { dealt_projectile_attack dp = dealt_projectile_attack(); - t.as_character()->on_hit( this, bodypart_str_id::NULL_ID().id(), 0.0f, &dp ); + t.as_character()->on_hit( &here, this, bodypart_str_id::NULL_ID().id(), 0.0f, &dp ); } return true; } diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index b26505e2e8ccc..67cb714e2f1c9 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -2856,7 +2856,7 @@ std::set talk_function::loot_building( const tripoint_abs_omt &site, //Kill zombies! Only works against pre-spawned enemies at the moment... Creature *critter = creatures.creature_at( rebase_bub( p ) ); if( critter != nullptr ) { - critter->die( nullptr ); + critter->die( bay.cast_to_map(), nullptr ); } //Hoover up tasty items! map_stack items = bay.i_at( p ); diff --git a/src/monattack.cpp b/src/monattack.cpp index af9dbf9042cf2..5b341f9f65fa0 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -765,6 +765,8 @@ bool mattack::acid( monster *z ) bool mattack::acid_barf( monster *z ) { + map &here = get_map(); + if( !z->can_act() ) { return false; } @@ -822,7 +824,7 @@ bool mattack::acid_barf( monster *z ) body_part_name_accusative( hit ) ); } - target->on_hit( z, hit, z->type->melee_skill ); + target->on_hit( &here, z, hit, z->type->melee_skill ); return true; } @@ -1513,7 +1515,7 @@ bool mattack::vine( monster *z ) d.add_damage( damage_cut, 8 ); d.add_damage( damage_bash, 8 ); critter->deal_damage( z, bphit, d ); - critter->check_dead_state(); + critter->check_dead_state( &here ); z->mod_moves( -to_moves( 1_seconds ) ); return true; } @@ -1762,6 +1764,7 @@ bool mattack::fungus_big_blossom( monster *z ) bool mattack::fungus_inject( monster *z ) { + map &here = get_map(); // For faster copy+paste Creature *target = &get_player_character(); Character &player_character = get_player_character(); @@ -1818,14 +1821,16 @@ bool mattack::fungus_inject( monster *z ) body_part_name_accusative( hit ) ); } - target->on_hit( z, hit, z->type->melee_skill ); - player_character.check_dead_state(); + target->on_hit( &here, z, hit, z->type->melee_skill ); + player_character.check_dead_state( &here ); return true; } bool mattack::fungus_bristle( monster *z ) { + map &here = get_map(); + Character &player_character = get_player_character(); if( player_character.has_trait( trait_THRESH_MARLOSS ) || player_character.has_trait( trait_THRESH_MYCUS ) ) { @@ -1874,7 +1879,7 @@ bool mattack::fungus_bristle( monster *z ) z->name(), body_part_name_accusative( hit ) ); } - target->on_hit( z, hit, z->type->melee_skill ); + target->on_hit( &here, z, hit, z->type->melee_skill ); return true; } @@ -2000,7 +2005,7 @@ bool mattack::fungus_fortify( monster *z ) add_msg( m_bad, _( "A fungal tendril bursts forth from the earth and pierces your %s!" ), body_part_name_accusative( hit ) ); player_character.deal_damage( z, hit, damage_instance( damage_cut, rng( 5, 11 ) ) ); - player_character.check_dead_state(); + player_character.check_dead_state( &here ); // Probably doesn't have spores available *just* yet. Let's be nice. } else if( monster *const tendril = g->place_critter_at( mon_fungal_tendril, hit_pos ) ) { add_msg( m_bad, _( "A fungal tendril bursts forth from the earth!" ) ); @@ -2040,8 +2045,8 @@ bool mattack::fungus_fortify( monster *z ) body_part_name_accusative( hit ) ); } - target->on_hit( z, hit, z->type->melee_skill ); - player_character.check_dead_state(); + target->on_hit( &here, z, hit, z->type->melee_skill ); + player_character.check_dead_state( &here ); return true; } @@ -2093,7 +2098,7 @@ bool mattack::depart( monster *z ) } z->no_corpse_quiet = true; z->no_extra_death_drops = true; - z->die( nullptr ); + z->die( &here, nullptr ); return true; } @@ -2657,6 +2662,8 @@ bool mattack::check_money_left( monster *z ) } bool mattack::photograph( monster *z ) { + map &here = get_map(); + if( !within_visual_range( z, 6 ) ) { return false; } @@ -2674,7 +2681,7 @@ bool mattack::photograph( monster *z ) z->name() ); z->no_corpse_quiet = true; z->no_extra_death_drops = true; - z->die( nullptr ); + z->die( &here, nullptr ); return false; } else { add_msg( m_info, @@ -2694,7 +2701,7 @@ bool mattack::photograph( monster *z ) z->name() ); z->no_corpse_quiet = true; z->no_extra_death_drops = true; - z->die( nullptr ); + z->die( &here, nullptr ); return false; } else { add_msg( m_info, @@ -2712,7 +2719,7 @@ bool mattack::photograph( monster *z ) z->name() ); z->no_corpse_quiet = true; z->no_extra_death_drops = true; - z->die( nullptr ); + z->die( &here, nullptr ); return false; } else { add_msg( m_info, _( "The %s acknowledges you as SWAT onsite, but hangs around to watch." ), @@ -2729,7 +2736,7 @@ bool mattack::photograph( monster *z ) add_msg( m_info, _( "The %s flashes a LED and departs. The Feds got this." ), z->name() ); z->no_corpse_quiet = true; z->no_extra_death_drops = true; - z->die( nullptr ); + z->die( &here, nullptr ); return false; } } @@ -2797,6 +2804,8 @@ bool mattack::tazer( monster *z ) void mattack::taze( monster *z, Creature *target ) { + map &here = get_map(); + // It takes a while z->mod_moves( -to_moves( 2_seconds ) ); if( target == nullptr ) { @@ -2837,7 +2846,7 @@ void mattack::taze( monster *z, Creature *target ) _( "The %s shocks you!" ), _( "The %s shocks !" ), z->name() ); - target->check_dead_state(); + target->check_dead_state( &here ); } bool mattack::searchlight( monster *z ) @@ -3246,6 +3255,8 @@ bool mattack::brandish( monster *z ) bool mattack::flesh_golem( monster *z ) { + map &here = get_map(); + if( !z->can_act() ) { return false; } @@ -3300,7 +3311,7 @@ bool mattack::flesh_golem( monster *z ) //~ 1$s is bodypart name, 2$d is damage value. target->add_msg_if_player( m_bad, _( "Your %1$s is battered for %2$d damage!" ), body_part_name( hit ), dam ); - target->on_hit( z, hit, z->type->melee_skill ); + target->on_hit( &here, z, hit, z->type->melee_skill ); return true; } @@ -3362,6 +3373,8 @@ bool mattack::absorb_meat( monster *z ) bool mattack::lunge( monster *z ) { + map &here = get_map(); + if( !z->can_act() ) { return false; } @@ -3430,8 +3443,8 @@ bool mattack::lunge( monster *z ) if( one_in( 6 ) ) { target->add_effect( effect_downed, 3_turns ); } - target->on_hit( z, hit, z->type->melee_skill ); - target->check_dead_state(); + target->on_hit( &here, z, hit, z->type->melee_skill ); + target->check_dead_state( &here ); return true; } @@ -4072,6 +4085,8 @@ bool mattack::bio_op_random_biojutsu( monster *z ) bool mattack::bio_op_takedown( monster *z ) { + map &here = get_map(); + if( !z->can_act() ) { return false; } @@ -4111,7 +4126,7 @@ bool mattack::bio_op_takedown( monster *z ) if( seen ) { add_msg( _( "%1$s slams %2$s to the ground!" ), z->name(), target->disp_name() ); } - target->check_dead_state(); + target->check_dead_state( &here ); return true; } // Yes, it has the CQC bionic. @@ -4173,14 +4188,16 @@ bool mattack::bio_op_takedown( monster *z ) target->add_msg_if_player( m_bad, _( "and slams you for %d damage!" ), dam ); foe->deal_damage( z, bodypart_id( "torso" ), damage_instance( damage_bash, dam ) ); } - target->on_hit( z, hit, z->type->melee_skill ); - foe->check_dead_state(); + target->on_hit( &here, z, hit, z->type->melee_skill ); + foe->check_dead_state( &here ); return true; } bool mattack::bio_op_impale( monster *z ) { + map &here = get_map(); + if( !z->can_act() ) { return false; } @@ -4228,7 +4245,7 @@ bool mattack::bio_op_impale( monster *z ) if( seen ) { add_msg( _( "The %1$s impales %2$s!" ), z->name(), target->disp_name() ); } - target->check_dead_state(); + target->check_dead_state( &here ); return true; } @@ -4251,8 +4268,8 @@ bool mattack::bio_op_impale( monster *z ) _( "but fails to penetrate 's armor!" ) ); } - target->on_hit( z, hit, z->type->melee_skill ); - foe->check_dead_state(); + target->on_hit( &here, z, hit, z->type->melee_skill ); + foe->check_dead_state( &here ); return true; } @@ -4325,17 +4342,21 @@ bool mattack::bio_op_disarm( monster *z ) bool mattack::suicide( monster *z ) { + map &here = get_map(); + Creature *target = z->attack_target(); if( !within_target_range( z, target, 2 ) ) { return false; } - z->die( z ); + z->die( &here, z ); return false; } bool mattack::kamikaze( monster *z ) { + map &here = get_map(); + if( z->ammo.empty() ) { // We somehow lost our ammo! Toggle this special off so we stop processing debugmsg( "Missing ammo in kamikaze special for %s.", z->name() ); @@ -4376,7 +4397,7 @@ bool mattack::kamikaze( monster *z ) // HACK: HORRIBLE HACK ALERT! Remove the following code completely once we have working monster inventory processing if( z->has_effect( effect_countdown ) ) { if( z->get_effect( effect_countdown ).get_duration() == 1_turns ) { - z->die( nullptr ); + z->die( &here, nullptr ); // Timer is out, detonate item i_explodes( act_bomb_type, calendar::turn ); i_explodes.active = true; @@ -4621,9 +4642,11 @@ bool mattack::grenadier_elite( monster *const z ) bool mattack::zombie_fuse( monster *z ) { + map &here = get_map(); + monster *critter = nullptr; creature_tracker &creatures = get_creature_tracker(); - for( const tripoint_bub_ms &p : get_map().points_in_radius( z->pos_bub(), 1 ) ) { + for( const tripoint_bub_ms &p : here.points_in_radius( z->pos_bub(), 1 ) ) { critter = creatures.creature_at( p ); if( critter != nullptr && critter->faction == z->faction && critter != z && critter->get_size() <= z->get_size() ) { @@ -4657,7 +4680,7 @@ bool mattack::zombie_fuse( monster *z ) } critter->death_drops = false; critter->quiet_death = true; - critter->die( z ); + critter->die( &here, z ); return true; } diff --git a/src/mondeath.cpp b/src/mondeath.cpp index d24ae9079c82c..9139ed8c8692f 100644 --- a/src/mondeath.cpp +++ b/src/mondeath.cpp @@ -54,14 +54,14 @@ static const harvest_drop_type_id harvest_drop_flesh( "flesh" ); static const species_id species_ZOMBIE( "ZOMBIE" ); -item_location mdeath::normal( monster &z ) +item_location mdeath::normal( map *here, monster &z ) { if( z.no_corpse_quiet ) { return {}; } if( !z.quiet_death && !z.has_flag( mon_flag_QUIETDEATH ) ) { - if( z.type->in_species( species_ZOMBIE ) ) { + if( z.type->in_species( species_ZOMBIE ) && get_map().inbounds( z.pos_abs() ) ) { sfx::play_variant_sound( "mon_death", "zombie_death", sfx::get_heard_volume( z.pos_bub() ) ); } @@ -78,16 +78,17 @@ item_location mdeath::normal( monster &z ) z.bleed(); // leave some blood if we have to if( pulverized ) { - return splatter( z ); + return splatter( here, z ); } else { const float damage = std::floor( corpse_damage * itype::damage_scale ); - return make_mon_corpse( z, static_cast( damage ) ); + return make_mon_corpse( here, z, static_cast( damage ) ); } } return {}; } -static void scatter_chunks( const itype_id &chunk_name, int chunk_amt, monster &z, int distance, +static void scatter_chunks( map *here, const itype_id &chunk_name, int chunk_amt, monster &z, + int distance, int pile_size = 1 ) { // can't have less than one item in a pile or it would cause an infinite loop @@ -96,24 +97,24 @@ static void scatter_chunks( const itype_id &chunk_name, int chunk_amt, monster & pile_size = std::min( chunk_amt, pile_size ); distance = std::abs( distance ); const item chunk( chunk_name, calendar::turn ); - map &here = get_map(); int placed_chunks = 0; while( placed_chunks < chunk_amt ) { bool drop_chunks = true; - tripoint_bub_ms tarp( z.pos_bub() + point( rng( -distance, distance ), rng( -distance, - distance ) ) ); - const std::vector traj = line_to( z.pos_bub(), tarp ); + tripoint_bub_ms tarp( here->get_bub( z.pos_abs() ) + point( rng( -distance, distance ), + rng( -distance, + distance ) ) ); + const std::vector traj = line_to( here->get_bub( z.pos_abs() ), tarp ); for( size_t j = 0; j < traj.size(); j++ ) { tarp = traj[j]; if( one_in( 2 ) && z.bloodType().id() ) { - here.add_splatter( z.bloodType(), tarp ); + here->add_splatter( z.bloodType(), tarp ); } else { - here.add_splatter( z.gibType(), tarp, rng( 1, j + 1 ) ); + here->add_splatter( z.gibType(), tarp, rng( 1, j + 1 ) ); } - if( here.impassable( tarp ) ) { - here.bash( tarp, distance ); - if( here.impassable( tarp ) ) { + if( here->impassable( tarp ) ) { + here->bash( tarp, distance ); + if( here->impassable( tarp ) ) { // Target is obstacle, not destroyed by bashing, // stop trajectory in front of it, if this is the first // point (e.g. wall adjacent to monster), don't drop anything on it @@ -128,14 +129,14 @@ static void scatter_chunks( const itype_id &chunk_name, int chunk_amt, monster & } if( drop_chunks ) { for( int i = placed_chunks; i < chunk_amt && i < placed_chunks + pile_size; i++ ) { - here.add_item_or_charges( tarp, chunk ); + here->add_item_or_charges( tarp, chunk ); } } placed_chunks += pile_size; } } -item_location mdeath::splatter( monster &z ) +item_location mdeath::splatter( map *here, monster &z ) { const bool gibbable = !z.type->has_flag( mon_flag_NOGIB ); @@ -146,19 +147,21 @@ item_location mdeath::splatter( monster &z ) const field_type_id type_blood = z.bloodType(); const field_type_id type_gib = z.gibType(); - map &here = get_map(); if( gibbable ) { - const tripoint_range area = here.points_in_radius( z.pos_bub(), 1 ); + const tripoint_range area = here->points_in_radius( here->get_bub( z.pos_abs() ), + 1 ); int number_of_gibs = std::min( std::floor( corpse_damage ) - 1, 1 + max_hp / 5.0f ); if( z.type->size >= creature_size::medium ) { number_of_gibs += rng( 1, 6 ); - sfx::play_variant_sound( "mon_death", "zombie_gibbed", sfx::get_heard_volume( z.pos_bub() ) ); + if( get_map().inbounds( z.pos_abs() ) ) { + sfx::play_variant_sound( "mon_death", "zombie_gibbed", sfx::get_heard_volume( z.pos_bub() ) ); + } } for( int i = 0; i < number_of_gibs; ++i ) { - here.add_splatter( type_gib, random_entry( area ), rng( 1, i + 1 ) ); - here.add_splatter( type_blood, random_entry( area ) ); + here->add_splatter( type_gib, random_entry( area ), rng( 1, i + 1 ) ); + here->add_splatter( type_blood, random_entry( area ) ); } } // 1% of the weight of the monster is the base, with overflow damage as a multiplier @@ -178,7 +181,7 @@ item_location mdeath::splatter( monster &z ) const int chunk_amt = entry.mass_ratio / overflow_ratio / 10 * z.get_weight() / item::find_type( itype_id( entry.drop ) )->weight; - scatter_chunks( itype_id( entry.drop ), chunk_amt, z, gib_distance, + scatter_chunks( here, itype_id( entry.drop ), chunk_amt, z, gib_distance, chunk_amt / ( gib_distance - 1 ) ); gibbed_weight -= entry.mass_ratio / overflow_ratio / 20 * to_gram( z.get_weight() ); } @@ -187,7 +190,7 @@ item_location mdeath::splatter( monster &z ) const itype_id &leftover_id = z.type->id->harvest->leftovers; const int chunk_amount = gibbed_weight / to_gram( item::find_type( leftover_id )->weight ); - scatter_chunks( leftover_id, chunk_amount, z, gib_distance, + scatter_chunks( here, leftover_id, chunk_amount, z, gib_distance, chunk_amount / ( gib_distance + 1 ) ); } // add corpse with gib flag @@ -204,7 +207,7 @@ item_location mdeath::splatter( monster &z ) if( !z.has_eaten_enough() ) { corpse.set_flag( STATIC( flag_id( "UNDERFED" ) ) ); } - return here.add_item_ret_loc( z.pos_bub(), corpse ); + return here->add_item_ret_loc( here->get_bub( z.pos_abs() ), corpse ); } return {}; } @@ -216,7 +219,7 @@ void mdeath::disappear( monster &z ) } } -void mdeath::broken( monster &z ) +void mdeath::broken( map *here, monster &z ) { // Bail out if flagged (simulates eyebot flying away) if( z.no_corpse_quiet ) { @@ -236,8 +239,7 @@ void mdeath::broken( monster &z ) const float corpse_damage = 2.5 * overflow_damage / max_hp; broken_mon.set_damage( static_cast( std::floor( corpse_damage * itype::damage_scale ) ) ); - map &here = get_map(); - here.add_item_or_charges( z.pos_bub(), broken_mon ); + here->add_item_or_charges( here->get_bub( z.pos_abs() ), broken_mon ); if( z.type->has_flag( mon_flag_DROPS_AMMO ) ) { for( const std::pair &ammo_entry : z.ammo ) { @@ -260,15 +262,15 @@ void mdeath::broken( monster &z ) mags.insert( mags.end(), mag ); ammo_count -= mag.type->magazine->capacity; } - here.spawn_items( z.pos_bub(), mags ); + here->spawn_items( here->get_bub( z.pos_abs() ), mags ); spawned = true; break; } } } if( !spawned ) { - here.spawn_item( z.pos_bub(), ammo_entry.first, ammo_entry.second, 1, - calendar::turn ); + here->spawn_item( here->get_bub( z.pos_abs() ), ammo_entry.first, ammo_entry.second, 1, + calendar::turn ); } } } @@ -282,7 +284,7 @@ void mdeath::broken( monster &z ) } } -item_location make_mon_corpse( monster &z, int damageLvl ) +item_location make_mon_corpse( map *here, monster &z, int damageLvl ) { item corpse = item::make_corpse( z.type->id, calendar::turn, z.unique_name, z.get_upgrade_time() ); // All corpses are at 37 C at time of death @@ -297,5 +299,5 @@ item_location make_mon_corpse( monster &z, int damageLvl ) if( !z.has_eaten_enough() ) { corpse.set_flag( STATIC( flag_id( "UNDERFED" ) ) ); } - return get_map().add_item_ret_loc( z.pos_bub(), corpse ); + return here->add_item_ret_loc( here->get_bub( z.pos_abs() ), corpse ); } diff --git a/src/mondeath.h b/src/mondeath.h index 0f1e09e0b4106..99434963db170 100644 --- a/src/mondeath.h +++ b/src/mondeath.h @@ -4,20 +4,21 @@ #include "item.h" +class map; class monster; namespace mdeath { // Drop a body -item_location normal( monster &z ); +item_location normal( map *here, monster &z ); // Overkill splatter (also part of normal under conditions) -item_location splatter( monster &z ); +item_location splatter( map *here, monster &z ); // Hallucination disappears void disappear( monster &z ); // Broken robot drop -void broken( monster &z ); +void broken( map *here, monster &z ); } //namespace mdeath -item_location make_mon_corpse( monster &z, int damageLvl ); +item_location make_mon_corpse( map *here, monster &z, int damageLvl ); #endif // CATA_SRC_MONDEATH_H diff --git a/src/mondefense.cpp b/src/mondefense.cpp index e9756b902d406..68c94492b5475 100644 --- a/src/mondefense.cpp +++ b/src/mondefense.cpp @@ -47,6 +47,8 @@ void mdefense::none( monster &, Creature *, const dealt_projectile_attack * ) void mdefense::zapback( monster &m, Creature *const source, dealt_projectile_attack const *proj ) { + map &here = get_map(); + if( source == nullptr ) { return; } @@ -87,7 +89,7 @@ void mdefense::zapback( monster &m, Creature *const source, source->deal_damage( &m, bodypart_id( "arm_l" ), shock ); source->deal_damage( &m, bodypart_id( "arm_r" ), shock ); - source->check_dead_state(); + source->check_dead_state( &here ); } void mdefense::acidsplash( monster &m, Creature *const source, diff --git a/src/monmove.cpp b/src/monmove.cpp index f80c1a176f97a..0a903781218f7 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -798,9 +798,11 @@ bool monster::is_aquatic_danger( const tripoint_bub_ms &at_pos ) const bool monster::die_if_drowning( const tripoint_bub_ms &at_pos, const int chance ) { + map &here = get_map(); + if( is_aquatic_danger( at_pos ) && one_in( chance ) ) { add_msg_if_player_sees( at_pos, _( "The %s drowns!" ), name() ); - die( nullptr ); + die( &here, nullptr ); return true; } return false; @@ -814,6 +816,8 @@ bool monster::die_if_drowning( const tripoint_bub_ms &at_pos, const int chance ) // 4) Sound-based tracking void monster::move() { + map &here = get_map(); + add_msg_debug( debugmode::DF_MONMOVE, "Monster %s starting monmove::move, remaining moves %d", name(), moves ); // We decrement wandf no matter what. We'll save our wander_to plans until @@ -824,10 +828,9 @@ void monster::move() //Hallucinations have a chance of disappearing each turn if( is_hallucination() && one_in( 25 ) ) { - die( nullptr ); + die( &here, nullptr ); return; } - map &here = get_map(); Character &player_character = get_player_character(); behavior::monster_oracle_t oracle( this ); @@ -2054,6 +2057,8 @@ bool monster::move_to( const tripoint_bub_ms &p, bool force, bool step_on_critte bool monster::push_to( const tripoint_bub_ms &p, const int boost, const size_t depth ) { + map &here = get_map(); + if( is_hallucination() ) { // Don't let hallucinations push, not even other hallucinations return false; @@ -2078,7 +2083,7 @@ bool monster::push_to( const tripoint_bub_ms &p, const int boost, const size_t d if( critter->is_hallucination() ) { // Kill the hallu, but return false so that the regular move_to is uses instead - critter->die( nullptr ); + critter->die( &here, nullptr ); return false; } @@ -2090,7 +2095,6 @@ bool monster::push_to( const tripoint_bub_ms &p, const int boost, const size_t d return false; } - map &here = get_map(); const int movecost_from = 50 * here.move_cost( p ); const int movecost_attacker = std::max( movecost_from, 200 - 10 * ( attack - defend ) ); const tripoint_rel_ms dir = p - pos_bub(); @@ -2153,7 +2157,7 @@ bool monster::push_to( const tripoint_bub_ms &p, const int boost, const size_t d critter_recur = creatures.creature_at( dest ); if( critter_recur != nullptr ) { if( critter_recur->is_hallucination() ) { - critter_recur->die( nullptr ); + critter_recur->die( &here, nullptr ); } } else if( !critter->has_flag( mon_flag_IMMOBILE ) ) { critter->setpos( dest ); @@ -2241,12 +2245,14 @@ void monster::stumble() void monster::knock_back_to( const tripoint_bub_ms &to ) { + map &here = get_map(); + if( to == pos_bub() ) { return; // No effect } if( is_hallucination() ) { - die( nullptr ); + die( &here, nullptr ); return; } @@ -2265,7 +2271,7 @@ void monster::knock_back_to( const tripoint_bub_ms &to ) z->apply_damage( this, bodypart_id( "torso" ), static_cast( type->size ) ); z->add_effect( effect_stunned, 1_turns ); } - z->check_dead_state(); + z->check_dead_state( &here ); if( u_see ) { add_msg( _( "The %1$s bounces off a %2$s!" ), name(), z->name() ); @@ -2283,7 +2289,7 @@ void monster::knock_back_to( const tripoint_bub_ms &to ) add_msg( _( "The %1$s bounces off %2$s!" ), name(), p->get_name() ); } - p->check_dead_state(); + p->check_dead_state( &here ); return; } @@ -2291,13 +2297,12 @@ void monster::knock_back_to( const tripoint_bub_ms &to ) // die_if_drowning will kill the monster if necessary, but if the deep water // tile is on a vehicle, we should check for swimmers out of water if( !die_if_drowning( to ) && has_flag( mon_flag_AQUATIC ) ) { - die( nullptr ); + die( &here, nullptr ); if( u_see ) { add_msg( _( "The %s flops around and dies!" ), name() ); } } - map &here = get_map(); // It's some kind of wall. if( here.impassable( to ) ) { const int dam = static_cast( type->size ); @@ -2311,7 +2316,7 @@ void monster::knock_back_to( const tripoint_bub_ms &to ) } else { // It's no wall setpos( to ); } - check_dead_state(); + check_dead_state( &here ); } /* will_reach() is used for determining whether we'll get to stairs (and diff --git a/src/monster.cpp b/src/monster.cpp index 99d07357c8e07..b9b04545c34e4 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -385,9 +385,14 @@ bool monster::can_upgrade() const void monster::gravity_check() { - map &here = get_map(); - if( here.is_open_air( pos_bub() ) && !flies() ) { - here.try_fall( pos_bub(), this ); + monster::gravity_check( &get_map() ); +} + +void monster::gravity_check( map *here ) +{ + const tripoint_bub_ms pos = here->get_bub( pos_abs() ); + if( here->is_open_air( pos ) && !flies() ) { + here->try_fall( pos, this ); } } @@ -440,6 +445,8 @@ int monster::next_upgrade_time() void monster::try_upgrade( bool pin_time ) { + map &here = get_map(); + if( !can_upgrade() ) { return; } @@ -513,7 +520,7 @@ void monster::try_upgrade( bool pin_time ) if( type->upgrade_null_despawn ) { g->remove_zombie( *this ); } else { - die( nullptr ); + die( &here, nullptr ); } return; } @@ -2050,6 +2057,7 @@ bool monster::melee_attack( Creature &target ) bool monster::melee_attack( Creature &target, float accuracy ) { + map &here = get_map(); // Note: currently this method must consume move even if attack hasn't actually happen // otherwise infinite loop will happen mod_moves( -type->attack_cost ); @@ -2200,11 +2208,11 @@ bool monster::melee_attack( Creature &target, float accuracy ) } } - target.check_dead_state(); + target.check_dead_state( &here ); if( is_hallucination() ) { if( one_in( 7 ) ) { - die( nullptr ); + die( &here, nullptr ); } return true; } @@ -2248,7 +2256,7 @@ bool monster::melee_attack( Creature &target, float accuracy ) return true; } -void monster::deal_projectile_attack( Creature *source, dealt_projectile_attack &attack, +void monster::deal_projectile_attack( map *here, Creature *source, dealt_projectile_attack &attack, const double &missed_by, bool print_messages, const weakpoint_attack &wp_attack ) { @@ -2265,11 +2273,11 @@ void monster::deal_projectile_attack( Creature *source, dealt_projectile_attack return; } - Creature::deal_projectile_attack( source, attack, missed_by, print_messages, wp_attack ); + Creature::deal_projectile_attack( here, source, attack, missed_by, print_messages, wp_attack ); if( !is_hallucination() && attack.last_hit_critter == this ) { // Maybe TODO: Get difficulty from projectile speed/size/missed_by - on_hit( source, bodypart_id( "torso" ), INT_MIN, &attack ); + on_hit( here, source, bodypart_id( "torso" ), INT_MIN, &attack ); } } @@ -2345,8 +2353,10 @@ void monster::apply_damage( Creature *source, bodypart_id /*bp*/, int dam, void monster::die_in_explosion( Creature *source ) { + map &here = get_map(); + hp = -9999; // huge to trigger explosion and prevent corpse item - die( source ); + die( &here, source ); } void monster::heal_bp( bodypart_id, int dam ) @@ -2902,7 +2912,7 @@ void monster::process_turn() Creature::process_turn(); } -void monster::die( Creature *nkiller ) +void monster::die( map *here, Creature *nkiller ) { if( dead ) { // We are already dead, don't die again, note that monster::dead is @@ -2935,19 +2945,19 @@ void monster::die( Creature *nkiller ) } } } - map &here = get_map(); creature_tracker &creatures = get_creature_tracker(); if( has_effect_with_flag( json_flag_GRAB_FILTER ) ) { // Need to filter out which limb we were grabbing before death - for( const tripoint_bub_ms &player_pos : here.points_in_radius( pos_bub(), 1, 0 ) ) { - Creature *you = creatures.creature_at( player_pos ); + for( const tripoint_bub_ms &player_pos : here->points_in_radius( here->get_bub( pos_abs() ), 1, + 0 ) ) { + Creature *you = creatures.creature_at( here->get_abs( player_pos ) ); if( !you || !you->has_effect_with_flag( json_flag_GRAB ) ) { continue; } // ...but if there are no grabbers around we can just skip to the end bool grabbed = false; - for( const tripoint_bub_ms &mon_pos : here.points_in_radius( player_pos, 1, 0 ) ) { - const monster *const mon = creatures.creature_at( mon_pos ); + for( const tripoint_bub_ms &mon_pos : here->points_in_radius( player_pos, 1, 0 ) ) { + const monster *const mon = creatures.creature_at( here->get_abs( mon_pos ) ); // No persisting our grabs from beyond the grave, but we also don't get to remove the effect early if( mon && mon->has_effect_with_flag( json_flag_GRAB_FILTER ) && mon != this ) { grabbed = true; @@ -2977,7 +2987,7 @@ void monster::die( Creature *nkiller ) if( !is_hallucination() && has_flag( mon_flag_QUEEN ) ) { // The submap coordinates of this monster, monster groups coordinates are // submap coordinates. - const tripoint_abs_sm abssub = coords::project_to( here.get_abs( pos_bub() ) ); + const tripoint_abs_sm abssub = coords::project_to( pos_abs() ); // Do it for overmap above/below too for( const tripoint_abs_sm &p : points_in_radius( abssub, HALF_MAPSIZE, 1 ) ) { for( mongroup *&mgp : overmap_buffer.groups_at( p ) ) { @@ -3001,10 +3011,13 @@ void monster::die( Creature *nkiller ) //Not a hallucination, go process the death effects. spell death_spell = type->mdeath_effect.sp.get_spell( *this ); if( killer != nullptr && !type->mdeath_effect.sp.self && - death_spell.is_target_in_range( *this, killer->pos_bub() ) ) { - death_spell.cast_all_effects( *this, killer->pos_bub() ); + // TODO: Get the death_spell stuff to work on any map. + death_spell.is_target_in_range( *this, + killer->pos_bub() ) ) { // The operation called uses reality bubble internally + death_spell.cast_all_effects( *this, + killer->pos_bub() ); // ditto, so we should feed them pos_bub(). } else if( type->mdeath_effect.sp.self ) { - death_spell.cast_all_effects( *this, pos_bub() ); + death_spell.cast_all_effects( *this, pos_bub() ); // ditto. } } @@ -3030,13 +3043,13 @@ void monster::die( Creature *nkiller ) // drop a corpse, or not - this needs to happen after the spell, for e.g. revivification effects switch( type->mdeath_effect.corpse_type ) { case mdeath_type::NORMAL: - corpse = mdeath::normal( *this ); + corpse = mdeath::normal( here, *this ); break; case mdeath_type::BROKEN: - mdeath::broken( *this ); + mdeath::broken( here, *this ); break; case mdeath_type::SPLATTER: - corpse = mdeath::splatter( *this ); + corpse = mdeath::splatter( here, *this ); break; default: break; @@ -3059,7 +3072,7 @@ void monster::die( Creature *nkiller ) } if( death_drops && !no_extra_death_drops ) { - drop_items_on_death( corpse.get_item() ); + drop_items_on_death( here, corpse.get_item() ); spawn_dissectables_on_death( corpse.get_item() ); } if( death_drops && !is_hallucination() ) { @@ -3070,20 +3083,22 @@ void monster::die( Creature *nkiller ) if( corpse ) { corpse->force_insert_item( it, pocket_type::CONTAINER ); } else { - get_map().add_item_or_charges( pos_bub(), it ); + here->add_item_or_charges( here->get_bub( pos_abs() ), it ); } } for( const item &it : dissectable_inv ) { if( corpse ) { corpse->put_in( it, pocket_type::CORPSE ); } else { - get_map().add_item( pos_bub(), it ); + here->add_item( here->get_bub( pos_abs() ), it ); } } } if( corpse ) { - corpse->process( get_map(), nullptr, corpse.pos_bub() ); - corpse.make_active(); + corpse->process( *here, nullptr, corpse.pos_bub() ); + if( get_map().inbounds( pos_abs() ) ) { + corpse.make_active(); + } } // Adjust anger/morale of nearby monsters, if they have the appropriate trigger and are friendly @@ -3178,7 +3193,7 @@ void monster::generate_inventory( bool disableDrops ) no_extra_death_drops = disableDrops; } -void monster::drop_items_on_death( item *corpse ) +void monster::drop_items_on_death( map *here, item *corpse ) { if( is_hallucination() ) { return; @@ -3198,7 +3213,7 @@ void monster::drop_items_on_death( item *corpse ) // for non corpses this is much simpler if( !corpse ) { for( item &it : new_items ) { - get_map().add_item_or_charges( pos_bub(), it ); + here->add_item_or_charges( here->get_bub( pos_abs() ), it ); } return; } @@ -3774,7 +3789,7 @@ void monster::on_dodge( Creature *, float, float ) // Currently does nothing, later should handle faction relations } -void monster::on_hit( Creature *source, bodypart_id, +void monster::on_hit( map *here, Creature *source, bodypart_id, float, dealt_projectile_attack const *const proj ) { if( is_hallucination() ) { @@ -3793,14 +3808,13 @@ void monster::on_hit( Creature *source, bodypart_id, if( trigger ) { int light = g->light_level( posz() ); - map &here = get_map(); for( monster &critter : g->all_monsters() ) { // Do we actually care about this faction? if( critter.faction->attitude( faction ) != MFA_FRIENDLY ) { continue; } - if( here.sees( critter.pos_bub(), pos_bub(), light ) ) { + if( here->sees( here->get_bub( critter.pos_abs() ), here->get_bub( pos_abs() ), light ) ) { // Anger trumps fear trumps ennui if( critter.type->has_anger_trigger( mon_trigger::FRIEND_ATTACKED ) ) { critter.anger += 15; @@ -3826,7 +3840,7 @@ void monster::on_hit( Creature *source, bodypart_id, enchantment_cache->cast_hit_me( *this, source ); - check_dead_state(); + check_dead_state( here ); // TODO: Faction relations } diff --git a/src/monster.h b/src/monster.h index 50591316d1d11..794016ff1f1d0 100644 --- a/src/monster.h +++ b/src/monster.h @@ -33,6 +33,7 @@ class JsonOut; class effect; class effect_source; class item; +class map; struct monster_plan; namespace catacurses { @@ -109,6 +110,7 @@ class monster : public Creature return faction.id(); } void gravity_check() override; + void gravity_check( map *here ) override; void poly( const mtype_id &id ); bool can_upgrade() const; void hasten_upgrade(); @@ -366,7 +368,7 @@ class monster : public Creature bool melee_attack( Creature &target ); bool melee_attack( Creature &target, float accuracy ); void melee_attack( Creature &p, bool ) = delete; - void deal_projectile_attack( Creature *source, dealt_projectile_attack &attack, + void deal_projectile_attack( map *here, Creature *source, dealt_projectile_attack &attack, const double &missed_by = 0, bool print_messages = true, const weakpoint_attack &wp_attack = weakpoint_attack() ) override; void deal_damage_handle_type( const effect_source &source, const damage_unit &du, bodypart_id bp, @@ -439,7 +441,7 @@ class monster : public Creature void on_dodge( Creature *source, float difficulty, float training_level = 0.0 ) override; void on_try_dodge() override {} // Something hit us (possibly null source) - void on_hit( Creature *source, bodypart_id bp_hit, + void on_hit( map *here, Creature *source, bodypart_id bp_hit, float difficulty = INT_MIN, dealt_projectile_attack const *proj = nullptr ) override; /** Resets a given special to its monster type cooldown value */ @@ -461,8 +463,8 @@ class monster : public Creature /** Resets stats, and applies effects in an idempotent manner */ void reset_stats() override; - void die( Creature *killer ) override; //this is the die from Creature, it calls kill_mo - void drop_items_on_death( item *corpse ); + void die( map *here, Creature *killer ) override; //this is the die from Creature, it calls kill_mo + void drop_items_on_death( map *here, item *corpse ); void spawn_dissectables_on_death( item *corpse ) const; //spawn dissectable CBMs into CORPSE pocket //spawn monster's inventory without killing it void generate_inventory( bool disableDrops = true ); diff --git a/src/npc.cpp b/src/npc.cpp index 1ecb0b7c2162e..e53d09736e4f3 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1169,15 +1169,15 @@ void npc::spawn_at_precise( const tripoint_abs_ms &p ) set_pos_abs_only( p ); } -void npc::place_on_map() +void npc::place_on_map( map *here ) { - if( g->is_empty( pos_bub() ) || is_mounted() ) { + if( g->is_empty( here, pos_abs() ) || is_mounted() ) { return; } - for( const tripoint_bub_ms &p : closest_points_first( pos_bub(), SEEX + 1 ) ) { - if( g->is_empty( p ) ) { - setpos( p ); + for( const tripoint_abs_ms &p : closest_points_first( pos_abs(), SEEX + 1 ) ) { + if( g->is_empty( here, p ) ) { + setpos( here, here->get_bub( p ) ); return; } } @@ -1803,8 +1803,10 @@ void npc::make_angry() void npc::on_attacked( const Creature &attacker ) { + map &here = get_map(); + if( is_hallucination() ) { - die( nullptr ); + die( &here, nullptr ); } if( attacker.is_avatar() && !is_enemy() && !is_dead() && !guaranteed_hostile() ) { make_angry(); @@ -2940,7 +2942,7 @@ void npc::reboot() add_effect( effect_npc_suspend, 24_hours, true, 1 ); } -void npc::die( Creature *nkiller ) +void npc::die( map *here, Creature *nkiller ) { if( dead ) { // We are already dead, don't die again, note that npc::dead is @@ -2975,7 +2977,7 @@ void npc::die( Creature *nkiller ) // Need to unboard from vehicle before dying, otherwise // the vehicle code cannot find us if( in_vehicle ) { - get_map().unboard_vehicle( pos_bub(), true ); + here->unboard_vehicle( here->get_bub( pos_abs() ), true ); } if( is_mounted() ) { monster *critter = mounted_creature.get(); @@ -2997,7 +2999,7 @@ void npc::die( Creature *nkiller ) } } dead = true; - Character::die( nkiller ); + Character::die( here, nkiller ); if( is_hallucination() || lifespan_end ) { add_msg_if_player_sees( *this, _( "%s disappears." ), get_name().c_str() ); @@ -3057,7 +3059,7 @@ void npc::die( Creature *nkiller ) } } - place_corpse(); + place_corpse( here ); } void npc::prevent_death() @@ -3220,7 +3222,7 @@ void npc::npc_update_body() } } -void npc::on_load() +void npc::on_load( map *here ) { const auto advance_effects = [&]( const time_duration & elapsed_dur ) { for( auto &elem : *effects ) { @@ -3274,7 +3276,7 @@ void npc::on_load() if( dt > 0_turns ) { // This ensures food is properly rotten at load // Otherwise NPCs try to eat rotten food and fail - process_items(); + process_items( here ); // give NPCs that are doing activities a pile of moves if( has_destination() || activity ) { mod_moves( to_moves( dt ) ); @@ -3284,20 +3286,19 @@ void npc::on_load() // Not necessarily true, but it's not a bad idea to set this has_new_items = true; - map &here = get_map(); // for spawned npcs - gravity_check(); - if( here.has_flag( ter_furn_flag::TFLAG_UNSTABLE, pos_bub() ) && - !here.has_vehicle_floor( pos_bub() ) ) { + gravity_check( here ); + if( here->has_flag( ter_furn_flag::TFLAG_UNSTABLE, here->get_bub( pos_abs() ) ) && + !here->has_vehicle_floor( here->get_bub( pos_abs() ) ) ) { add_effect( effect_bouldering, 1_turns, true ); } else if( has_effect( effect_bouldering ) ) { remove_effect( effect_bouldering ); } - if( here.veh_at( pos_bub() ).part_with_feature( VPFLAG_BOARDABLE, true ) && !in_vehicle ) { - here.board_vehicle( pos_bub(), this ); + if( here->veh_at( pos_abs() ).part_with_feature( VPFLAG_BOARDABLE, true ) && !in_vehicle ) { + here->board_vehicle( here->get_bub( pos_abs() ), this ); } if( has_effect( effect_riding ) && !mounted_creature ) { - if( const monster *const mon = get_creature_tracker().creature_at( pos_bub() ) ) { + if( const monster *const mon = get_creature_tracker().creature_at( pos_abs() ) ) { mounted_creature = g->shared_from( *mon ); } else { add_msg_debug( debugmode::DF_NPC, diff --git a/src/npc.h b/src/npc.h index 36c6110fcacb7..951b7a3ac09de 100644 --- a/src/npc.h +++ b/src/npc.h @@ -51,6 +51,7 @@ class JsonObject; class JsonOut; class JsonValue; +class map; class mission; class monfaction; class monster; @@ -816,7 +817,7 @@ class npc : public Character * If the square on the map where the NPC would go is not empty * a spiral search for an empty square around it is performed. */ - void place_on_map(); + void place_on_map( map *here ); /** * See @ref dialogue_chatbin::add_new_mission */ @@ -1013,7 +1014,7 @@ class npc : public Character int indoor_voice() const; void decide_needs(); void reboot(); - void die( Creature *killer ) override; + void die( map *here, Creature *killer ) override; bool is_dead() const; void prevent_death() override; // How well we smash terrain (not corpses!) @@ -1412,7 +1413,7 @@ class npc : public Character /** * Retroactively update npc. */ - void on_load(); + void on_load( map *here ); /** * Update body, but throttled. */ diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 5ebdb00b35023..df94e70c35594 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -2421,6 +2421,8 @@ healing_options npc::patient_assessment( const Character &c ) npc_action npc::address_needs( float danger ) { + map &here = get_map(); + Character &player_character = get_player_character(); // rng because NPCs are not meant to be hypervigilant hawks that notice everything // and swing into action with alarming alacrity. @@ -2500,7 +2502,7 @@ npc_action npc::address_needs( float danger ) } //Hallucinations have a chance of disappearing each turn if( is_hallucination() && one_in( 25 ) ) { - die( nullptr ); + die( &here, nullptr ); } if( danger > NPC_DANGER_VERY_LOW ) { diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 64d0d562a7e99..ab67468ab9cd0 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -5305,7 +5305,8 @@ talk_effect_fun_t::func f_attack( const JsonObject &jo, std::string_view member, talk_effect_fun_t::func f_die( bool is_npc ) { return [is_npc]( dialogue const & d ) { - d.actor( is_npc )->die(); + map &here = get_map(); + d.actor( is_npc )->die( &here ); }; } diff --git a/src/talker.h b/src/talker.h index a9ab8931123b3..7564bfacb581e 100644 --- a/src/talker.h +++ b/src/talker.h @@ -14,6 +14,7 @@ class computer; class faction; class item_location; +class map; class mission; class monster; class npc; @@ -788,7 +789,7 @@ class talker: virtual public const_talker virtual void set_npc_anger( int ) {} virtual void set_all_parts_hp_cur( int ) {} virtual void set_degradation( int ) {} - virtual void die() {} + virtual void die( map * ) {} virtual void set_mana_cur( int ) {} virtual void mod_daily_health( int, int ) {} virtual void mod_livestyle( int ) {} diff --git a/src/talker_character.cpp b/src/talker_character.cpp index 5fe0d55099924..092523e8e1240 100644 --- a/src/talker_character.cpp +++ b/src/talker_character.cpp @@ -1330,9 +1330,9 @@ bool talker_character_const::is_warm() const return me_chr_const->is_warm(); } -void talker_character::die() +void talker_character::die( map *here ) { - me_chr->die( nullptr ); + me_chr->die( here, nullptr ); } matec_id talker_character_const::get_random_technique( Creature const &t, bool crit, diff --git a/src/talker_character.h b/src/talker_character.h index bb1b52de99841..b85ee092c561c 100644 --- a/src/talker_character.h +++ b/src/talker_character.h @@ -16,6 +16,7 @@ class character_id; class faction; class item; +class map; class time_duration; class vehicle; @@ -324,7 +325,7 @@ class talker_character: virtual public talker void remove_bionic( const bionic_id &old_bionic ) override; void set_all_parts_hp_cur( int ) override; void set_part_hp_cur( const bodypart_id &id, int set ) override; - void die() override; + void die( map *here ) override; void attack_target( Creature &t, bool allow_special, const matec_id &force_technique, bool allow_unarmed, int forced_movecost ) override; void learn_martial_art( const matype_id &id ) override; diff --git a/src/talker_item.cpp b/src/talker_item.cpp index 14c1a10452046..28aaa123389f2 100644 --- a/src/talker_item.cpp +++ b/src/talker_item.cpp @@ -157,7 +157,7 @@ void talker_item::set_degradation( int set ) me_it->get_item()->set_degradation( set ); } -void talker_item::die() +void talker_item::die( map * ) { me_it->remove_item(); } diff --git a/src/talker_item.h b/src/talker_item.h index e8ed10fee7f7e..08bce8cf6e450 100644 --- a/src/talker_item.h +++ b/src/talker_item.h @@ -9,6 +9,7 @@ #include "type_id.h" class item; +class map; struct tripoint; @@ -86,7 +87,7 @@ class talker_item: public talker_item_const, public talker_cloner void set_power_cur( units::energy value ) override; void set_all_parts_hp_cur( int ) override; void set_degradation( int ) override; - void die() override; + void die( map *here ) override; private: item_location *me_it{}; diff --git a/src/talker_monster.cpp b/src/talker_monster.cpp index 091c4db4c954a..edbe9b2ce244e 100644 --- a/src/talker_monster.cpp +++ b/src/talker_monster.cpp @@ -220,9 +220,9 @@ bool talker_monster::get_is_alive() const return !me_mon->is_dead(); } -void talker_monster::die() +void talker_monster::die( map *here ) { - me_mon->die( nullptr ); + me_mon->die( here, nullptr ); } void talker_monster::set_all_parts_hp_cur( int set ) diff --git a/src/talker_monster.h b/src/talker_monster.h index fcab60d13adb4..f06ceddf1b634 100644 --- a/src/talker_monster.h +++ b/src/talker_monster.h @@ -14,6 +14,7 @@ class faction; class item; +class map; class mission; class npc; class time_duration; @@ -122,7 +123,7 @@ class talker_monster: public talker_monster_const, public talker_cloneris_safe(); } -void talker_npc::die() +void talker_npc::die( map *here ) { - me_npc->die( nullptr ); + me_npc->die( here, nullptr ); const shared_ptr_fast guy = overmap_buffer.find_npc( me_npc->getID() ); if( guy && !guy->is_dead() ) { guy->marked_for_death = true; diff --git a/src/talker_npc.h b/src/talker_npc.h index 78bf65f327382..3a7bdf1a9d3d3 100644 --- a/src/talker_npc.h +++ b/src/talker_npc.h @@ -12,6 +12,7 @@ class Character; class item; class mission; +class map; class talker; /* @@ -119,7 +120,7 @@ class talker_npc : virtual public talker_npc_const, void add_opinion( const npc_opinion &op ) override; bool enslave_mind() override; void set_first_topic( const std::string &chat_topic ) override; - void die() override; + void die( map *here ) override; void set_npc_trust( int trust ) override; void set_npc_fear( int fear ) override; void set_npc_value( int value ) override; diff --git a/src/teleport.cpp b/src/teleport.cpp index aee47188bff4b..97540978e1e4d 100644 --- a/src/teleport.cpp +++ b/src/teleport.cpp @@ -121,7 +121,7 @@ bool teleport::teleport_to_point( Creature &critter, tripoint_bub_ms target, boo add_msg( m_bad, _( "You die after teleporting into a solid." ) ); } } - critter.check_dead_state(); + critter.check_dead_state( &here ); } } //update pos @@ -183,7 +183,7 @@ bool teleport::teleport_to_point( Creature &critter, tripoint_bub_ms target, boo if( force ) { //this should only happen through debug menu, so this won't affect the player. poor_soul->apply_damage( nullptr, bodypart_id( "torso" ), 9999 ); - poor_soul->check_dead_state(); + poor_soul->check_dead_state( &here ); } else if( safe ) { if( c_is_u && display_message ) { add_msg( m_bad, _( "You cannot teleport safely." ) ); @@ -229,7 +229,7 @@ bool teleport::teleport_to_point( Creature &critter, tripoint_bub_ms target, boo static_cast( poor_soul->get_part_hp_max( bp_id ) ) / static_cast( rng( 6, 12 ) ); poor_soul->apply_damage( nullptr, bp_id, damage_to_deal ); } - poor_soul->check_dead_state(); + poor_soul->check_dead_state( &here ); } } } @@ -247,7 +247,7 @@ bool teleport::teleport_to_point( Creature &critter, tripoint_bub_ms target, boo static_cast( critter.get_part_hp_max( bp_id ) ) / static_cast( rng( 6, 12 ) ); critter.apply_damage( nullptr, bp_id, damage_to_deal ); } - critter.check_dead_state(); + critter.check_dead_state( &here ); } //player and npc exclusive teleporting effects if( p && add_teleglow ) { diff --git a/src/trapfunc.cpp b/src/trapfunc.cpp index 32b9f319bb1a7..4a8c296044430 100644 --- a/src/trapfunc.cpp +++ b/src/trapfunc.cpp @@ -147,6 +147,8 @@ bool trapfunc::bubble( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::glass( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); + if( c == nullptr ) { return false; } @@ -165,7 +167,7 @@ bool trapfunc::glass( const tripoint_bub_ms &p, Creature *c, item * ) } sounds::sound( p, 8, sounds::sound_t::combat, _( "glass cracking!" ), false, "trap", "glass" ); get_map().remove_trap( p ); - c->check_dead_state(); + c->check_dead_state( &here ); return true; } @@ -217,7 +219,7 @@ bool trapfunc::beartrap( const tripoint_bub_ms &p, Creature *c, item * ) you->add_effect( effect_tetanus, 1_turns, true ); } } - c->check_dead_state(); + c->check_dead_state( &here ); } else { here.spawn_item( p, itype_beartrap ); } @@ -285,7 +287,7 @@ bool trapfunc::board( const tripoint_bub_ms &p, Creature *c, item * ) random_entry( c->get_ground_contact_bodyparts() ), damage_instance( damage_cut, rng( 3, 5 ) ) ); try_apply_tetanus( c->as_character(), dd.type_damage( damage_cut ) ); - c->check_dead_state(); + c->check_dead_state( &here ); // Weight of 100kg+ is guaranteed to break the trap, linear chance as weight increases if( x_in_y( c->get_weight() / 1_kilogram, 100 ) ) { // destroy trap @@ -341,7 +343,7 @@ bool trapfunc::caltrops( const tripoint_bub_ms &p, Creature *c, item * ) // 20% chance disarm trap here.tr_at( p ).on_disarmed( here, p ); } - c->check_dead_state(); + c->check_dead_state( &here ); return true; } @@ -366,7 +368,7 @@ bool trapfunc::caltrops_glass( const tripoint_bub_ms &p, Creature *c, item * ) } c->deal_damage( nullptr, random_entry( c->get_ground_contact_bodyparts() ), damage_instance( damage_cut, rng( 3, 10 ) ) ); - c->check_dead_state(); + c->check_dead_state( &here ); add_msg_if_player_sees( p, _( "The shards shatter!" ) ); sounds::sound( p, 8, sounds::sound_t::combat, _( "glass cracking!" ), false, "trap", "glass_caltrops" ); @@ -456,12 +458,13 @@ bool trapfunc::tripwire( const tripoint_bub_ms &p, Creature *c, item * ) } } } - c->check_dead_state(); + c->check_dead_state( &here ); return true; } bool trapfunc::crossbow( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); bool add_bolt = true; if( c != nullptr ) { if( c->has_effect( effect_ridden ) ) { @@ -546,9 +549,8 @@ bool trapfunc::crossbow( const tripoint_bub_ms &p, Creature *c, item * ) add_msg( m_neutral, _( "A bolt shoots out, but misses the %s." ), z->name() ); } } - c->check_dead_state(); + c->check_dead_state( &here ); } - map &here = get_map(); here.remove_trap( p ); here.spawn_item( p, itype_crossbow ); here.spawn_item( p, itype_string_36 ); @@ -651,7 +653,7 @@ bool trapfunc::shotgun( const tripoint_bub_ms &p, Creature *c, item * ) rng( 40 * shots, 60 * shots ) ) ); } - c->check_dead_state(); + c->check_dead_state( &here ); } here.spawn_item( p, here.tr_at( p ) == tr_shotgun_1 ? itype_shotgun_s : itype_shotgun_d ); @@ -662,6 +664,7 @@ bool trapfunc::shotgun( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::blade( const tripoint_bub_ms &, Creature *c, item * ) { + map &here = get_map(); if( c == nullptr ) { return false; } @@ -674,7 +677,7 @@ bool trapfunc::blade( const tripoint_bub_ms &, Creature *c, item * ) d.add_damage( damage_bash, 12 ); d.add_damage( damage_cut, 30 ); c->deal_damage( nullptr, bodypart_id( "torso" ), d ); - c->check_dead_state(); + c->check_dead_state( &here ); return true; } @@ -706,8 +709,9 @@ bool trapfunc::snare_light( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::snare_heavy( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); sounds::sound( p, 4, sounds::sound_t::combat, _( "Snap!" ), false, "trap", "snare" ); - get_map().remove_trap( p ); + here.remove_trap( p ); if( c == nullptr ) { return false; } @@ -743,7 +747,7 @@ bool trapfunc::snare_heavy( const tripoint_bub_ms &p, Creature *c, item * ) } z->deal_damage( nullptr, hit, damage_instance( damage_bash, damage ) ); } - c->check_dead_state(); + c->check_dead_state( &here ); return true; } @@ -802,7 +806,7 @@ bool trapfunc::snare_species( const tripoint_bub_ms &p, Creature *critter, item } // Actual effects critter->add_effect( effect_immobilization, 10_turns, hit ); - critter->check_dead_state(); + critter->check_dead_state( &here ); } here.remove_trap( p ); @@ -841,7 +845,8 @@ bool trapfunc::boobytrap( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::goo( const tripoint_bub_ms &p, Creature *c, item * ) { - get_map().remove_trap( p ); + map &here = get_map(); + here.remove_trap( p ); if( c == nullptr ) { return false; } @@ -863,7 +868,7 @@ bool trapfunc::goo( const tripoint_bub_ms &p, Creature *c, item * ) you->string_for_ground_contact_bodyparts( bps ) ), string_format( _( "The acidic goo eats away at 's %s!" ), you->string_for_ground_contact_bodyparts( bps ) ) ); - you->check_dead_state(); + you->check_dead_state( &here ); } return true; } else if( z != nullptr ) { @@ -889,6 +894,8 @@ bool trapfunc::goo( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::dissector( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); + if( c == nullptr ) { return false; } @@ -921,7 +928,7 @@ bool trapfunc::dissector( const tripoint_bub_ms &p, Creature *c, item * ) ch->add_msg_player_or_npc( m_bad, _( "Electrical beams emit from the floor and slice your flesh!" ), _( "Electrical beams emit from the floor and slice s flesh!" ) ); } - ch->check_dead_state(); + ch->check_dead_state( &here ); } } @@ -941,12 +948,14 @@ bool trapfunc::dissector( const tripoint_bub_ms &p, Creature *c, item * ) c->deal_damage( nullptr, bodypart_id( "foot_l" ), damage_instance( damage_cut, 10 ) ); c->deal_damage( nullptr, bodypart_id( "foot_r" ), damage_instance( damage_cut, 10 ) ); - c->check_dead_state(); + c->check_dead_state( &here ); return true; } bool trapfunc::pit( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); + if( c == nullptr ) { return false; } @@ -990,12 +999,14 @@ bool trapfunc::pit( const tripoint_bub_ms &p, Creature *c, item * ) z->deal_damage( nullptr, bodypart_id( "leg_r" ), damage_instance( damage_bash, eff * rng( 10, 20 ) ) ); } - c->check_dead_state(); + c->check_dead_state( &here ); return true; } bool trapfunc::pit_spikes( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); + if( c == nullptr ) { return false; } @@ -1064,7 +1075,7 @@ bool trapfunc::pit_spikes( const tripoint_bub_ms &p, Creature *c, item * ) } z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( damage_cut, rng( 20, 50 ) ) ); } - c->check_dead_state(); + c->check_dead_state( &here ); if( one_in( 4 ) ) { add_msg_if_player_sees( p, _( "The spears break!" ) ); map &here = get_map(); @@ -1081,6 +1092,8 @@ bool trapfunc::pit_spikes( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::pit_glass( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); + if( c == nullptr ) { return false; } @@ -1154,7 +1167,7 @@ bool trapfunc::pit_glass( const tripoint_bub_ms &p, Creature *c, item * ) z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( damage_cut, rng( 20, 50 ) ) ); } - c->check_dead_state(); + c->check_dead_state( &here ); if( one_in( 5 ) ) { add_msg_if_player_sees( p, _( "The shards shatter!" ) ); map &here = get_map(); @@ -1171,6 +1184,8 @@ bool trapfunc::pit_glass( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::lava( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); + if( c == nullptr ) { return false; } @@ -1208,7 +1223,7 @@ bool trapfunc::lava( const tripoint_bub_ms &p, Creature *c, item * ) } z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( damage_heat, dam ) ); } - c->check_dead_state(); + c->check_dead_state( &here ); return true; } @@ -1409,6 +1424,8 @@ bool trapfunc::temple_toggle( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::glow( const tripoint_bub_ms &p, Creature *c, item * ) { + map &here = get_map(); + if( c == nullptr ) { return false; } @@ -1443,7 +1460,7 @@ bool trapfunc::glow( const tripoint_bub_ms &p, Creature *c, item * ) c->add_msg_if_player( _( "Small flashes surround you." ) ); } } - c->check_dead_state(); + c->check_dead_state( &here ); return true; } @@ -1526,6 +1543,8 @@ bool trapfunc::map_regen( const tripoint_bub_ms &p, Creature *c, item * ) bool trapfunc::drain( const tripoint_bub_ms &, Creature *c, item * ) { + map &here = get_map(); + if( c != nullptr ) { c->add_msg_if_player( m_bad, _( "You feel your life force sapping away." ) ); monster *z = dynamic_cast( c ); @@ -1535,7 +1554,7 @@ bool trapfunc::drain( const tripoint_bub_ms &, Creature *c, item * ) } else if( z != nullptr ) { z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( damage_pure, 1 ) ); } - c->check_dead_state(); + c->check_dead_state( &here ); return true; } return false; diff --git a/tests/active_item_test.cpp b/tests/active_item_test.cpp index d4783b28fd352..1a99fcfcd76e3 100644 --- a/tests/active_item_test.cpp +++ b/tests/active_item_test.cpp @@ -42,7 +42,7 @@ TEST_CASE( "active_items_processed_regularly", "[active_item]" ) // Call item processing entry points. here.process_items(); - player_character.process_items(); + player_character.process_items( &here ); // Each chainsaw was processed and turned off from lack of fuel CHECK( inventory_item->typeId().str() == "chainsaw_off" ); diff --git a/tests/archery_damage_test.cpp b/tests/archery_damage_test.cpp index 25498530810c0..74ff9de732698 100644 --- a/tests/archery_damage_test.cpp +++ b/tests/archery_damage_test.cpp @@ -75,7 +75,7 @@ static void test_projectile_attack( const std::string &target_type, bool killabl monster target{ mtype_id( target_type ), tripoint_bub_ms::zero }; //the missed_by field is modified by deal_projectile_attack() and must be reset attack.missed_by = headshot ? accuracy_headshot * 0.75 : accuracy_critical; - target.deal_projectile_attack( nullptr, attack, attack.missed_by, false ); + target.deal_projectile_attack( &get_map(), nullptr, attack, attack.missed_by, false ); CAPTURE( target_type ); CAPTURE( target.get_hp() ); CAPTURE( target.get_hp_max() ); diff --git a/tests/coverage_test.cpp b/tests/coverage_test.cpp index 181c991fc95fc..33ee9618babc6 100644 --- a/tests/coverage_test.cpp +++ b/tests/coverage_test.cpp @@ -160,7 +160,7 @@ static float get_avg_bullet_dmg( const itype_id &clothing_id ) dealt_projectile_attack atk; projectile_attack( atk, proj, badguy_pos, dude_pos, dispersion_sources(), &*badguy ); - dude->deal_projectile_attack( &*badguy, atk, atk.missed_by, false ); + dude->deal_projectile_attack( &get_map(), & *badguy, atk, atk.missed_by, false ); if( atk.missed_by < 1.0 ) { num_hits++; } diff --git a/tests/enchantments_test.cpp b/tests/enchantments_test.cpp index d1debfd9f889e..a32b742561097 100644 --- a/tests/enchantments_test.cpp +++ b/tests/enchantments_test.cpp @@ -85,7 +85,7 @@ static void test_generic_ench( avatar &p, enchant_test enc_test ) clear_map(); monster &zombie = spawn_test_monster( "mon_zombie", spot ); - p.on_hit( &zombie, bodypart_id( "torso" ), 0.0, nullptr ); + p.on_hit( &get_map(), & zombie, bodypart_id( "torso" ), 0.0, nullptr ); CHECK( zombie.has_effect( effect_blind ) ); } diff --git a/tests/eoc_test.cpp b/tests/eoc_test.cpp index b7582315da97d..1a7d21510991e 100644 --- a/tests/eoc_test.cpp +++ b/tests/eoc_test.cpp @@ -1198,6 +1198,8 @@ TEST_CASE( "EOC_event_test", "[eoc]" ) TEST_CASE( "EOC_combat_event_test", "[eoc]" ) { + map &here = get_map(); + size_t loop; global_variables &globvars = get_globals(); globvars.clear_global_values(); @@ -1273,7 +1275,7 @@ TEST_CASE( "EOC_combat_event_test", "[eoc]" ) // character_kills_monster clear_map(); monster &victim = spawn_test_monster( "mon_zombie", target_pos ); - victim.die( &get_avatar() ); + victim.die( &here, &get_avatar() ); CHECK( get_avatar().get_value( "test_event_last_event" ) == "character_kills_monster" ); CHECK( globvars.get_global_value( "victim_type" ) == "mon_zombie" ); diff --git a/tests/explosion_balance_test.cpp b/tests/explosion_balance_test.cpp index 62b9dd3012eb1..3d6b9fd8991e1 100644 --- a/tests/explosion_balance_test.cpp +++ b/tests/explosion_balance_test.cpp @@ -59,7 +59,7 @@ static float get_damage_vs_target( const std::string &target_id ) //REQUIRE( target_monster.type->armor_bullet == 0 ); // This mirrors code in explosion::shrapnel() that scales hit rate with size and avoids crits. frag.missed_by = rng_float( 0.05, 1.0 / target_monster.ranged_target_size() ); - target_monster.deal_projectile_attack( nullptr, frag, frag.missed_by, false ); + target_monster.deal_projectile_attack( &get_map(), nullptr, frag, frag.missed_by, false ); if( frag.dealt_dam.total_damage() > 0 ) { damaging_hits++; damage_taken += frag.dealt_dam.total_damage(); diff --git a/tests/harvest_test.cpp b/tests/harvest_test.cpp index 75629183a284c..8c59bd65d1109 100644 --- a/tests/harvest_test.cpp +++ b/tests/harvest_test.cpp @@ -38,7 +38,7 @@ static void butcher_mon( const mtype_id &monid, const activity_id &actid, int *c u.wield( scalpel ); monster cow( monid, mon_pos ); const tripoint_bub_ms cow_loc = cow.pos_bub(); - cow.die( nullptr ); + cow.die( &here, nullptr ); u.move_to( cow.pos_abs() ); player_activity act( actid, 0, true ); act.targets.emplace_back( map_cursor( u.pos_abs() ), &*here.i_at( cow_loc ).begin() ); diff --git a/tests/magic_spell_test.cpp b/tests/magic_spell_test.cpp index bccc5f525be5e..923bbbd593abe 100644 --- a/tests/magic_spell_test.cpp +++ b/tests/magic_spell_test.cpp @@ -583,6 +583,8 @@ TEST_CASE( "spell_effect_-_target_attack", "[magic][spell][effect][target_attack // spell_effect::spawn_summoned_monster TEST_CASE( "spell_effect_-_summon", "[magic][spell][effect][summon]" ) { + map &here = get_map(); + clear_map(); // Avatar/spellcaster and summoned mummy locations @@ -607,7 +609,7 @@ TEST_CASE( "spell_effect_-_summon", "[magic][spell][effect][summon]" ) CHECK( g->num_creatures() == 2 ); //kill the ghost - creatures.creature_at( mummy_loc )->die( nullptr ); + creatures.creature_at( mummy_loc )->die( &here, nullptr ); g->cleanup_dead(); //a corpse was not created @@ -625,7 +627,7 @@ TEST_CASE( "spell_effect_-_summon", "[magic][spell][effect][summon]" ) CHECK( g->num_creatures() == 2 ); //kill the mummy - creatures.creature_at( mummy_loc )->die( nullptr ); + creatures.creature_at( mummy_loc )->die( &here, nullptr ); g->cleanup_dead(); //a corpse was created diff --git a/tests/map_helpers.cpp b/tests/map_helpers.cpp index 8cb690e1624f8..5a98c55fb9ed3 100644 --- a/tests/map_helpers.cpp +++ b/tests/map_helpers.cpp @@ -85,10 +85,11 @@ void clear_creatures() void clear_npcs() { + map &here = get_map(); // Reload to ensure that all active NPCs are in the overmap_buffer. g->reload_npcs(); for( npc &n : g->all_npcs() ) { - n.die( nullptr ); + n.die( & here, nullptr ); } g->cleanup_dead(); } diff --git a/tests/map_test.cpp b/tests/map_test.cpp index cb156c11a4fc3..5a9b9910ca8b3 100644 --- a/tests/map_test.cpp +++ b/tests/map_test.cpp @@ -295,7 +295,7 @@ TEST_CASE( "active_monster_drops", "[active_item][map]" ) zombo.no_extra_death_drops = true; zombo.inv.emplace_back( bag_plastic ); calendar::turn += time_duration::from_seconds( cookie.processing_speed() + 1 ); - zombo.die( nullptr ); + zombo.die( &here, nullptr ); REQUIRE( here.i_at( start_loc ).size() == 1 ); item &dropped_bag = here.i_at( start_loc ).begin()->only_item(); diff --git a/tests/monster_attack_test.cpp b/tests/monster_attack_test.cpp index 618f73dab0d0c..f8604befa605b 100644 --- a/tests/monster_attack_test.cpp +++ b/tests/monster_attack_test.cpp @@ -293,6 +293,7 @@ TEST_CASE( "Mattack_dialog_condition_test", "[mattack]" ) TEST_CASE( "Targeted_grab_removal_test", "[mattack][grab]" ) { + map &here = get_map(); const std::string grabber_left = "mon_debug_grabber_left"; const std::string grabber_right = "mon_debug_grabber_right"; @@ -325,7 +326,7 @@ TEST_CASE( "Targeted_grab_removal_test", "[mattack][grab]" ) REQUIRE( test_monster_left.is_grabbing( body_part_arm_l ) ); // Kill the left grabber - test_monster_left.die( nullptr ); + test_monster_left.die( &here, nullptr ); // Now we only have the one REQUIRE( you.has_effect( effect_grabbed, body_part_arm_r ) ); diff --git a/tests/npc_attack_test.cpp b/tests/npc_attack_test.cpp index 8aebf1e6063c3..48dd0d2f9732a 100644 --- a/tests/npc_attack_test.cpp +++ b/tests/npc_attack_test.cpp @@ -54,7 +54,7 @@ static npc &respawn_main_npc() { npc *guy = get_creature_tracker().creature_at( main_npc_start_tripoint ); if( guy ) { - guy->die( nullptr ); + guy->die( &get_map(), nullptr ); } return spawn_main_npc(); } diff --git a/tests/npc_talk_test.cpp b/tests/npc_talk_test.cpp index b6461befb447b..ea741da07f289 100644 --- a/tests/npc_talk_test.cpp +++ b/tests/npc_talk_test.cpp @@ -1124,7 +1124,7 @@ TEST_CASE( "npc_compare_int", "[npc_talk]" ) get_weather().weather_precise->humidity = 16; get_weather().weather_precise->pressure = 17; get_weather().clear_temp_cache(); - player_character.setpos( { -1, -2, -3 } ); + player_character.setpos( tripoint_bub_ms{ -1, -2, -3 } ); player_character.set_pain( 21 ); player_character.add_bionic( bio_power_storage ); player_character.set_power_level( 22_mJ ); diff --git a/tests/npc_test.cpp b/tests/npc_test.cpp index b089af35aff9a..3307bbbc5beac 100644 --- a/tests/npc_test.cpp +++ b/tests/npc_test.cpp @@ -58,7 +58,7 @@ static void on_load_test( npc &who, const time_duration &from, const time_durati calendar::turn = calendar::turn_zero + from; who.on_unload(); calendar::turn = calendar::turn_zero + to; - who.on_load(); + who.on_load( &get_map() ); } static void test_needs( const npc &who, const numeric_interval &hunger, diff --git a/tests/player_activities_test.cpp b/tests/player_activities_test.cpp index 87faee26b97d3..d7a676a2b6ca9 100644 --- a/tests/player_activities_test.cpp +++ b/tests/player_activities_test.cpp @@ -427,6 +427,8 @@ TEST_CASE( "shearing", "[activity][shearing][animals]" ) SECTION( "shearing losing tool" ) { GIVEN( "an electric tool with shearing quality three" ) { + map &here = get_map(); + clear_avatar(); clear_map(); monster &mon = test_monster( true ); @@ -456,7 +458,7 @@ TEST_CASE( "shearing", "[activity][shearing][animals]" ) WHEN( "tool runs out of charges mid activity" ) { for( int i = 0; i < 10000; ++i ) { - dummy.process_items(); + dummy.process_items( &here ); } CHECK( dummy.get_wielded_item()->ammo_remaining() == 0 ); diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index 6c025a8c7b723..e63dfbb171c9f 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -493,6 +493,7 @@ static void shoot_monster( const itype_id &gun_type, const std::vector int expected_damage, const std::string &monster_type, const std::function &other_checks = nullptr ) { + map &here = get_map(); clear_map(); statistics damage; constexpr tripoint_bub_ms shooter_pos{ 60, 60, 0 }; @@ -515,7 +516,7 @@ static void shoot_monster( const itype_id &gun_type, const std::vector if( damage.margin_of_error() < 0.05 && damage.n() > 500 ) { break; } - mon.die( nullptr ); + mon.die( &here, nullptr ); } while( damage.n() < 1000 ); // In fact, stable results can only be obtained when n reaches 10000 const double avg = damage.avg(); CAPTURE( damage.n() );