2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Playerman/ManagePilot.cpp $
15 * ManagePilot.cpp has code to load and save pilot files, and to select and
19 * Revision 1.6 2004/07/04 11:41:24 taylor
20 * warning fixes, cross platform pilot compat with OSX-Linux-Windows
22 * Revision 1.5 2003/05/25 02:30:43 taylor
25 * Revision 1.4 2002/06/09 04:41:25 relnev
26 * added copyright header
28 * Revision 1.3 2002/06/09 03:16:05 relnev
31 * removed unneeded asm, old sdl 2d setup.
33 * fixed crash caused by opengl_get_region.
35 * Revision 1.2 2002/05/07 03:16:50 theoddone33
36 * The Great Newline Fix
38 * Revision 1.1.1.1 2002/05/03 03:28:11 root
42 * 41 9/13/99 4:52p Dave
45 * 40 9/01/99 10:09a Dave
48 * 39 8/26/99 8:49p Jefff
49 * old player file compatibility with new medal stuff
51 * 38 8/22/99 5:53p Dave
52 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
53 * instead of ship designations for multiplayer players.
55 * 37 8/16/99 4:06p Dave
56 * Big honking checkin.
58 * 36 8/11/99 11:36a Jefff
59 * added compatibility w/ fs2 demo plr version
61 * 35 8/10/99 3:46p Jefff
62 * changes for Intelligence section of new tech room
64 * 34 8/04/99 11:38p Andsager
65 * make new pilot detail level match registry info.
67 * 33 8/02/99 9:55p Dave
68 * Hardcode a nice hud color config for the demo.
70 * 32 8/02/99 9:13p Dave
73 * 31 8/01/99 12:39p Dave
74 * Added HUD contrast control key (for nebula).
76 * 30 7/30/99 10:31p Dave
77 * Added comm menu to the configurable hud files.
79 * 29 7/29/99 10:47p Dave
80 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
82 * 28 7/29/99 12:05a Dave
83 * Nebula speed optimizations.
85 * 27 7/24/99 1:54p Dave
86 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
89 * 26 6/22/99 7:03p Dave
90 * New detail options screen.
92 * 25 6/16/99 4:06p Dave
93 * New pilot info popup. Added new draw-bitmap-as-poly function.
95 * 24 6/11/99 11:13a Dave
96 * last minute changes before press tour build.
98 * 23 6/08/99 1:14a Dave
99 * Multi colored hud test.
101 * 22 5/03/99 8:33p Dave
102 * New version of multi host options screen.
104 * 21 3/24/99 4:05p Dave
105 * Put in support for assigning the player to a specific squadron with a
106 * specific logo. Preliminary work for doing pos/orient checksumming in
107 * multiplayer to reduce bandwidth.
109 * 20 1/30/99 1:29a Dave
110 * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
111 * screen. Fixed beam weapon death messages.
113 * 19 1/29/99 2:08a Dave
114 * Fixed beam weapon collisions with players. Reduced size of scoring
115 * struct for multiplayer. Disabled PXO.
117 * 18 1/21/99 2:06p Dave
118 * Final checkin for multiplayer testing.
120 * 17 1/15/99 2:49p Dave
121 * Fixed creation of pilots.
123 * 16 1/14/99 6:06p Dave
124 * 100% full squad logo support for single player and multiplayer.
126 * 15 1/12/99 3:15a Dave
127 * Barracks screen support for selecting squad logos. We need real artwork
130 * 14 1/06/99 2:24p Dave
131 * Stubs and release build fixes.
133 * 13 12/14/98 12:13p Dave
134 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
137 * 12 11/20/98 11:16a Dave
138 * Fixed up IPX support a bit. Making sure that switching modes and
139 * loading/saving pilot files maintains proper state.
141 * 11 11/19/98 4:51p Dave
142 * Ignore multiplayer protocol settings in the pilot file for now.
144 * 10 11/19/98 4:19p Dave
145 * Put IPX sockets back in psnet. Consolidated all multiplayer config
148 * 9 10/13/98 2:47p Andsager
149 * Remove reference to Tech_shivan_species_avail
151 * 8 10/13/98 9:29a Dave
152 * Started neatening up freespace.h. Many variables renamed and
153 * reorganized. Added AlphaColors.[h,cpp]
155 * 7 10/12/98 9:30a Andsager
156 * Clean up barracks.cpp. Remove unneeded ".h" files from ManagePilot
158 * 6 10/09/98 5:17p Andsager
159 * move barracks screen into barracks.cpp
161 * 5 10/09/98 2:57p Dave
162 * Starting splitting up OS stuff.
164 * 4 10/08/98 9:19a Andsager
165 * Clean up pilot player read and write, starting with new version.
167 * 3 10/07/98 6:27p Dave
168 * Globalized mission and campaign file extensions. Removed Silent Threat
169 * special code. Moved \cache \players and \multidata into the \data
172 * 2 10/07/98 10:53a Dave
175 * 1 10/07/98 10:50a Dave
177 * 279 9/21/98 10:02p Dave
178 * Last minute changes to techroom weapon/ship/species stuff.
180 * 278 9/08/98 12:10p Andsager
181 * Fixed a bug with saving ship and weapon info techroom flags.
183 * 277 9/01/98 4:25p Dave
184 * Put in total (I think) backwards compatibility between mission disk
185 * freespace and non mission disk freespace, including pilot files and
186 * campaign savefiles.
188 * 276 6/09/98 10:31a Hoffoss
189 * Created index numbers for all xstr() references. Any new xstr() stuff
190 * added from here on out should be added to the end if the list. The
191 * current list count can be found in FreeSpace.cpp (search for
194 * 275 6/05/98 9:49a Lawrance
197 * 274 6/01/98 11:43a John
198 * JAS & MK: Classified all strings for localization.
200 * 273 5/26/98 11:53a Allender
201 * fix multiplayer problems and sexpression crash
203 * 272 5/24/98 2:46p Lawrance
204 * Fix bug where skill level would be reset to default when switching
207 * 271 5/23/98 4:02p Allender
210 * 270 5/23/98 2:41p Mike
211 * Make Easy the default skill level and prevent old pilot's skill level
212 * from carrying into new pilot.
217 #include "managepilot.h"
219 #include "freespace.h"
220 #include "hudsquadmsg.h"
223 #include "eventmusic.h"
224 #include "audiostr.h"
225 #include "osregistry.h"
227 #include "playermenu.h"
228 #include "missionshipchoice.h"
229 #include "hudconfig.h"
231 #include "redalert.h"
232 #include "techmenu.h"
235 #include "cutscenes.h"
239 // update this when altering data that is read/written to .PLR file
240 #if defined(FS2_DEMO)
241 #define CURRENT_PLAYER_FILE_VERSION 136 // 1.10
242 #define PREVIOUS_PLAYER_FILE_VERSION 135 // 1.00
244 #define LOWEST_COMPATIBLE_PLAYER_FILE_VERSION PREVIOUS_PLAYER_FILE_VERSION
245 #elif defined(FS1_DEMO)
246 #define CURRENT_PLAYER_FILE_VERSION 94 // 1.20
247 #define PREVIOUS_PLAYER_FILE_VERSION 86 // 1.00
249 #define LOWEST_COMPATIBLE_PLAYER_FILE_VERSION PREVIOUS_PLAYER_FILE_VERSION
250 #elif defined(MAKE_FS1)
251 #define CURRENT_PLAYER_FILE_VERSION 100 // 1.04
252 #define PREVIOUS_PLAYER_FILE_VERSION 99 // 1.00
254 #define LOWEST_COMPATIBLE_PLAYER_FILE_VERSION PREVIOUS_PLAYER_FILE_VERSION
256 #define CURRENT_PLAYER_FILE_VERSION 140 // 1.00
258 #define LOWEST_COMPATIBLE_PLAYER_FILE_VERSION CURRENT_PLAYER_FILE_VERSION // demo plr files should work in final
261 // keep track of pilot file changes here
262 // version 2 : Added squad logo filename
263 // version 3 : Changed size of scoring struct. use ushort instead of ints for storing alltime kills by ship type
264 // version 4/5 : Added squadron name field
265 // version 6 : changed max length on a multiplayer options field
266 // version 130 : changed size of hud config struct
267 // version 133 : misc changes. new hud gauge
268 // version 134 : added HUD contrast toggle key
269 // version 135 : added tips flag (THIS IS THE DEMO VERSION - RETAIN COMPATIBILITY FROM HERE ON OUT)
270 // version 136 : added intelligence flags to tech room visibility data
271 // version 137 : 2 new HUD gauges.
272 // version 138 : new multiplayer config
273 // version 139 : # medals increased - added compatibility with old plr file versions
274 // version 140 : ships table reordered. clear out old pilot files
275 // search for PLAYER INIT for new pilot initialization stuff. I _think_ its in the right spot for now
276 #define PLR_FILE_ID 0x46505346 // FPSF, unique signiture to identify a .PLR file (FreeSpace Player File) // FPSF appears as FSPF in file.
279 #define PLR_MAX_SHIP_TYPES_OLD 75
280 #define PLR_MAX_WEAPON_TYPES_OLD 44
282 extern void hud_config_set_color(int color);
285 // Current content of a .PLR file
291 // pilot pic image list stuff ( call pilot_load_pic_list() to make these valid )
292 char Pilot_images_arr[MAX_PILOT_IMAGES][MAX_FILENAME_LEN];
293 char *Pilot_image_names[MAX_PILOT_IMAGES];
294 int Num_pilot_images = 0;
296 // squad logo list stuff (call pilot_load_squad_pic_list() to make these valid )
297 char Pilot_squad_images_arr[MAX_PILOT_IMAGES][MAX_FILENAME_LEN];
298 char *Pilot_squad_image_names[MAX_PILOT_IMAGES];
299 int Num_pilot_squad_images = 0;
301 static uint Player_file_version;
303 // forward declarations
304 void read_detail_settings(CFILE *file, int Player_file_version);
305 void write_detail_settings(CFILE *file);
306 void read_stats_block(CFILE *file, int Player_file_version, scoring_struct *stats);
307 void write_stats_block(CFILE *file, scoring_struct *stats);
308 void read_multiplayer_options(player *p,CFILE *file);
309 void write_multiplayer_options(player *p,CFILE *file);
311 static SDL_Keycode keycode_translate_from(short keycode);
312 static short keycode_translate_to(SDL_Keycode keycode);
314 // internal function to delete a player file. Called after a pilot is obsoleted, and when a pilot is deleted
315 // used in barracks and player_select
316 void delete_pilot_file( const char *pilot_name, int single )
318 char filename[MAX_FILENAME_LEN];
319 char basename[MAX_FILENAME_LEN];
321 // get the player file.
323 base_filename(pilot_name, basename, SDL_arraysize(basename));
325 SDL_strlcpy( filename, basename, SDL_arraysize(filename) );
326 SDL_strlcat(filename, NOX(".plr"), SDL_arraysize(filename) );
327 if (Player_sel_mode == PLAYER_SELECT_MODE_SINGLE){
328 cf_delete(filename, CF_TYPE_SINGLE_PLAYERS);
330 cf_delete(filename, CF_TYPE_MULTI_PLAYERS);
333 // we must try and delete the campaign save files for a pilot as well.
334 mission_campaign_delete_all_savefiles( basename, !single );
337 // check if a pilot file is valid or not (i.e. is usable, not out of date, etc)
338 // used in barracks and player_select
339 int verify_pilot_file(const char *filename, int single, int *rank)
342 uint id, file_version;
345 filename = cf_add_ext(filename, NOX(".plr"));
348 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
350 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
357 id = cfread_uint(file);
358 if (id != PLR_FILE_ID) {
359 nprintf(("Warning", "Player file has invalid signature\n"));
361 delete_pilot_file( filename, single );
365 // check for compatibility here
366 file_version = cfread_uint(file);
367 /* if (file_version < INITIAL_RELEASE_FILE_VERSION) { */
368 // if (file_version != CURRENT_PLAYER_FILE_VERSION) {
369 if (file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
370 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
372 delete_pilot_file( filename, single );
376 type = !cfread_ubyte(file);
382 *rank = cfread_int(file);
395 void pilot_write_techroom_data(CFILE *file)
405 for (idx = 0; idx < Num_ship_types; idx++) {
406 if (Ship_info[idx].flags & SIF_IN_TECH_DATABASE) {
411 cfwrite_int(flags, file);
413 // weapons - first set
416 for (idx = 0; (idx < 32) && (idx < Num_weapon_types); idx++) {
417 if (Weapon_info[idx].wi_flags & WIF_IN_TECH_DATABASE) {
422 cfwrite_int(flags, file);
424 // weapons - second set
427 for (idx = 32; idx < Num_weapon_types; idx++) {
428 if (Weapon_info[idx].wi_flags & WIF_IN_TECH_DATABASE) {
429 flags |= 1<<(idx-32);
433 cfwrite_int(flags, file);
437 // write the ship and weapon count
438 cfwrite_int(Num_ship_types, file);
439 cfwrite_int(Num_weapon_types, file);
441 cfwrite_int(Intel_info_size, file);
444 // write all ship flags out
445 for (idx=0; idx<Num_ship_types; idx++) {
446 out = (Ship_info[idx].flags & SIF_IN_TECH_DATABASE) ? (ubyte)1 : (ubyte)0;
447 cfwrite_ubyte(out, file);
450 // write all weapon types out
451 for (idx=0; idx<Num_weapon_types; idx++) {
452 out = (Weapon_info[idx].wi_flags & WIF_IN_TECH_DATABASE) ? (ubyte)1 : (ubyte)0;
453 cfwrite_ubyte(out, file);
458 // write all intel entry flags out
459 for (idx=0; idx<Intel_info_size; idx++) {
460 cfwrite_ubyte((ubyte)Intel_info[idx].in_tech_db, file);
463 // whether shivans are visible or not
464 int shivans = Intel_info[2].in_tech_db ? 1 : 0;
465 cfwrite_int(shivans, file);
470 void pilot_read_techroom_data(CFILE *file)
473 int ship_count, weapon_count, shivans;
476 if (Player_file_version < 100) {
479 // first set of ships visible
480 vflags = cfread_int(file);
482 for (idx = 0; idx < 32; idx++) {
483 if ( (vflags & (1<<idx)) && (idx < Num_ship_types) ) {
484 Ship_info[idx].flags |= SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M;
485 } else if (idx < Num_ship_types) {
486 Ship_info[idx].flags &= ~SIF_IN_TECH_DATABASE;
491 // second set of ships visible
492 vflags = cfread_int(file);
494 for (idx = 0; idx < 32; idx++) {
495 if ( (vflags & (1<<idx)) && ((idx+32) < Num_ship_types) ) {
496 Ship_info[idx+32].flags |= SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M;
497 } else if ((idx+32) < Num_ship_types) {
498 Ship_info[idx+32].flags &= ~SIF_IN_TECH_DATABASE;
502 // last set of ships visible
503 vflags = cfread_int(file);
505 for (idx = 0; idx < 32; idx++) {
506 if ( (vflags & (1<<idx)) && ((idx+64) < Num_ship_types) ) {
507 Ship_info[idx+64].flags |= SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M;
508 } else if ((idx+64) < Num_ship_types) {
509 Ship_info[idx+64].flags &= ~SIF_IN_TECH_DATABASE;
514 // first set of weapons visible
515 vflags = cfread_int(file);
517 for (idx = 0; idx < 32; idx++) {
518 if ( (vflags & (1<<idx)) && (idx < Num_weapon_types) ) {
519 Weapon_info[idx].wi_flags |= WIF_IN_TECH_DATABASE;
520 } else if (idx < Num_weapon_types) {
521 Weapon_info[idx].wi_flags &= ~WIF_IN_TECH_DATABASE;
525 // last set of weapons visible
526 vflags = cfread_int(file);
528 for (idx = 0; idx < 32; idx++) {
529 if ( (vflags & (1<<idx)) && ((idx+32) < Num_weapon_types) ) {
530 Weapon_info[idx+32].wi_flags |= WIF_IN_TECH_DATABASE;
531 } else if ((idx+32) < Num_weapon_types) {
532 Weapon_info[idx+32].wi_flags &= ~WIF_IN_TECH_DATABASE;
537 shivans = cfread_int(file);
540 Intel_info[2].in_tech_db = 1;
542 Intel_info[2].in_tech_db = 0;
545 // read in ship and weapon counts
546 ship_count = cfread_int(file);
547 weapon_count = cfread_int(file);
548 SDL_assert(ship_count <= MAX_SHIP_TYPES);
549 SDL_assert(weapon_count <= MAX_WEAPON_TYPES);
552 for (idx=0; idx<ship_count; idx++) {
553 in = cfread_ubyte(file);
555 Ship_info[idx].flags |= SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M;
557 Ship_info[idx].flags &= ~SIF_IN_TECH_DATABASE;
561 // read all weapons in
562 for (idx=0; idx<weapon_count; idx++) {
563 in = cfread_ubyte(file);
565 Weapon_info[idx].wi_flags |= WIF_IN_TECH_DATABASE;
567 Weapon_info[idx].wi_flags &= ~WIF_IN_TECH_DATABASE;
572 shivans = cfread_int(file);
575 Intel_info[2].in_tech_db = 1;
577 Intel_info[2].in_tech_db = 0;
582 void pilot_read_techroom_data(CFILE *file)
585 int ship_count, weapon_count, intel_count;
588 // read in ship and weapon counts
589 ship_count = cfread_int(file);
590 weapon_count = cfread_int(file);
591 SDL_assert(ship_count <= MAX_SHIP_TYPES);
592 SDL_assert(weapon_count <= MAX_WEAPON_TYPES);
594 // maintain compatibility w/ demo version
595 if (Player_file_version < 136) {
596 // skip over all this data, because the lack of tech room in the demo
597 // left this all hosed in the demo .plr files
598 // this will all get initialized as if this fella was a new pilot
599 for (idx=0; idx<ship_count+weapon_count; idx++) {
605 intel_count = cfread_int(file);
606 SDL_assert(intel_count <= MAX_INTEL_ENTRIES);
609 for (idx=0; idx<ship_count; idx++) {
610 in = cfread_ubyte(file);
612 Ship_info[idx].flags |= SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M;
614 Ship_info[idx].flags &= ~SIF_IN_TECH_DATABASE;
618 // read all weapons in
619 for (idx=0; idx<weapon_count; idx++) {
620 in = cfread_ubyte(file);
622 Weapon_info[idx].wi_flags |= WIF_IN_TECH_DATABASE;
624 Weapon_info[idx].wi_flags &= ~WIF_IN_TECH_DATABASE;
628 // read all intel entries in
629 for (idx=0; idx<intel_count; idx++) {
630 in = cfread_ubyte(file);
632 Intel_info[idx].in_tech_db = 1;
634 Intel_info[idx].in_tech_db = 0;
641 // write out the player ship selection
642 void pilot_write_loadout(CFILE *file)
647 cfwrite_string_len(Player_loadout.filename, file);
648 cfwrite_string_len(Player_loadout.last_modified, file);
652 for ( i = 0; i < MAX_SHIP_TYPES; i++ ) {
653 cfwrite_int(Player_loadout.ship_pool[i], file);
656 // write weapons pool
657 for ( i = 0; i < MAX_WEAPON_TYPES; i++ ) {
658 cfwrite_int(Player_loadout.weapon_pool[i], file);
661 // write ship and weapon counts
662 cfwrite_int(Num_ship_types, file);
663 cfwrite_int(Num_weapon_types, file);
666 for ( i = 0; i < Num_ship_types; i++ ) {
667 cfwrite_int(Player_loadout.ship_pool[i], file);
670 // write weapons pool
671 for ( i = 0; i < Num_weapon_types; i++ ) {
672 cfwrite_int(Player_loadout.weapon_pool[i], file);
676 // write ship loadouts
677 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
678 slot = &Player_loadout.unit_data[i];
679 cfwrite_int(slot->ship_class, file);
680 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
681 cfwrite_int(slot->wep[j], file);
682 cfwrite_int(slot->wep_count[j], file);
687 // read in the ship selection for the pilot
688 void pilot_read_loadout(CFILE *file)
692 int ship_count, weapon_count;
694 memset(Player_loadout.filename, 0, MAX_FILENAME_LEN);
695 cfread_string_len(Player_loadout.filename, MAX_FILENAME_LEN, file);
697 memset(Player_loadout.last_modified, 0, DATE_TIME_LENGTH);
698 cfread_string_len(Player_loadout.last_modified, DATE_TIME_LENGTH, file);
700 // read in ship and weapon counts
701 #if defined(FS1_DEMO)
702 ship_count = MAX_SHIP_TYPES;
703 weapon_count = MAX_WEAPON_TYPES;
704 #elif defined(MAKE_FS1)
705 if (Player_file_version < 100) {
706 ship_count = PLR_MAX_SHIP_TYPES_OLD;
707 weapon_count = PLR_MAX_WEAPON_TYPES_OLD;
709 ship_count = cfread_int(file);
710 weapon_count = cfread_int(file);
713 ship_count = cfread_int(file);
714 weapon_count = cfread_int(file);
717 SDL_assert(ship_count <= MAX_SHIP_TYPES);
718 SDL_assert(weapon_count <= MAX_WEAPON_TYPES);
721 for ( i = 0; i < ship_count; i++ ) {
722 Player_loadout.ship_pool[i] = cfread_int(file);
725 // read in weapons pool
726 for ( i = 0; i < weapon_count; i++ ) {
727 Player_loadout.weapon_pool[i] = cfread_int(file);
730 // read in loadout info
731 for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
732 slot = &Player_loadout.unit_data[i];
733 slot->ship_class = cfread_int(file);
734 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
735 slot->wep[j] = cfread_int(file);
736 slot->wep_count[j] = cfread_int(file);
743 // returns 0 - file read in correctly
744 // -1 - .PLR file doesn't exist or file not compatible
745 // >0 - errno from fopen error
746 // if single == 1, look for players in the single players directory, otherwise look in the
747 // multiplayers directory
748 int read_pilot_file(const char *callsign, int single, player *p)
752 char filename[MAX_FILENAME_LEN], ship_name[NAME_LENGTH];
758 SDL_assert((Player_num >= 0) && (Player_num < MAX_PLAYERS));
759 p = &Players[Player_num];
762 //sprintf(filename, "%-.8s.plr",Players[Player_num].callsign);
763 SDL_assert(strlen(callsign) < MAX_FILENAME_LEN - 4); // ensure we won't overrun the buffer
764 SDL_strlcpy( filename, callsign, SDL_arraysize(filename) );
765 SDL_strlcat( filename, NOX(".plr"), SDL_arraysize(filename) );
767 // if we're a standalone server in multiplayer, just fill in some bogus values since we don't have a pilot file
768 if ((Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER)) {
769 memset(Player, 0, sizeof(player));
770 SDL_strlcpy(Player->callsign, NOX("Standalone"), SDL_arraysize(Player->callsign));
771 SDL_strlcpy(Player->short_callsign, NOX("Standalone"), SDL_arraysize(Player->short_callsign));
775 // see comments at the beginning of function
777 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
779 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
786 id = cfread_uint(file);
787 if (id != PLR_FILE_ID) {
788 Warning(LOCATION, "Player file has invalid signature");
793 // check for compatibility here
794 Player_file_version = cfread_uint(file);
795 cf_set_version( file, Player_file_version );
797 if (Player_file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
798 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
800 delete_pilot_file( filename, single );
804 // read in whether he's a multiplayer or not
805 is_multi = cfread_ubyte(file);
807 p->flags |= PLAYER_FLAGS_IS_MULTI;
809 p->flags &= ~PLAYER_FLAGS_IS_MULTI; // this takes care of unsetting any leftover bits from a (possibly) previously selected pilot
817 // get player location
818 p->on_bastion = cfread_ubyte(file);
822 p->tips = cfread_int(file);
825 // write out the image file name
826 cfread_string_len(p->image_filename, MAX_FILENAME_LEN - 1, file);
828 // write out the image file name
829 p->insignia_texture = -1;
831 cfread_string_len(p->squad_name, NAME_LENGTH, file);
832 cfread_string_len(p->squad_filename, MAX_FILENAME_LEN - 1, file);
833 player_set_squad_bitmap(p, p->squad_filename);
836 // deal with campaign stuff. The way we store the information in the file is to first store the
837 // name of the current campaign that the player is playing. Next we store the info regarding the campaigns
838 // that the player is currently playing
839 memset(p->current_campaign, 0, MAX_FILENAME_LEN);
840 cfread_string_len(p->current_campaign, MAX_FILENAME_LEN, file);
842 // read in the ship name for last ship flown by the player
843 memset(ship_name, 0, NAME_LENGTH);
844 cfread_string_len(ship_name, NAME_LENGTH, file);
845 p->last_ship_flown_si_index = ship_info_lookup(ship_name);
846 if ( p->last_ship_flown_si_index < 0 ) {
847 nprintf(("Warning","WARNING => Ship class %s not located in Ship_info[] in player file\n",ship_name));
848 p->last_ship_flown_si_index = ship_info_lookup(default_player_ship);
851 // set all the entries in the control config arrays to -1 (undefined)
852 control_config_clear();
854 // ---------------------------------------------
855 // read in the keyboard/joystick mapping
856 // ---------------------------------------------
857 num_ctrls = cfread_ubyte(file);
858 for (i=0; i<num_ctrls; i++) {
859 key_value = cfread_short(file);
860 // NOTE: next two lines are only here for transitioning from 255 to -1 as undefined key items
861 if (key_value == 255)
864 Control_config[i].key_id = keycode_translate_from((short)key_value);
866 key_value = cfread_short(file);
867 // NOTE: next two lines are only here for transitioning from 255 to -1 as undefined key items
868 if (key_value == 255)
871 Control_config[i].joy_id = (short) key_value;
874 HUD_config.show_flags = cfread_int(file);
875 HUD_config.show_flags2 = cfread_int(file);
877 HUD_config.popup_flags = cfread_int(file);
878 HUD_config.popup_flags2 = cfread_int(file);
880 HUD_config.num_msg_window_lines = cfread_ubyte(file);
881 HUD_config.rp_flags = cfread_int(file);
882 HUD_config.rp_dist = cfread_int(file);
885 HUD_config.main_color = cfread_int(file);
886 HUD_color_alpha = cfread_int(file);
888 if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MIN ) {
889 HUD_color_alpha = HUD_COLOR_ALPHA_DEFAULT;
892 hud_config_set_color(HUD_config.main_color);
893 #elif defined(FS2_DEMO)
894 for(i=0; i<NUM_HUD_GAUGES; i++){
895 cfread(&HUD_config.clr[i], sizeof(color), 1, file);
898 // added 2 gauges with version 137
899 if(Player_file_version < 137){
900 for(i=0; i<NUM_HUD_GAUGES-2; i++){
901 cfread(&HUD_config.clr[i], sizeof(color), 1, file);
904 // set the 2 new gauges to be radar color
905 memcpy(&HUD_config.clr[NUM_HUD_GAUGES-2], &HUD_config.clr[HUD_RADAR], sizeof(color));
906 memcpy(&HUD_config.clr[NUM_HUD_GAUGES-1], &HUD_config.clr[HUD_RADAR], sizeof(color));
908 for(i=0; i<NUM_HUD_GAUGES; i++){
909 cfread(&HUD_config.clr[i], sizeof(color), 1, file);
915 // read in the cutscenes which have been viewed
916 Cutscenes_viewable = cfread_int(file);
919 Master_sound_volume = cfread_float(file);
920 Master_event_music_volume = cfread_float(file);
921 Master_voice_volume = cfread_float(file);
923 audiostream_set_volume_all(Master_voice_volume, ASF_VOICE);
924 audiostream_set_volume_all(Master_event_music_volume, ASF_EVENTMUSIC);
926 if ( Master_event_music_volume > 0.0f ) {
927 Event_music_enabled = 1;
929 Event_music_enabled = 0;
932 read_detail_settings(file, Player_file_version);
934 // restore list of most recently played missions
935 Num_recent_missions = cfread_int( file );
936 SDL_assert(Num_recent_missions <= MAX_RECENT_MISSIONS);
937 for ( i = 0; i < Num_recent_missions; i++ ) {
940 cfread_string_len( Recent_missions[i], MAX_FILENAME_LEN, file);
941 // Remove the extension
942 c = SDL_strchr(Recent_missions[i], '.');
947 // use this block of stats from now on
948 read_stats_block(file, Player_file_version, &p->stats);
950 Game_skill_level = cfread_int(file);
952 // original axes (4) not bindable, just inverted or not
953 if (Player_file_version < 94) {
954 // heading, pitch, bank, throttle
955 for (i = 0; i < 4; i++) {
956 Invert_axis[i] = cfread_int(file);
959 // throttle and roll axes can be disabled (not supported here)
963 for (i=0; i<NUM_JOY_AXIS_ACTIONS; i++) {
964 Axis_map_to[i] = cfread_int(file);
965 Invert_axis[i] = cfread_int(file);
969 // restore some player flags
970 Player[Player_num].save_flags = cfread_int(file);
972 // restore the most recent ship selection
973 pilot_read_loadout(file);
975 // read in multiplayer options
976 read_multiplayer_options(p,file);
978 p->readyroom_listing_mode = cfread_int(file);
979 Briefing_voice_enabled = cfread_int(file);
981 // restore the default netgame protocol mode
982 int protocol_temp = cfread_int(file);
983 switch(protocol_temp){
986 Multi_options_g.pxo = 1;
987 Multi_options_g.protocol = NET_TCP;
992 Multi_options_g.pxo = 0;
993 Multi_options_g.protocol = NET_TCP;
996 // in case of IPX, which is deprecated
998 Multi_options_g.pxo = 0;
999 Multi_options_g.protocol = NET_TCP;
1003 // restore wingman status used by red alert missions
1004 red_alert_read_wingman_status(file, Player_file_version);
1010 cfread(blank, SDL_arraysize(blank), 1, file);
1013 // read techroom data
1014 pilot_read_techroom_data(file);
1016 // restore auto-advance pref
1017 Player->auto_advance = cfread_int(file);
1019 if (Player_file_version >= 94) {
1020 Use_mouse_to_fly = cfread_int(file);
1021 Mouse_sensitivity = cfread_int(file);
1022 Joy_sensitivity = cfread_int(file);
1023 Dead_zone_size = cfread_int(file);
1029 // restore the callsign into the Player structure
1030 SDL_strlcpy(p->callsign, callsign, SDL_arraysize(p->callsign));
1032 // restore the truncated callsign into Player structure
1033 pilot_set_short_callsign(p, SHORT_CALLSIGN_PIXEL_W);
1035 // when we store the LastPlayer key, we have to mark it as being single or multiplayer, so we know where to look for him
1036 // (since we could have a single and a multiplayer pilot with the same callsign)
1037 // 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
1040 SDL_strlcpy(cat, p->callsign, SDL_arraysize(cat));
1042 SDL_strlcat(cat, NOX("M"), SDL_arraysize(cat));
1044 SDL_strlcat(cat, NOX("S"), SDL_arraysize(cat));
1046 os_config_write_string( NULL, "LastPlayer", cat );
1048 // if he's not a multiplayer pilot, then load in the campaign file at this point!
1050 if (mission_campaign_load_by_name(campaign_fname)) {
1051 strcpy(campaign_fname, BUILTIN_CAMPAIGN);
1052 if (mission_campaign_load_by_name(campaign_fname))
1056 //Campaign.current_mission = mission_num;*/
1058 hud_squadmsg_save_keys(); // when new pilot read in, must save info for squadmate messaging
1063 void read_stats_block(CFILE *file, int file_version, scoring_struct *stats)
1067 init_scoring_element(stats);
1068 stats->score = cfread_int(file);
1069 stats->rank = cfread_int(file);
1070 stats->assists = cfread_int(file);
1073 if (file_version < 139) {
1074 // support for FS2_DEMO pilots that still have FS1 medal info in the .plr files
1075 for (i=0; i < NUM_MEDALS_FS1; i++) {
1076 cfread_int(file); // dummy read
1079 // read the usual way
1080 for (i=0; i < NUM_MEDALS; i++) {
1081 stats->medals[i] = cfread_int(file);
1085 for (i = 0; i < NUM_MEDALS; i++) {
1086 stats->medals[i] = cfread_int(file);
1090 total = cfread_int(file);
1091 if (total > MAX_SHIP_TYPES){
1092 Warning(LOCATION, "Some ship kill information will be lost due to MAX_SHIP_TYPES decrease");
1095 for (i=0; i<total && i<MAX_SHIP_TYPES; i++){
1097 stats->kills[i] = cfread_ushort(file);
1099 stats->kills[i] = cfread_int(file);
1103 stats->kill_count = cfread_int(file);
1104 stats->kill_count_ok = cfread_int(file);
1106 stats->p_shots_fired = cfread_uint(file);
1107 stats->s_shots_fired = cfread_uint(file);
1108 stats->p_shots_hit = cfread_uint(file);
1109 stats->s_shots_hit = cfread_uint(file);
1111 stats->p_bonehead_hits = cfread_uint(file);
1112 stats->s_bonehead_hits = cfread_uint(file);
1113 stats->bonehead_kills = cfread_uint(file);
1116 // grab the various detail settings
1117 void read_detail_settings(CFILE *file, int pfile_version)
1119 detail_level_set(NUM_DEFAULT_DETAIL_LEVELS-1);
1122 Detail.setting = cfread_int(file);
1124 Detail.nebula_detail = cfread_int(file);
1125 Detail.detail_distance = cfread_int(file);
1127 Detail.weapon_detail = cfread_int(file);
1129 Detail.hardware_textures = cfread_int(file);
1130 Detail.num_small_debris = cfread_int(file);
1131 Detail.num_particles = cfread_int(file);
1132 Detail.num_stars = cfread_int(file);
1133 Detail.shield_effects = cfread_int(file);
1134 Detail.lighting = cfread_int(file);
1136 Detail.unknown_slider = cfread_int(file);
1140 Detail.targetview_model = cfread_int(file);
1141 Detail.planets_suns = cfread_int(file);
1143 Detail.unknown_boolean1 = cfread_int(file);
1144 Detail.unknown_boolean2 = cfread_int(file);
1145 Detail.engine_glows = cfread_int(file);
1146 Detail.alpha_effects = cfread_int(file);
1148 Detail.weapon_extras = cfread_int(file);
1152 // Will write the pilot file in the most current format
1154 // if single == 1, save into the single players directory, else save into the multiplayers directory
1155 int write_pilot_file_core(player *p)
1157 char filename[MAX_FILENAME_LEN + 1];
1162 // never save a pilot file for the standalone server in multiplayer
1163 if ((Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER)) {
1168 SDL_assert((Player_num >= 0) && (Player_num < MAX_PLAYERS));
1169 p = &Players[Player_num];
1172 i = strlen(p->callsign);
1174 return 0; // This means there is no player, probably meaning he was deleted and game exited from same screen.
1176 SDL_assert((i > 0) && (i <= MAX_FILENAME_LEN - 4)); // ensure we won't overrun the buffer
1177 SDL_strlcpy( filename, p->callsign, SDL_arraysize(filename));
1178 SDL_strlcat( filename, NOX(".plr"), SDL_arraysize(filename) );
1180 // determine if this pilot is a multiplayer pilot or not
1181 if (p->flags & PLAYER_FLAGS_IS_MULTI){
1189 file = cfopen(filename, "wb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
1191 file = cfopen(filename, "wb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
1198 // Write out player's info
1199 cfwrite_uint(PLR_FILE_ID, file);
1200 cfwrite_uint(CURRENT_PLAYER_FILE_VERSION, file);
1202 cfwrite_ubyte(is_multi, file);
1204 cfwrite_int(p->stats.rank, file);
1206 cfwrite_ubyte((ubyte) p->on_bastion, file);
1209 cfwrite_int(p->tips, file);
1212 // write out the image file name
1213 cfwrite_string_len(p->image_filename, file);
1216 // write out the image file name
1217 cfwrite_string_len(p->squad_name, file);
1218 cfwrite_string_len(p->squad_filename, file);
1221 // write out the name of the player's active campaign.
1222 cfwrite_string_len(p->current_campaign, file);
1224 // write the ship name for last ship flown by the player
1225 si_index = p->last_ship_flown_si_index;
1226 if((si_index < 0) || (si_index >= Num_ship_types)){
1230 cfwrite_string_len(Ship_info[si_index].name, file);
1232 // ---------------------------------------------
1233 // write the keyboard/joystick configuration
1234 // ---------------------------------------------
1236 cfwrite_ubyte( CCFG_MAX, file );
1237 for (i=0; i<CCFG_MAX; i++) {
1238 key_id = keycode_translate_to(Control_config[i].key_id);
1239 cfwrite_short( key_id, file );
1240 cfwrite_short( Control_config[i].joy_id, file );
1243 // if this hud is an observer, the player ended the last mission as an observer, so we should
1244 // restore his "real" ship HUD.
1245 HUD_CONFIG_TYPE hc_temp;
1246 hc_temp.show_flags = 0;
1247 int stored_observer = 0;
1248 if ( HUD_config.is_observer ){
1249 // if we're in mission, copy the HUD we're currently using
1250 if(Game_mode & GM_IN_MISSION){
1251 memcpy(&hc_temp,&HUD_config,sizeof(HUD_CONFIG_TYPE));
1252 stored_observer = 1;
1255 hud_config_restore();
1258 // write the hud configuration
1259 cfwrite_int(HUD_config.show_flags, file);
1260 cfwrite_int(HUD_config.show_flags2, file);
1261 cfwrite_int(HUD_config.popup_flags, file);
1262 cfwrite_int(HUD_config.popup_flags2, file);
1263 cfwrite_ubyte( (ubyte) HUD_config.num_msg_window_lines, file );
1264 cfwrite_int( HUD_config.rp_flags, file );
1265 cfwrite_int( HUD_config.rp_dist, file );
1268 cfwrite_int( HUD_config.main_color, file );
1269 cfwrite_int( HUD_color_alpha, file );
1271 for(i=0; i<NUM_HUD_GAUGES; i++){
1272 cfwrite(&HUD_config.clr[i], sizeof(color), 1, file);
1276 // restore the HUD we backed up
1277 if( (Game_mode & GM_IN_MISSION) && stored_observer ){
1278 memcpy(&HUD_config,&hc_temp,sizeof(HUD_CONFIG_TYPE));
1282 // write the cutscenes which have been viewed
1283 cfwrite_int(Cutscenes_viewable, file);
1286 // store the digital sound fx volume, and music volume
1287 cfwrite_float(Master_sound_volume, file);
1288 cfwrite_float(Master_event_music_volume, file);
1289 cfwrite_float(Master_voice_volume, file);
1292 //cfwrite( &Detail, sizeof(detail_levels), 1, file );
1293 write_detail_settings(file);
1295 // store list of most recently played missions
1296 cfwrite_int(Num_recent_missions, file);
1297 for (i=0; i<Num_recent_missions; i++) {
1298 cfwrite_string_len(Recent_missions[i], file);
1301 // write the player stats
1302 write_stats_block(file, &p->stats);
1303 cfwrite_int(Game_skill_level, file);
1305 for (i=0; i<NUM_JOY_AXIS_ACTIONS; i++) {
1306 cfwrite_int(Axis_map_to[i], file);
1307 cfwrite_int(Invert_axis[i], file);
1310 // store some player flags
1311 cfwrite_int(Player->save_flags, file);
1313 // store ship selection for most recent mission
1314 pilot_write_loadout(file);
1316 // read in multiplayer options
1317 write_multiplayer_options(p, file);
1319 cfwrite_int(p->readyroom_listing_mode, file);
1320 cfwrite_int(Briefing_voice_enabled, file);
1322 // store the default netgame protocol mode for this pilot
1323 SDL_assert(Multi_options_g.protocol == NET_TCP);
1324 if (Multi_options_g.pxo == 1) {
1325 cfwrite_int(NET_VMT, file);
1327 cfwrite_int(NET_TCP, file);
1330 red_alert_write_wingman_status(file);
1335 cfwrite(blank, SDL_arraysize(blank), 1, file);
1337 pilot_write_techroom_data(file);
1339 // store auto-advance pref
1340 cfwrite_int(Player->auto_advance, file);
1342 cfwrite_int(Use_mouse_to_fly, file);
1343 cfwrite_int(Mouse_sensitivity, file);
1344 cfwrite_int(Joy_sensitivity, file);
1345 cfwrite_int(Dead_zone_size, file);
1353 static player *callback_player = NULL;
1354 static void error_writing_callback(int choice)
1360 write_pilot_file(callback_player);
1361 } else if (choice == 1) {
1369 void write_pilot_file(player *the_player)
1371 // save for later, in case of a retry
1372 callback_player = the_player;
1374 // write_pilot_file_core returns 0 if ok, non-zero for error
1375 int rval = write_pilot_file_core(the_player);
1377 // check with user if write not successful
1379 popup_callback(error_writing_callback, PF_TITLE_RED | PF_TITLE_BIG, 3, XSTR( "&Retry", 41), XSTR( "&Ignore", 42), XSTR( "&Quit Game", 43),
1380 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) );
1384 void write_stats_block(CFILE *file,scoring_struct *stats)
1389 cfwrite_int(stats->score, file);
1390 cfwrite_int(stats->rank, file);
1391 cfwrite_int(stats->assists, file);
1392 for (i=0; i<NUM_MEDALS; i++){
1393 cfwrite_int(stats->medals[i], file);
1396 total = MAX_SHIP_TYPES;
1397 while (total && !stats->kills[total - 1]){ // find last used element
1401 cfwrite_int(total, file);
1402 for (i=0; i<total; i++){
1404 cfwrite_ushort(stats->kills[i], file);
1406 cfwrite_int(stats->kills[i], file);
1410 cfwrite_int(stats->kill_count,file);
1411 cfwrite_int(stats->kill_count_ok,file);
1413 cfwrite_uint(stats->p_shots_fired,file);
1414 cfwrite_uint(stats->s_shots_fired,file);
1415 cfwrite_uint(stats->p_shots_hit,file);
1416 cfwrite_uint(stats->s_shots_hit,file);
1417 cfwrite_uint(stats->p_bonehead_hits,file);
1418 cfwrite_uint(stats->s_bonehead_hits,file);
1419 cfwrite_uint(stats->bonehead_kills,file);
1422 // write the various detail settings
1423 void write_detail_settings(CFILE *file)
1425 cfwrite_int(Detail.setting, file);
1427 cfwrite_int(Detail.nebula_detail, file);
1428 cfwrite_int(Detail.detail_distance, file);
1430 cfwrite_int(Detail.weapon_detail, file);
1432 cfwrite_int(Detail.hardware_textures, file);
1433 cfwrite_int(Detail.num_small_debris, file);
1434 cfwrite_int(Detail.num_particles, file);
1435 cfwrite_int(Detail.num_stars, file);
1436 cfwrite_int(Detail.shield_effects, file);
1437 cfwrite_int(Detail.lighting, file);
1439 cfwrite_int(Detail.unknown_slider, file);
1442 cfwrite_int(Detail.targetview_model, file);
1443 cfwrite_int(Detail.planets_suns, file);
1445 cfwrite_int(Detail.unknown_boolean1, file);
1446 cfwrite_int(Detail.unknown_boolean2, file);
1447 cfwrite_int(Detail.engine_glows, file);
1448 cfwrite_int(Detail.alpha_effects, file);
1450 cfwrite_int(Detail.weapon_extras, file);
1454 // write multiplayer information
1455 void write_multiplayer_options(player *p,CFILE *file)
1457 // write the netgame options
1458 cfwrite_ubyte(p->m_server_options.squad_set,file);
1459 cfwrite_ubyte(p->m_server_options.endgame_set,file);
1460 cfwrite_int(p->m_server_options.flags,file);
1461 cfwrite_uint(p->m_server_options.respawn,file);
1462 cfwrite_ubyte(p->m_server_options.max_observers,file);
1463 cfwrite_ubyte(p->m_server_options.skill_level,file);
1464 cfwrite_ubyte(p->m_server_options.voice_qos,file);
1465 cfwrite_int(p->m_server_options.voice_token_wait,file);
1466 cfwrite_int(p->m_server_options.voice_record_time,file);
1467 cfwrite(&p->m_server_options.mission_time_limit,sizeof(fix),1,file);
1468 cfwrite_int(p->m_server_options.kill_limit,file);
1470 // write the local options
1471 cfwrite_int(p->m_local_options.flags,file);
1472 cfwrite_int(p->m_local_options.obj_update_level,file);
1475 // read multiplayer options
1476 void read_multiplayer_options(player *p,CFILE *file)
1478 // read the netgame options
1479 p->m_server_options.squad_set = cfread_ubyte(file);
1480 p->m_server_options.endgame_set = cfread_ubyte(file);
1481 p->m_server_options.flags = cfread_int(file);
1482 p->m_server_options.respawn = cfread_uint(file);
1483 p->m_server_options.max_observers = cfread_ubyte(file);
1484 p->m_server_options.skill_level = cfread_ubyte(file);
1485 p->m_server_options.voice_qos = cfread_ubyte(file);
1486 p->m_server_options.voice_token_wait = cfread_int(file);
1487 p->m_server_options.voice_record_time = cfread_int(file);
1488 cfread(&p->m_server_options.mission_time_limit,sizeof(fix),1,file);
1489 p->m_server_options.kill_limit = cfread_int(file);
1491 // read the local options
1492 p->m_local_options.flags = cfread_int(file);
1493 p->m_local_options.obj_update_level = cfread_int(file);
1496 // run thorough an open file (at the beginning) and see if this pilot is a multiplayer pilot
1497 int is_pilot_multi(CFILE *fp)
1499 uint id,file_version;
1502 id = cfread_uint(fp);
1503 if (id != PLR_FILE_ID) {
1504 Warning(LOCATION, "Player file has invalid signature");
1509 // check for compatibility here
1510 file_version = cfread_uint(fp);
1511 if (file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
1512 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
1517 // read in whether he's a multiplayer or not
1518 is_multi = cfread_ubyte(fp);
1525 int is_pilot_multi(player *p)
1527 return (p->flags & PLAYER_FLAGS_IS_MULTI) ? 1 : 0;
1530 // this works on barracks and player_select interface screens
1531 void init_new_pilot(player *p, int reset)
1536 hud_set_default_hud_config(p); // use a default hud config
1539 // in the demo, load up the hardcoded hcf file
1541 hud_config_color_load("hud_1.hcf");
1543 hud_config_color_load("hud_3.hcf");
1546 hud_config_set_color(HUD_COLOR_GREEN);
1549 control_config_reset_defaults(); // get a default keyboard config
1550 player_set_pilot_defaults(p); // set up any player struct defaults
1552 cur_speed = os_config_read_uint(NULL, NOX("ComputerSpeed"), 2 );
1553 if ( cur_speed < 0 ) {
1555 } else if ( cur_speed >= NUM_DEFAULT_DETAIL_LEVELS ) {
1556 cur_speed = NUM_DEFAULT_DETAIL_LEVELS-1;
1558 // always set to high
1559 // DKA: 8/4/99 USE speed from registry
1560 // cur_speed = NUM_DEFAULT_DETAIL_LEVELS-2;
1562 #if NUM_DEFAULT_DETAIL_LEVELS != 4
1563 #error Code in ManagePilot assumes NUM_DEFAULT_DETAIL_LEVELS = 4
1566 detail_level_set(cur_speed);
1568 Game_skill_level = game_get_default_skill_level();
1570 mprintf(( "Setting detail level to %d because of new pilot\n", cur_speed ));
1571 Use_mouse_to_fly = 0;
1572 Mouse_sensitivity = 4;
1573 Joy_sensitivity = 9;
1574 Dead_zone_size = 10;
1577 // unassigned squadron
1578 SDL_strlcpy(p->squad_name, XSTR("Unassigned", 1255), SDL_arraysize(p->squad_name));
1579 SDL_strlcpy(p->squad_filename, "", SDL_arraysize(p->squad_filename));
1581 // set him to be a single player pilot by default (the actual creation routines will change this if necessary)
1582 p->flags &= ~PLAYER_FLAGS_IS_MULTI;
1584 // effectively sets the length return by strlen() to 0
1585 Campaign.filename[0] = 0;
1588 // pick a random pilot image for this guy
1590 pilot_set_random_pic(p);
1591 p->insignia_texture = -1;
1592 pilot_set_random_squad_pic(p);
1595 init_scoring_element(&p->stats);
1598 p->stats.rank = RANK_ENSIGN;
1606 Multi_options_g.protocol = NET_TCP;
1608 Multi_options_g.pxo = 1;
1611 // initialize default multiplayer options
1612 multi_options_set_netgame_defaults(&p->m_server_options);
1613 multi_options_set_local_defaults(&p->m_local_options);
1615 Player_loadout.filename[0] = 0;
1617 // reset the cutscenes which can be viewed
1619 Cutscenes_viewable = INTRO_CUTSCENE_FLAG;
1623 void pilot_set_short_callsign(player *p, int max_width)
1625 SDL_strlcpy(p->short_callsign, p->callsign, SDL_arraysize(p->short_callsign));
1627 gr_force_fit_string(p->short_callsign, CALLSIGN_LEN - 1, max_width);
1628 gr_get_string_size( &(p->short_callsign_width), NULL, p->short_callsign );
1631 // pick a random image for the passed player
1632 void pilot_set_random_pic(player *p)
1634 // if there are no available pilot pics, set the image filename to null
1635 if (Num_pilot_images <= 0) {
1636 SDL_strlcpy(p->image_filename, "", SDL_arraysize(p->image_filename));
1638 // pick a random name from the list
1639 int random_index = rand() % Num_pilot_images;
1640 SDL_assert((random_index >= 0) && (random_index < Num_pilot_images));
1641 SDL_strlcpy(p->image_filename, Pilot_images_arr[random_index], SDL_arraysize(p->image_filename));
1645 // pick a random image for the passed player
1646 void pilot_set_random_squad_pic(player *p)
1648 // if there are no available pilot pics, set the image filename to null
1649 if (Num_pilot_squad_images <= 0) {
1650 player_set_squad_bitmap(p, "");
1651 // strcpy(p->squad_filename, "");
1653 // pick a random name from the list
1654 int random_index = rand() % Num_pilot_squad_images;
1655 SDL_assert((random_index >= 0) && (random_index < Num_pilot_squad_images));
1656 player_set_squad_bitmap(p, Pilot_squad_images_arr[random_index]);
1657 // strcpy(p->squad_filename, Pilot_squad_images_arr[random_index]);
1661 // format a pilot's callsign into a "personal" form - ie, adding a 's or just an ' as appropriate
1662 void pilot_format_callsign_personal(const char *in_callsign, char *out_callsign, const int out_size)
1664 // don't do anything if we've got invalid strings
1665 if((in_callsign == NULL) || (out_callsign == NULL)){
1669 // copy the original string
1670 SDL_strlcpy(out_callsign, in_callsign, out_size);
1672 // tack on the appropriate postfix
1673 if(in_callsign[strlen(in_callsign) - 1] == 's'){
1674 SDL_strlcat(out_callsign,XSTR( "\'", 45), out_size);
1676 SDL_strlcat(out_callsign,XSTR( "\'s", 46), out_size);
1680 // throw up a popup asking the user to verify the overwrite of an existing pilot name
1681 // 1 == ok to overwrite, 0 == not ok
1682 int pilot_verify_overwrite()
1684 return popup_sync(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));
1687 extern int Skip_packfile_search; // located in CFileList.cpp
1690 // load up the list of pilot image filenames (do this at game startup as well as barracks startup)
1691 void pilot_load_pic_list()
1693 Num_pilot_images = 0;
1695 // load pilot images from the player images directory
1696 Num_pilot_images = cf_get_file_list_preallocated(MAX_PILOT_IMAGES, Pilot_images_arr, Pilot_image_names, CF_TYPE_PLAYER_IMAGES_MAIN, NOX("*.pcx"));
1698 // sort all filenames
1699 cf_sort_filenames(Num_pilot_images, Pilot_image_names, CF_SORT_NAME);
1702 // load up the list of pilot squad filenames
1703 void pilot_load_squad_pic_list()
1705 Num_pilot_squad_images = 0;
1707 // load pilot images from the player images directory
1708 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"));
1710 // sort all filenames
1711 cf_sort_filenames(Num_pilot_squad_images, Pilot_squad_image_names, CF_SORT_NAME);
1714 // will attempt to load an insignia bitmap and set it as active for the player
1715 void player_set_squad_bitmap(player *p, const char *fname)
1722 // if he has another bitmap already - unload it
1723 if(p->insignia_texture >= 0){
1724 bm_unload(p->insignia_texture);
1727 p->insignia_texture = -1;
1729 // try and set the new one
1730 if (fname != p->squad_filename) {
1731 SDL_strlcpy(p->squad_filename, fname, SDL_arraysize(p->squad_filename));
1734 if(strlen(p->squad_filename) > 0){
1735 p->insignia_texture = bm_load_duplicate(fname);
1737 // lock is as a transparent texture
1738 if(p->insignia_texture != -1){
1739 bm_lock(p->insignia_texture, 16, BMP_TEX_XPARENT);
1740 bm_unlock(p->insignia_texture);
1745 flen = strlen(filename);
1747 SDL_assert(flen < MAX_PATH_LEN);
1748 strcpy(path, filename);
1749 if ((flen < 4) || SDL_strcasecmp(path + flen - elen, ext)) {
1750 SDL_assert(flen + elen < MAX_PATH_LEN);
1757 void player_set_squad(player *p, const char *squad_name)
1764 SDL_strlcpy(p->squad_name, squad_name, SDL_arraysize(p->squad_name));
1767 DCF(pilot,"Changes pilot stats. (Like reset campaign)" )
1770 dc_get_arg(ARG_STRING);
1771 if (!strcmp(Dc_arg, NOX("reset"))) {
1772 if (strlen(Campaign.filename)) {
1773 mission_campaign_savefile_delete(Campaign.filename);
1774 mission_campaign_load(Campaign.filename);
1778 Dc_help = 1; // print usage, not stats
1783 dc_printf( "Usage: pilot keyword\nWhere keyword can be in the following forms:\n" );
1784 dc_printf( "pilot reset Resets campaign stats.\n" );
1785 Dc_status = 0; // don't print status if help is printed. Too messy.
1793 struct fs_keycode_t {
1795 SDL_Keycode sdl_code;
1798 static const fs_keycode_t keycode_lookup[] = {
1799 { /* KEY_0 */ 0x0B, SDLK_0 },
1800 { /* KEY_1 */ 0x02, SDLK_1 },
1801 { /* KEY_2 */ 0x03, SDLK_2 },
1802 { /* KEY_3 */ 0x04, SDLK_3 },
1803 { /* KEY_4 */ 0x05, SDLK_4 },
1804 { /* KEY_5 */ 0x06, SDLK_5 },
1805 { /* KEY_6 */ 0x07, SDLK_6 },
1806 { /* KEY_7 */ 0x08, SDLK_7 },
1807 { /* KEY_8 */ 0x09, SDLK_8 },
1808 { /* KEY_9 */ 0x0A, SDLK_9 },
1809 { /* KEY_A */ 0x1E, SDLK_a },
1810 { /* KEY_B */ 0x30, SDLK_b },
1811 { /* KEY_C */ 0x2E, SDLK_c },
1812 { /* KEY_D */ 0x20, SDLK_d },
1813 { /* KEY_E */ 0x12, SDLK_e },
1814 { /* KEY_F */ 0x21, SDLK_f },
1815 { /* KEY_G */ 0x22, SDLK_g },
1816 { /* KEY_H */ 0x23, SDLK_h },
1817 { /* KEY_I */ 0x17, SDLK_i },
1818 { /* KEY_J */ 0x24, SDLK_j },
1819 { /* KEY_K */ 0x25, SDLK_k },
1820 { /* KEY_L */ 0x26, SDLK_l },
1821 { /* KEY_M */ 0x32, SDLK_m },
1822 { /* KEY_N */ 0x31, SDLK_n },
1823 { /* KEY_O */ 0x18, SDLK_o },
1824 { /* KEY_P */ 0x19, SDLK_p },
1825 { /* KEY_Q */ 0x10, SDLK_q },
1826 { /* KEY_R */ 0x13, SDLK_r },
1827 { /* KEY_S */ 0x1F, SDLK_s },
1828 { /* KEY_T */ 0x14, SDLK_t },
1829 { /* KEY_U */ 0x16, SDLK_u },
1830 { /* KEY_V */ 0x2F, SDLK_v },
1831 { /* KEY_W */ 0x11, SDLK_w },
1832 { /* KEY_X */ 0x2D, SDLK_x },
1833 { /* KEY_Y */ 0x15, SDLK_y },
1834 { /* KEY_Z */ 0x2C, SDLK_z },
1835 { /* KEY_MINUS */ 0x0C, SDLK_MINUS },
1836 { /* KEY_EQUAL */ 0x0D, SDLK_EQUALS },
1837 { /* KEY_DIVIDE */ 0x35, SDLK_SLASH },
1838 { /* KEY_SLASH */ 0x2B, SDLK_BACKSLASH },
1839 { /* KEY_SLASH_UK */ 0x56, SDLK_BACKSLASH },
1840 { /* KEY_COMMA */ 0x33, SDLK_COMMA },
1841 { /* KEY_PERIOD */ 0x34, SDLK_PERIOD },
1842 { /* KEY_SEMICOL */ 0x27, SDLK_SEMICOLON },
1843 { /* KEY_LBRACKET */ 0x1A, SDLK_LEFTBRACKET },
1844 { /* KEY_RBRACKET */ 0x1B, SDLK_RIGHTBRACKET },
1845 { /* KEY_RAPOSTRO */ 0x28, SDLK_QUOTE },
1846 { /* KEY_LAPOSTRO */ 0x29, SDLK_BACKQUOTE },
1847 { /* KEY_ESC */ 0x01, SDLK_ESCAPE },
1848 { /* KEY_ENTER */ 0x1C, SDLK_RETURN },
1849 { /* KEY_BACKSP */ 0x0E, SDLK_BACKSPACE },
1850 { /* KEY_TAB */ 0x0F, SDLK_TAB },
1851 { /* KEY_SPACEBAR */ 0x39, SDLK_SPACE },
1852 { /* KEY_NUMLOCK */ 0x61, SDLK_NUMLOCKCLEAR },
1853 { /* KEY_SCROLLOCK */ 0x46, SDLK_SCROLLLOCK },
1854 { /* KEY_CAPSLOCK */ 0x3A, SDLK_CAPSLOCK },
1855 { /* KEY_LSHIFT */ 0x2A, SDLK_LSHIFT },
1856 { /* KEY_RSHIFT */ 0x36, SDLK_RSHIFT },
1857 { /* KEY_LALT */ 0x38, SDLK_LALT },
1858 { /* KEY_RALT */ 0xB8, SDLK_RALT },
1859 { /* KEY_LCTRL */ 0x1D, SDLK_LCTRL },
1860 { /* KEY_RCTRL */ 0x9D, SDLK_RCTRL },
1861 { /* KEY_F1 */ 0x3B, SDLK_F1 },
1862 { /* KEY_F2 */ 0x3C, SDLK_F2 },
1863 { /* KEY_F3 */ 0x3D, SDLK_F3 },
1864 { /* KEY_F4 */ 0x3E, SDLK_F4 },
1865 { /* KEY_F5 */ 0x3F, SDLK_F5 },
1866 { /* KEY_F6 */ 0x40, SDLK_F6 },
1867 { /* KEY_F7 */ 0x41, SDLK_F7 },
1868 { /* KEY_F8 */ 0x42, SDLK_F8 },
1869 { /* KEY_F9 */ 0x43, SDLK_F9 },
1870 { /* KEY_F10 */ 0x44, SDLK_F10 },
1871 { /* KEY_F11 */ 0x57, SDLK_F11 },
1872 { /* KEY_F12 */ 0x58, SDLK_F12 },
1873 { /* KEY_PAD0 */ 0x52, SDLK_KP_0 },
1874 { /* KEY_PAD1 */ 0x4F, SDLK_KP_1 },
1875 { /* KEY_PAD2 */ 0x50, SDLK_KP_2 },
1876 { /* KEY_PAD3 */ 0x51, SDLK_KP_3 },
1877 { /* KEY_PAD4 */ 0x4B, SDLK_KP_4 },
1878 { /* KEY_PAD5 */ 0x4C, SDLK_KP_5 },
1879 { /* KEY_PAD6 */ 0x4D, SDLK_KP_6 },
1880 { /* KEY_PAD7 */ 0x47, SDLK_KP_7 },
1881 { /* KEY_PAD8 */ 0x48, SDLK_KP_8 },
1882 { /* KEY_PAD9 */ 0x49, SDLK_KP_9 },
1883 { /* KEY_PADMINUS */ 0x4A, SDLK_KP_MINUS },
1884 { /* KEY_PADPLUS */ 0x4E, SDLK_KP_PLUS },
1885 { /* KEY_PADPERIOD */ 0x53, SDLK_KP_PERIOD },
1886 { /* KEY_PADDIVIDE */ 0xB5, SDLK_KP_DIVIDE },
1887 { /* KEY_PADMULTIPLY */ 0x37, SDLK_KP_MULTIPLY },
1888 { /* KEY_PADENTER */ 0x9C, SDLK_KP_ENTER },
1889 { /* KEY_INSERT */ 0xD2, SDLK_INSERT },
1890 { /* KEY_HOME */ 0xC7, SDLK_HOME },
1891 { /* KEY_PAGEUP */ 0xC9, SDLK_PAGEUP },
1892 { /* KEY_DELETE */ 0xd3, SDLK_DELETE },
1893 { /* KEY_END */ 0xCF, SDLK_END },
1894 { /* KEY_PAGEDOWN */ 0xD1, SDLK_PAGEDOWN },
1895 { /* KEY_UP */ 0xC8, SDLK_UP },
1896 { /* KEY_DOWN */ 0xD0, SDLK_DOWN },
1897 { /* KEY_LEFT */ 0xCB, SDLK_LEFT },
1898 { /* KEY_RIGHT */ 0xCD, SDLK_RIGHT },
1899 { /* KEY_PRINT_SCRN */ 0xB7, SDLK_PRINTSCREEN },
1900 { /* KEY_PAUSE */ 0x45, SDLK_PAUSE },
1901 { /* KEY_BREAK */ 0xc6, SDLK_PAUSE }
1904 static SDL_Keycode keycode_translate_from(short keycode)
1906 const int tbl_size = sizeof(keycode_lookup) / sizeof(fs_keycode_t);
1912 int mods = keycode & 0xf900;
1913 keycode &= KEY_MASK;
1915 for (int i = 0; i < tbl_size; i++) {
1916 if (keycode_lookup[i].fs_code == keycode) {
1917 return (SDL_Keycode)(keycode_lookup[i].sdl_code | mods);
1924 static short keycode_translate_to(SDL_Keycode keycode)
1926 const int tbl_size = sizeof(keycode_lookup) / sizeof(fs_keycode_t);
1932 int mods = keycode & 0xf900;
1933 keycode &= KEY_MASK;
1935 for (int i = 0; i < tbl_size; i++) {
1936 if (keycode_lookup[i].sdl_code == keycode) {
1937 return (short)(keycode_lookup[i].fs_code | mods);