2 * $Logfile: /Freespace2/code/MenuUI/PlayerMenu.cpp $
7 * Code to drive the Player Select initial screen
10 * Revision 1.1 2002/05/03 03:28:09 root
14 * 43 11/02/99 11:42a Jefff
15 * fixed copyright symbol in german fonts
17 * 42 10/27/99 12:27a Jefff
18 * localized tips correctly
20 * 41 9/13/99 4:52p Dave
23 * 40 9/02/99 11:10a Jefff
24 * fixed 1024 list display bug - was only showing 8 pilots at a time
26 * 39 8/26/99 8:51p Dave
27 * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
29 * 38 8/26/99 9:45a Dave
30 * First pass at easter eggs and cheats.
32 * 37 8/16/99 6:39p Jefff
34 * 36 8/16/99 6:37p Jefff
35 * minor string alterations
37 * 35 8/05/99 4:17p Dave
38 * Tweaks to client interpolation.
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.
44 * 33 8/04/99 10:53a Dave
45 * Added title to the user tips popup.
47 * 32 8/03/99 3:21p Jefff
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"
53 * 30 8/02/99 9:13p Dave
56 * 29 7/30/99 10:29a Jefff
57 * fixed colors of bottom display texts
59 * 28 7/27/99 7:17p Jefff
60 * Replaced some art text with XSTR() text.
62 * 27 7/19/99 2:06p Jasons
63 * Remove all palette stuff from player select menu.
65 * 26 7/15/99 9:20a Andsager
66 * FS2_DEMO initial checkin
68 * 25 7/09/99 9:51a Dave
69 * Added thick polyline code.
71 * 24 6/11/99 11:13a Dave
72 * last minute changes before press tour build.
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.
78 * 22 4/25/99 3:02p Dave
79 * Build defines for the E3 build.
81 * 21 3/25/99 2:31p Neilk
82 * Coordinate changes to handle new artwork
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
89 * 19 2/01/99 5:55p Dave
90 * Removed the idea of explicit bitmaps for buttons. Fixed text
91 * highlighting for disabled gadgets.
93 * 18 1/30/99 5:08p Dave
94 * More new hi-res stuff.Support for nice D3D textures.
96 * 17 1/30/99 1:53a Dave
97 * Fix some harcoded coords.
99 * 16 1/30/99 1:28a Dave
100 * 1024x768 full support.
102 * 15 1/29/99 1:25p Dave
103 * New code for choose pilot screen.
105 * 14 1/29/99 12:47a Dave
106 * Put in sounds for beam weapon. A bunch of interface screens (tech
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
115 * 12 12/18/98 1:13a Dave
116 * Rough 1024x768 support for Direct3D. Proper detection and usage through
119 * 11 12/06/98 2:36p Dave
120 * Drastically improved nebula fogging.
122 * 10 12/01/98 6:20p Dave
123 * Removed tga test bitmap code.
125 * 9 12/01/98 4:46p Dave
126 * Put in targa bitmap support (16 bit).
128 * 8 11/30/98 1:07p Dave
129 * 16 bit conversion, first run.
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.
135 * 6 11/19/98 4:19p Dave
136 * Put IPX sockets back in psnet. Consolidated all multiplayer config
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
144 * 4 10/13/98 9:28a Dave
145 * Started neatening up freespace.h. Many variables renamed and
146 * reorganized. Added AlphaColors.[h,cpp]
148 * 3 10/09/98 2:57p Dave
149 * Starting splitting up OS stuff.
151 * 2 10/07/98 10:53a Dave
154 * 1 10/07/98 10:49a Dave
163 #include "playermenu.h"
170 #include "managepilot.h"
171 #include "missionscreencommon.h"
173 #include "freespace.h"
175 #include "gamesequence.h"
178 #include "osregistry.h"
180 #include "mainhallmenu.h"
184 #include "alphacolors.h"
185 #include "localize.h"
187 // --------------------------------------------------------------------------------------------------------
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");
197 // --------------------------------------------------------------------------------------------------------
198 // PLAYER SELECT defines
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
207 // button control defines
208 #define NUM_PLAYER_SELECT_BUTTONS 8 // button control defines
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 //
219 // list text display area
220 int Choose_list_coords[GR_NUM_RESOLUTIONS][4] = {
229 char *Player_select_background_bitmap_name[GR_NUM_RESOLUTIONS] = {
233 char *Player_select_background_mask_bitmap[GR_NUM_RESOLUTIONS] = {
237 // #define PLAYER_SELECT_PALETTE NOX("ChoosePilotPalette") // palette for the screen
239 #define PLAYER_SELECT_MAIN_HALL_OVERLAY NOX("MainHall1") // main hall help overlay
241 // convenient struct for handling all button controls
242 struct barracks_buttons {
246 UI_BUTTON button; // because we have a class inside this struct, we need the constructor below..
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) {}
251 static barracks_buttons Player_select_buttons[GR_NUM_RESOLUTIONS][NUM_PLAYER_SELECT_BUTTONS] = {
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),
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),
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)
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),
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),
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)
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] = {
288 { "Choose Pilot", 1436, 122, 90, UI_XSTR_COLOR_GREEN, -1, NULL }
291 { "Choose Pilot", 1436, 195, 143, UI_XSTR_COLOR_GREEN, -1, NULL }
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
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;
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];
311 extern int Main_hall_bitmap; // bitmap handle to the main hall bitmap
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;
324 int Player_select_force_bastion = 0;
326 // notification text areas
328 static int Player_select_bottom_text_y[GR_NUM_RESOLUTIONS] = {
333 static int Player_select_middle_text_y[GR_NUM_RESOLUTIONS] = {
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);
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();
366 // basically, gray out all controls (gray == 1), or ungray the controls (gray == 0)
367 void player_select_set_controls(int gray)
371 for(idx=0;idx<NUM_PLAYER_SELECT_BUTTONS;idx++){
373 Player_select_buttons[gr_screen.res][idx].button.disable();
375 Player_select_buttons[gr_screen.res][idx].button.enable();
380 // functions for selecting single/multiplayer pilots at the very beginning of Freespace
381 void player_select_init()
387 // start a looping ambient sound
388 main_hall_start_ambient();
390 Player_select_force_bastion = 0;
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);
399 Demo_title_active = 1;
400 Demo_title_expire_timestamp = timestamp(5000);
402 Demo_title_active = 0;
405 Demo_title_active = 0;
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]);
412 // initialize the control buttons
413 for (i=0; i<NUM_PLAYER_SELECT_BUTTONS; i++) {
414 b = &Player_select_buttons[gr_screen.res][i];
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);
420 b->button.create(&Player_select_window, NULL, b->x, b->y, 60, 30, 1, 1);
422 // set its highlight action
423 b->button.set_highlight_action(common_play_highlight_sound);
425 // set its animation bitmaps
426 b->button.set_bmaps(b->filename);
428 // link the mask hotspot
429 b->button.link_hotspot(b->hotspot);
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);
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]);
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();
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();
456 // not currently entering any text
457 Player_select_input_mode = 0;
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);
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();
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);
479 // load in the palette for the screen
480 // Player_select_palette = bm_load(PLAYER_SELECT_PALETTE);
481 // Player_select_palette_set = 0;
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);
488 // if(Player_select_num_pilots == 0){
489 // Player_select_autoaccept = 1;
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);
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);
502 player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
505 // otherwise go to the single player mode by default
507 player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
511 if((Player_select_num_pilots == 1) && Player_select_input_mode){
512 Player_select_autoaccept = 1;
517 // Display the demo title screen
518 void demo_title_blit()
524 if ( timestamp_elapsed(Demo_title_expire_timestamp) ) {
525 Demo_title_active = 0;
530 Demo_title_active = 0;
533 if ( Demo_title_need_fade_in ) {
537 gr_set_bitmap(Demo_title_bitmap);
542 if ( Demo_title_need_fade_in ) {
544 Demo_title_need_fade_in = 0;
547 if ( !Demo_title_active ) {
555 void player_select_do()
560 if ( Demo_title_active ) {
561 // demo_title_blit();
566 //if ( !Player_select_palette_set ) {
567 // Assert(Player_select_palette >= 0);
568 //#ifndef HARDWARE_ONLY
569 // palette_use_bm_palette(Player_select_palette);
571 // Player_select_palette_set = 1;
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();
579 // process any ui window stuff
580 k = Player_select_window.process();
582 extern void game_process_cheats(int k);
583 game_process_cheats(k);
586 // switch between single and multiplayer modes
588 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
592 if(Player_select_input_mode){
593 gamesnd_play_iface(SND_GENERAL_FAIL);
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));
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));
606 // reinitialize as multiplayer mode
607 player_select_init_player_stuff(PLAYER_SELECT_MODE_MULTI);
613 // draw the player select pseudo-dialog over it
614 gr_set_bitmap(Player_select_background_bitmap);
617 // press the accept button
618 if (Player_select_autoaccept) {
619 Player_select_buttons[gr_screen.res][ACCEPT_BUTTON].button.press_button();
622 // draw any ui window stuf
623 Player_select_window.draw();
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);
629 Player_select_buttons[gr_screen.res][MULTI_BUTTON].button.draw_forced(2);
632 // draw the pilot list text
633 player_select_draw_list();
635 // draw copyright message on the bottom on the screen
636 player_select_display_copyright();
638 if (!Player_select_input_mode) {
639 player_select_process_noninput(k);
641 player_select_process_input(k);
644 // draw any pending messages on the bottom or middle of the screen
645 player_select_display_all_text();
648 // gr_set_color_fast(&Color_bright_green);
649 // gr_string(0x8000, 10, "Development version - DO NOT RELEASE");
653 gr_set_color(255, 0, 0);
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);
668 void player_select_close()
670 // destroy the player select window
671 Player_select_window.destroy();
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();
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"));
684 // unload all bitmaps
685 if(Player_select_background_bitmap >= 0){
686 bm_release(Player_select_background_bitmap);
687 Player_select_background_bitmap = -1;
689 // if(Player_select_palette >= 0){
690 // bm_release(Player_select_palette);
691 //Player_select_palette = -1;
694 // setup the player struct
696 Player = &Players[0];
697 Player->flags |= PLAYER_FLAGS_STRUCTURE_IN_USE;
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");
705 if (Player_select_force_bastion) {
706 Player->on_bastion = 1;
710 void player_select_set_input_mode(int n)
714 // set the input mode
715 Player_select_input_mode = n;
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);
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);
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();
730 Player_select_input_box.hide();
731 Player_select_input_box.disable();
735 void player_select_button_pressed(int n)
740 case SCROLL_LIST_UP_BUTTON:
741 player_select_set_bottom_text("");
743 player_select_scroll_list_up();
746 case SCROLL_LIST_DOWN_BUTTON:
747 player_select_set_bottom_text("");
749 player_select_scroll_list_down();
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));
757 player_select_commit();
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));
766 gamesnd_play_iface(SND_GENERAL_FAIL);
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;
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");
784 // set the clone flag
785 Player_select_clone_flag = 1;
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));
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));
802 // display some text on the bottom of the dialog
803 player_select_set_bottom_text(XSTR( "Type Callsign and Press Enter", 381));
805 // gray out all controls in the dialog
806 player_select_set_controls(1);
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));
815 gamesnd_play_iface(SND_GENERAL_FAIL);
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));
824 // don't clone anyone
825 Player_select_clone_flag = 0;
827 // display some text on the bottom of the dialog
828 player_select_set_bottom_text(XSTR( "Type Callsign and Press Enter", 381));
830 // gray out all controls
831 player_select_set_controls(1);
835 player_select_set_bottom_text("");
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));
843 player_select_delete_pilot();
849 player_select_set_bottom_text("");
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);
857 player_select_set_bottom_text(XSTR( "Single Player Mode", 376));
859 // reinitialize as single player mode
860 player_select_init_player_stuff(PLAYER_SELECT_MODE_SINGLE);
862 gamesnd_play_iface(SND_GENERAL_FAIL);
867 player_select_set_bottom_text("");
869 Player_select_autoaccept = 0;
870 #if defined(DEMO) || defined(OEM_BUILD) // not for FS2_DEMO
871 game_feature_not_in_demo_popup();
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);
878 player_select_set_bottom_text(XSTR( "Multiplayer Mode", 377));
880 // reinitialize as multiplayer mode
881 player_select_init_player_stuff(PLAYER_SELECT_MODE_MULTI);
883 gamesnd_play_iface(SND_GENERAL_FAIL);
890 int player_select_create_new_pilot()
894 // make sure we haven't reached the max
895 if (Player_select_num_pilots >= MAX_PILOTS) {
896 gamesnd_play_iface(SND_GENERAL_FAIL);
900 int play_scroll_sound = 1;
903 if ( Demo_title_active ) {
904 play_scroll_sound = 0;
908 if ( play_scroll_sound ) {
909 gamesnd_play_iface(SND_SCROLL);
912 idx = Player_select_num_pilots;
914 // move all the pilots in the list up
916 strcpy(Pilots[idx + 1], Pilots[idx]);
919 // by default, set the default netgame protocol to be VMT
920 Multi_options_g.protocol = NET_TCP;
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;
928 // set us to be in input mode
929 player_select_set_input_mode(1);
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());
939 void player_select_delete_pilot()
941 char filename[MAX_PATH_LEN + 1];
942 int i, deleted_cur_pilot;
944 deleted_cur_pilot = 0;
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") );
952 // attempt to delete the pilot
953 if (Player_select_mode == PLAYER_SELECT_MODE_SINGLE) {
954 cf_delete( filename, CF_TYPE_SINGLE_PLAYERS );
956 cf_delete( filename, CF_TYPE_MULTI_PLAYERS );
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) );
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]);
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;
975 // scroll the list of players up
976 void player_select_scroll_list_up()
978 if (Player_select_pilot == -1)
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);
986 gamesnd_play_iface(SND_GENERAL_FAIL);
989 if (Player_select_pilot < Player_select_list_start){
990 Player_select_list_start = Player_select_pilot;
994 // scroll the list of players down
995 void player_select_scroll_list_down()
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);
1002 gamesnd_play_iface(SND_GENERAL_FAIL);
1005 if (Player_select_pilot >= (Player_select_list_start + Player_select_max_lines[gr_screen.res])){
1006 Player_select_list_start++;
1010 // fill in the data on the last played pilot (callsign and is_multi or not)
1011 int player_select_get_last_pilot_info()
1015 last_player = os_config_read_string( NULL, "LastPlayer", NULL);
1017 if(last_player == NULL){
1020 strcpy(Player_select_last_pilot,last_player);
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';
1030 int player_select_get_last_pilot()
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){
1036 if(!player_select_get_last_pilot_info()){
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);
1043 Player_select_num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_SINGLE_PLAYERS, NOX("*.plr"), CF_SORT_TIME);
1046 Player_select_pilot = -1;
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;
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;
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;
1072 void player_select_init_player_stuff(int mode)
1074 Player_select_list_start = 0;
1076 // set the select mode to single player for default
1077 Player_select_mode = mode;
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);
1084 Player_select_num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_MULTI_PLAYERS, NOX("*.plr"), CF_SORT_TIME);
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;
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();
1101 Player_select_pilot = 0;
1105 void player_select_draw_list()
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)
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);
1119 // otherwise draw him normally
1121 gr_set_color_fast(&Color_text_normal);
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]);
1129 void player_select_process_noninput(int k)
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);
1140 // check for keypresses
1142 // quit the game entirely
1144 gameseq_post_event(GS_EVENT_QUIT_GAME);
1147 case KEY_ENTER | KEY_CTRLED:
1148 player_select_button_pressed(ACCEPT_BUTTON);
1151 // delete the currently highlighted pilot
1153 if (Player_select_pilot >= 0) {
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));
1161 player_select_delete_pilot();
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()) {
1171 // get the mouse position
1172 Player_select_list_region.get_mouse_pos(NULL, &click_y);
1174 // determine what index to select
1175 //idx = (click_y+5) / 10;
1176 idx = click_y / gr_get_font_height();
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;
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);
1193 void player_select_process_input(int k)
1195 char buf[CALLSIGN_LEN + 1];
1198 // if the player is in the process of typing in a new pilot name...
1200 // cancel create pilot
1202 player_select_cancel_create();
1205 // accept a new pilot name
1207 Player_select_input_box.get_text(buf);
1208 drop_white_space(buf);
1210 if (!isalpha(*buf)) {
1213 for (idx=1; buf[idx]; idx++) {
1214 if (!isalpha(buf[idx]) && !isdigit(buf[idx]) && !strchr(VALID_PILOT_CHARS, buf[idx])) {
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;
1239 if (!*buf || (idx < Player_select_num_pilots)) {
1244 gamesnd_play_iface(SND_GENERAL_FAIL);
1248 // Create the new pilot, and write out his file
1249 strcpy(Pilots[0], buf);
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;
1258 strcpy(Player->callsign, buf);
1259 init_new_pilot(Player, !Player_select_clone_flag);
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;
1267 // create his pilot file
1268 write_pilot_file(Player);
1271 memset(Player, 0, sizeof(player));
1274 // make this guy the selected pilot and put him first on the list
1275 Player_select_pilot = 0;
1277 // unset the input mode
1278 player_select_set_input_mode(0);
1280 // clear any pending bottom text
1281 player_select_set_bottom_text("");
1283 // clear any pending middle text
1284 player_select_set_middle_text("");
1286 // ungray all the controls
1287 player_select_set_controls(0);
1289 // evaluate whether or not this is the very first pilot
1290 player_select_eval_very_first_pilot();
1296 // always kill middle text when a char is pressed in input mode
1298 player_select_set_middle_text("");
1303 // draw copyright message on the bottom on the screen
1304 void player_select_display_copyright()
1307 char Copyright_msg1[256], Copyright_msg2[256];
1309 // strcpy(Copyright_msg1, XSTR("Descent: FreeSpace - The Great War, Copyright c 1998, Volition, Inc.", -1));
1310 gr_set_color_fast(&Color_white);
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');
1316 sprintf(Copyright_msg2, XSTR("Copyright %c 1999, Volition, Inc. All rights reserved.", 385), '\x83');
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);
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);
1330 void player_select_display_all_text()
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);
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);
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);
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);
1353 int player_select_pilot_file_filter(char *filename)
1355 return !verify_pilot_file(filename, Player_select_mode == PLAYER_SELECT_MODE_SINGLE);
1358 void player_select_set_bottom_text(char *txt)
1361 strncpy(Player_select_bottom_text, txt, 149);
1365 void player_select_set_middle_text(char *txt)
1368 strncpy(Player_select_middle_text, txt, 149);
1372 void player_select_eval_very_first_pilot()
1374 // never bring up the initial main hall help overlay
1375 // Player_select_very_first_pilot = 0;
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;
1384 // otherwise check to see if there is only 1 pilot
1386 if((Player_select_num_pilots == 1) && (Player_select_initial_count == 0)){
1388 Player_select_very_first_pilot = 1;
1389 strcpy(Player_select_very_first_pilot_callsign,Pilots[Player_select_pilot]);
1394 void player_select_commit()
1396 // if we've gotten to this point, we should have ensured this was the case
1397 Assert(Player_select_num_pilots > 0);
1399 gameseq_post_event(GS_EVENT_MAIN_MENU);
1400 gamesnd_play_iface(SND_COMMIT_PRESSED);
1402 // evaluate if this is the _very_ first pilot
1403 player_select_eval_very_first_pilot();
1406 void player_select_cancel_create()
1410 Player_select_num_pilots--;
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;
1417 // move all pilots down
1418 for (idx=0; idx<Player_select_num_pilots; idx++) {
1419 strcpy(Pilots[idx], Pilots[idx + 1]);
1422 // unset the input mode
1423 player_select_set_input_mode(0);
1425 // clear any bottom text
1426 player_select_set_bottom_text("");
1428 // clear any middle text
1429 player_select_set_middle_text("");
1431 // ungray all controls
1432 player_select_set_controls(0);
1434 // disable the autoaccept
1435 Player_select_autoaccept = 0;
1438 DCF(bastion,"Sets the player to be on the bastion")
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");
1446 #define MAX_PLAYER_TIPS 40
1448 char *Player_tips[MAX_PLAYER_TIPS];
1449 int Num_player_tips;
1450 int Player_tips_shown = 0;
1453 void player_tips_init()
1455 Num_player_tips = 0;
1457 // begin external localization stuff
1460 read_file_text("tips.tbl");
1463 while(!optional_string("#end")){
1464 required_string("+Tip:");
1466 if(Num_player_tips >= MAX_PLAYER_TIPS){
1469 Player_tips[Num_player_tips++] = stuff_and_malloc_string(F_NAME, NULL, 1024);
1472 // stop externalizing, homey
1475 void player_tips_popup()
1479 // player has disabled tips
1480 if((Player != NULL) && !Player->tips){
1483 // only show tips once per instance of Freespace
1484 if(Player_tips_shown == 1){
1487 Player_tips_shown = 1;
1489 // randomly pick one
1490 tip = (int)frand_range(0.0f, (float)Num_player_tips - 1.0f);
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);
1502 if(tip >= Num_player_tips - 1){
1509 // don't show me this again
1513 write_pilot_file(Player);