Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert monster opts #69399

Merged
merged 2 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 0 additions & 64 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
#include "field.h"
#include "field_type.h"
#include "flag.h"
#include "flood_fill.h"
#include "fragment_cloud.h"
#include "fungal_effects.h"
#include "game.h"
Expand Down Expand Up @@ -10272,66 +10271,3 @@ tripoint drawsq_params::center() const
return view_center;
}
}

/** This is lazily evaluated on demand. Each creature in a zone is visited
* as it flood fills, then the zone number is incremented. At the end all creatures in
* the same zone will have the same zone number assigned, which can be used to have creatures in
* different zones ignore each other very cheaply.
*/
void map::flood_fill_zone( const Creature &origin )
{
creature_tracker &tracker = get_creature_tracker();

ff::flood_fill_visit_10_connected( origin.pos_bub(),
[this]( const tripoint_bub_ms & loc, int direction ) {
if( direction == 0 ) {
return inbounds( loc ) && ( is_transparent_wo_fields( loc.raw() ) ||
passable( loc ) );
}
if( direction == 1 ) {
const maptile &up = maptile_at( loc );
const ter_t &up_ter = up.get_ter_t();
if( up_ter.id.is_null() ) {
return false;
}
if( ( ( up_ter.movecost != 0 && up.get_furn_t().movecost >= 0 ) ||
is_transparent_wo_fields( loc.raw() ) ) &&
( up_ter.has_flag( ter_furn_flag::TFLAG_NO_FLOOR ) ||
up_ter.has_flag( ter_furn_flag::TFLAG_GOES_DOWN ) ) ) {
return true;
}
}
if( direction == -1 ) {
const maptile &up = maptile_at( loc + tripoint_above );
const ter_t &up_ter = up.get_ter_t();
if( up_ter.id.is_null() ) {
return false;
}
const maptile &down = maptile_at( loc );
const ter_t &down_ter = up.get_ter_t();
if( down_ter.id.is_null() ) {
return false;
}
if( ( ( down_ter.movecost != 0 && down.get_furn_t().movecost >= 0 ) ||
is_transparent_wo_fields( loc.raw() ) ) &&
( up_ter.has_flag( ter_furn_flag::TFLAG_NO_FLOOR ) ||
up_ter.has_flag( ter_furn_flag::TFLAG_GOES_DOWN ) ) ) {
return true;
}
}
return false;
},
[&tracker, this]( const tripoint_bub_ms & loc ) {
Creature *creature = tracker.creature_at<Creature>( loc );
if( creature ) {
const int n = zone_number * zone_tick;
creatures_by_zone[n].push_back( creature );
creature->set_reachable_zone( n );
}
} );
if( zone_number == std::numeric_limits<int>::max() ) {
zone_number = 1;
} else {
zone_number++;
}
}
49 changes: 2 additions & 47 deletions src/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -2236,59 +2236,14 @@ class map
bool _main_requires_cleanup = false;
std::optional<bool> _main_cleanup_override = std::nullopt;

// Tracks the dirtiness of the visitable zones cache. This must be flipped when
// Tracks the dirtiness of the visitable zones cache, but that cache does not live here,
// it is distributed among the active monsters. This must be flipped when
// persistent visibility from terrain or furniture changes
// (this excludes vehicles and fields) or when persistent traversability changes,
// which means walls and floors.
bool visitable_cache_dirty = false;
int zone_number = 1;
int zone_tick = 1;
std::unordered_map<int, std::vector<Creature *>> creatures_by_zone;
std::unordered_set<Creature *> to_remove;

void flood_fill_zone( const Creature &origin );

void flood_fill_if_needed( const Creature &origin ) {
if( get_visitable_zones_cache_dirty() ) {
creatures_by_zone.clear();
to_remove.clear();
zone_tick = zone_tick > 0 ? -1 : 1;
set_visitable_zones_cache_dirty( false );
zone_number = 1;
}
// This check insures we only flood fill when the target monster has an uninitialized zone,
// or if it has a zone from last turn. In other words it only triggers on
// the first monster in a zone each turn. We can detect this because the sign
// of the zone numbers changes on every invalidation.
int old_zone = origin.get_reachable_zone();
// Compare with zone_tick == old_zone && old_zone != 0
if( old_zone * zone_tick <= 0 ) {
flood_fill_zone( origin );
}
}

