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