1 
2 /* WARNING:
3  *    This is magic-number central, but these numbers are set specifically
4  *    to the acceptable defaults or range values that were used when the
5  *    pl2/plr files were created.  Standard game defines should not be used in
6  *    place of these major numbers for /any/ reason, *ever*!
7  */
8 
9 #include "cfile/cfilesystem.h"
10 #include "mission/missionbriefcommon.h"
11 #include "network/psnet2.h"
12 #include "pilotfile/pilotfile_convert.h"
13 
14 
15 // this struct isn't well packed, and is written whole to the pilot file, so
16 // we can't easily just get the RGBA that we need and instead must retain this
17 typedef struct conv_color { //-V802
18 	uint		screen_sig;
19 	ubyte		red;
20 	ubyte		green;
21 	ubyte		blue;
22 	ubyte		alpha;
23 	ubyte		ac_type;
24 	int		is_alphacolor;
25 	ubyte		raw8;
26 	int		alphacolor;
27 	int		magic;
28 } conv_color;
29 
30 
plr_data()31 plr_data::plr_data()
32 {
33 	// not carried over, just for reference during conversion process
34 	version = 0;
35 	is_multi = 0;
36 	lcl_get_language_name(language);
37 
38 	// basic flags and settings
39 	tips = 0;
40 	rank = 0;
41 	skill_level = 1;
42 	save_flags = 0;
43 	readyroom_listing_mode = 0;
44 	voice_enabled = 1;
45 	auto_advance = 1;
46 	Use_mouse_to_fly = 0;
47 	Mouse_sensitivity = 4;
48 	Joy_sensitivity = 9;
49 	Dead_zone_size = 10;
50 
51 	// multiplayer settings/options
52 	net_protocol = 1;
53 
54 	multi_squad_set = 2;
55 	multi_endgame_set = 3;
56 	multi_flags = 3;
57 	multi_respawn = 2;
58 	multi_max_observers = 2;
59 	multi_skill_level = 2;
60 	multi_voice_qos = 10;
61 	multi_voice_token_wait = 2000;
62 	multi_voice_record_time = 5000;
63 	multi_time_limit = -65536;
64 	multi_kill_limit = 9999;
65 
66 	multi_local_flags = 5;
67 	multi_local_update_level = 0;
68 
69 	// pilot info stuff
70 	memset(image_filename, 0, sizeof(image_filename));
71 	memset(squad_name, 0, sizeof(squad_name));
72 	memset(squad_filename, 0, sizeof(squad_filename));
73 	memset(current_campaign, 0, sizeof(current_campaign));
74 	memset(last_ship_flown, 0, sizeof(last_ship_flown));
75 
76 	// HUD config
77 	hud_show_flags = -1;
78 	hud_show_flags2 = 31;
79 	hud_popup_flags = 0;
80 	hud_popup_flags2 = 0;
81 	hud_num_lines = 4;
82 	hud_rp_flags = 7;
83 	hud_rp_dist = 2;
84 
85 	for (int idx = 0; idx < 39; idx++) {
86 		hud_colors[idx][0] = 0;
87 		hud_colors[idx][1] = 255;
88 		hud_colors[idx][2] = 0;
89 		hud_colors[idx][3] = 144;
90 	}
91 
92 	// control setup
93 	joy_axis_map_to[0] = 0;
94 	joy_axis_map_to[1] = 1;
95 	joy_axis_map_to[2] = 3;
96 	joy_invert_axis[3] = -1;
97 	joy_invert_axis[4] = -1;
98 
99 	memset(joy_invert_axis, 0, sizeof(joy_invert_axis));
100 
101 	// audio
102 	sound_volume = 1.0f;
103 	music_volume = 0.5f;
104 	voice_volume = 0.7f;
105 
106 	// detail settings
107 	detail_setting = 3;
108 	detail_nebula = 3;
109 	detail_distance = 3;
110 	detail_hardware_textures = 4;
111 	detail_num_debris = 4;
112 	detail_num_particles = 3;
113 	detail_num_stars = 4;
114 	detail_shield_effects = 4;
115 	detail_lighting = 4;
116 	detail_targetview_model = 1;
117 	detail_planets_suns = 1;
118 	detail_weapon_extras = 1;
119 }
120 
~plr_data()121 plr_data::~plr_data()
122 {
123 	controls.clear();
124 }
125 
plr_import_controls()126 void pilotfile_convert::plr_import_controls()
127 {
128 	int idx;
129 	CCI con;
130 	short buf;
131 
132 	unsigned char num_controls = cfread_ubyte(cfp);
133 
134 	if ( !num_controls ) {
135 		return;
136 	}
137 
138 	// it may be less than 118, but it shouldn't be more than 118
139 	// Don't touch this magic number! This is for old playerfiles. See banner at top of this file.
140 	if (num_controls > 118) {
141 		throw "Data check failure in controls!";
142 	}
143 
144 	plr->controls.reserve(num_controls);
145 
146 	for (idx = 0; idx < num_controls; idx++) {
147 		buf = cfread_short(cfp);
148 		if (buf == 255) {
149 			buf = -1;
150 		}
151 		con.take(CC_bind(CID_KEYBOARD, buf), 0);
152 
153 		buf = cfread_short(cfp);
154 		if (buf == 255) {
155 			buf = -1;
156 		}
157 		con.take(CC_bind(CID_JOY0, buf), 1);
158 
159 		plr->controls.push_back( con );
160 	}
161 }
162 
plr_import_hud()163 void pilotfile_convert::plr_import_hud()
164 {
165 	int idx;
166 	conv_color c;
167 
168 	plr->hud_show_flags = cfread_int(cfp);
169 	plr->hud_show_flags2 = cfread_int(cfp);
170 
171 	plr->hud_popup_flags = cfread_int(cfp);
172 	plr->hud_popup_flags2 = cfread_int(cfp);
173 
174 	plr->hud_num_lines = cfread_ubyte(cfp);
175 	plr->hud_rp_flags = cfread_int(cfp);
176 	plr->hud_rp_dist = cfread_int(cfp);
177 
178 	for (idx = 0; idx < 39; idx++) {
179 		cfread(&c, sizeof(conv_color), 1, cfp);
180 
181 		if ( (c.alphacolor != -1) || (c.is_alphacolor != 1) ) {
182 			throw "Data check failure in hud!";
183 		}
184 
185 		plr->hud_colors[idx][0] = c.red;
186 		plr->hud_colors[idx][1] = c.green;
187 		plr->hud_colors[idx][2] = c.blue;
188 		plr->hud_colors[idx][3] = c.alpha;
189 	}
190 }
191 
plr_import_detail()192 void pilotfile_convert::plr_import_detail()
193 {
194 	bool data_failure = false;
195 
196 	plr->detail_setting = cfread_int(cfp);
197 	plr->detail_nebula = cfread_int(cfp);
198 	plr->detail_distance = cfread_int(cfp);
199 	plr->detail_hardware_textures = cfread_int(cfp);
200 	plr->detail_num_debris = cfread_int(cfp);
201 	plr->detail_num_particles = cfread_int(cfp);
202 	plr->detail_num_stars = cfread_int(cfp);
203 	plr->detail_shield_effects = cfread_int(cfp);
204 	plr->detail_lighting = cfread_int(cfp);
205 	plr->detail_targetview_model = cfread_int(cfp);
206 	plr->detail_planets_suns = cfread_int(cfp);
207 	plr->detail_weapon_extras = cfread_int(cfp);
208 
209 	if ( (plr->detail_setting < -1) || (plr->detail_setting > 4) ) {
210 		data_failure = true;
211 	} else 	if ( (plr->detail_nebula < 0) || (plr->detail_nebula > 4) ) {
212 		data_failure = true;
213 	} else 	if ( (plr->detail_distance < 0) || (plr->detail_distance > 4) ) {
214 		data_failure = true;
215 	} else 	if ( (plr->detail_hardware_textures < 0) || (plr->detail_hardware_textures > 4) ) {
216 		data_failure = true;
217 	} else 	if ( (plr->detail_num_debris < 0) || (plr->detail_num_debris > 4) ) {
218 		data_failure = true;
219 	} else 	if ( (plr->detail_num_particles < 0) || (plr->detail_num_particles > 4) ) {
220 		data_failure = true;
221 	} else 	if ( (plr->detail_num_stars < 0) || (plr->detail_num_stars > 4) ) {
222 		data_failure = true;
223 	} else 	if ( (plr->detail_shield_effects < 0) || (plr->detail_shield_effects > 4) ) {
224 		data_failure = true;
225 	} else 	if ( (plr->detail_lighting < 0) || (plr->detail_lighting > 4) ) {
226 		data_failure = true;
227 	} else 	if ( (plr->detail_targetview_model < 0) || (plr->detail_targetview_model > 1) ) {
228 		data_failure = true;
229 	} else 	if ( (plr->detail_planets_suns < 0) || (plr->detail_planets_suns > 1) ) {
230 		data_failure = true;
231 	} else 	if ( (plr->detail_weapon_extras < 0) || (plr->detail_weapon_extras > 1) ) {
232 		data_failure = true;
233 	}
234 
235 	if (data_failure) {
236 		throw "Data check failure in details!";
237 	}
238 }
239 
plr_import_stats()240 void pilotfile_convert::plr_import_stats()
241 {
242 	int idx;
243 	char name[35];
244 
245 	if (fver >= 242) {
246 		return;
247 	}
248 
249 	// read everything, but we don't need any of it ...
250 
251 	cfread_int(cfp);	// score
252 	cfread_int(cfp);	// rank
253 	cfread_int(cfp);	// assists
254 
255 	// medals
256 	for (idx = 0; idx < 18; idx++) {
257 		cfread_int(cfp);
258 	}
259 
260 	// kills per ship
261 	int count = cfread_int(cfp);
262 
263 	for (idx = 0; idx < count; idx++) {
264 		cfread_ushort(cfp);
265 		cfread_string_len(name, sizeof(name), cfp);
266 	}
267 
268 	cfread_int(cfp);	// kill_count
269 	cfread_int(cfp);	// kill_count_ok
270 
271 	cfread_uint(cfp);	// p_shots_fired
272 	cfread_uint(cfp);	// s_shots_fired
273 	cfread_uint(cfp);	// p_shots_hit
274 	cfread_uint(cfp);	// s_shots_hit
275 
276 	cfread_uint(cfp);	// p_bonehead_hits
277 	cfread_uint(cfp);	// s_bonehead_hits
278 	cfread_uint(cfp);	// bonehead_kills
279 }
280 
plr_import_loadout()281 void pilotfile_convert::plr_import_loadout()
282 {
283 	int idx, j;
284 	int s_count, w_count;
285 	char name[52];
286 
287 	if (fver >= 242) {
288 		return;
289 	}
290 
291 	// have to read it, but don't need any of it ...
292 
293 	cfread_string_len(name, sizeof(name), cfp);	// filename
294 	cfread_string_len(name, sizeof(name), cfp);	// last_modified
295 
296 	s_count = cfread_int(cfp);	// num ships
297 	w_count = cfread_int(cfp);	// num weapons
298 
299 	// ships
300 	for (idx = 0; idx < s_count; idx++) {
301 		cfread_int(cfp);	// count
302 		cfread_string_len(name, sizeof(name), cfp);	// name
303 	}
304 
305 	// weapons
306 	for (idx = 0; idx < w_count; idx++) {
307 		cfread_int(cfp);	// count
308 		cfread_string_len(name, sizeof(name), cfp);	// name
309 	}
310 
311 	// loadout info
312 	for (idx = 0; idx < 12; idx++) {
313 		cfread_int(cfp);	// ship class
314 		cfread_string_len(name, sizeof(name), cfp);	// ship name
315 
316 		for (j = 0; j < 12; j++) {
317 			cfread_int(cfp);	// weapon type
318 			cfread_int(cfp);	// weapon count
319 			cfread_string_len(name, sizeof(name), cfp);	// weapon name
320 		}
321 	}
322 }
323 
plr_import_multiplayer()324 void pilotfile_convert::plr_import_multiplayer()
325 {
326 	plr->multi_squad_set = cfread_ubyte(cfp);
327 	plr->multi_endgame_set = cfread_ubyte(cfp);
328 	plr->multi_flags = cfread_int(cfp);
329 	plr->multi_respawn = cfread_uint(cfp);
330 	plr->multi_max_observers = cfread_ubyte(cfp);
331 	plr->multi_skill_level = cfread_ubyte(cfp);
332 	plr->multi_voice_qos = cfread_ubyte(cfp);
333 	plr->multi_voice_token_wait = cfread_int(cfp);
334 	plr->multi_voice_record_time = cfread_int(cfp);
335 	plr->multi_time_limit = cfread_int(cfp);
336 	plr->multi_kill_limit = cfread_int(cfp);
337 
338 	plr->multi_local_flags = cfread_int(cfp);
339 	plr->multi_local_update_level = cfread_int(cfp);
340 }
341 
plr_import_red_alert()342 void pilotfile_convert::plr_import_red_alert()
343 {
344 	int idx, j;
345 	char name[35];
346 
347 	if (fver >= 242) {
348 		return;
349 	}
350 
351 	// have to read it, but don't need any of it ...
352 
353 	int num_slots = cfread_int(cfp);
354 
355 	if ( (num_slots < 0) || (num_slots >= 32) ) {
356 		throw "Data check failure in red-alert!";
357 	}
358 
359 	if ( !num_slots ) {
360 		return;
361 	}
362 
363 	for (idx = 0; idx < num_slots; idx++) {
364 		cfread_string(name, sizeof(name) - 1, cfp);
365 		cfread_float(cfp);
366 
367 		cfread_string_len(name, sizeof(name), cfp);
368 
369 		// subsystem hits
370 		for (j = 0; j < 64; j++) {
371 			cfread_float(cfp);
372 		}
373 
374 		// aggregate hits
375 		for (j = 0; j < 12; j++) {
376 			cfread_float(cfp);
377 		}
378 
379 		// weapons
380 		for (j = 0; j < 12; j++) {
381 			cfread_string_len(name, sizeof(name), cfp);
382 			cfread_int(cfp);
383 		}
384 	}
385 }
386 
plr_import_variables()387 void pilotfile_convert::plr_import_variables()
388 {
389 	int idx;
390 	sexp_variable nvar;
391 
392 	int num_variables = cfread_int(cfp);
393 
394 	if ( (num_variables < 0) || (num_variables >= 100) ) {
395 		throw "Data check failure in variables!";
396 	}
397 
398 	plr->variables.reserve(num_variables);
399 
400 	for (idx = 0; idx < num_variables; idx++) {
401 		nvar.type = cfread_int(cfp);
402 		cfread_string_len(nvar.text, sizeof(nvar.text), cfp);
403 		cfread_string_len(nvar.variable_name, sizeof(nvar.variable_name), cfp);
404 
405 		plr->variables.push_back( nvar );
406 	}
407 }
408 
plr_import()409 void pilotfile_convert::plr_import()
410 {
411 	char name[35];
412 	int idx;
413 
414 	unsigned int plr_id = cfread_uint(cfp);
415 
416 	if (plr_id != 0x46505346) {
417 		throw "Invalid file signature!";
418 	}
419 
420 	fver = cfread_uint(cfp);
421 
422 	if ( (fver != 142) && (fver != 242) ) {
423 		throw "Unsupported file version!";
424 	}
425 
426 	// multi flag
427 	plr->is_multi = (int)cfread_ubyte(cfp);
428 
429 	// rank
430 	plr->rank = cfread_int(cfp);
431 
432 	// mainhall, don't need it
433 	if (fver < 242) {
434 		cfread_ubyte(cfp);
435 	}
436 
437 	plr->tips = cfread_int(cfp);
438 
439 	if ( (plr->tips < 0) || (plr->tips > 1) ) {
440 		throw "Data check failure!";
441 	}
442 
443 	cfread_string_len(plr->image_filename, sizeof(plr->image_filename), cfp);
444 	cfread_string_len(plr->squad_name, sizeof(plr->squad_name), cfp);
445 	cfread_string_len(plr->squad_filename, sizeof(plr->squad_filename), cfp);
446 	cfread_string_len(plr->current_campaign, sizeof(plr->current_campaign), cfp);
447 	cfread_string_len(plr->last_ship_flown, sizeof(plr->last_ship_flown), cfp);
448 
449 	// controls
450 	plr_import_controls();
451 
452 	// hud config
453 	plr_import_hud();
454 
455 	// cutscenes, don't need it
456 	if (fver < 242) {
457 		cfread_int(cfp);
458 	}
459 
460 	// volume stuff
461 	plr->sound_volume = cfread_float(cfp);
462 	plr->music_volume = cfread_float(cfp);
463 	plr->voice_volume = cfread_float(cfp);
464 
465 	// detail settings
466 	plr_import_detail();
467 
468 	// recent missions, don't need it
469 	int num_missions = cfread_int(cfp);
470 
471 	for (idx = 0; idx < num_missions; idx++) {
472 		cfread_string_len(name, sizeof(name), cfp);
473 	}
474 
475 	// stats, will skip if fver < 242
476 	plr_import_stats();
477 
478 	plr->skill_level = cfread_int(cfp);
479 
480 	if ( (plr->skill_level < 0) || (plr->skill_level > 4) ) {
481 		throw "Data check failure!";
482 	}
483 
484 	// extra joystick stuff
485 	for (idx = 0; idx < 5; idx++) {
486 		plr->joy_axis_map_to[idx] = cfread_int(cfp);
487 		plr->joy_invert_axis[idx] = cfread_int(cfp);
488 	}
489 
490 	// flags
491 	plr->save_flags = cfread_int(cfp);
492 
493 	// loadout, will skip if fver < 242
494 	plr_import_loadout();
495 
496 	// multiplayer
497 	plr_import_multiplayer();
498 
499 	// two briefing related values
500 	plr->readyroom_listing_mode = cfread_int(cfp);
501 	Briefing_voice_enabled = cfread_int(cfp) != 0;
502 
503 	plr->net_protocol = cfread_int(cfp);
504 
505 	// protocol must be set to something
506 	if (plr->net_protocol == NET_NONE) {
507 		plr->net_protocol = NET_TCP;
508 	} else if ( (plr->net_protocol < 0) || (plr->net_protocol > NET_VMT) ) {
509 		throw "Data check failure!";
510 	}
511 
512 	// red alert status, will skip if fver < 242 (and should be empty if multi)
513 	plr_import_red_alert();
514 
515 	// briefing auto-advance
516 	plr->auto_advance = cfread_int(cfp);
517 
518 	if ( (plr->auto_advance < 0) || (plr->auto_advance > 1) ) {
519 		throw "Data check failure!";
520 	}
521 
522 	// some input options
523 	plr->Use_mouse_to_fly = cfread_int(cfp);
524 	plr->Mouse_sensitivity = cfread_int(cfp);
525 	plr->Joy_sensitivity = cfread_int(cfp);
526 	plr->Dead_zone_size = cfread_int(cfp);
527 
528 	// variables
529 	plr_import_variables();
530 
531 
532 	// and... we're done! :)
533 }
534 
plr_export_flags()535 void pilotfile_convert::plr_export_flags()
536 {
537 	startSection(Section::Flags);
538 
539 	// tips
540 	cfwrite_ubyte((unsigned char)plr->tips, cfp);
541 
542 	// saved flags
543 	cfwrite_int(plr->save_flags, cfp);
544 
545 	// listing mode (single or campaign missions)
546 	cfwrite_int(plr->readyroom_listing_mode, cfp);
547 
548 	// briefing auto-play
549 	cfwrite_int(plr->auto_advance, cfp);
550 
551 	// special rank setting (to avoid having to read all stats on verify)
552 	cfwrite_int(plr->rank, cfp);
553 
554 	// What game mode we were in last on this pilot
555 	cfwrite_int(plr->is_multi, cfp);
556 
557 	// which language was this pilot created with
558 	cfwrite_string_len(plr->language, cfp);
559 
560 	endSection();
561 }
562 
plr_export_info()563 void pilotfile_convert::plr_export_info()
564 {
565 	startSection(Section::Info);
566 
567 	// pilot image
568 	cfwrite_string_len(plr->image_filename, cfp);
569 
570 	// squad name
571 	cfwrite_string_len(plr->squad_name, cfp);
572 
573 	// squad image
574 	cfwrite_string_len(plr->squad_filename, cfp);
575 
576 	// active campaign
577 	cfwrite_string_len(plr->current_campaign, cfp);
578 
579 	endSection();
580 }
581 
plr_export_stats()582 void pilotfile_convert::plr_export_stats()
583 {
584 	int idx, list_size = 0;
585 
586 	startSection(Section::Scoring);
587 
588 	// global, all-time stats
589 	cfwrite_int(all_time_stats.score, cfp);
590 	cfwrite_int(all_time_stats.rank, cfp);
591 	cfwrite_int(all_time_stats.assists, cfp);
592 	cfwrite_int(all_time_stats.kill_count, cfp);
593 	cfwrite_int(all_time_stats.kill_count_ok, cfp);
594 	cfwrite_int(all_time_stats.bonehead_kills, cfp);
595 
596 	cfwrite_uint(all_time_stats.p_shots_fired, cfp);
597 	cfwrite_uint(all_time_stats.p_shots_hit, cfp);
598 	cfwrite_uint(all_time_stats.p_bonehead_hits, cfp);
599 
600 	cfwrite_uint(all_time_stats.s_shots_fired, cfp);
601 	cfwrite_uint(all_time_stats.s_shots_hit, cfp);
602 	cfwrite_uint(all_time_stats.s_bonehead_hits, cfp);
603 
604 	cfwrite_uint(all_time_stats.flight_time, cfp);
605 	cfwrite_uint(all_time_stats.missions_flown, cfp);
606 	cfwrite_int((int)all_time_stats.last_flown, cfp);
607 	cfwrite_int((int)all_time_stats.last_backup, cfp);
608 
609 	// ship kills (contains ships across all mods, not just current)
610 	list_size = (int)all_time_stats.ship_kills.size();
611 	cfwrite_int(list_size, cfp);
612 
613 	for (idx = 0; idx < list_size; idx++) {
614 		cfwrite_string_len(all_time_stats.ship_kills[idx].name.c_str(), cfp);
615 		cfwrite_int(all_time_stats.ship_kills[idx].val, cfp);
616 	}
617 
618 	// medals earned (contains medals across all mods, not just current)
619 	list_size = (int)all_time_stats.medals_earned.size();
620 	cfwrite_int(list_size, cfp);
621 
622 	for (idx = 0; idx < list_size; idx++) {
623 		cfwrite_string_len(all_time_stats.medals_earned[idx].name.c_str(), cfp);
624 		cfwrite_int(all_time_stats.medals_earned[idx].val, cfp);
625 	}
626 
627 	endSection();
628 }
629 
plr_export_stats_multi()630 void pilotfile_convert::plr_export_stats_multi()
631 {
632 	int idx, list_size = 0;
633 
634 	startSection(Section::ScoringMulti);
635 
636 	// global, all-time stats
637 	cfwrite_int(multi_stats.score, cfp);
638 	cfwrite_int(multi_stats.rank, cfp);
639 	cfwrite_int(multi_stats.assists, cfp);
640 	cfwrite_int(multi_stats.kill_count, cfp);
641 	cfwrite_int(multi_stats.kill_count_ok, cfp);
642 	cfwrite_int(multi_stats.bonehead_kills, cfp);
643 
644 	cfwrite_uint(multi_stats.p_shots_fired, cfp);
645 	cfwrite_uint(multi_stats.p_shots_hit, cfp);
646 	cfwrite_uint(multi_stats.p_bonehead_hits, cfp);
647 
648 	cfwrite_uint(multi_stats.s_shots_fired, cfp);
649 	cfwrite_uint(multi_stats.s_shots_hit, cfp);
650 	cfwrite_uint(multi_stats.s_bonehead_hits, cfp);
651 
652 	cfwrite_uint(multi_stats.flight_time, cfp);
653 	cfwrite_uint(multi_stats.missions_flown, cfp);
654 	cfwrite_int((int)multi_stats.last_flown, cfp);
655 	cfwrite_int((int)multi_stats.last_backup, cfp);
656 
657 	// ship kills (contains medals across all mods, not just current)
658 	list_size = (int)multi_stats.ship_kills.size();
659 	cfwrite_int(list_size, cfp);
660 
661 	for (idx = 0; idx < list_size; idx++) {
662 		cfwrite_string_len(multi_stats.ship_kills[idx].name.c_str(), cfp);
663 		cfwrite_int(multi_stats.ship_kills[idx].val, cfp);
664 	}
665 
666 	// medals earned (contains medals across all mods, not just current)
667 	list_size = (int)multi_stats.medals_earned.size();
668 	cfwrite_int(list_size, cfp);
669 
670 	for (idx = 0; idx < list_size; idx++) {
671 		cfwrite_string_len(multi_stats.medals_earned[idx].name.c_str(), cfp);
672 		cfwrite_int(multi_stats.medals_earned[idx].val, cfp);
673 	}
674 
675 	endSection();
676 }
677 
plr_export_hud()678 void pilotfile_convert::plr_export_hud()
679 {
680 	int idx;
681 
682 	startSection(Section::HUD);
683 
684 	// flags
685 	cfwrite_int(plr->hud_show_flags, cfp);
686 	cfwrite_int(plr->hud_show_flags2, cfp);
687 
688 	cfwrite_int(plr->hud_popup_flags, cfp);
689 	cfwrite_int(plr->hud_popup_flags2, cfp);
690 
691 	// settings
692 	cfwrite_ubyte(plr->hud_num_lines, cfp);
693 
694 	cfwrite_int(plr->hud_rp_flags, cfp);
695 	cfwrite_int(plr->hud_rp_dist, cfp);
696 
697 	// basic colors
698 	cfwrite_int(0, cfp);	// color
699 	cfwrite_int(8, cfp);	// alpha
700 
701 	// gauge-specific colors
702 	cfwrite_int(39, cfp);
703 
704 	for (idx = 0; idx < 39; idx++) {
705 		cfwrite_ubyte(plr->hud_colors[idx][0], cfp);
706 		cfwrite_ubyte(plr->hud_colors[idx][1], cfp);
707 		cfwrite_ubyte(plr->hud_colors[idx][2], cfp);
708 		cfwrite_ubyte(plr->hud_colors[idx][3], cfp);
709 	}
710 
711 	endSection();
712 }
713 
plr_export_variables()714 void pilotfile_convert::plr_export_variables()
715 {
716 	int list_size = 0;
717 	int idx;
718 
719 	startSection(Section::Variables);
720 
721 	list_size = (int)plr->variables.size();
722 
723 	cfwrite_int(list_size, cfp);
724 
725 	for (idx = 0; idx < list_size; idx++) {
726 		cfwrite_int(plr->variables[idx].type, cfp);
727 		cfwrite_string_len(plr->variables[idx].text, cfp);
728 		cfwrite_string_len(plr->variables[idx].variable_name, cfp);
729 	}
730 
731 	endSection();
732 }
733 
plr_export_multiplayer()734 void pilotfile_convert::plr_export_multiplayer()
735 {
736 	startSection(Section::Multiplayer);
737 
738 	// netgame options
739 	cfwrite_ubyte(plr->multi_squad_set, cfp);
740 	cfwrite_ubyte(plr->multi_endgame_set, cfp);
741 	cfwrite_int(plr->multi_flags, cfp);
742 	cfwrite_uint(plr->multi_respawn, cfp);
743 	cfwrite_ubyte(plr->multi_max_observers, cfp);
744 	cfwrite_ubyte(plr->multi_skill_level, cfp);
745 	cfwrite_ubyte(plr->multi_voice_qos, cfp);
746 	cfwrite_int(plr->multi_voice_token_wait, cfp);
747 	cfwrite_int(plr->multi_voice_record_time, cfp);
748 	cfwrite_int(plr->multi_time_limit, cfp);
749 	cfwrite_int(plr->multi_kill_limit, cfp);
750 
751 	// local options
752 	cfwrite_int(plr->multi_local_flags, cfp);
753 	cfwrite_int(plr->multi_local_update_level, cfp);
754 
755 	// netgame protocol
756 	cfwrite_int(plr->net_protocol, cfp);
757 
758 	endSection();
759 }
760 
plr_export_controls()761 void pilotfile_convert::plr_export_controls()
762 {
763 	unsigned int idx;
764 
765 	startSection(Section::Controls);
766 
767 	cfwrite_ushort((unsigned short)plr->controls.size(), cfp);
768 
769 	for (idx = 0; idx < plr->controls.size(); idx++) {
770 		cfwrite_short(plr->controls[idx].get_btn(CID_KEYBOARD), cfp);
771 		cfwrite_short(plr->controls[idx].get_btn(CID_JOY0), cfp);
772 		// placeholder? for future mouse_id?
773 		cfwrite_short(-1, cfp);
774 	}
775 
776 	// extra joystick stuff
777 	cfwrite_int(MAX_JOY_AXES_CONV, cfp);
778 	for (idx = 0; idx < MAX_JOY_AXES_CONV; idx++) {
779 		cfwrite_int(plr->joy_axis_map_to[idx], cfp);
780 		cfwrite_int(plr->joy_invert_axis[idx], cfp);
781 	}
782 
783 	endSection();
784 }
785 
plr_export_settings()786 void pilotfile_convert::plr_export_settings()
787 {
788 	startSection(Section::Settings);
789 
790 	// sound/voice/music
791 	cfwrite_float(plr->sound_volume, cfp);
792 	cfwrite_float(plr->music_volume, cfp);
793 	cfwrite_float(plr->voice_volume, cfp);
794 
795 	cfwrite_int(plr->voice_enabled, cfp);
796 
797 	// skill level
798 	cfwrite_int(plr->skill_level, cfp);
799 
800 	// input options
801 	cfwrite_int(plr->Use_mouse_to_fly, cfp);
802 	cfwrite_int(plr->Mouse_sensitivity, cfp);
803 	cfwrite_int(plr->Joy_sensitivity, cfp);
804 	cfwrite_int(plr->Dead_zone_size, cfp);
805 
806 	// detail
807 	cfwrite_int(plr->detail_setting, cfp);
808 	cfwrite_int(plr->detail_nebula, cfp);
809 	cfwrite_int(plr->detail_distance, cfp);
810 	cfwrite_int(plr->detail_hardware_textures, cfp);
811 	cfwrite_int(plr->detail_num_debris, cfp);
812 	cfwrite_int(plr->detail_num_particles, cfp);
813 	cfwrite_int(plr->detail_num_stars, cfp);
814 	cfwrite_int(plr->detail_shield_effects, cfp);
815 	cfwrite_int(plr->detail_lighting, cfp);
816 	cfwrite_int(plr->detail_targetview_model, cfp);
817 	cfwrite_int(plr->detail_planets_suns, cfp);
818 	cfwrite_int(plr->detail_weapon_extras, cfp);
819 
820 	endSection();
821 }
822 
plr_export()823 void pilotfile_convert::plr_export()
824 {
825 	Assert( cfp != NULL );
826 
827 	// header and version
828 	cfwrite_int(PLR_FILE_ID, cfp);
829 	cfwrite_ubyte(PLR_VERSION, cfp);
830 
831 	// flags and info sections go first
832 	plr_export_flags();
833 	plr_export_info();
834 
835 	// everything else is next, not order specific
836 	plr_export_stats();
837 	plr_export_stats_multi();
838 	plr_export_hud();
839 	plr_export_variables();
840 	plr_export_multiplayer();
841 	plr_export_controls();
842 	plr_export_settings();
843 
844 
845 	// and... we're done! :)
846 }
847 
plr_convert(const char * fname,bool inferno)848 bool pilotfile_convert::plr_convert(const char *fname, bool inferno)
849 {
850 	Assert( fname != NULL );
851 
852 	SCP_string filename;
853 	bool rval = true;
854 
855 
856 	if (plr == NULL) {
857 		plr = new(std::nothrow) plr_data;
858 	}
859 
860 	if (plr == NULL) {
861 		return false;
862 	}
863 
864 	filename.reserve(200);
865 
866 	cf_create_default_path_string(filename, CF_TYPE_SINGLE_PLAYERS, (inferno) ? "inferno" : nullptr, false,
867 	                              CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
868 
869 	if (inferno) {
870 		filename.append(DIR_SEPARATOR_STR);
871 	}
872 
873 	filename.append(fname);
874 	filename.append(".pl2");
875 
876 	mprintf(("  PL2 => Converting '%s'...\n", filename.c_str()));
877 
878 	cfp = cfopen(filename.c_str(), "rb", CFILE_NORMAL);
879 
880 	if ( !cfp ) {
881 		mprintf(("  PL2 => Unable to open '%s' for import!\n", fname));
882 		return false;
883 	}
884 
885 	try {
886 		plr_import();
887 	} catch (const char *err) {
888 		mprintf((  "  PL2 => Import ERROR: %s\n", err));
889 		rval = false;
890 	}
891 
892 	cfclose(cfp);
893 	cfp = NULL;
894 
895 	if ( !rval ) {
896 		return false;
897 	}
898 
899 	filename.assign(fname);
900 	filename.append(".plr");
901 
902 	cfp = cfopen(filename.c_str(), "wb", CFILE_NORMAL, CF_TYPE_PLAYERS, false,
903 	             CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
904 
905 	if ( !cfp ) {
906 		mprintf(("  PLR => Unable to open '%s' for export!\n", fname));
907 		return false;
908 	}
909 
910 	try {
911 		plr_export();
912 	} catch (const char *err) {
913 		mprintf(("  PLR => Export ERROR: %s\n", err));
914 		rval = false;
915 	}
916 
917 	cfclose(cfp);
918 	cfp = NULL;
919 
920 	if (rval) {
921 		mprintf(("  PLR => Conversion complete!\n"));
922 	}
923 
924 	return rval;
925 }
926 
927