FS2_Open
Open source remastering of the Freespace 2 engine
csg.cpp
Go to the documentation of this file.
1 
2 #include "cutscene/cutscenes.h"
3 #include "freespace2/freespace.h"
4 #include "gamesnd/eventmusic.h"
5 #include "hud/hudconfig.h"
6 #include "io/joy.h"
7 #include "io/mouse.h"
8 #include "menuui/techmenu.h"
10 #include "mission/missionload.h"
13 #include "pilotfile/pilotfile.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 #define REDALERT_INTERNAL
21 #include "missionui/redalert.h"
22 
23 #include <iostream>
24 #include <sstream>
25 
26 
27 
28 void pilotfile::csg_read_flags()
29 {
30  // tips?
31  p->tips = (int)cfread_ubyte(cfp);
32 
33  // avoid having to read everything to get the rank
34  if (csg_ver >= 5) {
35  p->stats.rank = cfread_int(cfp);
36  }
37 }
38 
39 void pilotfile::csg_write_flags()
40 {
41  startSection(Section::Flags);
42 
43  // tips
44  cfwrite_ubyte((ubyte)p->tips, cfp);
45 
46  // avoid having to read everything to get the rank
47  cfwrite_int(p->stats.rank, cfp);
48 
49  endSection();
50 }
51 
52 void pilotfile::csg_read_info()
53 {
54  char t_string[NAME_LENGTH+1] = { '\0' };
55  index_list_t ilist;
56  int idx, list_size = 0;
57  ubyte allowed = 0;
58 
59  if ( !m_have_flags ) {
60  throw "Info before Flags!";
61  }
62 
63  //
64  // NOTE: lists may contain missing/invalid entries for current data
65  // this is not necessarily fatal
66  //
67 
68  // ship list (NOTE: may contain more than MAX_SHIP_CLASSES)
69  list_size = cfread_int(cfp);
70 
71  for (idx = 0; idx < list_size; idx++) {
72  cfread_string_len(t_string, NAME_LENGTH, cfp);
73 
74  ilist.name = t_string;
75  ilist.index = ship_info_lookup(t_string);
76 
77  ship_list.push_back(ilist);
78  }
79 
80  // weapon list (NOTE: may contain more than MAX_WEAPON_TYPES)
81  list_size = cfread_int(cfp);
82 
83  for (idx = 0; idx < list_size; idx++) {
84  cfread_string_len(t_string, NAME_LENGTH, cfp);
85 
86  ilist.name = t_string;
87  ilist.index = weapon_info_lookup(t_string);
88 
89  weapon_list.push_back(ilist);
90  }
91 
92  // intel list (NOTE: may contain more than MAX_INTEL_ENTRIES)
93  list_size = cfread_int(cfp);
94 
95  for (idx = 0; idx < list_size; idx++) {
96  cfread_string_len(t_string, NAME_LENGTH, cfp);
97 
98  ilist.name = t_string;
99  ilist.index = intel_info_lookup(t_string);
100 
101  intel_list.push_back(ilist);
102  }
103 
104  // medals list (NOTE: may contain more than Num_medals)
105  list_size = cfread_int(cfp);
106 
107  for (idx = 0; idx < list_size; idx++) {
108  cfread_string_len(t_string, NAME_LENGTH, cfp);
109 
110  ilist.name = t_string;
111  ilist.index = medals_info_lookup(t_string);
112 
113  medals_list.push_back(ilist);
114  }
115 
116  // last ship flown (index into ship_list)
117  idx = cfread_int(cfp);
118 
119  // check the idx is within bounds
120  Assertion ((idx < (int)ship_list.size()), "Campaign file contains an incorrect value for the last flown ship class. No data in ship_list for ship number %d.", idx);
121  if (idx >= (int)ship_list.size())
122  idx = -1;
123  else if (idx != -1)
124  p->last_ship_flown_si_index = ship_list[idx].index;
125  else
126  p->last_ship_flown_si_index = -1;
127 
128  // progression state
131 
132  // loop state
135 
136  // missions completed
138 
139  // allowed ships
140  list_size = (int)ship_list.size();
141  for (idx = 0; idx < list_size; idx++) {
142  allowed = cfread_ubyte(cfp);
143 
144  if (allowed) {
145  if (ship_list[idx].index >= 0) {
146  Campaign.ships_allowed[ship_list[idx].index] = 1;
147  } else {
148  m_data_invalid = true;
149  }
150  }
151  }
152 
153  // allowed weapons
154  list_size = (int)weapon_list.size();
155  for (idx = 0; idx < list_size; idx++) {
156  allowed = cfread_ubyte(cfp);
157 
158  if (allowed) {
159  if (weapon_list[idx].index >= 0) {
160  Campaign.weapons_allowed[weapon_list[idx].index] = 1;
161  } else {
162  m_data_invalid = true;
163  }
164  }
165  }
166 
167  if (csg_ver >= 2) {
168  // single/campaign squad name & image
169  cfread_string_len(p->s_squad_name, NAME_LENGTH, cfp);
170  cfread_string_len(p->s_squad_filename, MAX_FILENAME_LEN, cfp);
171  }
172 
173  // if anything we need/use was missing then it should be considered fatal
174  if (m_data_invalid) {
175  throw "Invalid data for CSG!";
176  }
177 }
178 
179 void pilotfile::csg_write_info()
180 {
181  int idx;
182 
183  startSection(Section::Info);
184 
185  // ship list
186  cfwrite_int(static_cast<int>(Ship_info.size()), cfp);
187 
188  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
189  cfwrite_string_len(it->name, cfp);
190  }
191 
192  // weapon list
194 
195  for (idx = 0; idx < Num_weapon_types; idx++) {
197  }
198 
199  // intel list
201 
202  for (idx = 0; idx < Intel_info_size; idx++) {
204  }
205 
206  // medals list
207  cfwrite_int(Num_medals, cfp);
208 
209  for (idx = 0; idx < Num_medals; idx++) {
210  cfwrite_string_len(Medals[idx].name, cfp);
211  }
212 
213  // last ship flown
214  cfwrite_int(p->last_ship_flown_si_index, cfp);
215 
216  // progression state
219 
220  // loop state
223 
224  // missions completed
226 
227  // allowed ships
228  for (idx = 0; idx < static_cast<int>(Ship_info.size()); idx++) {
230  }
231 
232  // allowed weapons
233  for (idx = 0; idx < Num_weapon_types; idx++) {
235  }
236 
237  // single/campaign squad name & image
238  cfwrite_string_len(p->s_squad_name, cfp);
239  cfwrite_string_len(p->s_squad_filename, cfp);
240 
241  endSection();
242 }
243 
244 void pilotfile::csg_read_missions()
245 {
246  int i, j, idx, list_size;
247  cmission *missionp;
248 
249  if ( !m_have_info ) {
250  throw "Missions before Info!";
251  }
252 
253  for (i = 0; i < Campaign.num_missions_completed; i++) {
254  idx = cfread_int(cfp);
255  missionp = &Campaign.missions[idx];
256 
257  missionp->completed = 1;
258 
259  // flags
260  missionp->flags = cfread_int(cfp);
261 
262  // goals
263  missionp->num_goals = cfread_int(cfp);
264 
265  if (missionp->num_goals > 0) {
266  missionp->goals = (mgoal *) vm_malloc( missionp->num_goals * sizeof(mgoal) );
267  Verify( missionp->goals != NULL );
268 
269  memset( missionp->goals, 0, missionp->num_goals * sizeof(mgoal) );
270 
271  for (j = 0; j < missionp->num_goals; j++) {
272  cfread_string_len(missionp->goals[j].name, NAME_LENGTH, cfp);
273  missionp->goals[j].status = cfread_char(cfp);
274  }
275  }
276 
277  // events
278  missionp->num_events = cfread_int(cfp);
279 
280  if (missionp->num_events > 0) {
281  missionp->events = (mevent *) vm_malloc( missionp->num_events * sizeof(mevent) );
282  Verify( missionp->events != NULL );
283 
284  memset( missionp->events, 0, missionp->num_events * sizeof(mevent) );
285 
286  for (j = 0; j < missionp->num_events; j++) {
287  cfread_string_len(missionp->events[j].name, NAME_LENGTH, cfp);
288  missionp->events[j].status = cfread_char(cfp);
289  }
290  }
291 
292  // variables
293  missionp->num_variables = cfread_int(cfp);
294 
295  if (missionp->num_variables > 0) {
296  missionp->variables = (sexp_variable *) vm_malloc( missionp->num_variables * sizeof(sexp_variable) );
297  Verify( missionp->variables != NULL );
298 
299  memset( missionp->variables, 0, missionp->num_variables * sizeof(sexp_variable) );
300 
301  for (j = 0; j < missionp->num_variables; j++) {
302  missionp->variables[j].type = cfread_int(cfp);
303  cfread_string_len(missionp->variables[j].text, TOKEN_LENGTH, cfp);
305  }
306  }
307 
308  // scoring stats
309  missionp->stats.score = cfread_int(cfp);
310  missionp->stats.rank = cfread_int(cfp);
311  missionp->stats.assists = cfread_int(cfp);
312  missionp->stats.kill_count = cfread_int(cfp);
313  missionp->stats.kill_count_ok = cfread_int(cfp);
314  missionp->stats.bonehead_kills = cfread_int(cfp);
315 
316  missionp->stats.p_shots_fired = cfread_uint(cfp);
317  missionp->stats.p_shots_hit = cfread_uint(cfp);
318  missionp->stats.p_bonehead_hits = cfread_uint(cfp);
319 
320  missionp->stats.s_shots_fired = cfread_uint(cfp);
321  missionp->stats.s_shots_hit = cfread_uint(cfp);
322  missionp->stats.s_bonehead_hits = cfread_uint(cfp);
323 
324  // ship kills (scoring)
325  list_size = (int)ship_list.size();
326  for (j = 0; j < list_size; j++) {
327  idx = cfread_int(cfp);
328 
329  if (ship_list[j].index >= 0) {
330  missionp->stats.kills[ship_list[j].index] = idx;
331  }
332  }
333 
334  // medals (scoring)
335  list_size = (int)medals_list.size();
336  for (j = 0; j < list_size; j++) {
337  idx = cfread_int(cfp);
338 
339  if (medals_list[j].index >= 0) {
340  missionp->stats.medal_counts[medals_list[j].index] = idx;
341  }
342  }
343  }
344 }
345 
346 void pilotfile::csg_write_missions()
347 {
348  int idx, j;
349  cmission *missionp;
350 
351  startSection(Section::Missions);
352 
353  for (idx = 0; idx < MAX_CAMPAIGN_MISSIONS; idx++) {
354  if (Campaign.missions[idx].completed) {
355  missionp = &Campaign.missions[idx];
356 
357  cfwrite_int(idx, cfp);
358 
359  // flags
360  cfwrite_int(missionp->flags, cfp);
361 
362  // goals
363  cfwrite_int(missionp->num_goals, cfp);
364 
365  for (j = 0; j < missionp->num_goals; j++) {
366  cfwrite_string_len(missionp->goals[j].name, cfp);
367  cfwrite_char(missionp->goals[j].status, cfp);
368  }
369 
370  // events
371  cfwrite_int(missionp->num_events, cfp);
372 
373  for (j = 0; j < missionp->num_events; j++) {
374  cfwrite_string_len(missionp->events[j].name, cfp);
375  cfwrite_char(missionp->events[j].status, cfp);
376  }
377 
378  // variables
379  cfwrite_int(missionp->num_variables, cfp);
380 
381  for (j = 0; j < missionp->num_variables; j++) {
382  cfwrite_int(missionp->variables[j].type, cfp);
383  cfwrite_string_len(missionp->variables[j].text, cfp);
384  cfwrite_string_len(missionp->variables[j].variable_name, cfp);
385  }
386 
387  // scoring stats
388  cfwrite_int(missionp->stats.score, cfp);
389  cfwrite_int(missionp->stats.rank, cfp);
390  cfwrite_int(missionp->stats.assists, cfp);
391  cfwrite_int(missionp->stats.kill_count, cfp);
392  cfwrite_int(missionp->stats.kill_count_ok, cfp);
393  cfwrite_int(missionp->stats.bonehead_kills, cfp);
394 
395  cfwrite_uint(missionp->stats.p_shots_fired, cfp);
396  cfwrite_uint(missionp->stats.p_shots_hit, cfp);
397  cfwrite_uint(missionp->stats.p_bonehead_hits, cfp);
398 
399  cfwrite_uint(missionp->stats.s_shots_fired, cfp);
400  cfwrite_uint(missionp->stats.s_shots_hit, cfp);
401  cfwrite_uint(missionp->stats.s_bonehead_hits, cfp);
402 
403  // ship kills (scoring)
404  for (j = 0; j < static_cast<int>(Ship_info.size()); j++) {
405  cfwrite_int(missionp->stats.kills[j], cfp);
406  }
407 
408  // medals earned (scoring)
409  for (j = 0; j < Num_medals; j++) {
410  cfwrite_int(missionp->stats.medal_counts[j], cfp);
411  }
412  }
413  }
414 
415  endSection();
416 }
417 
418 void pilotfile::csg_read_techroom()
419 {
420  int idx, list_size = 0;
421  ubyte visible;
422 
423  if ( !m_have_info ) {
424  throw "Techroom before Info!";
425  }
426 
427  // visible ships
428  list_size = (int)ship_list.size();
429  for (idx = 0; idx < list_size; idx++) {
430  visible = cfread_ubyte(cfp);
431 
432  if (visible) {
433  if (ship_list[idx].index >= 0) {
434  Ship_info[ship_list[idx].index].flags |= SIF_IN_TECH_DATABASE;
435  } else {
436  m_data_invalid = true;
437  }
438  }
439  }
440 
441  // visible weapons
442  list_size = (int)weapon_list.size();
443  for (idx = 0; idx < list_size; idx++) {
444  visible = cfread_ubyte(cfp);
445 
446  if (visible) {
447  if (weapon_list[idx].index >= 0) {
448  Weapon_info[weapon_list[idx].index].wi_flags |= WIF_IN_TECH_DATABASE;
449  } else {
450  m_data_invalid = true;
451  }
452  }
453  }
454 
455  // visible intel entries
456  list_size = (int)intel_list.size();
457  for (idx = 0; idx < list_size; idx++) {
458  visible = cfread_ubyte(cfp);
459 
460  if (visible) {
461  if (intel_list[idx].index >= 0) {
462  Intel_info[intel_list[idx].index].flags |= IIF_IN_TECH_DATABASE;
463  } else {
464  m_data_invalid = true;
465  }
466  }
467  }
468 
469  // if anything we need/use was missing then it should be considered fatal
470  if (m_data_invalid) {
471  throw "Invalid data for CSG!";
472  }
473 }
474 
475 void pilotfile::csg_write_techroom()
476 {
477  int idx;
478  ubyte visible;
479 
480  startSection(Section::Techroom);
481 
482  // visible ships
483  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
484  // only visible if not in techroom by default
485  if ( (it->flags & SIF_IN_TECH_DATABASE) && !(it->flags2 & SIF2_DEFAULT_IN_TECH_DATABASE) ) {
486  visible = 1;
487  } else {
488  visible = 0;
489  }
490 
491  cfwrite_ubyte(visible, cfp);
492  }
493 
494  // visible weapons
495  for (idx = 0; idx < Num_weapon_types; idx++) {
496  // only visible if not in techroom by default
497  if ( (Weapon_info[idx].wi_flags & WIF_IN_TECH_DATABASE) && !(Weapon_info[idx].wi_flags2 & WIF2_DEFAULT_IN_TECH_DATABASE) ) {
498  visible = 1;
499  } else {
500  visible = 0;
501  }
502 
503  cfwrite_ubyte(visible, cfp);
504  }
505 
506  // visible intel entries
507  for (idx = 0; idx < Intel_info_size; idx++) {
508  // only visible if not in techroom by default
510  visible = 1;
511  } else {
512  visible = 0;
513  }
514 
515  cfwrite_ubyte(visible, cfp);
516  }
517 
518  endSection();
519 }
520 
521 void pilotfile::csg_read_loadout()
522 {
523  int j, count, ship_idx = -1, wep_idx = -1;
524  uint idx, list_size = 0;
525 
526  if ( !m_have_info ) {
527  throw "Loadout before Info!";
528  }
529 
530  // base info
533 
534  // ship pool
535  list_size = ship_list.size();
536  for (idx = 0; idx < list_size; idx++) {
537  count = cfread_int(cfp);
538 
539  if (ship_list[idx].index >= 0) {
540  Player_loadout.ship_pool[ship_list[idx].index] = count;
541  }
542  }
543 
544  // weapon pool
545  list_size = weapon_list.size();
546  for (idx = 0; idx < list_size; idx++) {
547  count = cfread_int(cfp);
548 
549  if (weapon_list[idx].index >= 0) {
550  Player_loadout.weapon_pool[weapon_list[idx].index] = count;
551  }
552  }
553 
554  // player ship loadout
555  list_size = (uint)cfread_ushort(cfp);
556  for (uint i = 0; i < list_size; i++) {
557  wss_unit *slot = NULL;
558 
559  if (i < MAX_WSS_SLOTS) {
560  slot = &Player_loadout.unit_data[i];
561  }
562 
563  // ship
564  ship_idx = cfread_int(cfp);
565 
566  if ( (ship_idx >= (int)ship_list.size()) || (ship_idx < -1) ) { // on the casts, assume that ship & weapon lists will never exceed ~2 billion
567  mprintf(("CSG => Parse Warning: Invalid value for ship index (%d), emptying slot.\n", ship_idx));
568  ship_idx = -1;
569  }
570 
571  if (slot) {
572  if (ship_idx == -1) { // -1 means no ship in this slot
573  slot->ship_class = -1;
574  } else {
575  slot->ship_class = ship_list[ship_idx].index;
576  }
577  }
578 
579  // primary weapons
580  count = cfread_int(cfp);
581 
582  for (j = 0; j < count; j++) {
583  wep_idx = cfread_int(cfp);
584 
585  if ( (wep_idx >= (int)weapon_list.size()) || (wep_idx < -1) ) {
586  mprintf(("CSG => Parse Warning: Invalid value for primary weapon index (%d), emptying slot.\n", wep_idx));
587  wep_idx = -1;
588  }
589 
590 
591  if ( slot && (j < MAX_SHIP_PRIMARY_BANKS) ) {
592  if (wep_idx == -1) { // -1 means no weapon in this slot
593  slot->wep[j] = -1;
594  } else {
595  slot->wep[j] = weapon_list[wep_idx].index;
596  }
597  }
598 
599  idx = cfread_int(cfp);
600 
601  if ( slot && (j < MAX_SHIP_PRIMARY_BANKS) ) {
602  slot->wep_count[j] = idx;
603  }
604  }
605 
606  // secondary weapons
607  count = cfread_int(cfp);
608 
609  for (j = 0; j < count; j++) {
610  wep_idx = cfread_int(cfp);
611 
612  if ( (wep_idx >= (int)weapon_list.size()) || (wep_idx < -1) ) {
613  mprintf(("CSG => Parse Warning: Invalid value for secondary weapon index (%d), emptying slot.\n", wep_idx));
614  wep_idx = -1;
615  }
616 
617  if ( slot && (j < MAX_SHIP_SECONDARY_BANKS) ) {
618  if (wep_idx == -1) { // -1 means no weapon in this slot
619  slot->wep[j+MAX_SHIP_PRIMARY_BANKS] = -1;
620  } else {
621  slot->wep[j+MAX_SHIP_PRIMARY_BANKS] = weapon_list[wep_idx].index;
622  }
623  }
624 
625  idx = cfread_int(cfp);
626 
627  if ( slot && (j < MAX_SHIP_SECONDARY_BANKS) ) {
629  }
630  }
631  }
632 }
633 
634 void pilotfile::csg_write_loadout()
635 {
636  int idx, j;
637 
638  startSection(Section::Loadout);
639 
640  // base info
643 
644  // ship pool
645  for (idx = 0; idx < static_cast<int>(Ship_info.size()); idx++) {
647  }
648 
649  // weapon pool
650  for (idx = 0; idx < Num_weapon_types; idx++) {
652  }
653 
654  // play ship loadout
656 
657  for (idx = 0; idx < MAX_WSS_SLOTS; idx++) {
659 
660  // ship
661  cfwrite_int(slot->ship_class, cfp);
662 
663  // primary weapons
665 
666  for (j = 0; j < MAX_SHIP_PRIMARY_BANKS; j++) {
667  cfwrite_int(slot->wep[j], cfp);
668  cfwrite_int(slot->wep_count[j], cfp);
669  }
670 
671  // secondary weapons
673 
674  for (j = 0; j < MAX_SHIP_SECONDARY_BANKS; j++) {
675  cfwrite_int(slot->wep[j+MAX_SHIP_PRIMARY_BANKS], cfp);
676  cfwrite_int(slot->wep_count[j+MAX_SHIP_PRIMARY_BANKS], cfp);
677  }
678  }
679 
680  endSection();
681 }
682 
683 void pilotfile::csg_read_stats()
684 {
685  int idx, list_size = 0;
686  int count;
687 
688  if ( !m_have_info ) {
689  throw "Stats before Info!";
690  }
691 
692  // scoring stats
693  p->stats.score = cfread_int(cfp);
694  p->stats.rank = cfread_int(cfp);
695  p->stats.assists = cfread_int(cfp);
696  p->stats.kill_count = cfread_int(cfp);
697  p->stats.kill_count_ok = cfread_int(cfp);
698  p->stats.bonehead_kills = cfread_int(cfp);
699 
700  p->stats.p_shots_fired = cfread_uint(cfp);
701  p->stats.p_shots_hit = cfread_uint(cfp);
702  p->stats.p_bonehead_hits = cfread_uint(cfp);
703 
704  p->stats.s_shots_fired = cfread_uint(cfp);
705  p->stats.s_shots_hit = cfread_uint(cfp);
706  p->stats.s_bonehead_hits = cfread_uint(cfp);
707 
708  p->stats.flight_time = cfread_uint(cfp);
709  p->stats.missions_flown = cfread_uint(cfp);
710  p->stats.last_flown = (_fs_time_t)cfread_int(cfp);
711  p->stats.last_backup = (_fs_time_t)cfread_int(cfp);
712 
713  // ship kills (scoring)
714  list_size = (int)ship_list.size();
715  for (idx = 0; idx < list_size; idx++) {
716  count = cfread_int(cfp);
717 
718  if (ship_list[idx].index >= 0) {
719  p->stats.kills[ship_list[idx].index] = count;
720  }
721  }
722 
723  // medals earned (scoring)
724  list_size = (int)medals_list.size();
725  for (idx = 0; idx < list_size; idx++) {
726  count = cfread_int(cfp);
727 
728  if (medals_list[idx].index >= 0) {
729  p->stats.medal_counts[medals_list[idx].index] = count;
730  }
731  }
732 }
733 
734 void pilotfile::csg_write_stats()
735 {
736  int idx;
737 
738  startSection(Section::Scoring);
739 
740  // scoring stats
741  cfwrite_int(p->stats.score, cfp);
742  cfwrite_int(p->stats.rank, cfp);
743  cfwrite_int(p->stats.assists, cfp);
744  cfwrite_int(p->stats.kill_count, cfp);
745  cfwrite_int(p->stats.kill_count_ok, cfp);
746  cfwrite_int(p->stats.bonehead_kills, cfp);
747 
748  cfwrite_uint(p->stats.p_shots_fired, cfp);
749  cfwrite_uint(p->stats.p_shots_hit, cfp);
750  cfwrite_uint(p->stats.p_bonehead_hits, cfp);
751 
752  cfwrite_uint(p->stats.s_shots_fired, cfp);
753  cfwrite_uint(p->stats.s_shots_hit, cfp);
754  cfwrite_uint(p->stats.s_bonehead_hits, cfp);
755 
756  cfwrite_uint(p->stats.flight_time, cfp);
757  cfwrite_uint(p->stats.missions_flown, cfp);
758  cfwrite_int((int)p->stats.last_flown, cfp);
759  cfwrite_int((int)p->stats.last_backup, cfp);
760 
761  // ship kills (scoring)
762  for (idx = 0; idx < static_cast<int>(Ship_info.size()); idx++) {
763  cfwrite_int(p->stats.kills[idx], cfp);
764  }
765 
766  // medals earned (scoring)
767  for (idx = 0; idx < Num_medals; idx++) {
768  cfwrite_int(p->stats.medal_counts[idx], cfp);
769  }
770 
771  endSection();
772 }
773 
774 void pilotfile::csg_read_redalert()
775 {
776  int idx, i, j, list_size = 0;
777  int count;
778  char t_string[MAX_FILENAME_LEN+NAME_LENGTH+1] = { '\0' };
779  float hit;
780  wep_t weapons;
781 
782  if ( !m_have_info ) {
783  throw "RedAlert before Info!";
784  }
785 
786  list_size = cfread_int(cfp);
787 
788  if (list_size <= 0) {
789  return;
790  }
791 
792  cfread_string_len(t_string, MAX_FILENAME_LEN, cfp);
793 
794  Red_alert_precursor_mission = t_string;
795 
796  for (idx = 0; idx < list_size; idx++) {
797  red_alert_ship_status ras;
798 
799  cfread_string_len(t_string, NAME_LENGTH, cfp);
800  ras.name = t_string;
801 
802  ras.hull = cfread_float(cfp);
803 
804  // ship class, index into ship_list[]
805  i = cfread_int(cfp);
806  if ( (i >= (int)ship_list.size()) || (i < RED_ALERT_LOWEST_VALID_SHIP_CLASS) ) {
807  mprintf(("CSG => Parse Warning: Invalid value for red alert ship index (%d), emptying slot.\n", i));
808  ras.ship_class = RED_ALERT_DESTROYED_SHIP_CLASS;
809  } else if ( (i < 0 ) && (i >= RED_ALERT_LOWEST_VALID_SHIP_CLASS) ) { // ship destroyed/exited
810  ras.ship_class = i;
811  } else {
812  ras.ship_class = ship_list[i].index;
813  }
814 
815  // subsystem hits
816  count = cfread_int(cfp);
817 
818  for (j = 0; j < count; j++) {
819  hit = cfread_float(cfp);
820  ras.subsys_current_hits.push_back( hit );
821  }
822 
823  // subsystem aggregate hits
824  count = cfread_int(cfp);
825 
826  for (j = 0; j < count; j++) {
827  hit = cfread_float(cfp);
828  ras.subsys_aggregate_current_hits.push_back( hit );
829  }
830 
831  // primary weapon loadout and status
832  count = cfread_int(cfp);
833 
834  for (j = 0; j < count; j++) {
835  i = cfread_int(cfp);
836  weapons.index = weapon_list[i].index;
837  weapons.count = cfread_int(cfp);
838 
839  // triggering this means something is really fubar
840  if (weapons.index < 0) {
841  continue;
842  }
843 
844  ras.primary_weapons.push_back( weapons );
845  }
846 
847  // secondary weapon loadout and status
848  count = cfread_int(cfp);
849 
850  for (j = 0; j < count; j++) {
851  i = cfread_int(cfp);
852  weapons.index = weapon_list[i].index;
853  weapons.count = cfread_int(cfp);
854 
855  // triggering this means something is really fubar
856  if (weapons.index < 0) {
857  continue;
858  }
859 
860  ras.secondary_weapons.push_back( weapons );
861  }
862 
863  // this is quite likely a *bad* thing if it doesn't happen
864  if (ras.ship_class >= RED_ALERT_LOWEST_VALID_SHIP_CLASS) {
865  Red_alert_wingman_status.push_back( ras );
866  }
867  }
868 }
869 
870 void pilotfile::csg_write_redalert()
871 {
872  int idx, j, list_size = 0;
873  int count;
874  red_alert_ship_status *ras;
875 
876  startSection(Section::RedAlert);
877 
878  list_size = (int)Red_alert_wingman_status.size();
879 
880  cfwrite_int(list_size, cfp);
881 
882  if (list_size) {
884 
885  for (idx = 0; idx < list_size; idx++) {
887 
888  cfwrite_string_len(ras->name.c_str(), cfp);
889 
890  cfwrite_float(ras->hull, cfp);
891 
892  // ship class, should be index into ship_list[] on load
893  cfwrite_int(ras->ship_class, cfp);
894 
895  // subsystem hits
896  count = (int)ras->subsys_current_hits.size();
897  cfwrite_int(count, cfp);
898 
899  for (j = 0; j < count; j++) {
900  cfwrite_float(ras->subsys_current_hits[j], cfp);
901  }
902 
903  // subsystem aggregate hits
904  count = (int)ras->subsys_aggregate_current_hits.size();
905  cfwrite_int(count, cfp);
906 
907  for (j = 0; j < count; j++) {
908  cfwrite_float(ras->subsys_aggregate_current_hits[j], cfp);
909  }
910 
911  // primary weapon loadout and status
912  count = (int)ras->primary_weapons.size();
913  cfwrite_int(count, cfp);
914 
915  for (j = 0; j < count; j++) {
916  cfwrite_int(ras->primary_weapons[j].index, cfp);
917  cfwrite_int(ras->primary_weapons[j].count, cfp);
918  }
919 
920  // secondary weapon loadout and status
921  count = (int)ras->secondary_weapons.size();
922  cfwrite_int(count, cfp);
923 
924  for (j = 0; j < count; j++) {
925  cfwrite_int(ras->secondary_weapons[j].index, cfp);
926  cfwrite_int(ras->secondary_weapons[j].count, cfp);
927  }
928  }
929  }
930 
931  endSection();
932 }
933 
934 void pilotfile::csg_read_hud()
935 {
936  int idx;
937 
938  // flags
941 
944 
945  // settings
947 
950 
951  // basic colors
954 
957  }
958 
960 
961  // gauge-specific colors
962  int num_gauges = cfread_int(cfp);
963 
964  for (idx = 0; idx < num_gauges; idx++) {
965  ubyte red = cfread_ubyte(cfp);
966  ubyte green = cfread_ubyte(cfp);
967  ubyte blue = cfread_ubyte(cfp);
968  ubyte alpha = cfread_ubyte(cfp);
969 
970  if (idx >= NUM_HUD_GAUGES) {
971  continue;
972  }
973 
974  HUD_config.clr[idx].red = red;
978  }
979 }
980 
981 void pilotfile::csg_write_hud()
982 {
983  int idx;
984 
985  startSection(Section::HUD);
986 
987  // flags
990 
993 
994  // settings
996 
999 
1000  // basic colors
1003 
1004  // gauge-specific colors
1006 
1007  for (idx = 0; idx < NUM_HUD_GAUGES; idx++) {
1008  cfwrite_ubyte(HUD_config.clr[idx].red, cfp);
1009  cfwrite_ubyte(HUD_config.clr[idx].green, cfp);
1010  cfwrite_ubyte(HUD_config.clr[idx].blue, cfp);
1011  cfwrite_ubyte(HUD_config.clr[idx].alpha, cfp);
1012  }
1013 
1014  endSection();
1015 }
1016 
1017 void pilotfile::csg_read_variables()
1018 {
1019  int idx;
1020 
1022 
1023  if (Campaign.num_variables > 0) {
1025  Verify( Campaign.variables != NULL );
1026 
1027  memset( Campaign.variables, 0, Campaign.num_variables * sizeof(sexp_variable) );
1028 
1029  for (idx = 0; idx < Campaign.num_variables; idx++) {
1033  }
1034  }
1035 
1036  if (csg_ver < 4) { // CSG files before version 4 don't have a Red Alert set of CPVs to load, so just copy the regular set.
1040 
1042  } else {
1044 
1045  if (Campaign.redalert_num_variables > 0) {
1047  Verify( Campaign.redalert_variables != NULL );
1048 
1050 
1051  for (idx = 0; idx < Campaign.redalert_num_variables; idx++) {
1055  }
1056  }
1057  }
1058 }
1059 
1060 void pilotfile::csg_write_variables()
1061 {
1062  int idx;
1063 
1064  startSection(Section::Variables);
1065 
1067 
1068  for (idx = 0; idx < Campaign.num_variables; idx++) {
1069  cfwrite_int(Campaign.variables[idx].type, cfp);
1072  }
1073 
1075 
1076  for (idx = 0; idx < Campaign.redalert_num_variables; idx++) {
1080  }
1081 
1082  endSection();
1083 }
1084 
1085 void pilotfile::csg_read_settings()
1086 {
1087  // sound/voice/music
1091 
1094 
1095  if (Master_event_music_volume > 0.0f) {
1096  Event_music_enabled = 1;
1097  } else {
1098  Event_music_enabled = 0;
1099  }
1100 
1102 
1103  // skill level
1105 
1106  // input options
1109  Joy_sensitivity = cfread_int(cfp);
1110  Dead_zone_size = cfread_int(cfp);
1111 
1112  if (csg_ver < 3) {
1113  // detail
1114  int dummy __UNUSED = cfread_int(cfp);
1115  dummy = cfread_int(cfp);
1116  dummy = cfread_int(cfp);
1117  dummy = cfread_int(cfp);
1118  dummy = cfread_int(cfp);
1119  dummy = cfread_int(cfp);
1120  dummy = cfread_int(cfp);
1121  dummy = cfread_int(cfp);
1122  dummy = cfread_int(cfp);
1123  dummy = cfread_int(cfp);
1124  dummy = cfread_int(cfp);
1125  dummy = cfread_int(cfp);
1126  }
1127 }
1128 
1129 void pilotfile::csg_write_settings()
1130 {
1131  startSection(Section::Settings);
1132 
1133  // sound/voice/music
1137 
1139 
1140  // skill level
1142 
1143  // input options
1148 
1149  endSection();
1150 }
1151 
1152 void pilotfile::csg_read_controls()
1153 {
1154  int idx, list_size;
1155  short id1, id2, id3 __UNUSED;
1156 
1157  list_size = (int)cfread_ushort(cfp);
1158 
1159  for (idx = 0; idx < list_size; idx++) {
1160  id1 = cfread_short(cfp);
1161  id2 = cfread_short(cfp);
1162  id3 = cfread_short(cfp); // unused, at the moment
1163 
1164  if (idx < CCFG_MAX) {
1165  Control_config[idx].key_id = id1;
1166  Control_config[idx].joy_id = id2;
1167  }
1168  }
1169 }
1170 
1171 void pilotfile::csg_write_controls()
1172 {
1173  int idx;
1174 
1175  startSection(Section::Controls);
1176 
1177  cfwrite_ushort(CCFG_MAX, cfp);
1178 
1179  for (idx = 0; idx < CCFG_MAX; idx++) {
1180  cfwrite_short(Control_config[idx].key_id, cfp);
1181  cfwrite_short(Control_config[idx].joy_id, cfp);
1182  // placeholder? for future mouse_id?
1183  cfwrite_short(-1, cfp);
1184  }
1185 
1186  endSection();
1187 }
1188 
1189 void pilotfile::csg_read_cutscenes() {
1190  size_t list_size = cfread_uint(cfp);
1191 
1192  for(size_t i = 0; i < list_size; i++) {
1193  char tempFilename[MAX_FILENAME_LEN];
1194 
1195  cfread_string_len(tempFilename, MAX_FILENAME_LEN, cfp);
1196  cutscene_mark_viewable(tempFilename);
1197  }
1198 }
1199 
1200 void pilotfile::csg_write_cutscenes() {
1202 
1203  startSection(Section::Cutscenes);
1204 
1205  size_t viewableScenes = 0;
1206  for(cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) {
1207  if(cut->viewable)
1208  viewableScenes ++;
1209  }
1210  cfwrite_uint(viewableScenes, cfp);
1211 
1212  for(cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) {
1213  if(cut->viewable)
1214  cfwrite_string_len(cut->filename, cfp);
1215  }
1216 
1217  endSection();
1218 }
1219 
1220 /*
1221  * Only used for quick start missions
1222  */
1223 void pilotfile::csg_read_lastmissions()
1224 {
1225  int i;
1226 
1227  // restore list of most recently played missions
1230  for ( i = 0; i < Num_recent_missions; i++ ) {
1231  char *cp;
1232 
1234  // Remove the extension (safety check: shouldn't exist anyway)
1235  cp = strchr(Recent_missions[i], '.');
1236  if (cp)
1237  *cp = 0;
1238  }
1239 }
1240 
1241 /*
1242  * Only used for quick start missions
1243  */
1244 
1245 void pilotfile::csg_write_lastmissions()
1246 {
1247  int i;
1248 
1249  startSection(Section::LastMissions);
1250 
1251  // store list of most recently played missions
1252  cfwrite_int(Num_recent_missions, cfp);
1253  for (i=0; i<Num_recent_missions; i++) {
1255  }
1256 
1257  endSection();
1258 }
1259 
1260 void pilotfile::csg_reset_data()
1261 {
1262  int idx;
1263  cmission *missionp;
1264 
1265  // internals
1266  m_have_flags = false;
1267  m_have_info = false;
1268 
1269  m_data_invalid = false;
1270 
1271  // init stats
1272  p->stats.init();
1273 
1274  // zero out allowed ships/weapons
1275  memset(Campaign.ships_allowed, 0, sizeof(Campaign.ships_allowed));
1276  memset(Campaign.weapons_allowed, 0, sizeof(Campaign.weapons_allowed));
1277 
1278  // reset campaign status
1279  Campaign.prev_mission = -1;
1280  Campaign.next_mission = -1;
1282 
1283  // techroom reset
1285 
1286  // clear out variables
1287  if (Campaign.variables) {
1288  Campaign.num_variables = 0;
1290  Campaign.variables = NULL;
1291  }
1292 
1297  }
1298 
1299  // clear red alert data
1300  Red_alert_wingman_status.clear();
1301 
1302  // clear out mission stuff
1303  for (idx = 0; idx < MAX_CAMPAIGN_MISSIONS; idx++) {
1304  missionp = &Campaign.missions[idx];
1305 
1306  if (missionp->goals) {
1307  missionp->num_goals = 0;
1308  vm_free(missionp->goals);
1309  missionp->goals = NULL;
1310  }
1311 
1312  if (missionp->events) {
1313  missionp->num_events = 0;
1314  vm_free(missionp->events);
1315  missionp->events = NULL;
1316  }
1317 
1318  if (missionp->variables) {
1319  missionp->num_variables = 0;
1320  vm_free(missionp->variables);
1321  missionp->variables = NULL;
1322  }
1323 
1324  missionp->stats.init();
1325  }
1326 }
1327 
1328 void pilotfile::csg_close()
1329 {
1330  if (cfp) {
1331  cfclose(cfp);
1332  cfp = NULL;
1333  }
1334 
1335  p = NULL;
1336  filename = "";
1337 
1338  ship_list.clear();
1339  weapon_list.clear();
1340  intel_list.clear();
1341  medals_list.clear();
1342 
1343  m_have_flags = false;
1344  m_have_info = false;
1345 }
1346 
1348 {
1349  char base[_MAX_FNAME] = { '\0' };
1350  std::ostringstream buf;
1351 
1352  if (Game_mode & GM_MULTIPLAYER) {
1353  return false;
1354  }
1355 
1356  if ( (campaign == NULL) || !strlen(campaign) ) {
1357  return false;
1358  }
1359 
1360  // set player ptr first thing
1361  Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) );
1362  p = &Players[Player_num];
1363 
1364  // build up filename for the savefile...
1365  _splitpath((char*)campaign, NULL, NULL, base, NULL);
1366 
1367  buf << p->callsign << "." << base << ".csg";
1368 
1369  filename = buf.str().c_str();
1370 
1371  // if campaign file doesn't exist, abort so we don't load irrelevant data
1372  buf.str(std::string());
1373  buf << base << FS_CAMPAIGN_FILE_EXT;
1374  if ( !cf_exists_full((char*)buf.str().c_str(), CF_TYPE_MISSIONS) ) {
1375  mprintf(("CSG => Unable to find campaign file '%s'!\n", buf.str().c_str()));
1376  return false;
1377  }
1378 
1379  // we need to reset this early, in case open fails and we need to create
1380  m_data_invalid = false;
1381 
1382  // open it, hopefully...
1383  cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS);
1384 
1385  if ( !cfp ) {
1386  mprintf(("CSG => Unable to open '%s' for reading!\n", filename.c_str()));
1387  return false;
1388  }
1389 
1390  unsigned int csg_id = cfread_uint(cfp);
1391 
1392  if (csg_id != CSG_FILE_ID) {
1393  mprintf(("CSG => Invalid header id for '%s'!\n", filename.c_str()));
1394  csg_close();
1395  return false;
1396  }
1397 
1398  // version, now used
1399  csg_ver = cfread_ubyte(cfp);
1400 
1401  mprintf(("CSG => Loading '%s' with version %d...\n", filename.c_str(), (int)csg_ver));
1402 
1403  csg_reset_data();
1404 
1405  // the point of all this: read in the CSG contents
1406  while ( !cfeof(cfp) ) {
1407  ushort section_id = cfread_ushort(cfp);
1408  uint section_size = cfread_uint(cfp);
1409 
1410  size_t start_pos = cftell(cfp);
1411 
1412  // safety, to help protect against long reads
1413  cf_set_max_read_len(cfp, section_size);
1414 
1415  try {
1416  switch (section_id) {
1417  case Section::Flags:
1418  mprintf(("CSG => Parsing: Flags...\n"));
1419  m_have_flags = true;
1420  csg_read_flags();
1421  break;
1422 
1423  case Section::Info:
1424  mprintf(("CSG => Parsing: Info...\n"));
1425  m_have_info = true;
1426  csg_read_info();
1427  break;
1428 
1429  case Section::Variables:
1430  mprintf(("CSG => Parsing: Variables...\n"));
1431  csg_read_variables();
1432  break;
1433 
1434  case Section::HUD:
1435  mprintf(("CSG => Parsing: HUD...\n"));
1436  csg_read_hud();
1437  break;
1438 
1439  case Section::RedAlert:
1440  mprintf(("CSG => Parsing: RedAlert...\n"));
1441  csg_read_redalert();
1442  break;
1443 
1444  case Section::Scoring:
1445  mprintf(("CSG => Parsing: Scoring...\n"));
1446  csg_read_stats();
1447  break;
1448 
1449  case Section::Loadout:
1450  mprintf(("CSG => Parsing: Loadout...\n"));
1451  csg_read_loadout();
1452  break;
1453 
1454  case Section::Techroom:
1455  mprintf(("CSG => Parsing: Techroom...\n"));
1456  csg_read_techroom();
1457  break;
1458 
1459  case Section::Missions:
1460  mprintf(("CSG => Parsing: Missions...\n"));
1461  csg_read_missions();
1462  break;
1463 
1464  case Section::Settings:
1465  mprintf(("CSG => Parsing: Settings...\n"));
1466  csg_read_settings();
1467  break;
1468 
1469  case Section::Controls:
1470  mprintf(("CSG => Parsing: Controls...\n"));
1471  csg_read_controls();
1472  break;
1473 
1474  case Section::Cutscenes:
1475  mprintf(("CSG => Parsing: Cutscenes...\n"));
1476  csg_read_cutscenes();
1477  break;
1478 
1479  case Section::LastMissions:
1480  mprintf(("CSG => Parsing: Last Missions...\n"));
1481  csg_read_lastmissions();
1482  break;
1483 
1484  default:
1485  mprintf(("CSG => Skipping unknown section 0x%04x!\n", section_id));
1486  break;
1487  }
1488  } catch (cfile::max_read_length &msg) {
1489  // read to max section size, move to next section, discarding
1490  // extra/unknown data
1491  mprintf(("CSG => Warning: (0x%04x) %s\n", section_id, msg.what()));
1492  } catch (const char *err) {
1493  mprintf(("CSG => ERROR: %s\n", err));
1494  csg_close();
1495  return false;
1496  }
1497 
1498  // reset safety catch
1499  cf_set_max_read_len(cfp, 0);
1500 
1501  // skip to next section (if not already there)
1502  size_t offset_pos = (start_pos + section_size) - cftell(cfp);
1503 
1504  if (offset_pos) {
1505  mprintf(("CSG => Warning: (0x%04x) Short read, information may have been lost!\n", section_id));
1506  cfseek(cfp, offset_pos, CF_SEEK_CUR);
1507  }
1508  }
1509 
1510  // if the campaign (for whatever reason) doesn't have a squad image, use the multi one
1511  if (p->s_squad_filename[0] == '\0') {
1512  strcpy_s(p->s_squad_filename, p->m_squad_filename);
1513  }
1514  player_set_squad_bitmap(p, p->s_squad_filename, false);
1515 
1516  mprintf(("CSG => Loading complete!\n"));
1517 
1518  // cleanup and return
1519  csg_close();
1520 
1521  return true;
1522 }
1523 
1525 {
1526  char base[_MAX_FNAME] = { '\0' };
1527  std::ostringstream buf;
1528 
1529  if (Game_mode & GM_MULTIPLAYER) {
1530  return false;
1531  }
1532 
1533  // set player ptr first thing
1534  Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) );
1535  p = &Players[Player_num];
1536 
1537  if ( !strlen(Campaign.filename) ) {
1538  return false;
1539  }
1540 
1541  // build up filename for the savefile...
1542  _splitpath(Campaign.filename, NULL, NULL, base, NULL);
1543 
1544  buf << p->callsign << "." << base << ".csg";
1545 
1546  filename = buf.str().c_str();
1547 
1548  // make sure that we can actually save this safely
1549  if (m_data_invalid) {
1550  mprintf(("CSG => Skipping save of '%s' due to invalid data check!\n", filename.c_str()));
1551  return false;
1552  }
1553 
1554  // validate the number of red alert entries
1555  // assertion before writing so that we don't corrupt the .csg by asserting halfway through writing
1556  // assertion should also prevent loss of major campaign progress
1557  // i.e. lose one mission, not several missions worth (in theory)
1558  Assertion(Red_alert_wingman_status.size() <= MAX_SHIPS, "Invalid number of Red_alert_wingman_status entries: " SIZE_T_ARG "\n", Red_alert_wingman_status.size());
1559 
1560  // open it, hopefully...
1561  cfp = cfopen((char*)filename.c_str(), "wb", CFILE_NORMAL, CF_TYPE_PLAYERS);
1562 
1563  if ( !cfp ) {
1564  mprintf(("CSG => Unable to open '%s' for saving!\n", filename.c_str()));
1565  return false;
1566  }
1567 
1568  // header and version
1569  cfwrite_int(CSG_FILE_ID, cfp);
1570  cfwrite_ubyte(CSG_VERSION, cfp);
1571 
1572  mprintf(("CSG => Saving '%s' with version %d...\n", filename.c_str(), (int)CSG_VERSION));
1573 
1574  // flags and info sections go first
1575  mprintf(("CSG => Saving: Flags...\n"));
1576  csg_write_flags();
1577  mprintf(("CSG => Saving: Info...\n"));
1578  csg_write_info();
1579 
1580  // everything else is next, not order specific
1581  mprintf(("CSG => Saving: Missions...\n"));
1582  csg_write_missions();
1583  mprintf(("CSG => Saving: Techroom...\n"));
1584  csg_write_techroom();
1585  mprintf(("CSG => Saving: Loadout...\n"));
1586  csg_write_loadout();
1587  mprintf(("CSG => Saving: Scoring...\n"));
1588  csg_write_stats();
1589  mprintf(("CSG => Saving: RedAlert...\n"));
1590  csg_write_redalert();
1591  mprintf(("CSG => Saving: HUD...\n"));
1592  csg_write_hud();
1593  mprintf(("CSG => Saving: Variables...\n"));
1594  csg_write_variables();
1595  mprintf(("CSG => Saving: Settings...\n"));
1596  csg_write_settings();
1597  mprintf(("CSG => Saving: Controls...\n"));
1598  csg_write_controls();
1599  mprintf(("CSG => Saving: Cutscenes...\n"));
1600  csg_write_cutscenes();
1601  mprintf(("CSG => Saving: Last Missions...\n"));
1602  csg_write_lastmissions();
1603 
1604  // Done!
1605  mprintf(("CSG => Saving complete!\n"));
1606 
1607  csg_close();
1608 
1609  return true;
1610 }
1611 
1612 /*
1613  * get_csg_rank: this function is called from plr.cpp & is
1614  * tightly linked with pilotfile::verify()
1615  */
1616 bool pilotfile::get_csg_rank(int *rank)
1617 {
1618  player t_csg;
1619 
1620  // set player ptr first thing
1621  p = &t_csg;
1622 
1623  // filename has already been set
1624  cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS);
1625 
1626  if ( !cfp ) {
1627  mprintf(("CSG => Unable to open '%s'!\n", filename.c_str()));
1628  return false;
1629  }
1630 
1631  unsigned int csg_id = cfread_uint(cfp);
1632 
1633  if (csg_id != CSG_FILE_ID) {
1634  mprintf(("CSG => Invalid header id for '%s'!\n", filename.c_str()));
1635  csg_close();
1636  return false;
1637  }
1638 
1639  // version, now used
1640  csg_ver = cfread_ubyte(cfp);
1641 
1642  mprintf(("CSG => Get Rank from '%s' with version %d...\n", filename.c_str(), (int)csg_ver));
1643 
1644  // the point of all this: read in the CSG contents
1645  while ( !m_have_flags && !cfeof(cfp) ) {
1646  ushort section_id = cfread_ushort(cfp);
1647  uint section_size = cfread_uint(cfp);
1648 
1649  size_t start_pos = cftell(cfp);
1650  size_t offset_pos;
1651 
1652  // safety, to help protect against long reads
1653  cf_set_max_read_len(cfp, section_size);
1654 
1655  try {
1656  switch (section_id) {
1657  case Section::Flags:
1658  mprintf(("CSG => Parsing: Flags...\n"));
1659  m_have_flags = true;
1660  csg_read_flags();
1661  break;
1662 
1663  default:
1664  break;
1665  }
1666  } catch (cfile::max_read_length &msg) {
1667  // read to max section size, move to next section, discarding
1668  // extra/unknown data
1669  mprintf(("CSG => (0x%04x) %s\n", section_id, msg.what()));
1670  } catch (const char *err) {
1671  mprintf(("CSG => ERROR: %s\n", err));
1672  csg_close();
1673  return false;
1674  }
1675 
1676  // reset safety catch
1677  cf_set_max_read_len(cfp, 0);
1678 
1679  // skip to next section (if not already there)
1680  offset_pos = (start_pos + section_size) - cftell(cfp);
1681 
1682  if (offset_pos) {
1683  mprintf(("CSG => Warning: (0x%04x) Short read, information may have been lost!\n", section_id));
1684  cfseek(cfp, offset_pos, CF_SEEK_CUR);
1685  }
1686  }
1687 
1688  // this is what we came for...
1689  *rank = p->stats.rank;
1690 
1691  mprintf(("CSG => Get Rank complete!\n"));
1692 
1693  // cleanup & return
1694  csg_close();
1695 
1696  return true;
1697 }
#define __UNUSED
Definition: clang.h:23
int Joy_sensitivity
Definition: joy-unix.cpp:29
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
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
int i
Definition: multi_pxo.cpp:466
SCP_vector< medal_stuff > Medals
Definition: medals.cpp:33
int Briefing_voice_enabled
#define vm_free(ptr)
Definition: pstypes.h:548
int kill_count_ok
Definition: scoring.h:90
void audiostream_set_volume_all(float volume, int type)
Definition: audiostr.cpp:1857
int HUD_color_alpha
Definition: hud.cpp:76
#define Verify(x)
Definition: pstypes.h:272
SCP_string name
#define MAX_SHIP_PRIMARY_BANKS
Definition: globals.h:62
#define HUD_COLOR_ALPHA_DEFAULT
Definition: hud.h:74
SCP_vector< cutscene_info > Cutscenes
Definition: cutscenes.cpp:39
int kills[MAX_SHIP_CLASSES]
Definition: scoring.h:87
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
char Recent_missions[MAX_RECENT_MISSIONS][MAX_FILENAME_LEN]
Definition: missionload.cpp:34
short key_id
actual key bound to action
weapon_info Weapon_info[MAX_WEAPON_TYPES]
Definition: weapons.cpp:79
#define CF_TYPE_PLAYERS
Definition: cfile.h:67
#define ASF_EVENTMUSIC
Definition: audiostr.h:19
GLuint index
Definition: Glext.h:5608
bool save_savefile()
Definition: csg.cpp:1524
#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 index
Definition: pstypes.h:213
#define MAX_SHIPS
Definition: globals.h:37
int Dead_zone_size
Definition: joy-unix.cpp:27
int cfwrite_uint(uint i, CFILE *file)
Definition: cfile.cpp:1316
int weapon_info_lookup(const char *name=NULL)
Definition: weapons.cpp:467
Assert(pm!=NULL)
virtual const char * what() const
Definition: cfile.h:372
#define WIF2_DEFAULT_IN_TECH_DATABASE
Definition: weapon.h:86
char filename[MAX_FILENAME_LEN]
#define mprintf(args)
Definition: pstypes.h:238
SCP_string Red_alert_precursor_mission
Definition: redalert.cpp:49
int weapon_pool[MAX_WEAPON_TYPES]
void tech_reset_to_default()
Definition: techmenu.cpp:1438
GLclampf f
Definition: Glext.h:7097
#define SIZE_T_ARG
Definition: clang.h:61
long _fs_time_t
Definition: pstypes.h:55
int kill_count
Definition: scoring.h:89
color clr[NUM_HUD_GAUGES]
Definition: hudconfig.h:60
#define Assertion(expr, msg,...)
Definition: clang.h:41
#define MAX_WSS_SLOTS
SCP_vector< red_alert_ship_status > Red_alert_wingman_status
Definition: redalert.cpp:48
#define CF_SEEK_CUR
Definition: cfile.h:25
char name[NAME_LENGTH]
ubyte blue
Definition: 2d.h:102
ubyte ships_allowed[MAX_SHIP_CLASSES]
unsigned int s_shots_fired
Definition: scoring.h:92
void hud_config_record_color(int in_color)
Definition: hudconfig.cpp:1002
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
int Num_recent_missions
Definition: missionload.cpp:35
short joy_id
joystick button bound to action
config_item Control_config[]
Stores the keyboard configuration.
int wep_count[MAX_SHIP_WEAPONS]
sexp_variable * redalert_variables
ubyte green
Definition: 2d.h:101
#define SIF2_DEFAULT_IN_TECH_DATABASE
Definition: ship.h:918
player Players[MAX_PLAYERS]
#define FS_CAMPAIGN_FILE_EXT
Definition: freespace.h:26
int cfwrite_char(char b, CFILE *file)
Definition: cfile.cpp:1361
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
#define MAX_SHIP_SECONDARY_BANKS
Definition: globals.h:63
Definition: player.h:85
int intel_info_lookup(char *name)
Definition: techmenu.cpp:1422
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
#define WIF_IN_TECH_DATABASE
Definition: weapon.h:67
ubyte weapons_allowed[MAX_WEAPON_TYPES]
int cfwrite_float(float f, CFILE *file)
Definition: cfile.cpp:1304
unsigned int p_shots_fired
Definition: scoring.h:91
GLclampf GLclampf blue
Definition: Glext.h:5177
int cf_exists_full(const char *filename, int dir_type)
Definition: cfile.cpp:527
int Intel_info_size
Definition: techmenu.cpp:247
wss_unit unit_data[MAX_WSS_SLOTS]
ubyte red
Definition: 2d.h:100
int num_variables
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 Use_mouse_to_fly
Definition: mouse.cpp:51
GLsizei const GLchar ** string
Definition: Glext.h:5636
#define MAX_PLAYERS
Definition: pstypes.h:32
SCP_vector< int > medal_counts
Definition: scoring.h:85
short cfread_short(CFILE *file, int ver, short deflt)
Definition: cfile.cpp:1192
int idx
Definition: multiui.cpp:761
GLclampf green
Definition: Glext.h:5177
#define SIF_IN_TECH_DATABASE
Definition: ship.h:897
char name[NAME_LENGTH]
int cfwrite_int(int i, CFILE *file)
Definition: cfile.cpp:1310
int type
Definition: sexp.h:1043
ubyte alpha
Definition: 2d.h:103
unsigned char ubyte
Definition: pstypes.h:62
int wi_flags
Definition: weapon.h:384
#define DATE_TIME_LENGTH
Definition: globals.h:19
sexp_variable * variables
void _splitpath(char *path, char *drive, char *dir, char *fname, char *ext)
int cfeof(CFILE *cfile)
#define IIF_IN_TECH_DATABASE
Definition: techmenu.h:29
GLbitfield flags
Definition: Glext.h:6722
#define vm_malloc(size)
Definition: pstypes.h:547
int Num_weapon_types
Definition: weapons.cpp:105
ubyte cfread_ubyte(CFILE *file, int ver, ubyte deflt)
Definition: cfile.cpp:1220
int flags
Definition: techmenu.h:24
GLuint const GLchar * name
Definition: Glext.h:5608
#define TOKEN_LENGTH
Definition: globals.h:41
int cftell(CFILE *fp)
intel_data Intel_info[MAX_INTEL_ENTRIES]
Definition: techmenu.cpp:246
char status
ubyte num_msg_window_lines
Definition: hudconfig.h:57
bool load_savefile(const char *campaign)
Definition: csg.cpp:1347
campaign Campaign
char cfread_char(CFILE *file, int ver, char deflt)
Definition: cfile.cpp:1265
#define NAME_LENGTH
Definition: globals.h:15
int wep[MAX_SHIP_WEAPONS]
loadout_data Player_loadout
#define IIF_DEFAULT_IN_TECH_DATABASE
Definition: techmenu.h:30
int cfwrite_short(short s, CFILE *file)
Definition: cfile.cpp:1322
unsigned short ushort
Definition: pstypes.h:63
mgoal * goals
unsigned int p_shots_hit
Definition: scoring.h:94
#define CF_TYPE_MISSIONS
Definition: cfile.h:74
GLfloat GLfloat p
Definition: Glext.h:8373
unsigned int p_bonehead_hits
Definition: scoring.h:97
HUD_CONFIG_TYPE HUD_config
Definition: hudconfig.cpp:49
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
float Master_event_music_volume
Definition: eventmusic.cpp:40
The total number of defined control actions (or last define + 1)
Definition: pstypes.h:212
int count
Definition: pstypes.h:214
mevent * events
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
GLint GLsizei count
Definition: Gl.h:1491
#define MAX_CAMPAIGN_MISSIONS
char status
void cutscene_mark_viewable(char *filename)
Definition: cutscenes.cpp:126
char variable_name[TOKEN_LENGTH]
Definition: sexp.h:1045
char filename[MAX_FILENAME_LEN]
scoring_struct stats
int bonehead_kills
Definition: scoring.h:99
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
#define MAX_RECENT_MISSIONS
Definition: missionload.h:20
GLclampf GLclampf GLclampf alpha
Definition: Glext.h:5177
int Event_music_enabled
Definition: eventmusic.cpp:237
int num_missions_completed
sexp_variable * variables
int Num_medals
Definition: medals.cpp:30
unsigned int s_shots_hit
Definition: scoring.h:95
int ship_pool[MAX_SHIP_CLASSES]
unsigned int s_bonehead_hits
Definition: scoring.h:98
float Master_voice_volume
Definition: sound.cpp:54
cmission missions[MAX_CAMPAIGN_MISSIONS]
uint cfread_uint(CFILE *file, int ver, uint deflt)
Definition: cfile.cpp:1178
int redalert_num_variables
char last_modified[DATE_TIME_LENGTH]
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
#define _MAX_FNAME
Definition: config.h:220
int cfseek(CFILE *fp, int offset, int where)