]> icculus.org git repositories - taylor/freespace2.git/blob - src/menuui/playermenu.cpp
added copyright header
[taylor/freespace2.git] / src / menuui / playermenu.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/MenuUI/PlayerMenu.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code to drive the Player Select initial screen
16  *
17  * $Log$
18  * Revision 1.3  2002/06/09 04:41:22  relnev
19  * added copyright header
20  *
21  * Revision 1.2  2002/05/07 03:16:46  theoddone33
22  * The Great Newline Fix
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:09  root
25  * Initial import.
26  * 
27  * 
28  * 43    11/02/99 11:42a Jefff
29  * fixed copyright symbol in german fonts
30  * 
31  * 42    10/27/99 12:27a Jefff
32  * localized tips correctly
33  * 
34  * 41    9/13/99 4:52p Dave
35  * RESPAWN FIX
36  * 
37  * 40    9/02/99 11:10a Jefff
38  * fixed 1024 list display bug - was only showing 8 pilots at a time
39  * 
40  * 39    8/26/99 8:51p Dave
41  * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
42  * 
43  * 38    8/26/99 9:45a Dave
44  * First pass at easter eggs and cheats.
45  * 
46  * 37    8/16/99 6:39p Jefff
47  * 
48  * 36    8/16/99 6:37p Jefff
49  * minor string alterations
50  * 
51  * 35    8/05/99 4:17p Dave
52  * Tweaks to client interpolation.
53  * 
54  * 34    8/05/99 11:29a Mikek
55  * Jacked up number of comments from 20 to 40, thereby doubling the
56  * quality of our game.
57  * 
58  * 33    8/04/99 10:53a Dave
59  * Added title to the user tips popup.
60  * 
61  * 32    8/03/99 3:21p Jefff
62  * 
63  * 31    8/03/99 10:32a Jefff
64  * raised location of bottom_text to not interfere w/ logo.  changed
65  * "please enter callsign" to "type callsign and press enter"
66  * 
67  * 30    8/02/99 9:13p Dave
68  * Added popup tips.
69  * 
70  * 29    7/30/99 10:29a Jefff
71  * fixed colors of bottom display texts
72  * 
73  * 28    7/27/99 7:17p Jefff
74  * Replaced some art text with XSTR() text.
75  * 
76  * 27    7/19/99 2:06p Jasons
77  * Remove all palette stuff from player select menu.
78  * 
79  * 26    7/15/99 9:20a Andsager
80  * FS2_DEMO initial checkin
81  * 
82  * 25    7/09/99 9:51a Dave
83  * Added thick polyline code.
84  * 
85  * 24    6/11/99 11:13a Dave
86  * last minute changes before press tour build.
87  * 
88  * 23    5/21/99 6:45p Dave
89  * Sped up ui loading a bit. Sped up localization disk access stuff. Multi
90  * start game screen, multi password, and multi pxo-help screen.
91  * 
92  * 22    4/25/99 3:02p Dave
93  * Build defines for the E3 build.
94  * 
95  * 21    3/25/99 2:31p Neilk
96  * Coordinate changes to handle new artwork
97  * 
98  * 20    2/25/99 4:19p Dave
99  * Added multiplayer_beta defines. Added cd_check define. Fixed a few
100  * release build warnings. Added more data to the squad war request and
101  * response packets.
102  * 
103  * 19    2/01/99 5:55p Dave
104  * Removed the idea of explicit bitmaps for buttons. Fixed text
105  * highlighting for disabled gadgets.
106  * 
107  * 18    1/30/99 5:08p Dave
108  * More new hi-res stuff.Support for nice D3D textures.
109  * 
110  * 17    1/30/99 1:53a Dave
111  * Fix some harcoded coords.
112  * 
113  * 16    1/30/99 1:28a Dave
114  * 1024x768 full support.
115  * 
116  * 15    1/29/99 1:25p Dave
117  * New code for choose pilot screen.
118  * 
119  * 14    1/29/99 12:47a Dave
120  * Put in sounds for beam weapon. A bunch of interface screens (tech
121  * database stuff).
122  * 
123  * 13    1/12/99 12:53a Dave
124  * More work on beam weapons - made collision detection very efficient -
125  * collide against all object types properly - made 3 movement types
126  * smooth. Put in test code to check for possible non-darkening pixels on
127  * object textures.
128  * 
129  * 12    12/18/98 1:13a Dave
130  * Rough 1024x768 support for Direct3D. Proper detection and usage through
131  * the launcher.
132  * 
133  * 11    12/06/98 2:36p Dave
134  * Drastically improved nebula fogging.
135  * 
136  * 10    12/01/98 6:20p Dave
137  * Removed tga test bitmap code.
138  * 
139  * 9     12/01/98 4:46p Dave
140  * Put in targa bitmap support (16 bit).
141  * 
142  * 8     11/30/98 1:07p Dave
143  * 16 bit conversion, first run.
144  * 
145  * 7     11/20/98 11:16a Dave
146  * Fixed up IPX support a bit. Making sure that switching modes and
147  * loading/saving pilot files maintains proper state.
148  * 
149  * 6     11/19/98 4:19p Dave
150  * Put IPX sockets back in psnet. Consolidated all multiplayer config
151  * files into one.
152  * 
153  * 5     11/05/98 4:18p Dave
154  * First run nebula support. Beefed up localization a bit. Removed all
155  * conditional compiles for foreign versions. Modified mission file
156  * format.
157  * 
158  * 4     10/13/98 9:28a Dave
159  * Started neatening up freespace.h. Many variables renamed and
160  * reorganized. Added AlphaColors.[h,cpp]
161  * 
162  * 3     10/09/98 2:57p Dave
163  * Starting splitting up OS stuff.
164  * 
165  * 2     10/07/98 10:53a Dave
166  * Initial checkin.
167  * 
168  * 1     10/07/98 10:49a Dave
169  * 
170  *
171  * $NoKeywords: $
172  *
173  */
174
175 #include <ctype.h>
176
177 #include "playermenu.h"
178 #include "2d.h"
179 #include "ui.h"
180 #include "gamesnd.h"
181 #include "player.h"
182 #include "cfile.h"
183 #include "key.h"
184 #include "managepilot.h"
185 #include "missionscreencommon.h"
186 #include "bmpman.h"
187 #include "freespace.h"
188 #include "parselo.h"
189 #include "gamesequence.h"
190 #include "timer.h"
191 #include "cmdline.h"
192 #include "osregistry.h"
193 #include "palman.h"
194 #include "mainhallmenu.h"
195 #include "multi.h"
196 #include "popup.h"
197 #include "mouse.h"
198 #include "alphacolors.h"
199 #include "localize.h"
200
201 // --------------------------------------------------------------------------------------------------------
202 // Demo title screen
203 #ifdef FS2_DEMO
204 static int Demo_title_active = 0;
205 static int Demo_title_bitmap = -1;
206 static int Demo_title_expire_timestamp = 0;
207 static int Demo_title_need_fade_in = 1;
208 static char *Demo_title_bitmap_filename = NOX("DemoTitle1");
209 #endif
210
211 // --------------------------------------------------------------------------------------------------------
212 // PLAYER SELECT defines
213 //
214
215 //#define MAX_PLAYER_SELECT_LINES               8                                                       // max # of pilots displayed at once
216 int Player_select_max_lines[GR_NUM_RESOLUTIONS] = {                     // max # of pilots displayed at once
217         8,                      // GR_640
218         15                      // GR_1024
219 };
220
221 // button control defines
222 #define NUM_PLAYER_SELECT_BUTTONS       8                                                       // button control defines
223
224 #define CREATE_PILOT_BUTTON                     0                                                       //      
225 #define CLONE_BUTTON                                            1                                                       //
226 #define DELETE_BUTTON                                   2                                                       //
227 #define SCROLL_LIST_UP_BUTTON                   3                                                       //
228 #define SCROLL_LIST_DOWN_BUTTON         4                                                       //
229 #define ACCEPT_BUTTON                                   5                                                       //
230 #define SINGLE_BUTTON                                   6                                                       //
231 #define MULTI_BUTTON                                            7                                                       //
232
233 // list text display area
234 int Choose_list_coords[GR_NUM_RESOLUTIONS][4] = {
235         { // GR_640
236                 114, 117, 400, 87
237         },
238         { // GR_1024
239                 183, 186, 640, 139
240         }
241 };
242
243 char *Player_select_background_bitmap_name[GR_NUM_RESOLUTIONS] = {
244         "ChoosePilot",
245         "2_ChoosePilot"
246 };
247 char *Player_select_background_mask_bitmap[GR_NUM_RESOLUTIONS] = {
248         "ChoosePilot-m",
249         "2_ChoosePilot-m"
250 };
251 // #define PLAYER_SELECT_PALETTE                                                        NOX("ChoosePilotPalette")       // palette for the screen       
252
253 #define PLAYER_SELECT_MAIN_HALL_OVERLAY         NOX("MainHall1")                                // main hall help overlay
254
255 // convenient struct for handling all button controls
256 struct barracks_buttons {
257         char *filename;
258         int x, y, xt, yt;
259         int hotspot;
260         UI_BUTTON button;  // because we have a class inside this struct, we need the constructor below..
261
262         barracks_buttons(char *name, int x1, int y1, int xt1, int yt1, int h) : filename(name), x(x1), y(y1), xt(xt1), yt(yt1), hotspot(h) {}
263 };
264
265 static barracks_buttons Player_select_buttons[GR_NUM_RESOLUTIONS][NUM_PLAYER_SELECT_BUTTONS] = {        
266         { // GR_640
267                 // create, clone and delete (respectively)
268                 barracks_buttons("CPB_00",              114,    205,    117,    240,    0),
269                 barracks_buttons("CPB_01",              172,    205,    175,    240,    1),
270                 barracks_buttons("CPB_02",              226,    205,    229,    240,    2),
271
272                 // scroll up, scroll down,      and accept (respectively)
273                 barracks_buttons("CPB_03",              429,    213,    -1,     -1,     3),
274                 barracks_buttons("CPB_04",              456,    213,    -1,     -1,     4),
275                 barracks_buttons("CPB_05",              481,  207,      484,    246,    5),     
276                 
277                 // single player select and multiplayer select, respectively
278                 barracks_buttons("CPB_06",              428,    82,     430,    108,    6),
279                 barracks_buttons("CPB_07",              477,    82,     481,    108,    7)
280         }, 
281         { // GR_1024
282                 // create, clone and delete (respectively)
283                 barracks_buttons("2_CPB_00",    182,  328,      199,    384,    0),
284                 barracks_buttons("2_CPB_01",    275,    328,    292,    384,    1),
285                 barracks_buttons("2_CPB_02",    361,    328,    379,    384,    2),
286
287                 // scroll up, scroll down, and accept (respectively)
288                 barracks_buttons("2_CPB_03",    686,    341,    -1,     -1,     3),
289                 barracks_buttons("2_CPB_04",    729,    341,    -1,     -1,     4),
290                 barracks_buttons("2_CPB_05",    770,  332,      787,    394,    5),     
291                 
292                 // single player select and multiplayer select, respectively
293                 barracks_buttons("2_CPB_06",    685,    132,    700,    173,    6),
294                 barracks_buttons("2_CPB_07",    764,    132,    782,    173,    7)
295         }
296 };
297
298 // FIXME add to strings.tbl
299 #define PLAYER_SELECT_NUM_TEXT                  1
300 UI_XSTR Player_select_text[GR_NUM_RESOLUTIONS][PLAYER_SELECT_NUM_TEXT] = {
301         { // GR_640
302                 { "Choose Pilot",               1436,           122,    90,     UI_XSTR_COLOR_GREEN, -1, NULL }
303         }, 
304         { // GR_1024
305                 { "Choose Pilot",               1436,           195,    143,    UI_XSTR_COLOR_GREEN, -1, NULL }
306         }
307 };
308
309 UI_WINDOW Player_select_window;                                                         // ui window for this screen
310 UI_BUTTON Player_select_list_region;                                            // button for detecting mouse clicks on this screen
311 UI_INPUTBOX Player_select_input_box;                                            // input box for adding new pilot names                         
312
313 // #define PLAYER_SELECT_PALETTE_FNAME                                  NOX("InterfacePalette")
314 int Player_select_background_bitmap;                                            // bitmap for this screen
315 // int Player_select_palette;                                                                           // palette bitmap for this screen
316 int Player_select_autoaccept = 0;
317 // int Player_select_palette_set = 0;
318
319 // flag indicating if this is the absolute first pilot created and selected. Used to determine
320 // if the main hall should display the help overlay screen
321 int Player_select_very_first_pilot = 0;                 
322 int Player_select_initial_count = 0;
323 char Player_select_very_first_pilot_callsign[CALLSIGN_LEN + 2];
324
325 extern int Main_hall_bitmap;                                                                    // bitmap handle to the main hall bitmap
326
327 int Player_select_mode;                                                                                 // single or multiplayer - never set directly. use player_select_init_player_stuff()
328 int Player_select_num_pilots;                                                                   // # of pilots on the list
329 int Player_select_list_start;                                                                   // index of first list item to start displaying in the box
330 int Player_select_pilot;                                                                            // index into the Pilot array of which is selected as the active pilot
331 int Player_select_input_mode;                                                                   // 0 if the player _isn't_ typing a callsign, 1 if he is
332 char Pilots_arr[MAX_PILOTS][MAX_FILENAME_LEN];          
333 char *Pilots[MAX_PILOTS];
334 int Player_select_clone_flag;                                                                   // clone the currently selected pilot
335 char Player_select_last_pilot[CALLSIGN_LEN + 10];               // callsign of the last used pilot, or none if there wasn't one
336 int Player_select_last_is_multi;
337
338 int Player_select_force_bastion = 0;
339
340 // notification text areas
341
342 static int Player_select_bottom_text_y[GR_NUM_RESOLUTIONS] = {
343         314,    // GR_640
344         502     // GR_1024
345 };
346
347 static int Player_select_middle_text_y[GR_NUM_RESOLUTIONS] = {
348         253,    // GR_640
349         404     // GR_1024
350 };
351
352 char Player_select_bottom_text[150] = "";
353 char Player_select_middle_text[150] = "";
354 void player_select_set_bottom_text(char *txt);
355 void player_select_set_middle_text(char *txt);
356
357
358 // FORWARD DECLARATIONS
359 void player_select_init_player_stuff(int mode);                 // switch between single and multiplayer modes
360 void player_select_set_input_mode(int n);                                       
361 void player_select_button_pressed(int n);
362 void player_select_scroll_list_up();
363 void player_select_scroll_list_down();
364 int player_select_create_new_pilot();
365 void player_select_delete_pilot();
366 void player_select_display_all_text();
367 void player_select_display_copyright();
368 void player_select_set_bottom_text(char *txt);
369 void player_select_set_controls(int gray);
370 void player_select_draw_list();
371 void player_select_process_noninput(int k);
372 void player_select_process_input(int k);
373 int player_select_pilot_file_filter(char *filename);
374 int player_select_get_last_pilot_info();
375 void player_select_eval_very_first_pilot();
376 void player_select_commit();
377 void player_select_cancel_create();
378
379
380 // basically, gray out all controls (gray == 1), or ungray the controls (gray == 0) 
381 void player_select_set_controls(int gray)
382 {
383         int idx;
384         
385         for(idx=0;idx<NUM_PLAYER_SELECT_BUTTONS;idx++){
386                 if(gray){
387                         Player_select_buttons[gr_screen.res][idx].button.disable();
388                 } else {
389                         Player_select_buttons[gr_screen.res][idx].button.enable();
390                 }
391         }
392 }
393
394 // functions for selecting single/multiplayer pilots at the very beginning of Freespace
395 void player_select_init()
396 {                       
397         int i;
398         barracks_buttons *b;   
399         UI_WINDOW *w;
400
401         // start a looping ambient sound
402         main_hall_start_ambient();
403
404         Player_select_force_bastion = 0;
405
406 #ifdef FS2_DEMO
407         /*
408         Demo_title_bitmap = bm_load(Demo_title_bitmap_filename);
409         if ( Demo_title_bitmap >= 0 ) {
410 #ifndef HARDWARE_ONLY
411                 palette_use_bm_palette(Demo_title_bitmap);
412 #endif
413                 Demo_title_active = 1;
414                 Demo_title_expire_timestamp = timestamp(5000);
415         } else {
416                 Demo_title_active = 0;
417         }
418         */
419         Demo_title_active = 0;
420 #endif
421
422         // create the UI window
423         Player_select_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
424         Player_select_window.set_mask_bmap(Player_select_background_mask_bitmap[gr_screen.res]);
425         
426         // initialize the control buttons
427         for (i=0; i<NUM_PLAYER_SELECT_BUTTONS; i++) {
428                 b = &Player_select_buttons[gr_screen.res][i];
429
430                 // create the button
431                 if ( (i == SCROLL_LIST_UP_BUTTON) || (i == SCROLL_LIST_DOWN_BUTTON) )
432                         b->button.create(&Player_select_window, NULL, b->x, b->y, 60, 30, 1, 1);
433                 else
434                         b->button.create(&Player_select_window, NULL, b->x, b->y, 60, 30, 1, 1);
435
436                 // set its highlight action
437                 b->button.set_highlight_action(common_play_highlight_sound);
438
439                 // set its animation bitmaps
440                 b->button.set_bmaps(b->filename);
441
442                 // link the mask hotspot
443                 b->button.link_hotspot(b->hotspot);
444         }               
445
446         // add some text
447         w = &Player_select_window;      
448         w->add_XSTR("Create", 1034, Player_select_buttons[gr_screen.res][CREATE_PILOT_BUTTON].xt, Player_select_buttons[gr_screen.res][CREATE_PILOT_BUTTON].yt, &Player_select_buttons[gr_screen.res][CREATE_PILOT_BUTTON].button, UI_XSTR_COLOR_GREEN);        
449         w->add_XSTR("Clone", 1040, Player_select_buttons[gr_screen.res][CLONE_BUTTON].xt, Player_select_buttons[gr_screen.res][CLONE_BUTTON].yt, &Player_select_buttons[gr_screen.res][CLONE_BUTTON].button, UI_XSTR_COLOR_GREEN);      
450         w->add_XSTR("Remove", 1038, Player_select_buttons[gr_screen.res][DELETE_BUTTON].xt, Player_select_buttons[gr_screen.res][DELETE_BUTTON].yt, &Player_select_buttons[gr_screen.res][DELETE_BUTTON].button, UI_XSTR_COLOR_GREEN);  
451         
452         w->add_XSTR("Select", 1039, Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].xt, Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].yt, &Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].button, UI_XSTR_COLOR_PINK);   
453         w->add_XSTR("Single", 1041, Player_select_buttons[gr_screen.res][SINGLE_BUTTON].xt, Player_select_buttons[gr_screen.res][SINGLE_BUTTON].yt, &Player_select_buttons[gr_screen.res][SINGLE_BUTTON].button, UI_XSTR_COLOR_GREEN);  
454         w->add_XSTR("Multi", 1042, Player_select_buttons[gr_screen.res][MULTI_BUTTON].xt, Player_select_buttons[gr_screen.res][MULTI_BUTTON].yt, &Player_select_buttons[gr_screen.res][MULTI_BUTTON].button, UI_XSTR_COLOR_GREEN);      
455         for(i=0; i<PLAYER_SELECT_NUM_TEXT; i++) {
456                 w->add_XSTR(&Player_select_text[gr_screen.res][i]);
457         }
458
459
460         // create the list button text select region
461         Player_select_list_region.create(&Player_select_window, "", Choose_list_coords[gr_screen.res][0], Choose_list_coords[gr_screen.res][1], Choose_list_coords[gr_screen.res][2], Choose_list_coords[gr_screen.res][3], 0, 1);
462         Player_select_list_region.hide();
463
464         // create the pilot callsign input box
465         Player_select_input_box.create(&Player_select_window, Choose_list_coords[gr_screen.res][0], Choose_list_coords[gr_screen.res][1], Choose_list_coords[gr_screen.res][2] , CALLSIGN_LEN - 1, "", UI_INPUTBOX_FLAG_INVIS | UI_INPUTBOX_FLAG_KEYTHRU | UI_INPUTBOX_FLAG_LETTER_FIRST);
466         Player_select_input_box.set_valid_chars(VALID_PILOT_CHARS);
467         Player_select_input_box.hide();
468         Player_select_input_box.disable();
469         
470         // not currently entering any text
471         Player_select_input_mode = 0;   
472
473         // set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
474         Player_select_buttons[gr_screen.res][SCROLL_LIST_UP_BUTTON].button.set_hotkey(KEY_UP);
475         Player_select_buttons[gr_screen.res][SCROLL_LIST_DOWN_BUTTON].button.set_hotkey(KEY_DOWN);
476         Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(KEY_ENTER);
477         Player_select_buttons[gr_screen.res][CREATE_PILOT_BUTTON].button.set_hotkey(KEY_C);
478
479         // disable the single player button in the multiplayer beta
480 #ifdef MULTIPLAYER_BETA_BUILD
481         Player_select_buttons[gr_screen.res][SINGLE_BUTTON].button.hide();
482         Player_select_buttons[gr_screen.res][SINGLE_BUTTON].button.disable();
483 #elif defined(E3_BUILD) || defined(PRESS_TOUR_BUILD)
484         Player_select_buttons[gr_screen.res][MULTI_BUTTON].button.hide();
485         Player_select_buttons[gr_screen.res][MULTI_BUTTON].button.disable();
486 #endif
487
488
489         // attempt to load in the background bitmap
490         Player_select_background_bitmap = bm_load(Player_select_background_bitmap_name[gr_screen.res]);                         
491         Assert(Player_select_background_bitmap >= 0);   
492
493         // load in the palette for the screen
494         // Player_select_palette = bm_load(PLAYER_SELECT_PALETTE);
495         // Player_select_palette_set = 0;
496
497         // unset the very first pilot data
498         Player_select_very_first_pilot = 0;
499         Player_select_initial_count = -1;
500         memset(Player_select_very_first_pilot_callsign, 0, CALLSIGN_LEN + 2);   
501
502 //      if(Player_select_num_pilots == 0){
503 //              Player_select_autoaccept = 1;
504 //      }
505                 
506         // if we found a pilot
507 #if defined(DEMO) || defined(OEM_BUILD) || defined(E3_BUILD) || defined(PRESS_TOUR_BUILD) // not for FS2_DEMO
508         player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);     
509 #elif defined(MULTIPLAYER_BETA_BUILD)
510         player_select_init_player_stuff(PLAYER_SELECT_MODE_MULTI);      
511 #else
512         if (player_select_get_last_pilot_info()) {
513                 if (Player_select_last_is_multi) {
514                         player_select_init_player_stuff(PLAYER_SELECT_MODE_MULTI);
515                 } else {
516                         player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
517                 }
518         } 
519         // otherwise go to the single player mode by default
520         else {
521                 player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
522         }
523 #endif  
524
525         if((Player_select_num_pilots == 1) && Player_select_input_mode){
526                 Player_select_autoaccept = 1;
527         }       
528 }
529
530 #ifdef FS2_DEMO
531 // Display the demo title screen
532 void demo_title_blit()
533 {
534         int k;
535
536         Mouse_hidden = 1;
537
538         if ( timestamp_elapsed(Demo_title_expire_timestamp) ) {
539                 Demo_title_active = 0;
540         }
541
542         k = game_poll();
543         if ( k > 0 ) {
544                 Demo_title_active = 0;
545         }
546
547         if ( Demo_title_need_fade_in ) {
548                 gr_fade_out(0);
549         }
550         
551         gr_set_bitmap(Demo_title_bitmap);
552         gr_bitmap(0,0);
553
554         gr_flip();
555
556         if ( Demo_title_need_fade_in ) {
557                 gr_fade_in(0);
558                 Demo_title_need_fade_in = 0;
559         }
560
561         if ( !Demo_title_active ) {
562                 gr_fade_out(0);
563                 Mouse_hidden = 0;
564         }
565 }
566
567 #endif
568
569 void player_select_do()
570 {
571         int k;
572
573 #ifdef FS2_DEMO
574         if ( Demo_title_active ) {
575                 // demo_title_blit();
576                 return;
577         }
578 #endif
579
580         //if ( !Player_select_palette_set ) {
581         //      Assert(Player_select_palette >= 0);
582 //#ifndef HARDWARE_ONLY
583 //              palette_use_bm_palette(Player_select_palette);
584 //#endif
585 //              Player_select_palette_set = 1;
586 //      }
587                 
588         // set the input box at the "virtual" line 0 to be active so the player can enter a callsign
589         if (Player_select_input_mode){
590                 Player_select_input_box.set_focus();
591         }
592
593         // process any ui window stuff
594         k = Player_select_window.process();
595         if(k){
596                 extern void game_process_cheats(int k);
597                 game_process_cheats(k);
598         }
599         switch(k){
600         // switch between single and multiplayer modes
601         case KEY_TAB : 
602 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
603                 break;
604 #else
605
606                 if(Player_select_input_mode){
607                         gamesnd_play_iface(SND_GENERAL_FAIL);
608                         break;
609                 }
610                 // play a little sound
611                 gamesnd_play_iface(SND_USER_SELECT);
612                 if(Player_select_mode == PLAYER_SELECT_MODE_MULTI){                                     
613                         player_select_set_bottom_text(XSTR( "Single-Player Mode", 376));
614                                 
615                         // reinitialize as single player mode
616                         player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
617                 } else if(Player_select_mode == PLAYER_SELECT_MODE_SINGLE){                                                                             
618                         player_select_set_bottom_text(XSTR( "Multiplayer Mode", 377));
619                                 
620                         // reinitialize as multiplayer mode
621                         player_select_init_player_stuff(PLAYER_SELECT_MODE_MULTI);
622                 }
623                 break;  
624 #endif
625         }       
626
627         // draw the player select pseudo-dialog over it
628         gr_set_bitmap(Player_select_background_bitmap);
629         gr_bitmap(0,0);
630
631         // press the accept button
632         if (Player_select_autoaccept) {
633                 Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].button.press_button();
634         }
635         
636         // draw any ui window stuf
637         Player_select_window.draw();
638
639         // light up the correct mode button (single or multi)
640         if (Player_select_mode == PLAYER_SELECT_MODE_SINGLE){
641                 Player_select_buttons[gr_screen.res][SINGLE_BUTTON].button.draw_forced(2);
642         } else {
643                 Player_select_buttons[gr_screen.res][MULTI_BUTTON].button.draw_forced(2);
644         }
645
646         // draw the pilot list text
647         player_select_draw_list();      
648
649         // draw copyright message on the bottom on the screen
650         player_select_display_copyright();
651
652         if (!Player_select_input_mode) {
653                 player_select_process_noninput(k);
654         } else {
655                 player_select_process_input(k);
656         }
657         
658         // draw any pending messages on the bottom or middle of the screen
659         player_select_display_all_text();       
660
661 #ifndef RELEASE_REAL
662         // gr_set_color_fast(&Color_bright_green);
663         // gr_string(0x8000, 10, "Development version - DO NOT RELEASE");
664 #endif
665         
666         /*
667         gr_set_color(255, 0, 0);
668         vector whee[5];
669         vector *arr[5] = {&whee[0], &whee[1], &whee[2], &whee[3], &whee[4]};
670         whee[0].x = 10; whee[0].y = 10; whee[0].z = 0.0f;
671         whee[1].x = 50; whee[1].y = 50; whee[1].z = 0.0f;
672         whee[2].x = 50; whee[2].y = 90; whee[2].z = 0.0f;
673         whee[3].x = 90; whee[3].y = 130; whee[3].z = 0.0f;
674         whee[4].x = 180; whee[4].y = 130; whee[4].z = 0.0f;
675         gr_pline_special(arr, 5, 2);
676         */
677         
678
679         gr_flip();
680 }
681
682 void player_select_close()
683 {
684         // destroy the player select window
685         Player_select_window.destroy();
686
687         // if we're in input mode - we should undo the pilot create reqeust
688         if(Player_select_input_mode){
689                 player_select_cancel_create();
690         }
691         
692         // actually set up the Player struct here       
693         if((Player_select_pilot == -1) || (Player_select_num_pilots == 0)){
694                 nprintf(("General","WARNING! No pilot selected! We should be exiting the game now!\n"));
695                 return;
696         }
697
698         // unload all bitmaps
699         if(Player_select_background_bitmap >= 0){
700                 bm_release(Player_select_background_bitmap);
701                 Player_select_background_bitmap = -1;
702         } 
703         // if(Player_select_palette >= 0){
704         //      bm_release(Player_select_palette);
705                 //Player_select_palette = -1;
706         // }
707                         
708         // setup the player  struct
709         Player_num = 0;
710         Player = &Players[0];
711         Player->flags |= PLAYER_FLAGS_STRUCTURE_IN_USE;
712                 
713         // now read in a the pilot data
714         if (read_pilot_file(Pilots[Player_select_pilot], !Player_select_mode, Player) != 0) {
715                 Error(LOCATION,"Couldn't load pilot file, bailing");
716                 Player = NULL;
717         }               
718
719         if (Player_select_force_bastion) {
720                 Player->on_bastion = 1;
721         }
722 }
723
724 void player_select_set_input_mode(int n)
725 {
726         int i;
727
728         // set the input mode
729         Player_select_input_mode = n;   
730         
731         // enable all the player select buttons
732         for (i=0; i<NUM_PLAYER_SELECT_BUTTONS; i++){
733                 Player_select_buttons[gr_screen.res][i].button.enable(!n);
734         }
735
736         Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].button.set_hotkey(n ? -1 : KEY_ENTER);
737         Player_select_buttons[gr_screen.res][CREATE_PILOT_BUTTON].button.set_hotkey(n ? -1 : KEY_C);
738
739         // enable the player select input box
740         if(Player_select_input_mode){
741                 Player_select_input_box.enable();
742                 Player_select_input_box.unhide();
743         } else {
744                 Player_select_input_box.hide();
745                 Player_select_input_box.disable();
746         }
747 }
748
749 void player_select_button_pressed(int n)
750 {
751         int ret;
752
753         switch (n) {
754         case SCROLL_LIST_UP_BUTTON:
755                 player_select_set_bottom_text("");
756
757                 player_select_scroll_list_up();
758                 break;
759
760         case SCROLL_LIST_DOWN_BUTTON:
761                 player_select_set_bottom_text("");
762
763                 player_select_scroll_list_down();
764                 break;
765
766         case ACCEPT_BUTTON:
767                 // make sure he has a valid pilot selected
768                 if (Player_select_pilot < 0) {                                                          
769                         popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR( "You must select a valid pilot first", 378));
770                 } else {
771                         player_select_commit();                         
772                 }
773                 break;
774
775         case CLONE_BUTTON:
776                 // if we're at max-pilots, don't allow another to be added
777                 if (Player_select_num_pilots >= MAX_PILOTS) {
778                         player_select_set_bottom_text(XSTR( "You already have the maximum # of pilots!", 379));
779                         
780                         gamesnd_play_iface(SND_GENERAL_FAIL);
781                         break;
782                 }
783
784                 if (Player_select_pilot >= 0) {                                         
785                         // first we have to make sure this guy is actually loaded for when we create the clone
786                         if (Player == NULL) {
787                                 Player = &Players[0];
788                                 Player->flags |= PLAYER_FLAGS_STRUCTURE_IN_USE;
789                         }                               
790
791                         // attempt to read in the pilot file of the guy to be cloned
792                         if (read_pilot_file(Pilots[Player_select_pilot], !Player_select_mode, Player) != 0) {
793                                 Error(LOCATION,"Couldn't load pilot file, bailing");
794                                 Player = NULL;
795                                 Int3();
796                         }                               
797
798                         // set the clone flag
799                         Player_select_clone_flag = 1;
800
801                         // create the new pilot (will be cloned with Player_select_clone_flag_set)
802                         if (!player_select_create_new_pilot()) {                                        
803                                 player_select_set_bottom_text(XSTR( "Error creating new pilot file!", 380));
804                                 Player_select_clone_flag = 0;
805                                 memset(Player,0,sizeof(player));
806                                 Player = NULL;
807                                 break;
808                         }                               
809
810                         // clear the player out
811                         // JH: What the hell?  How do you clone a pilot if you clear out the source you are copying
812                         // from?  These next 2 lines are pure stupidity, so I commented them out!
813 //                      memset(Player,0,sizeof(player));
814 //                      Player = NULL;
815                                 
816                         // display some text on the bottom of the dialog
817                         player_select_set_bottom_text(XSTR( "Type Callsign and Press Enter", 381));                             
818                         
819                         // gray out all controls in the dialog
820                         player_select_set_controls(1);                                  
821                 }
822                 break;
823
824         case CREATE_PILOT_BUTTON:
825                 // if we're at max-pilots, don't allow another to be added
826                 if(Player_select_num_pilots >= MAX_PILOTS){
827                         player_select_set_bottom_text(XSTR( "You already have the maximum # of pilots!", 379));
828
829                         gamesnd_play_iface(SND_GENERAL_FAIL);
830                         break;
831                 }
832
833                 // create a new pilot
834                 if (!player_select_create_new_pilot()) {
835                         player_select_set_bottom_text(XSTR( "Type Callsign and Press Enter", 381));
836                 }
837
838                 // don't clone anyone
839                 Player_select_clone_flag = 0;
840                         
841                 // display some text on the bottom of the dialog                        
842                 player_select_set_bottom_text(XSTR( "Type Callsign and Press Enter", 381));
843                         
844                 // gray out all controls
845                 player_select_set_controls(1);                                          
846                 break;
847
848         case DELETE_BUTTON:
849                 player_select_set_bottom_text("");
850
851                 if (Player_select_pilot >= 0) {
852                         // display a popup requesting confirmation
853                         ret = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_NO, POPUP_YES, XSTR( "Warning!\n\nAre you sure you wish to delete this pilot?", 382));
854
855                         // delete the pilot
856                         if(ret == 1){
857                                 player_select_delete_pilot();
858                         } 
859                 }
860                 break;
861
862         case SINGLE_BUTTON:
863                 player_select_set_bottom_text("");
864
865                 Player_select_autoaccept = 0;
866                 // switch to single player mode
867                 if (Player_select_mode != PLAYER_SELECT_MODE_SINGLE) {
868                         // play a little sound
869                         gamesnd_play_iface(SND_USER_SELECT);
870                                 
871                         player_select_set_bottom_text(XSTR( "Single Player Mode", 376));
872                                 
873                         // reinitialize as single player mode
874                         player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
875                 } else {
876                         gamesnd_play_iface(SND_GENERAL_FAIL);
877                 }
878                 break;
879
880         case MULTI_BUTTON:
881                 player_select_set_bottom_text("");
882
883                 Player_select_autoaccept = 0;
884 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
885                 game_feature_not_in_demo_popup();
886 #else
887                 // switch to multiplayer mode
888                 if (Player_select_mode != PLAYER_SELECT_MODE_MULTI) {
889                         // play a little sound
890                         gamesnd_play_iface(SND_USER_SELECT);
891                         
892                         player_select_set_bottom_text(XSTR( "Multiplayer Mode", 377));
893                                 
894                         // reinitialize as multiplayer mode
895                         player_select_init_player_stuff(PLAYER_SELECT_MODE_MULTI);
896                 } else {
897                         gamesnd_play_iface(SND_GENERAL_FAIL);
898                 }
899 #endif
900                 break;
901         }
902 }
903
904 int player_select_create_new_pilot()
905 {
906         int idx;
907
908         // make sure we haven't reached the max
909         if (Player_select_num_pilots >= MAX_PILOTS) {
910                 gamesnd_play_iface(SND_GENERAL_FAIL);
911                 return 0;
912         }
913
914         int play_scroll_sound = 1;
915
916 #ifdef FS2_DEMO
917         if ( Demo_title_active ) {
918                 play_scroll_sound = 0;
919         }
920 #endif
921
922         if ( play_scroll_sound ) {
923                 gamesnd_play_iface(SND_SCROLL);
924         }
925
926         idx = Player_select_num_pilots; 
927         
928         // move all the pilots in the list up
929         while (idx--) {
930                 strcpy(Pilots[idx + 1], Pilots[idx]);           
931         }       
932
933         // by default, set the default netgame protocol to be VMT
934         Multi_options_g.protocol = NET_TCP;     
935
936         // select the beginning of the list
937         Player_select_pilot = 0;
938         Player_select_num_pilots++;
939         Pilots[Player_select_pilot][0] = 0;
940         Player_select_list_start= 0;
941
942         // set us to be in input mode
943         player_select_set_input_mode(1);
944         
945         // set the input box to have focus
946         Player_select_input_box.set_focus();
947         Player_select_input_box.set_text("");
948         Player_select_input_box.update_dimensions(Choose_list_coords[gr_screen.res][0], Choose_list_coords[gr_screen.res][1], Choose_list_coords[gr_screen.res][2], gr_get_font_height());      
949
950         return 1;
951 }
952
953 void player_select_delete_pilot()
954 {
955         char filename[MAX_PATH_LEN + 1];
956         int i, deleted_cur_pilot;
957
958         deleted_cur_pilot = 0;
959
960         // tack on the full path and the pilot file extension
961         // build up the path name length
962         // make sure we do this based upon whether we're in single or multiplayer mode
963         strcpy( filename, Pilots[Player_select_pilot] );
964         strcat( filename, NOX(".plr") );
965
966         // attempt to delete the pilot
967         if (Player_select_mode == PLAYER_SELECT_MODE_SINGLE) {
968                 cf_delete( filename, CF_TYPE_SINGLE_PLAYERS );
969         } else {
970                 cf_delete( filename, CF_TYPE_MULTI_PLAYERS );
971         }
972
973         // delete all the campaign save files for this pilot.
974         mission_campaign_delete_all_savefiles( Pilots[Player_select_pilot], (Player_select_mode != PLAYER_SELECT_MODE_SINGLE) );
975
976         // move all the players down
977         for (i=Player_select_pilot; i<Player_select_num_pilots-1; i++){
978                 strcpy(Pilots[i], Pilots[i + 1]);               
979         }               
980
981         // correcly set the # of pilots and the currently selected pilot
982         Player_select_num_pilots--;
983         if (Player_select_pilot >= Player_select_num_pilots) {
984                 Player_select_pilot = Player_select_num_pilots - 1;             
985         }               
986
987 }
988
989 // scroll the list of players up
990 void player_select_scroll_list_up()
991 {
992         if (Player_select_pilot == -1)
993                 return;
994
995         // change the pilot selected index and play the appropriate sound
996         if (Player_select_pilot) {
997                 Player_select_pilot--;
998                 gamesnd_play_iface(SND_SCROLL);
999         } else {
1000                 gamesnd_play_iface(SND_GENERAL_FAIL);
1001         }
1002                 
1003         if (Player_select_pilot < Player_select_list_start){
1004                 Player_select_list_start = Player_select_pilot;
1005         }
1006 }
1007
1008 // scroll the list of players down
1009 void player_select_scroll_list_down()
1010 {       
1011         // change the pilot selected index and play the appropriate sound
1012         if (Player_select_pilot < Player_select_num_pilots - 1) {
1013                 Player_select_pilot++;
1014                 gamesnd_play_iface(SND_SCROLL);
1015         } else {
1016                 gamesnd_play_iface(SND_GENERAL_FAIL);
1017         }
1018                 
1019         if (Player_select_pilot >= (Player_select_list_start + Player_select_max_lines[gr_screen.res])){
1020                 Player_select_list_start++;
1021         }
1022 }
1023
1024 // fill in the data on the last played pilot (callsign and is_multi or not)
1025 int player_select_get_last_pilot_info()
1026 {
1027         char *last_player;
1028
1029         last_player = os_config_read_string( NULL, "LastPlayer", NULL);
1030         
1031         if(last_player == NULL){
1032                 return 0;               
1033         } else {
1034                 strcpy(Player_select_last_pilot,last_player);
1035         }
1036
1037         // determine if he was a single or multi-player based upon the last character in his callsign
1038         Player_select_last_is_multi = Player_select_last_pilot[strlen(Player_select_last_pilot)-1] == 'M' ? 1 : 0;
1039         Player_select_last_pilot[strlen(Player_select_last_pilot)-1]='\0';
1040
1041         return 1;       
1042 }
1043
1044 int player_select_get_last_pilot()
1045 {
1046         // if the player has the Cmdline_use_last_pilot command line option set, try and drop out quickly
1047         if(Cmdline_use_last_pilot){                     
1048                 int idx;                                
1049
1050                 if(!player_select_get_last_pilot_info()){
1051                         return 0;
1052                 }
1053
1054                 if(Player_select_last_is_multi){
1055                         Player_select_num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_MULTI_PLAYERS, NOX("*.plr"), CF_SORT_TIME);                            
1056                 } else {
1057                         Player_select_num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_SINGLE_PLAYERS, NOX("*.plr"), CF_SORT_TIME);                                           
1058                 }
1059
1060                 Player_select_pilot = -1;
1061                 idx = 0;
1062                 // pick the last player         
1063                 for(idx=0;idx<Player_select_num_pilots;idx++){
1064                         if(strcmp(Player_select_last_pilot,Pilots_arr[idx])==0){
1065                                 Player_select_pilot = idx;
1066                                 break;
1067                         }
1068                 }               
1069
1070                 // set this so that we don't incorrectly create a "blank" pilot - .plr
1071                 // in the player_select_close() function
1072                 Player_select_num_pilots = 0;
1073
1074                 // if we've actually found a valid pilot, load him up           
1075                 if(Player_select_pilot != -1){
1076                         Player = &Players[0];                   
1077                         read_pilot_file(Pilots_arr[idx],!Player_select_last_is_multi,Player);
1078                         Player->flags |= PLAYER_FLAGS_STRUCTURE_IN_USE;
1079                         return 1;               
1080                 }                       
1081         } 
1082
1083         return 0;
1084 }
1085
1086 void player_select_init_player_stuff(int mode)
1087 {                       
1088         Player_select_list_start = 0;   
1089
1090         // set the select mode to single player for default
1091         Player_select_mode = mode;
1092
1093         // load up the list of players based upon the Player_select_mode (single or multiplayer)
1094         Get_file_list_filter = player_select_pilot_file_filter;
1095         if (mode == PLAYER_SELECT_MODE_SINGLE){
1096                 Player_select_num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_SINGLE_PLAYERS, NOX("*.plr"), CF_SORT_TIME);
1097         } else {
1098                 Player_select_num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_MULTI_PLAYERS, NOX("*.plr"), CF_SORT_TIME);
1099         }
1100
1101         Player = NULL;  
1102
1103         // if this value is -1, it means we should set it to the num pilots count
1104         if(Player_select_initial_count == -1){
1105                 Player_select_initial_count = Player_select_num_pilots;
1106         }
1107                 
1108         // select the first pilot if any exist, otherwise set to -1
1109         if (Player_select_num_pilots == 0) {            
1110                 Player_select_pilot = -1;               
1111                 player_select_set_middle_text(XSTR( "Type Callsign and Press Enter", 381));
1112                 player_select_set_controls(1);          // gray out the controls
1113                 player_select_create_new_pilot();
1114         } else {
1115                 Player_select_pilot = 0;        
1116         }
1117 }
1118
1119 void player_select_draw_list()
1120 {
1121         int idx;
1122
1123         for (idx=0; idx<Player_select_max_lines[gr_screen.res]; idx++) {
1124                 // only draw as many pilots as we have
1125                 if ((idx + Player_select_list_start) == Player_select_num_pilots)
1126                         break;
1127
1128                 // if the currently selected pilot is this line, draw it highlighted
1129                 if ( (idx + Player_select_list_start) == Player_select_pilot) {
1130                         // if he's the active pilot and is also the current selection, super-highlight him                                                                      
1131                         gr_set_color_fast(&Color_text_active);
1132                 }
1133                 // otherwise draw him normally
1134                 else {
1135                         gr_set_color_fast(&Color_text_normal);
1136                 }
1137                 
1138                 // draw the actual callsign
1139                 gr_printf(Choose_list_coords[gr_screen.res][0], Choose_list_coords[gr_screen.res][1] + (idx * gr_get_font_height()), Pilots[idx + Player_select_list_start]);
1140         }
1141 }
1142
1143 void player_select_process_noninput(int k)
1144 {
1145         int idx;
1146         
1147         // check for pressed buttons
1148         for (idx=0; idx<NUM_PLAYER_SELECT_BUTTONS; idx++) {
1149                 if (Player_select_buttons[gr_screen.res][idx].button.pressed()) {
1150                         player_select_button_pressed(idx);
1151                 }
1152         }       
1153
1154         // check for keypresses
1155         switch (k) {                    
1156         // quit the game entirely
1157         case KEY_ESC:
1158                 gameseq_post_event(GS_EVENT_QUIT_GAME);
1159                 break;
1160
1161         case KEY_ENTER | KEY_CTRLED:
1162                 player_select_button_pressed(ACCEPT_BUTTON);
1163                 break;
1164
1165         // delete the currently highlighted pilot
1166         case KEY_DELETE:
1167                 if (Player_select_pilot >= 0) {
1168                         int ret;
1169
1170                         // display a popup requesting confirmation
1171                         ret = popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON,2,POPUP_NO,POPUP_YES,XSTR( "Are you sure you want to delete this pilot?", 383));                                                                             
1172
1173                         // delete the pilot
1174                         if(ret == 1){
1175                                 player_select_delete_pilot();
1176                         } 
1177                 }
1178                 break;  
1179         }
1180
1181         // check to see if the user has clicked on the "list region" button
1182         // and change the selected pilot appropriately
1183         if (Player_select_list_region.pressed()) {
1184                 int click_y;
1185                 // get the mouse position
1186                 Player_select_list_region.get_mouse_pos(NULL, &click_y);
1187                 
1188                 // determine what index to select
1189                 //idx = (click_y+5) / 10;
1190                 idx = click_y / gr_get_font_height();
1191
1192
1193                 // if he selected a valid item
1194                 if(((idx + Player_select_list_start) < Player_select_num_pilots) && (idx >= 0)){
1195                         Player_select_pilot = idx + Player_select_list_start;                   
1196                 }
1197         }
1198
1199         // if the player has double clicked on a valid pilot, choose it and hit the accept button
1200         if (Player_select_list_region.double_clicked()) {
1201                 if ((Player_select_pilot >= 0) && (Player_select_pilot < Player_select_num_pilots)) {
1202                         player_select_button_pressed(ACCEPT_BUTTON);
1203                 }
1204         }
1205 }
1206
1207 void player_select_process_input(int k)
1208 {
1209         char buf[CALLSIGN_LEN + 1];
1210         int idx,z;
1211         
1212         // if the player is in the process of typing in a new pilot name...
1213         switch (k) {
1214         // cancel create pilot
1215         case KEY_ESC:
1216                 player_select_cancel_create();          
1217                 break;
1218
1219         // accept a new pilot name
1220         case KEY_ENTER:
1221                 Player_select_input_box.get_text(buf);
1222                 drop_white_space(buf);
1223                 z = 0;
1224                 if (!isalpha(*buf)) {
1225                         z = 1;
1226                 } else {
1227                         for (idx=1; buf[idx]; idx++) {
1228                                 if (!isalpha(buf[idx]) && !isdigit(buf[idx]) && !strchr(VALID_PILOT_CHARS, buf[idx])) {
1229                                         z = 1;
1230                                         break;
1231                                 }
1232                         }
1233                 }
1234
1235                 for (idx=1; idx<Player_select_num_pilots; idx++) {
1236                         if (!stricmp(buf, Pilots[idx])) {
1237                                 // verify if it is ok to overwrite the file
1238                                 if (pilot_verify_overwrite() == 1) {
1239                                         // delete the pilot and select the beginning of the list
1240                                         Player_select_pilot = idx;
1241                                         player_select_delete_pilot();
1242                                         Player_select_pilot = 0;
1243                                         idx = Player_select_num_pilots;
1244                                         z = 0;
1245
1246                                 } else
1247                                         z = 1;
1248
1249                                 break;
1250                         }
1251                 }
1252
1253                 if (!*buf || (idx < Player_select_num_pilots)) {
1254                         z = 1;
1255                 }
1256
1257                 if (z) {
1258                         gamesnd_play_iface(SND_GENERAL_FAIL);
1259                         break;
1260                 }               
1261
1262                 // Create the new pilot, and write out his file
1263                 strcpy(Pilots[0], buf);
1264
1265                 // if this is the first guy, we should set the Player struct
1266                 if (Player == NULL) {
1267                         Player = &Players[0];
1268                         memset(Player, 0, sizeof(player));
1269                         Player->flags |= PLAYER_FLAGS_STRUCTURE_IN_USE;
1270                 }
1271
1272                 strcpy(Player->callsign, buf);
1273                 init_new_pilot(Player, !Player_select_clone_flag);
1274
1275                 // set him as being a multiplayer pilot if we're in the correct mode
1276                 if (Player_select_mode == PLAYER_SELECT_MODE_MULTI) {
1277                         Player->flags |= PLAYER_FLAGS_IS_MULTI;
1278                         Player->stats.flags |= STATS_FLAG_MULTIPLAYER;
1279                 }
1280
1281                 // create his pilot file
1282                 write_pilot_file(Player);
1283
1284                 // unset the player
1285                 memset(Player, 0, sizeof(player));
1286                 Player = NULL;
1287
1288                 // make this guy the selected pilot and put him first on the list
1289                 Player_select_pilot = 0;
1290                                 
1291                 // unset the input mode
1292                 player_select_set_input_mode(0);
1293
1294                 // clear any pending bottom text
1295                 player_select_set_bottom_text("");              
1296
1297                 // clear any pending middle text
1298                 player_select_set_middle_text("");
1299                                 
1300                 // ungray all the controls
1301                 player_select_set_controls(0);
1302
1303                 // evaluate whether or not this is the very first pilot
1304                 player_select_eval_very_first_pilot();
1305                 break;
1306
1307         case 0:
1308                 break;
1309
1310         // always kill middle text when a char is pressed in input mode
1311         default:
1312                 player_select_set_middle_text("");
1313                 break;
1314         }
1315 }
1316     
1317 // draw copyright message on the bottom on the screen
1318 void player_select_display_copyright()
1319 {
1320         int     sx, sy, w;
1321         char    Copyright_msg1[256], Copyright_msg2[256];
1322         
1323 //      strcpy(Copyright_msg1, XSTR("Descent: FreeSpace - The Great War, Copyright c 1998, Volition, Inc.", -1));
1324         gr_set_color_fast(&Color_white);
1325
1326         sprintf(Copyright_msg1, NOX("FreeSpace 2"));
1327 #if defined(GERMAN_BUILD)
1328         sprintf(Copyright_msg2, XSTR("Copyright %c 1999, Volition, Inc.  All rights reserved.", 385), '\xA8');
1329 #else
1330         sprintf(Copyright_msg2, XSTR("Copyright %c 1999, Volition, Inc.  All rights reserved.", 385), '\x83');
1331 #endif
1332
1333         gr_get_string_size(&w, NULL, Copyright_msg1);
1334         sx = fl2i((gr_screen.max_w / 2) - w/2.0f + 0.5f);
1335         sy = (gr_screen.max_h - 2) - 2*gr_get_font_height();
1336         gr_string(sx, sy, Copyright_msg1);
1337
1338         gr_get_string_size(&w, NULL, Copyright_msg2);
1339         sx = fl2i((gr_screen.max_w / 2) - w/2.0f + 0.5f);
1340         sy = (gr_screen.max_h - 2) - gr_get_font_height();
1341         gr_string(sx, sy, Copyright_msg2);
1342 }
1343
1344 void player_select_display_all_text()
1345 {
1346         int w, h;
1347
1348         // only draw if we actually have a valid string
1349         if (strlen(Player_select_bottom_text)) {
1350                 gr_get_string_size(&w, &h, Player_select_bottom_text);
1351         
1352                 w = (gr_screen.max_w - w) / 2;
1353                 gr_set_color_fast(&Color_bright_white);
1354                 gr_printf(w, Player_select_bottom_text_y[gr_screen.res], Player_select_bottom_text);
1355         }
1356
1357         // only draw if we actually have a valid string
1358         if (strlen(Player_select_middle_text)) {
1359                 gr_get_string_size(&w, &h, Player_select_middle_text);
1360         
1361                 w = (gr_screen.max_w - w) / 2;
1362                 gr_set_color_fast(&Color_bright_white);
1363                 gr_printf(w, Player_select_middle_text_y[gr_screen.res], Player_select_middle_text);
1364         }
1365 }
1366
1367 int player_select_pilot_file_filter(char *filename)
1368 {
1369         return !verify_pilot_file(filename, Player_select_mode == PLAYER_SELECT_MODE_SINGLE);
1370 }
1371
1372 void player_select_set_bottom_text(char *txt)
1373 {
1374         if (txt) {
1375                 strncpy(Player_select_bottom_text, txt, 149);
1376         }
1377 }
1378
1379 void player_select_set_middle_text(char *txt)
1380 {
1381         if (txt) {
1382                 strncpy(Player_select_middle_text, txt, 149);
1383         }
1384 }
1385
1386 void player_select_eval_very_first_pilot()
1387 {       
1388         // never bring up the initial main hall help overlay
1389         // Player_select_very_first_pilot = 0;
1390
1391         // if we already have this flag set, check to see if our callsigns match
1392         if(Player_select_very_first_pilot){
1393                 // if the callsign has changed, unset the flag
1394                 if(strcmp(Player_select_very_first_pilot_callsign,Pilots[Player_select_pilot])){
1395                         Player_select_very_first_pilot = 0;
1396                 }
1397         }
1398         // otherwise check to see if there is only 1 pilot
1399         else {
1400                 if((Player_select_num_pilots == 1) && (Player_select_initial_count == 0)){
1401                         // set up the data
1402                         Player_select_very_first_pilot = 1;
1403                         strcpy(Player_select_very_first_pilot_callsign,Pilots[Player_select_pilot]);
1404                 }
1405         }
1406 }
1407
1408 void player_select_commit()
1409 {
1410         // if we've gotten to this point, we should have ensured this was the case
1411         Assert(Player_select_num_pilots > 0);
1412         
1413         gameseq_post_event(GS_EVENT_MAIN_MENU);
1414         gamesnd_play_iface(SND_COMMIT_PRESSED);
1415
1416         // evaluate if this is the _very_ first pilot
1417         player_select_eval_very_first_pilot();
1418
1419
1420 void player_select_cancel_create()
1421 {
1422         int idx;
1423
1424         Player_select_num_pilots--;
1425
1426         // make sure we correct the Selected_pilot index to account for the cancelled action
1427         if (Player_select_num_pilots == 0) {
1428                 Player_select_pilot = -1;
1429         }
1430
1431         // move all pilots down
1432         for (idx=0; idx<Player_select_num_pilots; idx++) {
1433                 strcpy(Pilots[idx], Pilots[idx + 1]);
1434         }
1435
1436         // unset the input mode
1437         player_select_set_input_mode(0);
1438
1439         // clear any bottom text
1440         player_select_set_bottom_text("");
1441
1442         // clear any middle text
1443         player_select_set_middle_text("");
1444
1445         // ungray all controls
1446         player_select_set_controls(0);
1447
1448         // disable the autoaccept
1449         Player_select_autoaccept = 0;
1450 }
1451
1452 DCF(bastion,"Sets the player to be on the bastion")
1453 {
1454         if(gameseq_get_state() == GS_STATE_INITIAL_PLAYER_SELECT){
1455                 Player_select_force_bastion = 1;
1456                 dc_printf("Player is now in the Bastion\n");
1457         }
1458 }
1459
1460 #define MAX_PLAYER_TIPS                 40
1461
1462 char *Player_tips[MAX_PLAYER_TIPS];
1463 int Num_player_tips;
1464 int Player_tips_shown = 0;
1465
1466 // tooltips
1467 void player_tips_init()
1468 {
1469         Num_player_tips = 0;
1470
1471         // begin external localization stuff
1472         lcl_ext_open();
1473
1474         read_file_text("tips.tbl");
1475         reset_parse();
1476
1477         while(!optional_string("#end")){
1478                 required_string("+Tip:");
1479
1480                 if(Num_player_tips >= MAX_PLAYER_TIPS){
1481                         break;
1482                 }
1483                 Player_tips[Num_player_tips++] = stuff_and_malloc_string(F_NAME, NULL, 1024);                           
1484         }
1485
1486         // stop externalizing, homey
1487         lcl_ext_close();
1488 }
1489 void player_tips_popup()
1490 {
1491         int tip, ret;   
1492         
1493         // player has disabled tips
1494         if((Player != NULL) && !Player->tips){
1495                 return;
1496         }
1497         // only show tips once per instance of Freespace
1498         if(Player_tips_shown == 1){
1499                 return;
1500         }
1501         Player_tips_shown = 1;
1502
1503         // randomly pick one
1504         tip = (int)frand_range(0.0f, (float)Num_player_tips - 1.0f);
1505
1506         char all_txt[2048];     
1507
1508         do {
1509                 sprintf(all_txt, XSTR("NEW USER TIP\n\n%s", 1565), Player_tips[tip]);
1510                 ret = popup(PF_NO_SPECIAL_BUTTONS | PF_TITLE | PF_TITLE_WHITE, 3, XSTR("&Ok", 669), XSTR("&Next", 1444), XSTR("Don't show me this again", 1443), all_txt);
1511                 
1512                 // now what?
1513                 switch(ret){
1514                 // next
1515                 case 1:
1516                         if(tip >= Num_player_tips - 1){
1517                                 tip = 0;
1518                         } else {
1519                                 tip++;
1520                         }
1521                         break;
1522
1523                 // don't show me this again
1524                 case 2:
1525                         ret = 0;
1526                         Player->tips = 0;
1527                         write_pilot_file(Player);
1528                         break;
1529                 }
1530         } while(ret > 0);
1531 }