diff --git a/src/character.h b/src/character.h index 5772d56393dc9..07dc4906ec4ec 100644 --- a/src/character.h +++ b/src/character.h @@ -1394,6 +1394,12 @@ class Character : public Creature, public visitable bool has_flag( const json_character_flag &flag ) const; /** Returns the count of traits, bionics, effects, bodyparts, and martial arts buffs with a flag */ int count_flag( const json_character_flag &flag ) const; + + private: + // Cache if character has a flag on their mutations. It is cleared whenever my_mutations is modified. + mutable std::map trait_flag_cache; + + public: /** Returns the trait id with the given invlet, or an empty string if no trait has that invlet */ trait_id trait_by_invlet( int ch ) const; /** Returns the vector of all traits in category, good/bad/any */ diff --git a/src/mutation.cpp b/src/mutation.cpp index 25a3fe500c414..5429cbd7a6080 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -136,20 +136,27 @@ bool Character::has_trait_variant( const trait_and_var &test ) const bool Character::has_trait_flag( const json_character_flag &b ) const { - // UGLY, SLOW, should be cached as my_mutation_flags or something + auto iter = trait_flag_cache.find( b ); + if( iter != trait_flag_cache.end() ) { + return iter->second; + } + for( const trait_id &mut : get_mutations() ) { const mutation_branch &mut_data = mut.obj(); if( mut_data.flags.count( b ) > 0 ) { + trait_flag_cache[b] = true; return true; } else if( mut_data.activated ) { Character &player = get_player_character(); if( ( mut_data.active_flags.count( b ) > 0 && player.has_active_mutation( mut ) ) || ( mut_data.inactive_flags.count( b ) > 0 && !player.has_active_mutation( mut ) ) ) { + trait_flag_cache[b] = true; return true; } } } + trait_flag_cache[b] = false; return false; } @@ -302,6 +309,8 @@ void Character::set_mutation_unsafe( const trait_id &trait, const mutation_varia if( !trait.obj().vanity ) { mutation_effect( trait, false ); } + + trait_flag_cache.clear(); } void Character::do_mutation_updates() @@ -334,6 +343,7 @@ void Character::set_mut_variant( const trait_id &trait, const mutation_variant * auto mutit = my_mutations.find( trait ); if( mutit != my_mutations.end() ) { mutit->second.variant = variant; + trait_flag_cache.clear(); } } @@ -357,6 +367,7 @@ void Character::unset_mutation( const trait_id &trait_ ) if( !mut.vanity ) { mutation_loss_effect( trait ); } + trait_flag_cache.clear(); do_mutation_updates(); } @@ -373,6 +384,7 @@ void Character::switch_mutations( const trait_id &switched, const trait_id &targ if( has_trait( target ) ) { my_mutations[target].powered = start_powered; } + trait_flag_cache.clear(); } bool Character::can_power_mutation( const trait_id &mut ) const @@ -635,7 +647,7 @@ void Character::mutation_effect( const trait_id &mut, const bool worn_destroyed_ if( branch.starts_active ) { my_mutations[mut].powered = true; } - + trait_flag_cache.clear(); on_mutation_gain( mut ); } @@ -666,6 +678,7 @@ void Character::mutation_loss_effect( const trait_id &mut ) remove_moncam( moncam.first ); } + trait_flag_cache.clear(); on_mutation_loss( mut ); } @@ -697,6 +710,7 @@ void Character::set_cost_timer( const trait_id &mut, time_duration set ) const auto all_iter = std::find( all_mut.begin(), all_mut.end(), mut ); if( iter != my_mutations.end() ) { iter->second.charge = set; + trait_flag_cache.clear(); } else if( all_iter == all_mut.end() ) { // don't have the mutation and don't have it from an item debugmsg( "Tried to set cost timer of %s but doesn't have this mutation.", mut.c_str() ); @@ -808,6 +822,8 @@ void Character::activate_mutation( const trait_id &mut ) mutation_name( mut ) ); return; } + + trait_flag_cache.clear(); if( tdata.powered && tdata.charge > 0_turns ) { // Already-on units just lose a bit of charge tdata.charge -= 1_turns; @@ -979,6 +995,7 @@ void Character::activate_mutation( const trait_id &mut ) void Character::deactivate_mutation( const trait_id &mut ) { my_mutations[mut].powered = false; + trait_flag_cache.clear(); // Handle stat changes from deactivation apply_mods( mut, false ); diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index e7c6ce6d51fb1..7a4d1b9ec8d8f 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -1000,6 +1000,7 @@ void Character::initialize( bool learn_recipes ) my_mutations[mut].powered = true; } } + trait_flag_cache.clear(); // Ensure that persistent morale effects (e.g. Optimist) are present at the start. apply_persistent_morale();