]> icculus.org git repositories - taylor/freespace2.git/blob - src/playerman/managepilot.cpp
various valgrind warning fixes
[taylor/freespace2.git] / src / playerman / managepilot.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Playerman/ManagePilot.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * ManagePilot.cpp has code to load and save pilot files, and to select and 
16  * manage the pilot
17  *
18  * $Log$
19  * Revision 1.6  2004/07/04 11:41:24  taylor
20  * warning fixes, cross platform pilot compat with OSX-Linux-Windows
21  *
22  * Revision 1.5  2003/05/25 02:30:43  taylor
23  * Freespace 1 support
24  *
25  * Revision 1.4  2002/06/09 04:41:25  relnev
26  * added copyright header
27  *
28  * Revision 1.3  2002/06/09 03:16:05  relnev
29  * added _splitpath.
30  *
31  * removed unneeded asm, old sdl 2d setup.
32  *
33  * fixed crash caused by opengl_get_region.
34  *
35  * Revision 1.2  2002/05/07 03:16:50  theoddone33
36  * The Great Newline Fix
37  *
38  * Revision 1.1.1.1  2002/05/03 03:28:11  root
39  * Initial import.
40  *
41  * 
42  * 41    9/13/99 4:52p Dave
43  * RESPAWN FIX
44  * 
45  * 40    9/01/99 10:09a Dave
46  * Pirate bob.
47  * 
48  * 39    8/26/99 8:49p Jefff
49  * old player file compatibility with new medal stuff
50  * 
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.
54  * 
55  * 37    8/16/99 4:06p Dave
56  * Big honking checkin.
57  * 
58  * 36    8/11/99 11:36a Jefff
59  * added compatibility w/ fs2 demo plr version
60  * 
61  * 35    8/10/99 3:46p Jefff
62  * changes for Intelligence section of new tech room
63  * 
64  * 34    8/04/99 11:38p Andsager
65  * make new pilot detail level match registry info.
66  * 
67  * 33    8/02/99 9:55p Dave
68  * Hardcode a nice hud color config for the demo.
69  * 
70  * 32    8/02/99 9:13p Dave
71  * Added popup tips.
72  * 
73  * 31    8/01/99 12:39p Dave
74  * Added HUD contrast control key (for nebula).
75  * 
76  * 30    7/30/99 10:31p Dave
77  * Added comm menu to the configurable hud files.
78  * 
79  * 29    7/29/99 10:47p Dave
80  * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
81  * 
82  * 28    7/29/99 12:05a Dave
83  * Nebula speed optimizations.
84  * 
85  * 27    7/24/99 1:54p Dave
86  * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
87  * missions.
88  * 
89  * 26    6/22/99 7:03p Dave
90  * New detail options screen.
91  * 
92  * 25    6/16/99 4:06p Dave
93  * New pilot info popup. Added new draw-bitmap-as-poly function.
94  * 
95  * 24    6/11/99 11:13a Dave
96  * last minute changes before press tour build.
97  * 
98  * 23    6/08/99 1:14a Dave
99  * Multi colored hud test.
100  * 
101  * 22    5/03/99 8:33p Dave
102  * New version of multi host options screen.
103  * 
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.
108  * 
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.
112  * 
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.
116  * 
117  * 18    1/21/99 2:06p Dave
118  * Final checkin for multiplayer testing.
119  * 
120  * 17    1/15/99 2:49p Dave
121  * Fixed creation of pilots.
122  * 
123  * 16    1/14/99 6:06p Dave
124  * 100% full squad logo support for single player and multiplayer.
125  * 
126  * 15    1/12/99 3:15a Dave
127  * Barracks screen support for selecting squad logos. We need real artwork
128  * :)
129  * 
130  * 14    1/06/99 2:24p Dave
131  * Stubs and release build fixes.
132  * 
133  * 13    12/14/98 12:13p Dave
134  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
135  * Need to test now.
136  * 
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.
140  * 
141  * 11    11/19/98 4:51p Dave
142  * Ignore multiplayer protocol settings in the pilot file for now.
143  * 
144  * 10    11/19/98 4:19p Dave
145  * Put IPX sockets back in psnet. Consolidated all multiplayer config
146  * files into one.
147  * 
148  * 9     10/13/98 2:47p Andsager
149  * Remove reference to Tech_shivan_species_avail
150  * 
151  * 8     10/13/98 9:29a Dave
152  * Started neatening up freespace.h. Many variables renamed and
153  * reorganized. Added AlphaColors.[h,cpp]
154  * 
155  * 7     10/12/98 9:30a Andsager
156  * Clean up barracks.cpp.  Remove unneeded ".h" files from ManagePilot
157  * 
158  * 6     10/09/98 5:17p Andsager
159  * move barracks screen into barracks.cpp
160  * 
161  * 5     10/09/98 2:57p Dave
162  * Starting splitting up OS stuff.
163  * 
164  * 4     10/08/98 9:19a Andsager
165  * Clean up pilot player read and write, starting with new version.
166  * 
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
170  * directory.
171  * 
172  * 2     10/07/98 10:53a Dave
173  * Initial checkin.
174  * 
175  * 1     10/07/98 10:50a Dave
176  * 
177  * 279   9/21/98 10:02p Dave
178  * Last minute changes to techroom weapon/ship/species stuff.
179  * 
180  * 278   9/08/98 12:10p Andsager
181  * Fixed a bug with saving ship and weapon info techroom flags.
182  * 
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.
187  * 
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
192  * XSTR_SIZE).
193  * 
194  * 275   6/05/98 9:49a Lawrance
195  * OEM changes
196  * 
197  * 274   6/01/98 11:43a John
198  * JAS & MK:  Classified all strings for localization.
199  * 
200  * 273   5/26/98 11:53a Allender
201  * fix multiplayer problems and sexpression crash
202  * 
203  * 272   5/24/98 2:46p Lawrance
204  * Fix bug where skill level would be reset to default when switching
205  * between pilots
206  * 
207  * 271   5/23/98 4:02p Allender
208  * version change
209  * 
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.
213  *
214 */
215
216 #include <errno.h>
217 #include "managepilot.h"
218 #include "2d.h"
219 #include "freespace.h"
220 #include "hudsquadmsg.h"
221 #include "sound.h"
222 #include "multi.h"
223 #include "eventmusic.h"
224 #include "audiostr.h"
225 #include "osregistry.h"
226 #include "font.h"
227 #include "playermenu.h"
228 #include "missionshipchoice.h"
229 #include "hudconfig.h"
230 #include "popup.h"
231 #include "redalert.h"
232 #include "techmenu.h"
233 #include "joy.h"
234 #include "mouse.h"
235 #include "cutscenes.h"
236 #include "bmpman.h"
237
238 // update this when altering data that is read/written to .PLR file
239 #ifndef MAKE_FS1
240 #define CURRENT_PLAYER_FILE_VERSION                             140
241 #else
242 // 141: add more FS1 detail settings
243 // 142: HUD config settings (brightness)
244 #define CURRENT_PLAYER_FILE_VERSION                             142
245 #define PREVIOUS_PLAYER_FILE_VERSION                    140
246 #endif
247 #define FS2_DEMO_PLAYER_FILE_VERSION                            135
248 #ifndef MAKE_FS1
249 #define LOWEST_COMPATIBLE_PLAYER_FILE_VERSION   CURRENT_PLAYER_FILE_VERSION                     // demo plr files should work in final
250 #else
251 #define LOWEST_COMPATIBLE_PLAYER_FILE_VERSION   PREVIOUS_PLAYER_FILE_VERSION
252 #endif
253
254 // keep track of pilot file changes here 
255 // version 2    : Added squad logo filename
256 // version 3    : Changed size of scoring struct. use ushort instead of ints for storing alltime kills by ship type
257 // version 4/5 : Added squadron name field
258 // version 6    : changed max length on a multiplayer options field
259 // version 130  : changed size of hud config struct
260 // version 133 : misc changes. new hud gauge
261 // version 134 : added HUD contrast toggle key
262 // version 135 : added tips flag  (THIS IS THE DEMO VERSION - RETAIN COMPATIBILITY FROM HERE ON OUT)
263 // version 136 : added intelligence flags to tech room visibility data
264 // version 137 : 2 new HUD gauges. 
265 // version 138  : new multiplayer config
266 // version 139 : # medals increased - added compatibility with old plr file versions
267 // version 140 : ships table reordered. clear out old pilot files
268 // search for PLAYER INIT for new pilot initialization stuff. I _think_ its in the right spot for now
269 #define PLR_FILE_ID     0x46505346      // FPSF, unique signiture to identify a .PLR file (FreeSpace Player File)  // FPSF appears as FSPF in file.
270
271 // Current content of a .PLR file
272 //
273
274 // Global variables
275 int Player_sel_mode;
276
277 // pilot pic image list stuff ( call pilot_load_pic_list() to make these valid )
278 char Pilot_images_arr[MAX_PILOT_IMAGES][MAX_FILENAME_LEN];
279 char *Pilot_image_names[MAX_PILOT_IMAGES];
280 int Num_pilot_images = 0;
281
282 // squad logo list stuff (call pilot_load_squad_pic_list() to make these valid )
283 char Pilot_squad_images_arr[MAX_PILOT_IMAGES][MAX_FILENAME_LEN];
284 char *Pilot_squad_image_names[MAX_PILOT_IMAGES];
285 int Num_pilot_squad_images = 0;
286
287 static uint Player_file_version;
288
289 // forward declarations
290 void read_detail_settings(CFILE *file, int Player_file_version);
291 void write_detail_settings(CFILE *file);
292 void read_stats_block(CFILE *file, int Player_file_version, scoring_struct *stats);
293 void write_stats_block(CFILE *file, scoring_struct *stats);
294 void read_multiplayer_options(player *p,CFILE *file);
295 void write_multiplayer_options(player *p,CFILE *file);
296
297 // internal function to delete a player file.  Called after a pilot is obsoleted, and when a pilot is deleted
298 // used in barracks and player_select
299 void delete_pilot_file( const char *pilot_name, int single )
300 {
301         char filename[MAX_FILENAME_LEN];
302         char basename[MAX_FILENAME_LEN];
303
304         // get the player file.
305
306         _splitpath(pilot_name, NULL, NULL, basename, NULL);
307
308         strcpy( filename, basename );
309         strcat( filename, NOX(".plr") );
310         if (Player_sel_mode == PLAYER_SELECT_MODE_SINGLE){
311                 cf_delete(filename, CF_TYPE_SINGLE_PLAYERS);
312         } else {
313                 cf_delete(filename, CF_TYPE_MULTI_PLAYERS);
314         }
315
316         // we must try and delete the campaign save files for a pilot as well.
317         mission_campaign_delete_all_savefiles( basename, !single );
318 }
319
320 // check if a pilot file is valid or not (i.e. is usable, not out of date, etc)
321 // used in barracks and player_select
322 int verify_pilot_file(const char *filename, int single, int *rank)
323 {
324         CFILE   *file;
325         uint id, file_version;
326         int type;
327
328         filename = cf_add_ext(filename, NOX(".plr"));
329         
330         if (single){
331                 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
332         } else {
333                 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
334         }
335
336         if (!file){
337                 return -1;
338         }
339
340         id = cfread_uint(file);
341         if (id != PLR_FILE_ID) {
342                 nprintf(("Warning", "Player file has invalid signature\n"));
343                 cfclose(file);
344                 delete_pilot_file( filename, single );
345                 return -1;
346         }
347
348         // check for compatibility here
349         file_version = cfread_uint(file);
350 /*      if (file_version < INITIAL_RELEASE_FILE_VERSION) { */
351 //      if (file_version != CURRENT_PLAYER_FILE_VERSION) {
352         if (file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
353                 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
354                 cfclose(file);
355                 delete_pilot_file( filename, single );
356                 return -1;
357         }
358
359         type = !cfread_ubyte(file);
360         if (rank){
361                 *rank = 0;      
362         }
363                 
364         if (rank){
365                 *rank = cfread_int(file);
366         } else {
367                 cfread_int(file);
368         }
369
370         cfclose(file);
371         if (type != single){
372                 return -1;
373         }
374
375         return 0;
376 }
377
378 void pilot_write_techroom_data(CFILE *file)
379 {
380         int idx;                
381         ubyte out;
382
383         // write the ship and weapon count
384         cfwrite_int(Num_ship_types, file);
385         cfwrite_int(Num_weapon_types, file);
386         cfwrite_int(Intel_info_size, file);
387
388         // write all ship flags out
389         for (idx=0; idx<Num_ship_types; idx++) {
390                 out = (Ship_info[idx].flags & SIF_IN_TECH_DATABASE) ? (ubyte)1 : (ubyte)0;              
391                 cfwrite_ubyte(out, file);                               
392         }
393
394         // write all weapon types out
395         for (idx=0; idx<Num_weapon_types; idx++) {
396                 out = (Weapon_info[idx].wi_flags & WIF_IN_TECH_DATABASE) ? (ubyte)1 : (ubyte)0;
397                 cfwrite_ubyte(out, file);
398         }       
399
400         // write all intel entry flags out
401         for (idx=0; idx<Intel_info_size; idx++) {
402                 cfwrite_ubyte((ubyte)Intel_info[idx].in_tech_db, file);
403         }
404 }
405
406 void pilot_read_techroom_data(CFILE *file)
407 {
408         int idx;
409         int ship_count, weapon_count, intel_count;
410         ubyte in;
411
412         // read in ship and weapon counts
413         ship_count = cfread_int(file);
414         weapon_count = cfread_int(file);
415         Assert(ship_count <= MAX_SHIP_TYPES);
416         Assert(weapon_count <= MAX_WEAPON_TYPES);
417
418         // maintain compatibility w/ demo version
419         if (Player_file_version < 136) {
420                 // skip over all this data, because the lack of tech room in the demo
421                 // left this all hosed in the demo .plr files
422                 // this will all get initialized as if this fella was a new pilot
423                 for (idx=0; idx<ship_count+weapon_count; idx++) {
424                         in = cfread_ubyte(file);
425                 }
426
427         } else {
428
429                 intel_count = cfread_int(file);
430                 Assert(intel_count <= MAX_INTEL_ENTRIES);
431
432                 // read all ships in
433                 for (idx=0; idx<ship_count; idx++) {
434                         in = cfread_ubyte(file);
435                         if (in) {
436                                 Ship_info[idx].flags |= SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M;
437                         } else {
438                                 Ship_info[idx].flags &= ~SIF_IN_TECH_DATABASE;
439                         }
440                 }
441
442                 // read all weapons in
443                 for (idx=0; idx<weapon_count; idx++) {
444                         in = cfread_ubyte(file);
445                         if (in) {
446                                 Weapon_info[idx].wi_flags |= WIF_IN_TECH_DATABASE;
447                         } else {
448                                 Weapon_info[idx].wi_flags &= ~WIF_IN_TECH_DATABASE;
449                         }
450                 }
451
452                 // read all intel entries in
453                 for (idx=0; idx<intel_count; idx++) {
454                         in = cfread_ubyte(file);
455                         if (in) {
456                                 Intel_info[idx].in_tech_db = 1;
457                         } else {
458                                 Intel_info[idx].in_tech_db = 0;
459                         }
460                 }
461         }
462 }
463
464 // write out the player ship selection
465 void pilot_write_loadout(CFILE *file)
466 {
467         int i, j;
468         wss_unit *slot; 
469
470         cfwrite_string_len(Player_loadout.filename, file);
471         cfwrite_string_len(Player_loadout.last_modified, file);
472
473         // write ship and weapon counts
474         cfwrite_int(Num_ship_types, file);
475         cfwrite_int(Num_weapon_types, file);
476
477         // write ship pool
478         for ( i = 0; i < Num_ship_types; i++ ) {
479                 cfwrite_int(Player_loadout.ship_pool[i], file);
480         }
481
482         // write weapons pool
483         for ( i = 0; i < Num_weapon_types; i++ ) {
484                 cfwrite_int(Player_loadout.weapon_pool[i], file);
485         }
486
487         // write ship loadouts
488         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
489                 slot = &Player_loadout.unit_data[i];
490                 cfwrite_int(slot->ship_class, file);
491                 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
492                         cfwrite_int(slot->wep[j], file);
493                         cfwrite_int(slot->wep_count[j], file);
494                 }
495         }
496 }
497
498 // read in the ship selection for the pilot
499 void pilot_read_loadout(CFILE *file)
500 {
501         int i, j;
502         wss_unit *slot;
503         int ship_count, weapon_count;
504
505         memset(Player_loadout.filename, 0, MAX_FILENAME_LEN);
506         cfread_string_len(Player_loadout.filename, MAX_FILENAME_LEN, file);
507
508         memset(Player_loadout.last_modified, 0, DATE_TIME_LENGTH);      
509         cfread_string_len(Player_loadout.last_modified, DATE_TIME_LENGTH, file);        
510
511         // read in ship and weapon counts
512         ship_count = cfread_int(file);
513         weapon_count = cfread_int(file);
514         Assert(ship_count <= MAX_SHIP_TYPES);
515         Assert(weapon_count <= MAX_WEAPON_TYPES);
516
517         // read in ship pool
518         for ( i = 0; i < ship_count; i++ ) {
519                 Player_loadout.ship_pool[i] = cfread_int(file);
520         }
521
522         // read in weapons pool
523         for ( i = 0; i < weapon_count; i++ ) {
524                 Player_loadout.weapon_pool[i] = cfread_int(file);
525         }
526
527         // read in loadout info
528         for ( i = 0; i < MAX_WSS_SLOTS; i++ ) {
529                 slot = &Player_loadout.unit_data[i];
530                 slot->ship_class = cfread_int(file);
531                 for ( j = 0; j < MAX_WL_WEAPONS; j++ ) {
532                         slot->wep[j] = cfread_int(file);
533                         slot->wep_count[j] = cfread_int(file);
534                 }
535         }
536 }
537
538 // read_pilot_file()
539 //
540 // returns 0 - file read in correctly
541 //        -1 - .PLR file doesn't exist or file not compatible
542 //        >0 - errno from fopen error
543 // if single == 1, look for players in the single players directory, otherwise look in the 
544 // multiplayers directory
545 int read_pilot_file(const char *callsign, int single, player *p)
546 {
547         ubyte num_ctrls;
548         ubyte is_multi = 0;
549         char filename[MAX_FILENAME_LEN], ship_name[NAME_LENGTH];
550         CFILE   *file;
551         uint id;
552         int idx;
553         int i, key_value;
554
555         if (!p) {
556                 Assert((Player_num >= 0) && (Player_num < MAX_PLAYERS));
557                 p = &Players[Player_num];
558         }
559
560         //sprintf(filename, "%-.8s.plr",Players[Player_num].callsign);
561         Assert(strlen(callsign) < MAX_FILENAME_LEN - 4);  // ensure we won't overrun the buffer
562         strcpy( filename, callsign );
563         strcat( filename, NOX(".plr") );
564
565         // if we're a standalone server in multiplayer, just fill in some bogus values since we don't have a pilot file
566         if ((Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER)) {
567                 memset(Player, 0, sizeof(player));
568                 strcpy(Player->callsign, NOX("Standalone"));
569                 strcpy(Player->short_callsign, NOX("Standalone"));
570                 return 0;
571         }
572         
573         // see comments at the beginning of function
574         if (single) {
575                 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
576         } else {
577                 file = cfopen(filename, "rb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
578         }
579
580         if (!file) {
581                 return errno;
582         }
583
584         id = cfread_uint(file);
585         if (id != PLR_FILE_ID) {
586                 Warning(LOCATION, "Player file has invalid signature");
587                 cfclose(file);
588                 return -1;
589         }
590
591         // check for compatibility here
592         Player_file_version = cfread_uint(file);
593         cf_set_version( file, Player_file_version );
594
595         if (Player_file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
596                 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
597                 cfclose(file);
598                 delete_pilot_file( filename, single );
599                 return -1;
600         }
601
602         // read in whether he's a multiplayer or not
603         is_multi = cfread_ubyte(file);
604         if (is_multi){
605                 p->flags |= PLAYER_FLAGS_IS_MULTI;
606         } else {
607                 p->flags &= ~PLAYER_FLAGS_IS_MULTI;     // this takes care of unsetting any leftover bits from a (possibly) previously selected pilot
608         }
609
610         // read in rank.
611         cfread_int(file);  
612
613         // get player location
614         p->on_bastion = cfread_ubyte(file);
615
616         // tips?
617         p->tips = cfread_int(file);
618
619         // write out the image file name
620         cfread_string_len(p->image_filename, MAX_FILENAME_LEN - 1, file);
621
622         // write out the image file name
623         p->insignia_texture = -1;
624         cfread_string_len(p->squad_name, NAME_LENGTH, file);
625         cfread_string_len(p->squad_filename, MAX_FILENAME_LEN - 1, file);
626         player_set_squad_bitmap(p, p->squad_filename);
627
628         // deal with campaign stuff.  The way we store the information in the file is to first store the
629         // name of the current campaign that the player is playing.  Next we store the info regarding the campaigns
630         // that the player is currently playing
631         memset(p->current_campaign, 0, MAX_FILENAME_LEN);
632         cfread_string_len(p->current_campaign, MAX_FILENAME_LEN, file);
633
634         // read in the ship name for last ship flown by the player
635         memset(ship_name, 0, NAME_LENGTH);
636         cfread_string_len(ship_name, NAME_LENGTH, file);
637         p->last_ship_flown_si_index = ship_info_lookup(ship_name);
638         if ( p->last_ship_flown_si_index < 0 ) {
639                 nprintf(("Warning","WARNING => Ship class %s not located in Ship_info[] in player file\n",ship_name));
640                 p->last_ship_flown_si_index = ship_info_lookup(default_player_ship);
641         }
642
643         // set all the entries in the control config arrays to -1 (undefined)
644         control_config_clear();
645
646         // ---------------------------------------------
647         // read in the keyboard/joystick mapping
648         // ---------------------------------------------
649         num_ctrls = cfread_ubyte(file);
650         for (i=0; i<num_ctrls; i++) {
651                 key_value = cfread_short(file);
652                 // NOTE: next two lines are only here for transitioning from 255 to -1 as undefined key items
653                 if (key_value == 255)
654                         key_value = -1;
655
656                 Control_config[i].key_id = (short) key_value;
657
658                 key_value = cfread_short(file);
659                 // NOTE: next two lines are only here for transitioning from 255 to -1 as undefined key items
660                 if (key_value == 255)
661                         key_value = -1;
662
663                 Control_config[i].joy_id = (short) key_value;
664         }
665         
666         HUD_config.show_flags = cfread_int(file);       
667         HUD_config.show_flags2 = cfread_int(file);
668
669         HUD_config.popup_flags = cfread_int(file);
670         HUD_config.popup_flags2 = cfread_int(file);
671
672         HUD_config.num_msg_window_lines = cfread_ubyte(file);                   
673         HUD_config.rp_flags = cfread_int(file);
674         HUD_config.rp_dist =    cfread_int(file);
675 #ifdef MAKE_FS1
676         if(Player_file_version >= 142){
677                 HUD_config.main_color = cfread_int(file);
678                 HUD_color_alpha = cfread_int(file);
679         }
680         if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MIN ) {
681                 HUD_color_alpha = HUD_COLOR_ALPHA_DEFAULT;
682         }
683         hud_config_record_color(HUD_config.main_color);
684 #endif
685
686         // added 2 gauges with version 137
687         if(Player_file_version < 137){
688                 for(idx=0; idx<NUM_HUD_GAUGES-2; idx++){
689                         cfread(&HUD_config.clr[idx], sizeof(color), 1, file);
690                 }
691
692                 // set the 2 new gauges to be radar color
693                 memcpy(&HUD_config.clr[NUM_HUD_GAUGES-2], &HUD_config.clr[HUD_RADAR], sizeof(color));
694                 memcpy(&HUD_config.clr[NUM_HUD_GAUGES-1], &HUD_config.clr[HUD_RADAR], sizeof(color));
695         } else {
696                 for(idx=0; idx<NUM_HUD_GAUGES; idx++){
697                         cfread(&HUD_config.clr[idx], sizeof(color), 1, file);
698                 }
699         }
700
701         // read in the cutscenes which have been viewed
702         Cutscenes_viewable = cfread_int(file);
703
704         Master_sound_volume = cfread_float(file);
705         Master_event_music_volume = cfread_float(file);
706         Master_voice_volume = cfread_float(file);
707
708         audiostream_set_volume_all(Master_voice_volume, ASF_VOICE);
709         audiostream_set_volume_all(Master_event_music_volume, ASF_EVENTMUSIC);
710
711         if ( Master_event_music_volume > 0.0f ) {
712                 Event_music_enabled = 1;
713         } else {
714                 Event_music_enabled = 0;
715         }
716
717         read_detail_settings(file, Player_file_version);
718
719         // restore list of most recently played missions
720         Num_recent_missions = cfread_int( file );
721         Assert(Num_recent_missions <= MAX_RECENT_MISSIONS);
722         for ( i = 0; i < Num_recent_missions; i++ ) {
723                 char *p;
724
725                 cfread_string_len( Recent_missions[i], MAX_FILENAME_LEN, file);
726                 // Remove the extension
727                 p = strchr(Recent_missions[i], '.');
728                 if (p)
729                         *p = 0;
730         }
731         
732         // use this block of stats from now on
733         read_stats_block(file, Player_file_version, &p->stats); 
734
735    Game_skill_level = cfread_int(file);
736
737         for (i=0; i<NUM_JOY_AXIS_ACTIONS; i++) {
738                 Axis_map_to[i] = cfread_int(file);
739                 Invert_axis[i] = cfread_int(file);
740         }
741
742         // restore some player flags
743         Player[Player_num].save_flags = cfread_int(file);
744
745         // restore the most recent ship selection       
746         pilot_read_loadout(file);       
747
748         // read in multiplayer options
749         read_multiplayer_options(p,file);
750
751         p->readyroom_listing_mode = cfread_int(file);
752         Briefing_voice_enabled = cfread_int(file);
753
754         // restore the default netgame protocol mode
755         int protocol_temp = cfread_int(file);
756         switch(protocol_temp){
757         // plain TCP
758         case NET_VMT:   
759         case NET_TCP:
760                 Multi_options_g.protocol = NET_TCP;
761                 break;
762         // IPX
763         case NET_IPX:           
764                 Multi_options_g.protocol = NET_IPX;
765                 break;                  
766         }       
767
768         // restore wingman status used by red alert missions
769         red_alert_read_wingman_status(file, Player_file_version);
770
771         // read techroom data
772         pilot_read_techroom_data(file);
773
774         // restore auto-advance pref
775         Player->auto_advance = cfread_int(file);
776
777         Use_mouse_to_fly = cfread_int(file);
778         Mouse_sensitivity = cfread_int(file);
779         Joy_sensitivity = cfread_int(file);
780         Dead_zone_size = cfread_int(file);
781
782         if (cfclose(file))
783                 return errno;
784
785         // restore the callsign into the Player structure
786         strcpy(p->callsign, callsign);
787
788         // restore the truncated callsign into Player structure
789         pilot_set_short_callsign(p, SHORT_CALLSIGN_PIXEL_W);
790         
791         // when we store the LastPlayer key, we have to mark it as being single or multiplayer, so we know where to look for him
792         // (since we could have a single and a multiplayer pilot with the same callsign)
793         // 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
794         char cat[35];
795
796         strcpy(cat, p->callsign);
797         if (is_multi)
798                 strcat(cat, NOX("M"));
799         else
800                 strcat(cat, NOX("S"));
801
802         os_config_write_string( NULL, "LastPlayer", cat );
803 /*
804         // if he's not a multiplayer pilot, then load in the campaign file at this point!
805         if (!is_multi) {
806                 if (mission_campaign_load_by_name(campaign_fname)) {
807                         strcpy(campaign_fname, BUILTIN_CAMPAIGN);
808                         if (mission_campaign_load_by_name(campaign_fname))
809                                 Assert(0);
810                 }
811         }
812         //Campaign.current_mission = mission_num;*/
813
814         hud_squadmsg_save_keys();                       // when new pilot read in, must save info for squadmate messaging
815
816         return 0;
817 }
818
819 void read_stats_block(CFILE *file, int Player_file_version, scoring_struct *stats)
820 {
821         int i, total;
822    
823         init_scoring_element(stats);
824         stats->score = cfread_int(file);
825         stats->rank = cfread_int(file);
826         stats->assists = cfread_int(file);
827
828         if (Player_file_version < 139) {
829                 // support for FS2_DEMO pilots that still have FS1 medal info in the .plr files
830                 for (i=0; i < NUM_MEDALS_FS1; i++) {
831                         total = cfread_int(file);                       // dummy read
832                 }
833         } else {
834                 // read the usual way
835                 for (i=0; i < NUM_MEDALS; i++) {
836                         stats->medals[i] = cfread_int(file);
837                 }
838         }
839
840         total = cfread_int(file);
841         if (total > MAX_SHIP_TYPES){
842                 Warning(LOCATION, "Some ship kill information will be lost due to MAX_SHIP_TYPES decrease");
843         }
844
845         for (i=0; i<total && i<MAX_SHIP_TYPES; i++){
846                 stats->kills[i] = cfread_ushort(file);
847         }
848
849         stats->kill_count = cfread_int(file);
850         stats->kill_count_ok = cfread_int(file);
851         
852         stats->p_shots_fired = cfread_uint(file);
853         stats->s_shots_fired = cfread_uint(file);
854         stats->p_shots_hit = cfread_uint(file);
855         stats->s_shots_hit = cfread_uint(file);
856         
857    stats->p_bonehead_hits = cfread_uint(file);
858         stats->s_bonehead_hits = cfread_uint(file);
859         stats->bonehead_kills = cfread_uint(file);
860 }
861
862 // grab the various detail settings
863 void read_detail_settings(CFILE *file, int pfile_version)
864 {
865         // mass read the Detail struct
866 #ifdef MAKE_FS1
867         // add in extra detail settings
868         if(pfile_version < 141){
869                 cfread( &Detail, sizeof(detail_levels) - sizeof(Detail.engine_glows), 1, file );
870         } else {
871                 cfread( &Detail, sizeof(detail_levels), 1, file );
872         }
873 #else
874         cfread( &Detail, sizeof(detail_levels), 1, file );
875 #endif
876
877         // swap, swap, swap
878         Detail.setting = INTEL_INT(Detail.setting);
879
880         // hack for old pilot files with big-endian data
881         if ( (Detail.setting >= -1) && (Detail.setting <= 5) ) {
882                 // new way - it's little-endian...
883                 Detail.nebula_detail = INTEL_INT(Detail.nebula_detail);
884                 Detail.detail_distance = INTEL_INT(Detail.detail_distance);
885                 Detail.hardware_textures = INTEL_INT(Detail.hardware_textures);
886                 Detail.num_small_debris = INTEL_INT(Detail.num_small_debris);
887                 Detail.num_particles = INTEL_INT(Detail.num_particles);
888                 Detail.num_stars = INTEL_INT(Detail.num_stars);
889                 Detail.shield_effects = INTEL_INT(Detail.shield_effects);
890                 Detail.lighting = INTEL_INT(Detail.lighting);
891                 Detail.targetview_model = INTEL_INT(Detail.targetview_model);
892                 Detail.planets_suns = INTEL_INT(Detail.planets_suns);
893                 Detail.weapon_extras = INTEL_INT(Detail.weapon_extras);
894 #ifdef MAKE_FS1
895                 if (pfile_version >= 141)
896                         Detail.engine_glows = INTEL_INT(Detail.engine_glows);
897 #endif
898         } else {
899                 // it's the old way... un-swap and the new way will be used on save
900                 Detail.setting = INTEL_INT(Detail.setting);
901         }
902 }
903
904 // Will write the pilot file in the most current format
905 //
906 // if single == 1, save into the single players directory, else save into the multiplayers directory
907 int write_pilot_file_core(player *p)
908 {
909         char filename[MAX_FILENAME_LEN + 1];
910    int i, si_index, idx;
911         ubyte is_multi;
912         CFILE *file;
913
914         // never save a pilot file for the standalone server in multiplayer
915         if ((Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER)) {
916                 return 0;
917         }
918
919         if (!p) {
920                 Assert((Player_num >= 0) && (Player_num < MAX_PLAYERS));
921                 p = &Players[Player_num];
922         }
923
924         i = strlen(p->callsign);
925         if (i == 0)
926                 return 0;       //      This means there is no player, probably meaning he was deleted and game exited from same screen.
927
928         Assert((i > 0) && (i <= MAX_FILENAME_LEN - 4));  // ensure we won't overrun the buffer
929         strcpy( filename, p->callsign);
930         strcat( filename, NOX(".plr") );
931
932         // determine if this pilot is a multiplayer pilot or not
933         if (p->flags & PLAYER_FLAGS_IS_MULTI){
934                 is_multi = 1;
935         } else {
936                 is_multi = 0;
937         }
938
939         // see above
940         if ( !is_multi ){
941                 file = cfopen(filename, "wb", CFILE_NORMAL, CF_TYPE_SINGLE_PLAYERS);
942         } else {
943                 file = cfopen(filename, "wb", CFILE_NORMAL, CF_TYPE_MULTI_PLAYERS);
944         }
945
946         if (!file){
947                 return errno;
948         }
949
950         // Write out player's info
951         cfwrite_uint(PLR_FILE_ID, file);
952         cfwrite_uint(CURRENT_PLAYER_FILE_VERSION, file);
953
954         cfwrite_ubyte(is_multi, file);
955         cfwrite_int(p->stats.rank, file);
956         cfwrite_ubyte((ubyte) p->on_bastion, file);
957
958         cfwrite_int(p->tips, file);
959
960         // write out the image file name
961         cfwrite_string_len(p->image_filename, file);
962
963         // write out the image file name
964         cfwrite_string_len(p->squad_name, file);
965         cfwrite_string_len(p->squad_filename, file);
966
967         // write out the name of the player's active campaign.
968         cfwrite_string_len(p->current_campaign, file);  
969
970         // write the ship name for last ship flown by the player
971         si_index = p->last_ship_flown_si_index;
972         if((si_index < 0) || (si_index >= Num_ship_types)){
973                 si_index = 0;
974         }
975
976         cfwrite_string_len(Ship_info[si_index].name, file);
977
978         // ---------------------------------------------
979         // write the keyboard/joystick configuration
980         // ---------------------------------------------
981         cfwrite_ubyte( CCFG_MAX, file );
982         for (i=0; i<CCFG_MAX; i++) {
983                 cfwrite_short( Control_config[i].key_id, file );
984                 cfwrite_short( Control_config[i].joy_id, file );
985         }               
986
987         // if this hud is an observer, the player ended the last mission as an observer, so we should
988         // restore his "real" ship HUD.
989         HUD_CONFIG_TYPE hc_temp;
990         hc_temp.show_flags = 0;
991         int stored_observer = 0;
992         if ( HUD_config.is_observer ){
993                 // if we're in mission, copy the HUD we're currently using
994                 if(Game_mode & GM_IN_MISSION){                  
995                         memcpy(&hc_temp,&HUD_config,sizeof(HUD_CONFIG_TYPE));
996                         stored_observer = 1;
997                 }
998
999                 hud_config_restore();                           
1000         }
1001
1002         // write the hud configuration
1003         cfwrite_int(HUD_config.show_flags, file);       
1004         cfwrite_int(HUD_config.show_flags2, file);      
1005         cfwrite_int(HUD_config.popup_flags, file);      
1006         cfwrite_int(HUD_config.popup_flags2, file);     
1007         cfwrite_ubyte( (ubyte) HUD_config.num_msg_window_lines, file );
1008         cfwrite_int( HUD_config.rp_flags, file );
1009         cfwrite_int( HUD_config.rp_dist, file );
1010 #ifdef MAKE_FS1
1011         cfwrite_int( HUD_config.main_color, file );
1012         cfwrite_int( HUD_color_alpha, file );
1013 #endif
1014         for(idx=0; idx<NUM_HUD_GAUGES; idx++){
1015                 cfwrite(&HUD_config.clr[idx], sizeof(color), 1, file);
1016         }
1017
1018         // restore the HUD we backed up
1019         if( (Game_mode & GM_IN_MISSION) && stored_observer ){           
1020                 memcpy(&HUD_config,&hc_temp,sizeof(HUD_CONFIG_TYPE));
1021         }
1022
1023         // write the cutscenes which have been viewed
1024         cfwrite_int(Cutscenes_viewable, file);
1025
1026         // store the digital sound fx volume, and music volume
1027         cfwrite_float(Master_sound_volume, file);
1028         cfwrite_float(Master_event_music_volume, file);
1029         cfwrite_float(Master_voice_volume, file);
1030
1031
1032         //cfwrite( &Detail, sizeof(detail_levels), 1, file );
1033         write_detail_settings(file);
1034
1035         // store list of most recently played missions
1036         cfwrite_int(Num_recent_missions, file);
1037         for (i=0; i<Num_recent_missions; i++) {
1038                 cfwrite_string_len(Recent_missions[i], file);
1039         }
1040
1041         // write the player stats
1042         write_stats_block(file, &p->stats);     
1043    cfwrite_int(Game_skill_level, file);
1044
1045         for (i=0; i<NUM_JOY_AXIS_ACTIONS; i++) {
1046                 cfwrite_int(Axis_map_to[i], file);
1047                 cfwrite_int(Invert_axis[i], file);
1048         }
1049
1050         // store some player flags
1051    cfwrite_int(Player->save_flags, file);
1052
1053         // store ship selection for most recent mission
1054         pilot_write_loadout(file);
1055
1056         // read in multiplayer options  
1057         write_multiplayer_options(p, file);
1058
1059         cfwrite_int(p->readyroom_listing_mode, file);
1060    cfwrite_int(Briefing_voice_enabled, file);
1061
1062         // store the default netgame protocol mode for this pilot
1063         if (Multi_options_g.protocol == NET_TCP) {              
1064                 cfwrite_int(NET_TCP, file);             
1065         } else {
1066                 cfwrite_int(NET_IPX, file);
1067         }       
1068
1069         red_alert_write_wingman_status(file);
1070         pilot_write_techroom_data(file);
1071
1072         // store auto-advance pref
1073    cfwrite_int(Player->auto_advance, file);
1074
1075         cfwrite_int(Use_mouse_to_fly, file);
1076         cfwrite_int(Mouse_sensitivity, file);
1077         cfwrite_int(Joy_sensitivity, file);
1078         cfwrite_int(Dead_zone_size, file);
1079
1080         if (!cfclose(file))
1081                 return 0;
1082
1083         return errno;
1084 }
1085
1086 int write_pilot_file(player *the_player)
1087 {
1088         int pilot_write_rval;
1089         do {
1090                 // write_pilot_file_core returns 0 if ok, non-zero for error
1091                 pilot_write_rval = write_pilot_file_core(the_player);
1092
1093                 // check with user if write not successful
1094                 if (pilot_write_rval) {
1095                         int popup_rval = popup(PF_TITLE_RED | PF_TITLE_BIG, 3, XSTR( "&Retry", 41), XSTR( "&Ignore", 42), XSTR( "&Quit Game", 43),
1096                                 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) );
1097
1098                         // quit game popup return value (2)
1099                         if (popup_rval == 2) {
1100                                 exit(1);
1101                         }
1102
1103                         // _ignore_ popup return value (1) - don't save the file
1104                         if (popup_rval) {
1105                                 return pilot_write_rval;
1106                         }
1107
1108                         // retry popup return value (0) - try again 
1109                 }
1110
1111         } while (pilot_write_rval);
1112
1113         // write successful
1114         return 0;
1115 }
1116
1117 void write_stats_block(CFILE *file,scoring_struct *stats)
1118 {
1119         int i;
1120         int total;
1121
1122         cfwrite_int(stats->score, file);
1123         cfwrite_int(stats->rank, file);
1124         cfwrite_int(stats->assists, file);
1125         for (i=0; i<NUM_MEDALS; i++){
1126                 cfwrite_int(stats->medals[i], file);
1127         }
1128
1129         total = MAX_SHIP_TYPES;
1130         while (total && !stats->kills[total - 1]){  // find last used element
1131                 total--;
1132         }
1133
1134         cfwrite_int(total, file);
1135         for (i=0; i<total; i++){
1136                 cfwrite_ushort(stats->kills[i], file);
1137         }
1138
1139         cfwrite_int(stats->kill_count,file);
1140         cfwrite_int(stats->kill_count_ok,file);
1141
1142    cfwrite_uint(stats->p_shots_fired,file);
1143         cfwrite_uint(stats->s_shots_fired,file);
1144         cfwrite_uint(stats->p_shots_hit,file);
1145         cfwrite_uint(stats->s_shots_hit,file);
1146         cfwrite_uint(stats->p_bonehead_hits,file);
1147         cfwrite_uint(stats->s_bonehead_hits,file);
1148         cfwrite_uint(stats->bonehead_kills,file);
1149 }
1150
1151 // write the various detail settings
1152 void write_detail_settings(CFILE *file)
1153 {
1154         // we still need sane values in the Detail struct so create
1155         // a temporary one to value swap and write to file
1156         detail_levels Detail_tmp;
1157         memset(&Detail_tmp, 0, sizeof(detail_levels));
1158         memcpy(&Detail_tmp, &Detail, sizeof(detail_levels));
1159
1160         // swap, swap, swap - on big-endian this will convert back to little-endian
1161         Detail_tmp.setting = INTEL_INT(Detail_tmp.setting);
1162         Detail_tmp.nebula_detail = INTEL_INT(Detail_tmp.nebula_detail);
1163         Detail_tmp.detail_distance = INTEL_INT(Detail_tmp.detail_distance);
1164         Detail_tmp.hardware_textures = INTEL_INT(Detail_tmp.hardware_textures);
1165         Detail_tmp.num_small_debris = INTEL_INT(Detail_tmp.num_small_debris);
1166         Detail_tmp.num_particles = INTEL_INT(Detail_tmp.num_particles);
1167         Detail_tmp.num_stars = INTEL_INT(Detail_tmp.num_stars);
1168         Detail_tmp.shield_effects = INTEL_INT(Detail_tmp.shield_effects);
1169         Detail_tmp.lighting = INTEL_INT(Detail_tmp.lighting);
1170         Detail_tmp.targetview_model = INTEL_INT(Detail_tmp.targetview_model);
1171         Detail_tmp.planets_suns = INTEL_INT(Detail_tmp.planets_suns);
1172         Detail_tmp.weapon_extras = INTEL_INT(Detail_tmp.weapon_extras);
1173
1174 #ifdef MAKE_FS1
1175         Detail.engine_glows = INTEL_INT(Detail.engine_glows);
1176 #endif // MAKE_FS1
1177
1178         cfwrite( &Detail_tmp, sizeof(detail_levels), 1, file );
1179 }
1180
1181 // write multiplayer information
1182 void write_multiplayer_options(player *p,CFILE *file)
1183 {       
1184         // write the netgame options
1185         cfwrite_ubyte(p->m_server_options.squad_set,file);
1186         cfwrite_ubyte(p->m_server_options.endgame_set,file);    
1187         cfwrite_int(p->m_server_options.flags,file);
1188         cfwrite_uint(p->m_server_options.respawn,file);
1189         cfwrite_ubyte(p->m_server_options.max_observers,file);
1190         cfwrite_ubyte(p->m_server_options.skill_level,file);
1191         cfwrite_ubyte(p->m_server_options.voice_qos,file);
1192         cfwrite_int(p->m_server_options.voice_token_wait,file);
1193         cfwrite_int(p->m_server_options.voice_record_time,file);
1194         cfwrite(&p->m_server_options.mission_time_limit,sizeof(fix),1,file);
1195         cfwrite_int(p->m_server_options.kill_limit,file);
1196
1197         // write the local options
1198         cfwrite_int(p->m_local_options.flags,file);
1199         cfwrite_int(p->m_local_options.obj_update_level,file);
1200 }
1201
1202 // read multiplayer options
1203 void read_multiplayer_options(player *p,CFILE *file)
1204 {
1205         // read the netgame options
1206         p->m_server_options.squad_set = cfread_ubyte(file);
1207         p->m_server_options.endgame_set = cfread_ubyte(file);   
1208         p->m_server_options.flags = cfread_int(file);
1209         p->m_server_options.respawn = cfread_uint(file);
1210         p->m_server_options.max_observers = cfread_ubyte(file);
1211         p->m_server_options.skill_level = cfread_ubyte(file);
1212         p->m_server_options.voice_qos = cfread_ubyte(file);
1213         p->m_server_options.voice_token_wait = cfread_int(file);
1214         p->m_server_options.voice_record_time = cfread_int(file);
1215         cfread(&p->m_server_options.mission_time_limit,sizeof(fix),1,file);
1216         p->m_server_options.kill_limit = cfread_int(file);
1217
1218         // read the local options
1219         p->m_local_options.flags = cfread_int(file);
1220         p->m_local_options.obj_update_level = cfread_int(file);
1221 }
1222
1223 // run thorough an open file (at the beginning) and see if this pilot is a multiplayer pilot
1224 int is_pilot_multi(CFILE *fp)
1225 {
1226         uint id,file_version;
1227         ubyte is_multi;
1228         
1229         id = cfread_uint(fp);
1230         if (id != PLR_FILE_ID) {
1231                 Warning(LOCATION, "Player file has invalid signature");
1232                 cfclose(fp);
1233                 return -1;
1234         }
1235
1236         // check for compatibility here
1237         file_version = cfread_uint(fp);
1238         if (file_version < LOWEST_COMPATIBLE_PLAYER_FILE_VERSION) {
1239                 nprintf(("Warning", "WARNING => Player file is outdated and not compatible...\n"));
1240                 cfclose(fp);
1241                 return -1;
1242         }
1243
1244         // read in whether he's a multiplayer or not
1245         is_multi = cfread_ubyte(fp);
1246         if (is_multi)
1247                 return 1;
1248
1249         return 0;
1250 }
1251
1252 int is_pilot_multi(player *p)
1253 {
1254         return (p->flags & PLAYER_FLAGS_IS_MULTI) ? 1 : 0;
1255 }
1256
1257 // this works on barracks and player_select interface screens
1258 void init_new_pilot(player *p, int reset)
1259 {
1260         int cur_speed;
1261
1262         if (reset) {
1263                 hud_set_default_hud_config(p);          // use a default hud config
1264
1265                 // in the demo, load up the hardcoded hcf file
1266 #ifdef FS2_DEMO
1267                 hud_config_color_load("hud_1.hcf");
1268 #else
1269                 hud_config_color_load("hud_3.hcf");
1270 #endif
1271
1272                 control_config_reset_defaults();                // get a default keyboard config
1273                 player_set_pilot_defaults(p);                   // set up any player struct defaults
1274
1275                 cur_speed = os_config_read_uint(NULL, NOX("ComputerSpeed"), 2 );
1276                 if ( cur_speed < 0 )    {
1277                         cur_speed = 0;
1278                 } else if ( cur_speed >= NUM_DEFAULT_DETAIL_LEVELS )    {
1279                         cur_speed = NUM_DEFAULT_DETAIL_LEVELS-1;
1280                 }       
1281                 // always set to high
1282                 // DKA: 8/4/99 USE speed from registry
1283                 // cur_speed = NUM_DEFAULT_DETAIL_LEVELS-2;
1284
1285 #if NUM_DEFAULT_DETAIL_LEVELS != 4
1286 #error Code in ManagePilot assumes NUM_DEFAULT_DETAIL_LEVELS = 4
1287 #endif
1288
1289                 detail_level_set(cur_speed);
1290
1291                 Game_skill_level = game_get_default_skill_level();
1292
1293                 mprintf(( "Setting detail level to %d because of new pilot\n", cur_speed ));
1294                 Use_mouse_to_fly = 0;
1295                 Mouse_sensitivity = 4;
1296                 Joy_sensitivity = 9;
1297                 Dead_zone_size = 10;
1298         }
1299
1300         // unassigned squadron
1301         strcpy(p->squad_name, XSTR("Unassigned", 1255));
1302         strcpy(p->squad_filename, "");
1303
1304         // set him to be a single player pilot by default (the actual creation routines will change this if necessary)
1305         p->flags &= ~PLAYER_FLAGS_IS_MULTI;
1306
1307         // effectively sets the length return by strlen() to 0  
1308         Campaign.filename[0] = 0;
1309         p->on_bastion = 0;
1310
1311         // pick a random pilot image for this guy
1312         if (reset){
1313                 pilot_set_random_pic(p);
1314                 p->insignia_texture = -1;
1315                 pilot_set_random_squad_pic(p);
1316         }
1317
1318         init_scoring_element(&p->stats);        
1319         
1320         p->stats.score = 0;
1321         p->stats.rank = RANK_ENSIGN;    
1322
1323         p->tips = 1;
1324
1325         Multi_options_g.protocol = NET_TCP;     
1326
1327         // initialize default multiplayer options
1328         multi_options_set_netgame_defaults(&p->m_server_options);
1329         multi_options_set_local_defaults(&p->m_local_options);
1330
1331         Player_loadout.filename[0] = 0;
1332
1333         // reset the cutscenes which can be viewed
1334         if ( reset ){
1335                 Cutscenes_viewable = INTRO_CUTSCENE_FLAG;
1336         }
1337 }
1338
1339 void pilot_set_short_callsign(player *p, int max_width)
1340 {
1341         strcpy(p->short_callsign, p->callsign);
1342         gr_set_font(FONT1);
1343         gr_force_fit_string(p->short_callsign, CALLSIGN_LEN - 1, max_width);
1344         gr_get_string_size( &(p->short_callsign_width), NULL, p->short_callsign );
1345 }
1346
1347 // pick a random image for the passed player
1348 void pilot_set_random_pic(player *p)
1349 {
1350         // if there are no available pilot pics, set the image filename to null
1351         if (Num_pilot_images <= 0) {
1352                 strcpy(p->image_filename, "");
1353         } else {
1354                 // pick a random name from the list
1355                 int random_index = rand() % Num_pilot_images;
1356                 Assert((random_index >= 0) && (random_index < Num_pilot_images));
1357                 strcpy(p->image_filename, Pilot_images_arr[random_index]);
1358         }       
1359 }
1360
1361 // pick a random image for the passed player
1362 void pilot_set_random_squad_pic(player *p)
1363 {       
1364         // if there are no available pilot pics, set the image filename to null
1365         if (Num_pilot_squad_images <= 0) {
1366                 player_set_squad_bitmap(p, "");
1367                 // strcpy(p->squad_filename, "");               
1368         } else {
1369                 // pick a random name from the list
1370                 int random_index = rand() % Num_pilot_squad_images;             
1371                 Assert((random_index >= 0) && (random_index < Num_pilot_squad_images));
1372                 player_set_squad_bitmap(p, Pilot_squad_images_arr[random_index]); 
1373                 // strcpy(p->squad_filename, Pilot_squad_images_arr[random_index]);
1374         }       
1375 }
1376
1377 // format a pilot's callsign into a "personal" form - ie, adding a 's or just an ' as appropriate
1378 void pilot_format_callsign_personal(const char *in_callsign, char *out_callsign)
1379 {
1380         // don't do anything if we've got invalid strings
1381         if((in_callsign == NULL) || (out_callsign == NULL)){
1382                 return;
1383         }
1384
1385         // copy the original string
1386         strcpy(out_callsign,in_callsign);
1387
1388         // tack on the appropriate postfix
1389         if(in_callsign[strlen(in_callsign) - 1] == 's'){                
1390                 strcat(out_callsign,XSTR( "\'", 45));
1391         } else {
1392                 strcat(out_callsign,XSTR( "\'s", 46));
1393         }
1394 }
1395
1396 // throw up a popup asking the user to verify the overwrite of an existing pilot name
1397 // 1 == ok to overwrite, 0 == not ok
1398 int pilot_verify_overwrite()
1399 {
1400         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));
1401 }
1402
1403 extern int Skip_packfile_search;  // located in CFileList.cpp
1404
1405
1406 // load up the list of pilot image filenames (do this at game startup as well as barracks startup)
1407 void pilot_load_pic_list()
1408 {
1409         Num_pilot_images = 0;
1410         
1411         // load pilot images from the player images directory
1412         Num_pilot_images = cf_get_file_list_preallocated(MAX_PILOT_IMAGES, Pilot_images_arr, Pilot_image_names, CF_TYPE_PLAYER_IMAGES_MAIN, NOX("*.pcx"));
1413
1414         // sort all filenames
1415         cf_sort_filenames(Num_pilot_images, Pilot_image_names, CF_SORT_NAME);
1416 }
1417
1418 // load up the list of pilot squad filenames
1419 void pilot_load_squad_pic_list()
1420 {
1421         Num_pilot_squad_images = 0;
1422         
1423         // load pilot images from the player images directory
1424         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"));
1425
1426         // sort all filenames
1427         cf_sort_filenames(Num_pilot_squad_images, Pilot_squad_image_names, CF_SORT_NAME);
1428 }
1429
1430 // will attempt to load an insignia bitmap and set it as active for the player
1431 void player_set_squad_bitmap(player *p, const char *fname)
1432 {
1433         // sanity check
1434         if(p == NULL){
1435                 return;
1436         }
1437
1438         // if he has another bitmap already - unload it
1439         if(p->insignia_texture >= 0){
1440                 bm_unload(p->insignia_texture);
1441         }
1442
1443         p->insignia_texture = -1;
1444
1445         // try and set the new one
1446         if (fname != p->squad_filename) {
1447                 strncpy(p->squad_filename, fname, MAX_FILENAME_LEN);
1448         }
1449
1450         if(strlen(p->squad_filename) > 0){
1451                 p->insignia_texture = bm_load_duplicate(fname);
1452                 
1453                 // lock is as a transparent texture
1454                 if(p->insignia_texture != -1){
1455                         bm_lock(p->insignia_texture, 16, BMP_TEX_XPARENT);
1456                         bm_unlock(p->insignia_texture);
1457                 }
1458         }
1459
1460         /*
1461         flen = strlen(filename);
1462         elen = strlen(ext);
1463         Assert(flen < MAX_PATH_LEN);
1464         strcpy(path, filename);
1465         if ((flen < 4) || stricmp(path + flen - elen, ext)) {
1466                 Assert(flen + elen < MAX_PATH_LEN);
1467                 strcat(path, ext);
1468         }
1469         */
1470 }
1471
1472 // set squadron
1473 void player_set_squad(player *p, const char *squad_name)
1474 {
1475         // sanity check
1476         if(p == NULL){
1477                 return;
1478         }
1479
1480         strncpy(p->squad_name, squad_name, NAME_LENGTH+1);
1481 }
1482
1483 DCF(pilot,"Changes pilot stats. (Like reset campaign)" )
1484 {
1485         if (Dc_command) {
1486                 dc_get_arg(ARG_STRING);
1487                 if (!strcmp(Dc_arg, NOX("reset"))) {
1488                         if (strlen(Campaign.filename)) {
1489                                 mission_campaign_savefile_delete(Campaign.filename);
1490                                 mission_campaign_load(Campaign.filename);
1491                         }
1492
1493                 } else {
1494                         Dc_help = 1;  // print usage, not stats
1495                 }
1496         }
1497
1498         if (Dc_help) {
1499                 dc_printf( "Usage: pilot keyword\nWhere keyword can be in the following forms:\n" );
1500                 dc_printf( "pilot reset                 Resets campaign stats.\n" );
1501                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
1502         }
1503
1504         if (Dc_status) {
1505                 // no stats
1506         }
1507 }
1508