rewrite quest category menu system
This commit is contained in:
+1
-1
@@ -18,7 +18,7 @@ constexpr uint32_t INFORMATION = 0x22000022;
|
||||
constexpr uint32_t LOBBY = 0x33000033;
|
||||
constexpr uint32_t GAME = 0x44000044;
|
||||
constexpr uint32_t QUEST = 0x55000055;
|
||||
constexpr uint32_t QUEST_FILTER = 0x66000066;
|
||||
constexpr uint32_t QUEST_CATEGORIES = 0x66000066;
|
||||
constexpr uint32_t PROXY_DESTINATIONS = 0x77000077;
|
||||
constexpr uint32_t PROGRAMS = 0x88000088;
|
||||
constexpr uint32_t PATCHES = 0x99000099;
|
||||
|
||||
+47
-25
@@ -23,29 +23,20 @@ using namespace std;
|
||||
|
||||
QuestCategoryIndex::Category::Category(uint32_t category_id, const JSON& json)
|
||||
: category_id(category_id) {
|
||||
this->flags = json.get_int(0);
|
||||
this->enabled_flags = json.get_int(0);
|
||||
this->directory_name = json.get_string(1);
|
||||
this->name = json.get_string(2);
|
||||
this->description = json.get_string(3);
|
||||
}
|
||||
|
||||
bool QuestCategoryIndex::Category::matches_flags(uint8_t request) const {
|
||||
// If the request is for v1 or v2 (hence it has the HIDE_ON_PRE_V3 flag set)
|
||||
// and the category also has that flag set, it never matches
|
||||
if (request & this->flags & Flag::HIDE_ON_PRE_V3) {
|
||||
return false;
|
||||
}
|
||||
return request & this->flags;
|
||||
}
|
||||
|
||||
QuestCategoryIndex::QuestCategoryIndex(const JSON& json) {
|
||||
uint32_t next_category_id = 1;
|
||||
for (const auto& it : json.as_list()) {
|
||||
this->categories.emplace_back(next_category_id++, *it);
|
||||
this->categories.emplace_back(new Category(next_category_id++, *it));
|
||||
}
|
||||
}
|
||||
|
||||
const QuestCategoryIndex::Category& QuestCategoryIndex::at(uint32_t category_id) const {
|
||||
shared_ptr<const QuestCategoryIndex::Category> QuestCategoryIndex::at(uint32_t category_id) const {
|
||||
return this->categories.at(category_id - 1);
|
||||
}
|
||||
|
||||
@@ -460,12 +451,12 @@ QuestIndex::QuestIndex(
|
||||
for (const auto& cat : this->category_index->categories) {
|
||||
// Don't index Ep3 download categories for non-Ep3 quest indexing, and vice
|
||||
// versa
|
||||
if (is_ep3 == !(cat.flags & QuestCategoryIndex::Category::Flag::EP3_DOWNLOAD)) {
|
||||
if (is_ep3 != cat->check_flag(QuestMenuType::EP3_DOWNLOAD)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto add_file = [&](map<string, shared_ptr<const string>>& files, const string& name, string&& value) {
|
||||
if (categories.emplace(name, cat.category_id).first->second != cat.category_id) {
|
||||
if (categories.emplace(name, cat->category_id).first->second != cat->category_id) {
|
||||
throw runtime_error("file " + name + " exists in multiple categories");
|
||||
}
|
||||
shared_ptr<const string> data_ptr(new string(std::move(value)));
|
||||
@@ -474,7 +465,7 @@ QuestIndex::QuestIndex(
|
||||
}
|
||||
};
|
||||
|
||||
string cat_path = directory + "/" + cat.directory_name;
|
||||
string cat_path = directory + "/" + cat->directory_name;
|
||||
if (!isdir(cat_path)) {
|
||||
static_game_data_log.warning("Quest category directory %s is missing; skipping it", cat_path.c_str());
|
||||
continue;
|
||||
@@ -673,7 +664,7 @@ QuestIndex::QuestIndex(
|
||||
battle_rules,
|
||||
challenge_template_index));
|
||||
|
||||
auto category_name = this->category_index->at(vq->category_id).name;
|
||||
auto category_name = this->category_index->at(vq->category_id)->name;
|
||||
string dat_str = dat_filename.empty() ? "" : (" with layout from " + dat_filename + ".dat");
|
||||
string battle_rules_str = battle_rules ? (" with battle rules from " + json_filename + ".json") : "";
|
||||
string challenge_template_str = (challenge_template_index >= 0) ? string_printf(" with challenge template index %zd", vq->challenge_template_index) : "";
|
||||
@@ -719,16 +710,47 @@ shared_ptr<const Quest> QuestIndex::get(uint32_t quest_number) const {
|
||||
}
|
||||
}
|
||||
|
||||
vector<shared_ptr<const Quest>> QuestIndex::filter(Episode episode, uint32_t category_id, Version version) const {
|
||||
vector<shared_ptr<const Quest>> ret;
|
||||
for (auto it : this->quests_by_number) {
|
||||
if (((episode == Episode::NONE) || (it.second->episode == episode)) &&
|
||||
(it.second->category_id == category_id) &&
|
||||
it.second->has_version_any_language(version)) {
|
||||
ret.emplace_back(it.second);
|
||||
}
|
||||
const vector<shared_ptr<const QuestCategoryIndex::Category>>& QuestIndex::categories(
|
||||
QuestMenuType menu_type, Episode episode, Version version) const {
|
||||
// The episode filter should apply in normal or solo mode
|
||||
if ((menu_type != QuestMenuType::NORMAL) && (menu_type != QuestMenuType::SOLO)) {
|
||||
episode = Episode::NONE;
|
||||
}
|
||||
|
||||
uint64_t key = (static_cast<uint32_t>(menu_type) << 20) | (static_cast<uint32_t>(episode) << 16) | static_cast<uint32_t>(version);
|
||||
try {
|
||||
return this->category_filter_results_cache.at(key);
|
||||
} catch (const out_of_range&) {
|
||||
auto& ret = this->category_filter_results_cache[key];
|
||||
for (const auto& cat : this->category_index->categories) {
|
||||
if (cat->check_flag(menu_type) && !this->filter(menu_type, episode, version, cat->category_id).empty()) {
|
||||
ret.emplace_back(cat);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
const vector<shared_ptr<const Quest>>& QuestIndex::filter(
|
||||
QuestMenuType menu_type, Episode episode, Version version, uint32_t category_id) const {
|
||||
if ((menu_type != QuestMenuType::NORMAL) && (menu_type != QuestMenuType::SOLO)) {
|
||||
episode = Episode::NONE;
|
||||
}
|
||||
|
||||
uint64_t key = (static_cast<uint64_t>(episode) << 48) | (static_cast<uint64_t>(version) << 32) | category_id;
|
||||
try {
|
||||
return this->quest_filter_results_cache.at(key);
|
||||
} catch (const out_of_range&) {
|
||||
vector<shared_ptr<const Quest>>& ret = this->quest_filter_results_cache[key];
|
||||
for (auto it : this->quests_by_number) {
|
||||
if (((episode == Episode::NONE) || (it.second->episode == episode)) &&
|
||||
(it.second->category_id == category_id) &&
|
||||
it.second->has_version_any_language(version)) {
|
||||
ret.emplace_back(it.second);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
string encode_download_quest_data(const string& compressed_data, size_t decompressed_size, uint32_t encryption_seed) {
|
||||
|
||||
+24
-16
@@ -21,35 +21,36 @@ enum class QuestFileFormat {
|
||||
QST,
|
||||
};
|
||||
|
||||
enum class QuestMenuType {
|
||||
NORMAL = 0,
|
||||
BATTLE = 1,
|
||||
CHALLENGE = 2,
|
||||
SOLO = 3,
|
||||
GOVERNMENT = 4,
|
||||
DOWNLOAD = 5,
|
||||
EP3_DOWNLOAD = 6,
|
||||
};
|
||||
|
||||
struct QuestCategoryIndex {
|
||||
struct Category {
|
||||
enum Flag {
|
||||
NORMAL = 0x01,
|
||||
BATTLE = 0x02,
|
||||
CHALLENGE = 0x04,
|
||||
SOLO = 0x08,
|
||||
GOVERNMENT = 0x10,
|
||||
DOWNLOAD = 0x20,
|
||||
EP3_DOWNLOAD = 0x40,
|
||||
HIDE_ON_PRE_V3 = 0x80,
|
||||
};
|
||||
|
||||
uint32_t category_id;
|
||||
uint8_t flags;
|
||||
uint8_t enabled_flags;
|
||||
std::string directory_name;
|
||||
std::string name;
|
||||
std::string description;
|
||||
|
||||
explicit Category(uint32_t category_id, const JSON& json);
|
||||
|
||||
bool matches_flags(uint8_t request) const;
|
||||
[[nodiscard]] inline bool check_flag(QuestMenuType menu_type) const {
|
||||
return this->enabled_flags & (1 << static_cast<uint8_t>(menu_type));
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<Category> categories;
|
||||
std::vector<std::shared_ptr<Category>> categories;
|
||||
|
||||
explicit QuestCategoryIndex(const JSON& json);
|
||||
|
||||
const Category& at(uint32_t category_id) const;
|
||||
std::shared_ptr<const Category> at(uint32_t category_id) const;
|
||||
};
|
||||
|
||||
struct VersionedQuest {
|
||||
@@ -120,10 +121,17 @@ struct QuestIndex {
|
||||
|
||||
std::map<uint32_t, std::shared_ptr<Quest>> quests_by_number;
|
||||
|
||||
mutable std::unordered_map<uint32_t, std::vector<std::shared_ptr<const QuestCategoryIndex::Category>>> category_filter_results_cache;
|
||||
mutable std::unordered_map<uint64_t, std::vector<std::shared_ptr<const Quest>>> quest_filter_results_cache;
|
||||
|
||||
QuestIndex(const std::string& directory, std::shared_ptr<const QuestCategoryIndex> category_index, bool is_ep3);
|
||||
|
||||
std::shared_ptr<const Quest> get(uint32_t quest_number) const;
|
||||
std::vector<std::shared_ptr<const Quest>> filter(Episode episode, uint32_t category_id, Version version) const;
|
||||
|
||||
const std::vector<std::shared_ptr<const QuestCategoryIndex::Category>>& categories(
|
||||
QuestMenuType menu_type, Episode episode, Version version) const;
|
||||
const std::vector<std::shared_ptr<const Quest>>& filter(
|
||||
QuestMenuType menu_type, Episode episode, Version version, uint32_t category_id) const;
|
||||
};
|
||||
|
||||
std::string encode_download_quest_data(
|
||||
|
||||
+50
-45
@@ -1653,7 +1653,7 @@ static void on_09(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
auto s = c->require_server_state();
|
||||
|
||||
switch (cmd.menu_id) {
|
||||
case MenuID::QUEST_FILTER:
|
||||
case MenuID::QUEST_CATEGORIES:
|
||||
// Don't send anything here. The quest filter menu already has short
|
||||
// descriptions included with the entries, which the client shows in the
|
||||
// usual location on the screen.
|
||||
@@ -2043,40 +2043,23 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
|
||||
case MainMenuItemID::DOWNLOAD_QUESTS: {
|
||||
auto s = c->require_server_state();
|
||||
QuestMenuType menu_type = QuestMenuType::DOWNLOAD;
|
||||
if (is_ep3(c->version())) {
|
||||
menu_type = QuestMenuType::EP3_DOWNLOAD;
|
||||
// Episode 3 has only download quests, not online quests, so this is
|
||||
// always the download quest menu. (Episode 3 does actually have
|
||||
// online quests, but they're served via a server data request
|
||||
// instead of the file download paradigm that other versions use.)
|
||||
uint32_t ep3_category_id = 0;
|
||||
size_t num_ep3_categories = 0;
|
||||
for (const auto& category : s->quest_category_index->categories) {
|
||||
if (category.flags & QuestCategoryIndex::Category::Flag::EP3_DOWNLOAD) {
|
||||
ep3_category_id = category.category_id;
|
||||
num_ep3_categories++;
|
||||
}
|
||||
}
|
||||
if (num_ep3_categories == 1) {
|
||||
auto quest_index = s->quest_index_for_client(c);
|
||||
if (quest_index) {
|
||||
auto quests = quest_index->filter(Episode::EP3, ep3_category_id, c->version());
|
||||
send_quest_menu(c, MenuID::QUEST, quests, true);
|
||||
} else {
|
||||
send_lobby_message_box(c, "$C6Quests are not available.");
|
||||
}
|
||||
auto quest_index = s->quest_index_for_client(c);
|
||||
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);
|
||||
send_quest_menu(c, MenuID::QUEST, quests, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Not Episode 3, or there are multiple Episode 3 download categories;
|
||||
// send the categories menu instead
|
||||
uint8_t flags = is_ep3(c->version())
|
||||
? QuestCategoryIndex::Category::Flag::EP3_DOWNLOAD
|
||||
: QuestCategoryIndex::Category::Flag::DOWNLOAD;
|
||||
if (is_v1_or_v2(c->version())) {
|
||||
flags |= QuestCategoryIndex::Category::Flag::HIDE_ON_PRE_V3;
|
||||
}
|
||||
send_quest_menu(c, MenuID::QUEST_FILTER, s->quest_category_index, flags);
|
||||
send_quest_categories_menu(c, MenuID::QUEST_CATEGORIES, s->quest_index_for_client(c), menu_type, Episode::NONE);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2304,20 +2287,38 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
break;
|
||||
}
|
||||
|
||||
case MenuID::QUEST_FILTER: {
|
||||
case MenuID::QUEST_CATEGORIES: {
|
||||
auto s = c->require_server_state();
|
||||
auto quest_index = s->quest_index_for_client(c);
|
||||
if (!quest_index) {
|
||||
send_lobby_message_box(c, "$C6Quests are not available.");
|
||||
break;
|
||||
}
|
||||
const auto& category = s->quest_category_index->at(item_id);
|
||||
shared_ptr<Lobby> l = c->lobby.lock();
|
||||
bool filter_by_episode = l && !(category.flags & QuestCategoryIndex::Category::Flag::GOVERNMENT);
|
||||
auto quests = quest_index->filter(filter_by_episode ? l->episode : Episode::NONE, item_id, c->version());
|
||||
|
||||
// Hack: Assume the menu to be sent is the download quest menu if the
|
||||
// client is not in any lobby
|
||||
shared_ptr<Lobby> l = c->lobby.lock();
|
||||
Episode episode = l ? l->episode : Episode::NONE;
|
||||
QuestMenuType menu_type = QuestMenuType::NORMAL;
|
||||
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<QuestMenuType, 4> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto& quests = quest_index->filter(menu_type, episode, c->version(), item_id);
|
||||
send_quest_menu(c, MenuID::QUEST, quests, !l);
|
||||
break;
|
||||
}
|
||||
@@ -2647,34 +2648,29 @@ static void on_A2(shared_ptr<Client> c, uint16_t, uint32_t flag, string& data) {
|
||||
// filter menu.
|
||||
if (is_ep3(c->version())) {
|
||||
send_lobby_message_box(c, "$C6Episode 3 does not\nprovide online quests\nvia this interface.");
|
||||
|
||||
} else {
|
||||
uint8_t flags = is_v1_or_v2(c->version())
|
||||
? QuestCategoryIndex::Category::Flag::HIDE_ON_PRE_V3
|
||||
: 0;
|
||||
|
||||
QuestMenuType menu_type;
|
||||
if ((c->version() == Version::BB_V4) && flag) {
|
||||
flags |= QuestCategoryIndex::Category::Flag::GOVERNMENT;
|
||||
menu_type = QuestMenuType::GOVERNMENT;
|
||||
} else {
|
||||
switch (l->mode) {
|
||||
case GameMode::NORMAL:
|
||||
flags |= QuestCategoryIndex::Category::Flag::NORMAL;
|
||||
menu_type = QuestMenuType::NORMAL;
|
||||
break;
|
||||
case GameMode::BATTLE:
|
||||
flags |= QuestCategoryIndex::Category::Flag::BATTLE;
|
||||
menu_type = QuestMenuType::BATTLE;
|
||||
break;
|
||||
case GameMode::CHALLENGE:
|
||||
flags |= QuestCategoryIndex::Category::Flag::CHALLENGE;
|
||||
menu_type = QuestMenuType::CHALLENGE;
|
||||
break;
|
||||
case GameMode::SOLO:
|
||||
flags |= QuestCategoryIndex::Category::Flag::SOLO;
|
||||
menu_type = QuestMenuType::SOLO;
|
||||
break;
|
||||
default:
|
||||
throw logic_error("invalid game mode");
|
||||
}
|
||||
}
|
||||
|
||||
send_quest_menu(c, MenuID::QUEST_FILTER, s->quest_category_index, flags);
|
||||
send_quest_categories_menu(c, MenuID::QUEST_CATEGORIES, s->quest_index_for_client(c), menu_type, l->episode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4000,6 +3996,15 @@ static void on_C1_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
break;
|
||||
case 3:
|
||||
episode = Episode::EP4;
|
||||
// Disallow battle/challenge in Ep4
|
||||
if (mode == GameMode::BATTLE) {
|
||||
send_lobby_message_box(c, "$C6Episode 4 does not\nsupport Battle Mode.");
|
||||
return;
|
||||
}
|
||||
if (mode == GameMode::CHALLENGE) {
|
||||
send_lobby_message_box(c, "$C6Episode 4 does not\nsupport Challenge Mode.");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("invalid episode number");
|
||||
|
||||
+16
-17
@@ -1394,23 +1394,22 @@ void send_quest_menu_t(
|
||||
}
|
||||
|
||||
template <typename EntryT>
|
||||
void send_quest_menu_t(
|
||||
void send_quest_categories_menu_t(
|
||||
shared_ptr<Client> c,
|
||||
uint32_t menu_id,
|
||||
shared_ptr<const QuestCategoryIndex> category_index,
|
||||
uint8_t flags) {
|
||||
bool is_download_menu = flags & (QuestCategoryIndex::Category::Flag::DOWNLOAD | QuestCategoryIndex::Category::Flag::EP3_DOWNLOAD);
|
||||
shared_ptr<const QuestIndex> quest_index,
|
||||
QuestMenuType menu_type,
|
||||
Episode episode) {
|
||||
vector<EntryT> entries;
|
||||
for (const auto& category : category_index->categories) {
|
||||
if (!category.matches_flags(flags)) {
|
||||
continue;
|
||||
}
|
||||
for (const auto& cat : quest_index->categories(menu_type, episode, c->version())) {
|
||||
auto& e = entries.emplace_back();
|
||||
e.menu_id = menu_id;
|
||||
e.item_id = category.category_id;
|
||||
e.name.encode(category.name, c->language());
|
||||
e.short_description.encode(add_color(category.description), c->language());
|
||||
e.item_id = cat->category_id;
|
||||
e.name.encode(cat->name, c->language());
|
||||
e.short_description.encode(add_color(cat->description), c->language());
|
||||
}
|
||||
|
||||
bool is_download_menu = (menu_type == QuestMenuType::DOWNLOAD) || (menu_type == QuestMenuType::EP3_DOWNLOAD);
|
||||
send_command_vt(c, is_download_menu ? 0xA4 : 0xA2, entries.size(), entries);
|
||||
}
|
||||
|
||||
@@ -1441,11 +1440,11 @@ void send_quest_menu(shared_ptr<Client> c, uint32_t menu_id,
|
||||
}
|
||||
}
|
||||
|
||||
void send_quest_menu(shared_ptr<Client> c, uint32_t menu_id,
|
||||
shared_ptr<const QuestCategoryIndex> category_index, uint8_t flags) {
|
||||
void send_quest_categories_menu(shared_ptr<Client> c, uint32_t menu_id,
|
||||
shared_ptr<const QuestIndex> quest_index, QuestMenuType menu_type, Episode episode) {
|
||||
switch (c->version()) {
|
||||
case Version::PC_V2:
|
||||
send_quest_menu_t<S_QuestMenuEntry_PC_A2_A4>(c, menu_id, category_index, flags);
|
||||
send_quest_categories_menu_t<S_QuestMenuEntry_PC_A2_A4>(c, menu_id, quest_index, menu_type, episode);
|
||||
break;
|
||||
case Version::DC_NTE:
|
||||
case Version::DC_V1_12_2000_PROTOTYPE:
|
||||
@@ -1455,13 +1454,13 @@ void send_quest_menu(shared_ptr<Client> c, uint32_t menu_id,
|
||||
case Version::GC_V3:
|
||||
case Version::GC_EP3_TRIAL_EDITION:
|
||||
case Version::GC_EP3:
|
||||
send_quest_menu_t<S_QuestMenuEntry_DC_GC_A2_A4>(c, menu_id, category_index, flags);
|
||||
send_quest_categories_menu_t<S_QuestMenuEntry_DC_GC_A2_A4>(c, menu_id, quest_index, menu_type, episode);
|
||||
break;
|
||||
case Version::XB_V3:
|
||||
send_quest_menu_t<S_QuestMenuEntry_XB_A2_A4>(c, menu_id, category_index, flags);
|
||||
send_quest_categories_menu_t<S_QuestMenuEntry_XB_A2_A4>(c, menu_id, quest_index, menu_type, episode);
|
||||
break;
|
||||
case Version::BB_V4:
|
||||
send_quest_menu_t<S_QuestMenuEntry_BB_A2_A4>(c, menu_id, category_index, flags);
|
||||
send_quest_categories_menu_t<S_QuestMenuEntry_BB_A2_A4>(c, menu_id, quest_index, menu_type, episode);
|
||||
break;
|
||||
default:
|
||||
throw logic_error("unimplemented versioned command");
|
||||
|
||||
+11
-4
@@ -253,10 +253,17 @@ void send_game_menu(
|
||||
std::shared_ptr<Client> c,
|
||||
bool is_spectator_team_list,
|
||||
bool is_tournament_game_list);
|
||||
void send_quest_menu(std::shared_ptr<Client> c, uint32_t menu_id,
|
||||
const std::vector<std::shared_ptr<const Quest>>& quests, bool is_download_menu);
|
||||
void send_quest_menu(std::shared_ptr<Client> c, uint32_t menu_id,
|
||||
std::shared_ptr<const QuestCategoryIndex> category_index, uint8_t flags);
|
||||
void send_quest_menu(
|
||||
std::shared_ptr<Client> c,
|
||||
uint32_t menu_id,
|
||||
const std::vector<std::shared_ptr<const Quest>>& quests,
|
||||
bool is_download_menu);
|
||||
void send_quest_categories_menu(
|
||||
std::shared_ptr<Client> c,
|
||||
uint32_t menu_id,
|
||||
std::shared_ptr<const QuestIndex> quest_index,
|
||||
QuestMenuType menu_type,
|
||||
Episode episode);
|
||||
void send_lobby_list(std::shared_ptr<Client> c);
|
||||
|
||||
void send_player_records(std::shared_ptr<Client> c, std::shared_ptr<Lobby> l, std::shared_ptr<Client> joining_client = nullptr);
|
||||
|
||||
@@ -482,7 +482,6 @@
|
||||
// 0x10 - appears at government counter (BB)
|
||||
// 0x20 - appears in download quest menu
|
||||
// 0x40 - appears in Episode 3 download quest menu
|
||||
// 0x80 - hidden on pre-V3 versions (DC, PC)
|
||||
// directory_name: the directory inside system/quests that contains quests
|
||||
// for this category.
|
||||
// category_name: what appears in the quest menu on the client.
|
||||
@@ -493,8 +492,8 @@
|
||||
[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, "tower", "Control Tower", "$E$C6Quests that take\nplace at the Control\nTower"],
|
||||
[0x81, "team", "Team", "$E$C6Quests for you\nand your team\nmembers."],
|
||||
[0x01, "tower", "Control Tower", "$E$C6Quests that take\nplace at the Control\nTower"],
|
||||
[0x01, "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"],
|
||||
|
||||
Reference in New Issue
Block a user