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