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