From bd98fe6e02f33227135d24789ae3c27b5b733a74 Mon Sep 17 00:00:00 2001 From: Taylor Richards Date: Tue, 12 Dec 2017 19:45:15 -0500 Subject: [PATCH] make first pass at async popups --- include/managepilot.h | 2 +- include/popup.h | 26 +- include/readyroom.h | 2 +- src/freespace2/freespace.cpp | 5 + src/io/keycontrol.cpp | 46 +-- src/menuui/barracks.cpp | 82 ++--- src/menuui/mainhallmenu.cpp | 69 ++-- src/menuui/optionsmenu.cpp | 15 +- src/menuui/optionsmenumulti.cpp | 19 +- src/menuui/playermenu.cpp | 88 +++--- src/menuui/readyroom.cpp | 41 ++- src/mission/missiontraining.cpp | 23 +- src/missionui/missionbrief.cpp | 40 ++- src/missionui/missiondebrief.cpp | 128 +++++--- src/network/multi_endgame.cpp | 4 +- src/network/multi_fstracker.cpp | 2 +- src/network/multi_pxo.cpp | 57 ++-- src/network/multi_sw.cpp | 5 +- src/network/multi_update.cpp | 4 +- src/network/multiui.cpp | 91 +++--- src/network/multiutil.cpp | 9 +- src/playerman/managepilot.cpp | 50 +-- src/popup/popup.cpp | 520 ++++++++++++++++++------------- src/popup/popupdead.cpp | 42 +-- 24 files changed, 797 insertions(+), 573 deletions(-) diff --git a/include/managepilot.h b/include/managepilot.h index b7a2fbd..9f3700e 100644 --- a/include/managepilot.h +++ b/include/managepilot.h @@ -146,7 +146,7 @@ int is_pilot_multi(player *p); // pass a pointer to a player struct int verify_pilot_file(const char *filename, int single = 1, int *rank = NULL); int read_pilot_file(const char* callsign, int single = 1, player *p = NULL); -int write_pilot_file(player *p = NULL); +void write_pilot_file(player *p = NULL); // function to get default pilot callsign for game void choose_pilot(); diff --git a/include/popup.h b/include/popup.h index 0ced202..74afaca 100644 --- a/include/popup.h +++ b/include/popup.h @@ -147,20 +147,26 @@ #define PF_WEB_CURSOR_1 (1<<27) // button 1 will get web cursor #define PF_WEB_CURSOR_2 (1<<28) // button 2 will get web cursor -// input: flags => formatting specificatons (PF_... shown above) +// input: callback => function to call on user action (popup done, etc.) +// flags => formatting specificatons (PF_... shown above) // nchoices => number of choices popup has // text_1 => text for first button // ... => // text_n => text for last button // msg text => text msg for popup (can be of form "%s",pl->text) // -// exit: choice selected (0..nchoices-1) -// will return -1 if there was an error or popup was aborted -// // typical usage: +// popup(NULL, 0, 2, POPUP_YES, POPUP_NO, "Hey %s, do you want to quit", pl->callsign); // -// rval = popup(0, 2, POPUP_YES, POPUP_NO, "Hey %s, do you want to quit", pl->callsign); -int popup(int flags, int nchoices, ... ); +// this is an asynchronous call +void popup_callback(void(*callback)(int), int flags, int nchoices, ... ); + +// same, but without a callback +// use for info/warnings popups +void popup(int flags, int nchoices, ...); + +// synchronous popup +int popup_sync(int flags, int nchoices, ...); // popup with cancel button and conditional funcrion. // input: condition => function to call every frame, if condition() returns FALSE, the popup @@ -186,10 +192,13 @@ int popup(int flags, int nchoices, ... ); int popup_till_condition( int(*condition)() , ...); // popup to return the value from an input box -char *popup_input(int flags, const char *caption, int max_output_len = -1); +void popup_input(void (*callback)(int), int flags, const char *caption, int max_output_len = -1); +const char *popup_input_sync(int flags, const char *caption, int max_output_len = -1); int popup_active(); +const char *popup_get_input_text(); + int popup_running_state(); // kill any active popup, forcing it to return -1 (similar to ESC) @@ -198,5 +207,8 @@ void popup_kill_any_active(); // change the text inside of the popup void popup_change_text(const char *new_text); +void popup_do_frame(); +void popup_done(); + #endif diff --git a/include/readyroom.h b/include/readyroom.h index e32f46a..c005df7 100644 --- a/include/readyroom.h +++ b/include/readyroom.h @@ -49,7 +49,7 @@ void sim_room_close(); void sim_room_do_frame(float frametime); // called by main menu to continue on with current campaign (if there is one). -int readyroom_continue_campaign(); +void readyroom_continue_campaign(); void campaign_room_init(); void campaign_room_close(); diff --git a/src/freespace2/freespace.cpp b/src/freespace2/freespace.cpp index bded2b0..199bdf2 100644 --- a/src/freespace2/freespace.cpp +++ b/src/freespace2/freespace.cpp @@ -6690,6 +6690,11 @@ DCF(pofspew, "") static bool game_loop() { + if ( popup_active() ) { + popup_do_frame(); + return true; + } + os_poll(); if (gameseq_process_events() == GS_STATE_QUIT_GAME) { diff --git a/src/io/keycontrol.cpp b/src/io/keycontrol.cpp index 4a1ba91..a889e42 100644 --- a/src/io/keycontrol.cpp +++ b/src/io/keycontrol.cpp @@ -1537,27 +1537,13 @@ void process_player_ship_keys(int k) } } -// Handler for when player hits 'ESC' during the game -void game_do_end_mission_popup() +static void game_do_end_mission_popup_callback(int choice) { - int pf_flags, choice; // char savegame_filename[_MAX_FNAME]; - // do the multiplayer version of this - if(Game_mode & GM_MULTIPLAYER){ - multi_quit_game(PROMPT_ALL); - } else { + popup_done(); - // single player version.... - // do housekeeping things. - game_stop_time(); - game_stop_looped_sounds(); - snd_stop_all(); - - pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON; - choice = popup(pf_flags, 3, POPUP_NO, XSTR( "&Yes, Quit", 28), XSTR( "Yes, &Restart", 29), XSTR( "Do you really want to end the mission?", 30)); - - switch (choice) { + switch (choice) { case 1: // save the game before quitting if in campaign mode // MWA -- 3/26/98 -- no more save/restore!!!! @@ -1580,10 +1566,30 @@ void game_do_end_mission_popup() default: break; // do nothing - } + } + + game_start_time(); + game_flush(); +} + +// Handler for when player hits 'ESC' during the game +void game_do_end_mission_popup() +{ + int pf_flags; - game_start_time(); - game_flush(); + // do the multiplayer version of this + if(Game_mode & GM_MULTIPLAYER){ + multi_quit_game(PROMPT_ALL); + } else { + + // single player version.... + // do housekeeping things. + game_stop_time(); + game_stop_looped_sounds(); + snd_stop_all(); + + pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON; + popup_callback(game_do_end_mission_popup_callback, pf_flags, 3, POPUP_NO, XSTR( "&Yes, Quit", 28), XSTR( "Yes, &Restart", 29), XSTR( "Do you really want to end the mission?", 30)); } } diff --git a/src/menuui/barracks.cpp b/src/menuui/barracks.cpp index c670e58..f612455 100644 --- a/src/menuui/barracks.cpp +++ b/src/menuui/barracks.cpp @@ -905,18 +905,14 @@ void barracks_next_squad_pic() gamesnd_play_iface(SND_SCROLL); } -void barracks_delete_pilot() +static void barracks_delete_pilot_callback(int choice) { char buf[MAX_FILENAME_LEN]; int active = 0; - if (!Num_pilots) { - gamesnd_play_iface(SND_GENERAL_FAIL); - return; - } + popup_done(); - int popup_rval = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_NO, POPUP_YES, XSTR( "Warning!\n\nAre you sure you wish to delete this pilot?", 65)); - if (popup_rval != 1) { + if (choice != 1) { return; } @@ -947,6 +943,16 @@ void barracks_delete_pilot() gamesnd_play_iface(SND_USER_SELECT); } +void barracks_delete_pilot() +{ + if (!Num_pilots) { + gamesnd_play_iface(SND_GENERAL_FAIL); + return; + } + + popup_callback(barracks_delete_pilot_callback, PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_NO, POPUP_YES, XSTR( "Warning!\n\nAre you sure you wish to delete this pilot?", 65)); +} + // Filter out pilots of wrong type (which shouldn't be in the directory we are checking, but just to be safe..) int barracks_pilot_filter(const char *filename) { @@ -967,7 +973,7 @@ int barracks_pilot_filter(const char *filename) void barracks_squad_change_popup() { // show a popup - popup( PF_USE_AFFIRMATIVE_ICON | PF_NO_NETWORKING, 1, POPUP_OK, XSTR("You cannot change your squadron in Single Player mode.", 1445)); + popup(PF_USE_AFFIRMATIVE_ICON | PF_NO_NETWORKING, 1, POPUP_OK, XSTR("You cannot change your squadron in Single Player mode.", 1445)); } @@ -1031,6 +1037,38 @@ void barracks_init_player_stuff(int mode) } +static void barracks_convert_pilot_callback(int choice) +{ + char old_pic[256] = ""; + char old_squad_pic[256] = ""; + char old_squad[256] = ""; + + popup_done(); + + if (choice != 1) { + return; + } + + SDL_strlcpy(old_pic, Cur_pilot->image_filename, SDL_arraysize(old_pic)); + SDL_strlcpy(old_squad_pic, Cur_pilot->squad_filename, SDL_arraysize(old_squad_pic)); + SDL_strlcpy(old_squad, Cur_pilot->squad_name, SDL_arraysize(old_squad)); + init_new_pilot(Cur_pilot, 0); + SDL_strlcpy(Cur_pilot->image_filename, old_pic, SDL_arraysize(Cur_pilot->image_filename)); + SDL_strlcpy(Cur_pilot->squad_filename, old_squad_pic, SDL_arraysize(Cur_pilot->squad_filename)); + SDL_strlcpy(Cur_pilot->squad_name, old_squad, SDL_arraysize(Cur_pilot->squad_name)); + if (Player_sel_mode == PLAYER_SELECT_MODE_SINGLE) { + Cur_pilot->flags |= PLAYER_FLAGS_IS_MULTI; + write_pilot_file(); + barracks_init_player_stuff(PLAYER_SELECT_MODE_MULTI); + + } else { + write_pilot_file(); + barracks_init_player_stuff(PLAYER_SELECT_MODE_SINGLE); + } + + gamesnd_play_iface(SND_USER_SELECT); +} + void barracks_button_pressed(int n) { switch (n) { @@ -1115,10 +1153,6 @@ void barracks_button_pressed(int n) #else const char *str; char temp[256]; - char old_pic[256] = ""; - char old_squad_pic[256] = ""; - char old_squad[256] = ""; - int z; if (!barracks_new_pilot_selected()) { if (Player_sel_mode == PLAYER_SELECT_MODE_SINGLE) @@ -1128,30 +1162,8 @@ void barracks_button_pressed(int n) SDL_snprintf(temp, SDL_arraysize(temp), XSTR( "This will overwrite your %s pilot. Proceed?", 70), str); if (!verify_pilot_file(Cur_pilot->callsign, Player_sel_mode == PLAYER_SELECT_MODE_MULTI)) { - z = popup(0, 2, POPUP_CANCEL, POPUP_OK, temp); - if (z != 1) - break; + popup_callback(barracks_convert_pilot_callback, 0, 2, POPUP_CANCEL, POPUP_OK, temp); } - - SDL_strlcpy(old_pic, Cur_pilot->image_filename, SDL_arraysize(old_pic)); - SDL_strlcpy(old_squad_pic, Cur_pilot->squad_filename, SDL_arraysize(old_squad_pic)); - SDL_strlcpy(old_squad, Cur_pilot->squad_name, SDL_arraysize(old_squad)); - init_new_pilot(Cur_pilot, 0); - SDL_strlcpy(Cur_pilot->image_filename, old_pic, SDL_arraysize(Cur_pilot->image_filename)); - SDL_strlcpy(Cur_pilot->squad_filename, old_squad_pic, SDL_arraysize(Cur_pilot->squad_filename)); - SDL_strlcpy(Cur_pilot->squad_name, old_squad, SDL_arraysize(Cur_pilot->squad_name)); - if (Player_sel_mode == PLAYER_SELECT_MODE_SINGLE) { - Cur_pilot->flags |= PLAYER_FLAGS_IS_MULTI; - write_pilot_file(); - barracks_init_player_stuff(PLAYER_SELECT_MODE_MULTI); - - } else { - write_pilot_file(); - barracks_init_player_stuff(PLAYER_SELECT_MODE_SINGLE); - } - - gamesnd_play_iface(SND_USER_SELECT); - } else { gamesnd_play_iface(SND_GENERAL_FAIL); } diff --git a/src/menuui/mainhallmenu.cpp b/src/menuui/mainhallmenu.cpp index 87edfe0..90fae77 100644 --- a/src/menuui/mainhallmenu.cpp +++ b/src/menuui/mainhallmenu.cpp @@ -709,7 +709,7 @@ int main_hall_multi_stats_check() if (Player->save_flags & PLAYER_FLAGS_USING_LOCAL_STATS) { if (Multi_options_g.pxo == 1) { - int rc = popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_BIG | PF_TITLE_RED, 2, XSTR("&Back", 995), XSTR("&Continue",780), XSTR("Warning\n\nYou have been playing non-PXO games with this pilot. If you play PXO missions, your locally-stored statistics will be lost in favor of the PXO-only stats", -1)); + int rc = popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_BIG | PF_TITLE_RED, 2, XSTR("&Back", 995), XSTR("&Continue",780), XSTR("Warning\n\nYou have been playing non-PXO games with this pilot. If you play PXO missions, your locally-stored statistics will be lost in favor of the PXO-only stats", -1)); if (rc == 1) { Player->save_flags &= ~PLAYER_FLAGS_USING_LOCAL_STATS; @@ -720,7 +720,7 @@ int main_hall_multi_stats_check() } } else if (Player->save_flags & PLAYER_FLAGS_USING_PXO_STATS) { if (Multi_options_g.pxo == 0) { - int rc = popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_BIG | PF_TITLE_RED, 2, XSTR("&Back", 995), XSTR("&Continue",780), XSTR("Warning\n\nYou have been playing PXO games with this pilot. If you play non-PXO missions, the statistics the pilot accumulates will not be sent to the PXO servers. Only missions played on PXO will do this", -1)); + int rc = popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_BIG | PF_TITLE_RED, 2, XSTR("&Back", 995), XSTR("&Continue",780), XSTR("Warning\n\nYou have been playing PXO games with this pilot. If you play non-PXO missions, the statistics the pilot accumulates will not be sent to the PXO servers. Only missions played on PXO will do this", -1)); if (rc == 1) { Player->save_flags &= ~PLAYER_FLAGS_USING_PXO_STATS; @@ -829,18 +829,23 @@ void main_hall_blit_table_status() gr_line(Mh_weapon_table_status[gr_screen.res][0], Mh_weapon_table_status[gr_screen.res][1], Mh_weapon_table_status[gr_screen.res][0], Mh_ship_table_status[gr_screen.res][1]); } -// bash the player to a specific mission in a campaign -void main_hall_campaign_cheat() +static void campaign_cheat_callback(int choice) { - char *ret = popup_input(0, XSTR("Enter mission name.\n\n* This will destroy all legitimate progress in this campaign. *", -1)); + popup_done(); // yay - if(ret != NULL) { - // strcpy(Main_hall_campaign_cheat, ret); - mission_campaign_jump_to_mission(ret); + if (choice == 0) { + const char *name = popup_get_input_text(); + mission_campaign_jump_to_mission(name); } } +// bash the player to a specific mission in a campaign +void main_hall_campaign_cheat() +{ + popup_input(campaign_cheat_callback, 0, XSTR("Enter mission name.\n\n* This will destroy all legitimate progress in this campaign. *", -1)); +} + // ------------------------------------------------------------------------------------------------------------------- // FUNCTION DEFINITIONS BEGIN // @@ -1031,26 +1036,47 @@ void main_hall_init(int main_hall_num) } } -void main_hall_exit_game() -{ #if defined(NDEBUG) || defined(INTERPLAYQA) - int choice; +static void main_hall_exit_game_callback(int choice) +{ + popup_done(); - // stop music first - main_hall_stop_music(); - main_hall_stop_ambient(); - choice = popup( PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Exit Game?", 365)); - if ( choice == 1 ) { + if (choice == 1) { gameseq_post_event(GS_EVENT_QUIT_GAME); } else { main_hall_start_music(); main_hall_start_ambient(); } +} +#endif + +void main_hall_exit_game() +{ +#if defined(NDEBUG) || defined(INTERPLAYQA) + // stop music first + main_hall_stop_music(); + main_hall_stop_ambient(); + + popup_callback(main_hall_exit_game_callback, PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Exit Game?", 365)); #else gameseq_post_event(GS_EVENT_QUIT_GAME); #endif } +#if defined(FS2_DEMO) || defined(FS1_DEMO) +static void main_hall_reset_campaign_callback(int choice) +{ + popup_done(); + + if (choice != 1) { + return; + } + + mission_campaign_savefile_delete(Campaign.filename); + mission_campaign_load(Campaign.filename); + mission_campaign_next_mission(); +} +#endif // do a frame for the main hall void main_hall_do(float frametime) @@ -1164,16 +1190,9 @@ void main_hall_do(float frametime) #if defined(FS2_DEMO) || defined(FS1_DEMO) gamesnd_play_iface(SND_IFACE_MOUSE_CLICK); - { - //game_feature_not_in_demo_popup(); - int reset_campaign = popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 2, "Exit", "Restart Campaign", "Campaign Room only available in full version. However, you may restart the campaign."); - if (reset_campaign == 1) { - mission_campaign_savefile_delete(Campaign.filename); - mission_campaign_load(Campaign.filename); - mission_campaign_next_mission(); - } - } + //game_feature_not_in_demo_popup(); + popup_callback(main_hall_reset_campaign_callback, PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 2, "Exit", "Restart Campaign", "Campaign Room only available in full version. However, you may restart the campaign."); #else if(Player->flags & PLAYER_FLAGS_IS_MULTI){ gamesnd_play_iface(SND_IFACE_MOUSE_CLICK); diff --git a/src/menuui/optionsmenu.cpp b/src/menuui/optionsmenu.cpp index ad348f2..0b22ef6 100644 --- a/src/menuui/optionsmenu.cpp +++ b/src/menuui/optionsmenu.cpp @@ -1046,10 +1046,17 @@ void options_change_gamma(float delta) gr_set_gamma(Freespace_gamma); } -void options_button_pressed(int n) +static void options_abort_game_callback(int choice) { - int choice; + popup_done(); + + if (choice == 1) { + gameseq_post_event(GS_EVENT_QUIT_GAME); + } +} +void options_button_pressed(int n) +{ switch (n) { case OPTIONS_TAB: case MULTIPLAYER_TAB: @@ -1061,9 +1068,7 @@ void options_button_pressed(int n) case ABORT_GAME_BUTTON: gamesnd_play_iface(SND_USER_SELECT); - choice = popup( PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Exit Game?", 374)); - if ( choice == 1 ) - gameseq_post_event(GS_EVENT_QUIT_GAME); + popup_callback(options_abort_game_callback, PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Exit Game?", 374)); break; case CONTROL_CONFIG_BUTTON: diff --git a/src/menuui/optionsmenumulti.cpp b/src/menuui/optionsmenumulti.cpp index 0cdbb99..7841f5e 100644 --- a/src/menuui/optionsmenumulti.cpp +++ b/src/menuui/optionsmenumulti.cpp @@ -1295,13 +1295,20 @@ void options_multi_protocol_check_buttons() } } -// if a button was pressed -void options_multi_protocol_button_pressed(int n) -{ #ifdef MAKE_FS1 - int choice; +static void abort_game_callback(int choice) +{ + popup_done(); + + if (choice == 1) { + gameseq_post_event(GS_EVENT_QUIT_GAME); + } +} #endif +// if a button was pressed +void options_multi_protocol_button_pressed(int n) +{ switch(n){ // add an ip address case OM_PRO_ADD_IP: @@ -1480,9 +1487,7 @@ void options_multi_protocol_button_pressed(int n) #ifdef MAKE_FS1 case ABORT_GAME_BUTTON: gamesnd_play_iface(SND_USER_SELECT); - choice = popup( PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR("Exit Game?", 374)); - if ( choice == 1 ) - gameseq_post_event(GS_EVENT_QUIT_GAME); + popup_callback(abort_game_callback, PF_NO_NETWORKING | PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR("Exit Game?", 374)); break; #endif } diff --git a/src/menuui/playermenu.cpp b/src/menuui/playermenu.cpp index b61e555..217b83f 100644 --- a/src/menuui/playermenu.cpp +++ b/src/menuui/playermenu.cpp @@ -793,10 +793,20 @@ void player_select_set_input_mode(int n) } } -void player_select_button_pressed(int n) +static void delete_pilot_callback(int choice) { - int ret; + popup_done(); + + if (choice != 1) { + return; + } + + // delete the pilot + player_select_delete_pilot(); +} +void player_select_button_pressed(int n) +{ switch (n) { case SCROLL_LIST_UP_BUTTON: player_select_set_bottom_text(""); @@ -897,12 +907,7 @@ void player_select_button_pressed(int n) if (Player_select_pilot >= 0) { // display a popup requesting confirmation - 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)); - - // delete the pilot - if(ret == 1){ - player_select_delete_pilot(); - } + popup_callback(delete_pilot_callback, PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_NO, POPUP_YES, XSTR( "Warning!\n\nAre you sure you wish to delete this pilot?", 382)); } break; @@ -1214,15 +1219,8 @@ void player_select_process_noninput(int k) // delete the currently highlighted pilot case SDLK_DELETE: if (Player_select_pilot >= 0) { - int ret; - // display a popup requesting confirmation - 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)); - - // delete the pilot - if(ret == 1){ - player_select_delete_pilot(); - } + popup_callback(delete_pilot_callback, PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON,2,POPUP_NO,POPUP_YES,XSTR( "Are you sure you want to delete this pilot?", 383)); } break; } @@ -1574,11 +1572,36 @@ void player_tips_close() #endif } +#ifndef MAKE_FS1 +static int Tip_index = 0; + +static void player_tips_popup_callback(int choice) +{ + if (choice == 1) { + ++Tip_index; + + if (Tip_index >= Num_player_tips) { + Tip_index = 0; + } + + char all_txt[2048]; + SDL_snprintf(all_txt, SDL_arraysize(all_txt), XSTR("NEW USER TIP\n\n%s", 1565), Player_tips[Tip_index]); + + popup_change_text(all_txt); + } else { + popup_done(); + + if (choice == 2) { + Player->tips = 0; + write_pilot_file(Player); + } + } +} +#endif + void player_tips_popup() { -#ifndef MAKE_FS1 - int tip, ret; - +#ifndef MAKE_FS1 // player has disabled tips if((Player != NULL) && !Player->tips){ return; @@ -1590,32 +1613,11 @@ void player_tips_popup() Player_tips_shown = 1; // randomly pick one - tip = (int)frand_range(0.0f, (float)Num_player_tips - 1.0f); + Tip_index = (int)frand_range(0.0f, (float)Num_player_tips - 1.0f); char all_txt[2048]; - do { - SDL_snprintf(all_txt, SDL_arraysize(all_txt), XSTR("NEW USER TIP\n\n%s", 1565), Player_tips[tip]); - 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); - - // now what? - switch(ret){ - // next - case 1: - if(tip >= Num_player_tips - 1){ - tip = 0; - } else { - tip++; - } - break; - - // don't show me this again - case 2: - ret = 0; - Player->tips = 0; - write_pilot_file(Player); - break; - } - } while(ret > 0); + SDL_snprintf(all_txt, SDL_arraysize(all_txt), XSTR("NEW USER TIP\n\n%s", 1565), Player_tips[Tip_index]); + popup_callback(player_tips_popup_callback, 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); #endif } diff --git a/src/menuui/readyroom.cpp b/src/menuui/readyroom.cpp index 19592fb..37af1ce 100644 --- a/src/menuui/readyroom.cpp +++ b/src/menuui/readyroom.cpp @@ -878,6 +878,7 @@ void sim_room_scroll_line_down() gamesnd_play_iface(SND_GENERAL_FAIL); } +/* // returns: 0 = success, !0 = aborted or failed int ready_room_reset_campaign() { @@ -893,6 +894,7 @@ int ready_room_reset_campaign() return rval; } +*/ // Decide if we should offer choice to resume this savegame int sim_room_can_resume_savegame(char *savegame_filename) @@ -978,37 +980,45 @@ int sim_room_maybe_resume_savegame() */ } -int readyroom_continue_campaign() +#if defined(FS2_DEMO) || defined(FS1_DEMO) +static void continue_campaign_callback(int choice) { - if (mission_campaign_next_mission()) { // is campaign and next mission valid? + popup_done(); + + if (choice == 1) { + mission_campaign_savefile_delete(Campaign.filename); + mission_campaign_load(Campaign.filename); + mission_campaign_next_mission(); + + // set the bit for campaign mode + Game_mode |= GM_CAMPAIGN_MODE; + gameseq_post_event( GS_EVENT_START_GAME ); + } +} +#endif +void readyroom_continue_campaign() +{ + if (mission_campaign_next_mission()) { // is campaign and next mission valid? #if defined(FS2_DEMO) || defined(FS1_DEMO) - int reset_campaign = 0; - reset_campaign = popup(PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Demo Campaign Is Over. Would you like to play the campaign again?", 111) ); - if ( reset_campaign == 1 ) { - mission_campaign_savefile_delete(Campaign.filename); - mission_campaign_load(Campaign.filename); - mission_campaign_next_mission(); - } else { - return -1; - } + popup_callback(continue_campaign_callback, PF_BODY_BIG, 2, POPUP_NO, POPUP_YES, XSTR( "Demo Campaign Is Over. Would you like to play the campaign again?", 111) ); #else gamesnd_play_iface(SND_GENERAL_FAIL); + #ifdef MAKE_FS1 // make it the bottom button so that the graphic looks right popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR( "The campaign is over. To replay the campaign, either create a new pilot or restart the campaign in the campaign room.", 112) ); #else popup(0, 1, POPUP_OK, XSTR( "The campaign is over. To replay the campaign, either create a new pilot or restart the campaign in the campaign room.", 112) ); #endif - return -1; #endif + + return; } // set the bit for campaign mode Game_mode |= GM_CAMPAIGN_MODE; gameseq_post_event( GS_EVENT_START_GAME ); - - return 0; } void sim_room_commit() @@ -1673,8 +1683,7 @@ int campaign_room_reset_campaign(int n) char *filename; int z; - // z = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_CANCEL, POPUP_OK, XSTR( "Warning\nThis will cause all progress in your\ncurrent campaign to be lost", 110), Campaign_names[n]); - z = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_CANCEL, POPUP_OK, XSTR( "Warning\nThis will cause all progress in your\ncurrent campaign to be lost", 110)); + z = popup_sync(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_CANCEL, POPUP_OK, XSTR( "Warning\nThis will cause all progress in your\ncurrent campaign to be lost", 110)); if (z == 1) { int len = strlen(Campaign_file_names[n]) + 5; filename = (char *) malloc(len); diff --git a/src/mission/missiontraining.cpp b/src/mission/missiontraining.cpp index 5a37dd4..d0078e4 100644 --- a/src/mission/missiontraining.cpp +++ b/src/mission/missiontraining.cpp @@ -798,11 +798,23 @@ char *translate_msg_token(char *str, const int max_len) return NULL; } +static void translate_tokens_callback(int choice) +{ + popup_done(); + + if (choice) { + // abort the mission + gameseq_post_event(GS_EVENT_END_GAME); + } else { + // goto control config screen to bind the control + gameseq_post_event(GS_EVENT_CONTROL_CONFIG); + } +} + // translates all special tokens in a message, producing the new finalized message to be displayed void message_translate_tokens(char *buf, const int max_buflen, char *text) { char temp[40], *toke1, *toke2, *ptr; - int r; int len; *buf = 0; @@ -825,16 +837,9 @@ void message_translate_tokens(char *buf, const int max_buflen, char *text) if (ptr) { // was key translated properly? if (!SDL_strcasecmp(ptr, NOX("none")) && (Training_bind_warning != Missiontime)) { if ( The_mission.game_type & MISSION_TYPE_TRAINING ) { - r = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, XSTR( "&Bind Control", 424), XSTR( "&Abort mission", 425), + popup_callback(translate_tokens_callback, PF_TITLE_BIG | PF_TITLE_RED, 2, XSTR( "&Bind Control", 424), XSTR( "&Abort mission", 425), XSTR( "Warning\nYou have no control bound to the action \"%s\". You must do so before you can continue with your training.", 426), XSTR(Control_config[Failed_key_index].text, CONTROL_CONFIG_XSTR + Failed_key_index)); - - if (r) { // do they want to abort the mission? - gameseq_post_event(GS_EVENT_END_GAME); - return; - } - - gameseq_post_event(GS_EVENT_CONTROL_CONFIG); // goto control config screen to bind the control } } diff --git a/src/missionui/missionbrief.cpp b/src/missionui/missionbrief.cpp index 8d49e89..7b762e2 100644 --- a/src/missionui/missionbrief.cpp +++ b/src/missionui/missionbrief.cpp @@ -664,19 +664,12 @@ const char *brief_tooltip_handler(const char *str) return NULL; } -// brief_skip_training_pressed() -// -// called when the skip training button on the briefing screen is hit. When this happens, -// do a popup, then move to the next mission in the campaign. -void brief_skip_training_pressed() +static void skip_training_callback(int choice) { - int val; - - val = popup(PF_USE_NEGATIVE_ICON | PF_USE_AFFIRMATIVE_ICON,2,POPUP_NO,POPUP_YES,XSTR( "Skip Training\n\n\n\nAre you sure you want to skip this training mission?", 429)); + popup_done(); - // val is 0 when we hit no (first on the list) - // AL: also, -1 is returned when ESC is hit - if ( val <= 0 ){ + if (choice <= 0) { + // do nothing, user hit 'No' or aborted the popup window return; } @@ -693,11 +686,20 @@ void brief_skip_training_pressed() mission_campaign_store_goals_and_events(); mission_campaign_eval_next_mission(); - mission_campaign_mission_over(); + mission_campaign_mission_over(); gameseq_post_event( GS_EVENT_START_GAME ); } +// brief_skip_training_pressed() +// +// called when the skip training button on the briefing screen is hit. When this happens, +// do a popup, then move to the next mission in the campaign. +void brief_skip_training_pressed() +{ + popup_callback(skip_training_callback, PF_USE_NEGATIVE_ICON | PF_USE_AFFIRMATIVE_ICON,2,POPUP_NO,POPUP_YES,XSTR( "Skip Training\n\n\n\nAre you sure you want to skip this training mission?", 429)); +} + #if defined(FS2_DEMO) || defined(FS1_DEMO) extern void demo_reset_trailer_timer(); #endif @@ -810,14 +812,12 @@ void brief_scroll_down_text() } } - -// handles the exit loop option -void brief_exit_loop_pressed() +static void exit_loop_callback(int choice) { - int val = popup(PF_USE_NEGATIVE_ICON | PF_USE_AFFIRMATIVE_ICON, 2, POPUP_NO, POPUP_YES, XSTR( "Exit Loop\n\n\n\nAre you sure you want to leave the mission loop?", 1489)); + popup_done(); // bail if esc hit or no clicked - if (val <= 0) { + if (choice <= 0) { return; } @@ -826,6 +826,12 @@ void brief_exit_loop_pressed() mission_campaign_exit_loop(); } +// handles the exit loop option +void brief_exit_loop_pressed() +{ + popup_callback(exit_loop_callback, PF_USE_NEGATIVE_ICON | PF_USE_AFFIRMATIVE_ICON, 2, POPUP_NO, POPUP_YES, XSTR( "Exit Loop\n\n\n\nAre you sure you want to leave the mission loop?", 1489)); +} + // ------------------------------------------------------------------------------------- // brief_select_button_do() do the button action for the specified pressed button diff --git a/src/missionui/missiondebrief.cpp b/src/missionui/missiondebrief.cpp index 6d044b2..7c4e142 100644 --- a/src/missionui/missiondebrief.cpp +++ b/src/missionui/missiondebrief.cpp @@ -1761,6 +1761,21 @@ void debrief_assemble_optional_mission_popup_text(char *buffer, const int buf_le SDL_strlcat(buffer, XSTR("\n\n\nDo you want to play the optional mission?", 1491), buf_len); } +static void debrief_accept_callback(int choice) +{ + popup_done(); + + if (choice == 0) { + // do nothing, will return to debrief + } else if (choice == 1) { + // return to main hall, tossing stats + gameseq_post_event(GS_EVENT_END_GAME); + } else if (choice == 2) { + // replay mission (cycle back to briefing) + gameseq_post_event(GS_EVENT_START_BRIEFING); + } +} + // what to do when the accept button is hit void debrief_accept(int ok_to_post_start_game_event) { @@ -1768,7 +1783,6 @@ void debrief_accept(int ok_to_post_start_game_event) if ( (/*Cheats_enabled ||*/ Turned_traitor || Must_replay_mission) && (Game_mode & GM_CAMPAIGN_MODE) ) { const char *str; - int z; if (Game_mode & GM_MULTIPLAYER) { return; @@ -1782,12 +1796,7 @@ void debrief_accept(int ok_to_post_start_game_event) str = XSTR( "You have failed this mission and cannot accept. What do you you wish to do instead?", 441); } - z = popup(0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str); - if (z == 2){ - gameseq_post_event(GS_EVENT_START_BRIEFING); // cycle back to briefing - } else if ( z == 1 ) { - gameseq_post_event(GS_EVENT_END_GAME); // return to main hall, tossing stats - } + popup_callback(debrief_accept_callback, 0, 3, XSTR( "Return to &Debriefing", 442), XSTR( "Go to &Flight Deck", 443), XSTR( "&Replay Mission", 444), str); return; } @@ -2089,16 +2098,25 @@ void debrief_stats_render() gr_reset_clip(); } +static void debrief_replay_callback(int choice) +{ + popup_done(); + + if (choice == 1) { + // replay mission + gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing + gamesnd_play_iface(SND_COMMIT_PRESSED); + } +} + // do action for when the replay button is pressed void debrief_replay_pressed() { if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) { - int choice; - choice = popup(0, 2, POPUP_CANCEL, XSTR( "&Replay", 451), XSTR( "If you choose to replay this mission, you will be required to complete it again before proceeding to future missions.\n\nIn addition, any statistics gathered during this mission will be discarded if you choose to replay.", 452)); + popup_callback(debrief_replay_callback, 0, 2, POPUP_CANCEL, XSTR( "&Replay", 451), XSTR( "If you choose to replay this mission, you will be required to complete it again before proceeding to future missions.\n\nIn addition, any statistics gathered during this mission will be discarded if you choose to replay.", 452)); - if (choice != 1){ - return; - } + // the callback will handle replay + return; } gameseq_post_event(GS_EVENT_START_BRIEFING); // take us to the briefing @@ -2658,6 +2676,30 @@ void debrief_close() Debrief_inited = 0; } +static void mission_replay_esc_callback(int choice) +{ + popup_done(); + + if (choice == 1) { + // accept and continue + debrief_accept(0); + gameseq_post_event(GS_EVENT_MAIN_MENU); + } else { + // return to main hall + gameseq_post_event(GS_EVENT_END_GAME); + } +} + +static void mission_must_replay_callback(int choice) +{ + popup_done(); + + if (choice > 0) { + // return to main hall + gameseq_post_event(GS_EVENT_END_GAME); + } +} + // handle keypresses in debriefing void debrief_do_keys(int new_k) { @@ -2671,9 +2713,6 @@ void debrief_do_keys(int new_k) break; case SDLK_ESCAPE: { - int pf_flags; - int choice; - // multiplayer accept popup is a little bit different if (Game_mode & GM_MULTIPLAYER) { multi_debrief_esc_hit(); @@ -2681,25 +2720,13 @@ void debrief_do_keys(int new_k) // display the normal debrief popup } else { if (!Turned_traitor && !Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) { - pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON; - choice = popup(pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456)); - if (choice == 1) { // accept and continue on - debrief_accept(0); - gameseq_post_event(GS_EVENT_MAIN_MENU); - } - - if (choice < 1) - break; + int pf_flags = PF_BODY_BIG; // | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON; + popup_callback(mission_replay_esc_callback, pf_flags, 3, POPUP_CANCEL, XSTR( "&Yes", 454), XSTR( "&No, retry later", 455), XSTR( "Accept this mission outcome?", 456)); } else if (Must_replay_mission && (Game_mode & GM_CAMPAIGN_MODE)) { // need to popup saying that mission was a failure and must be replayed - choice = popup(0, 2, POPUP_NO, POPUP_YES, XSTR( "Because this mission was a failure, you must replay this mission when you continue your campaign.\n\nReturn to the Flight Deck?", 457)); - if (choice <= 0) - break; + popup_callback(mission_must_replay_callback, 0, 2, POPUP_NO, POPUP_YES, XSTR( "Because this mission was a failure, you must replay this mission when you continue your campaign.\n\nReturn to the Flight Deck?", 457)); } - - // Return to Main Hall - gameseq_post_event(GS_EVENT_END_GAME); } } @@ -2782,6 +2809,23 @@ void debrief_add_award_text(char *str) } #endif // !MAKE_FS1: No text for FS1, it's all bitmaps +static void skip_mission_callback(int choice) +{ + popup_done(); + + if (choice == 0) { + // stay on this mission, so proceed to normal death popup + // in other words, do nothing. + } else if (choice == 1) { + // skip this mission + mission_campaign_skip_to_next(); + gameseq_post_event(GS_EVENT_START_GAME); + } else if (choice == 2) { + // don't show this popup again + Player->show_skip_popup = 0; + } +} + // called once per frame to drive all the input reading and rendering void debrief_do_frame(float frametime) { @@ -3053,25 +3097,11 @@ void debrief_do_frame(float frametime) // maybe show skip mission popup if ((!Debrief_skip_popup_already_shown) && (Player->show_skip_popup) && (Game_mode & GM_NORMAL) && (Game_mode & GM_CAMPAIGN_MODE) && (Player->failures_this_session >= PLAYER_MISSION_FAILURE_LIMIT) && !(Game_mode & GM_MULTIPLAYER)) { - int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473), - XSTR("Advance To The Next Mission", 1474), - XSTR("Don't Show Me This Again", 1475), - XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) ); - switch (popup_choice) { - case 0: - // stay on this mission, so proceed to normal debrief - // in other words, do nothing. - break; - case 1: - // skip this mission - mission_campaign_skip_to_next(); - gameseq_post_event(GS_EVENT_START_GAME); - break; - case 2: - // dont show this again - Player->show_skip_popup = 0; - break; - } + popup_callback(skip_mission_callback, 0, 3, + XSTR("Do Not Skip This Mission", 1473), + XSTR("Advance To The Next Mission", 1474), + XSTR("Don't Show Me This Again", 1475), + XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) ); Debrief_skip_popup_already_shown = 1; } diff --git a/src/network/multi_endgame.cpp b/src/network/multi_endgame.cpp index 35831d3..a9a1b3a 100644 --- a/src/network/multi_endgame.cpp +++ b/src/network/multi_endgame.cpp @@ -401,7 +401,7 @@ int multi_quit_game(int prompt, int notify_code, int err_code, int wsa_error) if ( Game_mode & GM_IN_MISSION ) p_flags |= PF_RUN_STATE; - ret_val = popup(p_flags,2,POPUP_CANCEL,POPUP_OK,XSTR("Warning - quitting will end the game for all players!",647)); + ret_val = popup_sync(p_flags,2,POPUP_CANCEL,POPUP_OK,XSTR("Warning - quitting will end the game for all players!",647)); // check for host cancel if((ret_val == 0) || (ret_val == -1)){ @@ -415,7 +415,7 @@ int multi_quit_game(int prompt, int notify_code, int err_code, int wsa_error) // see if we should be prompting the client for confirmation if((prompt==PROMPT_CLIENT || prompt==PROMPT_ALL) && !quit_already){ - ret_val = popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG,2,POPUP_NO,POPUP_YES,XSTR("Are you sure you want to quit?",648)); + ret_val = popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG,2,POPUP_NO,POPUP_YES,XSTR("Are you sure you want to quit?",648)); // check for host cancel if((ret_val == 0) || (ret_val == -1)){ diff --git a/src/network/multi_fstracker.cpp b/src/network/multi_fstracker.cpp index 3ccbc9f..234989e 100644 --- a/src/network/multi_fstracker.cpp +++ b/src/network/multi_fstracker.cpp @@ -487,7 +487,7 @@ int multi_fs_tracker_validate(int show_error) return 1; case MT_VALIDATE_TIMEOUT : - rval = popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG,2,XSTR("&Abort",673),XSTR("&Retry",674),XSTR("Validation timed out",675)); + rval = popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG,2,XSTR("&Abort",673),XSTR("&Retry",674),XSTR("Validation timed out",675)); // if the user clicked abort, then leave. otherwise try again if(rval == 0){ diff --git a/src/network/multi_pxo.cpp b/src/network/multi_pxo.cpp index ffcce1f..e820fe0 100644 --- a/src/network/multi_pxo.cpp +++ b/src/network/multi_pxo.cpp @@ -1800,6 +1800,32 @@ void multi_pxo_close() multi_pxo_ban_close(); } +static void login_failed_callback(int choice) +{ + popup_done(); + + if (choice == 0) { + nprintf(("Network","PXO CANCEL\n")); + + // flip his "pxo" bit temporarily and push him to the join game screen + Multi_options_g.pxo = 0; + gameseq_post_event(GS_EVENT_MULTI_JOIN_GAME); + } else if (choice == 1) { + nprintf(("Network","PXO CREATE\n")); + + // fire up the given URL + multi_pxo_url(Multi_options_g.pxo_create_url); + } else if (choice == 2) { + nprintf(("Network","PXO VERIFY\n")); + + // fire up the given URL + multi_pxo_url(Multi_options_g.pxo_verify_url); + } + + // go back to the main hall + gameseq_post_event(GS_EVENT_MAIN_MENU); +} + // run normally (no popups) void multi_pxo_do_normal() { @@ -1877,32 +1903,13 @@ void multi_pxo_do_normal() if(validate_code != 1){ // show an error popup if it failed (not cancelled by the user) if (validate_code == 0) { - switch (popup(PF_USE_AFFIRMATIVE_ICON | PF_WEB_CURSOR_1 | PF_WEB_CURSOR_2, 3, POPUP_CANCEL,XSTR("&Create Acct",936), XSTR("&Verify Acct",937), XSTR("PXO Login not accepted. You may visit the Parallax Online website to create or verify your login. Or you may click Cancel to play without using the Parallax Online service. (You may switch back to Parallax Online from the Options Menu under the Multi tab.)",938))) { - case 0: - nprintf(("Network","PXO CANCEL\n")); - - // flip his "pxo" bit temporarily and push him to the join game screen - Multi_options_g.pxo = 0; - // Net_game_tcp_mode = NET_TCP; - gameseq_post_event(GS_EVENT_MULTI_JOIN_GAME); - break; - - case 1: - nprintf(("Network","PXO CREATE\n")); - // fire up the given URL - multi_pxo_url(Multi_options_g.pxo_create_url); - break; - - case 2: - nprintf(("Network","PXO VERIFY\n")); - // fire up the given URL - multi_pxo_url(Multi_options_g.pxo_verify_url); - break; - } - } + popup_callback(login_failed_callback, PF_USE_AFFIRMATIVE_ICON | PF_WEB_CURSOR_1 | PF_WEB_CURSOR_2, 3, + POPUP_CANCEL, + XSTR("&Create Acct",936), + XSTR("&Verify Acct",937), + XSTR("PXO Login not accepted. You may visit the Parallax Online website to create or verify your login. Or you may click Cancel to play without using the Parallax Online service. (You may switch back to Parallax Online from the Options Menu under the Multi tab.)",938)); - // go back to the main hall - gameseq_post_event(GS_EVENT_MAIN_MENU); + } Multi_pxo_must_connect = 0; Multi_pxo_must_validate = 0; diff --git a/src/network/multi_sw.cpp b/src/network/multi_sw.cpp index c107925..6558e7d 100644 --- a/src/network/multi_sw.cpp +++ b/src/network/multi_sw.cpp @@ -118,17 +118,18 @@ void multi_sw_level_init() // determine if everything is ok to move forward for a squad war match int multi_sw_ok_to_commit() { - char *ret; + const char *ret; char match_code[MATCH_CODE_LEN] = ""; char bad_response[MAX_SQUAD_RESPONSE_LEN+1] = ""; + // make sure we have enough players per team if(!multi_sw_verify_squad_counts()){ return 0; } // prompt the host for the match code - ret = popup_input(0, XSTR("Please enter the match code", 1076), 32); + ret = popup_input_sync(0, XSTR("Please enter the match code", 1076), 32); if(ret == NULL){ return 0; } diff --git a/src/network/multi_update.cpp b/src/network/multi_update.cpp index b537fbd..7b6dfec 100644 --- a/src/network/multi_update.cpp +++ b/src/network/multi_update.cpp @@ -220,7 +220,7 @@ int multi_update_error_verifying() SDL_snprintf(out_str, SDL_arraysize(out_str), "(%s)\n\n%s", Multi_update_error_string, XSTR("There was an error verifying your version of Freespace, if you continue, you will not necessarily be up to date", 978)); - switch(popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Go back", 1524), XSTR("&Continue", 1525), out_str)){ + switch(popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Go back", 1524), XSTR("&Continue", 1525), out_str)){ // continue on in freespace like nothing happened case 1: case -1: @@ -277,7 +277,7 @@ int multi_update_gobaby() // earlier version - need to update case 0: - switch(popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, "&Update Later", "&Yes", XSTR("A new version of Freespace is available. You must update to the new version to play on PXO\n\nAuto update now?", 980))){ + switch(popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, "&Update Later", "&Yes", XSTR("A new version of Freespace is available. You must update to the new version to play on PXO\n\nAuto update now?", 980))){ // update later (go back to main hall for now case 0 : case -1: diff --git a/src/network/multiui.cpp b/src/network/multiui.cpp index ba2abf2..f2fbb15 100644 --- a/src/network/multiui.cpp +++ b/src/network/multiui.cpp @@ -2500,10 +2500,10 @@ int multi_join_warn_update_low(int code) { switch(code){ case CW_CODE_OK: - return popup(0,3,XSTR("&Cancel",779),XSTR("&Continue",780),XSTR("&More info",781),LOW_WARN_TEXT); + return popup_sync(0,3,XSTR("&Cancel",779),XSTR("&Continue",780),XSTR("&More info",781),LOW_WARN_TEXT); case CW_CODE_INFO: - return popup(0,3,XSTR("&Cancel",779),XSTR("&Continue",780),XSTR("&More info",781),LOW_INFO_TEXT); + return popup_sync(0,3,XSTR("&Cancel",779),XSTR("&Continue",780),XSTR("&More info",781),LOW_INFO_TEXT); } return CW_CODE_CANCEL; @@ -2513,10 +2513,10 @@ int multi_join_warn_update_medium(int code) { switch(code){ case CW_CODE_OK: - return popup(0,3,XSTR("&Cancel",779),XSTR("&Continue",780),XSTR("&More info",781),MED_WARN_TEXT); + return popup_sync(0,3,XSTR("&Cancel",779),XSTR("&Continue",780),XSTR("&More info",781),MED_WARN_TEXT); case CW_CODE_INFO: - return popup(0,3,XSTR("&Cancel",779),XSTR("&Continue",780),XSTR("&More info",781),MED_INFO_TEXT); + return popup_sync(0,3,XSTR("&Cancel",779),XSTR("&Continue",780),XSTR("&More info",781),MED_INFO_TEXT); } return CW_CODE_CANCEL; @@ -5670,7 +5670,7 @@ int multi_create_ok_to_commit() notify_of_hacked_ships_tbl = 0; } if(notify_of_hacked_ships_tbl){ - if(popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("You or the server you are playing on has a hacked ships.tbl. Your stats will not be updated on PXO", 1051)) <= 0){ + if(popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("You or the server you are playing on has a hacked ships.tbl. Your stats will not be updated on PXO", 1051)) <= 0){ return 0; } } @@ -5690,7 +5690,7 @@ int multi_create_ok_to_commit() notify_of_hacked_weapons_tbl = 0; } if(notify_of_hacked_weapons_tbl){ - if(popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("You or the server you are playing on has a hacked weapons.tbl. Your stats will not be updated on PXO", 1052)) <= 0){ + if(popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("You or the server you are playing on has a hacked weapons.tbl. Your stats will not be updated on PXO", 1052)) <= 0){ return 0; } } @@ -5729,7 +5729,7 @@ int multi_create_ok_to_commit() // otherwise, warn the players that stats will not saved else { // if this is squad war, don't allow it to continue - if(popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("One or more players has hacked data files. If you continue, stats will not be stored at the end of the mission", 1273)) <= 0){ + if(popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("One or more players has hacked data files. If you continue, stats will not be stored at the end of the mission", 1273)) <= 0){ return 0; } } @@ -5742,7 +5742,7 @@ int multi_create_ok_to_commit() } // non-pxo, just give a notice else { - if(popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("One or more players has hacked data files", 1274)) <= 0){ + if(popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("One or more players has hacked data files", 1274)) <= 0){ return 0; } } @@ -5797,7 +5797,7 @@ int multi_create_ok_to_commit() if(MULTI_IS_TRACKER_GAME){ #ifdef PXO_CHECK_VALID_MISSIONS if((Multi_create_file_list == Multi_create_mission_list) && (Multi_create_file_list[abs_index].valid_status != MVALID_STATUS_VALID)){ - if(popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("You have selected a mission which is either invalid or unknown to PXO. Your stats will not be saved if you continue",996)) <= 0){ + if(popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("You have selected a mission which is either invalid or unknown to PXO. Your stats will not be saved if you continue",996)) <= 0){ return 0; } } @@ -5807,7 +5807,7 @@ int multi_create_ok_to_commit() if(!(Netgame.type_flags & NG_TYPE_SW)){ // if he is playing by himself, tell him stats will not be accepted if(multi_num_players() == 1){ - if(popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_RED | PF_TITLE_BIG, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("Warning\n\nIf you start a PXO mission by yourself, your stats will not be updated", 997)) <= 0){ + if(popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_RED | PF_TITLE_BIG, 2, XSTR("&Back", 995), XSTR("&Continue", 780), XSTR("Warning\n\nIf you start a PXO mission by yourself, your stats will not be updated", 997)) <= 0){ return 0; } } @@ -9298,6 +9298,16 @@ void multi_debrief_close() } } +static void set_mission_loop_callback(int choice) +{ + popup_done(); + + if (choice == 1) { + Campaign.loop_enabled = 1; + Campaign.next_mission = Campaign.loop_mission; + } +} + // handle optional mission loop void multi_maybe_set_mission_loop() { @@ -9313,11 +9323,7 @@ void multi_maybe_set_mission_loop() char buffer[512]; debrief_assemble_optional_mission_popup_text(buffer, SDL_arraysize(buffer), Campaign.missions[cur].mission_loop_desc); - int choice = popup(0 , 2, POPUP_NO, POPUP_YES, buffer); - if (choice == 1) { - Campaign.loop_enabled = 1; - Campaign.next_mission = Campaign.loop_mission; - } + popup_callback(set_mission_loop_callback, 0 , 2, POPUP_NO, POPUP_YES, buffer); } } @@ -9370,7 +9376,7 @@ void multi_debrief_accept_hit() multi_maybe_set_mission_loop(); } else { - int res = popup(PF_TITLE | PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_IGNORE_ESC,3,XSTR("&Cancel",779),XSTR("&Accept",844),XSTR("&Toss",845),XSTR("(Continue Netgame)\nDo you wish to accept these stats?",846)); + int res = popup_sync(PF_TITLE | PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_IGNORE_ESC,3,XSTR("&Cancel",779),XSTR("&Accept",844),XSTR("&Toss",845),XSTR("(Continue Netgame)\nDo you wish to accept these stats?",846)); // evaluate the result switch(res){ @@ -9401,11 +9407,31 @@ void multi_debrief_accept_hit() } } +static void debrief_esc_hit_host_callback(int choice) +{ + popup_done(); + + if (choice == 1) { + multi_debrief_stats_accept(); + multi_quit_game(PROMPT_NONE); + } else if (choice == 2) { + multi_debrief_stats_toss(); + multi_quit_game(PROMPT_NONE); + } +} + +static void debrief_esc_hit_callback(int choice) +{ + popup_done(); + + if (choice == 1) { + multi_quit_game(PROMPT_NONE); + } +} + // handle all cases for when the escape key is hit in a multiplayer debriefing void multi_debrief_esc_hit() { - int res; - // if the server has left if(Multi_debrief_server_left){ multi_quit_game(PROMPT_ALL); @@ -9438,37 +9464,12 @@ void multi_debrief_esc_hit() multi_quit_game(PROMPT_HOST); } else { - res = popup(PF_TITLE | PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_IGNORE_ESC,3,XSTR("&Cancel",779),XSTR("&Accept",844),XSTR("&Toss",845),XSTR("(Exit Netgame)\nDo you wish to accept these stats?",847)); - - // evaluate the result - switch(res){ - // undo the accept - case -1: - case 0: - break; - - // set the accept code to be "not accepting" - case 2 : - multi_debrief_stats_toss(); - multi_quit_game(PROMPT_NONE); - break; - - // accept the stats and continue - case 1 : - multi_debrief_stats_accept(); - multi_quit_game(PROMPT_NONE); - break; - } + popup_callback(debrief_esc_hit_host_callback, PF_TITLE | PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_IGNORE_ESC,3,XSTR("&Cancel",779),XSTR("&Accept",844),XSTR("&Toss",845),XSTR("(Exit Netgame)\nDo you wish to accept these stats?",847)); } } else { // if the stats haven't been accepted yet, or this is a tracker game if((Multi_debrief_stats_accept_code == -1) && !(MULTI_IS_TRACKER_GAME)){ - res = popup(PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON,2,XSTR("&Cancel",779),XSTR("&Leave",848),XSTR("Are you sure you want to leave the netgame before stats are stored?",849)); - - // evaluate the result - if(res == 1){ - multi_quit_game(PROMPT_NONE); - } + popup_callback(debrief_esc_hit_callback, PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON,2,XSTR("&Cancel",779),XSTR("&Leave",848),XSTR("Are you sure you want to leave the netgame before stats are stored?",849)); } // otherwise go through the normal endgame channels else { diff --git a/src/network/multiutil.cpp b/src/network/multiutil.cpp index 272aa79..4df8938 100644 --- a/src/network/multiutil.cpp +++ b/src/network/multiutil.cpp @@ -2448,6 +2448,12 @@ void multi_handle_state_special() } } +static void xfer_notify_callback(int) +{ + popup_done(); + multi_quit_game(PROMPT_NONE); +} + // called by the file xfer subsytem when we start receiving a file void multi_file_xfer_notify(int handle) { @@ -2483,8 +2489,7 @@ void multi_file_xfer_notify(int handle) multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT); Net_player->flags &= ~(NETINFO_FLAG_DO_NETWORKING); - popup(PF_USE_AFFIRMATIVE_ICON, 1, XSTR("&Ok", 713), XSTR("An outdated copy of this file exists, but it cannot be overwritten by the server because it is set to be read-only. Change the permissions on this file next time.", 714)); - multi_quit_game(PROMPT_NONE); + popup_callback(xfer_notify_callback, PF_USE_AFFIRMATIVE_ICON, 1, XSTR("&Ok", 713), XSTR("An outdated copy of this file exists, but it cannot be overwritten by the server because it is set to be read-only. Change the permissions on this file next time.", 714)); return; } diff --git a/src/playerman/managepilot.cpp b/src/playerman/managepilot.cpp index 4b43ef0..d0aab8b 100644 --- a/src/playerman/managepilot.cpp +++ b/src/playerman/managepilot.cpp @@ -1350,35 +1350,35 @@ int write_pilot_file_core(player *p) return errno; } -int write_pilot_file(player *the_player) +static player *callback_player = NULL; +static void error_writing_callback(int choice) { - int pilot_write_rval; - do { - // write_pilot_file_core returns 0 if ok, non-zero for error - pilot_write_rval = write_pilot_file_core(the_player); - - // check with user if write not successful - if (pilot_write_rval) { - int popup_rval = popup(PF_TITLE_RED | PF_TITLE_BIG, 3, XSTR( "&Retry", 41), XSTR( "&Ignore", 42), XSTR( "&Quit Game", 43), - XSTR( "Warning\nFailed to save pilot file. You may be out of disk space. If so, you should press Alt-Tab, free up some disk space, then come back and choose retry.\n", 44) ); - - // quit game popup return value (2) - if (popup_rval == 2) { - exit(1); - } + popup_done(); - // _ignore_ popup return value (1) - don't save the file - if (popup_rval) { - return pilot_write_rval; - } + if (choice == 0) { + // retry + write_pilot_file(callback_player); + } else if (choice == 1) { + // ignore + } else { + // quit game + exit(1); + } +} - // retry popup return value (0) - try again - } +void write_pilot_file(player *the_player) +{ + // save for later, in case of a retry + callback_player = the_player; - } while (pilot_write_rval); + // write_pilot_file_core returns 0 if ok, non-zero for error + int rval = write_pilot_file_core(the_player); - // write successful - return 0; + // check with user if write not successful + if (rval) { + popup_callback(error_writing_callback, PF_TITLE_RED | PF_TITLE_BIG, 3, XSTR( "&Retry", 41), XSTR( "&Ignore", 42), XSTR( "&Quit Game", 43), + XSTR( "Warning\nFailed to save pilot file. You may be out of disk space. If so, you should press Alt-Tab, free up some disk space, then come back and choose retry.\n", 44) ); + } } void write_stats_block(CFILE *file,scoring_struct *stats) @@ -1681,7 +1681,7 @@ void pilot_format_callsign_personal(const char *in_callsign, char *out_callsign, // 1 == ok to overwrite, 0 == not ok int pilot_verify_overwrite() { - return popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_RED | PF_TITLE_BIG, 2, XSTR( "&No", 47), XSTR( "&Yes", 48), XSTR( "Warning\nA duplicate pilot exists\nOverwrite?", 49)); + return popup_sync(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_TITLE_RED | PF_TITLE_BIG, 2, XSTR( "&No", 47), XSTR( "&Yes", 48), XSTR( "Warning\nA duplicate pilot exists\nOverwrite?", 49)); } extern int Skip_packfile_search; // located in CFileList.cpp diff --git a/src/popup/popup.cpp b/src/popup/popup.cpp index 8edd4a9..ba08d7d 100644 --- a/src/popup/popup.cpp +++ b/src/popup/popup.cpp @@ -258,6 +258,11 @@ typedef struct popup_info char input_text[POPUP_INPUT_MAX_CHARS]; // input box text (if this is an inputbox popup) int max_input_text_len; int web_cursor_flag[POPUP_MAX_CHOICES]; // flag for using web cursor over button + void (*callback)(int); // callback to call on user choice (optional) + int flags; // popup flags (PF_*) + int choice; // choice user made + int screen_id; // background screen id + int (*condition)(); // test condition (optional) } popup_info; //////////////////////////////////////////////////////////////// @@ -311,7 +316,6 @@ static int Popup_is_active=0; static int Popup_should_die=0; // popup should quit during the next iteration of its loop static popup_info Popup_info; -static int Popup_flags; static int Title_coords[GR_NUM_RESOLUTIONS][5] = { @@ -513,7 +517,7 @@ void popup_play_default_change_sound(popup_info *pi) // exit: 0 .. nchoices-1 => choice selected through keypress // POPUP_ABORT => abort the popup // POPUP_NOCHANGE => nothing happenned -int popup_process_keys(popup_info *pi, int k, int flags) +int popup_process_keys(popup_info *pi, int k) { int i, masked_k; @@ -538,7 +542,7 @@ int popup_process_keys(popup_info *pi, int k, int flags) case SDLK_ESCAPE: // only process the escape key if this flag is not set - if(!(flags & PF_IGNORE_ESC)){ + if(!(pi->flags & PF_IGNORE_ESC)){ return POPUP_ABORT; } break; @@ -578,7 +582,7 @@ int popup_process_keys(popup_info *pi, int k, int flags) } // Split off the title and break up the body lines -void popup_split_lines(popup_info *pi, int flags) +void popup_split_lines(popup_info *pi) { int nlines, i, body_offset = 0; int n_chars[POPUP_MAX_LINES]; @@ -591,14 +595,14 @@ void popup_split_lines(popup_info *pi, int flags) nlines = split_str(pi->raw_text, 1000, n_chars, p_str, POPUP_MAX_LINES); SDL_assert(nlines >= 0 && nlines <= POPUP_MAX_LINES ); - if ( flags & (PF_TITLE | PF_TITLE_BIG) ) { + if ( pi->flags & (PF_TITLE | PF_TITLE_BIG) ) { // get first line out len = SDL_min(n_chars[0] + 1, POPUP_MAX_LINE_CHARS); SDL_strlcpy(pi->title, p_str[0], len); body_offset = 1; } - if ( flags & PF_BODY_BIG ) { + if ( pi->flags & PF_BODY_BIG ) { gr_set_font(FONT2); } @@ -617,17 +621,17 @@ void popup_split_lines(popup_info *pi, int flags) } // figure out what filename to use for the button icon -const char *popup_get_button_filename(popup_info *pi, int i, int flags) +const char *popup_get_button_filename(popup_info *pi, int i) { const char *fname = NULL; int is_tiny=0; // check for special button texts and if found, use specialized buttons for them. - if ((!SDL_strcasecmp(pi->button_text[i], POPUP_OK + 1) || !SDL_strcasecmp(pi->button_text[i], POPUP_YES + 1)) && !(flags & PF_NO_SPECIAL_BUTTONS)){ + if ((!SDL_strcasecmp(pi->button_text[i], POPUP_OK + 1) || !SDL_strcasecmp(pi->button_text[i], POPUP_YES + 1)) && !(pi->flags & PF_NO_SPECIAL_BUTTONS)){ return Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_POSITIVE]; } - if ((!SDL_strcasecmp(pi->button_text[i], POPUP_CANCEL + 1) || !SDL_strcasecmp(pi->button_text[i], POPUP_NO + 1)) && !(flags & PF_NO_SPECIAL_BUTTONS)){ + if ((!SDL_strcasecmp(pi->button_text[i], POPUP_CANCEL + 1) || !SDL_strcasecmp(pi->button_text[i], POPUP_NO + 1)) && !(pi->flags & PF_NO_SPECIAL_BUTTONS)){ return Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_NEGATIVE]; } @@ -636,9 +640,9 @@ const char *popup_get_button_filename(popup_info *pi, int i, int flags) fname = ""; break; case 1: - if ( (flags & PF_USE_AFFIRMATIVE_ICON) && !(flags & PF_NO_SPECIAL_BUTTONS) ) { + if ( (pi->flags & PF_USE_AFFIRMATIVE_ICON) && !(pi->flags & PF_NO_SPECIAL_BUTTONS) ) { fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_POSITIVE]; - } else if ( flags & PF_USE_NEGATIVE_ICON && !(flags & PF_NO_SPECIAL_BUTTONS) ) { + } else if ( pi->flags & PF_USE_NEGATIVE_ICON && !(pi->flags & PF_NO_SPECIAL_BUTTONS) ) { fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_NEGATIVE]; } else { fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_GENERIC_FIRST]; @@ -646,12 +650,12 @@ const char *popup_get_button_filename(popup_info *pi, int i, int flags) break; case 2: - if ( flags & PF_USE_NEGATIVE_ICON && i==0 ) { + if ( pi->flags & PF_USE_NEGATIVE_ICON && i==0 ) { fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_NEGATIVE]; break; } - if ( flags & PF_USE_AFFIRMATIVE_ICON && i==1 ) { + if ( pi->flags & PF_USE_AFFIRMATIVE_ICON && i==1 ) { fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_POSITIVE]; break; } @@ -688,13 +692,16 @@ void popup_slider_bogus() } // init the Popup window -int popup_init(popup_info *pi, int flags) +int popup_init(popup_info *pi) { int i; UI_BUTTON *b; popup_background *pbg; const char *fname; + pi->screen_id = -1; + pi->choice = POPUP_NOCHANGE; + if(pi->nchoices == 0){ pbg = &Popup_background[gr_screen.res][0]; } else { @@ -714,13 +721,13 @@ int popup_init(popup_info *pi, int flags) for (i=0; inchoices; i++) { b = &Popup_buttons[i]; // accommodate single-choice positive icon being positioned differently - if ( (pi->nchoices == 1) && (flags&PF_USE_AFFIRMATIVE_ICON) ) { + if ( (pi->nchoices == 1) && (pi->flags&PF_USE_AFFIRMATIVE_ICON) ) { b->create(&Popup_window, "", Button_coords[gr_screen.res][i+1][0], Button_coords[gr_screen.res][i+1][1], 30, 25, 0, 1); } else { b->create(&Popup_window, "", Button_coords[gr_screen.res][i][0], Button_coords[gr_screen.res][i][1], 30, 25, 0, 1); } - fname = popup_get_button_filename(pi, i, flags); + fname = popup_get_button_filename(pi, i); b->set_bmaps(fname, 3, 0); b->set_highlight_action(common_play_highlight_sound); if ( pi->keypress[i] >= 0 ) { @@ -735,7 +742,7 @@ int popup_init(popup_info *pi, int flags) b = &Popup_button_regions[i]; // accommodate single-choice positive icon being positioned differently - if ( (pi->nchoices == 1) && (flags&PF_USE_AFFIRMATIVE_ICON) ) { + if ( (pi->nchoices == 1) && (pi->flags&PF_USE_AFFIRMATIVE_ICON) ) { b->create(&Popup_window, "", lx, Button_regions[gr_screen.res][i+1][1], Button_regions[gr_screen.res][i+1][2]-lx, Button_regions[gr_screen.res][i+1][3]-Button_regions[gr_screen.res][i+1][1], 0, 1); } else { b->create(&Popup_window, "", lx, Button_regions[gr_screen.res][i][1], Button_regions[gr_screen.res][i][2]-lx, Button_regions[gr_screen.res][i][3]-Button_regions[gr_screen.res][i][1], 0, 1); @@ -746,16 +753,16 @@ int popup_init(popup_info *pi, int flags) // webcursor setup if (Web_cursor_bitmap >= 0) { - if (flags & PF_WEB_CURSOR_1) { + if (pi->flags & PF_WEB_CURSOR_1) { Popup_buttons[1].set_custom_cursor_bmap(Web_cursor_bitmap); } - if (flags & PF_WEB_CURSOR_2) { + if (pi->flags & PF_WEB_CURSOR_2) { Popup_buttons[2].set_custom_cursor_bmap(Web_cursor_bitmap); } } // if this is an input popup, create and center the popup - if(flags & PF_INPUT){ + if(pi->flags & PF_INPUT){ Popup_input.create(&Popup_window, Popup_text_coords[gr_screen.res][0], pbg->coords[1] + Popup_input_y_offset[gr_screen.res], Popup_text_coords[gr_screen.res][2], pi->max_input_text_len, "", UI_INPUTBOX_FLAG_INVIS | UI_INPUTBOX_FLAG_ESC_CLR | UI_INPUTBOX_FLAG_ESC_FOC | UI_INPUTBOX_FLAG_KEYTHRU | UI_INPUTBOX_FLAG_TEXT_CEN); Popup_input.set_focus(); } @@ -763,13 +770,13 @@ int popup_init(popup_info *pi, int flags) Popup_default_choice=0; Popup_should_die = 0; - if (flags & PF_RUN_STATE) { + if (pi->flags & PF_RUN_STATE) { Popup_running_state = 1; } else { Popup_running_state = 0; } - popup_split_lines(pi, flags); + popup_split_lines(pi); #ifndef MAKE_FS1 // create the popup slider (which we may not need to use @@ -781,7 +788,7 @@ int popup_init(popup_info *pi, int flags) } // called when a popup goes away -void popup_close(popup_info *pi,int screen) +void popup_close(popup_info *pi) { int i; @@ -794,9 +801,14 @@ void popup_close(popup_info *pi,int screen) } } - if(screen >= 0){ - gr_free_screen(screen); + if(pi->screen_id >= 0){ + gr_free_screen(pi->screen_id); + pi->screen_id = -1; } + + pi->callback = NULL; + pi->condition = NULL; + Popup_window.destroy(); anim_ignore_next_frametime(); // to avoid skips in animation since next frametime is saturated game_flush(); @@ -809,6 +821,17 @@ void popup_close(popup_info *pi,int screen) game_start_time(); } +void popup_done() +{ + if ( !Popup_is_active ) { + return; + } + + popup_info *pi = &Popup_info; + + popup_close(pi); +} + // set the popup text color void popup_set_text_color(int flags) { @@ -892,13 +915,13 @@ int popup_calc_starting_index(popup_info *pi) // Figure out the y-coord to start drawing the popup text. The text // is centered vertically within the popup. -int popup_calc_starting_y(popup_info *pi, int flags) +int popup_calc_starting_y(popup_info *pi) { int sy, total_h=0; int num_lines = pi->nlines > Popup_max_display[gr_screen.res] ? Popup_max_display[gr_screen.res] : pi->nlines; - if ( flags & (PF_TITLE | PF_TITLE_BIG) ) { - if ( flags & PF_TITLE_BIG ) { + if ( pi->flags & (PF_TITLE | PF_TITLE_BIG) ) { + if ( pi->flags & PF_TITLE_BIG ) { gr_set_font(FONT2); } else { gr_set_font(FONT1); @@ -906,7 +929,7 @@ int popup_calc_starting_y(popup_info *pi, int flags) total_h += gr_get_font_height(); } - if ( flags & PF_BODY_BIG ) { + if ( pi->flags & PF_BODY_BIG ) { gr_set_font(FONT2); } else { gr_set_font(FONT1); @@ -916,7 +939,7 @@ int popup_calc_starting_y(popup_info *pi, int flags) sy = fl2i((Popup_text_coords[gr_screen.res][1] + Popup_text_coords[gr_screen.res][3]/2.0f) - total_h/2.0f + 0.5f); // if this is an input style box, add in some y - if(flags & PF_INPUT){ + if(pi->flags & PF_INPUT){ sy += Popup_input_text_y_offset[gr_screen.res]; } @@ -924,7 +947,7 @@ int popup_calc_starting_y(popup_info *pi, int flags) } // Draw the message text nicely formatted in the popup -void popup_draw_msg_text(popup_info *pi, int flags) +void popup_draw_msg_text(popup_info *pi) { int sx, sy, i, w, h; int line_index; @@ -934,22 +957,22 @@ void popup_draw_msg_text(popup_info *pi, int flags) line_index = popup_calc_starting_index(pi); // figure out the starting y: - sy = popup_calc_starting_y(pi, flags); + sy = popup_calc_starting_y(pi); // draw title if required - if ( flags & (PF_TITLE | PF_TITLE_BIG) ) { - popup_draw_title(sy, pi->title, flags); + if ( pi->flags & (PF_TITLE | PF_TITLE_BIG) ) { + popup_draw_title(sy, pi->title, pi->flags); sy += gr_get_font_height(); } // draw body - if ( flags & PF_BODY_BIG ) { + if ( pi->flags & PF_BODY_BIG ) { gr_set_font(FONT2); } else { gr_set_font(FONT1); } - popup_set_text_color(flags); + popup_set_text_color(pi->flags); line_count = 0; for ( i = line_index; i < pi->nlines; i++, line_count++ ) { // if we've already displayed the max # of lines @@ -973,7 +996,7 @@ void popup_draw_msg_text(popup_info *pi, int flags) } // Draw the button text nicely formatted in the popup -void popup_draw_button_text(popup_info *pi, int flags) +void popup_draw_button_text(popup_info *pi) { int w, h, i, sx, sy; @@ -982,7 +1005,7 @@ void popup_draw_button_text(popup_info *pi, int flags) for ( i=0; i < pi->nchoices; i++ ) { gr_get_string_size(&w, &h, pi->button_text[i]); - if ( (pi->nchoices == 1) && (flags&PF_USE_AFFIRMATIVE_ICON) ) { + if ( (pi->nchoices == 1) && (pi->flags & PF_USE_AFFIRMATIVE_ICON) ) { sx = Button_regions[gr_screen.res][i+1][0]-w; sy = Button_regions[gr_screen.res][i+1][1]+4; } else { @@ -1042,131 +1065,113 @@ void popup_force_draw_buttons(popup_info *pi) } } -// exit: -1 => error -// 0..nchoices-1 => choice -int popup_do(popup_info *pi, int flags) +static void popup_do(popup_info *pi) { - int screen_id, choice = -1, done = 0; + int test; - screen_id = gr_save_screen(); + os_poll(); - if ( popup_init(pi, flags) == -1 ){ - return -1; - } + // if we were killed by a call to popup_kill_any_active(), kill the popup + if (Popup_should_die) { + pi->choice = -1; -#ifdef __EMSCRIPTEN__ - STUB_FUNCTION; - return POPUP_ABORT; -#endif + if (pi->callback) { + (*(pi->callback))(-1); + } else { + popup_close(pi); + } - while(!done) { - int k; + return; + } - os_poll(); + // if we're flagged as should be running the state underneath, then do so + if (pi->flags & PF_RUN_STATE) { + game_do_state(gameseq_get_state()); + } + // otherwise just run the common functions (for networking,etc) + else { + game_set_frametime(-1); + game_do_state_common(gameseq_get_state(), pi->flags & PF_NO_NETWORKING); // do stuff common to all states + } - // if we were killed by a call to popup_kill_any_active(), kill the popup - if(Popup_should_die){ - choice = -1; - break; - } + // test the condition function or process for the window + if (pi->condition && (test = (*(pi->condition))() > 0)) { + pi->choice = test; - // if we're flagged as should be running the state underneath, then do so - if(flags & PF_RUN_STATE){ - game_do_state(gameseq_get_state()); - } - // otherwise just run the common functions (for networking,etc) - else { - game_set_frametime(-1); - game_do_state_common(gameseq_get_state(),flags & PF_NO_NETWORKING); // do stuff common to all states + if (pi->callback) { + (*(pi->callback))(pi->choice); + } else { + popup_close(pi); } - k = Popup_window.process(); // poll for input, handle mouse - choice = popup_process_keys(pi, k, flags); - if ( choice != POPUP_NOCHANGE ) { - done=1; - } + return; + } else { + int k = Popup_window.process(); // poll for input, handle mouse - if ( !done ) { - choice = popup_check_buttons(pi); - if ( choice != POPUP_NOCHANGE ) { - done=1; + pi->choice = popup_process_keys(pi, k); + + if (pi->choice != POPUP_NOCHANGE) { + if (pi->callback) { + (*(pi->callback))(pi->choice); + } else { + popup_close(pi); } - } - // don't draw anything - if(!(flags & PF_RUN_STATE)){ - gr_restore_screen(screen_id); + return; } - // if this is an input popup, store the input text - if(flags & PF_INPUT){ - Popup_input.get_text(pi->input_text); + pi->choice = popup_check_buttons(pi); + + if (pi->choice != POPUP_NOCHANGE) { + if (pi->callback) { + (*(pi->callback))(pi->choice); + } else { + popup_close(pi); + } + + return; } + } + + // don't draw anything + if ( !(pi->flags & PF_RUN_STATE) ) { + gr_restore_screen(pi->screen_id); + } - Popup_window.draw(); - popup_force_draw_buttons(pi); - popup_draw_msg_text(pi, flags); - popup_draw_button_text(pi, flags); - gr_flip(); + // if this is an input popup, store the input text + if (pi->flags & PF_INPUT) { + Popup_input.get_text(pi->input_text); } - popup_close(pi,screen_id); - return choice; + Popup_window.draw(); + popup_force_draw_buttons(pi); + popup_draw_msg_text(pi); + popup_draw_button_text(pi); + + gr_flip(); } -int popup_do_with_condition(popup_info *pi, int flags, int(*condition)()) +void popup_do_frame() { - int screen_id, choice = -1, done = 0; - int test; - screen_id = gr_save_screen(); - if ( popup_init(pi, flags) == -1 ) - return -1; + if ( !Popup_is_active ) { + return; + } -#ifdef __EMSCRIPTEN__ - STUB_FUNCTION; - return POPUP_ABORT; -#endif + popup_info *pi = &Popup_info; - while(!done) { - int k; + popup_do(pi); +} - os_poll(); - - game_set_frametime(-1); - game_do_state_common(gameseq_get_state()); // do stuff common to all states - gr_restore_screen(screen_id); - - // draw one frame first - Popup_window.draw(); - popup_force_draw_buttons(pi); - popup_draw_msg_text(pi, flags); - popup_draw_button_text(pi, flags); - gr_flip(); - - // test the condition function or process for the window - if ((test = condition()) > 0) { - done = 1; - choice = test; - } else { - k = Popup_window.process(); // poll for input, handle mouse - choice = popup_process_keys(pi, k, flags); - if ( choice != POPUP_NOCHANGE ) { - done=1; - } +static int popup_do_sync() +{ + popup_info *pi = &Popup_info; - if ( !done ) { - choice = popup_check_buttons(pi); - if ( choice != POPUP_NOCHANGE ) { - done=1; - } - } - } - } + SDL_assert(Popup_is_active); - popup_close(pi,screen_id); - return choice; -} + popup_do(pi); + return pi->choice; +} // maybe assign a keyboard shortcut to this button // input: pi => popup information so far @@ -1204,62 +1209,120 @@ void popup_maybe_assign_keypress(popup_info *pi, int n, char *str) } } -// input: flags => flags => formatting specificatons (PF_...) +static void popup_internal(void (*callback)(int), int (*condition)(), int flags, int nchoices, va_list args) +{ + int i; + char *format, *s; + popup_info *pi = &Popup_info; + + pi->flags = flags; + pi->callback = callback; + pi->condition = condition; + + SDL_assert( nchoices > 0 && nchoices <= POPUP_MAX_CHOICES ); + pi->nchoices = nchoices; + + // get button text + for (i=0; ibutton_text[i] = NULL; + popup_maybe_assign_keypress(pi, i, s); + } + + // get msg text + format = va_arg( args, char * ); + pi->raw_text[0] = 0; + SDL_vsnprintf(pi->raw_text, SDL_arraysize(pi->raw_text), format, args); + + if ( popup_init(pi) == -1 ) { + if (callback) { + (*callback)(-1); + } + + pi->choice = POPUP_ABORT; + popup_close(pi); + return; + } + + pi->screen_id = gr_save_screen(); + + gamesnd_play_iface(SND_POPUP_APPEAR); // play sound when popup appears + + Mouse_hidden = 0; + Popup_is_active = 1; +} + +// input: callback => function to call on user action (popup done, etc.) +// flags => formatting specificatons (PF_... shown above) // nchoices => number of choices popup has // text_1 => text for first button -// ... => +// ... => // text_n => text for last button // msg text => text msg for popup (can be of form "%s",pl->text) // -// exit: choice selected (0..nchoices-1) -// will return -1 if there was an error or popup was aborted -// // typical usage: -// -// rval = popup(0, 2, POPUP_OK, POPUP_CANCEL, "Sorry %s, try again", pl->callsign); -int popup(int flags, int nchoices, ... ) +// popup(NULL, 0, 2, POPUP_YES, POPUP_NO, "Hey %s, do you want to quit", pl->callsign); +void popup_callback(void (*callback)(int), int flags, int nchoices, ... ) { - int i, choice; - char *format, *s; - va_list args; + va_list args; if ( Popup_is_active ) { Int3(); // should never happen - return -1; + return; } - Popup_flags = flags; + va_start(args, nchoices); - SDL_assert( nchoices > 0 && nchoices <= POPUP_MAX_CHOICES ); - Popup_info.nchoices = nchoices; + popup_internal(callback, NULL, flags, nchoices, args); - va_start(args, nchoices ); + va_end(args); +} - // get button text - for (i=0; ichoice; // if init failed, this will be ABORT + + while (rval == POPUP_NOCHANGE) { + rval = popup_do_sync(); + } - choice = popup_do( &Popup_info, flags ); - switch(choice) { - case POPUP_ABORT: + popup_done(); + + if (rval == POPUP_ABORT) { return -1; - default: - return choice; - } // end switch + } + + return rval; } // determine if a popup is being drawn @@ -1274,90 +1337,119 @@ int popup_active() // the condition() did if the condition() occurred, and FALSE if the cancel button was pressed. int popup_till_condition(int (*condition)(), ...) { - int choice; - char *format, *s; - va_list args; - int flags = 0; + popup_info *pi = &Popup_info; + va_list args; if ( Popup_is_active ) { Int3(); // should never happen return -1; } - //int nchoices = 1; - Popup_info.nchoices = 1; - - Popup_flags = 0; - va_start(args, condition ); + va_start(args, condition); - // get button text - s = va_arg( args, char * ); - Popup_info.button_text[0] = NULL; - popup_maybe_assign_keypress(&Popup_info, 0, s); + popup_internal(NULL, condition, 0, 1, args); - // get msg text - format = va_arg( args, char * ); - Popup_info.raw_text[0] = 0; - SDL_vsnprintf(Popup_info.raw_text, SDL_arraysize(Popup_info.raw_text), format, args); va_end(args); - - gamesnd_play_iface(SND_POPUP_APPEAR); // play sound when popup appears - Mouse_hidden = 0; - Popup_is_active = 1; + int rval = pi->choice; // if init failed, this will be ABORT + + while (rval == POPUP_NOCHANGE) { + rval = popup_do_sync(); + } - choice = popup_do_with_condition( &Popup_info, flags, condition ); - switch(choice) { - case POPUP_ABORT: + popup_done(); + + if (rval == POPUP_ABORT) { return 0; - default: - return choice; - } // end switch + } + + return rval; } // popup to return the value from an input box -char *popup_input(int flags, const char *caption, int max_output_len) +void popup_input(void (*callback)(int), int flags, const char *caption, int max_output_len) { + popup_info *pi = &Popup_info; + if ( Popup_is_active ) { Int3(); // should never happen - return NULL; + return; } // make it an inputbox type popup - Popup_flags = flags; - Popup_flags |= PF_INPUT; + pi->flags = flags | PF_INPUT; + + pi->callback = NULL; + pi->condition = NULL; // add a cancel button - Popup_info.nchoices = 0; + pi->nchoices = 0; // popup_maybe_assign_keypress(&Popup_info, 0, "&Cancel"); // get msg text SDL_assert(caption != NULL); - SDL_strlcpy(Popup_info.raw_text, caption, SDL_arraysize(Popup_info.raw_text)); - SDL_assert(strlen(Popup_info.raw_text) < POPUP_MAX_CHARS ); + SDL_strlcpy(pi->raw_text, caption, SDL_arraysize(pi->raw_text)); + SDL_assert(strlen(pi->raw_text) < POPUP_MAX_CHARS ); // set input text length if((max_output_len > POPUP_INPUT_MAX_CHARS) || (max_output_len == -1)){ - Popup_info.max_input_text_len = POPUP_INPUT_MAX_CHARS - 1; + pi->max_input_text_len = POPUP_INPUT_MAX_CHARS - 1; } else { - Popup_info.max_input_text_len = max_output_len; + pi->max_input_text_len = max_output_len; + } + + if ( popup_init(pi) == -1 ) { + if (callback) { + (*callback)(-1); + } + + pi->choice = POPUP_ABORT; + popup_close(pi); + return; } + pi->screen_id = gr_save_screen(); + // zero the popup input text - memset(Popup_info.input_text, 0, POPUP_INPUT_MAX_CHARS); - + SDL_zero(pi->input_text); + gamesnd_play_iface(SND_POPUP_APPEAR); // play sound when popup appears Mouse_hidden = 0; Popup_is_active = 1; +} - // if the user cancelled - if(popup_do(&Popup_info, Popup_flags) == POPUP_ABORT){ +const char *popup_input_sync(int flags, const char *caption, int max_output_len) +{ + popup_info *pi = &Popup_info; + + if ( Popup_is_active ) { + Int3(); // should never happen return NULL; } - - // otherwise return the - return Popup_info.input_text; + + popup_input(NULL, flags, caption, max_output_len); + + int rval = pi->choice; // if init failed, this will be ABORT + + while (rval == POPUP_NOCHANGE) { + rval = popup_do_sync(); + } + + popup_done(); + + if (rval == POPUP_ABORT) { + return NULL; + } + + return pi->input_text; +} + +const char *popup_get_input_text() +{ + popup_info *pi = &Popup_info; + + return pi->input_text; } int popup_running_state() @@ -1380,6 +1472,6 @@ void popup_change_text(const char *new_text) SDL_strlcpy(Popup_info.raw_text, new_text, SDL_arraysize(Popup_info.raw_text)); // recalculate all display information - popup_split_lines(&Popup_info,Popup_flags); + popup_split_lines(&Popup_info); } diff --git a/src/popup/popupdead.cpp b/src/popup/popupdead.cpp index 0be50d8..66e0810 100644 --- a/src/popup/popupdead.cpp +++ b/src/popup/popupdead.cpp @@ -573,6 +573,24 @@ int popupdead_skip_do_frame() } +static void skip_mission_callback(int choice) +{ + popup_done(); + + if (choice == 0) { + // stay on this mission, so proceed to normal death popup + // in other words, do nothing. + } else if (choice == 1) { + // skip this mission + Popupdead_active = 0; + mission_campaign_skip_to_next(); + gameseq_post_event(GS_EVENT_START_GAME); + } else if (choice == 2) { + // don't show this popup again + Player->show_skip_popup = 0; + } +} + // Called once per frame to run the dead popup int popupdead_do_frame(float frametime) { @@ -603,26 +621,10 @@ int popupdead_do_frame(float frametime) // maybe show skip mission popup if ((!Popupdead_skip_already_shown) && (Player->show_skip_popup) && (Game_mode & GM_NORMAL) && (Game_mode & GM_CAMPAIGN_MODE) && (Player->failures_this_session >= PLAYER_MISSION_FAILURE_LIMIT)) { - int popup_choice = popup(0, 3, XSTR("Do Not Skip This Mission", 1473), - XSTR("Advance To The Next Mission", 1474), - XSTR("Don't Show Me This Again", 1475), - XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) ); - switch (popup_choice) { - case 0: - // stay on this mission, so proceed to normal death popup - // in other words, do nothing. - break; - case 1: - // skip this mission - Popupdead_active = 0; - mission_campaign_skip_to_next(); - gameseq_post_event(GS_EVENT_START_GAME); - return -1; - case 2: - // dont show this again - Player->show_skip_popup = 0; - break; - } + popup_callback(skip_mission_callback, 0, 3, XSTR("Do Not Skip This Mission", 1473), + XSTR("Advance To The Next Mission", 1474), + XSTR("Don't Show Me This Again", 1475), + XSTR("You have failed this mission five times. If you like, you may advance to the next mission.", 1472) ); Popupdead_skip_already_shown = 1; } -- 2.39.2