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