allow specifying minimum levels for difficulties
This commit is contained in:
@@ -11,7 +11,6 @@
|
|||||||
- Figure out what causes the corruption message on PC proxy sessions and fix it
|
- Figure out what causes the corruption message on PC proxy sessions and fix it
|
||||||
- Make $edit for DC/PC
|
- Make $edit for DC/PC
|
||||||
- Add an idle connection timeout for proxy sessions
|
- Add an idle connection timeout for proxy sessions
|
||||||
- Make the proxy work with the various trial and beta versions
|
|
||||||
|
|
||||||
## Episode 3
|
## Episode 3
|
||||||
|
|
||||||
|
|||||||
@@ -3755,17 +3755,17 @@ shared_ptr<Lobby> create_game_generic(
|
|||||||
|
|
||||||
auto current_lobby = c->require_lobby();
|
auto current_lobby = c->require_lobby();
|
||||||
|
|
||||||
uint8_t min_level;
|
size_t min_level;
|
||||||
// A player's actual level is their displayed level - 1, so the minimums for
|
// A player's actual level is their displayed level - 1, so the minimums for
|
||||||
// Episode 1 (for example) are actually 1, 20, 40, 80.
|
// Episode 1 (for example) are actually 1, 20, 40, 80.
|
||||||
switch (episode) {
|
switch (episode) {
|
||||||
case Episode::EP1: {
|
case Episode::EP1: {
|
||||||
static const uint32_t min_levels[4] = {0, 19, 39, 79};
|
const auto& min_levels = (c->version() == Version::BB_V4) ? s->min_levels_v4[0] : DEFAULT_MIN_LEVELS_EP1;
|
||||||
min_level = min_levels[difficulty];
|
min_level = min_levels[difficulty];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Episode::EP2: {
|
case Episode::EP2: {
|
||||||
static const uint32_t min_levels[4] = {0, 29, 49, 89};
|
const auto& min_levels = (c->version() == Version::BB_V4) ? s->min_levels_v4[1] : DEFAULT_MIN_LEVELS_EP2;
|
||||||
min_level = min_levels[difficulty];
|
min_level = min_levels[difficulty];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3773,7 +3773,7 @@ shared_ptr<Lobby> create_game_generic(
|
|||||||
min_level = 0;
|
min_level = 0;
|
||||||
break;
|
break;
|
||||||
case Episode::EP4: {
|
case Episode::EP4: {
|
||||||
static const uint32_t min_levels[4] = {0, 39, 79, 109};
|
const auto& min_levels = (c->version() == Version::BB_V4) ? s->min_levels_v4[2] : DEFAULT_MIN_LEVELS_EP4;
|
||||||
min_level = min_levels[difficulty];
|
min_level = min_levels[difficulty];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3935,7 +3935,7 @@ shared_ptr<Lobby> create_game_generic(
|
|||||||
if (game->mode == GameMode::CHALLENGE) {
|
if (game->mode == GameMode::CHALLENGE) {
|
||||||
game->rare_enemy_rates = s->rare_enemy_rates_challenge;
|
game->rare_enemy_rates = s->rare_enemy_rates_challenge;
|
||||||
} else {
|
} else {
|
||||||
game->rare_enemy_rates = s->rare_enemy_rates.at(game->difficulty);
|
game->rare_enemy_rates = s->rare_enemy_rates_by_difficulty.at(game->difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game->base_version == Version::BB_V4) {
|
if (game->base_version == Version::BB_V4) {
|
||||||
|
|||||||
+37
-11
@@ -287,7 +287,7 @@ void ServerState::remove_lobby(uint32_t lobby_id) {
|
|||||||
this->id_to_lobby.erase(lobby_it);
|
this->id_to_lobby.erase(lobby_it);
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<Client> ServerState::find_client(const std::string* identifier, uint64_t serial_number, shared_ptr<Lobby> l) {
|
shared_ptr<Client> ServerState::find_client(const string* identifier, uint64_t serial_number, shared_ptr<Lobby> l) {
|
||||||
if ((serial_number == 0) && identifier) {
|
if ((serial_number == 0) && identifier) {
|
||||||
try {
|
try {
|
||||||
serial_number = stoull(*identifier, nullptr, 0);
|
serial_number = stoull(*identifier, nullptr, 0);
|
||||||
@@ -315,7 +315,7 @@ shared_ptr<Client> ServerState::find_client(const std::string* identifier, uint6
|
|||||||
throw out_of_range("client not found");
|
throw out_of_range("client not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ServerState::connect_address_for_client(std::shared_ptr<Client> c) const {
|
uint32_t ServerState::connect_address_for_client(shared_ptr<Client> c) const {
|
||||||
if (c->channel.is_virtual_connection) {
|
if (c->channel.is_virtual_connection) {
|
||||||
if (c->channel.remote_addr.ss_family != AF_INET) {
|
if (c->channel.remote_addr.ss_family != AF_INET) {
|
||||||
throw logic_error("virtual connection is missing remote IPv4 address");
|
throw logic_error("virtual connection is missing remote IPv4 address");
|
||||||
@@ -334,7 +334,7 @@ uint32_t ServerState::connect_address_for_client(std::shared_ptr<Client> c) cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const Menu> ServerState::information_menu_for_version(Version version) const {
|
shared_ptr<const Menu> ServerState::information_menu_for_version(Version version) const {
|
||||||
if (is_v1_or_v2(version)) {
|
if (is_v1_or_v2(version)) {
|
||||||
return this->information_menu_v2;
|
return this->information_menu_v2;
|
||||||
} else if (is_v3(version)) {
|
} else if (is_v3(version)) {
|
||||||
@@ -385,7 +385,7 @@ const vector<pair<string, uint16_t>>& ServerState::proxy_destinations_for_versio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const ItemParameterTable> ServerState::item_parameter_table_for_version(Version version) const {
|
shared_ptr<const ItemParameterTable> ServerState::item_parameter_table_for_version(Version version) const {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case Version::DC_NTE:
|
case Version::DC_NTE:
|
||||||
case Version::DC_V1_11_2000_PROTOTYPE:
|
case Version::DC_V1_11_2000_PROTOTYPE:
|
||||||
@@ -406,7 +406,7 @@ std::shared_ptr<const ItemParameterTable> ServerState::item_parameter_table_for_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServerState::describe_item(Version version, const ItemData& item, bool include_color_codes) const {
|
string ServerState::describe_item(Version version, const ItemData& item, bool include_color_codes) const {
|
||||||
return this->item_name_index->describe_item(
|
return this->item_name_index->describe_item(
|
||||||
version,
|
version,
|
||||||
item,
|
item,
|
||||||
@@ -448,9 +448,9 @@ void ServerState::set_port_configuration(
|
|||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<const string> ServerState::load_bb_file(
|
shared_ptr<const string> ServerState::load_bb_file(
|
||||||
const std::string& patch_index_filename,
|
const string& patch_index_filename,
|
||||||
const std::string& gsl_filename,
|
const string& gsl_filename,
|
||||||
const std::string& bb_directory_filename) const {
|
const string& bb_directory_filename) const {
|
||||||
|
|
||||||
if (this->bb_patch_file_index) {
|
if (this->bb_patch_file_index) {
|
||||||
// First, look in the patch tree's data directory
|
// First, look in the patch tree's data directory
|
||||||
@@ -919,10 +919,10 @@ void ServerState::parse_config(const JSON& json, bool is_reload) {
|
|||||||
try {
|
try {
|
||||||
string key = "RareEnemyRates-";
|
string key = "RareEnemyRates-";
|
||||||
key += token_name_for_difficulty(z);
|
key += token_name_for_difficulty(z);
|
||||||
this->rare_enemy_rates[z] = make_shared<Map::RareEnemyRates>(json.at(key));
|
this->rare_enemy_rates_by_difficulty[z] = make_shared<Map::RareEnemyRates>(json.at(key));
|
||||||
prev = this->rare_enemy_rates[z];
|
prev = this->rare_enemy_rates_by_difficulty[z];
|
||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
this->rare_enemy_rates[z] = prev;
|
this->rare_enemy_rates_by_difficulty[z] = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -930,6 +930,32 @@ void ServerState::parse_config(const JSON& json, bool is_reload) {
|
|||||||
} catch (const out_of_range&) {
|
} catch (const out_of_range&) {
|
||||||
this->rare_enemy_rates_challenge = Map::DEFAULT_RARE_ENEMIES;
|
this->rare_enemy_rates_challenge = Map::DEFAULT_RARE_ENEMIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->min_levels_v4[0] = DEFAULT_MIN_LEVELS_EP1;
|
||||||
|
this->min_levels_v4[1] = DEFAULT_MIN_LEVELS_EP2;
|
||||||
|
this->min_levels_v4[2] = DEFAULT_MIN_LEVELS_EP4;
|
||||||
|
try {
|
||||||
|
for (const auto& ep_it : json.get_dict("BBMinimumLevels")) {
|
||||||
|
array<size_t, 4> levels({0, 0, 0, 0});
|
||||||
|
for (size_t z = 0; z < 4; z++) {
|
||||||
|
levels[z] = ep_it.second->get_int(z) - 1;
|
||||||
|
}
|
||||||
|
switch (episode_for_token_name(ep_it.first)) {
|
||||||
|
case Episode::EP1:
|
||||||
|
this->min_levels_v4[0] = levels;
|
||||||
|
break;
|
||||||
|
case Episode::EP2:
|
||||||
|
this->min_levels_v4[1] = levels;
|
||||||
|
break;
|
||||||
|
case Episode::EP4:
|
||||||
|
this->min_levels_v4[2] = levels;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw runtime_error("unknown episode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const out_of_range&) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerState::load_bb_private_keys() {
|
void ServerState::load_bb_private_keys() {
|
||||||
|
|||||||
+2
-1
@@ -114,8 +114,9 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
|||||||
std::shared_ptr<const MagEvolutionTable> mag_evolution_table;
|
std::shared_ptr<const MagEvolutionTable> mag_evolution_table;
|
||||||
std::shared_ptr<const ItemNameIndex> item_name_index;
|
std::shared_ptr<const ItemNameIndex> item_name_index;
|
||||||
std::shared_ptr<const WordSelectTable> word_select_table;
|
std::shared_ptr<const WordSelectTable> word_select_table;
|
||||||
std::array<std::shared_ptr<const Map::RareEnemyRates>, 4> rare_enemy_rates;
|
std::array<std::shared_ptr<const Map::RareEnemyRates>, 4> rare_enemy_rates_by_difficulty;
|
||||||
std::shared_ptr<const Map::RareEnemyRates> rare_enemy_rates_challenge;
|
std::shared_ptr<const Map::RareEnemyRates> rare_enemy_rates_challenge;
|
||||||
|
std::array<std::array<size_t, 4>, 3> min_levels_v4; // Indexed as [episode][difficulty]
|
||||||
|
|
||||||
// Indexed as [type][difficulty][random_choice]
|
// Indexed as [type][difficulty][random_choice]
|
||||||
std::vector<std::vector<std::vector<ItemData>>> quest_F95E_results;
|
std::vector<std::vector<std::vector<ItemData>>> quest_F95E_results;
|
||||||
|
|||||||
@@ -42,6 +42,22 @@ const char* token_name_for_episode(Episode ep) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Episode episode_for_token_name(const string& name) {
|
||||||
|
if (name == "Episode1") {
|
||||||
|
return Episode::EP1;
|
||||||
|
}
|
||||||
|
if (name == "Episode2") {
|
||||||
|
return Episode::EP2;
|
||||||
|
}
|
||||||
|
if (name == "Episode3") {
|
||||||
|
return Episode::EP3;
|
||||||
|
}
|
||||||
|
if (name == "Episode4") {
|
||||||
|
return Episode::EP4;
|
||||||
|
}
|
||||||
|
throw runtime_error("unknown episode");
|
||||||
|
}
|
||||||
|
|
||||||
const char* abbreviation_for_episode(Episode ep) {
|
const char* abbreviation_for_episode(Episode ep) {
|
||||||
switch (ep) {
|
switch (ep) {
|
||||||
case Episode::NONE:
|
case Episode::NONE:
|
||||||
@@ -764,3 +780,7 @@ char char_for_challenge_rank(uint8_t rank) {
|
|||||||
}
|
}
|
||||||
return "BAS"[rank];
|
return "BAS"[rank];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const array<size_t, 4> DEFAULT_MIN_LEVELS_EP1({0, 19, 39, 79});
|
||||||
|
const array<size_t, 4> DEFAULT_MIN_LEVELS_EP2({0, 29, 49, 89});
|
||||||
|
const array<size_t, 4> DEFAULT_MIN_LEVELS_EP4({0, 39, 79, 109});
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ bool episode_has_arpg_semantics(Episode ep);
|
|||||||
const char* name_for_episode(Episode ep);
|
const char* name_for_episode(Episode ep);
|
||||||
const char* token_name_for_episode(Episode ep);
|
const char* token_name_for_episode(Episode ep);
|
||||||
const char* abbreviation_for_episode(Episode ep);
|
const char* abbreviation_for_episode(Episode ep);
|
||||||
|
Episode episode_for_token_name(const std::string& name);
|
||||||
|
|
||||||
enum class GameMode {
|
enum class GameMode {
|
||||||
NORMAL = 0,
|
NORMAL = 0,
|
||||||
@@ -78,3 +79,7 @@ const char* name_for_floor(Episode episode, uint8_t floor);
|
|||||||
uint32_t class_flags_for_class(uint8_t char_class);
|
uint32_t class_flags_for_class(uint8_t char_class);
|
||||||
|
|
||||||
char char_for_challenge_rank(uint8_t rank);
|
char char_for_challenge_rank(uint8_t rank);
|
||||||
|
|
||||||
|
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_EP1;
|
||||||
|
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_EP2;
|
||||||
|
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_EP4;
|
||||||
|
|||||||
@@ -730,7 +730,9 @@
|
|||||||
// rates significantly.
|
// rates significantly.
|
||||||
// If no rates are specified for a difficulty, the previous difficulty's rates
|
// If no rates are specified for a difficulty, the previous difficulty's rates
|
||||||
// will be used. (In the default configuration, only Normal is specified, so
|
// will be used. (In the default configuration, only Normal is specified, so
|
||||||
// all difficulties use the same rates.)
|
// all difficulties use the same rates.) If the Challenge set is not
|
||||||
|
// specified, the default rates are used for Challenge mode, which is 1/512
|
||||||
|
// for all enemies.
|
||||||
"RareEnemyRates-Normal": {
|
"RareEnemyRates-Normal": {
|
||||||
// These are probabilities out of 0xFFFFFFFF - so 0 means that rare enemy
|
// These are probabilities out of 0xFFFFFFFF - so 0 means that rare enemy
|
||||||
// will never appear, and 0xFFFFFFFF means it will always appear (until 16
|
// will never appear, and 0xFFFFFFFF means it will always appear (until 16
|
||||||
@@ -749,6 +751,14 @@
|
|||||||
// "RareEnemyRates-Ultimate": {...},
|
// "RareEnemyRates-Ultimate": {...},
|
||||||
// "RareEnemyRates-Challenge": {...},
|
// "RareEnemyRates-Challenge": {...},
|
||||||
|
|
||||||
|
// You can override the minimum character levels required to make BB games in
|
||||||
|
// each episode and difficulty level here.
|
||||||
|
"BBMinimumLevels": {
|
||||||
|
"Episode1": [1, 20, 50, 90],
|
||||||
|
"Episode2": [1, 30, 60, 100],
|
||||||
|
"Episode4": [1, 40, 70, 110],
|
||||||
|
},
|
||||||
|
|
||||||
// Whether to enable certain exception handling. Disabling this causes
|
// Whether to enable certain exception handling. Disabling this causes
|
||||||
// newserv to abort when any client causes an exception, which is generally
|
// newserv to abort when any client causes an exception, which is generally
|
||||||
// only useful for debugging newserv itself. This setting should usually be
|
// only useful for debugging newserv itself. This setting should usually be
|
||||||
|
|||||||
Reference in New Issue
Block a user