From e792bb88f004bd9e39f3d088763313fe3570af69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jianxiang=20Wang=20=28=E7=8E=8B=E5=81=A5=E7=BF=94=29?= Date: Fri, 24 Jan 2020 14:38:58 +0800 Subject: [PATCH] Computer refactor part 2 (#37299) * Remove unnecessary/unused members of class computer * Make name and mission_id of computer private * Make alerts a member of computer * Move initialization of next_attempt to constructor * Replace shutdown_terminal with reset_terminal * Check option enum instead of (translated) option string * Migrate computer_action and computer_failure_type to use enum conversion * Use JSON (de)serialization in class computer * Lift ordering restriction of computer_action and computer_failure_type * Remove COMPACT_OBSOLETE * Fix COMPFAIL_DESTROY_DATA range * Remove const modifiers in function declarations Co-Authored-By: ZhilkinSerg Co-authored-by: ZhilkinSerg --- src/computer.cpp | 381 ++++++++++++++++++++++++++------------- src/computer.h | 117 ++++++------ src/computer_session.cpp | 45 ++--- src/computer_session.h | 2 - src/mapgen.cpp | 2 +- src/mission_start.cpp | 6 +- src/savegame_json.cpp | 10 +- 7 files changed, 338 insertions(+), 225 deletions(-) diff --git a/src/computer.cpp b/src/computer.cpp index e522b0118a620..f11ce32832582 100644 --- a/src/computer.cpp +++ b/src/computer.cpp @@ -19,28 +19,48 @@ computer_option::computer_option( const std::string &N, computer_action A, int S { } -computer::computer( const std::string &new_name, int new_security ) - : name( new_name ), mission_id( -1 ), security( new_security ), - access_denied( _( "ERROR! Access denied!" ) ) +void computer_option::serialize( JsonOut &jout ) const { + jout.start_object(); + jout.member( "name", name ); + jout.member( "action" ); + jout.write_as_string( action ); + jout.member( "security", security ); + jout.end_object(); } -computer::computer( const computer &rhs ) +void computer_option::deserialize( JsonIn &jin ) { - *this = rhs; + const JsonObject jo = jin.get_object(); + name = jo.get_string( "name" ); + action = jo.get_enum_value( "action" ); + security = jo.get_int( "security" ); } -computer::~computer() = default; +computer_failure::computer_failure() + : type( COMPFAIL_NULL ) +{ +} -computer &computer::operator=( const computer &rhs ) +void computer_failure::serialize( JsonOut &jout ) const +{ + jout.start_object(); + jout.member( "action" ); + jout.write_as_string( type ); + jout.end_object(); +} + +void computer_failure::deserialize( JsonIn &jin ) +{ + const JsonObject jo = jin.get_object(); + type = jo.get_enum_value( "action" ); +} + +computer::computer( const std::string &new_name, int new_security ) + : name( new_name ), mission_id( -1 ), security( new_security ), alerts( 0 ), + next_attempt( calendar::before_time_starts ), + access_denied( _( "ERROR! Access denied!" ) ) { - security = rhs.security; - name = rhs.name; - access_denied = rhs.access_denied; - mission_id = rhs.mission_id; - options = rhs.options; - failures = rhs.failures; - return *this; } void computer::set_security( int Security ) @@ -74,38 +94,16 @@ void computer::set_access_denied_msg( const std::string &new_msg ) access_denied = new_msg; } -std::string computer::save_data() const +void computer::set_mission( const int id ) { - std::ostringstream data; - - data.imbue( std::locale::classic() ); - - data - << string_replace( name, " ", "_" ) << ' ' - << security << ' ' - << mission_id << ' ' - << options.size() << ' '; - - for( auto &elem : options ) { - data - << string_replace( elem.name, " ", "_" ) << ' ' - << static_cast( elem.action ) << ' ' - << elem.security << ' '; - } - - data << failures.size() << ' '; - for( auto &elem : failures ) { - data << static_cast( elem.type ) << ' '; - } - - data << string_replace( access_denied, " ", "_" ) << ' '; - - return data.str(); + mission_id = id; } -void computer::load_data( const std::string &data ) +static computer_action computer_action_from_legacy_enum( int val ); +static computer_failure_type computer_failure_type_from_legacy_enum( int val ); + +void computer::load_legacy_data( const std::string &data ) { - static const std::set blacklisted_options = {{ "Launch_Missile" }}; options.clear(); failures.clear(); @@ -126,10 +124,13 @@ void computer::load_data( const std::string &data ) int tmpsec; dump >> tmpname >> tmpaction >> tmpsec; - if( blacklisted_options.find( tmpname ) != blacklisted_options.end() ) { + // Legacy missle launch option that got removed before `computer_action` was + // refactored to be saved and loaded as string ids. Do not change this number: + // `computer_action` now has different underlying values from back then! + if( tmpaction == 15 ) { continue; } - add_option( string_replace( tmpname, "_", " " ), static_cast( tmpaction ), + add_option( string_replace( tmpname, "_", " " ), computer_action_from_legacy_enum( tmpaction ), tmpsec ); } @@ -139,7 +140,7 @@ void computer::load_data( const std::string &data ) for( int n = 0; n < failsize; n++ ) { int tmpfail; dump >> tmpfail; - add_failure( static_cast( tmpfail ) ); + add_failure( computer_failure_type_from_legacy_enum( tmpfail ) ); } std::string tmp_access_denied; @@ -153,6 +154,37 @@ void computer::load_data( const std::string &data ) } } +void computer::serialize( JsonOut &jout ) const +{ + jout.start_object(); + jout.member( "name", name ); + jout.member( "mission", mission_id ); + jout.member( "security", security ); + jout.member( "alerts", alerts ); + jout.member( "next_attempt", next_attempt ); + jout.member( "options", options ); + jout.member( "failures", failures ); + jout.member( "access_denied", access_denied ); + jout.end_object(); +} + +void computer::deserialize( JsonIn &jin ) +{ + if( jin.test_string() ) { + load_legacy_data( jin.get_string() ); + } else { + const JsonObject jo = jin.get_object(); + jo.read( "name", name ); + jo.read( "mission", mission_id ); + jo.read( "security", security ); + jo.read( "alerts", alerts ); + jo.read( "next_attempt", next_attempt ); + jo.read( "options", options ); + jo.read( "failures", failures ); + jo.read( "access_denied", access_denied ); + } +} + void computer::remove_option( computer_action const action ) { for( auto it = options.begin(); it != options.end(); ++it ) { @@ -163,105 +195,196 @@ void computer::remove_option( computer_action const action ) } } -static computer_action computer_action_from_string( const std::string &str ) +static computer_action computer_action_from_legacy_enum( const int val ) { - static const std::map actions = {{ - { "null", COMPACT_NULL }, - { "open", COMPACT_OPEN }, - { "open_disarm", COMPACT_OPEN_DISARM }, - { "lock", COMPACT_LOCK }, - { "unlock", COMPACT_UNLOCK }, - { "unlock_disarm", COMPACT_UNLOCK_DISARM }, - { "toll", COMPACT_TOLL }, - { "sample", COMPACT_SAMPLE }, - { "release", COMPACT_RELEASE }, - { "release_bionics", COMPACT_RELEASE_BIONICS }, - { "release_disarm", COMPACT_RELEASE_DISARM }, - { "terminate", COMPACT_TERMINATE }, - { "portal", COMPACT_PORTAL }, - { "cascade", COMPACT_CASCADE }, - { "research", COMPACT_RESEARCH }, - { "maps", COMPACT_MAPS }, - { "map_sewer", COMPACT_MAP_SEWER }, - { "map_subway", COMPACT_MAP_SUBWAY }, - { "miss_disarm", COMPACT_MISS_DISARM }, - { "list_bionics", COMPACT_LIST_BIONICS }, - { "elevator_on", COMPACT_ELEVATOR_ON }, - { "amigara_log", COMPACT_AMIGARA_LOG }, - { "amigara_start", COMPACT_AMIGARA_START }, - { "complete_disable_external_power", COMPACT_COMPLETE_DISABLE_EXTERNAL_POWER }, - { "repeater_mod", COMPACT_REPEATER_MOD }, - { "download_software", COMPACT_DOWNLOAD_SOFTWARE }, - { "blood_anal", COMPACT_BLOOD_ANAL }, - { "data_anal", COMPACT_DATA_ANAL }, - { "disconnect", COMPACT_DISCONNECT }, - { "emerg_mess", COMPACT_EMERG_MESS }, - { "emerg_ref_center", COMPACT_EMERG_REF_CENTER }, - { "tower_unresponsive", COMPACT_TOWER_UNRESPONSIVE }, - { "sr1_mess", COMPACT_SR1_MESS }, - { "sr2_mess", COMPACT_SR2_MESS }, - { "sr3_mess", COMPACT_SR3_MESS }, - { "sr4_mess", COMPACT_SR4_MESS }, - { "srcf_1_mess", COMPACT_SRCF_1_MESS }, - { "srcf_2_mess", COMPACT_SRCF_2_MESS }, - { "srcf_3_mess", COMPACT_SRCF_3_MESS }, - { "srcf_seal_order", COMPACT_SRCF_SEAL_ORDER }, - { "srcf_seal", COMPACT_SRCF_SEAL }, - { "srcf_elevator", COMPACT_SRCF_ELEVATOR }, - { "irradiator", COMPACT_IRRADIATOR }, - { "geiger", COMPACT_GEIGER }, - { "conveyor", COMPACT_CONVEYOR }, - { "shutters", COMPACT_SHUTTERS }, - { "extract_rad_source", COMPACT_EXTRACT_RAD_SOURCE }, - { "deactivate_shock_vent", COMPACT_DEACTIVATE_SHOCK_VENT }, - { "radio_archive", COMPACT_RADIO_ARCHIVE } - } - }; - - const auto iter = actions.find( str ); - if( iter != actions.end() ) { - return iter->second; + switch( val ) { + // Used to migrate old saves. Do not change the numbers! + // *INDENT-OFF* + default: return COMPACT_NULL; + case 0: return COMPACT_NULL; + case 1: return COMPACT_OPEN; + case 2: return COMPACT_LOCK; + case 3: return COMPACT_UNLOCK; + case 4: return COMPACT_TOLL; + case 5: return COMPACT_SAMPLE; + case 6: return COMPACT_RELEASE; + case 7: return COMPACT_RELEASE_BIONICS; + case 8: return COMPACT_TERMINATE; + case 9: return COMPACT_PORTAL; + case 10: return COMPACT_CASCADE; + case 11: return COMPACT_RESEARCH; + case 12: return COMPACT_MAPS; + case 13: return COMPACT_MAP_SEWER; + case 14: return COMPACT_MAP_SUBWAY; + // options with action enum 15 are removed in load_legacy_data() + case 16: return COMPACT_MISS_DISARM; + case 17: return COMPACT_LIST_BIONICS; + case 18: return COMPACT_ELEVATOR_ON; + case 19: return COMPACT_AMIGARA_LOG; + case 20: return COMPACT_AMIGARA_START; + case 21: return COMPACT_COMPLETE_DISABLE_EXTERNAL_POWER; + case 22: return COMPACT_REPEATER_MOD; + case 23: return COMPACT_DOWNLOAD_SOFTWARE; + case 24: return COMPACT_BLOOD_ANAL; + case 25: return COMPACT_DATA_ANAL; + case 26: return COMPACT_DISCONNECT; + case 27: return COMPACT_EMERG_MESS; + case 28: return COMPACT_EMERG_REF_CENTER; + case 29: return COMPACT_TOWER_UNRESPONSIVE; + case 30: return COMPACT_SR1_MESS; + case 31: return COMPACT_SR2_MESS; + case 32: return COMPACT_SR3_MESS; + case 33: return COMPACT_SR4_MESS; + case 34: return COMPACT_SRCF_1_MESS; + case 35: return COMPACT_SRCF_2_MESS; + case 36: return COMPACT_SRCF_3_MESS; + case 37: return COMPACT_SRCF_SEAL_ORDER; + case 38: return COMPACT_SRCF_SEAL; + case 39: return COMPACT_SRCF_ELEVATOR; + case 40: return COMPACT_OPEN_DISARM; + case 41: return COMPACT_UNLOCK_DISARM; + case 42: return COMPACT_RELEASE_DISARM; + case 43: return COMPACT_IRRADIATOR; + case 44: return COMPACT_GEIGER; + case 45: return COMPACT_CONVEYOR; + case 46: return COMPACT_SHUTTERS; + case 47: return COMPACT_EXTRACT_RAD_SOURCE; + case 48: return COMPACT_DEACTIVATE_SHOCK_VENT; + case 49: return COMPACT_RADIO_ARCHIVE; + // *INDENT-ON* } - - debugmsg( "Invalid computer action %s", str ); - return COMPACT_NULL; } -static computer_failure_type computer_failure_type_from_string( const std::string &str ) +static computer_failure_type computer_failure_type_from_legacy_enum( const int val ) { - static const std::map fails = {{ - { "null", COMPFAIL_NULL }, - { "shutdown", COMPFAIL_SHUTDOWN }, - { "alarm", COMPFAIL_ALARM }, - { "manhacks", COMPFAIL_MANHACKS }, - { "secubots", COMPFAIL_SECUBOTS }, - { "damage", COMPFAIL_DAMAGE }, - { "pump_explode", COMPFAIL_PUMP_EXPLODE }, - { "pump_leak", COMPFAIL_PUMP_LEAK }, - { "amigara", COMPFAIL_AMIGARA }, - { "destroy_blood", COMPFAIL_DESTROY_BLOOD }, - { "destroy_data", COMPFAIL_DESTROY_DATA } - } - }; + switch( val ) { + // Used to migrate old saves. Do not change the numbers! + // *INDENT-OFF* + default: return COMPFAIL_NULL; + case 0: return COMPFAIL_NULL; + case 1: return COMPFAIL_SHUTDOWN; + case 2: return COMPFAIL_ALARM; + case 3: return COMPFAIL_MANHACKS; + case 4: return COMPFAIL_SECUBOTS; + case 5: return COMPFAIL_DAMAGE; + case 6: return COMPFAIL_PUMP_EXPLODE; + case 7: return COMPFAIL_PUMP_LEAK; + case 8: return COMPFAIL_AMIGARA; + case 9: return COMPFAIL_DESTROY_BLOOD; + case 10: return COMPFAIL_DESTROY_DATA; + // *INDENT-ON* + } +} - const auto iter = fails.find( str ); - if( iter != fails.end() ) { - return iter->second; +namespace io +{ +template<> +std::string enum_to_string( const computer_action act ) +{ + switch( act ) { + // *INDENT-OFF* + case COMPACT_NULL: return "null"; + case COMPACT_AMIGARA_LOG: return "amigara_log"; + case COMPACT_AMIGARA_START: return "amigara_start"; + case COMPACT_BLOOD_ANAL: return "blood_anal"; + case COMPACT_CASCADE: return "cascade"; + case COMPACT_COMPLETE_DISABLE_EXTERNAL_POWER: return "complete_disable_external_power"; + case COMPACT_CONVEYOR: return "conveyor"; + case COMPACT_DATA_ANAL: return "data_anal"; + case COMPACT_DEACTIVATE_SHOCK_VENT: return "deactivate_shock_vent"; + case COMPACT_DISCONNECT: return "disconnect"; + case COMPACT_DOWNLOAD_SOFTWARE: return "download_software"; + case COMPACT_ELEVATOR_ON: return "elevator_on"; + case COMPACT_EMERG_MESS: return "emerg_mess"; + case COMPACT_EMERG_REF_CENTER: return "emerg_ref_center"; + case COMPACT_EXTRACT_RAD_SOURCE: return "extract_rad_source"; + case COMPACT_GEIGER: return "geiger"; + case COMPACT_IRRADIATOR: return "irradiator"; + case COMPACT_LIST_BIONICS: return "list_bionics"; + case COMPACT_LOCK: return "lock"; + case COMPACT_MAP_SEWER: return "map_sewer"; + case COMPACT_MAP_SUBWAY: return "map_subway"; + case COMPACT_MAPS: return "maps"; + case COMPACT_MISS_DISARM: return "miss_disarm"; + case COMPACT_OPEN: return "open"; + case COMPACT_OPEN_DISARM: return "open_disarm"; + case COMPACT_PORTAL: return "portal"; + case COMPACT_RADIO_ARCHIVE: return "radio_archive"; + case COMPACT_RELEASE: return "release"; + case COMPACT_RELEASE_BIONICS: return "release_bionics"; + case COMPACT_RELEASE_DISARM: return "release_disarm"; + case COMPACT_REPEATER_MOD: return "repeater_mod"; + case COMPACT_RESEARCH: return "research"; + case COMPACT_SAMPLE: return "sample"; + case COMPACT_SHUTTERS: return "shutters"; + case COMPACT_SR1_MESS: return "sr1_mess"; + case COMPACT_SR2_MESS: return "sr2_mess"; + case COMPACT_SR3_MESS: return "sr3_mess"; + case COMPACT_SR4_MESS: return "sr4_mess"; + case COMPACT_SRCF_1_MESS: return "srcf_1_mess"; + case COMPACT_SRCF_2_MESS: return "srcf_2_mess"; + case COMPACT_SRCF_3_MESS: return "srcf_3_mess"; + case COMPACT_SRCF_ELEVATOR: return "srcf_elevator"; + case COMPACT_SRCF_SEAL: return "srcf_seal"; + case COMPACT_SRCF_SEAL_ORDER: return "srcf_seal_order"; + case COMPACT_TERMINATE: return "terminate"; + case COMPACT_TOLL: return "toll"; + case COMPACT_TOWER_UNRESPONSIVE: return "tower_unresponsive"; + case COMPACT_UNLOCK: return "unlock"; + case COMPACT_UNLOCK_DISARM: return "unlock_disarm"; + // *INDENT-OFF* + case NUM_COMPUTER_ACTIONS: + break; } + debugmsg( "Invalid computer_action" ); + abort(); +} - debugmsg( "Invalid computer failure %s", str ); - return COMPFAIL_NULL; +template<> +std::string enum_to_string( const computer_failure_type fail ) +{ + switch( fail ){ + // *INDENT-OFF* + case COMPFAIL_NULL: return "null"; + case COMPFAIL_ALARM: return "alarm"; + case COMPFAIL_AMIGARA: return "amigara"; + case COMPFAIL_DAMAGE: return "damage"; + case COMPFAIL_DESTROY_BLOOD: return "destroy_blood"; + case COMPFAIL_DESTROY_DATA: return "destroy_data"; + case COMPFAIL_MANHACKS: return "manhacks"; + case COMPFAIL_PUMP_EXPLODE: return "pump_explode"; + case COMPFAIL_PUMP_LEAK: return "pump_leak"; + case COMPFAIL_SECUBOTS: return "secubots"; + case COMPFAIL_SHUTDOWN: return "shutdown"; + // *INDENT-ON* + case NUM_COMPUTER_FAILURES: + break; + } + debugmsg( "Invalid computer_failure_type" ); + abort(); } +} // namespace io + +template<> +struct enum_traits { + static constexpr computer_action last = NUM_COMPUTER_ACTIONS; +}; + +template<> +struct enum_traits { + static constexpr computer_failure_type last = NUM_COMPUTER_FAILURES; +}; + computer_option computer_option::from_json( const JsonObject &jo ) { - std::string name = jo.get_string( "name" ); - computer_action action = computer_action_from_string( jo.get_string( "action" ) ); - int sec = jo.get_int( "security", 0 ); + const std::string name = jo.get_string( "name" ); + const computer_action action = jo.get_enum_value( "action" ); + const int sec = jo.get_int( "security", 0 ); return computer_option( name, action, sec ); } computer_failure computer_failure::from_json( const JsonObject &jo ) { - computer_failure_type type = computer_failure_type_from_string( jo.get_string( "action" ) ); + const computer_failure_type type = jo.get_enum_value( "action" ); return computer_failure( type ); } diff --git a/src/computer.h b/src/computer.h index ee9c45346a1c0..59a92f598b941 100644 --- a/src/computer.h +++ b/src/computer.h @@ -7,41 +7,45 @@ #include "calendar.h" +class JsonIn; +class JsonOut; class JsonObject; -// Don't change those! They must stay in this specific order! -// TODO: Remove this enum enum computer_action { COMPACT_NULL = 0, - COMPACT_OPEN, - COMPACT_LOCK, - COMPACT_UNLOCK, - COMPACT_TOLL, - COMPACT_SAMPLE, - COMPACT_RELEASE, - COMPACT_RELEASE_BIONICS, - COMPACT_TERMINATE, - COMPACT_PORTAL, - COMPACT_CASCADE, - COMPACT_RESEARCH, - COMPACT_MAPS, - COMPACT_MAP_SEWER, - COMPACT_MAP_SUBWAY, - COMPACT_OBSOLETE, // No longer used - COMPACT_MISS_DISARM, - COMPACT_LIST_BIONICS, - COMPACT_ELEVATOR_ON, COMPACT_AMIGARA_LOG, COMPACT_AMIGARA_START, - COMPACT_COMPLETE_DISABLE_EXTERNAL_POWER, // Completes "Disable External Power" mission - COMPACT_REPEATER_MOD, //Converts a terminal in a radio station into a 'repeater', locks terminal and completes mission - COMPACT_DOWNLOAD_SOFTWARE, COMPACT_BLOOD_ANAL, + COMPACT_CASCADE, + COMPACT_COMPLETE_DISABLE_EXTERNAL_POWER, // Completes "Disable External Power" mission + COMPACT_CONVEYOR, COMPACT_DATA_ANAL, + COMPACT_DEACTIVATE_SHOCK_VENT, COMPACT_DISCONNECT, + COMPACT_DOWNLOAD_SOFTWARE, + COMPACT_ELEVATOR_ON, COMPACT_EMERG_MESS, COMPACT_EMERG_REF_CENTER, //Points to the refugee center - COMPACT_TOWER_UNRESPONSIVE, + COMPACT_EXTRACT_RAD_SOURCE, + COMPACT_GEIGER, + COMPACT_IRRADIATOR, + COMPACT_LIST_BIONICS, + COMPACT_LOCK, + COMPACT_MAP_SEWER, + COMPACT_MAP_SUBWAY, + COMPACT_MAPS, + COMPACT_MISS_DISARM, + COMPACT_OPEN, + COMPACT_OPEN_DISARM, + COMPACT_PORTAL, + COMPACT_RADIO_ARCHIVE, + COMPACT_RELEASE, + COMPACT_RELEASE_BIONICS, + COMPACT_RELEASE_DISARM, + COMPACT_REPEATER_MOD, //Converts a terminal in a radio station into a 'repeater', locks terminal and completes mission + COMPACT_RESEARCH, + COMPACT_SAMPLE, + COMPACT_SHUTTERS, COMPACT_SR1_MESS, //Security Reminders for Hazardous Waste Sarcophagus (SRCF) COMPACT_SR2_MESS, COMPACT_SR3_MESS, @@ -49,35 +53,29 @@ enum computer_action { COMPACT_SRCF_1_MESS, COMPACT_SRCF_2_MESS, COMPACT_SRCF_3_MESS, - COMPACT_SRCF_SEAL_ORDER, - COMPACT_SRCF_SEAL, COMPACT_SRCF_ELEVATOR, - COMPACT_OPEN_DISARM, + COMPACT_SRCF_SEAL, + COMPACT_SRCF_SEAL_ORDER, + COMPACT_TERMINATE, + COMPACT_TOLL, + COMPACT_TOWER_UNRESPONSIVE, + COMPACT_UNLOCK, COMPACT_UNLOCK_DISARM, - COMPACT_RELEASE_DISARM, - COMPACT_IRRADIATOR, - COMPACT_GEIGER, - COMPACT_CONVEYOR, - COMPACT_SHUTTERS, - COMPACT_EXTRACT_RAD_SOURCE, - COMPACT_DEACTIVATE_SHOCK_VENT, - COMPACT_RADIO_ARCHIVE, NUM_COMPUTER_ACTIONS }; -// Don't change those! They must stay in this specific order! -// TODO: Remove this enum + enum computer_failure_type { COMPFAIL_NULL = 0, - COMPFAIL_SHUTDOWN, COMPFAIL_ALARM, - COMPFAIL_MANHACKS, - COMPFAIL_SECUBOTS, - COMPFAIL_DAMAGE, - COMPFAIL_PUMP_EXPLODE, - COMPFAIL_PUMP_LEAK, COMPFAIL_AMIGARA, + COMPFAIL_DAMAGE, COMPFAIL_DESTROY_BLOOD, COMPFAIL_DESTROY_DATA, + COMPFAIL_MANHACKS, + COMPFAIL_PUMP_EXPLODE, + COMPFAIL_PUMP_LEAK, + COMPFAIL_SECUBOTS, + COMPFAIL_SHUTDOWN, NUM_COMPUTER_FAILURES }; @@ -88,16 +86,23 @@ struct computer_option { computer_option(); computer_option( const std::string &N, computer_action A, int S ); - + // Save to/load from saves + void serialize( JsonOut &jout ) const; + void deserialize( JsonIn &jin ); + // Load from data files static computer_option from_json( const JsonObject &jo ); }; struct computer_failure { computer_failure_type type; + computer_failure(); computer_failure( computer_failure_type t ) : type( t ) { } - + // Save to/load from saves + void serialize( JsonOut &jout ) const; + void deserialize( JsonIn &jin ); + // Load from data files static computer_failure from_json( const JsonObject &jo ); }; @@ -105,10 +110,7 @@ class computer { public: computer( const std::string &new_name, int new_security ); - computer( const computer &rhs ); - ~computer(); - computer &operator=( const computer &rhs ); // Initialization void set_security( int Security ); void add_option( const computer_option &opt ); @@ -116,19 +118,24 @@ class computer void add_failure( const computer_failure &failure ); void add_failure( computer_failure_type failure ); void set_access_denied_msg( const std::string &new_msg ); + void set_mission( int id ); // Save/load - std::string save_data() const; - void load_data( const std::string &data ); - - std::string name; // "Jon's Computer", "Lab 6E77-B Terminal Omega" - int mission_id; // Linked to a mission? + void load_legacy_data( const std::string &data ); + void serialize( JsonOut &jout ) const; + void deserialize( JsonIn &jin ); friend class computer_session; private: + // "Jon's Computer", "Lab 6E77-B Terminal Omega" + std::string name; + // Linked to a mission? + int mission_id; // Difficulty of simply logging in int security; + // Number of times security is tripped + int alerts; // Date of next attempt - time_point next_attempt = calendar::before_time_starts; + time_point next_attempt; // Things we can do std::vector options; // Things that happen if we fail a hack @@ -137,8 +144,6 @@ class computer // Can be customized to for example warn the player of potentially lethal // consequences like secubots spawning. std::string access_denied; - // Misc research notes from json - static std::vector lab_notes; void remove_option( computer_action action ); }; diff --git a/src/computer_session.cpp b/src/computer_session.cpp index c2de07f1b2bd9..2d28063415fa5 100644 --- a/src/computer_session.cpp +++ b/src/computer_session.cpp @@ -64,8 +64,6 @@ static const species_id HUMAN( "HUMAN" ); static const efftype_id effect_amigara( "amigara" ); -static int alerts = 0; - static catacurses::window init_window() { const int width = std::min( FULL_SCREEN_WIDTH, TERMX ); @@ -81,15 +79,6 @@ computer_session::computer_session( computer &comp ) : comp( comp ), { } -void computer_session::shutdown_terminal() -{ - // So yeah, you can reset the term by logging off. - // Otherwise, it's persistent across all terms. - // Decided to go easy on people for now. - alerts = 0; - reset_terminal(); -} - void computer_session::use() { // Login @@ -104,23 +93,23 @@ void computer_session::use() print_error( "%s", comp.access_denied ); switch( query_ynq( _( "Bypass security?" ) ) ) { case ynq::quit: - shutdown_terminal(); + reset_terminal(); return; case ynq::no: query_any( _( "Shutting down… press any key." ) ); - shutdown_terminal(); + reset_terminal(); return; case ynq::yes: if( !hack_attempt( g->u ) ) { if( comp.failures.empty() ) { query_any( _( "Maximum login attempts exceeded. Press any key…" ) ); - shutdown_terminal(); + reset_terminal(); return; } activate_random_failure(); - shutdown_terminal(); + reset_terminal(); return; } else { // Successful hack attempt comp.security = 0; @@ -156,12 +145,12 @@ void computer_session::use() computer_option current = comp.options[sel]; reset_terminal(); // Once you trip the security, you have to roll every time you want to do something - if( current.security + alerts > 0 ) { + if( current.security + comp.alerts > 0 ) { print_error( _( "Password required." ) ); if( query_bool( _( "Hack into system?" ) ) ) { if( !hack_attempt( g->u, current.security ) ) { activate_random_failure(); - shutdown_terminal(); + reset_terminal(); return; } else { // Successfully hacked function @@ -176,7 +165,7 @@ void computer_session::use() // Done processing a selected option. } - shutdown_terminal(); // This should have been done by now, but just in case. + reset_terminal(); // This should have been done by now, but just in case. } bool computer_session::hack_attempt( player &p, int Security ) @@ -189,8 +178,8 @@ bool computer_session::hack_attempt( player &p, int Security ) // Every time you dig for lab notes, (or, in future, do other suspicious stuff?) // +2 dice to the system's hack-resistance // So practical max files from a given terminal = 5, at 10 Computer - if( alerts > 0 ) { - Security += ( alerts * 2 ); + if( comp.alerts > 0 ) { + Security += ( comp.alerts * 2 ); } p.moves -= 10 * ( 5 + Security * 2 ) / std::max( 1, hack_skill + 1 ); @@ -455,7 +444,7 @@ void computer_session::action_research() { // TODO: seed should probably be a member of the computer, or better: of the computer action. // It is here to ensure one computer reporting the same text on each invocation. - const int seed = g->get_levx() + g->get_levy() + g->get_levz() + alerts; + const int seed = g->get_levx() + g->get_levy() + g->get_levz() + comp.alerts; cata::optional log = SNIPPET.random_from_category( "lab_notes", seed ); if( !log.has_value() ) { log = to_translation( "No data found." ); @@ -465,14 +454,14 @@ void computer_session::action_research() print_text( "%s", log.value() ); // One's an anomaly - if( alerts == 0 ) { + if( comp.alerts == 0 ) { query_any( _( "Local data-access error logged, alerting helpdesk. Press any key…" ) ); - alerts ++; + comp.alerts ++; } else { // Two's a trend. query_any( _( "Warning: anomalous archive-access activity detected at this node. Press any key…" ) ); - alerts ++; + comp.alerts ++; } } @@ -485,8 +474,8 @@ void computer_session::action_radio_archive() print_text( "Accessing archive. Playing audio recording nr %d.\n%s", rng( 1, 9999 ), SNIPPET.random_from_category( "radio_archive" ).value_or( translation() ) ); if( one_in( 3 ) ) { - query_any( _( "Warning: resticted data access. Attempt logged. Press any key…" ) ); - alerts ++; + query_any( _( "Warning: restricted data access. Attempt logged. Press any key…" ) ); + comp.alerts ++; } else { query_any( _( "Press any key…" ) ); } @@ -501,7 +490,7 @@ void computer_session::action_maps() query_any( _( "Surface map data downloaded. Local anomalous-access error logged. Press any key…" ) ); comp.remove_option( COMPACT_MAPS ); - alerts ++; + comp.alerts ++; } void computer_session::action_map_sewer() @@ -1352,7 +1341,7 @@ void computer_session::failure_destroy_blood() void computer_session::failure_destroy_data() { print_error( _( "ERROR: ACCESSING DATA MALFUNCTION" ) ); - for( const tripoint &p : g->m.points_in_radius( g->u.pos(), 24 ) ) { + for( const tripoint &p : g->m.points_in_radius( g->u.pos(), 2 ) ) { if( g->m.ter( p ) == t_floor_blue ) { map_stack items = g->m.i_at( p ); if( items.empty() ) { diff --git a/src/computer_session.h b/src/computer_session.h index 43d98fa396f8e..98fe9c0924866 100644 --- a/src/computer_session.h +++ b/src/computer_session.h @@ -28,8 +28,6 @@ class computer_session const int height; std::vector> lines; - /** Shutdown (free w_terminal, etc.) */ - void shutdown_terminal(); /** Returns true if the player successfully hacks the computer. Security = -1 defaults to * the main system security. */ bool hack_attempt( player &p, int Security = -1 ); diff --git a/src/mapgen.cpp b/src/mapgen.cpp index ec6ae6f724e26..dab03c863a83a 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -1469,7 +1469,7 @@ class jmapgen_computer : public jmapgen_piece cpu->add_failure( opt ); } if( target && dat.mission() ) { - cpu->mission_id = dat.mission()->get_id(); + cpu->set_mission( dat.mission()->get_id() ); } // The default access denied message is defined in computer's constructor diff --git a/src/mission_start.cpp b/src/mission_start.cpp index 672155a5b0d81..ada5d80d19088 100644 --- a/src/mission_start.cpp +++ b/src/mission_start.cpp @@ -225,7 +225,7 @@ void mission_start::place_npc_software( mission *miss ) compmap.ter_set( comppoint, t_console ); computer *tmpcomp = compmap.add_computer( comppoint, string_format( _( "%s's Terminal" ), dev->name ), 0 ); - tmpcomp->mission_id = miss->uid; + tmpcomp->set_mission( miss->get_id() ); tmpcomp->add_option( _( "Download Software" ), COMPACT_DOWNLOAD_SOFTWARE, 0 ); compmap.save(); } @@ -631,7 +631,7 @@ void static create_lab_consoles( mission *miss, const tripoint &place, const std tripoint comppoint = find_potential_computer_point( compmap ); computer *tmpcomp = compmap.add_computer( comppoint, _( comp_name ), security ); - tmpcomp->mission_id = miss->get_id(); + tmpcomp->set_mission( miss->get_id() ); tmpcomp->add_option( _( download_name ), COMPACT_DOWNLOAD_SOFTWARE, security ); tmpcomp->add_failure( COMPFAIL_ALARM ); tmpcomp->add_failure( COMPFAIL_DAMAGE ); @@ -712,7 +712,7 @@ void mission_start::reveal_lab_train_depot( mission *miss ) } computer *tmpcomp = compmap.computer_at( *comppoint ); - tmpcomp->mission_id = miss->uid; + tmpcomp->set_mission( miss->get_id() ); tmpcomp->add_option( _( "Download Routing Software" ), COMPACT_DOWNLOAD_SOFTWARE, 0 ); compmap.save(); diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index eb729e47e95d8..43572a2f0a278 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -3757,13 +3757,13 @@ void submap::store( JsonOut &jsout ) const if( legacy_computer ) { // it's possible that no access to computers has been made and legacy_computer // is not cleared - jsout.member( "computers", legacy_computer->save_data() ); + jsout.member( "computers", *legacy_computer ); } else if( !computers.empty() ) { jsout.member( "computers" ); jsout.start_array(); for( auto &elem : computers ) { jsout.write( elem.first ); - jsout.write( elem.second.save_data() ); + jsout.write( elem.second ); } jsout.end_array(); } @@ -4031,16 +4031,14 @@ void submap::load( JsonIn &jsin, const std::string &member_name, int version ) while( !jsin.end_array() ) { point loc; jsin.read( loc ); - std::string computer_data = jsin.get_string(); auto new_comp_it = computers.emplace( loc, computer( "BUGGED_COMPUTER", -100 ) ).first; - new_comp_it->second.load_data( computer_data ); + jsin.read( new_comp_it->second ); } } else { // only load legacy data here, but do not update to std::map, since // the terrain may not have been loaded yet. - std::string computer_data = jsin.get_string(); legacy_computer = std::make_unique( "BUGGED_COMPUTER", -100 ); - legacy_computer->load_data( computer_data ); + jsin.read( *legacy_computer ); } } else if( member_name == "camp" ) { camp = std::make_unique();