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