public:
// Only call from the Creature destructor.
void remove_creature_from_reachability( Creature *creature ) {
to_remove.insert( creature );
}

template <typename Functor>
void visit_reachable_creatures( const Creature &origin, Functor f ) {
flood_fill_if_needed( origin );
const auto map_iter = creatures_by_zone.find( origin.get_reachable_zone() );
if( map_iter != creatures_by_zone.end() ) {
auto vector_iter = map_iter->second.begin();
const auto vector_end = map_iter->second.end();
for( ; vector_iter != vector_end; ++vector_iter ) {
Creature *other = *vector_iter;
if( to_remove.count( other ) == 0 ) {
f( *other );
}
}
}
}

void queue_main_cleanup();
bool is_main_cleanup_queued() const;
void main_cleanup_override( bool over );
Expand Down
150 changes: 121 additions & 29 deletions src/monmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,85 @@ bool monster::mating_angry() const
return mating_angry;
}

/** This is lazily evaluated in monster::plan(). Each monster in a zone is visited
* as it flood fills, then the zone number is incremented. At the end all monsters in
* the same zone will have the same zone number assigned, which can be used to have monsters in
* different zones ignore each other very cheaply.
*/
static void flood_fill_zone( Creature &origin )
{
static int zone_number = 1;
static int zone_tick = 1;
map &here = get_map();
if( here.get_visitable_zones_cache_dirty() ) {
zone_tick = zone_tick > 0 ? -1 : 1;
here.set_visitable_zones_cache_dirty( false );
zone_number = 1;
}
// This check insures we only flood fill when the target monster has an uninitialized zone,
// or if it has a zone from last turn. In other words it only triggers on
// the first monster in a zone each turn. We can detect this because the sign
// of the zone numbers changes on every invalidation.
int old_zone = origin.get_reachable_zone();
// Compare with zone_tick == old_zone && old_zone != 0
if( ( zone_tick > 0 && old_zone > 0 ) ||
( zone_tick < 0 && old_zone < 0 ) ) {
return;
}
creature_tracker &tracker = get_creature_tracker();

ff::flood_fill_visit_10_connected( origin.pos_bub(),
[&here]( const tripoint_bub_ms & loc, int direction ) {
if( direction == 0 ) {
return here.inbounds( loc ) && ( here.is_transparent_wo_fields( loc.raw() ) ||
here.passable( loc ) );
}
if( direction == 1 ) {
const maptile &up = here.maptile_at( loc );
const ter_t &up_ter = up.get_ter_t();
if( up_ter.id.is_null() ) {
return false;
}
if( ( ( up_ter.movecost != 0 && up.get_furn_t().movecost >= 0 ) ||
here.is_transparent_wo_fields( loc.raw() ) ) &&
( up_ter.has_flag( ter_furn_flag::TFLAG_NO_FLOOR ) ||
up_ter.has_flag( ter_furn_flag::TFLAG_GOES_DOWN ) ) ) {
return true;
}
}
if( direction == -1 ) {
const maptile &up = here.maptile_at( loc + tripoint_above );
const ter_t &up_ter = up.get_ter_t();
if( up_ter.id.is_null() ) {
return false;
}
const maptile &down = here.maptile_at( loc );
const ter_t &down_ter = up.get_ter_t();
if( down_ter.id.is_null() ) {
return false;
}
if( ( ( down_ter.movecost != 0 && down.get_furn_t().movecost >= 0 ) ||
here.is_transparent_wo_fields( loc.raw() ) ) &&
( up_ter.has_flag( ter_furn_flag::TFLAG_NO_FLOOR ) ||
up_ter.has_flag( ter_furn_flag::TFLAG_GOES_DOWN ) ) ) {
return true;
}
}
return false;
},
[&tracker]( const tripoint_bub_ms & loc ) {
Creature *creature = tracker.creature_at<Creature>( loc );
if( creature ) {
creature->set_reachable_zone( zone_number * zone_tick );
}
} );
if( zone_number == std::numeric_limits<int>::max() ) {
zone_number = 1;
} else {
zone_number++;
}
}

