document the CARD lobby battle table commands

This commit is contained in:
Martin Michelsen
2022-10-05 11:33:46 -07:00
parent 4eb46b293e
commit 3d036404f7
6 changed files with 79 additions and 5 deletions
+2
View File
@@ -53,6 +53,8 @@ Client::Client(
bufferevent_get_base(bev), -1, EV_TIMEOUT | EV_PERSIST,
&Client::dispatch_save_game_data, this),
event_free),
card_battle_table_number(-1),
card_battle_table_seat_number(0),
next_exp_value(0),
override_section_id(-1),
override_random_seed(-1),
+2
View File
@@ -105,6 +105,8 @@ struct Client {
int64_t preferred_lobby_id; // <0 = no preference
ClientGameData game_data;
std::unique_ptr<struct event, void(*)(struct event*)> save_game_data_event;
int16_t card_battle_table_number;
uint8_t card_battle_table_seat_number;
// Miscellaneous (used by chat commands)
uint32_t next_exp_value; // next EXP value to give
+5 -3
View File
@@ -2430,10 +2430,12 @@ struct S_PlayerPreview_NoPlayer_BB_00E4 {
le_uint32_t error; // 2 = no player present
};
// E5 (C->S): Unknown (CARD lobby battle table) (Episode 3)
// E5 (C->S): Confirm CARD lobby battle table choice (Episode 3)
// header.flag specifies whether the client answered "Yes" (1) or "No" (0).
struct S_CardBattleTable_Unknown_GC_Ep3_E5 {
le_uint32_t unknown_a1;
struct S_CardBattleTableConfirmation_GC_Ep3_E5 {
le_uint16_t table_number;
le_uint16_t seat_number;
};
// E5 (S->C): Player preview (BB)
+37 -2
View File
@@ -770,6 +770,41 @@ static void on_ep3_meseta_transaction(shared_ptr<ServerState>,
send_command(c, command, 0x03, &out_cmd, sizeof(out_cmd));
}
static void on_ep3_battle_table_state(shared_ptr<ServerState> s,
shared_ptr<Client> c, uint16_t, uint32_t flag, const string& data) { // E4
const auto& cmd = check_size_t<C_CardBattleTableState_GC_Ep3_E4>(data);
auto l = s->find_lobby(c->lobby_id);
if (l->is_game() || !(l->flags & Lobby::Flag::EPISODE_3_ONLY)) {
throw runtime_error("battle table command sent in non-CARD lobby");
}
if (flag) {
c->card_battle_table_number = cmd.table_number;
c->card_battle_table_seat_number = cmd.seat_number;
} else {
c->card_battle_table_number = -1;
c->card_battle_table_seat_number = 0;
}
send_ep3_card_battle_table_state(l, c->card_battle_table_number);
// TODO: If a client disconnects while at the battle table, we need to send
// a table update to all the other clients at the table (if any). Use a
// disconnect hook for this.
}
static void on_ep3_battle_table_confirm(shared_ptr<ServerState> s,
shared_ptr<Client> c, uint16_t, uint32_t flag, const string& data) { // E4
check_size_t<S_CardBattleTableConfirmation_GC_Ep3_E5>(data);
auto l = s->find_lobby(c->lobby_id);
if (l->is_game() || !(l->flags & Lobby::Flag::EPISODE_3_ONLY)) {
throw runtime_error("battle table command sent in non-CARD lobby");
}
if (flag) {
// TODO
send_lobby_message_box(c, u"CARD battles are\nnot yet supported.");
}
}
static void on_ep3_counter_state(shared_ptr<ServerState>, shared_ptr<Client> c,
uint16_t, uint32_t flag, const string& data) { // DC
check_size_v(data.size(), 0);
@@ -3226,8 +3261,8 @@ static on_command_t handlers[0x100][6] = {
/* E1 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* E1 */
/* E2 */ {nullptr, nullptr, nullptr, on_ep3_tournament_control, nullptr, on_update_key_config_bb, }, /* E2 */
/* E3 */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_player_preview_request_bb, }, /* E3 */
/* E4 */ {nullptr, nullptr, nullptr, on_ignored_command, nullptr, nullptr, }, /* E4 */
/* E5 */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_create_character_bb, }, /* E5 */
/* E4 */ {nullptr, nullptr, nullptr, on_ep3_battle_table_state, nullptr, nullptr, }, /* E4 */
/* E5 */ {nullptr, nullptr, nullptr, on_ep3_battle_table_confirm, nullptr, on_create_character_bb, }, /* E5 */
/* E6 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* E6 */
/* E7 */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_return_player_data_bb, }, /* E7 */
/* E8 */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_client_checksum_bb, }, /* E8 */
+32
View File
@@ -1649,6 +1649,38 @@ void send_ep3_map_data(shared_ptr<ServerState> s, shared_ptr<Lobby> l, uint32_t
send_command(l, 0x6C, 0x00, w.str());
}
void send_ep3_card_battle_table_state(shared_ptr<Lobby> l, uint16_t table_number) {
S_CardBattleTableState_GC_Ep3_E4 cmd;
for (size_t z = 0; z < 4; z++) {
cmd.entries[z].present = 0;
cmd.entries[z].unknown_a1 = 0;
cmd.entries[z].guild_card_number = 0;
}
set<shared_ptr<Client>> clients;
for (const auto& c : l->clients) {
if (!c) {
continue;
}
if (c->card_battle_table_number == table_number) {
if (c->card_battle_table_seat_number > 3) {
throw runtime_error("invalid battle table seat number");
}
auto& e = cmd.entries[c->card_battle_table_seat_number];
if (e.present) {
throw runtime_error("multiple clients in the same battle table seat");
}
e.present = 1;
e.guild_card_number = c->license->serial_number;
clients.emplace(c);
}
}
for (const auto& c : clients) {
send_command_t(c, 0xE4, table_number, cmd);
}
}
void set_mask_for_ep3_game_command(void* vdata, size_t size, uint8_t mask_key) {
if (size < 8) {
throw logic_error("Episode 3 game command is too short for masking");
+1
View File
@@ -264,6 +264,7 @@ void send_ep3_map_list(
std::shared_ptr<ServerState> s, std::shared_ptr<Lobby> l);
void send_ep3_map_data(
std::shared_ptr<ServerState> s, std::shared_ptr<Lobby> l, uint32_t map_id);
void send_ep3_card_battle_table_state(std::shared_ptr<Lobby> l, uint16_t table_number);
// Pass mask_key = 0 to unmask the command
void set_mask_for_ep3_game_command(void* vdata, size_t size, uint8_t mask_key);