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