set up download quest menus
This commit is contained in:
+21
-9
@@ -498,11 +498,6 @@ void IPStackSimulator::on_client_tcp_frame(
|
|||||||
throw runtime_error("TCP SYN contains extra flags");
|
throw runtime_error("TCP SYN contains extra flags");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t key = this->tcp_conn_key_for_client_frame(fi);
|
|
||||||
if (c->tcp_connections.count(key)) {
|
|
||||||
throw runtime_error("TCP SYN received for already-open connection");
|
|
||||||
}
|
|
||||||
|
|
||||||
StringReader options_r(fi.tcp + 1, fi.tcp_options_size);
|
StringReader options_r(fi.tcp + 1, fi.tcp_options_size);
|
||||||
size_t max_frame_size = 1400;
|
size_t max_frame_size = 1400;
|
||||||
while (!options_r.eof()) {
|
while (!options_r.eof()) {
|
||||||
@@ -545,8 +540,14 @@ void IPStackSimulator::on_client_tcp_frame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the IPStackSimulator end of the virtual connection
|
|
||||||
auto& conn = c->tcp_connections.emplace(key, IPClient::TCPConnection()).first->second;
|
uint64_t key = this->tcp_conn_key_for_client_frame(fi);
|
||||||
|
auto emplace_ret = c->tcp_connections.emplace(key, IPClient::TCPConnection());
|
||||||
|
auto& conn = emplace_ret.first->second;
|
||||||
|
string conn_str = this->state->ip_stack_debug ? this->str_for_tcp_connection(c, conn) : "";
|
||||||
|
|
||||||
|
if (emplace_ret.second) {
|
||||||
|
// Connection is new; initialize it
|
||||||
conn.client = c;
|
conn.client = c;
|
||||||
conn.resend_push_event.reset(event_new(this->base.get(), -1, EV_TIMEOUT,
|
conn.resend_push_event.reset(event_new(this->base.get(), -1, EV_TIMEOUT,
|
||||||
&IPStackSimulator::dispatch_on_resend_push, &conn));
|
&IPStackSimulator::dispatch_on_resend_push, &conn));
|
||||||
@@ -558,13 +559,24 @@ void IPStackSimulator::on_client_tcp_frame(
|
|||||||
conn.resend_push_usecs = DEFAULT_RESEND_PUSH_USECS;
|
conn.resend_push_usecs = DEFAULT_RESEND_PUSH_USECS;
|
||||||
conn.awaiting_first_ack = true;
|
conn.awaiting_first_ack = true;
|
||||||
conn.max_frame_size = max_frame_size;
|
conn.max_frame_size = max_frame_size;
|
||||||
|
|
||||||
string conn_str = this->state->ip_stack_debug ? this->str_for_tcp_connection(c, conn) : "";
|
|
||||||
if (this->state->ip_stack_debug) {
|
if (this->state->ip_stack_debug) {
|
||||||
log(INFO, "[IPStackSimulator] Client opened TCP connection %s (acked_server_seq=%08" PRIX32 ", next_client_seq=%08" PRIX32 ")",
|
log(INFO, "[IPStackSimulator] Client opened TCP connection %s (acked_server_seq=%08" PRIX32 ", next_client_seq=%08" PRIX32 ")",
|
||||||
conn_str.c_str(), conn.acked_server_seq, conn.next_client_seq);
|
conn_str.c_str(), conn.acked_server_seq, conn.next_client_seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Connection is NOT new; this is probably a resend of an earlier SYN
|
||||||
|
if (!conn.awaiting_first_ack) {
|
||||||
|
throw logic_error("SYN received on already-open connection after initial phase");
|
||||||
|
}
|
||||||
|
// TODO: We should check the syn/ack numbers here instead of just assuming
|
||||||
|
// they're correct
|
||||||
|
if (this->state->ip_stack_debug) {
|
||||||
|
log(INFO, "[IPStackSimulator] Client resent SYN for TCP connection %s",
|
||||||
|
conn_str.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Send a SYN+ACK (send_tcp_frame always adds the ACK flag)
|
// Send a SYN+ACK (send_tcp_frame always adds the ACK flag)
|
||||||
this->send_tcp_frame(c, conn, TCPHeader::Flag::SYN);
|
this->send_tcp_frame(c, conn, TCPHeader::Flag::SYN);
|
||||||
if (this->state->ip_stack_debug) {
|
if (this->state->ip_stack_debug) {
|
||||||
|
|||||||
+9
-19
@@ -442,7 +442,7 @@ shared_ptr<const string> QuestIndex::get_gba(const string& name) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vector<shared_ptr<const Quest>> QuestIndex::filter(GameVersion version,
|
vector<shared_ptr<const Quest>> QuestIndex::filter(GameVersion version,
|
||||||
bool is_dcv1, QuestCategory category, uint8_t episode) const {
|
bool is_dcv1, QuestCategory category, int16_t episode) const {
|
||||||
auto it = this->version_id_to_quest.lower_bound(make_pair(version, 0));
|
auto it = this->version_id_to_quest.lower_bound(make_pair(version, 0));
|
||||||
auto end_it = this->version_id_to_quest.upper_bound(make_pair(version, 0xFFFFFFFF));
|
auto end_it = this->version_id_to_quest.upper_bound(make_pair(version, 0xFFFFFFFF));
|
||||||
|
|
||||||
@@ -453,9 +453,10 @@ vector<shared_ptr<const Quest>> QuestIndex::filter(GameVersion version,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only check episode and solo if the category isn't a mode (that is, ignore
|
// Only check episode and solo if the category isn't a mode (that is, ignore
|
||||||
// episode if querying for battle/challange/solo quests)
|
// episode if querying for battle/challenge/solo quests). Also, ignore
|
||||||
if (!category_is_mode(category) && ((q->episode != episode))) {
|
// ignore episode if it's < 0 (e.g. for the download quest menu).
|
||||||
|
if ((episode >= 0) && !category_is_mode(category) && ((q->episode != episode))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,7 +486,7 @@ static string create_download_quest_file(const string& compressed_data,
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<Quest> Quest::create_download_quest(const string& file_basename) const {
|
shared_ptr<Quest> Quest::create_download_quest() const {
|
||||||
if (this->category == QuestCategory::Download) {
|
if (this->category == QuestCategory::Download) {
|
||||||
throw invalid_argument("quest is already a download quest");
|
throw invalid_argument("quest is already a download quest");
|
||||||
}
|
}
|
||||||
@@ -497,10 +498,10 @@ shared_ptr<Quest> Quest::create_download_quest(const string& file_basename) cons
|
|||||||
reinterpret_cast<PSOQuestHeaderDC*>(data_ptr)->is_download = 0x01;
|
reinterpret_cast<PSOQuestHeaderDC*>(data_ptr)->is_download = 0x01;
|
||||||
break;
|
break;
|
||||||
case GameVersion::PC:
|
case GameVersion::PC:
|
||||||
reinterpret_cast<PSOQuestHeaderDC*>(data_ptr)->is_download = 0x01;
|
reinterpret_cast<PSOQuestHeaderPC*>(data_ptr)->is_download = 0x01;
|
||||||
break;
|
break;
|
||||||
case GameVersion::GC:
|
case GameVersion::GC:
|
||||||
reinterpret_cast<PSOQuestHeaderDC*>(data_ptr)->is_download = 0x01;
|
reinterpret_cast<PSOQuestHeaderGC*>(data_ptr)->is_download = 0x01;
|
||||||
break;
|
break;
|
||||||
case GameVersion::BB:
|
case GameVersion::BB:
|
||||||
throw invalid_argument("PSOBB does not support download quests");
|
throw invalid_argument("PSOBB does not support download quests");
|
||||||
@@ -508,16 +509,8 @@ shared_ptr<Quest> Quest::create_download_quest(const string& file_basename) cons
|
|||||||
throw invalid_argument("unknown game version");
|
throw invalid_argument("unknown game version");
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<Quest> dlq(new Quest(file_basename));
|
shared_ptr<Quest> dlq(new Quest(*this));
|
||||||
dlq->quest_id = this->quest_id;
|
|
||||||
dlq->category = QuestCategory::Download;
|
dlq->category = QuestCategory::Download;
|
||||||
dlq->episode = this->episode;
|
|
||||||
dlq->is_dcv1 = this->is_dcv1;
|
|
||||||
dlq->joinable = this->joinable;
|
|
||||||
dlq->version = this->version;
|
|
||||||
dlq->name = this->name;
|
|
||||||
dlq->short_description = this->short_description;
|
|
||||||
dlq->long_description = this->long_description;
|
|
||||||
|
|
||||||
dlq->bin_contents_ptr.reset(new string(create_download_quest_file(
|
dlq->bin_contents_ptr.reset(new string(create_download_quest_file(
|
||||||
prs_compress(decompressed_bin), decompressed_bin.size())));
|
prs_compress(decompressed_bin), decompressed_bin.size())));
|
||||||
@@ -526,8 +519,5 @@ shared_ptr<Quest> Quest::create_download_quest(const string& file_basename) cons
|
|||||||
dlq->dat_contents_ptr.reset(new string(create_download_quest_file(
|
dlq->dat_contents_ptr.reset(new string(create_download_quest_file(
|
||||||
*dat_contents, prs_decompress_size(*dat_contents))));
|
*dat_contents, prs_decompress_size(*dat_contents))));
|
||||||
|
|
||||||
save_file(dlq->bin_filename(), *dlq->bin_contents_ptr);
|
|
||||||
save_file(dlq->dat_filename(), *dlq->dat_contents_ptr);
|
|
||||||
|
|
||||||
return dlq;
|
return dlq;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -56,6 +56,10 @@ public:
|
|||||||
mutable std::shared_ptr<std::string> dat_contents_ptr;
|
mutable std::shared_ptr<std::string> dat_contents_ptr;
|
||||||
|
|
||||||
Quest(const std::string& file_basename);
|
Quest(const std::string& file_basename);
|
||||||
|
Quest(const Quest&) = default;
|
||||||
|
Quest(Quest&&) = default;
|
||||||
|
Quest& operator=(const Quest&) = default;
|
||||||
|
Quest& operator=(Quest&&) = default;
|
||||||
|
|
||||||
std::string bin_filename() const;
|
std::string bin_filename() const;
|
||||||
std::string dat_filename() const;
|
std::string dat_filename() const;
|
||||||
@@ -63,8 +67,7 @@ public:
|
|||||||
std::shared_ptr<const std::string> bin_contents() const;
|
std::shared_ptr<const std::string> bin_contents() const;
|
||||||
std::shared_ptr<const std::string> dat_contents() const;
|
std::shared_ptr<const std::string> dat_contents() const;
|
||||||
|
|
||||||
std::shared_ptr<Quest> create_download_quest(
|
std::shared_ptr<Quest> create_download_quest() const;
|
||||||
const std::string& file_basename) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QuestIndex {
|
struct QuestIndex {
|
||||||
@@ -82,7 +85,5 @@ struct QuestIndex {
|
|||||||
std::shared_ptr<const Quest> get(GameVersion version, uint32_t id) const;
|
std::shared_ptr<const Quest> get(GameVersion version, uint32_t id) const;
|
||||||
std::shared_ptr<const std::string> get_gba(const std::string& name) const;
|
std::shared_ptr<const std::string> get_gba(const std::string& name) const;
|
||||||
std::vector<std::shared_ptr<const Quest>> filter(GameVersion version,
|
std::vector<std::shared_ptr<const Quest>> filter(GameVersion version,
|
||||||
bool is_dcv1, QuestCategory category, uint8_t episode) const;
|
bool is_dcv1, QuestCategory category, int16_t episode) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
Quest create_download_quest(const Quest& src, size_t version);
|
|
||||||
|
|||||||
+63
-47
@@ -38,6 +38,45 @@ enum ClientStateBB {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vector<MenuItem> quest_categories_menu({
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Retrieval), u"Retrieval", u"$E$C6Quests that involve\nretrieving an object", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Extermination), u"Extermination", u"$E$C6Quests that involve\ndestroying all\nmonsters", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Event), u"Events", u"$E$C6Quests that are part\nof an event", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Shop), u"Shops", u"$E$C6Quests that contain\nshops", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::VR), u"Virtual Reality", u"$E$C6Quests that are\ndone in a simulator", MenuItemFlag::InvisibleOnDC | MenuItemFlag::InvisibleOnPC),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Tower), u"Control Tower", u"$E$C6Quests that take\nplace at the Control\nTower", MenuItemFlag::InvisibleOnDC | MenuItemFlag::InvisibleOnPC),
|
||||||
|
});
|
||||||
|
|
||||||
|
vector<MenuItem> quest_battle_menu({
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Battle), u"Battle", u"$E$C6Battle mode rule\nsets", 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
vector<MenuItem> quest_challenge_menu({
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Challenge), u"Challenge", u"$E$C6Challenge mode\nquests", 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
vector<MenuItem> quest_solo_menu({
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Solo), u"Solo Quests", u"$E$C6Quests that require\na single player", 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
vector<MenuItem> quest_government_menu({
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::GovernmentEpisode1), u"Hero in Red",u"$E$CG-Red Ring Rico-\n$C6Quests that follow\nthe Episode 1\nstoryline", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::GovernmentEpisode2), u"The Military's Hero",u"$E$CG-Heathcliff Flowen-\n$C6Quests that follow\nthe Episode 2\nstoryline", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::GovernmentEpisode4), u"The Meteor Impact Incident", u"$E$C6Quests that follow\nthe Episode 4\nstoryline", 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
vector<MenuItem> quest_download_menu({
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Retrieval), u"Retrieval", u"$E$C6Quests that involve\nretrieving an object", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Extermination), u"Extermination", u"$E$C6Quests that involve\ndestroying all\nmonsters", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Event), u"Events", u"$E$C6Quests that are part\nof an event", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Shop), u"Shops", u"$E$C6Quests that contain\nshops", 0),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::VR), u"Virtual Reality", u"$E$C6Quests that are\ndone in a simulator", MenuItemFlag::InvisibleOnDC | MenuItemFlag::InvisibleOnPC),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Tower), u"Control Tower", u"$E$C6Quests that take\nplace at the Control\nTower", MenuItemFlag::InvisibleOnDC | MenuItemFlag::InvisibleOnPC),
|
||||||
|
MenuItem(static_cast<uint32_t>(QuestCategory::Download), u"Download", u"$E$C6Quests to download\nto your Memory Card", 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void process_connect(std::shared_ptr<ServerState> s, std::shared_ptr<Client> c) {
|
void process_connect(std::shared_ptr<ServerState> s, std::shared_ptr<Client> c) {
|
||||||
@@ -636,6 +675,10 @@ void process_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
c->flags |= ClientFlag::InInformationMenu;
|
c->flags |= ClientFlag::InInformationMenu;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MAIN_MENU_DOWNLOAD_QUESTS:
|
||||||
|
send_quest_menu(c, QUEST_FILTER_MENU_ID, quest_download_menu, true);
|
||||||
|
break;
|
||||||
|
|
||||||
case MAIN_MENU_DISCONNECT:
|
case MAIN_MENU_DISCONNECT:
|
||||||
c->should_disconnect = true;
|
c->should_disconnect = true;
|
||||||
break;
|
break;
|
||||||
@@ -731,16 +774,19 @@ void process_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
send_lobby_message_box(c, u"$C6Quests are not available.");
|
send_lobby_message_box(c, u"$C6Quests are not available.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto l = s->find_lobby(c->lobby_id);
|
shared_ptr<Lobby> l = c->lobby_id ? s->find_lobby(c->lobby_id) : nullptr;
|
||||||
auto quests = s->quest_index->filter(c->version,
|
auto quests = s->quest_index->filter(c->version,
|
||||||
c->flags & ClientFlag::IsDCv1,
|
c->flags & ClientFlag::IsDCv1,
|
||||||
static_cast<QuestCategory>(cmd->item_id & 0xFF), l->episode - 1);
|
static_cast<QuestCategory>(cmd->item_id & 0xFF),
|
||||||
|
l.get() ? (l->episode - 1) : -1);
|
||||||
if (quests.empty()) {
|
if (quests.empty()) {
|
||||||
send_lobby_message_box(c, u"$C6There are no quests\navailable in that\ncategory.");
|
send_lobby_message_box(c, u"$C6There are no quests\navailable in that\ncategory.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
send_quest_menu(c, QUEST_MENU_ID, quests, false);
|
// Hack: assume the menu to be sent is the download quest menu if the
|
||||||
|
// client is not in any lobby
|
||||||
|
send_quest_menu(c, QUEST_MENU_ID, quests, !c->lobby_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,17 +801,23 @@ void process_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the client is not in a lobby, send the quest as a download quest.
|
||||||
|
// Otherwise, they must be in a game to load a quest.
|
||||||
|
shared_ptr<Lobby> l;
|
||||||
|
if (c->lobby_id) {
|
||||||
auto l = s->find_lobby(c->lobby_id);
|
auto l = s->find_lobby(c->lobby_id);
|
||||||
if (!l->is_game()) {
|
if (!l->is_game()) {
|
||||||
send_lobby_message_box(c, u"$C6Quests cannot be loaded\nin lobbies.");
|
send_lobby_message_box(c, u"$C6Quests cannot be loaded\nin lobbies.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto bin_basename = q->bin_filename();
|
auto bin_basename = q->bin_filename();
|
||||||
auto dat_basename = q->dat_filename();
|
auto dat_basename = q->dat_filename();
|
||||||
auto bin_contents = q->bin_contents();
|
auto bin_contents = q->bin_contents();
|
||||||
auto dat_contents = q->dat_contents();
|
auto dat_contents = q->dat_contents();
|
||||||
|
|
||||||
|
if (l) {
|
||||||
if (q->joinable) {
|
if (q->joinable) {
|
||||||
l->flags |= LobbyFlag::JoinableQuestInProgress;
|
l->flags |= LobbyFlag::JoinableQuestInProgress;
|
||||||
} else {
|
} else {
|
||||||
@@ -786,6 +838,13 @@ void process_menu_selection(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
|
|
||||||
l->clients[x]->flags |= ClientFlag::Loading;
|
l->clients[x]->flags |= ClientFlag::Loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// TODO: cache dlq somewhere maybe
|
||||||
|
auto dlq = q->create_download_quest();
|
||||||
|
send_quest_file(c, bin_basename, *bin_contents, true, false);
|
||||||
|
send_quest_file(c, dat_basename, *dat_contents, true, false);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,43 +910,6 @@ void process_change_block(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Quest commands
|
// Quest commands
|
||||||
|
|
||||||
vector<MenuItem> quest_categories_menu({
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Retrieval), u"Retrieval", u"$E$C6Quests that involve\nretrieving an object", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Extermination), u"Extermination", u"$E$C6Quests that involve\ndestroying all\nmonsters", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Event), u"Events", u"$E$C6Quests that are part\nof an event", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Shop), u"Shops", u"$E$C6Quests that contain\nshops", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::VR), u"Virtual Reality", u"$E$C6Quests that are\ndone in a simulator", MenuItemFlag::InvisibleOnDC | MenuItemFlag::InvisibleOnPC),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Tower), u"Control Tower", u"$E$C6Quests that take\nplace at the Control\nTower", MenuItemFlag::InvisibleOnDC | MenuItemFlag::InvisibleOnPC),
|
|
||||||
});
|
|
||||||
|
|
||||||
vector<MenuItem> quest_battle_menu({
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Battle), u"Battle", u"$E$C6Battle mode rule\nsets", 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
vector<MenuItem> quest_challenge_menu({
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Challenge), u"Challenge", u"$E$C6Challenge mode\nquests", 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
vector<MenuItem> quest_solo_menu({
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Solo), u"Solo Quests", u"$E$C6Quests that require\na single player", 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
vector<MenuItem> quest_government_menu({
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::GovernmentEpisode1), u"Hero in Red",u"$E$CG-Red Ring Rico-\n$C6Quests that follow\nthe Episode 1\nstoryline", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::GovernmentEpisode2), u"The Military's Hero",u"$E$CG-Heathcliff Flowen-\n$C6Quests that follow\nthe Episode 2\nstoryline", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::GovernmentEpisode4), u"The Meteor Impact Incident", u"$E$C6Quests that follow\nthe Episode 4\nstoryline", 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
vector<MenuItem> quest_download_menu({
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Retrieval), u"Retrieval", u"$E$C6Quests that involve\nretrieving an object", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Extermination), u"Extermination", u"$E$C6Quests that involve\ndestroying all\nmonsters", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Event), u"Events", u"$E$C6Quests that are part\nof an event", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Shop), u"Shops", u"$E$C6Quests that contain\nshops", 0),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::VR), u"Virtual Reality", u"$E$C6Quests that are\ndone in a simulator", MenuItemFlag::InvisibleOnDC | MenuItemFlag::InvisibleOnPC),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Tower), u"Control Tower", u"$E$C6Quests that take\nplace at the Control\nTower", MenuItemFlag::InvisibleOnDC | MenuItemFlag::InvisibleOnPC),
|
|
||||||
MenuItem(static_cast<uint32_t>(QuestCategory::Download), u"Download", u"$E$C6Quests to download\nto your Memory Card", 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
void process_quest_list_request(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
void process_quest_list_request(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||||
uint16_t, uint32_t flag, uint16_t size, const void*) { // A2
|
uint16_t, uint32_t flag, uint16_t size, const void*) { // A2
|
||||||
check_size(size, 0);
|
check_size(size, 0);
|
||||||
@@ -964,12 +986,6 @@ void process_gba_file_request(shared_ptr<ServerState>, shared_ptr<Client> c,
|
|||||||
send_quest_file(c, filename, *contents, false, false);
|
send_quest_file(c, filename, *contents, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_start_download_quest(shared_ptr<ServerState>, shared_ptr<Client> c,
|
|
||||||
uint16_t, uint32_t, uint16_t, const void*) { // A6
|
|
||||||
// TODO implement this
|
|
||||||
send_text_message(c, u"$C6Download quests\nare not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -1994,7 +2010,7 @@ static process_command_t gc_handlers[0x100] = {
|
|||||||
|
|
||||||
// A0
|
// A0
|
||||||
process_change_ship, process_change_block, process_quest_list_request, nullptr,
|
process_change_ship, process_change_block, process_quest_list_request, nullptr,
|
||||||
nullptr, nullptr, process_start_download_quest, process_ignored_command,
|
nullptr, nullptr, process_ignored_command, process_ignored_command,
|
||||||
nullptr, process_ignored_command, nullptr, nullptr,
|
nullptr, process_ignored_command, nullptr, nullptr,
|
||||||
process_quest_ready, nullptr, nullptr, nullptr,
|
process_quest_ready, nullptr, nullptr, nullptr,
|
||||||
|
|
||||||
|
|||||||
+8
-7
@@ -16,16 +16,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MAIN_MENU_ID 0x512CBD43
|
#define MAIN_MENU_ID 0x60000000
|
||||||
#define INFORMATION_MENU_ID 0x93320CAA
|
#define INFORMATION_MENU_ID 0x60000030
|
||||||
#define LOBBY_MENU_ID 0x01F8471B
|
#define LOBBY_MENU_ID 0x60000060
|
||||||
#define GAME_MENU_ID 0x205CD430
|
#define GAME_MENU_ID 0x60000090
|
||||||
#define QUEST_MENU_ID 0x7F02CA94
|
#define QUEST_MENU_ID 0x600000C0
|
||||||
#define QUEST_FILTER_MENU_ID 0xC38CA039
|
#define QUEST_FILTER_MENU_ID 0x600000F0
|
||||||
|
|
||||||
#define MAIN_MENU_GO_TO_LOBBY 0x00000001
|
#define MAIN_MENU_GO_TO_LOBBY 0x00000001
|
||||||
#define MAIN_MENU_INFORMATION 0x00000002
|
#define MAIN_MENU_INFORMATION 0x00000002
|
||||||
#define MAIN_MENU_DISCONNECT 0x00000003
|
#define MAIN_MENU_DOWNLOAD_QUESTS 0x00000003
|
||||||
|
#define MAIN_MENU_DISCONNECT 0x00000004
|
||||||
#define INFORMATION_MENU_GO_BACK 0xFFFFFFFF
|
#define INFORMATION_MENU_GO_BACK 0xFFFFFFFF
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ ServerState::ServerState()
|
|||||||
u"Join the lobby.", 0);
|
u"Join the lobby.", 0);
|
||||||
this->main_menu.emplace_back(MAIN_MENU_INFORMATION, u"Information",
|
this->main_menu.emplace_back(MAIN_MENU_INFORMATION, u"Information",
|
||||||
u"View server information.", MenuItemFlag::RequiresMessageBoxes);
|
u"View server information.", MenuItemFlag::RequiresMessageBoxes);
|
||||||
|
this->main_menu.emplace_back(MAIN_MENU_DOWNLOAD_QUESTS, u"Download quests",
|
||||||
|
u"Download quests.", 0);
|
||||||
this->main_menu.emplace_back(MAIN_MENU_DISCONNECT, u"Disconnect",
|
this->main_menu.emplace_back(MAIN_MENU_DISCONNECT, u"Disconnect",
|
||||||
u"Disconnect.", 0);
|
u"Disconnect.", 0);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user