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