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