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.
This commit is contained in:
parent
f3d31a6d27
commit
b737524415
|
@ -153,6 +153,8 @@ void calc_frame_time(void);
|
||||||
#ifdef dsx
|
#ifdef dsx
|
||||||
namespace dsx {
|
namespace dsx {
|
||||||
|
|
||||||
|
enum class next_level_request_secret_flag : uint8_t;
|
||||||
|
|
||||||
struct game_window;
|
struct game_window;
|
||||||
extern game_window *Game_wind;
|
extern game_window *Game_wind;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
||||||
#include "fwd-window.h"
|
#include "fwd-window.h"
|
||||||
#include "powerup.h"
|
#include "powerup.h"
|
||||||
|
|
||||||
#if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II)
|
#ifdef dsx
|
||||||
|
|
||||||
namespace dcx {
|
namespace dcx {
|
||||||
template <std::size_t>
|
template <std::size_t>
|
||||||
|
@ -58,33 +58,43 @@ extern int Player_highest_level;
|
||||||
//
|
//
|
||||||
|
|
||||||
// starts a new game on the given level
|
// starts a new game on the given level
|
||||||
#ifdef dsx
|
|
||||||
namespace 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);
|
void StartNewGame(int start_level);
|
||||||
|
|
||||||
// starts the next level
|
// starts the next level
|
||||||
window_event_result StartNewLevel(int level_num);
|
window_event_result StartNewLevel(int level_num);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
void InitPlayerObject(); //make sure player's object set up
|
void InitPlayerObject(); //make sure player's object set up
|
||||||
namespace dsx {
|
namespace dsx {
|
||||||
void init_player_stats_game(playernum_t pnum); //clear all stats
|
void init_player_stats_game(playernum_t pnum); //clear all stats
|
||||||
}
|
|
||||||
|
|
||||||
// called when the player has finished a level
|
// called when the player has finished a level
|
||||||
// if secret flag is true, advance to secret level, else next normal level
|
// if secret flag is true, advance to secret level, else next normal level
|
||||||
#ifdef dsx
|
window_event_result PlayerFinishedLevel(
|
||||||
namespace dsx {
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
window_event_result PlayerFinishedLevel(int secret_flag);
|
next_level_request_secret_flag secret_flag
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
// called when the player has died
|
// called when the player has died
|
||||||
window_event_result DoPlayerDead(void);
|
window_event_result DoPlayerDead(void);
|
||||||
|
|
||||||
#if defined(DXX_BUILD_DESCENT_I)
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
#define gameseq_remove_unused_players(Robot_info) gameseq_remove_unused_players()
|
#define gameseq_remove_unused_players(Robot_info) gameseq_remove_unused_players()
|
||||||
|
#undef PlayerFinishedLevel
|
||||||
#elif defined(DXX_BUILD_DESCENT_II)
|
#elif defined(DXX_BUILD_DESCENT_II)
|
||||||
#undef gameseq_remove_unused_players
|
#undef gameseq_remove_unused_players
|
||||||
|
#define PlayerFinishedLevel(secret_flag) ((void)secret_flag,PlayerFinishedLevel())
|
||||||
// load just the hxm file
|
// load just the hxm file
|
||||||
void load_level_robots(int level_num);
|
void load_level_robots(int level_num);
|
||||||
void load_level_robots(const d_fname &level_name);
|
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 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);
|
void bash_to_shield(const d_powerup_info_array &Powerup_info, const d_vclip_array &Vclip, object_base &i);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Show endlevel bonus scores
|
// Show endlevel bonus scores
|
||||||
namespace dcx {
|
namespace dcx {
|
||||||
|
|
|
@ -241,7 +241,11 @@ struct dispatch_table
|
||||||
virtual void send_endlevel_packet() const = 0;
|
virtual void send_endlevel_packet() const = 0;
|
||||||
virtual void kick_player(const _sockaddr &dump_addr, int why) const = 0;
|
virtual void kick_player(const _sockaddr &dump_addr, int why) const = 0;
|
||||||
virtual void disconnect_player(int playernum) 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;
|
virtual void leave_game() const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,11 @@ struct dispatch_table final : multi::dispatch_table
|
||||||
virtual void send_endlevel_packet() const override;
|
virtual void send_endlevel_packet() const override;
|
||||||
virtual void kick_player(const _sockaddr &dump_addr, int why) const override;
|
virtual void kick_player(const _sockaddr &dump_addr, int why) const override;
|
||||||
virtual void disconnect_player(int playernum) 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;
|
virtual void leave_game() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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))
|
if (!(!(Game_mode & GM_MULTI) && (endlevel_movie_played == movie_play_status::skipped) && endlevel_data_loaded))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
return PlayerFinishedLevel(next_level_request_secret_flag::only_normal_level); //done with level
|
||||||
return PlayerFinishedLevel(0); //done with level
|
|
||||||
}
|
}
|
||||||
#if defined(DXX_BUILD_DESCENT_II)
|
#if defined(DXX_BUILD_DESCENT_II)
|
||||||
int exit_models_loaded = 0;
|
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);
|
const auto tunnel_length = get_tunnel_length(vcsegptridx, console_seg, exit_console_side);
|
||||||
if (!tunnel_length)
|
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
|
//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]);
|
select_cockpit(PlayerCfg.CockpitMode[0]);
|
||||||
|
|
||||||
Endlevel_sequence = EL_OFF;
|
Endlevel_sequence = EL_OFF;
|
||||||
return PlayerFinishedLevel(0);
|
return PlayerFinishedLevel(next_level_request_secret_flag::only_normal_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VCLIP_BIG_PLAYER_EXPLOSION 58
|
#define VCLIP_BIG_PLAYER_EXPLOSION 58
|
||||||
|
|
|
@ -115,9 +115,10 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
||||||
namespace d1x {
|
namespace d1x {
|
||||||
namespace {
|
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(
|
for (const auto &&[idx, table_entry] : enumerate(
|
||||||
unchecked_partial_range(
|
unchecked_partial_range(
|
||||||
mission.secret_level_table.get(),
|
mission.secret_level_table.get(),
|
||||||
|
@ -221,7 +222,14 @@ static unsigned get_starting_concussion_missile_count()
|
||||||
namespace dsx {
|
namespace dsx {
|
||||||
namespace {
|
namespace {
|
||||||
static void init_player_stats_ship(object &, fix GameTime64);
|
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 StartLevel(int random_flag);
|
||||||
static void copy_defaults_to_robot_all(const d_robot_info_array &Robot_info);
|
static void copy_defaults_to_robot_all(const d_robot_info_array &Robot_info);
|
||||||
|
|
||||||
|
@ -1658,7 +1666,11 @@ void EnterSecretLevel(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//called when the player has finished a level
|
//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 &Objects = LevelUniqueObjectState.Objects;
|
||||||
auto &vmobjptr = Objects.vmptr;
|
auto &vmobjptr = Objects.vmptr;
|
||||||
|
@ -1670,7 +1682,7 @@ window_event_result PlayerFinishedLevel(int secret_flag)
|
||||||
auto &player_info = get_local_plrobj().ctype.player_info;
|
auto &player_info = get_local_plrobj().ctype.player_info;
|
||||||
player_info.mission.hostages_rescued_total += player_info.mission.hostages_on_board;
|
player_info.mission.hostages_rescued_total += player_info.mission.hostages_on_board;
|
||||||
#if defined(DXX_BUILD_DESCENT_I)
|
#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<newmenu_item, 1>;
|
using items_type = std::array<newmenu_item, 1>;
|
||||||
struct message_menu : items_type, passive_newmenu
|
struct message_menu : items_type, passive_newmenu
|
||||||
{
|
{
|
||||||
|
@ -1685,7 +1697,7 @@ window_event_result PlayerFinishedLevel(int secret_flag)
|
||||||
run_blocking_newmenu<message_menu>(*grd_curcanv);
|
run_blocking_newmenu<message_menu>(*grd_curcanv);
|
||||||
}
|
}
|
||||||
#elif defined(DXX_BUILD_DESCENT_II)
|
#elif defined(DXX_BUILD_DESCENT_II)
|
||||||
Assert(!secret_flag);
|
constexpr auto secret_flag = next_level_request_secret_flag::only_normal_level;
|
||||||
#endif
|
#endif
|
||||||
if (Game_mode & GM_NETWORK)
|
if (Game_mode & GM_NETWORK)
|
||||||
get_local_player().connected = CONNECT_WAITING; // Finished but did not die
|
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)
|
//called to go to the next level (if there is one)
|
||||||
//if secret_flag is true, advance to secret level, else next normal one
|
//if secret_flag is true, advance to secret level, else next normal one
|
||||||
// Return true if game over.
|
// 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 &LevelUniqueControlCenterState = LevelUniqueObjectState.ControlCenterState;
|
||||||
auto rval = window_event_result::handled;
|
auto rval = window_event_result::handled;
|
||||||
|
|
||||||
#if defined(DXX_BUILD_DESCENT_II)
|
#if defined(DXX_BUILD_DESCENT_II)
|
||||||
Assert(!secret_flag);
|
|
||||||
|
|
||||||
// Loading a level can write over homing_flag.
|
// Loading a level can write over homing_flag.
|
||||||
// So for simplicity, reset the homing weapon cheat here.
|
// So for simplicity, reset the homing weapon cheat here.
|
||||||
if (cheats.homingfire)
|
if (cheats.homingfire)
|
||||||
|
@ -1796,7 +1810,11 @@ static window_event_result AdvanceLevel(int secret_flag)
|
||||||
if (Game_mode & GM_MULTI)
|
if (Game_mode & GM_MULTI)
|
||||||
{
|
{
|
||||||
int result;
|
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
|
if (result) // failed to sync
|
||||||
{
|
{
|
||||||
// check if player has finished the game
|
// check if player has finished the game
|
||||||
|
@ -1906,7 +1924,7 @@ window_event_result DoPlayerDead()
|
||||||
const auto g = Game_wind;
|
const auto g = Game_wind;
|
||||||
if (g)
|
if (g)
|
||||||
g->set_visible(0);
|
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);
|
init_player_stats_new_ship(Player_num);
|
||||||
last_drawn_cockpit = cockpit_mode_t{UINT8_MAX};
|
last_drawn_cockpit = cockpit_mode_t{UINT8_MAX};
|
||||||
|
|
|
@ -1660,26 +1660,25 @@ namespace dsx {
|
||||||
namespace multi {
|
namespace multi {
|
||||||
namespace udp {
|
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
|
// Do whatever needs to be done between levels
|
||||||
#if defined(DXX_BUILD_DESCENT_II)
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
if (EMULATING_D1)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
// 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!
|
// 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))
|
range_for (const auto i, unchecked_partial_range(Current_mission->secret_level_table.get(), Current_mission->n_secret_levels))
|
||||||
{
|
{
|
||||||
if (Current_level_num == i)
|
if (Current_level_num == i)
|
||||||
{
|
{
|
||||||
*secret = 1;
|
*secret = next_level_request_secret_flag::use_secret;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(DXX_BUILD_DESCENT_II)
|
|
||||||
else
|
|
||||||
*secret = 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Network_status = network_state::endlevel; // We are between levels
|
Network_status = network_state::endlevel; // We are between levels
|
||||||
|
|
|
@ -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);
|
multi_send_endlevel_start(multi_endlevel_type::secret);
|
||||||
if (Game_mode & GM_NETWORK)
|
if (Game_mode & GM_NETWORK)
|
||||||
multi::dispatch->do_protocol_frame(1, 1);
|
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;
|
LevelUniqueControlCenterState.Control_center_destroyed = 0;
|
||||||
return std::max(result, window_event_result::handled);
|
return std::max(result, window_event_result::handled);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue