2 * $Logfile: /Freespace2/code/Playerman/ManagePilot.cpp $
7 * ManagePilot.cpp has code to load and save pilot files, and to select and
11 * Revision 1.1 2002/05/03 03:28:11 root
15 * 41 9/13/99 4:52p Dave
18 * 40 9/01/99 10:09a Dave
21 * 39 8/26/99 8:49p Jefff
22 * old player file compatibility with new medal stuff
24 * 38 8/22/99 5:53p Dave
25 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
26 * instead of ship designations for multiplayer players.
28 * 37 8/16/99 4:06p Dave
29 * Big honking checkin.
31 * 36 8/11/99 11:36a Jefff
32 * added compatibility w/ fs2 demo plr version
34 * 35 8/10/99 3:46p Jefff
35 * changes for Intelligence section of new tech room
37 * 34 8/04/99 11:38p Andsager
38 * make new pilot detail level match registry info.
40 * 33 8/02/99 9:55p Dave
41 * Hardcode a nice hud color config for the demo.
43 * 32 8/02/99 9:13p Dave
46 * 31 8/01/99 12:39p Dave
47 * Added HUD contrast control key (for nebula).
49 * 30 7/30/99 10:31p Dave
50 * Added comm menu to the configurable hud files.
52 * 29 7/29/99 10:47p Dave
53 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
55 * 28 7/29/99 12:05a Dave
56 * Nebula speed optimizations.
58 * 27 7/24/99 1:54p Dave
59 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
62 * 26 6/22/99 7:03p Dave
63 * New detail options screen.
65 * 25 6/16/99 4:06p Dave
66 * New pilot info popup. Added new draw-bitmap-as-poly function.
68 * 24 6/11/99 11:13a Dave
69 * last minute changes before press tour build.
71 * 23 6/08/99 1:14a Dave
72 * Multi colored hud test.
74 * 22 5/03/99 8:33p Dave
75 * New version of multi host options screen.
77 * 21 3/24/99 4:05p Dave
78 * Put in support for assigning the player to a specific squadron with a
79 * specific logo. Preliminary work for doing pos/orient checksumming in
80 * multiplayer to reduce bandwidth.
82 * 20 1/30/99 1:29a Dave
83 * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
84 * screen. Fixed beam weapon death messages.
86 * 19 1/29/99 2:08a Dave
87 * Fixed beam weapon collisions with players. Reduced size of scoring
88 * struct for multiplayer. Disabled PXO.
90 * 18 1/21/99 2:06p Dave
91 * Final checkin for multiplayer testing.
93 * 17 1/15/99 2:49p Dave
94 * Fixed creation of pilots.
96 * 16 1/14/99 6:06p Dave
97 * 100% full squad logo support for single player and multiplayer.
99 * 15 1/12/99 3:15a Dave
100 * Barracks screen support for selecting squad logos. We need real artwork
103 * 14 1/06/99 2:24p Dave
104 * Stubs and release build fixes.
106 * 13 12/14/98 12:13p Dave
107 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
110 * 12 11/20/98 11:16a Dave
111 * Fixed up IPX support a bit. Making sure that switching modes and
112 * loading/saving pilot files maintains proper state.
114 * 11 11/19/98 4:51p Dave
115 * Ignore multiplayer protocol settings in the pilot file for now.
117 * 10 11/19/98 4:19p Dave
118 * Put IPX sockets back in psnet. Consolidated all multiplayer config
121 * 9 10/13/98 2:47p Andsager
122 * Remove reference to Tech_shivan_species_avail
124 * 8 10/13/98 9:29a Dave
125 * Started neatening up freespace.h. Many variables renamed and
126 * reorganized. Added AlphaColors.[h,cpp]
128 * 7 10/12/98 9:30a Andsager
129 * Clean up barracks.cpp. Remove unneeded ".h" files from ManagePilot
131 * 6 10/09/98 5:17p Andsager
132 * move barracks screen into barracks.cpp
134 * 5 10/09/98 2:57p Dave
135 * Starting splitting up OS stuff.
137 * 4 10/08/98 9:19a Andsager
138 * Clean up pilot player read and write, starting with new version.
140 * 3 10/07/98 6:27p Dave
141 * Globalized mission and campaign file extensions. Removed Silent Threat
142 * special code. Moved \cache \players and \multidata into the \data
145 * 2 10/07/98 10:53a Dave
148 * 1 10/07/98 10:50a Dave
150 * 279 9/21/98 10:02p Dave
151 * Last minute changes to techroom weapon/ship/species stuff.
153 * 278 9/08/98 12:10p Andsager
154 * Fixed a bug with saving ship and weapon info techroom flags.
156 * 277 9/01/98 4:25p Dave
157 * Put in total (I think) backwards compatibility between mission disk
158 * freespace and non mission disk freespace, including pilot files and
159 * campaign savefiles.
161 * 276 6/09/98 10:31a Hoffoss
162 * Created index numbers for all xstr() references. Any new xstr() stuff
163 * added from here on out should be added to the end if the list. The
164 * current list count can be found in FreeSpace.cpp (search for
167 * 275 6/05/98 9:49a Lawrance
170 * 274 6/01/98 11:43a John
171 * JAS & MK: Classified all strings for localization.
173 * 273 5/26/98 11:53a Allender
174 * fix multiplayer problems and sexpression crash
176 * 272 5/24/98 2:46p Lawrance
177 * Fix bug where skill level would be reset to default when switching
180 * 271 5/23/98 4:02p Allender
183 * 270 5/23/98 2:41p Mike
184 * Make Easy the default skill level and prevent old pilot's skill level
185 * from carrying into new pilot.
190 #include "managepilot.h"
192 #include "freespace.h"
193 #include "hudsquadmsg.h"
196 #include "eventmusic.h"
197 #include "audiostr.h"
198 #include "osregistry.h"
200 #include "playermenu.h"
201 #include "missionshipchoice.h"
202 #include "hudconfig.h"
204 #include "redalert.h"
205 #include "techmenu.h"
208 #include "cutscenes.h"
211 // update this when altering data that is read/written to .PLR file
212 #define CURRENT_PLAYER_FILE_VERSION 140
213 #define FS2_DEMO_PLAYER_FILE_VERSION 135
214 #define LOWEST_COMPATIBLE_PLAYER_FILE_VERSION CURRENT_PLAYER_FILE_VERSION // demo plr files should work in final
216 // keep track of pilot file changes here
217 // version 2 : Added squad logo filename
218 // version 3 : Changed size of scoring struct. use ushort instead of ints for storing alltime kills by ship type
219 // version 4/5 : Added squadron name field
220 // version 6 : changed max length on a multiplayer options field
221 // version 130 : changed size of hud config struct
222 // version 133 : misc changes. new hud gauge
223 // version 134 : added HUD contrast toggle key
224 // version 135 : added tips flag (THIS IS THE DEMO VERSION - RETAIN COMPATIBILITY FROM HERE ON OUT)
225 // version 136 : added intelligence flags to tech room visibility data
226 // version 137 : 2 new HUD gauges.
227 // version 138 : new multiplayer config
228 // version 139 : # medals increased - added compatibility with old plr file versions
229 // version 140 : ships table reordered. clear out old pilot files
230 // search for PLAYER INIT for new pilot initialization stuff. I _think_ its in the right spot for now
231 #define PLR_FILE_ID 'FPSF' // unique signiture to identify a .PLR file (FreeSpace Player File) // FPSF appears as FSPF in file.
233 // Current content of a .PLR file
239 // pilot pic image list stuff ( call pilot_load_pic_list() to make these valid )
240 char Pilot_images_arr[MAX_PILOT_IMAGES][MAX_FILENAME_LEN];
241 char *Pilot_image_names[MAX_PILOT_IMAGES];
242 int Num_pilot_images = 0;
244 // squad logo list stuff (call pilot_load_squad_pic_list() to make these valid )
245 char Pilot_squad_images_arr[MAX_PILOT_IMAGES][MAX_FILENAME_LEN];
246 char *Pilot_squad_image_names[MAX_PILOT_IMAGES];
247 int Num_pilot_squad_images = 0;
249 static uint Player_file_version;
251 // forward declarations
252 void read_stats_block(CFILE *file, int Player_file_version, scoring_struct *stats);
253 void write_stats_block(CFILE *file, scoring_struct *stats);
254 void read_multiplayer_options(player *p,CFILE *file);
255 void write_multiplayer_options(player *p,CFILE *file);
257 // internal function to delete a player file. Called after a pilot is obsoleted, and when a pilot is deleted
258 // used in barracks and player_select
259 void delete_pilot_file( char *pilot_name, int single )
261 char filename[MAX_FILENAME_LEN];
262 char basename[MAX_FILENAME_LEN];
264 // get the player file.
268 _splitpath(pilot_name, NULL, NULL, basename, NULL);
270 strcpy( filename, basename );
271 strcat( filename, NOX(".plr") );
272 if (Player_sel_mode == PLAYER_SELECT_MODE_SINGLE){
273 cf_delete(filename, CF_TYPE_SINGLE_PLAYERS);
275 cf_delete(filename, CF_TYPE_MULTI_PLAYERS);
278 // we must try and delete the campaign save files for a pilot as well.
279 mission_campaign_delete_all_savefiles( basename, !single );
283 // check if a pilot file is valid or not (i.e. is usable, not out of date, etc)
284 // used in barracks and player_select
285 int verify_pilot_file(char *filename, int single, int *rank)
288 uint id, file_version;
291 filename = cf_add_ext(filename, NOX(".plr"));
294 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
296 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
303 id = cfread_uint(file);
304 if (id != PLR_FILE_ID) {
305 nprintf(("Warning", "Player file has invalid signature\n"));
307 delete_pilot_file( filename, single );
311 // check for compatibility here
312 file_version = cfread_uint(file);
313 /* if (file_version < INITIAL_RELEASE_FILE_VERSION) { */
314 // if (file_version != CURRENT_PLAYER_FILE_VERSION) {
315 if (file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
316 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
318 delete_pilot_file( filename, single );
322 type = !cfread_ubyte(file);
328 *rank = cfread_int(file);
341 void pilot_write_techroom_data(CFILE *file)
346 // write the ship and weapon count
347 cfwrite_int(Num_ship_types, file);
348 cfwrite_int(Num_weapon_types, file);
349 cfwrite_int(Intel_info_size, file);
351 // write all ship flags out
352 for (idx=0; idx<Num_ship_types; idx++) {
353 out = (Ship_info[idx].flags & SIF_IN_TECH_DATABASE) ? (ubyte)1 : (ubyte)0;
354 cfwrite_ubyte(out, file);
357 // write all weapon types out
358 for (idx=0; idx<Num_weapon_types; idx++) {
359 out = (Weapon_info[idx].wi_flags & WIF_IN_TECH_DATABASE) ? (ubyte)1 : (ubyte)0;
360 cfwrite_ubyte(out, file);
363 // write all intel entry flags out
364 for (idx=0; idx<Intel_info_size; idx++) {
365 cfwrite_ubyte((ubyte)Intel_info[idx].in_tech_db, file);
369 void pilot_read_techroom_data(CFILE *file)
372 int ship_count, weapon_count, intel_count;
375 // read in ship and weapon counts
376 ship_count = cfread_int(file);
377 weapon_count = cfread_int(file);
378 Assert(ship_count <= MAX_SHIP_TYPES);
379 Assert(weapon_count <= MAX_WEAPON_TYPES);
381 // maintain compatibility w/ demo version
382 if (Player_file_version < 136) {
383 // skip over all this data, because the lack of tech room in the demo
384 // left this all hosed in the demo .plr files
385 // this will all get initialized as if this fella was a new pilot
386 for (idx=0; idx<ship_count+weapon_count; idx++) {
387 in = cfread_ubyte(file);
392 intel_count = cfread_int(file);
393 Assert(intel_count <= MAX_INTEL_ENTRIES);
396 for (idx=0; idx<ship_count; idx++) {
397 in = cfread_ubyte(file);
399 Ship_info[idx].flags |= SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M;
401 Ship_info[idx].flags &= ~SIF_IN_TECH_DATABASE;
405 // read all weapons in
406 for (idx=0; idx<weapon_count; idx++) {
407 in = cfread_ubyte(file);
409 Weapon_info[idx].wi_flags |= WIF_IN_TECH_DATABASE;
411 Weapon_info[idx].wi_flags &= ~WIF_IN_TECH_DATABASE;
415 // read all intel entries in
416 for (idx=0; idx<intel_count; idx++) {
417 in = cfread_ubyte(file);
419 Intel_info[idx].in_tech_db = 1;
421 Intel_info[idx].in_tech_db = 0;
427 // write out the player ship selection
428 void pilot_write_loadout(CFILE *file)
433 cfwrite_string_len(Player_loadout.filename, file);
434 cfwrite_string_len(Player_loadout.last_modified, file);
436 // write ship and weapon counts
437 cfwrite_int(Num_ship_types, file);
438 cfwrite_int(Num_weapon_types, file);
441 for ( i = 0; i < Num_ship_types; i++ ) {
442 cfwrite_int(Player_loadout.ship_pool[i], file);
445 // write weapons pool
446 for ( i = 0; i < Num_weapon_types; i++ ) {
447 cfwrite_int(Player_loadout.weapon_pool[i], file);
450 // write ship loadouts
451 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
452 slot = &Player_loadout.unit_data[i];
453 cfwrite_int(slot->ship_class, file);
454 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
455 cfwrite_int(slot->wep[j], file);
456 cfwrite_int(slot->wep_count[j], file);
461 // read in the ship selection for the pilot
462 void pilot_read_loadout(CFILE *file)
466 int ship_count, weapon_count;
468 memset(Player_loadout.filename, 0, MAX_FILENAME_LEN);
469 cfread_string_len(Player_loadout.filename, MAX_FILENAME_LEN, file);
471 memset(Player_loadout.last_modified, 0, DATE_TIME_LENGTH);
472 cfread_string_len(Player_loadout.last_modified, DATE_TIME_LENGTH, file);
474 // read in ship and weapon counts
475 ship_count = cfread_int(file);
476 weapon_count = cfread_int(file);
477 Assert(ship_count <= MAX_SHIP_TYPES);
478 Assert(weapon_count <= MAX_WEAPON_TYPES);
481 for ( i = 0; i < ship_count; i++ ) {
482 Player_loadout.ship_pool[i] = cfread_int(file);
485 // read in weapons pool
486 for ( i = 0; i < weapon_count; i++ ) {
487 Player_loadout.weapon_pool[i] = cfread_int(file);
490 // read in loadout info
491 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
492 slot = &Player_loadout.unit_data[i];
493 slot->ship_class = cfread_int(file);
494 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
495 slot->wep[j] = cfread_int(file);
496 slot->wep_count[j] = cfread_int(file);
503 // returns 0 - file read in correctly
504 // -1 - .PLR file doesn't exist or file not compatible
505 // >0 - errno from fopen error
506 // if single == 1, look for players in the single players directory, otherwise look in the
507 // multiplayers directory
508 int read_pilot_file(char *callsign, int single, player *p)
512 char filename[MAX_FILENAME_LEN], ship_name[NAME_LENGTH];
519 Assert((Player_num >= 0) && (Player_num < MAX_PLAYERS));
520 p = &Players[Player_num];
523 //sprintf(filename, "%-.8s.plr",Players[Player_num].callsign);
524 Assert(strlen(callsign) < MAX_FILENAME_LEN - 4); // ensure we won't overrun the buffer
525 strcpy( filename, callsign );
526 strcat( filename, NOX(".plr") );
528 // if we're a standalone server in multiplayer, just fill in some bogus values since we don't have a pilot file
529 if ((Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER)) {
530 memset(Player, 0, sizeof(player));
531 strcpy(Player->callsign, NOX("Standalone"));
532 strcpy(Player->short_callsign, NOX("Standalone"));
536 // see comments at the beginning of function
538 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
540 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
547 id = cfread_uint(file);
548 if (id != PLR_FILE_ID) {
549 Warning(LOCATION, "Player file has invalid signature");
554 // check for compatibility here
555 Player_file_version = cfread_uint(file);
556 cf_set_version( file, Player_file_version );
558 if (Player_file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
559 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
561 delete_pilot_file( filename, single );
565 // read in whether he's a multiplayer or not
566 is_multi = cfread_ubyte(file);
568 p->flags |= PLAYER_FLAGS_IS_MULTI;
570 p->flags &= ~PLAYER_FLAGS_IS_MULTI; // this takes care of unsetting any leftover bits from a (possibly) previously selected pilot
576 // get player location
577 p->on_bastion = cfread_ubyte(file);
580 p->tips = cfread_int(file);
582 // write out the image file name
583 cfread_string_len(p->image_filename, MAX_FILENAME_LEN - 1, file);
585 // write out the image file name
586 p->insignia_texture = -1;
587 cfread_string_len(p->squad_name, NAME_LENGTH, file);
588 cfread_string_len(p->squad_filename, MAX_FILENAME_LEN - 1, file);
589 player_set_squad_bitmap(p, p->squad_filename);
591 // deal with campaign stuff. The way we store the information in the file is to first store the
592 // name of the current campaign that the player is playing. Next we store the info regarding the campaigns
593 // that the player is currently playing
594 memset(p->current_campaign, 0, MAX_FILENAME_LEN);
595 cfread_string_len(p->current_campaign, MAX_FILENAME_LEN, file);
597 // read in the ship name for last ship flown by the player
598 memset(ship_name, 0, NAME_LENGTH);
599 cfread_string_len(ship_name, NAME_LENGTH, file);
600 p->last_ship_flown_si_index = ship_info_lookup(ship_name);
601 if ( p->last_ship_flown_si_index < 0 ) {
602 nprintf(("Warning","WARNING => Ship class %s not located in Ship_info[] in player file\n",ship_name));
603 p->last_ship_flown_si_index = ship_info_lookup(default_player_ship);
606 // set all the entries in the control config arrays to -1 (undefined)
607 control_config_clear();
609 // ---------------------------------------------
610 // read in the keyboard/joystick mapping
611 // ---------------------------------------------
612 num_ctrls = cfread_ubyte(file);
613 for (i=0; i<num_ctrls; i++) {
614 key_value = cfread_short(file);
615 // NOTE: next two lines are only here for transitioning from 255 to -1 as undefined key items
616 if (key_value == 255)
619 Control_config[i].key_id = (short) key_value;
621 key_value = cfread_short(file);
622 // NOTE: next two lines are only here for transitioning from 255 to -1 as undefined key items
623 if (key_value == 255)
626 Control_config[i].joy_id = (short) key_value;
629 HUD_config.show_flags = cfread_int(file);
630 HUD_config.show_flags2 = cfread_int(file);
632 HUD_config.popup_flags = cfread_int(file);
633 HUD_config.popup_flags2 = cfread_int(file);
635 HUD_config.num_msg_window_lines = cfread_ubyte(file);
636 HUD_config.rp_flags = cfread_int(file);
637 HUD_config.rp_dist = cfread_int(file);
638 // HUD_config.color = cfread_int( file );
639 // HUD_color_alpha = cfread_int( file );
640 // if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MIN ) {
641 // HUD_color_alpha = HUD_COLOR_ALPHA_DEFAULT;
643 // hud_config_record_color(HUD_config.color);
645 // added 2 gauges with version 137
646 if(Player_file_version < 137){
647 for(idx=0; idx<NUM_HUD_GAUGES-2; idx++){
648 cfread(&HUD_config.clr[idx], sizeof(color), 1, file);
651 // set the 2 new gauges to be radar color
652 memcpy(&HUD_config.clr[NUM_HUD_GAUGES-2], &HUD_config.clr[HUD_RADAR], sizeof(color));
653 memcpy(&HUD_config.clr[NUM_HUD_GAUGES-1], &HUD_config.clr[HUD_RADAR], sizeof(color));
655 for(idx=0; idx<NUM_HUD_GAUGES; idx++){
656 cfread(&HUD_config.clr[idx], sizeof(color), 1, file);
660 // read in the cutscenes which have been viewed
661 Cutscenes_viewable = cfread_int(file);
663 Master_sound_volume = cfread_float(file);
664 Master_event_music_volume = cfread_float(file);
665 Master_voice_volume = cfread_float(file);
667 audiostream_set_volume_all(Master_voice_volume, ASF_VOICE);
668 audiostream_set_volume_all(Master_event_music_volume, ASF_EVENTMUSIC);
670 if ( Master_event_music_volume > 0.0f ) {
671 Event_music_enabled = 1;
673 Event_music_enabled = 0;
676 cfread( &Detail, sizeof(detail_levels), 1, file );
678 // restore list of most recently played missions
679 Num_recent_missions = cfread_int( file );
680 Assert(Num_recent_missions <= MAX_RECENT_MISSIONS);
681 for ( i = 0; i < Num_recent_missions; i++ ) {
684 cfread_string_len( Recent_missions[i], MAX_FILENAME_LEN, file);
685 // Remove the extension
686 p = strchr(Recent_missions[i], '.');
691 // use this block of stats from now on
692 read_stats_block(file, Player_file_version, &p->stats);
694 Game_skill_level = cfread_int(file);
696 for (i=0; i<NUM_JOY_AXIS_ACTIONS; i++) {
697 Axis_map_to[i] = cfread_int(file);
698 Invert_axis[i] = cfread_int(file);
701 // restore some player flags
702 Player[Player_num].save_flags = cfread_int(file);
704 // restore the most recent ship selection
705 pilot_read_loadout(file);
707 // read in multiplayer options
708 read_multiplayer_options(p,file);
710 p->readyroom_listing_mode = cfread_int(file);
711 Briefing_voice_enabled = cfread_int(file);
713 // restore the default netgame protocol mode
714 int protocol_temp = cfread_int(file);
715 switch(protocol_temp){
719 Multi_options_g.protocol = NET_TCP;
723 Multi_options_g.protocol = NET_IPX;
727 // restore wingman status used by red alert missions
728 red_alert_read_wingman_status(file, Player_file_version);
730 // read techroom data
731 pilot_read_techroom_data(file);
733 // restore auto-advance pref
734 Player->auto_advance = cfread_int(file);
736 Use_mouse_to_fly = cfread_int(file);
737 Mouse_sensitivity = cfread_int(file);
738 Joy_sensitivity = cfread_int(file);
739 Dead_zone_size = cfread_int(file);
744 // restore the callsign into the Player structure
745 strcpy(p->callsign, callsign);
747 // restore the truncated callsign into Player structure
748 pilot_set_short_callsign(p, SHORT_CALLSIGN_PIXEL_W);
750 // when we store the LastPlayer key, we have to mark it as being single or multiplayer, so we know where to look for him
751 // (since we could have a single and a multiplayer pilot with the same callsign)
752 // we'll distinguish them by putting an M and the end of the multiplayer callsign and a P at the end of a single player
755 strcpy(cat, p->callsign);
757 strcat(cat, NOX("M"));
759 strcat(cat, NOX("S"));
761 os_config_write_string( NULL, "LastPlayer", cat );
763 // if he's not a multiplayer pilot, then load in the campaign file at this point!
765 if (mission_campaign_load_by_name(campaign_fname)) {
766 strcpy(campaign_fname, BUILTIN_CAMPAIGN);
767 if (mission_campaign_load_by_name(campaign_fname))
771 //Campaign.current_mission = mission_num;*/
773 hud_squadmsg_save_keys(); // when new pilot read in, must save info for squadmate messaging
778 void read_stats_block(CFILE *file, int Player_file_version, scoring_struct *stats)
782 init_scoring_element(stats);
783 stats->score = cfread_int(file);
784 stats->rank = cfread_int(file);
785 stats->assists = cfread_int(file);
787 if (Player_file_version < 139) {
788 // support for FS2_DEMO pilots that still have FS1 medal info in the .plr files
789 for (i=0; i < NUM_MEDALS_FS1; i++) {
790 total = cfread_int(file); // dummy read
793 // read the usual way
794 for (i=0; i < NUM_MEDALS; i++) {
795 stats->medals[i] = cfread_int(file);
799 total = cfread_int(file);
800 if (total > MAX_SHIP_TYPES){
801 Warning(LOCATION, "Some ship kill information will be lost due to MAX_SHIP_TYPES decrease");
804 for (i=0; i<total && i<MAX_SHIP_TYPES; i++){
805 stats->kills[i] = cfread_ushort(file);
808 stats->kill_count = cfread_int(file);
809 stats->kill_count_ok = cfread_int(file);
811 stats->p_shots_fired = cfread_uint(file);
812 stats->s_shots_fired = cfread_uint(file);
813 stats->p_shots_hit = cfread_uint(file);
814 stats->s_shots_hit = cfread_uint(file);
816 stats->p_bonehead_hits = cfread_uint(file);
817 stats->s_bonehead_hits = cfread_uint(file);
818 stats->bonehead_kills = cfread_uint(file);
821 // Will write the pilot file in the most current format
823 // if single == 1, save into the single players directory, else save into the multiplayers directory
824 int write_pilot_file_core(player *p)
826 char filename[MAX_FILENAME_LEN + 1];
827 int i, si_index, idx;
831 // never save a pilot file for the standalone server in multiplayer
832 if ((Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER)) {
837 Assert((Player_num >= 0) && (Player_num < MAX_PLAYERS));
838 p = &Players[Player_num];
841 i = strlen(p->callsign);
843 return 0; // This means there is no player, probably meaning he was deleted and game exited from same screen.
845 Assert((i > 0) && (i <= MAX_FILENAME_LEN - 4)); // ensure we won't overrun the buffer
846 strcpy( filename, p->callsign);
847 strcat( filename, NOX(".plr") );
849 // determine if this pilot is a multiplayer pilot or not
850 if (p->flags & PLAYER_FLAGS_IS_MULTI){
858 file = cfopen(filename, "wb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
860 file = cfopen(filename, "wb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
867 // Write out player's info
868 cfwrite_uint(PLR_FILE_ID, file);
869 cfwrite_uint(CURRENT_PLAYER_FILE_VERSION, file);
871 cfwrite_ubyte(is_multi, file);
872 cfwrite_int(p->stats.rank, file);
873 cfwrite_ubyte((ubyte) p->on_bastion, file);
875 cfwrite_int(p->tips, file);
877 // write out the image file name
878 cfwrite_string_len(p->image_filename, file);
880 // write out the image file name
881 cfwrite_string_len(p->squad_name, file);
882 cfwrite_string_len(p->squad_filename, file);
884 // write out the name of the player's active campaign.
885 cfwrite_string_len(p->current_campaign, file);
887 // write the ship name for last ship flown by the player
888 si_index = p->last_ship_flown_si_index;
889 if((si_index < 0) || (si_index >= Num_ship_types)){
893 cfwrite_string_len(Ship_info[si_index].name, file);
895 // ---------------------------------------------
896 // write the keyboard/joystick configuration
897 // ---------------------------------------------
898 cfwrite_ubyte( CCFG_MAX, file );
899 for (i=0; i<CCFG_MAX; i++) {
900 cfwrite_short( Control_config[i].key_id, file );
901 cfwrite_short( Control_config[i].joy_id, file );
904 // if this hud is an observer, the player ended the last mission as an observer, so we should
905 // restore his "real" ship HUD.
906 HUD_CONFIG_TYPE hc_temp;
907 hc_temp.show_flags = 0;
908 int stored_observer = 0;
909 if ( HUD_config.is_observer ){
910 // if we're in mission, copy the HUD we're currently using
911 if(Game_mode & GM_IN_MISSION){
912 memcpy(&hc_temp,&HUD_config,sizeof(HUD_CONFIG_TYPE));
916 hud_config_restore();
919 // write the hud configuration
920 cfwrite_int(HUD_config.show_flags, file);
921 cfwrite_int(HUD_config.show_flags2, file);
922 cfwrite_int(HUD_config.popup_flags, file);
923 cfwrite_int(HUD_config.popup_flags2, file);
924 cfwrite_ubyte( (ubyte) HUD_config.num_msg_window_lines, file );
925 cfwrite_int( HUD_config.rp_flags, file );
926 cfwrite_int( HUD_config.rp_dist, file );
927 // cfwrite_int( HUD_config.color, file );
928 // cfwrite_int( HUD_color_alpha, file );
929 for(idx=0; idx<NUM_HUD_GAUGES; idx++){
930 cfwrite(&HUD_config.clr[idx], sizeof(color), 1, file);
933 // restore the HUD we backed up
934 if( (Game_mode & GM_IN_MISSION) && stored_observer ){
935 memcpy(&HUD_config,&hc_temp,sizeof(HUD_CONFIG_TYPE));
938 // write the cutscenes which have been viewed
939 cfwrite_int(Cutscenes_viewable, file);
941 // store the digital sound fx volume, and music volume
942 cfwrite_float(Master_sound_volume, file);
943 cfwrite_float(Master_event_music_volume, file);
944 cfwrite_float(Master_voice_volume, file);
947 cfwrite( &Detail, sizeof(detail_levels), 1, file );
949 // store list of most recently played missions
950 cfwrite_int(Num_recent_missions, file);
951 for (i=0; i<Num_recent_missions; i++) {
952 cfwrite_string_len(Recent_missions[i], file);
955 // write the player stats
956 write_stats_block(file, &p->stats);
957 cfwrite_int(Game_skill_level, file);
959 for (i=0; i<NUM_JOY_AXIS_ACTIONS; i++) {
960 cfwrite_int(Axis_map_to[i], file);
961 cfwrite_int(Invert_axis[i], file);
964 // store some player flags
965 cfwrite_int(Player->save_flags, file);
967 // store ship selection for most recent mission
968 pilot_write_loadout(file);
970 // read in multiplayer options
971 write_multiplayer_options(p, file);
973 cfwrite_int(p->readyroom_listing_mode, file);
974 cfwrite_int(Briefing_voice_enabled, file);
976 // store the default netgame protocol mode for this pilot
977 if (Multi_options_g.protocol == NET_TCP) {
978 cfwrite_int(NET_TCP, file);
980 cfwrite_int(NET_IPX, file);
983 red_alert_write_wingman_status(file);
984 pilot_write_techroom_data(file);
986 // store auto-advance pref
987 cfwrite_int(Player->auto_advance, file);
989 cfwrite_int(Use_mouse_to_fly, file);
990 cfwrite_int(Mouse_sensitivity, file);
991 cfwrite_int(Joy_sensitivity, file);
992 cfwrite_int(Dead_zone_size, file);
1000 int write_pilot_file(player *the_player)
1002 int pilot_write_rval;
1004 // write_pilot_file_core returns 0 if ok, non-zero for error
1005 pilot_write_rval = write_pilot_file_core(the_player);
1007 // check with user if write not successful
1008 if (pilot_write_rval) {
1009 int popup_rval = popup(PF_TITLE_RED | PF_TITLE_BIG, 3, XSTR( "&Retry", 41), XSTR( "&Ignore", 42), XSTR( "&Quit Game", 43),
1010 XSTR( "Warning\nFailed to save pilot file. You may be out of disk space. If so, you should press Alt-Tab, free up some disk space, then come back and choose retry.\n", 44) );
1012 // quit game popup return value (2)
1013 if (popup_rval == 2) {
1017 // _ignore_ popup return value (1) - don't save the file
1019 return pilot_write_rval;
1022 // retry popup return value (0) - try again
1025 } while (pilot_write_rval);
1031 void write_stats_block(CFILE *file,scoring_struct *stats)
1036 cfwrite_int(stats->score, file);
1037 cfwrite_int(stats->rank, file);
1038 cfwrite_int(stats->assists, file);
1039 for (i=0; i<NUM_MEDALS; i++){
1040 cfwrite_int(stats->medals[i], file);
1043 total = MAX_SHIP_TYPES;
1044 while (total && !stats->kills[total - 1]){ // find last used element
1048 cfwrite_int(total, file);
1049 for (i=0; i<total; i++){
1050 cfwrite_ushort(stats->kills[i], file);
1053 cfwrite_int(stats->kill_count,file);
1054 cfwrite_int(stats->kill_count_ok,file);
1056 cfwrite_uint(stats->p_shots_fired,file);
1057 cfwrite_uint(stats->s_shots_fired,file);
1058 cfwrite_uint(stats->p_shots_hit,file);
1059 cfwrite_uint(stats->s_shots_hit,file);
1060 cfwrite_uint(stats->p_bonehead_hits,file);
1061 cfwrite_uint(stats->s_bonehead_hits,file);
1062 cfwrite_uint(stats->bonehead_kills,file);
1065 // write multiplayer information
1066 void write_multiplayer_options(player *p,CFILE *file)
1068 // write the netgame options
1069 cfwrite_ubyte(p->m_server_options.squad_set,file);
1070 cfwrite_ubyte(p->m_server_options.endgame_set,file);
1071 cfwrite_int(p->m_server_options.flags,file);
1072 cfwrite_uint(p->m_server_options.respawn,file);
1073 cfwrite_ubyte(p->m_server_options.max_observers,file);
1074 cfwrite_ubyte(p->m_server_options.skill_level,file);
1075 cfwrite_ubyte(p->m_server_options.voice_qos,file);
1076 cfwrite_int(p->m_server_options.voice_token_wait,file);
1077 cfwrite_int(p->m_server_options.voice_record_time,file);
1078 cfwrite(&p->m_server_options.mission_time_limit,sizeof(fix),1,file);
1079 cfwrite_int(p->m_server_options.kill_limit,file);
1081 // write the local options
1082 cfwrite_int(p->m_local_options.flags,file);
1083 cfwrite_int(p->m_local_options.obj_update_level,file);
1086 // read multiplayer options
1087 void read_multiplayer_options(player *p,CFILE *file)
1089 // read the netgame options
1090 p->m_server_options.squad_set = cfread_ubyte(file);
1091 p->m_server_options.endgame_set = cfread_ubyte(file);
1092 p->m_server_options.flags = cfread_int(file);
1093 p->m_server_options.respawn = cfread_uint(file);
1094 p->m_server_options.max_observers = cfread_ubyte(file);
1095 p->m_server_options.skill_level = cfread_ubyte(file);
1096 p->m_server_options.voice_qos = cfread_ubyte(file);
1097 p->m_server_options.voice_token_wait = cfread_int(file);
1098 p->m_server_options.voice_record_time = cfread_int(file);
1099 cfread(&p->m_server_options.mission_time_limit,sizeof(fix),1,file);
1100 p->m_server_options.kill_limit = cfread_int(file);
1102 // read the local options
1103 p->m_local_options.flags = cfread_int(file);
1104 p->m_local_options.obj_update_level = cfread_int(file);
1107 // run thorough an open file (at the beginning) and see if this pilot is a multiplayer pilot
1108 int is_pilot_multi(CFILE *fp)
1110 uint id,file_version;
1113 id = cfread_uint(fp);
1114 if (id != PLR_FILE_ID) {
1115 Warning(LOCATION, "Player file has invalid signature");
1120 // check for compatibility here
1121 file_version = cfread_uint(fp);
1122 if (file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
1123 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
1128 // read in whether he's a multiplayer or not
1129 is_multi = cfread_ubyte(fp);
1136 int is_pilot_multi(player *p)
1138 return (p->flags & PLAYER_FLAGS_IS_MULTI) ? 1 : 0;
1141 // this works on barracks and player_select interface screens
1142 void init_new_pilot(player *p, int reset)
1147 hud_set_default_hud_config(p); // use a default hud config
1149 // in the demo, load up the hardcoded hcf file
1151 hud_config_color_load("hud_1.hcf");
1153 hud_config_color_load("hud_3.hcf");
1156 control_config_reset_defaults(); // get a default keyboard config
1157 player_set_pilot_defaults(p); // set up any player struct defaults
1159 cur_speed = os_config_read_uint(NULL, NOX("ComputerSpeed"), 2 );
1160 if ( cur_speed < 0 ) {
1162 } else if ( cur_speed >= NUM_DEFAULT_DETAIL_LEVELS ) {
1163 cur_speed = NUM_DEFAULT_DETAIL_LEVELS-1;
1165 // always set to high
1166 // DKA: 8/4/99 USE speed from registry
1167 // cur_speed = NUM_DEFAULT_DETAIL_LEVELS-2;
1169 #if NUM_DEFAULT_DETAIL_LEVELS != 4
1170 #error Code in ManagePilot assumes NUM_DEFAULT_DETAIL_LEVELS = 4
1173 detail_level_set(cur_speed);
1175 Game_skill_level = game_get_default_skill_level();
1177 mprintf(( "Setting detail level to %d because of new pilot\n", cur_speed ));
1178 Use_mouse_to_fly = 0;
1179 Mouse_sensitivity = 4;
1180 Joy_sensitivity = 9;
1181 Dead_zone_size = 10;
1184 // unassigned squadron
1185 strcpy(p->squad_name, XSTR("Unassigned", 1255));
1186 strcpy(p->squad_filename, "");
1188 // set him to be a single player pilot by default (the actual creation routines will change this if necessary)
1189 p->flags &= ~PLAYER_FLAGS_IS_MULTI;
1191 // effectively sets the length return by strlen() to 0
1192 Campaign.filename[0] = 0;
1195 // pick a random pilot image for this guy
1197 pilot_set_random_pic(p);
1198 p->insignia_texture = -1;
1199 pilot_set_random_squad_pic(p);
1202 init_scoring_element(&p->stats);
1205 p->stats.rank = RANK_ENSIGN;
1209 Multi_options_g.protocol = NET_TCP;
1211 // initialize default multiplayer options
1212 multi_options_set_netgame_defaults(&p->m_server_options);
1213 multi_options_set_local_defaults(&p->m_local_options);
1215 Player_loadout.filename[0] = 0;
1217 // reset the cutscenes which can be viewed
1219 Cutscenes_viewable = INTRO_CUTSCENE_FLAG;
1223 void pilot_set_short_callsign(player *p, int max_width)
1225 strcpy(p->short_callsign, p->callsign);
1227 gr_force_fit_string(p->short_callsign, CALLSIGN_LEN - 1, max_width);
1228 gr_get_string_size( &(p->short_callsign_width), NULL, p->short_callsign );
1231 // pick a random image for the passed player
1232 void pilot_set_random_pic(player *p)
1234 // if there are no available pilot pics, set the image filename to null
1235 if (Num_pilot_images <= 0) {
1236 strcpy(p->image_filename, "");
1238 // pick a random name from the list
1239 int random_index = rand() % Num_pilot_images;
1240 Assert((random_index >= 0) && (random_index < Num_pilot_images));
1241 strcpy(p->image_filename, Pilot_images_arr[random_index]);
1245 // pick a random image for the passed player
1246 void pilot_set_random_squad_pic(player *p)
1248 // if there are no available pilot pics, set the image filename to null
1249 if (Num_pilot_squad_images <= 0) {
1250 player_set_squad_bitmap(p, "");
1251 // strcpy(p->squad_filename, "");
1253 // pick a random name from the list
1254 int random_index = rand() % Num_pilot_squad_images;
1255 Assert((random_index >= 0) && (random_index < Num_pilot_squad_images));
1256 player_set_squad_bitmap(p, Pilot_squad_images_arr[random_index]);
1257 // strcpy(p->squad_filename, Pilot_squad_images_arr[random_index]);
1261 // format a pilot's callsign into a "personal" form - ie, adding a 's or just an ' as appropriate
1262 void pilot_format_callsign_personal(char *in_callsign,char *out_callsign)
1264 // don't do anything if we've got invalid strings
1265 if((in_callsign == NULL) || (out_callsign == NULL)){
1269 // copy the original string
1270 strcpy(out_callsign,in_callsign);
1272 // tack on the appropriate postfix
1273 if(in_callsign[strlen(in_callsign) - 1] == 's'){
1274 strcat(out_callsign,XSTR( "\'", 45));
1276 strcat(out_callsign,XSTR( "\'s", 46));
1280 // throw up a popup asking the user to verify the overwrite of an existing pilot name
1281 // 1 == ok to overwrite, 0 == not ok
1282 int pilot_verify_overwrite()
1284 return popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_RED | PF_TITLE_BIG, 2, XSTR( "&No", 47), XSTR( "&Yes", 48), XSTR( "Warning\nA duplicate pilot exists\nOverwrite?", 49));
1287 extern int Skip_packfile_search; // located in CFileList.cpp
1290 // load up the list of pilot image filenames (do this at game startup as well as barracks startup)
1291 void pilot_load_pic_list()
1293 Num_pilot_images = 0;
1295 // load pilot images from the player images directory
1296 Num_pilot_images = cf_get_file_list_preallocated(MAX_PILOT_IMAGES, Pilot_images_arr, Pilot_image_names, CF_TYPE_PLAYER_IMAGES_MAIN, NOX("*.pcx"));
1298 // sort all filenames
1299 cf_sort_filenames(Num_pilot_images, Pilot_image_names, CF_SORT_NAME);
1302 // load up the list of pilot squad filenames
1303 void pilot_load_squad_pic_list()
1305 Num_pilot_squad_images = 0;
1307 // load pilot images from the player images directory
1308 Num_pilot_squad_images = cf_get_file_list_preallocated(MAX_PILOT_IMAGES, Pilot_squad_images_arr, Pilot_squad_image_names, CF_TYPE_SQUAD_IMAGES_MAIN, NOX("*.pcx"));
1310 // sort all filenames
1311 cf_sort_filenames(Num_pilot_squad_images, Pilot_squad_image_names, CF_SORT_NAME);
1314 // will attempt to load an insignia bitmap and set it as active for the player
1315 void player_set_squad_bitmap(player *p, char *fname)
1322 // if he has another bitmap already - unload it
1323 if(p->insignia_texture >= 0){
1324 bm_unload(p->insignia_texture);
1327 p->insignia_texture = -1;
1329 // try and set the new one
1330 strncpy(p->squad_filename, fname, MAX_FILENAME_LEN);
1331 if(strlen(p->squad_filename) > 0){
1332 p->insignia_texture = bm_load_duplicate(fname);
1334 // lock is as a transparent texture
1335 if(p->insignia_texture != -1){
1336 bm_lock(p->insignia_texture, 16, BMP_TEX_XPARENT);
1337 bm_unlock(p->insignia_texture);
1342 flen = strlen(filename);
1344 Assert(flen < MAX_PATH_LEN);
1345 strcpy(path, filename);
1346 if ((flen < 4) || stricmp(path + flen - elen, ext)) {
1347 Assert(flen + elen < MAX_PATH_LEN);
1354 void player_set_squad(player *p, char *squad_name)
1361 strncpy(p->squad_name, squad_name, NAME_LENGTH+1);
1364 DCF(pilot,"Changes pilot stats. (Like reset campaign)" )
1367 dc_get_arg(ARG_STRING);
1368 if (!strcmp(Dc_arg, NOX("reset"))) {
1369 if (strlen(Campaign.filename)) {
1370 mission_campaign_savefile_delete(Campaign.filename);
1371 mission_campaign_load(Campaign.filename);
1375 Dc_help = 1; // print usage, not stats
1380 dc_printf( "Usage: pilot keyword\nWhere keyword can be in the following forms:\n" );
1381 dc_printf( "pilot reset Resets campaign stats.\n" );
1382 Dc_status = 0; // don't print status if help is printed. Too messy.