FS2_Open
Open source remastering of the Freespace 2 engine
plr.cpp
Go to the documentation of this file.
1 
2 #include "freespace2/freespace.h"
3 #include "gamesnd/eventmusic.h"
4 #include "hud/hudconfig.h"
5 #include "hud/hudsquadmsg.h"
6 #include "io/joy.h"
7 #include "io/mouse.h"
9 #include "menuui/techmenu.h"
10 #include "network/multi.h"
11 #include "osapi/osregistry.h"
12 #include "pilotfile/pilotfile.h"
13 #include "playerman/managepilot.h"
14 #include "playerman/player.h"
15 #include "ship/ship.h"
16 #include "sound/audiostr.h"
17 #include "stats/medals.h"
18 #include "weapon/weapon.h"
19 
20 
21 void pilotfile::plr_read_flags()
22 {
23  // tips?
24  p->tips = (int)cfread_ubyte(cfp);
25 
26  // saved flags
27  p->save_flags = cfread_int(cfp);
28 
29  // listing mode (single or campaign missions
30  p->readyroom_listing_mode = cfread_int(cfp);
31 
32  // briefing auto-play
33  p->auto_advance = cfread_int(cfp);
34 
35  // special rank setting (to avoid having to read all stats on verify)
36  // will be the multi rank
37  // if there's a valid CSG, this will be overwritten
38  p->stats.rank = cfread_int(cfp);
39 
40  if (version > 0)
41  {
42  p->player_was_multi = cfread_int(cfp);
43  } else
44  {
45  p->player_was_multi = 0; // Default to single player
46  }
47 
48  // which language was this pilot created with
49  if (version > 1) {
50  cfread_string_len(p->language, sizeof(p->language), cfp);
51  } else {
52  // if we don't know, default to the current language setting
53  lcl_get_language_name(p->language);
54  }
55 }
56 
57 void pilotfile::plr_write_flags()
58 {
59  startSection(Section::Flags);
60 
61  // tips
62  cfwrite_ubyte((unsigned char)p->tips, cfp);
63 
64  // saved flags
65  cfwrite_int(p->save_flags, cfp);
66 
67  // listing mode (single or campaign missions)
68  cfwrite_int(p->readyroom_listing_mode, cfp);
69 
70  // briefing auto-play
71  cfwrite_int(p->auto_advance, cfp);
72 
73  // special rank setting (to avoid having to read all stats on verify)
74  // should be multi only from now on
75  cfwrite_int(multi_stats.rank, cfp);
76 
77  // What game mode we were in last on this pilot
78  cfwrite_int(p->player_was_multi, cfp);
79 
80  // which language was this pilot created with
81  cfwrite_string_len(p->language, cfp);
82 
83  endSection();
84 }
85 
86 void pilotfile::plr_read_info()
87 {
88  if ( !m_have_flags ) {
89  throw "Info before Flags!";
90  }
91 
92  // pilot image
93  cfread_string_len(p->image_filename, MAX_FILENAME_LEN, cfp);
94 
95  // multi squad name
96  cfread_string_len(p->m_squad_name, NAME_LENGTH, cfp);
97 
98  // squad image
99  cfread_string_len(p->m_squad_filename, MAX_FILENAME_LEN, cfp);
100 
101  // active campaign
102  cfread_string_len(p->current_campaign, MAX_FILENAME_LEN, cfp);
103 }
104 
105 void pilotfile::plr_write_info()
106 {
107  startSection(Section::Info);
108 
109  // pilot image
110  cfwrite_string_len(p->image_filename, cfp);
111 
112  // multi squad name
113  cfwrite_string_len(p->m_squad_name, cfp);
114 
115  // squad image
116  cfwrite_string_len(p->m_squad_filename, cfp);
117 
118  // active campaign
119  cfwrite_string_len(p->current_campaign, cfp);
120 
121  endSection();
122 }
123 
124 void pilotfile::plr_read_hud()
125 {
126  int idx;
127 
128  // flags
131 
134 
135  // settings
137 
140 
141  // basic colors
144 
147  }
148 
150 
151  // gauge-specific colors
152  int num_gauges = cfread_int(cfp);
153 
154  for (idx = 0; idx < num_gauges; idx++) {
155  ubyte red = cfread_ubyte(cfp);
156  ubyte green = cfread_ubyte(cfp);
157  ubyte blue = cfread_ubyte(cfp);
158  ubyte alpha = cfread_ubyte(cfp);
159 
160  if (idx >= NUM_HUD_GAUGES) {
161  continue;
162  }
163 
164  HUD_config.clr[idx].red = red;
168  }
169 }
170 
171 void pilotfile::plr_write_hud()
172 {
173  int idx;
174 
175  startSection(Section::HUD);
176 
177  // flags
180 
183 
184  // settings
186 
189 
190  // basic colors
193 
194  // gauge-specific colors
196 
197  for (idx = 0; idx < NUM_HUD_GAUGES; idx++) {
198  cfwrite_ubyte(HUD_config.clr[idx].red, cfp);
199  cfwrite_ubyte(HUD_config.clr[idx].green, cfp);
200  cfwrite_ubyte(HUD_config.clr[idx].blue, cfp);
201  cfwrite_ubyte(HUD_config.clr[idx].alpha, cfp);
202  }
203 
204  endSection();
205 }
206 
207 void pilotfile::plr_read_variables()
208 {
209  int list_size = 0;
210  int idx;
211  sexp_variable n_var;
212 
213  list_size = cfread_int(cfp);
214 
215  if (list_size <= 0) {
216  return;
217  }
218 
219  p->variables.reserve(list_size);
220 
221  for (idx = 0; idx < list_size; idx++) {
222  n_var.type = cfread_int(cfp);
223  cfread_string_len(n_var.text, TOKEN_LENGTH, cfp);
225 
226  p->variables.push_back( n_var );
227  }
228 }
229 
230 void pilotfile::plr_write_variables()
231 {
232  int list_size = 0;
233  int idx;
234 
235  startSection(Section::Variables);
236 
237  list_size = (int)p->variables.size();
238 
239  cfwrite_int(list_size, cfp);
240 
241  for (idx = 0; idx < list_size; idx++) {
242  cfwrite_int(p->variables[idx].type, cfp);
243  cfwrite_string_len(p->variables[idx].text, cfp);
244  cfwrite_string_len(p->variables[idx].variable_name, cfp);
245  }
246 
247  endSection();
248 }
249 
250 void pilotfile::plr_read_multiplayer()
251 {
252  // netgame options
253  p->m_server_options.squad_set = cfread_ubyte(cfp);
254  p->m_server_options.endgame_set = cfread_ubyte(cfp);
255  p->m_server_options.flags = cfread_int(cfp);
256  p->m_server_options.respawn = cfread_uint(cfp);
257  p->m_server_options.max_observers = cfread_ubyte(cfp);
258  p->m_server_options.skill_level = cfread_ubyte(cfp);
259  p->m_server_options.voice_qos = cfread_ubyte(cfp);
260  p->m_server_options.voice_token_wait = cfread_int(cfp);
261  p->m_server_options.voice_record_time = cfread_int(cfp);
262  p->m_server_options.mission_time_limit = (fix)cfread_int(cfp);
263  p->m_server_options.kill_limit = cfread_int(cfp);
264 
265  // local options
266  p->m_local_options.flags = cfread_int(cfp);
267  p->m_local_options.obj_update_level = cfread_int(cfp);
268 
269  // netgame protocol
271 
274  }
275 }
276 
277 void pilotfile::plr_write_multiplayer()
278 {
279  startSection(Section::Multiplayer);
280 
281  // netgame options
282  cfwrite_ubyte(p->m_server_options.squad_set, cfp);
283  cfwrite_ubyte(p->m_server_options.endgame_set, cfp);
284  cfwrite_int(p->m_server_options.flags, cfp);
285  cfwrite_uint(p->m_server_options.respawn, cfp);
286  cfwrite_ubyte(p->m_server_options.max_observers, cfp);
287  cfwrite_ubyte(p->m_server_options.skill_level, cfp);
288  cfwrite_ubyte(p->m_server_options.voice_qos, cfp);
289  cfwrite_int(p->m_server_options.voice_token_wait, cfp);
290  cfwrite_int(p->m_server_options.voice_record_time, cfp);
291  cfwrite_int((int)p->m_server_options.mission_time_limit, cfp);
292  cfwrite_int(p->m_server_options.kill_limit, cfp);
293 
294  // local options
295  cfwrite_int(p->m_local_options.flags, cfp);
296  cfwrite_int(p->m_local_options.obj_update_level, cfp);
297 
298  // netgame protocol
300 
301  endSection();
302 }
303 
304 void pilotfile::plr_read_stats()
305 {
306  int idx, j, list_size = 0;
307  index_list_t ilist;
308  char t_string[NAME_LENGTH+1];
309 
310  // global, all-time stats (used only until campaign stats are loaded)
311  all_time_stats.score = cfread_int(cfp);
312  all_time_stats.rank = cfread_int(cfp);
313  all_time_stats.assists = cfread_int(cfp);
314  all_time_stats.kill_count = cfread_int(cfp);
315  all_time_stats.kill_count_ok = cfread_int(cfp);
316  all_time_stats.bonehead_kills = cfread_int(cfp);
317 
318  all_time_stats.p_shots_fired = cfread_uint(cfp);
319  all_time_stats.p_shots_hit = cfread_uint(cfp);
320  all_time_stats.p_bonehead_hits = cfread_uint(cfp);
321 
322  all_time_stats.s_shots_fired = cfread_uint(cfp);
323  all_time_stats.s_shots_hit = cfread_uint(cfp);
324  all_time_stats.s_bonehead_hits = cfread_uint(cfp);
325 
326  all_time_stats.flight_time = cfread_uint(cfp);
327  all_time_stats.missions_flown = cfread_uint(cfp);
328  all_time_stats.last_flown = (_fs_time_t)cfread_int(cfp);
329  all_time_stats.last_backup = (_fs_time_t)cfread_int(cfp);
330 
331  // ship kills (contains ships across all mods, not just current)
332  list_size = cfread_int(cfp);
333  all_time_stats.ship_kills.reserve(list_size);
334 
335  for (idx = 0; idx < list_size; idx++) {
336  cfread_string_len(t_string, NAME_LENGTH, cfp);
337 
338  ilist.name = t_string;
339  ilist.index = ship_info_lookup(t_string);
340  ilist.val = cfread_int(cfp);
341 
342  all_time_stats.ship_kills.push_back(ilist);
343  }
344 
345  // medals earned (contains medals across all mods, not just current)
346  list_size = cfread_int(cfp);
347  all_time_stats.medals_earned.reserve(list_size);
348 
349  for (idx = 0; idx < list_size; idx++) {
350  cfread_string_len(t_string, NAME_LENGTH,cfp);
351 
352  ilist.name = t_string;
353  ilist.index = medals_info_lookup(t_string);
354  ilist.val = cfread_int(cfp);
355 
356  all_time_stats.medals_earned.push_back(ilist);
357  }
358 
359  // if not in multiplayer mode then set these stats as the player stats
360  if ( !(Game_mode & GM_MULTIPLAYER) ) {
361  p->stats.score = all_time_stats.score;
362  p->stats.rank = all_time_stats.rank;
363  p->stats.assists = all_time_stats.assists;
364  p->stats.kill_count = all_time_stats.kill_count;
365  p->stats.kill_count_ok = all_time_stats.kill_count_ok;
366  p->stats.bonehead_kills = all_time_stats.bonehead_kills;
367 
368  p->stats.p_shots_fired = all_time_stats.p_shots_fired;
369  p->stats.p_shots_hit = all_time_stats.p_shots_hit;
370  p->stats.p_bonehead_hits = all_time_stats.p_bonehead_hits;
371 
372  p->stats.s_shots_fired = all_time_stats.s_shots_fired;
373  p->stats.s_shots_hit = all_time_stats.s_shots_hit;
374  p->stats.s_bonehead_hits = all_time_stats.s_bonehead_hits;
375 
376  p->stats.flight_time = all_time_stats.flight_time;
377  p->stats.missions_flown = all_time_stats.missions_flown;
378  p->stats.last_flown = all_time_stats.last_flown;
379  p->stats.last_backup = all_time_stats.last_backup;
380 
381  // ship kills (have to find ones that match content)
382  list_size = (int)all_time_stats.ship_kills.size();
383  for (idx = 0; idx < list_size; idx++) {
384  j = all_time_stats.ship_kills[idx].index;
385 
386  if (j >= 0) {
387  p->stats.kills[j] = all_time_stats.ship_kills[idx].val;
388  }
389  }
390 
391  // medals earned (have to find ones that match content)
392  list_size = (int)all_time_stats.medals_earned.size();
393  for (idx = 0; idx < list_size; idx++) {
394  j = all_time_stats.medals_earned[idx].index;
395 
396  if (j >= 0) {
397  p->stats.medal_counts[j] = all_time_stats.medals_earned[idx].val;
398  }
399  }
400  }
401 }
402 
403 void pilotfile::plr_write_stats()
404 {
405  int idx, list_size = 0;
406 
407  startSection(Section::Scoring);
408 
409  // global, all-time stats
410  cfwrite_int(all_time_stats.score, cfp);
411  cfwrite_int(all_time_stats.rank, cfp);
412  cfwrite_int(all_time_stats.assists, cfp);
413  cfwrite_int(all_time_stats.kill_count, cfp);
414  cfwrite_int(all_time_stats.kill_count_ok, cfp);
415  cfwrite_int(all_time_stats.bonehead_kills, cfp);
416 
417  cfwrite_uint(all_time_stats.p_shots_fired, cfp);
418  cfwrite_uint(all_time_stats.p_shots_hit, cfp);
419  cfwrite_uint(all_time_stats.p_bonehead_hits, cfp);
420 
421  cfwrite_uint(all_time_stats.s_shots_fired, cfp);
422  cfwrite_uint(all_time_stats.s_shots_hit, cfp);
423  cfwrite_uint(all_time_stats.s_bonehead_hits, cfp);
424 
425  cfwrite_uint(all_time_stats.flight_time, cfp);
426  cfwrite_uint(all_time_stats.missions_flown, cfp);
427  cfwrite_int((int)all_time_stats.last_flown, cfp);
428  cfwrite_int((int)all_time_stats.last_backup, cfp);
429 
430  // ship kills (contains ships across all mods, not just current)
431  list_size = (int)all_time_stats.ship_kills.size();
432  cfwrite_int(list_size, cfp);
433 
434  for (idx = 0; idx < list_size; idx++) {
435  cfwrite_string_len(all_time_stats.ship_kills[idx].name.c_str(), cfp);
436  cfwrite_int(all_time_stats.ship_kills[idx].val, cfp);
437  }
438 
439  // medals earned (contains medals across all mods, not just current)
440  list_size = (int)all_time_stats.medals_earned.size();
441  cfwrite_int(list_size, cfp);
442 
443  for (idx = 0; idx < list_size; idx++) {
444  cfwrite_string_len(all_time_stats.medals_earned[idx].name.c_str(), cfp);
445  cfwrite_int(all_time_stats.medals_earned[idx].val, cfp);
446  }
447 
448  endSection();
449 }
450 
451 void pilotfile::plr_read_stats_multi()
452 {
453  int idx, j, list_size = 0;
454  index_list_t ilist;
455  char t_string[NAME_LENGTH+1];
456 
457  // global, all-time stats (used only until campaign stats are loaded)
458  multi_stats.score = cfread_int(cfp);
459  multi_stats.rank = cfread_int(cfp);
460  multi_stats.assists = cfread_int(cfp);
461  multi_stats.kill_count = cfread_int(cfp);
462  multi_stats.kill_count_ok = cfread_int(cfp);
463  multi_stats.bonehead_kills = cfread_int(cfp);
464 
465  multi_stats.p_shots_fired = cfread_uint(cfp);
466  multi_stats.p_shots_hit = cfread_uint(cfp);
467  multi_stats.p_bonehead_hits = cfread_uint(cfp);
468 
469  multi_stats.s_shots_fired = cfread_uint(cfp);
470  multi_stats.s_shots_hit = cfread_uint(cfp);
471  multi_stats.s_bonehead_hits = cfread_uint(cfp);
472 
473  multi_stats.flight_time = cfread_uint(cfp);
474  multi_stats.missions_flown = cfread_uint(cfp);
475  multi_stats.last_flown = (_fs_time_t)cfread_int(cfp);
476  multi_stats.last_backup = (_fs_time_t)cfread_int(cfp);
477 
478  // ship kills (contains ships across all mods, not just current)
479  list_size = cfread_int(cfp);
480  multi_stats.ship_kills.reserve(list_size);
481 
482  for (idx = 0; idx < list_size; idx++) {
483  cfread_string_len(t_string, NAME_LENGTH, cfp);
484 
485  ilist.name = t_string;
486  ilist.index = ship_info_lookup(t_string);
487  ilist.val = cfread_int(cfp);
488 
489  multi_stats.ship_kills.push_back(ilist);
490  }
491 
492  // medals earned (contains medals across all mods, not just current)
493  list_size = cfread_int(cfp);
494  multi_stats.medals_earned.reserve(list_size);
495 
496  for (idx = 0; idx < list_size; idx++) {
497  cfread_string_len(t_string, NAME_LENGTH,cfp);
498 
499  ilist.name = t_string;
500  ilist.index = medals_info_lookup(t_string);
501  ilist.val = cfread_int(cfp);
502 
503  multi_stats.medals_earned.push_back(ilist);
504  }
505 
506  // if in multiplayer mode then set these stats as the player stats
507  if (Game_mode & GM_MULTIPLAYER) {
508  p->stats.score = multi_stats.score;
509  p->stats.rank = multi_stats.rank;
510  p->stats.assists = multi_stats.assists;
511  p->stats.kill_count = multi_stats.kill_count;
512  p->stats.kill_count_ok = multi_stats.kill_count_ok;
513  p->stats.bonehead_kills = multi_stats.bonehead_kills;
514 
515  p->stats.p_shots_fired = multi_stats.p_shots_fired;
516  p->stats.p_shots_hit = multi_stats.p_shots_hit;
517  p->stats.p_bonehead_hits = multi_stats.p_bonehead_hits;
518 
519  p->stats.s_shots_fired = multi_stats.s_shots_fired;
520  p->stats.s_shots_hit = multi_stats.s_shots_hit;
521  p->stats.s_bonehead_hits = multi_stats.s_bonehead_hits;
522 
523  p->stats.flight_time = multi_stats.flight_time;
524  p->stats.missions_flown = multi_stats.missions_flown;
525  p->stats.last_flown = multi_stats.last_flown;
526  p->stats.last_backup = multi_stats.last_backup;
527 
528  // ship kills (have to find ones that match content)
529  list_size = (int)multi_stats.ship_kills.size();
530  for (idx = 0; idx < list_size; idx++) {
531  j = multi_stats.ship_kills[idx].index;
532 
533  if (j >= 0) {
534  p->stats.kills[j] = multi_stats.ship_kills[idx].val;
535  }
536  }
537 
538  // medals earned (have to find ones that match content)
539  list_size = (int)multi_stats.medals_earned.size();
540  for (idx = 0; idx < list_size; idx++) {
541  j = multi_stats.medals_earned[idx].index;
542 
543  if (j >= 0) {
544  p->stats.medal_counts[j] = multi_stats.medals_earned[idx].val;
545  }
546  }
547  }
548 }
549 
550 void pilotfile::plr_write_stats_multi()
551 {
552  int idx, list_size = 0;
553 
554  startSection(Section::ScoringMulti);
555 
556  // global, all-time stats
557  cfwrite_int(multi_stats.score, cfp);
558  cfwrite_int(multi_stats.rank, cfp);
559  cfwrite_int(multi_stats.assists, cfp);
560  cfwrite_int(multi_stats.kill_count, cfp);
561  cfwrite_int(multi_stats.kill_count_ok, cfp);
562  cfwrite_int(multi_stats.bonehead_kills, cfp);
563 
564  cfwrite_uint(multi_stats.p_shots_fired, cfp);
565  cfwrite_uint(multi_stats.p_shots_hit, cfp);
566  cfwrite_uint(multi_stats.p_bonehead_hits, cfp);
567 
568  cfwrite_uint(multi_stats.s_shots_fired, cfp);
569  cfwrite_uint(multi_stats.s_shots_hit, cfp);
570  cfwrite_uint(multi_stats.s_bonehead_hits, cfp);
571 
572  cfwrite_uint(multi_stats.flight_time, cfp);
573  cfwrite_uint(multi_stats.missions_flown, cfp);
574  cfwrite_int((int)multi_stats.last_flown, cfp);
575  cfwrite_int((int)multi_stats.last_backup, cfp);
576 
577  // ship kills (contains medals across all mods, not just current)
578  list_size = (int)multi_stats.ship_kills.size();
579  cfwrite_int(list_size, cfp);
580 
581  for (idx = 0; idx < list_size; idx++) {
582  cfwrite_string_len(multi_stats.ship_kills[idx].name.c_str(), cfp);
583  cfwrite_int(multi_stats.ship_kills[idx].val, cfp);
584  }
585 
586  // medals earned (contains medals across all mods, not just current)
587  list_size = (int)multi_stats.medals_earned.size();
588  cfwrite_int(list_size, cfp);
589 
590  for (idx = 0; idx < list_size; idx++) {
591  cfwrite_string_len(multi_stats.medals_earned[idx].name.c_str(), cfp);
592  cfwrite_int(multi_stats.medals_earned[idx].val, cfp);
593  }
594 
595  endSection();
596 }
597 
598 void pilotfile::plr_read_controls()
599 {
600  int idx, list_size, list_axis;
601  short id1, id2, id3 __UNUSED;
602  int axi, inv;
603 
604  list_size = (int)cfread_ushort(cfp);
605  for (idx = 0; idx < list_size; idx++) {
606  id1 = cfread_short(cfp);
607  id2 = cfread_short(cfp);
608  id3 = cfread_short(cfp); // unused, at the moment
609 
610  if (idx < CCFG_MAX) {
611  Control_config[idx].key_id = id1;
612  Control_config[idx].joy_id = id2;
613  }
614  }
615 
616  list_axis = cfread_int(cfp);
617  for (idx = 0; idx < list_axis; idx++) {
618  axi = cfread_int(cfp);
619  inv = cfread_int(cfp);
620 
621  if (idx < NUM_JOY_AXIS_ACTIONS) {
622  Axis_map_to[idx] = axi;
623  Invert_axis[idx] = inv;
624  }
625  }
626 }
627 
628 void pilotfile::plr_write_controls()
629 {
630  int idx;
631 
632  startSection(Section::Controls);
633 
634  cfwrite_ushort(CCFG_MAX, cfp);
635 
636  for (idx = 0; idx < CCFG_MAX; idx++) {
637  cfwrite_short(Control_config[idx].key_id, cfp);
638  cfwrite_short(Control_config[idx].joy_id, cfp);
639  // placeholder? for future mouse_id?
640  cfwrite_short(-1, cfp);
641  }
642 
644 
645  for (idx = 0; idx < NUM_JOY_AXIS_ACTIONS; idx++) {
646  cfwrite_int(Axis_map_to[idx], cfp);
647  cfwrite_int(Invert_axis[idx], cfp);
648  }
649 
650  endSection();
651 }
652 
653 void pilotfile::plr_read_settings()
654 {
655  // sound/voice/music
659 
662 
663  if (Master_event_music_volume > 0.0f) {
665  } else {
667  }
668 
670 
671  // skill level
673 
674  // input options
678  Dead_zone_size = cfread_int(cfp);
679 
680  // detail
681  Detail.setting = cfread_int(cfp);
687  Detail.num_stars = cfread_int(cfp);
689  Detail.lighting = cfread_int(cfp);
693 }
694 
695 void pilotfile::plr_write_settings()
696 {
697  startSection(Section::Settings);
698 
699  // sound/voice/music
703 
705 
706  // skill level
708 
709  // input options
714 
715  // detail
716  cfwrite_int(Detail.setting, cfp);
728 
729  endSection();
730 }
731 
732 void pilotfile::plr_reset_data()
733 {
734  // internals
735  m_have_flags = false;
736  m_have_info = false;
737 
738  m_data_invalid = false;
739 
740  // set all the entries in the control config arrays to -1 (undefined)
742 
743  // init stats
744  p->stats.init();
745 
746  // reset scoring lists
747  all_time_stats.ship_kills.clear();
748  all_time_stats.medals_earned.clear();
749 
750  multi_stats.ship_kills.clear();
751  multi_stats.medals_earned.clear();
752 
753  // clear variables
754  p->variables.clear();
755 
756  // reset techroom to defaults (CSG will override this, multi will use defaults)
758 }
759 
760 void pilotfile::plr_close()
761 {
762  if (cfp) {
763  cfclose(cfp);
764  cfp = NULL;
765  }
766 
767  p = NULL;
768  filename = "";
769 
770  ship_list.clear();
771  weapon_list.clear();
772  intel_list.clear();
773  medals_list.clear();
774 
775  m_have_flags = false;
776  m_have_info = false;
777 }
778 
779 bool pilotfile::load_player(const char *callsign, player *_p)
780 {
781  // if we're a standalone server in multiplayer, just fill in some bogus values
782  // since we don't have a pilot file
783  if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER) ) {
784  Player->insignia_texture = -1;
785  strcpy_s(Player->callsign, NOX("Standalone"));
786  strcpy_s(Player->short_callsign, NOX("Standalone"));
787 
788  return true;
789  }
790 
791  // set player ptr first thing
792  p = _p;
793 
794  if ( !p ) {
795  Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) );
796  p = &Players[Player_num];
797  }
798 
799  filename = callsign;
800  filename += ".plr";
801 
802  if ( filename.size() == 4 ) {
803  mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str()));
804  return false;
805  }
806 
807  cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS);
808 
809  if ( !cfp ) {
810  mprintf(("PLR => Unable to open '%s' for reading!\n", filename.c_str()));
811  return false;
812  }
813 
814  unsigned int plr_id = cfread_uint(cfp);
815 
816  if (plr_id != PLR_FILE_ID) {
817  mprintf(("PLR => Invalid header id for '%s'!\n", filename.c_str()));
818  plr_close();
819  return false;
820  }
821 
822  // version, now used
823  version = cfread_ubyte(cfp);
824 
825  mprintf(("PLR => Loading '%s' with version %d...\n", filename.c_str(), version));
826 
827  plr_reset_data();
828 
829  // the point of all this: read in the PLR contents
830  while ( !cfeof(cfp) ) {
831  ushort section_id = cfread_ushort(cfp);
832  uint section_size = cfread_uint(cfp);
833 
834  size_t start_pos = cftell(cfp);
835 
836  // safety, to help protect against long reads
837  cf_set_max_read_len(cfp, section_size);
838 
839  try {
840  switch (section_id) {
841  case Section::Flags:
842  mprintf(("PLR => Parsing: Flags...\n"));
843  m_have_flags = true;
844  plr_read_flags();
845  break;
846 
847  case Section::Info:
848  mprintf(("PLR => Parsing: Info...\n"));
849  m_have_info = true;
850  plr_read_info();
851  break;
852 
853  case Section::Variables:
854  mprintf(("PLR => Parsing: Variables...\n"));
855  plr_read_variables();
856  break;
857 
858  case Section::HUD:
859  mprintf(("PLR => Parsing: HUD...\n"));
860  plr_read_hud();
861  break;
862 
863  case Section::Scoring:
864  mprintf(("PLR => Parsing: Scoring...\n"));
865  plr_read_stats();
866  break;
867 
868  case Section::ScoringMulti:
869  mprintf(("PLR => Parsing: ScoringMulti...\n"));
870  plr_read_stats_multi();
871  break;
872 
873  case Section::Multiplayer:
874  mprintf(("PLR => Parsing: Multiplayer...\n"));
875  plr_read_multiplayer();
876  break;
877 
878  case Section::Controls:
879  mprintf(("PLR => Parsing: Controls...\n"));
880  plr_read_controls();
881  break;
882 
883  case Section::Settings:
884  mprintf(("PLR => Parsing: Settings...\n"));
885  plr_read_settings();
886  break;
887 
888  default:
889  mprintf(("PLR => Skipping unknown section 0x%04x!\n", section_id));
890  break;
891  }
892  } catch (cfile::max_read_length &msg) {
893  // read to max section size, move to next section, discarding
894  // extra/unknown data
895  mprintf(("PLR => (0x%04x) %s\n", section_id, msg.what()));
896  } catch (const char *err) {
897  mprintf(("PLR => ERROR: %s\n", err));
898  plr_close();
899  return false;
900  }
901 
902  // reset safety catch
903  cf_set_max_read_len(cfp, 0);
904 
905  // skip to next section (if not already there)
906  size_t offset_pos = (start_pos + section_size) - cftell(cfp);
907 
908  if (offset_pos) {
909  cfseek(cfp, offset_pos, CF_SEEK_CUR);
910  mprintf(("PLR => WARNING: Advancing to the next section. " SIZE_T_ARG " bytes were skipped!\n", offset_pos));
911  }
912  }
913 
914  // restore the callsign into the Player structure
915  strcpy_s(p->callsign, callsign);
916 
917  // restore the truncated callsign into Player structure
919 
920  player_set_squad_bitmap(p, p->m_squad_filename, true);
921 
923 
924  // set last pilot
925  os_config_write_string(NULL, "LastPlayer", (char*)callsign);
926 
927  mprintf(("PLR => Loading complete!\n"));
928 
929  // cleanup and return
930  plr_close();
931 
932  return true;
933 }
934 
936 {
937  // never save a pilot file for the standalone server in multiplayer
938  if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER) ) {
939  return false;
940  }
941 
942  // set player ptr first thing
943  p = _p;
944 
945  if ( !p ) {
946  Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) );
947  p = &Players[Player_num];
948  }
949 
950  if ( !strlen(p->callsign) ) {
951  return false;
952  }
953 
954  filename = p->callsign;
955  filename += ".plr";
956 
957  if ( filename.size() == 4 ) {
958  mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str()));
959  return false;
960  }
961 
962  // open it, hopefully...
963  cfp = cfopen((char*)filename.c_str(), "wb", CFILE_NORMAL, CF_TYPE_PLAYERS);
964 
965  if ( !cfp ) {
966  mprintf(("PLR => Unable to open '%s' for saving!\n", filename.c_str()));
967  return false;
968  }
969 
970  // header and version
971  cfwrite_int(PLR_FILE_ID, cfp);
972  cfwrite_ubyte(PLR_VERSION, cfp);
973 
974  mprintf(("PLR => Saving '%s' with version %d...\n", filename.c_str(), (int)PLR_VERSION));
975 
976  // flags and info sections go first
977  mprintf(("PLR => Saving: Flags...\n"));
978  plr_write_flags();
979  mprintf(("PLR => Saving: Info...\n"));
980  plr_write_info();
981 
982  // everything else is next, not order specific
983  mprintf(("PLR => Saving: Scoring...\n"));
984  plr_write_stats();
985  mprintf(("PLR => Saving: ScoringMulti...\n"));
986  plr_write_stats_multi();
987  mprintf(("PLR => Saving: HUD...\n"));
988  plr_write_hud();
989  mprintf(("PLR => Saving: Variables...\n"));
990  plr_write_variables();
991  mprintf(("PLR => Saving: Multiplayer...\n"));
992  plr_write_multiplayer();
993  mprintf(("PLR => Saving: Controls...\n"));
994  plr_write_controls();
995  mprintf(("PLR => Saving: Settings...\n"));
996  plr_write_settings();
997 
998  // Done!
999  mprintf(("PLR => Saving complete!\n"));
1000 
1001  plr_close();
1002 
1003  return true;
1004 }
1005 
1006 bool pilotfile::verify(const char *fname, int *rank, char *valid_language)
1007 {
1008  player t_plr;
1009 
1010  // set player ptr first thing
1011  p = &t_plr;
1012 
1013  filename = fname;
1014 
1015  if ( filename.size() == 4 ) {
1016  mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str()));
1017  return false;
1018  }
1019 
1020  cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS);
1021 
1022  if ( !cfp ) {
1023  mprintf(("PLR => Unable to open '%s'!\n", filename.c_str()));
1024  return false;
1025  }
1026 
1027  unsigned int plr_id = cfread_uint(cfp);
1028 
1029  if (plr_id != PLR_FILE_ID) {
1030  mprintf(("PLR => Invalid header id for '%s'!\n", filename.c_str()));
1031  plr_close();
1032  return false;
1033  }
1034 
1035  // version, now used
1036  version = cfread_ubyte(cfp);
1037 
1038  mprintf(("PLR => Verifying '%s' with version %d...\n", filename.c_str(), (int)version));
1039 
1040  // the point of all this: read in the PLR contents
1041  while ( !(m_have_flags && m_have_info) && !cfeof(cfp) ) {
1042  ushort section_id = cfread_ushort(cfp);
1043  uint section_size = cfread_uint(cfp);
1044 
1045  size_t start_pos = cftell(cfp);
1046 
1047  // safety, to help protect against long reads
1048  cf_set_max_read_len(cfp, section_size);
1049 
1050  try {
1051  switch (section_id) {
1052  case Section::Flags:
1053  mprintf(("PLR => Parsing: Flags...\n"));
1054  m_have_flags = true;
1055  plr_read_flags();
1056  break;
1057 
1058  // now reading the Info section to get the campaign
1059  // and be able to lookup the campaign rank
1060  case Section::Info:
1061  mprintf(("PLR => Parsing: Info...\n"));
1062  m_have_info = true;
1063  plr_read_info();
1064  break;
1065 
1066  default:
1067  break;
1068  }
1069  } catch (cfile::max_read_length &msg) {
1070  // read to max section size, move to next section, discarding
1071  // extra/unknown data
1072  mprintf(("PLR => (0x%04x) %s\n", section_id, msg.what()));
1073  } catch (const char *err) {
1074  mprintf(("PLR => ERROR: %s\n", err));
1075  plr_close();
1076  return false;
1077  }
1078 
1079  // reset safety catch
1080  cf_set_max_read_len(cfp, 0);
1081 
1082  // skip to next section (if not already there)
1083  size_t offset_pos = (start_pos + section_size) - cftell(cfp);
1084 
1085  if (offset_pos) {
1086  mprintf(("PLR => Warning: (0x%04x) Short read, information may have been lost!\n", section_id));
1087  cfseek(cfp, offset_pos, CF_SEEK_CUR);
1088  }
1089  }
1090 
1091  if (valid_language) {
1092  strncpy(valid_language, p->language, sizeof(p->language));
1093  }
1094 
1095  // need to cleanup early to ensure everything is OK for use in the CSG next
1096  // also means we can't use *p from now on, use t_plr instead for a few vars
1097  plr_close();
1098 
1099  if (rank) {
1100  // maybe get the rank from the CSG
1101  if ( !(Game_mode & GM_MULTIPLAYER) ) {
1102  // build the csg filename
1103  // since filename/fname was validated above, perform less safety checks here
1104  filename = fname;
1105  filename = filename.replace(filename.find_last_of('.')+1,filename.npos, t_plr.current_campaign);
1106  filename.append(".csg");
1107 
1108  if (!this->get_csg_rank(rank)) {
1109  // if we failed to get the csg rank, default to multi rank
1110  *rank = t_plr.stats.rank;
1111  }
1112  } else {
1113  // if the CSG isn't valid, or for multi, use this rank
1114  *rank = t_plr.stats.rank;
1115  }
1116  }
1117 
1118  mprintf(("PLR => Verifying complete!\n"));
1119 
1120  return true;
1121 }
#define __UNUSED
Definition: clang.h:23
int Joy_sensitivity
Definition: joy-unix.cpp:29
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
int targetview_model
Definition: systemvars.h:177
int cfwrite_ushort(ushort s, CFILE *file)
Definition: cfile.cpp:1328
int ship_info_lookup(const char *token)
Definition: ship.cpp:12772
#define CFILE_NORMAL
Definition: cfile.h:89
#define NET_TCP
Definition: psnet2.h:29
int Briefing_voice_enabled
void audiostream_set_volume_all(float volume, int type)
Definition: audiostr.cpp:1857
int HUD_color_alpha
Definition: hud.cpp:76
SCP_string name
#define HUD_COLOR_ALPHA_DEFAULT
Definition: hud.h:74
void player_set_squad_bitmap(player *p, char *fname, bool ismulti)
char text[TOKEN_LENGTH]
Definition: sexp.h:1044
void cf_set_max_read_len(CFILE *cfile, size_t len)
Definition: cfile.cpp:1133
int Game_mode
Definition: systemvars.cpp:24
int Mouse_sensitivity
Definition: mouse.cpp:50
short key_id
actual key bound to action
int detail_distance
Definition: systemvars.h:168
#define CF_TYPE_PLAYERS
Definition: cfile.h:67
#define ASF_EVENTMUSIC
Definition: audiostr.h:19
#define ASF_VOICE
Definition: audiostr.h:21
int medals_info_lookup(const char *name)
Definition: medals.cpp:858
int cfwrite_ubyte(ubyte b, CFILE *file)
Definition: cfile.cpp:1334
int Dead_zone_size
Definition: joy-unix.cpp:27
int cfwrite_uint(uint i, CFILE *file)
Definition: cfile.cpp:1316
int insignia_texture
Definition: player.h:195
Assert(pm!=NULL)
virtual const char * what() const
Definition: cfile.h:372
#define mprintf(args)
Definition: pstypes.h:238
void tech_reset_to_default()
Definition: techmenu.cpp:1438
int shield_effects
Definition: systemvars.h:173
GLclampf f
Definition: Glext.h:7097
#define SIZE_T_ARG
Definition: clang.h:61
long _fs_time_t
Definition: pstypes.h:55
color clr[NUM_HUD_GAUGES]
Definition: hudconfig.h:60
#define CF_SEEK_CUR
Definition: cfile.h:25
ubyte blue
Definition: 2d.h:102
bool verify(const char *fname, int *rank=NULL, char *valid_language=NULL)
Definition: plr.cpp:1006
char callsign[CALLSIGN_LEN+1]
Definition: player.h:91
short joy_id
joystick button bound to action
config_item Control_config[]
Stores the keyboard configuration.
ubyte green
Definition: 2d.h:101
player Players[MAX_PLAYERS]
void os_config_write_string(const char *section, const char *name, const char *value)
Definition: osregistry.cpp:221
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
Definition: player.h:85
unsigned int uint
Definition: pstypes.h:64
#define HUD_COLOR_ALPHA_USER_MIN
Definition: hud.h:71
#define cfopen(...)
Definition: cfile.h:134
#define GM_MULTIPLAYER
Definition: systemvars.h:18
float Master_sound_volume
Definition: sound.cpp:53
char current_campaign[MAX_FILENAME_LEN+1]
Definition: player.h:101
detail_levels Detail
Definition: systemvars.cpp:478
int cfwrite_float(float f, CFILE *file)
Definition: cfile.cpp:1304
GLclampf GLclampf blue
Definition: Glext.h:5177
ubyte red
Definition: 2d.h:100
int cfwrite_string_len(const char *buf, CFILE *file)
Write a fixed length string (not including its null terminator), with the length stored in file...
Definition: cfile.cpp:1378
#define NUM_HUD_GAUGES
Definition: hudgauges.h:16
int hardware_textures
Definition: systemvars.h:169
void pilot_set_short_callsign(player *p, int max_width)
int Use_mouse_to_fly
Definition: mouse.cpp:51
#define MAX_PLAYERS
Definition: pstypes.h:32
short cfread_short(CFILE *file, int ver, short deflt)
Definition: cfile.cpp:1192
bool save_player(player *_p=NULL)
Definition: plr.cpp:935
int idx
Definition: multiui.cpp:761
GLclampf green
Definition: Glext.h:5177
int cfwrite_int(int i, CFILE *file)
Definition: cfile.cpp:1310
int type
Definition: sexp.h:1043
ubyte alpha
Definition: 2d.h:103
long fix
Definition: pstypes.h:54
unsigned char ubyte
Definition: pstypes.h:62
int cfeof(CFILE *cfile)
#define NOX(s)
Definition: pstypes.h:473
#define GM_STANDALONE_SERVER
Definition: systemvars.h:27
ubyte cfread_ubyte(CFILE *file, int ver, ubyte deflt)
Definition: cfile.cpp:1220
#define TOKEN_LENGTH
Definition: globals.h:41
int Invert_axis[]
int cftell(CFILE *fp)
ubyte num_msg_window_lines
Definition: hudconfig.h:57
void control_config_clear()
#define NAME_LENGTH
Definition: globals.h:15
bool load_player(const char *callsign, player *_p=NULL)
Definition: plr.cpp:779
player * Player
void hud_squadmsg_save_keys(int do_scroll)
int cfwrite_short(short s, CFILE *file)
Definition: cfile.cpp:1322
unsigned short ushort
Definition: pstypes.h:63
GLfloat GLfloat p
Definition: Glext.h:8373
HUD_CONFIG_TYPE HUD_config
Definition: hudconfig.cpp:49
float Master_event_music_volume
Definition: eventmusic.cpp:40
The total number of defined control actions (or last define + 1)
int Game_skill_level
Definition: fredstubs.cpp:170
ushort cfread_ushort(CFILE *file, int ver, ushort deflt)
Definition: cfile.cpp:1206
int cfread_int(CFILE *file, int ver, int deflt)
Definition: cfile.cpp:1164
float cfread_float(CFILE *file, int ver, float deflt)
Definition: cfile.cpp:1150
void hud_config_set_color(int in_color)
Definition: hudconfig.cpp:1011
char variable_name[TOKEN_LENGTH]
Definition: sexp.h:1045
int num_small_debris
Definition: systemvars.h:170
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
GLclampf GLclampf GLclampf alpha
Definition: Glext.h:5177
int Event_music_enabled
Definition: eventmusic.cpp:237
The total number of actions an axis may map to.
#define SHORT_CALLSIGN_PIXEL_W
Definition: globals.h:32
multi_global_options Multi_options_g
char short_callsign[CALLSIGN_LEN+1]
Definition: player.h:92
float Master_voice_volume
Definition: sound.cpp:54
void lcl_get_language_name(char *lang_name)
Definition: localize.cpp:1121
uint cfread_uint(CFILE *file, int ver, uint deflt)
Definition: cfile.cpp:1178
scoring_struct stats
Definition: player.h:127
void cfread_string_len(char *buf, int n, CFILE *file)
Read a fixed length string that is not null-terminated, with the length stored in file...
Definition: cfile.cpp:1291
int Player_num
#define strcpy_s(...)
Definition: safe_strings.h:67
int Axis_map_to[]
int cfseek(CFILE *fp, int offset, int where)