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