From b73752441537d229a2f206a2e11161c4283ea0d6 Mon Sep 17 00:00:00 2001 From: Kp Date: Sat, 16 Jul 2022 15:26:12 +0000 Subject: [PATCH] Use enum class for `next_level_request_secret_flag` Instead of passing a bare `int` named `secret_flag`, define it as an `enum class : uint8_t` to name the two special values. Rework the passing of this value, to deal with some confusing inconsistencies when reading the code. Before this change: In D1: - Multiplayer will always go to the secret level, regardless of which exit door the player used. In D2: - Flying through a D1 secret exit in multiplayer shows the on-HUD error "Secret Level Teleporter disabled in multiplayer!", and does not exit the level. This is at best confusing, and at worst dangerous, since D1 secret exits are only available during the countdown, so the player has little time to realize that the normal exit must be used instead. - Like D1, multiplayer will request to go to the secret level regardless of the exit used. Unlike D1, the caller ignores the flag and always advances to the next regular level. After this change: - No observable differences for the player in-game. The questionable D2 secret exit handling for D1 is retained. - The code makes clearer that secret exits do not work in D2 multiplayer, by way of `#if defined(DXX_BUILD_DESCENT_I)` guarding the existence of the parameter and all updates to it. --- common/main/fwd-game.h | 2 ++ common/main/gameseq.h | 25 ++++++++++++++++-------- common/main/multi.h | 6 +++++- common/main/net_udp.h | 6 +++++- similar/main/endlevel.cpp | 7 +++---- similar/main/gameseq.cpp | 40 ++++++++++++++++++++++++++++----------- similar/main/net_udp.cpp | 15 +++++++-------- similar/main/switch.cpp | 2 +- 8 files changed, 69 insertions(+), 34 deletions(-) diff --git a/common/main/fwd-game.h b/common/main/fwd-game.h index baca0aaf2..13d70de4b 100644 --- a/common/main/fwd-game.h +++ b/common/main/fwd-game.h @@ -153,6 +153,8 @@ void calc_frame_time(void); #ifdef dsx namespace dsx { +enum class next_level_request_secret_flag : uint8_t; + struct game_window; extern game_window *Game_wind; diff --git a/common/main/gameseq.h b/common/main/gameseq.h index 783ba4d0e..085082702 100644 --- a/common/main/gameseq.h +++ b/common/main/gameseq.h @@ -34,7 +34,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #include "fwd-window.h" #include "powerup.h" -#if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II) +#ifdef dsx namespace dcx { template @@ -58,33 +58,43 @@ extern int Player_highest_level; // // starts a new game on the given level -#ifdef dsx namespace dsx { + +enum class next_level_request_secret_flag : uint8_t +{ + only_normal_level, +#if defined(DXX_BUILD_DESCENT_I) + use_secret, +#endif +}; + void StartNewGame(int start_level); // starts the next level window_event_result StartNewLevel(int level_num); } -#endif void InitPlayerObject(); //make sure player's object set up namespace dsx { void init_player_stats_game(playernum_t pnum); //clear all stats -} // called when the player has finished a level // if secret flag is true, advance to secret level, else next normal level -#ifdef dsx -namespace dsx { -window_event_result PlayerFinishedLevel(int secret_flag); +window_event_result PlayerFinishedLevel( +#if defined(DXX_BUILD_DESCENT_I) + next_level_request_secret_flag secret_flag +#endif + ); // called when the player has died window_event_result DoPlayerDead(void); #if defined(DXX_BUILD_DESCENT_I) #define gameseq_remove_unused_players(Robot_info) gameseq_remove_unused_players() +#undef PlayerFinishedLevel #elif defined(DXX_BUILD_DESCENT_II) #undef gameseq_remove_unused_players +#define PlayerFinishedLevel(secret_flag) ((void)secret_flag,PlayerFinishedLevel()) // load just the hxm file void load_level_robots(int level_num); void load_level_robots(const d_fname &level_name); @@ -117,7 +127,6 @@ namespace dsx { void create_player_appearance_effect(const d_vclip_array &Vclip, const object_base &player_obj); void bash_to_shield(const d_powerup_info_array &Powerup_info, const d_vclip_array &Vclip, object_base &i); } -#endif // Show endlevel bonus scores namespace dcx { diff --git a/common/main/multi.h b/common/main/multi.h index a661cf358..50e351f73 100644 --- a/common/main/multi.h +++ b/common/main/multi.h @@ -241,7 +241,11 @@ struct dispatch_table virtual void send_endlevel_packet() const = 0; virtual void kick_player(const _sockaddr &dump_addr, int why) const = 0; virtual void disconnect_player(int playernum) const = 0; - virtual int end_current_level(int *secret) const = 0; + virtual int end_current_level( +#if defined(DXX_BUILD_DESCENT_I) + next_level_request_secret_flag *secret +#endif + ) const = 0; virtual void leave_game() const = 0; }; } diff --git a/common/main/net_udp.h b/common/main/net_udp.h index fe8410e79..a260bb123 100644 --- a/common/main/net_udp.h +++ b/common/main/net_udp.h @@ -33,7 +33,11 @@ struct dispatch_table final : multi::dispatch_table virtual void send_endlevel_packet() const override; virtual void kick_player(const _sockaddr &dump_addr, int why) const override; virtual void disconnect_player(int playernum) const override; - virtual int end_current_level(int *secret) const override; + virtual int end_current_level( +#if defined(DXX_BUILD_DESCENT_I) + next_level_request_secret_flag *secret +#endif + ) const override; virtual void leave_game() const override; }; diff --git a/similar/main/endlevel.cpp b/similar/main/endlevel.cpp index 22a42adad..d5ae431b9 100644 --- a/similar/main/endlevel.cpp +++ b/similar/main/endlevel.cpp @@ -723,8 +723,7 @@ window_event_result start_endlevel_sequence() if (!(!(Game_mode & GM_MULTI) && (endlevel_movie_played == movie_play_status::skipped) && endlevel_data_loaded)) #endif { - - return PlayerFinishedLevel(0); //done with level + return PlayerFinishedLevel(next_level_request_secret_flag::only_normal_level); //done with level } #if defined(DXX_BUILD_DESCENT_II) int exit_models_loaded = 0; @@ -747,7 +746,7 @@ window_event_result start_endlevel_sequence() const auto tunnel_length = get_tunnel_length(vcsegptridx, console_seg, exit_console_side); if (!tunnel_length) { - return PlayerFinishedLevel(0); //don't do special sequence + return PlayerFinishedLevel(next_level_request_secret_flag::only_normal_level); //don't do special sequence } //now pick transition segnum 1/3 of the way in @@ -793,7 +792,7 @@ window_event_result stop_endlevel_sequence() select_cockpit(PlayerCfg.CockpitMode[0]); Endlevel_sequence = EL_OFF; - return PlayerFinishedLevel(0); + return PlayerFinishedLevel(next_level_request_secret_flag::only_normal_level); } #define VCLIP_BIG_PLAYER_EXPLOSION 58 diff --git a/similar/main/gameseq.cpp b/similar/main/gameseq.cpp index 54110da6e..0aa58f537 100644 --- a/similar/main/gameseq.cpp +++ b/similar/main/gameseq.cpp @@ -115,9 +115,10 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. namespace d1x { namespace { -static int8_t find_next_level(const int secret_flag, const int current_level_num, const Mission &mission) +static int8_t find_next_level(const next_level_request_secret_flag secret_flag, const int current_level_num, const Mission &mission) { - if (secret_flag) { //go to secret level instead + if (secret_flag != next_level_request_secret_flag::only_normal_level) + { //go to secret level instead for (const auto &&[idx, table_entry] : enumerate( unchecked_partial_range( mission.secret_level_table.get(), @@ -221,7 +222,14 @@ static unsigned get_starting_concussion_missile_count() namespace dsx { namespace { static void init_player_stats_ship(object &, fix GameTime64); -static window_event_result AdvanceLevel(int secret_flag); +static window_event_result AdvanceLevel( +#if defined(DXX_BUILD_DESCENT_I) +#undef AdvanceLevel + next_level_request_secret_flag secret_flag +#elif defined(DXX_BUILD_DESCENT_II) +#define AdvanceLevel(secret_flag) ((void)secret_flag,AdvanceLevel()) +#endif + ); static void StartLevel(int random_flag); static void copy_defaults_to_robot_all(const d_robot_info_array &Robot_info); @@ -1658,7 +1666,11 @@ void EnterSecretLevel(void) #endif //called when the player has finished a level -window_event_result PlayerFinishedLevel(int secret_flag) +window_event_result (PlayerFinishedLevel)( +#if defined(DXX_BUILD_DESCENT_I) + const next_level_request_secret_flag secret_flag +#endif + ) { auto &Objects = LevelUniqueObjectState.Objects; auto &vmobjptr = Objects.vmptr; @@ -1670,7 +1682,7 @@ window_event_result PlayerFinishedLevel(int secret_flag) auto &player_info = get_local_plrobj().ctype.player_info; player_info.mission.hostages_rescued_total += player_info.mission.hostages_on_board; #if defined(DXX_BUILD_DESCENT_I) - if (!(Game_mode & GM_MULTI) && (secret_flag)) { + if (!(Game_mode & GM_MULTI) && secret_flag != next_level_request_secret_flag::only_normal_level) { using items_type = std::array; struct message_menu : items_type, passive_newmenu { @@ -1685,7 +1697,7 @@ window_event_result PlayerFinishedLevel(int secret_flag) run_blocking_newmenu(*grd_curcanv); } #elif defined(DXX_BUILD_DESCENT_II) - Assert(!secret_flag); + constexpr auto secret_flag = next_level_request_secret_flag::only_normal_level; #endif if (Game_mode & GM_NETWORK) get_local_player().connected = CONNECT_WAITING; // Finished but did not die @@ -1762,14 +1774,16 @@ static void DoEndGame() //called to go to the next level (if there is one) //if secret_flag is true, advance to secret level, else next normal one // Return true if game over. -static window_event_result AdvanceLevel(int secret_flag) +static window_event_result (AdvanceLevel)( +#if defined(DXX_BUILD_DESCENT_I) + next_level_request_secret_flag secret_flag +#endif + ) { auto &LevelUniqueControlCenterState = LevelUniqueObjectState.ControlCenterState; auto rval = window_event_result::handled; #if defined(DXX_BUILD_DESCENT_II) - Assert(!secret_flag); - // Loading a level can write over homing_flag. // So for simplicity, reset the homing weapon cheat here. if (cheats.homingfire) @@ -1796,7 +1810,11 @@ static window_event_result AdvanceLevel(int secret_flag) if (Game_mode & GM_MULTI) { int result; - result = multi::dispatch->end_current_level(&secret_flag); // Wait for other players to reach this point + result = multi::dispatch->end_current_level( +#if defined(DXX_BUILD_DESCENT_I) + &secret_flag +#endif + ); // Wait for other players to reach this point if (result) // failed to sync { // check if player has finished the game @@ -1906,7 +1924,7 @@ window_event_result DoPlayerDead() const auto g = Game_wind; if (g) g->set_visible(0); - result = AdvanceLevel(0); //if finished, go on to next level + result = AdvanceLevel(next_level_request_secret_flag::only_normal_level); //if finished, go on to next level init_player_stats_new_ship(Player_num); last_drawn_cockpit = cockpit_mode_t{UINT8_MAX}; diff --git a/similar/main/net_udp.cpp b/similar/main/net_udp.cpp index e1a38edd0..3f3bf2c8a 100644 --- a/similar/main/net_udp.cpp +++ b/similar/main/net_udp.cpp @@ -1660,26 +1660,25 @@ namespace dsx { namespace multi { namespace udp { -int dispatch_table::end_current_level(int *secret) const +int dispatch_table::end_current_level( +#if defined(DXX_BUILD_DESCENT_I) + next_level_request_secret_flag *const secret +#endif + ) const { // Do whatever needs to be done between levels -#if defined(DXX_BUILD_DESCENT_II) - if (EMULATING_D1) -#endif +#if defined(DXX_BUILD_DESCENT_I) { // We do not really check if a player has actually found a secret level... yeah, I am too lazy! So just go there and pretend we did! range_for (const auto i, unchecked_partial_range(Current_mission->secret_level_table.get(), Current_mission->n_secret_levels)) { if (Current_level_num == i) { - *secret = 1; + *secret = next_level_request_secret_flag::use_secret; break; } } } -#if defined(DXX_BUILD_DESCENT_II) - else - *secret = 0; #endif Network_status = network_state::endlevel; // We are between levels diff --git a/similar/main/switch.cpp b/similar/main/switch.cpp index c002c3156..59a7f4c36 100644 --- a/similar/main/switch.cpp +++ b/similar/main/switch.cpp @@ -347,7 +347,7 @@ window_event_result check_trigger_sub(object &plrobj, const trgnum_t trigger_num multi_send_endlevel_start(multi_endlevel_type::secret); if (Game_mode & GM_NETWORK) multi::dispatch->do_protocol_frame(1, 1); - result = std::max(PlayerFinishedLevel(1), result); //1 means go to secret level + result = std::max(PlayerFinishedLevel(next_level_request_secret_flag::use_secret), result); LevelUniqueControlCenterState.Control_center_destroyed = 0; return std::max(result, window_event_result::handled); }