void monster::plan()
{
const auto &factions = g->critter_tracker->factions();
Expand All @@ -495,6 +574,7 @@ void monster::plan()
std::bitset<OVERMAP_LAYERS> seen_levels = here.get_inter_level_visibility( pos().z );
monster_attitude mood = attitude();
Character &player_character = get_player_character();
flood_fill_zone( *this );
// If we can see the player, move toward them or flee.
if( friendly == 0 && seen_levels.test( player_character.pos().z + OVERMAP_DEPTH ) &&
sees( player_character ) ) {
Expand Down Expand Up @@ -599,40 +679,52 @@ void monster::plan()
turns_since_target );
int turns_to_skip = max_turns_to_skip * rate_limiting_factor;
if( friendly == 0 && ( turns_to_skip == 0 || turns_since_target % turns_to_skip == 0 ) ) {
here.visit_reachable_creatures( *this, [this, &seen_levels, &mon_plan,
&valid_targets]( Creature & other ) {
mf_attitude faction_att = faction.obj().attitude( other.get_monster_faction() );
for( const auto &fac_list : factions ) {
mf_attitude faction_att = faction.obj().attitude( fac_list.first );
if( faction_att == MFA_NEUTRAL || faction_att == MFA_FRIENDLY ) {
return;
}
if( !seen_levels.test( other.posz() + OVERMAP_DEPTH ) ) {
return;
continue;
}
float rating = rate_target( other, mon_plan.dist, mon_plan.smart_planning );
if( rating == mon_plan.dist ) {
++valid_targets;
if( one_in( valid_targets ) ) {
mon_plan.target = &other;

for( const auto &fac : fac_list.second ) {
if( !seen_levels.test( fac.first + OVERMAP_DEPTH ) ) {
continue;
}
}
if( rating < mon_plan.dist ) {
mon_plan.target = &other;
mon_plan.dist = rating;
valid_targets = 1;
}
if( rating <= 5 ) {
if( anger <= 30 ) {
anger += mon_plan.angers_hostile_near;
for( const weak_ptr_fast<monster> &weak : fac.second ) {
const shared_ptr_fast<monster> shared = weak.lock();
if( !shared ) {
continue;
}
monster &mon = *shared;
if( get_reachable_zone() != mon.get_reachable_zone() ) {
continue;
}
float rating = rate_target( mon, mon_plan.dist, mon_plan.smart_planning );
if( rating == mon_plan.dist ) {
++valid_targets;
if( one_in( valid_targets ) ) {
mon_plan.target = &mon;
}
}
if( rating < mon_plan.dist ) {
mon_plan.target = &mon;
mon_plan.dist = rating;
valid_targets = 1;
}
if( rating <= 5 ) {
if( anger <= 30 ) {
anger += mon_plan.angers_hostile_near;
}
morale -= mon_plan.fears_hostile_near;
}
if( !mon_plan.fleeing && anger <= 20 && valid_targets != 0 ) {
anger += mon_plan.angers_hostile_seen;
}
if( !mon_plan.fleeing && valid_targets != 0 ) {
morale -= mon_plan.fears_hostile_seen;
}
}
morale -= mon_plan.fears_hostile_near;
}
if( !mon_plan.fleeing && anger <= 20 && valid_targets != 0 ) {
anger += mon_plan.angers_hostile_seen;
}
if( !mon_plan.fleeing && valid_targets != 0 ) {
morale -= mon_plan.fears_hostile_seen;
}
} );
}
}
if( mon_plan.target == nullptr ) {
// Just avoiding overflow.
Expand Down
1 change: 0 additions & 1 deletion src/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3703,7 +3703,6 @@ bool monster::will_join_horde( int size )
void monster::on_unload()
{
last_updated = calendar::turn;
get_map().remove_creature_from_reachability( this );
}

void monster::on_load()
Expand Down
1 change: 0 additions & 1 deletion src/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3196,7 +3196,6 @@ void npc::add_new_mission( class mission *miss )

void npc::on_unload()
{
get_map().remove_creature_from_reachability( this );
}

// A throtled version of player::update_body since npc's don't need to-the-turn updates.
Expand Down
Loading