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