From 137967ac450987bdf3d53ba95d04346069aa501f Mon Sep 17 00:00:00 2001 From: irwiss Date: Wed, 15 May 2024 01:22:09 +0300 Subject: [PATCH 1/2] Load faults/fixes via generic_factory --- src/avatar_action.cpp | 4 +- src/character.cpp | 2 +- src/explosion.cpp | 4 +- src/fault.cpp | 292 ++++++++++++++++++++---------------------- src/fault.h | 45 ++++--- src/game.cpp | 4 +- src/init.cpp | 12 +- src/item.cpp | 4 +- 8 files changed, 179 insertions(+), 188 deletions(-) diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 0d9e8fc93a6a3..1c5e0d0ed29c5 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -1136,10 +1136,10 @@ void avatar_action::use_item( avatar &you, item_location &loc, std::string const if( loc->wetness && loc->has_flag( flag_WATER_BREAK_ACTIVE ) ) { if( query_yn( _( "This item is still wet and it will break if you turn it on. Proceed?" ) ) ) { loc->deactivate(); - loc.get_item()->set_fault( random_entry( fault::get_by_type( std::string( "wet" ) ) ) ); + loc.get_item()->set_fault( random_entry( faults::get_by_type( std::string( "wet" ) ) ) ); // An electronic item in water is also shorted. if( loc->has_flag( flag_ELECTRONIC ) ) { - loc.get_item()->set_fault( random_entry( fault::get_by_type( std::string( "shorted" ) ) ) ); + loc.get_item()->set_fault( random_entry( faults::get_by_type( std::string( "shorted" ) ) ) ); } } else { return; diff --git a/src/character.cpp b/src/character.cpp index 3d6e662ba3688..24afe64be6ec0 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -6736,7 +6736,7 @@ void Character::mend_item( item_location &&obj, bool interactive ) const fault_fix &fix = opt.fix; assign_activity( ACT_MEND_ITEM, to_moves( opt.time_to_fix ) ); activity.name = opt.fault.str(); - activity.str_values.emplace_back( fix.id_ ); + activity.str_values.emplace_back( fix.id.str() ); activity.targets.push_back( std::move( obj ) ); } } diff --git a/src/explosion.cpp b/src/explosion.cpp index 77dd8c2ddc7d7..6993f75a74a62 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -782,7 +782,7 @@ void emp_blast( const tripoint &p ) !player_character.has_flag( json_flag_EMP_IMMUNE ) ) { add_msg( m_bad, _( "The EMP blast fries your %s!" ), it->tname() ); it->deactivate(); - it->faults.insert( random_entry( fault::get_by_type( "shorted" ) ) ); + it->faults.insert( random_entry( faults::get_by_type( "shorted" ) ) ); } } } @@ -795,7 +795,7 @@ void emp_blast( const tripoint &p ) add_msg( _( "The EMP blast fries the %s!" ), it.tname() ); } it.deactivate(); - it.set_fault( random_entry( fault::get_by_type( "shorted" ) ) ); + it.set_fault( random_entry( faults::get_by_type( "shorted" ) ) ); } } // TODO: Drain NPC energy reserves diff --git a/src/fault.cpp b/src/fault.cpp index e754b84fd275e..43ee43f6665d5 100644 --- a/src/fault.cpp +++ b/src/fault.cpp @@ -3,62 +3,90 @@ #include #include -#include "assign.h" #include "debug.h" -#include "flexbuffer_json-inl.h" -#include "flexbuffer_json.h" #include "generic_factory.h" -#include "json_error.h" #include "requirements.h" -static std::map faults_all; -static std::map fault_fixes_all; +namespace +{ + +generic_factory fault_factory( "fault", "id" ); +generic_factory fault_fixes_factory( "fault_fix", "id" ); + +// we'll store requirement_ids here and wait for requirements to load in, then we can actualize them +std::multimap> reqs_temp_storage; + // Have a list of faults by type, the type right now is item prefix to avoid adding more JSON data -static std::map> faults_by_type; +std::map> faults_by_type; + +} // namespace + +const std::list &faults::get_by_type( const std::string &type ) +{ + return faults_by_type.at( type ); +} + +void faults::load_fault( const JsonObject &jo, const std::string &src ) +{ + fault_factory.load( jo, src ); +} + +void faults::load_fix( const JsonObject &jo, const std::string &src ) +{ + fault_fixes_factory.load( jo, src ); +} + +void faults::reset() +{ + fault_factory.reset(); + fault_fixes_factory.reset(); +} + +void faults::finalize() +{ + fault_factory.finalize(); + fault_fixes_factory.finalize(); + + // actualize the requirements + for( const fault_fix &const_fix : fault_fixes_factory.get_all() ) { + fault_fix &fix = const_cast( const_fix ); + fix.finalize(); + } + reqs_temp_storage.clear(); +} + +void faults::check_consistency() +{ + fault_factory.check(); + fault_fixes_factory.check(); +} /** @relates string_id */ template<> bool string_id::is_valid() const { - return faults_all.count( *this ); + return fault_factory.is_valid( *this ); } /** @relates string_id */ template<> const fault &string_id::obj() const { - const auto found = faults_all.find( *this ); - if( found == faults_all.end() ) { - debugmsg( "Tried to get invalid fault: %s", c_str() ); - static const fault null_fault{}; - return null_fault; - } - return found->second; + return fault_factory.obj( *this ); } /** @relates string_id */ template<> bool string_id::is_valid() const { - return fault_fixes_all.count( *this ); + return fault_fixes_factory.is_valid( *this ); } /** @relates string_id */ template<> const fault_fix &string_id::obj() const { - const auto found = fault_fixes_all.find( *this ); - if( found == fault_fixes_all.end() ) { - debugmsg( "Tried to get invalid fault fix: %s", c_str() ); - static const fault_fix null_fault_fix{}; - return null_fault_fix; - } - return found->second; -} - -const fault_id &fault::id() const -{ - return id_; + return fault_fixes_factory.obj( *this ); } std::string fault::name() const @@ -97,56 +125,27 @@ const std::set &fault::get_fixes() const return fixes; } -void fault::load( const JsonObject &jo ) +void fault::load( const JsonObject &jo, std::string_view ) { - fault f; - - mandatory( jo, false, "id", f.id_ ); - mandatory( jo, false, "name", f.name_ ); - mandatory( jo, false, "description", f.description_ ); - optional( jo, false, "item_prefix", f.item_prefix_ ); - optional( jo, false, "fault_type", f.type_ ); - optional( jo, false, "flags", f.flags ); - optional( jo, false, "price_modifier", f.price_modifier, 1.0 ); - - if( !faults_all.emplace( f.id_, f ).second ) { - jo.throw_error_at( "id", "parsed fault overwrites existing definition" ); + mandatory( jo, was_loaded, "name", name_ ); + mandatory( jo, was_loaded, "description", description_ ); + optional( jo, was_loaded, "item_prefix", item_prefix_ ); + optional( jo, was_loaded, "fault_type", type_ ); + optional( jo, was_loaded, "flags", flags ); + optional( jo, was_loaded, "price_modifier", price_modifier, 1.0 ); + if( !type_.empty() ) { + faults_by_type[ std::string( type_ ) ].push_back( id ); } - if( !f.type_.empty() ) { - faults_by_type[ std::string( f.type_ ) ].push_back( f.id() ); - } -} - -const std::map &fault::all() -{ - return faults_all; } -void fault::reset() +void fault::check() const { - faults_all.clear(); -} - -void fault::check_consistency() -{ - for( const auto& [fault_id, fault] : faults_all ) { - if( fault.name_.empty() ) { - debugmsg( "fault '%s' has empty name", fault_id.str() ); - } - if( fault.description_.empty() ) { - debugmsg( "fault '%s' has empty description", fault_id.str() ); - } + if( name_.empty() ) { + debugmsg( "fault '%s' has empty name", id.str() ); + } + if( description_.empty() ) { + debugmsg( "fault '%s' has empty description", id.str() ); } -} - -const std::map &fault_fix::all() -{ - return fault_fixes_all; -} - -const std::list &fault::get_by_type( const std::string &type ) -{ - return faults_by_type.at( type ); } const requirement_data &fault_fix::get_requirements() const @@ -154,25 +153,19 @@ const requirement_data &fault_fix::get_requirements() const return *requirements; } -// we'll store requirement_ids here and wait for requirements to load in, then we can actualize them -static std::multimap> reqs_temp_storage; - -void fault_fix::load( const JsonObject &jo ) +void fault_fix::load( const JsonObject &jo, std::string_view ) { - fault_fix f; - - assign( jo, "id", f.id_, true ); - assign( jo, "name", f.name, true ); - assign( jo, "success_msg", f.success_msg, true ); - assign( jo, "time", f.time, false ); - assign( jo, "set_variables", f.set_variables, true ); - assign( jo, "skills", f.skills, true ); - assign( jo, "faults_removed", f.faults_removed ); - assign( jo, "faults_added", f.faults_added ); - assign( jo, "mod_damage", f.mod_damage ); - assign( jo, "mod_degradation", f.mod_degradation ); - assign( jo, "time_save_profs", f.time_save_profs, false ); - assign( jo, "time_save_flags", f.time_save_flags, false ); + mandatory( jo, was_loaded, "name", name ); + optional( jo, was_loaded, "success_msg", success_msg ); + optional( jo, was_loaded, "time", time ); + optional( jo, was_loaded, "set_variables", set_variables ); + optional( jo, was_loaded, "skills", skills ); + optional( jo, was_loaded, "faults_removed", faults_removed ); + optional( jo, was_loaded, "faults_added", faults_added ); + optional( jo, was_loaded, "mod_damage", mod_damage ); + optional( jo, was_loaded, "mod_degradation", mod_degradation ); + optional( jo, was_loaded, "time_save_profs", time_save_profs ); + optional( jo, was_loaded, "time_save_flags", time_save_flags ); if( jo.has_array( "requirements" ) ) { for( const JsonValue &jv : jo.get_array( "requirements" ) ) { @@ -181,94 +174,81 @@ void fault_fix::load( const JsonObject &jo ) const JsonArray &req = static_cast( jv ); const std::string req_id = req.get_string( 0 ); const int req_amount = req.get_int( 1 ); - reqs_temp_storage.emplace( f.id_, std::make_pair( req_id, req_amount ) ); + reqs_temp_storage.emplace( id, std::make_pair( req_id, req_amount ) ); } else if( jv.test_object() ) { // defining single requirement inline const JsonObject &req = static_cast( jv ); - const requirement_id req_id( "fault_fix_" + f.id_.str() + "_inline_req" ); + const requirement_id req_id( "fault_fix_" + id.str() + "_inline_req" ); requirement_data::load_requirement( req, req_id ); - reqs_temp_storage.emplace( f.id_, std::make_pair( req_id.str(), 1 ) ); + reqs_temp_storage.emplace( id, std::make_pair( req_id.str(), 1 ) ); } else { - debugmsg( "fault_fix '%s' has has invalid requirement element", f.id_.str() ); + debugmsg( "fault_fix '%s' has has invalid requirement element", id.str() ); } } } - fault_fixes_all.emplace( f.id_, f ); -} - -void fault_fix::reset() -{ - fault_fixes_all.clear(); } void fault_fix::finalize() { - for( auto& [fix_id, fix] : fault_fixes_all ) { - const auto range = reqs_temp_storage.equal_range( fix_id ); - for( auto it = range.first; it != range.second; ++it ) { - const requirement_id req_id( it->second.first ); - const int amount = it->second.second; - if( !req_id.is_valid() ) { - debugmsg( "fault_fix '%s' has invalid requirement_id '%s'", fix_id.str(), req_id.str() ); - continue; - } - *fix.requirements = *fix.requirements + ( *req_id ) * amount; - } - fix.requirements->consolidate(); - for( const fault_id &fid : fix.faults_removed ) { - const_cast( *fid ).fixes.emplace( fix_id ); + const auto range = reqs_temp_storage.equal_range( id ); + for( auto it = range.first; it != range.second; ++it ) { + const requirement_id req_id( it->second.first ); + const int amount = it->second.second; + if( !req_id.is_valid() ) { + debugmsg( "fault_fix '%s' has invalid requirement_id '%s'", id.str(), req_id.str() ); + continue; } + *requirements = *requirements + ( *req_id ) * amount; + } + requirements->consolidate(); + for( const fault_id &fid : faults_removed ) { + const_cast( *fid ).fixes.emplace( id ); } - reqs_temp_storage.clear(); } -void fault_fix::check_consistency() +void fault_fix::check() const { - for( const auto &[fix_id, fix] : fault_fixes_all ) { - if( fix.time < 0_turns ) { - debugmsg( "fault_fix '%s' has negative time", fix_id.str() ); + if( time < 0_turns ) { + debugmsg( "fault_fix '%s' has negative time", id.str() ); + } + for( const auto &[skill_id, lvl] : skills ) { + if( !skill_id.is_valid() ) { + debugmsg( "fault_fix %s requires unknown skill '%s'", id.str(), skill_id.str() ); } - for( const auto &[skill_id, lvl] : fix.skills ) { - if( !skill_id.is_valid() ) { - debugmsg( "fault_fix %s requires unknown skill '%s'", - fix_id.str(), skill_id.str() ); - } - if( lvl <= 0 ) { - debugmsg( "fault_fix '%s' requires negative level of skill '%s'", - fix_id.str(), skill_id.str() ); - } + if( lvl <= 0 ) { + debugmsg( "fault_fix '%s' requires negative level of skill '%s'", id.str(), skill_id.str() ); } - for( const fault_id &fault_id : fix.faults_removed ) { - if( !fault_id.is_valid() ) { - debugmsg( "fault_fix '%s' has invalid fault_id '%s' in 'faults_removed' field", - fix_id.str(), fault_id.str() ); - } + } + for( const fault_id &fault_id : faults_removed ) { + if( !fault_id.is_valid() ) { + debugmsg( "fault_fix '%s' has invalid fault_id '%s' in 'faults_removed' field", + id.str(), fault_id.str() ); } - for( const fault_id &fault_id : fix.faults_added ) { - if( !fault_id.is_valid() ) { - debugmsg( "fault_fix '%s' has invalid fault_id '%s' in 'faults_added' field", - fix_id.str(), fault_id.str() ); - } + } + for( const fault_id &fault_id : faults_added ) { + if( !fault_id.is_valid() ) { + debugmsg( "fault_fix '%s' has invalid fault_id '%s' in 'faults_added' field", + id.str(), fault_id.str() ); } - for( const auto &[proficiency_id, mult] : fix.time_save_profs ) { - if( !proficiency_id.is_valid() ) { - debugmsg( "fault_fix %s has unknown proficiency_id '%s'", - fix_id.str(), proficiency_id.str() ); - } - if( mult < 0 ) { - debugmsg( "fault_fix '%s' has negative mend time if possessing proficiency '%s'", - fix_id.str(), proficiency_id.str() ); - } + } + for( const auto &[proficiency_id, mult] : time_save_profs ) { + if( !proficiency_id.is_valid() ) { + debugmsg( "fault_fix %s has unknown proficiency_id '%s'", + id.str(), proficiency_id.str() ); } - for( const auto &[flag_id, mult] : fix.time_save_flags ) { - if( !flag_id.is_valid() ) { - debugmsg( "fault_fix %s has unknown flag_id '%s'", - fix_id.str(), flag_id.str() ); - } - if( mult < 0 ) { - debugmsg( "fault_fix '%s' has negative mend time if item possesses flag '%s'", - fix_id.str(), flag_id.str() ); - } + if( mult < 0 ) { + debugmsg( "fault_fix '%s' has negative mend time if possessing proficiency '%s'", + id.str(), proficiency_id.str() ); + } + } + for( const auto &[flag_id, mult] : time_save_flags ) { + if( !flag_id.is_valid() ) { + debugmsg( "fault_fix %s has unknown flag_id '%s'", + id.str(), flag_id.str() ); + } + if( mult < 0 ) { + debugmsg( "fault_fix '%s' has negative mend time if item possesses flag '%s'", + id.str(), flag_id.str() ); } } } diff --git a/src/fault.h b/src/fault.h index a0054375f1285..b8a3f03e4cfea 100644 --- a/src/fault.h +++ b/src/fault.h @@ -14,15 +14,32 @@ #include "translation.h" #include "type_id.h" +template class generic_factory; + +class fault; +class fault_fix; class JsonObject; +struct requirement_data; + +namespace faults +{ +void load_fault( const JsonObject &jo, const std::string &src ); +void load_fix( const JsonObject &jo, const std::string &src ); + +void reset(); +void finalize(); +void check_consistency(); + +const std::list &get_by_type( const std::string &type ); +} // namespace faults class fault_fix { public: - fault_fix_id id_ = fault_fix_id::NULL_ID(); + fault_fix_id id = fault_fix_id::NULL_ID(); translation name; translation success_msg; // message to print on applying successfully - time_duration time; + time_duration time = 0_seconds; std::map set_variables; // item vars applied to item std::map skills; // map of skill_id to required level std::set faults_removed; // which faults are removed on applying @@ -36,12 +53,12 @@ class fault_fix const requirement_data &get_requirements() const; - static void load( const JsonObject &jo ); - static const std::map &all(); - static void reset(); - static void finalize(); - static void check_consistency(); + void finalize(); private: + void load( const JsonObject &jo, std::string_view src ); + void check() const; + bool was_loaded = false; // used by generic_factory + friend class generic_factory; friend class fault; shared_ptr_fast requirements = make_shared_fast(); }; @@ -49,7 +66,7 @@ class fault_fix class fault { public: - const fault_id &id() const; + fault_id id = fault_id::NULL_ID(); std::string name() const; std::string type() const; // use a set of types? std::string description() const; @@ -58,16 +75,12 @@ class fault bool has_flag( const std::string &flag ) const; const std::set &get_fixes() const; - - static const std::map &all(); - static const std::list &get_by_type( const std::string &type ); - static void load( const JsonObject &jo ); - static void reset(); - static void check_consistency(); - private: + void load( const JsonObject &jo, std::string_view ); + void check() const; + bool was_loaded = false; // used by generic_factory + friend class generic_factory; friend class fault_fix; - fault_id id_ = fault_id::NULL_ID(); std::string type_; translation name_; translation description_; diff --git a/src/game.cpp b/src/game.cpp index 34b9be63b7d98..e85a411d43d3e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -11795,10 +11795,10 @@ void game::water_affect_items( Character &ch ) const loc->deactivate(); // TODO: Maybe different types of wet faults? But I can't think of any. // This just means it's still too wet to use. - loc->set_fault( random_entry( fault::get_by_type( std::string( "wet" ) ) ) ); + loc->set_fault( random_entry( faults::get_by_type( std::string( "wet" ) ) ) ); // An electronic item in water is also shorted. if( loc->has_flag( flag_ELECTRONIC ) ) { - loc->set_fault( random_entry( fault::get_by_type( std::string( "shorted" ) ) ) ); + loc->set_fault( random_entry( faults::get_by_type( std::string( "shorted" ) ) ) ); } } else if( loc->has_flag( flag_WATER_BREAK_ACTIVE ) && !loc->is_broken() && !loc.protected_from_liquids() ) { diff --git a/src/init.cpp b/src/init.cpp index c65e6be9b599c..beda2c8d1ba87 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -249,8 +249,8 @@ void DynamicDataLoader::initialize() add( "jmath_function", &jmath_func::load_func ); add( "var_migration", &global_variables::load_migrations ); add( "connect_group", &connect_group::load ); - add( "fault", &fault::load ); - add( "fault_fix", &fault_fix::load ); + add( "fault", &faults::load_fault ); + add( "fault_fix", &faults::load_fix ); add( "relic_procgen_data", &relic_procgen_data::load_relic_procgen_data ); add( "effect_on_condition", &effect_on_conditions::load ); add( "field_type", &field_types::load ); @@ -579,8 +579,7 @@ void DynamicDataLoader::unload_data() effect_on_conditions::reset(); event_transformation::reset(); faction_template::reset(); - fault_fix::reset(); - fault::reset(); + faults::reset(); field_types::reset(); gates::reset(); harvest_drop_type::reset(); @@ -757,7 +756,7 @@ void DynamicDataLoader::finalize_loaded_data( loading_ui &ui ) { _( "Achievements" ), &achievement::finalize }, { _( "Damage info orders" ), &damage_info_order::finalize_all }, { _( "Widgets" ), &widget::finalize }, - { _( "Fault fixes" ), &fault_fix::finalize }, + { _( "Faults" ), &faults::finalize }, #if defined(TILES) { _( "Tileset" ), &load_tileset }, #endif @@ -811,8 +810,7 @@ void DynamicDataLoader::check_consistency( loading_ui &ui ) } }, { _( "Materials" ), &materials::check }, - { _( "Faults" ), &fault::check_consistency }, - { _( "Fault fixes" ), &fault_fix::check_consistency }, + { _( "Faults" ), &faults::check_consistency }, { _( "Vehicle parts" ), &vehicles::parts::check }, { _( "Vehicle part migrations" ), &vpart_migration::check }, { _( "Mapgen definitions" ), &check_mapgen_definitions }, diff --git a/src/item.cpp b/src/item.cpp index 9d3850ee9f9ca..f82ef25fc900a 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -14132,9 +14132,9 @@ bool item::process_internal( map &here, Character *carrier, const tripoint &pos, if( wetness && has_flag( flag_WATER_BREAK ) ) { deactivate(); - set_fault( random_entry( fault::get_by_type( std::string( "wet" ) ) ) ); + set_fault( random_entry( faults::get_by_type( std::string( "wet" ) ) ) ); if( has_flag( flag_ELECTRONIC ) ) { - set_fault( random_entry( fault::get_by_type( std::string( "shorted" ) ) ) ); + set_fault( random_entry( faults::get_by_type( std::string( "shorted" ) ) ) ); } } From 779b8fc5f12ae29189f876641aa5d08f597998af Mon Sep 17 00:00:00 2001 From: irwiss Date: Wed, 15 May 2024 02:53:25 +0300 Subject: [PATCH 2/2] Cleanup fault types --- data/core/sentinels.json | 6 ++++++ src/avatar_action.cpp | 4 ++-- src/explosion.cpp | 4 ++-- src/fault.cpp | 21 +++++++++++++++------ src/fault.h | 3 +-- src/game.cpp | 4 ++-- src/item.cpp | 4 ++-- 7 files changed, 30 insertions(+), 16 deletions(-) diff --git a/data/core/sentinels.json b/data/core/sentinels.json index 9189e86e1288d..06a74c091b5f8 100644 --- a/data/core/sentinels.json +++ b/data/core/sentinels.json @@ -44,6 +44,12 @@ "legacy_enum_id": 0, "intensity_levels": [ { "name": "nothing" } ] }, + { + "id": "null", + "type": "fault", + "name": { "str": "This is a bug" }, + "description": "This fault id is a reserved sentinel." + }, { "type": "SPELL", "id": "null", diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 1c5e0d0ed29c5..999258b8f4c9c 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -1136,10 +1136,10 @@ void avatar_action::use_item( avatar &you, item_location &loc, std::string const if( loc->wetness && loc->has_flag( flag_WATER_BREAK_ACTIVE ) ) { if( query_yn( _( "This item is still wet and it will break if you turn it on. Proceed?" ) ) ) { loc->deactivate(); - loc.get_item()->set_fault( random_entry( faults::get_by_type( std::string( "wet" ) ) ) ); + loc.get_item()->set_fault( faults::random_of_type( "wet" ) ); // An electronic item in water is also shorted. if( loc->has_flag( flag_ELECTRONIC ) ) { - loc.get_item()->set_fault( random_entry( faults::get_by_type( std::string( "shorted" ) ) ) ); + loc.get_item()->set_fault( faults::random_of_type( "shorted" ) ); } } else { return; diff --git a/src/explosion.cpp b/src/explosion.cpp index 6993f75a74a62..23e98a30cf1f0 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -782,7 +782,7 @@ void emp_blast( const tripoint &p ) !player_character.has_flag( json_flag_EMP_IMMUNE ) ) { add_msg( m_bad, _( "The EMP blast fries your %s!" ), it->tname() ); it->deactivate(); - it->faults.insert( random_entry( faults::get_by_type( "shorted" ) ) ); + it->faults.insert( faults::random_of_type( "shorted" ) ); } } } @@ -795,7 +795,7 @@ void emp_blast( const tripoint &p ) add_msg( _( "The EMP blast fries the %s!" ), it.tname() ); } it.deactivate(); - it.set_fault( random_entry( faults::get_by_type( "shorted" ) ) ); + it.set_fault( faults::random_of_type( "shorted" ) ); } } // TODO: Drain NPC energy reserves diff --git a/src/fault.cpp b/src/fault.cpp index 43ee43f6665d5..e5d3a9697f1a4 100644 --- a/src/fault.cpp +++ b/src/fault.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "debug.h" #include "generic_factory.h" @@ -17,13 +18,18 @@ generic_factory fault_fixes_factory( "fault_fix", "id" ); std::multimap> reqs_temp_storage; // Have a list of faults by type, the type right now is item prefix to avoid adding more JSON data -std::map> faults_by_type; +std::map> faults_by_type; } // namespace -const std::list &faults::get_by_type( const std::string &type ) +const fault_id &faults::random_of_type( const std::string &type ) { - return faults_by_type.at( type ); + const auto &typed = faults_by_type.find( type ); + if( typed == faults_by_type.end() ) { + debugmsg( "there are no faults with type '%s'", type ); + return fault_id::NULL_ID(); + } + return random_entry_ref( typed->second ); } void faults::load_fault( const JsonObject &jo, const std::string &src ) @@ -40,6 +46,7 @@ void faults::reset() { fault_factory.reset(); fault_fixes_factory.reset(); + faults_by_type.clear(); } void faults::finalize() @@ -52,6 +59,11 @@ void faults::finalize() fault_fix &fix = const_cast( const_fix ); fix.finalize(); } + for( const fault &f : fault_factory.get_all() ) { + if( !f.type().empty() ) { + faults_by_type[f.type()].emplace_back( f.id.str() ); + } + } reqs_temp_storage.clear(); } @@ -133,9 +145,6 @@ void fault::load( const JsonObject &jo, std::string_view ) optional( jo, was_loaded, "fault_type", type_ ); optional( jo, was_loaded, "flags", flags ); optional( jo, was_loaded, "price_modifier", price_modifier, 1.0 ); - if( !type_.empty() ) { - faults_by_type[ std::string( type_ ) ].push_back( id ); - } } void fault::check() const diff --git a/src/fault.h b/src/fault.h index b8a3f03e4cfea..b2512d66d306b 100644 --- a/src/fault.h +++ b/src/fault.h @@ -2,7 +2,6 @@ #ifndef CATA_SRC_FAULT_H #define CATA_SRC_FAULT_H -#include #include #include #include @@ -30,7 +29,7 @@ void reset(); void finalize(); void check_consistency(); -const std::list &get_by_type( const std::string &type ); +const fault_id &random_of_type( const std::string &type ); } // namespace faults class fault_fix diff --git a/src/game.cpp b/src/game.cpp index e85a411d43d3e..5e3d3b3b974af 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -11795,10 +11795,10 @@ void game::water_affect_items( Character &ch ) const loc->deactivate(); // TODO: Maybe different types of wet faults? But I can't think of any. // This just means it's still too wet to use. - loc->set_fault( random_entry( faults::get_by_type( std::string( "wet" ) ) ) ); + loc->set_fault( faults::random_of_type( "wet" ) ) ; // An electronic item in water is also shorted. if( loc->has_flag( flag_ELECTRONIC ) ) { - loc->set_fault( random_entry( faults::get_by_type( std::string( "shorted" ) ) ) ); + loc->set_fault( faults::random_of_type( "shorted" ) ); } } else if( loc->has_flag( flag_WATER_BREAK_ACTIVE ) && !loc->is_broken() && !loc.protected_from_liquids() ) { diff --git a/src/item.cpp b/src/item.cpp index f82ef25fc900a..270153fe01a50 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -14132,9 +14132,9 @@ bool item::process_internal( map &here, Character *carrier, const tripoint &pos, if( wetness && has_flag( flag_WATER_BREAK ) ) { deactivate(); - set_fault( random_entry( faults::get_by_type( std::string( "wet" ) ) ) ); + set_fault( faults::random_of_type( "wet" ) ); if( has_flag( flag_ELECTRONIC ) ) { - set_fault( random_entry( faults::get_by_type( std::string( "shorted" ) ) ) ); + set_fault( faults::random_of_type( "shorted" ) ); } }