diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index b38fed46..1d674ea1 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -698,6 +698,14 @@ static void server_command_cheat(shared_ptr c, const std::string&) { } else { l->toggle_flag(Lobby::Flag::CHEATS_ENABLED); send_text_message_printf(l, "Cheat mode %s", l->check_flag(Lobby::Flag::CHEATS_ENABLED) ? "enabled" : "disabled"); + + if (!(c->license->flags & License::Flag::CHEAT_ANYWHERE)) { + size_t default_min_level = s->default_min_level_for_game(l->base_version, l->episode, l->difficulty); + if (l->min_level < default_min_level) { + l->min_level = default_min_level; + send_text_message_printf(l, "$C6Minimum level set\nto %" PRIu32, l->min_level + 1); + } + } } } @@ -985,7 +993,19 @@ static void server_command_min_level(shared_ptr c, const std::string& ar check_is_game(l, true); check_is_leader(l, c); - l->min_level = stoull(args) - 1; + size_t new_min_level = stoull(args) - 1; + + auto s = c->require_server_state(); + bool cheats_allowed = (l->check_flag(Lobby::Flag::CHEATS_ENABLED) || (c->license->flags & License::Flag::CHEAT_ANYWHERE)); + if (!cheats_allowed) { + size_t default_min_level = s->default_min_level_for_game(l->base_version, l->episode, l->difficulty); + if (new_min_level < default_min_level) { + send_text_message_printf(c, "$C6Cannot set minimum\nlevel below %zu", default_min_level + 1); + return; + } + } + + l->min_level = new_min_level; send_text_message_printf(l, "$C6Minimum level set\nto %" PRIu32, l->min_level + 1); } diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 1dccabf5..c56503fb 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -3966,31 +3966,7 @@ shared_ptr create_game_generic( auto current_lobby = c->require_lobby(); - size_t min_level; - // A player's actual level is their displayed level - 1, so the minimums for - // Episode 1 (for example) are actually 1, 20, 40, 80. - switch (episode) { - case Episode::EP1: { - const auto& min_levels = (c->version() == Version::BB_V4) ? s->min_levels_v4[0] : DEFAULT_MIN_LEVELS_V3; - min_level = min_levels[difficulty]; - break; - } - case Episode::EP2: { - const auto& min_levels = (c->version() == Version::BB_V4) ? s->min_levels_v4[1] : DEFAULT_MIN_LEVELS_V3; - min_level = min_levels[difficulty]; - break; - } - case Episode::EP3: - min_level = 0; - break; - case Episode::EP4: { - const auto& min_levels = (c->version() == Version::BB_V4) ? s->min_levels_v4[2] : DEFAULT_MIN_LEVELS_V3; - min_level = min_levels[difficulty]; - break; - } - default: - throw runtime_error("invalid episode"); - } + size_t min_level = s->default_min_level_for_game(c->version(), episode, difficulty); auto p = c->character(); if (!(c->license->flags & License::Flag::FREE_JOIN_GAMES) && diff --git a/src/ServerState.cc b/src/ServerState.cc index 682c2739..b9f5c8e6 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -342,6 +342,29 @@ shared_ptr ServerState::quest_index(Version version) const { return is_ep3(version) ? this->ep3_download_quest_index : this->default_quest_index; } +size_t ServerState::default_min_level_for_game(Version version, Episode episode, uint8_t difficulty) const { + // A player's actual level is their displayed level - 1, so the minimums for + // Episode 1 (for example) are actually 1, 20, 40, 80. + switch (episode) { + case Episode::EP1: { + const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[0] : DEFAULT_MIN_LEVELS_V3; + return min_levels.at(difficulty); + } + case Episode::EP2: { + const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[1] : DEFAULT_MIN_LEVELS_V3; + return min_levels.at(difficulty); + } + case Episode::EP3: + return 0; + case Episode::EP4: { + const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[2] : DEFAULT_MIN_LEVELS_V3; + return min_levels.at(difficulty); + } + default: + throw runtime_error("invalid episode"); + } +} + void ServerState::dispatch_destroy_lobbies(evutil_socket_t, short, void* ctx) { reinterpret_cast(ctx)->lobbies_to_destroy.clear(); } diff --git a/src/ServerState.hh b/src/ServerState.hh index cf6839b2..de1189b6 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -282,6 +282,8 @@ struct ServerState : public std::enable_shared_from_this { std::shared_ptr> information_contents_for_client(std::shared_ptr c) const; std::shared_ptr quest_index(Version version) const; + size_t default_min_level_for_game(Version version, Episode episode, uint8_t difficulty) const; + void set_port_configuration(const std::vector& port_configs); std::shared_ptr load_bb_file(