handle incorrect flags in 10 command
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
0019 = P2 Scientist after defeating dragon
|
||||
001E = Entered Caves 1 (Gov 2-1)
|
||||
001F = Entered De Rol Le in 2-4
|
||||
0020 = De Ro lee defeated
|
||||
0020 = De Rol Le defeated
|
||||
0021 = Mines unlocked (P2 Tyrell after defeating De Rol Le)
|
||||
0028 = Entered Mines 1
|
||||
0029 = Entered Vol Opt Area
|
||||
|
||||
+20
-9
@@ -674,15 +674,26 @@ struct S_LegacyJoinGame_XB_0E {
|
||||
|
||||
// 10 (C->S): Menu selection
|
||||
// Internal name: SndAction
|
||||
// header.flag is a bit field containing two flags: 02 specifies if a password
|
||||
// is present, and 01 specifies if a name is present. (If both are set, the
|
||||
// name comes first, as described below). These two bits directly correspond to
|
||||
// the two lowest bits in the flags field of the game menu: 02 specifies that
|
||||
// the game is locked, but the function of 01 is unknown. The ability to send
|
||||
// a name along with a menu choice is unused in all client versions except
|
||||
// Episode 3, where it's used in the tourname entries menu. It's not clear why
|
||||
// all other versions have the ability send a name here - it may be a relic
|
||||
// from very early development.
|
||||
// header.flag has different meanings depending on which menu is selected.
|
||||
// For most menus, header.flag is a bit field containing two flags: 02
|
||||
// specifies if a password is present, and 01 specifies if a name is present.
|
||||
// (If both are set, the name comes first, as described below). These two bits
|
||||
// directly correspond to the two lowest bits in the flags field of the game
|
||||
// menu: 02 specifies that the game is locked, but the function of 01 is
|
||||
// unknown. The ability to send a name along with a menu choice is unused in
|
||||
// all client versions except Episode 3, where it's used in the tournament
|
||||
// entries menu. It's not clear why all other versions have the ability send a
|
||||
// name here - it may be a relic from very early development.
|
||||
// For the quest categories menu, header.flag specifies the player's
|
||||
// progression through the story. The values are:
|
||||
// 0 = has not yet defeated Dragon
|
||||
// 1 = has defeated Dragon but not De Rol Le
|
||||
// 2 = has defeated De Rol Le but not Vol Opt
|
||||
// 3 = has defeated Vol Opt but not Dark Falz
|
||||
// 4 = has defeated Dark Falz
|
||||
// For the challenge categories menu, header.flag specifies something related
|
||||
// to challenge stage completion (TODO: reverse-engineer function at
|
||||
// 59NL:004DA300 to see what this is)
|
||||
|
||||
struct C_MenuSelectionBase_10 {
|
||||
le_uint32_t menu_id = 0;
|
||||
|
||||
+31
-38
@@ -2978,83 +2978,76 @@ template <bool UsesUTF16>
|
||||
static asio::awaitable<void> on_10(shared_ptr<Client> c, Channel::Message& msg) {
|
||||
constexpr TextEncoding Encoding = UsesUTF16 ? TextEncoding::UTF16 : TextEncoding::MARKED;
|
||||
|
||||
uint32_t menu_id;
|
||||
uint32_t item_id;
|
||||
const auto& base_cmd = check_size_t<C_MenuSelectionBase_10>(msg.data, 0xFFFF);
|
||||
|
||||
string name;
|
||||
string password;
|
||||
switch (msg.flag) {
|
||||
case 0: {
|
||||
const auto& cmd = check_size_t<C_MenuSelectionBase_10>(msg.data);
|
||||
menu_id = cmd.menu_id;
|
||||
item_id = cmd.item_id;
|
||||
switch (msg.data.size()) {
|
||||
case sizeof(C_MenuSelectionBase_10):
|
||||
break;
|
||||
case sizeof(C_MenuSelectionWithNameT_10<Encoding>): {
|
||||
static_assert(
|
||||
sizeof(C_MenuSelectionWithNameT_10<Encoding>) == sizeof(C_MenuSelectionWithPasswordT_10<Encoding>),
|
||||
"Single-flag 10 commands should be the same size");
|
||||
if (msg.flag & 1) {
|
||||
const auto& cmd = check_size_t<C_MenuSelectionWithNameT_10<Encoding>>(msg.data);
|
||||
name = cmd.name.decode(c->language());
|
||||
} else if (msg.flag & 2) {
|
||||
const auto& cmd = check_size_t<C_MenuSelectionWithPasswordT_10<Encoding>>(msg.data);
|
||||
password = cmd.password.decode(c->language());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
const auto& cmd = check_size_t<C_MenuSelectionWithNameT_10<Encoding>>(msg.data);
|
||||
name = cmd.name.decode(c->language());
|
||||
menu_id = cmd.menu_id;
|
||||
item_id = cmd.item_id;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
const auto& cmd = check_size_t<C_MenuSelectionWithPasswordT_10<Encoding>>(msg.data);
|
||||
password = cmd.password.decode(c->language());
|
||||
menu_id = cmd.menu_id;
|
||||
item_id = cmd.item_id;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
case sizeof(C_MenuSelectionWithNameAndPasswordT_10<Encoding>): {
|
||||
const auto& cmd = check_size_t<C_MenuSelectionWithNameAndPasswordT_10<Encoding>>(msg.data);
|
||||
name = cmd.name.decode(c->language());
|
||||
password = cmd.password.decode(c->language());
|
||||
menu_id = cmd.menu_id;
|
||||
item_id = cmd.item_id;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("invalid options for menu selection command");
|
||||
throw runtime_error("unknown menu selection format");
|
||||
}
|
||||
|
||||
auto s = c->require_server_state();
|
||||
switch (menu_id) {
|
||||
switch (base_cmd.menu_id) {
|
||||
case MenuID::MAIN:
|
||||
co_await on_10_main_menu(c, item_id);
|
||||
co_await on_10_main_menu(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::CLEAR_LICENSE_CONFIRMATION:
|
||||
co_await on_10_clear_license_confirmation(c, item_id);
|
||||
co_await on_10_clear_license_confirmation(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::INFORMATION:
|
||||
co_await on_10_information(c, item_id);
|
||||
co_await on_10_information(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::PROXY_OPTIONS:
|
||||
co_await on_10_proxy_options(c, item_id);
|
||||
co_await on_10_proxy_options(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::PROXY_DESTINATIONS:
|
||||
co_await on_10_proxy_destinations(c, item_id);
|
||||
co_await on_10_proxy_destinations(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::GAME:
|
||||
co_await on_10_game_menu(c, item_id, std::move(password));
|
||||
co_await on_10_game_menu(c, base_cmd.item_id, std::move(password));
|
||||
break;
|
||||
case MenuID::QUEST_CATEGORIES_EP1:
|
||||
case MenuID::QUEST_CATEGORIES_EP2:
|
||||
co_await on_10_quest_categories(c, item_id);
|
||||
co_await on_10_quest_categories(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::QUEST_EP1:
|
||||
case MenuID::QUEST_EP2:
|
||||
co_await on_10_quest_menu(c, item_id);
|
||||
co_await on_10_quest_menu(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::PATCH_SWITCHES:
|
||||
co_await on_10_patch_switches(c, item_id);
|
||||
co_await on_10_patch_switches(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::PROGRAMS:
|
||||
co_await on_10_programs(c, item_id);
|
||||
co_await on_10_programs(c, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::TOURNAMENTS_FOR_SPEC:
|
||||
case MenuID::TOURNAMENTS:
|
||||
co_await on_10_tournaments(c, menu_id, item_id);
|
||||
co_await on_10_tournaments(c, base_cmd.menu_id, base_cmd.item_id);
|
||||
break;
|
||||
case MenuID::TOURNAMENT_ENTRIES:
|
||||
co_await on_10_tournament_entries(c, item_id, std::move(name), std::move(password));
|
||||
co_await on_10_tournament_entries(c, base_cmd.item_id, std::move(name), std::move(password));
|
||||
break;
|
||||
default:
|
||||
send_message_box(c, "Incorrect menu ID");
|
||||
|
||||
Reference in New Issue
Block a user