Cataclysm-DDA/src/computer.cpp

441 lines
14 KiB
C++

#include "computer.h"
#include <clocale>
#include <cstdlib>
#include <sstream>
#include "computer.h"
#include "debug.h"
#include "enum_conversions.h"
#include "json.h"
#include "output.h"
#include "talker_furniture.h"
#include "translations.h"
template <typename E> struct enum_traits;
computer_option::computer_option()
: name( "Unknown" ), action( COMPACT_NULL ), security( 0 )
{
}
computer_option::computer_option( const std::string &N, computer_action A, int S )
: name( N ), action( A ), security( S )
{
}
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();
}
void computer_option::deserialize( const JsonObject &jo )
{
name = jo.get_string( "name" );
action = jo.get_enum_value<computer_action>( "action" );
security = jo.get_int( "security" );
}
computer_failure::computer_failure()
: type( COMPFAIL_NULL )
{
}
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( const JsonObject &jo )
{
type = jo.get_enum_value<computer_failure_type>( "action" );
}
computer::computer( const std::string &new_name, int new_security, tripoint new_loc )
: name( new_name ), mission_id( -1 ), security( new_security ), alerts( 0 ),
next_attempt( calendar::before_time_starts ),
access_denied( _( "ERROR! Access denied!" ) )
{
loc = new_loc;
}
void computer::set_security( int Security )
{
security = Security;
}
void computer::add_option( const computer_option &opt )
{
options.emplace_back( opt );
}
void computer::add_eoc( const effect_on_condition_id &eoc )
{
eocs.emplace_back( eoc );
}
void computer::add_chat_topic( const std::string &topic )
{
chat_topics.emplace_back( topic );
}
void computer::add_option( const std::string &opt_name, computer_action action,
int security )
{
add_option( computer_option( opt_name, action, security ) );
}
void computer::add_failure( const computer_failure &failure )
{
failures.emplace_back( failure );
}
void computer::add_failure( computer_failure_type failure )
{
add_failure( computer_failure( failure ) );
}
void computer::set_access_denied_msg( const std::string &new_msg )
{
access_denied = new_msg;
}
void computer::set_mission( const int id )
{
mission_id = id;
}
// Methods for setting/getting misc key/value pairs.
void computer::set_value( const std::string &key, const std::string &value )
{
values[ key ] = value;
}
void computer::remove_value( const std::string &key )
{
values.erase( key );
}
std::string computer::get_value( const std::string &key ) const
{
auto it = values.find( key );
return ( it == values.end() ) ? "" : it->second;
}
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 )
{
options.clear();
failures.clear();
std::istringstream dump( data );
dump.imbue( std::locale::classic() );
dump >> name >> security >> mission_id;
name = string_replace( name, "_", " " );
// Pull in options
int optsize;
dump >> optsize;
for( int n = 0; n < optsize; n++ ) {
std::string tmpname;
int tmpaction;
int tmpsec;
dump >> tmpname >> tmpaction >> tmpsec;
// Legacy missile 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, "_", " " ), computer_action_from_legacy_enum( tmpaction ),
tmpsec );
}
// Pull in failures
int failsize;
dump >> failsize;
for( int n = 0; n < failsize; n++ ) {
int tmpfail;
dump >> tmpfail;
add_failure( computer_failure_type_from_legacy_enum( tmpfail ) );
}
std::string tmp_access_denied;
dump >> tmp_access_denied;
// For backwards compatibility, only set the access denied message if it
// isn't empty. This is to avoid the message becoming blank when people
// load old saves.
if( !tmp_access_denied.empty() ) {
access_denied = string_replace( tmp_access_denied, "_", " " );
}
}
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.member( "eocs", eocs );
jout.member( "chat_topics", chat_topics );
jout.member( "values", values );
jout.member( "loc", loc );
jout.end_object();
}
void computer::deserialize( const JsonValue &jv )
{
if( jv.test_string() ) {
load_legacy_data( jv.get_string() );
} else {
const JsonObject jo = jv.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 );
jo.read( "eocs", eocs );
jo.read( "chat_topics", chat_topics );
jo.read( "values", values );
jo.read( "loc", loc );
}
}
void computer::remove_option( computer_action const action )
{
for( auto it = options.begin(); it != options.end(); ++it ) {
if( it->action == action ) {
options.erase( it );
break;
}
}
}
static computer_action computer_action_from_legacy_enum( const int val )
{
switch( val ) {
// Used to migrate old saves. Do not change the numbers!
// *INDENT-OFF*
default:
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*
}
}
static computer_failure_type computer_failure_type_from_legacy_enum( const int val )
{
switch( val ) {
// Used to migrate old saves. Do not change the numbers!
// *INDENT-OFF*
default:
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*
}
}
namespace io
{
template<>
std::string enum_to_string<computer_action>( 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_MISS_LAUNCH: return "miss_launch";
case COMPACT_OPEN: return "open";
case COMPACT_OPEN_GATE: return "open_gate";
case COMPACT_CLOSE_GATE: return "close_gate";
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;
}
cata_fatal( "Invalid computer_action" );
}
template<>
std::string enum_to_string<computer_failure_type>( 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;
}
cata_fatal( "Invalid computer_failure_type" );
}
} // namespace io
template<>
struct enum_traits<computer_action> {
static constexpr computer_action last = NUM_COMPUTER_ACTIONS;
};
template<>
struct enum_traits<computer_failure_type> {
static constexpr computer_failure_type last = NUM_COMPUTER_FAILURES;
};
computer_option computer_option::from_json( const JsonObject &jo )
{
translation name;
jo.read( "name", name );
const computer_action action = jo.get_enum_value<computer_action>( "action" );
const int sec = jo.get_int( "security", 0 );
return computer_option( name.translated(), action, sec );
}
computer_failure computer_failure::from_json( const JsonObject &jo )
{
const computer_failure_type type = jo.get_enum_value<computer_failure_type>( "action" );
return computer_failure( type );
}
std::unique_ptr<talker> get_talker_for( computer &me )
{
return std::make_unique<talker_furniture>( &me );
}
std::unique_ptr<talker> get_talker_for( computer *me )
{
return std::make_unique<talker_furniture>( me );
}