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