From a2e3f4882d1abdae3995d2f8b4cf3d81767e5bde Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Fri, 1 Mar 2024 21:22:14 -0800 Subject: [PATCH] make quest episode filter configurable --- src/Quest.cc | 15 ++++----------- src/Quest.hh | 5 ++++- src/ReceiveCommands.cc | 28 ++++------------------------ system/config.example.json | 15 ++++++++------- tests/config.json | 12 ++++++------ 5 files changed, 26 insertions(+), 49 deletions(-) diff --git a/src/Quest.cc b/src/Quest.cc index bbeea680..7adbea98 100644 --- a/src/Quest.cc +++ b/src/Quest.cc @@ -777,14 +777,9 @@ vector> QuestIndex::categories( Episode episode, Version version, IncludeCondition include_condition) const { - // The episode filter should apply in normal or solo mode - if ((menu_type != QuestMenuType::NORMAL) && (menu_type != QuestMenuType::SOLO)) { - episode = Episode::NONE; - } - vector> ret; for (const auto& cat : this->category_index->categories) { - if (cat->check_flag(menu_type) && !this->filter(menu_type, episode, version, cat->category_id, include_condition, 1).empty()) { + if (cat->check_flag(menu_type) && !this->filter(episode, version, cat->category_id, include_condition, 1).empty()) { ret.emplace_back(cat); } } @@ -792,15 +787,13 @@ vector> QuestIndex::categories( } vector>> QuestIndex::filter( - QuestMenuType menu_type, Episode episode, Version version, uint32_t category_id, IncludeCondition include_condition, size_t limit) const { - if ((menu_type != QuestMenuType::NORMAL) && (menu_type != QuestMenuType::SOLO)) { - episode = Episode::NONE; - } + auto cat = this->category_index->at(category_id); + Episode effective_episode = cat->enable_episode_filter() ? episode : Episode::NONE; vector>> ret; auto category_it = this->quests_by_category_id_and_number.find(category_id); @@ -808,7 +801,7 @@ vector>> QuestIndex::filt return ret; } for (auto it : category_it->second) { - if (((episode == Episode::NONE) || (it.second->episode == episode)) && + if (((effective_episode == Episode::NONE) || (it.second->episode == effective_episode)) && it.second->has_version_any_language(version)) { IncludeState state = include_condition ? include_condition(it.second) : IncludeState::AVAILABLE; if (state == IncludeState::HIDDEN) { diff --git a/src/Quest.hh b/src/Quest.hh index f508a46a..fb486bb1 100644 --- a/src/Quest.hh +++ b/src/Quest.hh @@ -31,6 +31,7 @@ enum class QuestMenuType { GOVERNMENT = 4, DOWNLOAD = 5, EP3_DOWNLOAD = 6, + // 7 can't be used as a menu type (it enables the per-episode filter) }; struct QuestCategoryIndex { @@ -46,6 +47,9 @@ struct QuestCategoryIndex { [[nodiscard]] inline bool check_flag(QuestMenuType menu_type) const { return this->enabled_flags & (1 << static_cast(menu_type)); } + [[nodiscard]] inline bool enable_episode_filter() const { + return this->enabled_flags & 0x80; + } }; std::vector> categories; @@ -151,7 +155,6 @@ struct QuestIndex { Version version, IncludeCondition include_condition = nullptr) const; std::vector>> filter( - QuestMenuType menu_type, Episode episode, Version version, uint32_t category_id, diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index f16b32e0..d32c67da 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -2228,7 +2228,7 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, string& data) { auto quest_index = s->quest_index(c->version()); const auto& categories = quest_index->categories(menu_type, Episode::EP3, c->version()); if (categories.size() == 1) { - auto quests = quest_index->filter(menu_type, Episode::EP3, c->version(), categories[0]->category_id); + auto quests = quest_index->filter(Episode::EP3, c->version(), categories[0]->category_id); send_quest_menu(c, quests, true); break; } @@ -2491,32 +2491,12 @@ static void on_10(shared_ptr c, uint16_t, uint32_t, string& data) { shared_ptr l = c->lobby.lock(); Episode episode = l ? l->episode : Episode::NONE; - QuestMenuType menu_type = QuestMenuType::NORMAL; QuestIndex::IncludeCondition include_condition = nullptr; - if (!l) { - // Assume the menu to be sent is the download quest menu if the client - // is not in any lobby - menu_type = is_ep3(c->version()) ? QuestMenuType::EP3_DOWNLOAD : QuestMenuType::DOWNLOAD; - } else { - auto cat = quest_index->category_index->at(item_id); - static const std::array menu_types({ - QuestMenuType::GOVERNMENT, - QuestMenuType::CHALLENGE, - QuestMenuType::BATTLE, - QuestMenuType::SOLO, - }); - for (QuestMenuType check_menu_type : menu_types) { - if (cat->check_flag(check_menu_type)) { - menu_type = check_menu_type; - break; - } - } - if (!c->license->check_flag(License::Flag::DISABLE_QUEST_REQUIREMENTS)) { - include_condition = l->quest_include_condition(); - } + if (l && !c->license->check_flag(License::Flag::DISABLE_QUEST_REQUIREMENTS)) { + include_condition = l->quest_include_condition(); } - const auto& quests = quest_index->filter(menu_type, episode, c->version(), item_id, include_condition); + const auto& quests = quest_index->filter(episode, c->version(), item_id, include_condition); send_quest_menu(c, quests, !l); break; } diff --git a/system/config.example.json b/system/config.example.json index a9d687ee..81fa9ea9 100644 --- a/system/config.example.json +++ b/system/config.example.json @@ -648,18 +648,19 @@ // 0x10 - appears at government counter (BB) // 0x20 - appears in download quest menu // 0x40 - appears in Episode 3 download quest menu + // 0x80 - hide quests that don't match the game's episode // directory_name: the directory inside system/quests that contains quests // for this category. // category_name: what appears in the quest menu on the client. // description: what appears in the category description window (may // contain color escape codes like $C6). - [0x01, "retrieval", "Retrieval", "$E$C6Quests that involve\nretrieving an object"], - [0x01, "extermination", "Extermination", "$E$C6Quests that involve\ndestroying all\nmonsters"], - [0x01, "events", "Events", "$E$C6Quests that are part\nof an event"], - [0x01, "shops", "Shops", "$E$C6Quests that contain\nshops"], - [0x01, "vr", "Virtual Reality", "$E$C6Quests that are\ndone in a simulator"], - [0x01, "tower", "Control Tower", "$E$C6Quests that take\nplace at the Control\nTower"], - [0x01, "team", "Team", "$E$C6Quests for you\nand your team\nmembers."], + [0x81, "retrieval", "Retrieval", "$E$C6Quests that involve\nretrieving an object"], + [0x81, "extermination", "Extermination", "$E$C6Quests that involve\ndestroying all\nmonsters"], + [0x81, "events", "Events", "$E$C6Quests that are part\nof an event"], + [0x81, "shops", "Shops", "$E$C6Quests that contain\nshops"], + [0x81, "vr", "Virtual Reality", "$E$C6Quests that are\ndone in a simulator"], + [0x81, "tower", "Control Tower", "$E$C6Quests that take\nplace at the Control\nTower"], + [0x81, "team", "Team", "$E$C6Quests for you\nand your team\nmembers."], [0x02, "battle", "Battle", "$E$C6Battle mode rule\nsets"], [0x04, "challenge-ep1", "Challenge (Episode 1)", "$E$C6Challenge mode\nquests in Episode 1"], [0x04, "challenge-ep2", "Challenge (Episode 2)", "$E$C6Challenge mode\nquests in Episode 2"], diff --git a/tests/config.json b/tests/config.json index d0e83c90..84fea5bb 100644 --- a/tests/config.json +++ b/tests/config.json @@ -178,16 +178,16 @@ }, "QuestCategories": [ - [0x01, "retrieval", "Retrieval", "$E$C6Quests that involve\nretrieving an object"], - [0x01, "extermination", "Extermination", "$E$C6Quests that involve\ndestroying all\nmonsters"], - [0x01, "events", "Events", "$E$C6Quests that are part\nof an event"], - [0x01, "shops", "Shops", "$E$C6Quests that contain\nshops"], - [0x01, "vr", "Virtual Reality", "$E$C6Quests that are\ndone in a simulator"], + [0x81, "retrieval", "Retrieval", "$E$C6Quests that involve\nretrieving an object"], + [0x81, "extermination", "Extermination", "$E$C6Quests that involve\ndestroying all\nmonsters"], + [0x81, "events", "Events", "$E$C6Quests that are part\nof an event"], + [0x81, "shops", "Shops", "$E$C6Quests that contain\nshops"], + [0x81, "vr", "Virtual Reality", "$E$C6Quests that are\ndone in a simulator"], [0x81, "tower", "Control Tower", "$E$C6Quests that take\nplace at the Control\nTower"], [0x81, "team", "Team", "$E$C6Quests for you\nand your team\nmembers."], [0x02, "battle", "Battle", "$E$C6Battle mode rule\nsets"], [0x04, "challenge-ep1", "Challenge (Episode 1)", "$E$C6Challenge mode\nquests in Episode 1"], - [0x84, "challenge-ep2", "Challenge (Episode 2)", "$E$C6Challenge mode\nquests in Episode 2"], + [0x04, "challenge-ep2", "Challenge (Episode 2)", "$E$C6Challenge mode\nquests in Episode 2"], [0x08, "solo-story", "Story", "$E$C6Quests that follow\nthe Episode 1 story"], [0x08, "solo-extra", "Solo", "$E$C6Quests that require\na single player"], [0x10, "government-ep1", "Hero in Red", "$E$CG-Red Ring Rico-\n$C6Quests that follow\nthe Episode 1\nstoryline"],