1 #include "computer.h"
2
3 #include <clocale>
4 #include <cstdlib>
5 #include <sstream>
6
7 #include "debug.h"
8 #include "enum_conversions.h"
9 #include "json.h"
10 #include "output.h"
11 #include "translations.h"
12
13 template <typename E> struct enum_traits;
14
computer_option()15 computer_option::computer_option()
16 : name( "Unknown" ), action( COMPACT_NULL ), security( 0 )
17 {
18 }
19
computer_option(const std::string & N,computer_action A,int S)20 computer_option::computer_option( const std::string &N, computer_action A, int S )
21 : name( N ), action( A ), security( S )
22 {
23 }
24
serialize(JsonOut & jout) const25 void computer_option::serialize( JsonOut &jout ) const
26 {
27 jout.start_object();
28 jout.member( "name", name );
29 jout.member( "action" );
30 jout.write_as_string( action );
31 jout.member( "security", security );
32 jout.end_object();
33 }
34
deserialize(JsonIn & jin)35 void computer_option::deserialize( JsonIn &jin )
36 {
37 const JsonObject jo = jin.get_object();
38 name = jo.get_string( "name" );
39 action = jo.get_enum_value<computer_action>( "action" );
40 security = jo.get_int( "security" );
41 }
42
computer_failure()43 computer_failure::computer_failure()
44 : type( COMPFAIL_NULL )
45 {
46 }
47
serialize(JsonOut & jout) const48 void computer_failure::serialize( JsonOut &jout ) const
49 {
50 jout.start_object();
51 jout.member( "action" );
52 jout.write_as_string( type );
53 jout.end_object();
54 }
55
deserialize(JsonIn & jin)56 void computer_failure::deserialize( JsonIn &jin )
57 {
58 const JsonObject jo = jin.get_object();
59 type = jo.get_enum_value<computer_failure_type>( "action" );
60 }
61
computer(const std::string & new_name,int new_security)62 computer::computer( const std::string &new_name, int new_security )
63 : name( new_name ), mission_id( -1 ), security( new_security ), alerts( 0 ),
64 next_attempt( calendar::before_time_starts ),
65 access_denied( _( "ERROR! Access denied!" ) )
66 {
67 }
68
set_security(int Security)69 void computer::set_security( int Security )
70 {
71 security = Security;
72 }
73
add_option(const computer_option & opt)74 void computer::add_option( const computer_option &opt )
75 {
76 options.emplace_back( opt );
77 }
78
add_option(const std::string & opt_name,computer_action action,int security)79 void computer::add_option( const std::string &opt_name, computer_action action,
80 int security )
81 {
82 add_option( computer_option( opt_name, action, security ) );
83 }
84
add_failure(const computer_failure & failure)85 void computer::add_failure( const computer_failure &failure )
86 {
87 failures.emplace_back( failure );
88 }
89
add_failure(computer_failure_type failure)90 void computer::add_failure( computer_failure_type failure )
91 {
92 add_failure( computer_failure( failure ) );
93 }
94
set_access_denied_msg(const std::string & new_msg)95 void computer::set_access_denied_msg( const std::string &new_msg )
96 {
97 access_denied = new_msg;
98 }
99
set_mission(const int id)100 void computer::set_mission( const int id )
101 {
102 mission_id = id;
103 }
104
105 static computer_action computer_action_from_legacy_enum( int val );
106 static computer_failure_type computer_failure_type_from_legacy_enum( int val );
107
load_legacy_data(const std::string & data)108 void computer::load_legacy_data( const std::string &data )
109 {
110 options.clear();
111 failures.clear();
112
113 std::istringstream dump( data );
114 dump.imbue( std::locale::classic() );
115
116 dump >> name >> security >> mission_id;
117
118 name = string_replace( name, "_", " " );
119
120 // Pull in options
121 int optsize;
122 dump >> optsize;
123 for( int n = 0; n < optsize; n++ ) {
124 std::string tmpname;
125
126 int tmpaction;
127 int tmpsec;
128
129 dump >> tmpname >> tmpaction >> tmpsec;
130 // Legacy missle launch option that got removed before `computer_action` was
131 // refactored to be saved and loaded as string ids. Do not change this number:
132 // `computer_action` now has different underlying values from back then!
133 if( tmpaction == 15 ) {
134 continue;
135 }
136 add_option( string_replace( tmpname, "_", " " ), computer_action_from_legacy_enum( tmpaction ),
137 tmpsec );
138 }
139
140 // Pull in failures
141 int failsize;
142 dump >> failsize;
143 for( int n = 0; n < failsize; n++ ) {
144 int tmpfail;
145 dump >> tmpfail;
146 add_failure( computer_failure_type_from_legacy_enum( tmpfail ) );
147 }
148
149 std::string tmp_access_denied;
150 dump >> tmp_access_denied;
151
152 // For backwards compatibility, only set the access denied message if it
153 // isn't empty. This is to avoid the message becoming blank when people
154 // load old saves.
155 if( !tmp_access_denied.empty() ) {
156 access_denied = string_replace( tmp_access_denied, "_", " " );
157 }
158 }
159
serialize(JsonOut & jout) const160 void computer::serialize( JsonOut &jout ) const
161 {
162 jout.start_object();
163 jout.member( "name", name );
164 jout.member( "mission", mission_id );
165 jout.member( "security", security );
166 jout.member( "alerts", alerts );
167 jout.member( "next_attempt", next_attempt );
168 jout.member( "options", options );
169 jout.member( "failures", failures );
170 jout.member( "access_denied", access_denied );
171 jout.end_object();
172 }
173
deserialize(JsonIn & jin)174 void computer::deserialize( JsonIn &jin )
175 {
176 if( jin.test_string() ) {
177 load_legacy_data( jin.get_string() );
178 } else {
179 const JsonObject jo = jin.get_object();
180 jo.read( "name", name );
181 jo.read( "mission", mission_id );
182 jo.read( "security", security );
183 jo.read( "alerts", alerts );
184 jo.read( "next_attempt", next_attempt );
185 jo.read( "options", options );
186 jo.read( "failures", failures );
187 jo.read( "access_denied", access_denied );
188 }
189 }
190
remove_option(computer_action const action)191 void computer::remove_option( computer_action const action )
192 {
193 for( auto it = options.begin(); it != options.end(); ++it ) {
194 if( it->action == action ) {
195 options.erase( it );
196 break;
197 }
198 }
199 }
200
computer_action_from_legacy_enum(const int val)201 static computer_action computer_action_from_legacy_enum( const int val )
202 {
203 switch( val ) {
204 // Used to migrate old saves. Do not change the numbers!
205 // *INDENT-OFF*
206 default: return COMPACT_NULL;
207 case 0: return COMPACT_NULL;
208 case 1: return COMPACT_OPEN;
209 case 2: return COMPACT_LOCK;
210 case 3: return COMPACT_UNLOCK;
211 case 4: return COMPACT_TOLL;
212 case 5: return COMPACT_SAMPLE;
213 case 6: return COMPACT_RELEASE;
214 case 7: return COMPACT_RELEASE_BIONICS;
215 case 8: return COMPACT_TERMINATE;
216 case 9: return COMPACT_PORTAL;
217 case 10: return COMPACT_CASCADE;
218 case 11: return COMPACT_RESEARCH;
219 case 12: return COMPACT_MAPS;
220 case 13: return COMPACT_MAP_SEWER;
221 case 14: return COMPACT_MAP_SUBWAY;
222 // options with action enum 15 are removed in load_legacy_data()
223 case 16: return COMPACT_MISS_DISARM;
224 case 17: return COMPACT_LIST_BIONICS;
225 case 18: return COMPACT_ELEVATOR_ON;
226 case 19: return COMPACT_AMIGARA_LOG;
227 case 20: return COMPACT_AMIGARA_START;
228 case 21: return COMPACT_COMPLETE_DISABLE_EXTERNAL_POWER;
229 case 22: return COMPACT_REPEATER_MOD;
230 case 23: return COMPACT_DOWNLOAD_SOFTWARE;
231 case 24: return COMPACT_BLOOD_ANAL;
232 case 25: return COMPACT_DATA_ANAL;
233 case 26: return COMPACT_DISCONNECT;
234 case 27: return COMPACT_EMERG_MESS;
235 case 28: return COMPACT_EMERG_REF_CENTER;
236 case 29: return COMPACT_TOWER_UNRESPONSIVE;
237 case 30: return COMPACT_SR1_MESS;
238 case 31: return COMPACT_SR2_MESS;
239 case 32: return COMPACT_SR3_MESS;
240 case 33: return COMPACT_SR4_MESS;
241 case 34: return COMPACT_SRCF_1_MESS;
242 case 35: return COMPACT_SRCF_2_MESS;
243 case 36: return COMPACT_SRCF_3_MESS;
244 case 37: return COMPACT_SRCF_SEAL_ORDER;
245 case 38: return COMPACT_SRCF_SEAL;
246 case 39: return COMPACT_SRCF_ELEVATOR;
247 case 40: return COMPACT_OPEN_DISARM;
248 case 41: return COMPACT_UNLOCK_DISARM;
249 case 42: return COMPACT_RELEASE_DISARM;
250 case 43: return COMPACT_IRRADIATOR;
251 case 44: return COMPACT_GEIGER;
252 case 45: return COMPACT_CONVEYOR;
253 case 46: return COMPACT_SHUTTERS;
254 case 47: return COMPACT_EXTRACT_RAD_SOURCE;
255 case 48: return COMPACT_DEACTIVATE_SHOCK_VENT;
256 case 49: return COMPACT_RADIO_ARCHIVE;
257 // *INDENT-ON*
258 }
259 }
260
computer_failure_type_from_legacy_enum(const int val)261 static computer_failure_type computer_failure_type_from_legacy_enum( const int val )
262 {
263 switch( val ) {
264 // Used to migrate old saves. Do not change the numbers!
265 // *INDENT-OFF*
266 default: return COMPFAIL_NULL;
267 case 0: return COMPFAIL_NULL;
268 case 1: return COMPFAIL_SHUTDOWN;
269 case 2: return COMPFAIL_ALARM;
270 case 3: return COMPFAIL_MANHACKS;
271 case 4: return COMPFAIL_SECUBOTS;
272 case 5: return COMPFAIL_DAMAGE;
273 case 6: return COMPFAIL_PUMP_EXPLODE;
274 case 7: return COMPFAIL_PUMP_LEAK;
275 case 8: return COMPFAIL_AMIGARA;
276 case 9: return COMPFAIL_DESTROY_BLOOD;
277 case 10: return COMPFAIL_DESTROY_DATA;
278 // *INDENT-ON*
279 }
280 }
281
282 namespace io
283 {
284 template<>
enum_to_string(const computer_action act)285 std::string enum_to_string<computer_action>( const computer_action act )
286 {
287 switch( act ) {
288 // *INDENT-OFF*
289 case COMPACT_NULL: return "null";
290 case COMPACT_AMIGARA_LOG: return "amigara_log";
291 case COMPACT_AMIGARA_START: return "amigara_start";
292 case COMPACT_BLOOD_ANAL: return "blood_anal";
293 case COMPACT_CASCADE: return "cascade";
294 case COMPACT_COMPLETE_DISABLE_EXTERNAL_POWER: return "complete_disable_external_power";
295 case COMPACT_CONVEYOR: return "conveyor";
296 case COMPACT_DATA_ANAL: return "data_anal";
297 case COMPACT_DEACTIVATE_SHOCK_VENT: return "deactivate_shock_vent";
298 case COMPACT_DISCONNECT: return "disconnect";
299 case COMPACT_DOWNLOAD_SOFTWARE: return "download_software";
300 case COMPACT_ELEVATOR_ON: return "elevator_on";
301 case COMPACT_EMERG_MESS: return "emerg_mess";
302 case COMPACT_EMERG_REF_CENTER: return "emerg_ref_center";
303 case COMPACT_EXTRACT_RAD_SOURCE: return "extract_rad_source";
304 case COMPACT_GEIGER: return "geiger";
305 case COMPACT_IRRADIATOR: return "irradiator";
306 case COMPACT_LIST_BIONICS: return "list_bionics";
307 case COMPACT_LOCK: return "lock";
308 case COMPACT_MAP_SEWER: return "map_sewer";
309 case COMPACT_MAP_SUBWAY: return "map_subway";
310 case COMPACT_MAPS: return "maps";
311 case COMPACT_MISS_DISARM: return "miss_disarm";
312 case COMPACT_OPEN: return "open";
313 case COMPACT_OPEN_DISARM: return "open_disarm";
314 case COMPACT_PORTAL: return "portal";
315 case COMPACT_RADIO_ARCHIVE: return "radio_archive";
316 case COMPACT_RELEASE: return "release";
317 case COMPACT_RELEASE_BIONICS: return "release_bionics";
318 case COMPACT_RELEASE_DISARM: return "release_disarm";
319 case COMPACT_REPEATER_MOD: return "repeater_mod";
320 case COMPACT_RESEARCH: return "research";
321 case COMPACT_SAMPLE: return "sample";
322 case COMPACT_SHUTTERS: return "shutters";
323 case COMPACT_SR1_MESS: return "sr1_mess";
324 case COMPACT_SR2_MESS: return "sr2_mess";
325 case COMPACT_SR3_MESS: return "sr3_mess";
326 case COMPACT_SR4_MESS: return "sr4_mess";
327 case COMPACT_SRCF_1_MESS: return "srcf_1_mess";
328 case COMPACT_SRCF_2_MESS: return "srcf_2_mess";
329 case COMPACT_SRCF_3_MESS: return "srcf_3_mess";
330 case COMPACT_SRCF_ELEVATOR: return "srcf_elevator";
331 case COMPACT_SRCF_SEAL: return "srcf_seal";
332 case COMPACT_SRCF_SEAL_ORDER: return "srcf_seal_order";
333 case COMPACT_TERMINATE: return "terminate";
334 case COMPACT_TOLL: return "toll";
335 case COMPACT_TOWER_UNRESPONSIVE: return "tower_unresponsive";
336 case COMPACT_UNLOCK: return "unlock";
337 case COMPACT_UNLOCK_DISARM: return "unlock_disarm";
338 // *INDENT-OFF*
339 case NUM_COMPUTER_ACTIONS:
340 break;
341 }
342 debugmsg( "Invalid computer_action" );
343 abort();
344 }
345
346 template<>
enum_to_string(const computer_failure_type fail)347 std::string enum_to_string<computer_failure_type>( const computer_failure_type fail )
348 {
349 switch( fail ){
350 // *INDENT-OFF*
351 case COMPFAIL_NULL: return "null";
352 case COMPFAIL_ALARM: return "alarm";
353 case COMPFAIL_AMIGARA: return "amigara";
354 case COMPFAIL_DAMAGE: return "damage";
355 case COMPFAIL_DESTROY_BLOOD: return "destroy_blood";
356 case COMPFAIL_DESTROY_DATA: return "destroy_data";
357 case COMPFAIL_MANHACKS: return "manhacks";
358 case COMPFAIL_PUMP_EXPLODE: return "pump_explode";
359 case COMPFAIL_PUMP_LEAK: return "pump_leak";
360 case COMPFAIL_SECUBOTS: return "secubots";
361 case COMPFAIL_SHUTDOWN: return "shutdown";
362 // *INDENT-ON*
363 case NUM_COMPUTER_FAILURES:
364 break;
365 }
366 debugmsg( "Invalid computer_failure_type" );
367 abort();
368 }
369 } // namespace io
370
371 template<>
372 struct enum_traits<computer_action> {
373 static constexpr computer_action last = NUM_COMPUTER_ACTIONS;
374 };
375
376 template<>
377 struct enum_traits<computer_failure_type> {
378 static constexpr computer_failure_type last = NUM_COMPUTER_FAILURES;
379 };
380
from_json(const JsonObject & jo)381 computer_option computer_option::from_json( const JsonObject &jo )
382 {
383 translation name;
384 jo.read( "name", name );
385 const computer_action action = jo.get_enum_value<computer_action>( "action" );
386 const int sec = jo.get_int( "security", 0 );
387 return computer_option( name.translated(), action, sec );
388 }
389
from_json(const JsonObject & jo)390 computer_failure computer_failure::from_json( const JsonObject &jo )
391 {
392 const computer_failure_type type = jo.get_enum_value<computer_failure_type>( "action" );
393 return computer_failure( type );
394 }
395