2 * $Logfile: /Freespace2/code/MenuUI/PlayerMenu.cpp $
7 * Code to drive the Player Select initial screen
10 * Revision 1.2 2002/05/07 03:16:46 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:09 root
17 * 43 11/02/99 11:42a Jefff
18 * fixed copyright symbol in german fonts
20 * 42 10/27/99 12:27a Jefff
21 * localized tips correctly
23 * 41 9/13/99 4:52p Dave
26 * 40 9/02/99 11:10a Jefff
27 * fixed 1024 list display bug - was only showing 8 pilots at a time
29 * 39 8/26/99 8:51p Dave
30 * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
32 * 38 8/26/99 9:45a Dave
33 * First pass at easter eggs and cheats.
35 * 37 8/16/99 6:39p Jefff
37 * 36 8/16/99 6:37p Jefff
38 * minor string alterations
40 * 35 8/05/99 4:17p Dave
41 * Tweaks to client interpolation.
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.
47 * 33 8/04/99 10:53a Dave
48 * Added title to the user tips popup.
50 * 32 8/03/99 3:21p Jefff
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"
56 * 30 8/02/99 9:13p Dave
59 * 29 7/30/99 10:29a Jefff
60 * fixed colors of bottom display texts
62 * 28 7/27/99 7:17p Jefff
63 * Replaced some art text with XSTR() text.
65 * 27 7/19/99 2:06p Jasons
66 * Remove all palette stuff from player select menu.
68 * 26 7/15/99 9:20a Andsager
69 * FS2_DEMO initial checkin
71 * 25 7/09/99 9:51a Dave
72 * Added thick polyline code.
74 * 24 6/11/99 11:13a Dave
75 * last minute changes before press tour build.
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.
81 * 22 4/25/99 3:02p Dave
82 * Build defines for the E3 build.
84 * 21 3/25/99 2:31p Neilk
85 * Coordinate changes to handle new artwork
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
92 * 19 2/01/99 5:55p Dave
93 * Removed the idea of explicit bitmaps for buttons. Fixed text
94 * highlighting for disabled gadgets.
96 * 18 1/30/99 5:08p Dave
97 * More new hi-res stuff.Support for nice D3D textures.
99 * 17 1/30/99 1:53a Dave
100 * Fix some harcoded coords.
102 * 16 1/30/99 1:28a Dave
103 * 1024x768 full support.
105 * 15 1/29/99 1:25p Dave
106 * New code for choose pilot screen.
108 * 14 1/29/99 12:47a Dave
109 * Put in sounds for beam weapon. A bunch of interface screens (tech
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
118 * 12 12/18/98 1:13a Dave
119 * Rough 1024x768 support for Direct3D. Proper detection and usage through
122 * 11 12/06/98 2:36p Dave
123 * Drastically improved nebula fogging.
125 * 10 12/01/98 6:20p Dave
126 * Removed tga test bitmap code.
128 * 9 12/01/98 4:46p Dave
129 * Put in targa bitmap support (16 bit).
131 * 8 11/30/98 1:07p Dave
132 * 16 bit conversion, first run.
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.
138 * 6 11/19/98 4:19p Dave
139 * Put IPX sockets back in psnet. Consolidated all multiplayer config
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
147 * 4 10/13/98 9:28a Dave
148 * Started neatening up freespace.h. Many variables renamed and
149 * reorganized. Added AlphaColors.[h,cpp]
151 * 3 10/09/98 2:57p Dave
152 * Starting splitting up OS stuff.
154 * 2 10/07/98 10:53a Dave
157 * 1 10/07/98 10:49a Dave
166 #include "playermenu.h"
173 #include "managepilot.h"
174 #include "missionscreencommon.h"
176 #include "freespace.h"
178 #include "gamesequence.h"
181 #include "osregistry.h"
183 #include "mainhallmenu.h"
187 #include "alphacolors.h"
188 #include "localize.h"
190 // --------------------------------------------------------------------------------------------------------
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");
200 // --------------------------------------------------------------------------------------------------------
201 // PLAYER SELECT defines
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
210 // button control defines
211 #define NUM_PLAYER_SELECT_BUTTONS 8 // button control defines
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 //
222 // list text display area
223 int Choose_list_coords[GR_NUM_RESOLUTIONS][4] = {
232 char *Player_select_background_bitmap_name[GR_NUM_RESOLUTIONS] = {
236 char *Player_select_background_mask_bitmap[GR_NUM_RESOLUTIONS] = {
240 // #define PLAYER_SELECT_PALETTE NOX("ChoosePilotPalette") // palette for the screen
242 #define PLAYER_SELECT_MAIN_HALL_OVERLAY NOX("MainHall1") // main hall help overlay
244 // convenient struct for handling all button controls
245 struct barracks_buttons {
249 UI_BUTTON button; // because we have a class inside this struct, we need the constructor below..
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) {}
254 static barracks_buttons Player_select_buttons[GR_NUM_RESOLUTIONS][NUM_PLAYER_SELECT_BUTTONS] = {
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),
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),
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)
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),
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),
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)
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] = {
291 { "Choose Pilot", 1436, 122, 90, UI_XSTR_COLOR_GREEN, -1, NULL }
294 { "Choose Pilot", 1436, 195, 143, UI_XSTR_COLOR_GREEN, -1, NULL }
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
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;
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];
314 extern int Main_hall_bitmap; // bitmap handle to the main hall bitmap
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;
327 int Player_select_force_bastion = 0;
329 // notification text areas
331 static int Player_select_bottom_text_y[GR_NUM_RESOLUTIONS] = {
336 static int Player_select_middle_text_y[GR_NUM_RESOLUTIONS] = {
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);
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();
369 // basically, gray out all controls (gray == 1), or ungray the controls (gray == 0)
370 void player_select_set_controls(int gray)
374 for(idx=0;idx<NUM_PLAYER_SELECT_BUTTONS;idx++){
376 Player_select_buttons[gr_screen.res][idx].button.disable();
378 Player_select_buttons[gr_screen.res][idx].button.enable();
383 // functions for selecting single/multiplayer pilots at the very beginning of Freespace
384 void player_select_init()
390 // start a looping ambient sound
391 main_hall_start_ambient();
393 Player_select_force_bastion = 0;
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);
402 Demo_title_active = 1;
403 Demo_title_expire_timestamp = timestamp(5000);
405 Demo_title_active = 0;
408 Demo_title_active = 0;
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]);
415 // initialize the control buttons
416 for (i=0; i<NUM_PLAYER_SELECT_BUTTONS; i++) {
417 b = &Player_select_buttons[gr_screen.res][i];
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);
423 b->button.create(&Player_select_window, NULL, b->x, b->y, 60, 30, 1, 1);
425 // set its highlight action
426 b->button.set_highlight_action(common_play_highlight_sound);
428 // set its animation bitmaps
429 b->button.set_bmaps(b->filename);
431 // link the mask hotspot
432 b->button.link_hotspot(b->hotspot);
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);
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]);
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();
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();
459 // not currently entering any text
460 Player_select_input_mode = 0;
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);
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();
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);
482 // load in the palette for the screen
483 // Player_select_palette = bm_load(PLAYER_SELECT_PALETTE);
484 // Player_select_palette_set = 0;
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);
491 // if(Player_select_num_pilots == 0){
492 // Player_select_autoaccept = 1;
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);
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);
505 player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
508 // otherwise go to the single player mode by default
510 player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
514 if((Player_select_num_pilots == 1) && Player_select_input_mode){
515 Player_select_autoaccept = 1;
520 // Display the demo title screen
521 void demo_title_blit()
527 if ( timestamp_elapsed(Demo_title_expire_timestamp) ) {
528 Demo_title_active = 0;
533 Demo_title_active = 0;
536 if ( Demo_title_need_fade_in ) {
540 gr_set_bitmap(Demo_title_bitmap);
545 if ( Demo_title_need_fade_in ) {
547 Demo_title_need_fade_in = 0;
550 if ( !Demo_title_active ) {
558 void player_select_do()
563 if ( Demo_title_active ) {
564 // demo_title_blit();
569 //if ( !Player_select_palette_set ) {
570 // Assert(Player_select_palette >= 0);
571 //#ifndef HARDWARE_ONLY
572 // palette_use_bm_palette(Player_select_palette);
574 // Player_select_palette_set = 1;
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();
582 // process any ui window stuff
583 k = Player_select_window.process();
585 extern void game_process_cheats(int k);
586 game_process_cheats(k);
589 // switch between single and multiplayer modes
591 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
595 if(Player_select_input_mode){
596 gamesnd_play_iface(SND_GENERAL_FAIL);
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));
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));
609 // reinitialize as multiplayer mode
610 player_select_init_player_stuff(PLAYER_SELECT_MODE_MULTI);
616 // draw the player select pseudo-dialog over it
617 gr_set_bitmap(Player_select_background_bitmap);
620 // press the accept button
621 if (Player_select_autoaccept) {
622 Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].button.press_button();
625 // draw any ui window stuf
626 Player_select_window.draw();
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);
632 Player_select_buttons[gr_screen.res][MULTI_BUTTON].button.draw_forced(2);
635 // draw the pilot list text
636 player_select_draw_list();
638 // draw copyright message on the bottom on the screen
639 player_select_display_copyright();
641 if (!Player_select_input_mode) {
642 player_select_process_noninput(k);
644 player_select_process_input(k);
647 // draw any pending messages on the bottom or middle of the screen
648 player_select_display_all_text();
651 // gr_set_color_fast(&Color_bright_green);
652 // gr_string(0x8000, 10, "Development version - DO NOT RELEASE");
656 gr_set_color(255, 0, 0);
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);
671 void player_select_close()
673 // destroy the player select window
674 Player_select_window.destroy();
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();
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"));
687 // unload all bitmaps
688 if(Player_select_background_bitmap >= 0){
689 bm_release(Player_select_background_bitmap);
690 Player_select_background_bitmap = -1;
692 // if(Player_select_palette >= 0){
693 // bm_release(Player_select_palette);
694 //Player_select_palette = -1;
697 // setup the player struct
699 Player = &Players[0];
700 Player->flags |= PLAYER_FLAGS_STRUCTURE_IN_USE;
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");
708 if (Player_select_force_bastion) {
709 Player->on_bastion = 1;
713 void player_select_set_input_mode(int n)
717 // set the input mode
718 Player_select_input_mode = n;
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);
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);
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();
733 Player_select_input_box.hide();
734 Player_select_input_box.disable();
738 void player_select_button_pressed(int n)
743 case SCROLL_LIST_UP_BUTTON:
744 player_select_set_bottom_text("");
746 player_select_scroll_list_up();
749 case SCROLL_LIST_DOWN_BUTTON:
750 player_select_set_bottom_text("");
752 player_select_scroll_list_down();
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));
760 player_select_commit();
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));
769 gamesnd_play_iface(SND_GENERAL_FAIL);
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;
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");
787 // set the clone flag
788 Player_select_clone_flag = 1;
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));
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));
805 // display some text on the bottom of the dialog
806 player_select_set_bottom_text(XSTR( "Type Callsign and Press Enter", 381));
808 // gray out all controls in the dialog
809 player_select_set_controls(1);
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));
818 gamesnd_play_iface(SND_GENERAL_FAIL);
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));
827 // don't clone anyone
828 Player_select_clone_flag = 0;
830 // display some text on the bottom of the dialog
831 player_select_set_bottom_text(XSTR( "Type Callsign and Press Enter", 381));
833 // gray out all controls
834 player_select_set_controls(1);
838 player_select_set_bottom_text("");
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));
846 player_select_delete_pilot();
852 player_select_set_bottom_text("");
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);
860 player_select_set_bottom_text(XSTR( "Single Player Mode", 376));
862 // reinitialize as single player mode
863 player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
865 gamesnd_play_iface(SND_GENERAL_FAIL);
870 player_select_set_bottom_text("");
872 Player_select_autoaccept = 0;
873 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
874 game_feature_not_in_demo_popup();
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);
881 player_select_set_bottom_text(XSTR( "Multiplayer Mode", 377));
883 // reinitialize as multiplayer mode
884 player_select_init_player_stuff(PLAYER_SELECT_MODE_MULTI);
886 gamesnd_play_iface(SND_GENERAL_FAIL);
893 int player_select_create_new_pilot()
897 // make sure we haven't reached the max
898 if (Player_select_num_pilots >= MAX_PILOTS) {
899 gamesnd_play_iface(SND_GENERAL_FAIL);
903 int play_scroll_sound = 1;
906 if ( Demo_title_active ) {
907 play_scroll_sound = 0;
911 if ( play_scroll_sound ) {
912 gamesnd_play_iface(SND_SCROLL);
915 idx = Player_select_num_pilots;
917 // move all the pilots in the list up
919 strcpy(Pilots[idx + 1], Pilots[idx]);
922 // by default, set the default netgame protocol to be VMT
923 Multi_options_g.protocol = NET_TCP;
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;
931 // set us to be in input mode
932 player_select_set_input_mode(1);
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());
942 void player_select_delete_pilot()
944 char filename[MAX_PATH_LEN + 1];
945 int i, deleted_cur_pilot;
947 deleted_cur_pilot = 0;
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") );
955 // attempt to delete the pilot
956 if (Player_select_mode == PLAYER_SELECT_MODE_SINGLE) {
957 cf_delete( filename, CF_TYPE_SINGLE_PLAYERS );
959 cf_delete( filename, CF_TYPE_MULTI_PLAYERS );
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) );
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]);
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;
978 // scroll the list of players up
979 void player_select_scroll_list_up()
981 if (Player_select_pilot == -1)
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);
989 gamesnd_play_iface(SND_GENERAL_FAIL);
992 if (Player_select_pilot < Player_select_list_start){
993 Player_select_list_start = Player_select_pilot;
997 // scroll the list of players down
998 void player_select_scroll_list_down()
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);
1005 gamesnd_play_iface(SND_GENERAL_FAIL);
1008 if (Player_select_pilot >= (Player_select_list_start + Player_select_max_lines[gr_screen.res])){
1009 Player_select_list_start++;
1013 // fill in the data on the last played pilot (callsign and is_multi or not)
1014 int player_select_get_last_pilot_info()
1018 last_player = os_config_read_string( NULL, "LastPlayer", NULL);
1020 if(last_player == NULL){
1023 strcpy(Player_select_last_pilot,last_player);
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';
1033 int player_select_get_last_pilot()
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){
1039 if(!player_select_get_last_pilot_info()){
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);
1046 Player_select_num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_SINGLE_PLAYERS, NOX("*.plr"), CF_SORT_TIME);
1049 Player_select_pilot = -1;
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;
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;
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;
1075 void player_select_init_player_stuff(int mode)
1077 Player_select_list_start = 0;
1079 // set the select mode to single player for default
1080 Player_select_mode = mode;
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);
1087 Player_select_num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_MULTI_PLAYERS, NOX("*.plr"), CF_SORT_TIME);
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;
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();
1104 Player_select_pilot = 0;
1108 void player_select_draw_list()
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)
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);
1122 // otherwise draw him normally
1124 gr_set_color_fast(&Color_text_normal);
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]);
1132 void player_select_process_noninput(int k)
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);
1143 // check for keypresses
1145 // quit the game entirely
1147 gameseq_post_event(GS_EVENT_QUIT_GAME);
1150 case KEY_ENTER | KEY_CTRLED:
1151 player_select_button_pressed(ACCEPT_BUTTON);
1154 // delete the currently highlighted pilot
1156 if (Player_select_pilot >= 0) {
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));
1164 player_select_delete_pilot();
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()) {
1174 // get the mouse position
1175 Player_select_list_region.get_mouse_pos(NULL, &click_y);
1177 // determine what index to select
1178 //idx = (click_y+5) / 10;
1179 idx = click_y / gr_get_font_height();
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;
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);
1196 void player_select_process_input(int k)
1198 char buf[CALLSIGN_LEN + 1];
1201 // if the player is in the process of typing in a new pilot name...
1203 // cancel create pilot
1205 player_select_cancel_create();
1208 // accept a new pilot name
1210 Player_select_input_box.get_text(buf);
1211 drop_white_space(buf);
1213 if (!isalpha(*buf)) {
1216 for (idx=1; buf[idx]; idx++) {
1217 if (!isalpha(buf[idx]) && !isdigit(buf[idx]) && !strchr(VALID_PILOT_CHARS, buf[idx])) {
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;
1242 if (!*buf || (idx < Player_select_num_pilots)) {
1247 gamesnd_play_iface(SND_GENERAL_FAIL);
1251 // Create the new pilot, and write out his file
1252 strcpy(Pilots[0], buf);
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;
1261 strcpy(Player->callsign, buf);
1262 init_new_pilot(Player, !Player_select_clone_flag);
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;
1270 // create his pilot file
1271 write_pilot_file(Player);
1274 memset(Player, 0, sizeof(player));
1277 // make this guy the selected pilot and put him first on the list
1278 Player_select_pilot = 0;
1280 // unset the input mode
1281 player_select_set_input_mode(0);
1283 // clear any pending bottom text
1284 player_select_set_bottom_text("");
1286 // clear any pending middle text
1287 player_select_set_middle_text("");
1289 // ungray all the controls
1290 player_select_set_controls(0);
1292 // evaluate whether or not this is the very first pilot
1293 player_select_eval_very_first_pilot();
1299 // always kill middle text when a char is pressed in input mode
1301 player_select_set_middle_text("");
1306 // draw copyright message on the bottom on the screen
1307 void player_select_display_copyright()
1310 char Copyright_msg1[256], Copyright_msg2[256];
1312 // strcpy(Copyright_msg1, XSTR("Descent: FreeSpace - The Great War, Copyright c 1998, Volition, Inc.", -1));
1313 gr_set_color_fast(&Color_white);
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');
1319 sprintf(Copyright_msg2, XSTR("Copyright %c 1999, Volition, Inc. All rights reserved.", 385), '\x83');
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);
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);
1333 void player_select_display_all_text()
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);
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);
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);
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);
1356 int player_select_pilot_file_filter(char *filename)
1358 return !verify_pilot_file(filename, Player_select_mode == PLAYER_SELECT_MODE_SINGLE);
1361 void player_select_set_bottom_text(char *txt)
1364 strncpy(Player_select_bottom_text, txt, 149);
1368 void player_select_set_middle_text(char *txt)
1371 strncpy(Player_select_middle_text, txt, 149);
1375 void player_select_eval_very_first_pilot()
1377 // never bring up the initial main hall help overlay
1378 // Player_select_very_first_pilot = 0;
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;
1387 // otherwise check to see if there is only 1 pilot
1389 if((Player_select_num_pilots == 1) && (Player_select_initial_count == 0)){
1391 Player_select_very_first_pilot = 1;
1392 strcpy(Player_select_very_first_pilot_callsign,Pilots[Player_select_pilot]);
1397 void player_select_commit()
1399 // if we've gotten to this point, we should have ensured this was the case
1400 Assert(Player_select_num_pilots > 0);
1402 gameseq_post_event(GS_EVENT_MAIN_MENU);
1403 gamesnd_play_iface(SND_COMMIT_PRESSED);
1405 // evaluate if this is the _very_ first pilot
1406 player_select_eval_very_first_pilot();
1409 void player_select_cancel_create()
1413 Player_select_num_pilots--;
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;
1420 // move all pilots down
1421 for (idx=0; idx<Player_select_num_pilots; idx++) {
1422 strcpy(Pilots[idx], Pilots[idx + 1]);
1425 // unset the input mode
1426 player_select_set_input_mode(0);
1428 // clear any bottom text
1429 player_select_set_bottom_text("");
1431 // clear any middle text
1432 player_select_set_middle_text("");
1434 // ungray all controls
1435 player_select_set_controls(0);
1437 // disable the autoaccept
1438 Player_select_autoaccept = 0;
1441 DCF(bastion,"Sets the player to be on the bastion")
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");
1449 #define MAX_PLAYER_TIPS 40
1451 char *Player_tips[MAX_PLAYER_TIPS];
1452 int Num_player_tips;
1453 int Player_tips_shown = 0;
1456 void player_tips_init()
1458 Num_player_tips = 0;
1460 // begin external localization stuff
1463 read_file_text("tips.tbl");
1466 while(!optional_string("#end")){
1467 required_string("+Tip:");
1469 if(Num_player_tips >= MAX_PLAYER_TIPS){
1472 Player_tips[Num_player_tips++] = stuff_and_malloc_string(F_NAME, NULL, 1024);
1475 // stop externalizing, homey
1478 void player_tips_popup()
1482 // player has disabled tips
1483 if((Player != NULL) && !Player->tips){
1486 // only show tips once per instance of Freespace
1487 if(Player_tips_shown == 1){
1490 Player_tips_shown = 1;
1492 // randomly pick one
1493 tip = (int)frand_range(0.0f, (float)Num_player_tips - 1.0f);
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);
1505 if(tip >= Num_player_tips - 1){
1512 // don't show me this again
1516 write_pilot_file(Player);