diff --git a/src/ItemCreator.cc b/src/ItemCreator.cc index e3cadf59..08e4a611 100644 --- a/src/ItemCreator.cc +++ b/src/ItemCreator.cc @@ -66,8 +66,9 @@ bool ItemCreator::are_rare_drops_allowed() const { // Note: The client has an additional check here, which appears to be a subtle // anti-cheating measure. There is a flag on the client, initially zero, which // is set to 1 when certain unexpected item-related things happen (for - // example, a player possessing a mag with a level above 200). When the flag - // is set, this function returns false, which prevents all rare item drops. + // example, a player possessing a mag with a level above 200, or a stack of + // consumables with an amount above the stack size limit). When the flag is + // set, this function returns false, which prevents all rare item drops. // newserv intentionally does not implement this flag. return (this->mode != GameMode::CHALLENGE); } diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index f646a15c..ef056827 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -1999,8 +1999,18 @@ static void on_pick_up_item_generic( if (fi->flags & 0x1000) { uint32_t pi = fi->data.primary_identifier(); - bool should_send_game_notif = s->notify_game_for_item_primary_identifiers.count(pi); - bool should_send_global_notif = s->notify_server_for_item_primary_identifiers.count(pi); + bool should_send_game_notif, should_send_global_notif; + if (is_v1_or_v2(c->version()) && (c->version() != Version::GC_NTE)) { + should_send_game_notif = s->notify_game_for_item_primary_identifiers_v1_v2.count(pi); + should_send_global_notif = s->notify_server_for_item_primary_identifiers_v1_v2.count(pi); + } else if (!is_v4(c->version())) { + should_send_game_notif = s->notify_game_for_item_primary_identifiers_v3.count(pi); + should_send_global_notif = s->notify_server_for_item_primary_identifiers_v3.count(pi); + } else { + should_send_game_notif = s->notify_game_for_item_primary_identifiers_v4.count(pi); + should_send_global_notif = s->notify_server_for_item_primary_identifiers_v4.count(pi); + } + if (should_send_game_notif || should_send_global_notif) { string p_name = p->disp.name.decode(); string desc = s->describe_item(c->version(), fi->data, true); diff --git a/src/ServerState.cc b/src/ServerState.cc index ff2e6852..4f5b72db 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -1214,30 +1214,34 @@ void ServerState::load_config_late() { } catch (const out_of_range&) { } - this->notify_game_for_item_primary_identifiers.clear(); - try { - for (const auto& pi_json : this->config_json->get_list("NotifyGameForItemPrimaryIdentifiers")) { - if (pi_json->is_int()) { - this->notify_game_for_item_primary_identifiers.emplace(pi_json->as_int()); - } else { - auto item = this->parse_item_description(Version::BB_V4, pi_json->as_string()); - this->notify_game_for_item_primary_identifiers.emplace(item.primary_identifier()); + auto parse_primary_identifier_list = [&](const char* key, Version base_version) -> std::unordered_set { + std::unordered_set ret; + try { + for (const auto& pi_json : this->config_json->get_list(key)) { + if (pi_json->is_int()) { + ret.emplace(pi_json->as_int()); + } else { + auto item = this->parse_item_description(base_version, pi_json->as_string()); + ret.emplace(item.primary_identifier()); + } } + } catch (const out_of_range&) { } - } catch (const out_of_range&) { - } - this->notify_server_for_item_primary_identifiers.clear(); - try { - for (const auto& pi_json : this->config_json->get_list("NotifyServerForItemPrimaryIdentifiers")) { - if (pi_json->is_int()) { - this->notify_server_for_item_primary_identifiers.emplace(pi_json->as_int()); - } else { - auto item = this->parse_item_description(Version::BB_V4, pi_json->as_string()); - this->notify_server_for_item_primary_identifiers.emplace(item.primary_identifier()); - } - } - } catch (const out_of_range&) { - } + return ret; + }; + this->notify_game_for_item_primary_identifiers_v1_v2 = parse_primary_identifier_list( + "NotifyGameForItemPrimaryIdentifiersV1V2", Version::PC_V2); + this->notify_game_for_item_primary_identifiers_v3 = parse_primary_identifier_list( + "NotifyGameForItemPrimaryIdentifiersV3", Version::GC_V3); + this->notify_game_for_item_primary_identifiers_v4 = parse_primary_identifier_list( + "NotifyGameForItemPrimaryIdentifiersV4", Version::BB_V4); + this->notify_server_for_item_primary_identifiers_v1_v2 = parse_primary_identifier_list( + "NotifyServerForItemPrimaryIdentifiersV1V2", Version::PC_V2); + this->notify_server_for_item_primary_identifiers_v3 = parse_primary_identifier_list( + "NotifyServerForItemPrimaryIdentifiersV3", Version::GC_V3); + this->notify_server_for_item_primary_identifiers_v4 = parse_primary_identifier_list( + "NotifyServerForItemPrimaryIdentifiersV4", Version::BB_V4); + } else { config_log.warning("BB item name index is missing; cannot load quest reward lists from config"); } diff --git a/src/ServerState.hh b/src/ServerState.hh index 13d475f1..06e04d5d 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -129,8 +129,12 @@ struct ServerState : public std::enable_shared_from_this { bool use_game_creator_section_id = false; bool default_rare_notifs_enabled_v1_v2 = false; bool default_rare_notifs_enabled_v3_v4 = false; - std::unordered_set notify_game_for_item_primary_identifiers; - std::unordered_set notify_server_for_item_primary_identifiers; + std::unordered_set notify_game_for_item_primary_identifiers_v1_v2; + std::unordered_set notify_game_for_item_primary_identifiers_v3; + std::unordered_set notify_game_for_item_primary_identifiers_v4; + std::unordered_set notify_server_for_item_primary_identifiers_v1_v2; + std::unordered_set notify_server_for_item_primary_identifiers_v3; + std::unordered_set notify_server_for_item_primary_identifiers_v4; bool notify_server_for_max_level_achieved = false; std::vector> bb_private_keys; std::shared_ptr function_code_index; diff --git a/system/config.example.json b/system/config.example.json index e167b690..c2fe0c73 100644 --- a/system/config.example.json +++ b/system/config.example.json @@ -992,8 +992,12 @@ // notifications regardless of their stats. For textual descriptions, the // items are parsed as they would be on BB, so certain V2-only items cannot // be represented this way. - "NotifyGameForItemPrimaryIdentifiers": [], - "NotifyServerForItemPrimaryIdentifiers": [], + "NotifyGameForItemPrimaryIdentifiersV1V2": [], + "NotifyGameForItemPrimaryIdentifiersV3": [], + "NotifyGameForItemPrimaryIdentifiersV4": [], + "NotifyServerForItemPrimaryIdentifiersV1V2": [], + "NotifyServerForItemPrimaryIdentifiersV3": [], + "NotifyServerForItemPrimaryIdentifiersV4": [], // Whether to notify the entire server when a player reaches the maximum level // (100 on v1, 200 on other versions, or 999 on Episode 3). diff --git a/tests/config.json b/tests/config.json index e1956e35..4d2b3c0d 100644 --- a/tests/config.json +++ b/tests/config.json @@ -31,8 +31,12 @@ "DefaultDropModeV4Challenge": "SERVER_SHARED", "CheatModeBehavior": "OnByDefault", "RareNotificationsEnabledByDefault": false, - "NotifyGameForItemPrimaryIdentifiers": [], - "NotifyServerForItemPrimaryIdentifiers": [], + "NotifyGameForItemPrimaryIdentifiersV1V2": [], + "NotifyGameForItemPrimaryIdentifiersV3": [], + "NotifyGameForItemPrimaryIdentifiersV4": [], + "NotifyServerForItemPrimaryIdentifiersV1V2": [], + "NotifyServerForItemPrimaryIdentifiersV3": [], + "NotifyServerForItemPrimaryIdentifiersV4": [], "NotifyServerForMaxLevelAchieved": false, "LocalAddress": "en0",