diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 8aef5755..6c7338fb 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -2607,6 +2607,14 @@ struct S_StreamFileChunk_BB_02EB { // EC: Leave character select (BB) +struct C_LeaveCharacterSelect_BB_00EC { + // Reason codes: + // 0 = canceled + // 1 = recreate character + // 2 = dressing room + le_uint32_t reason; +}; + // ED (S->C): Force leave lobby/game (Episode 3) // No arguments // This command forces the client out of the game or lobby they're currently in diff --git a/src/Player.hh b/src/Player.hh index c08f8420..32e2a87f 100644 --- a/src/Player.hh +++ b/src/Player.hh @@ -463,12 +463,16 @@ struct SavedPlayerDataBB { // .nsc file format void print_inventory(FILE* stream) const; } __attribute__((packed)); +enum AccountFlag { + IN_DRESSING_ROOM = 0x00000001, +}; + struct SavedAccountDataBB { // .nsa file format ptext signature; parray blocked_senders; GuildCardFileBB guild_cards; KeyAndTeamConfigBB key_config; - le_uint32_t unused; + le_uint32_t newserv_flags; le_uint32_t option_flags; parray shortcuts; parray symbol_chats; diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index c45bcdb5..7ba9fd45 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -1706,6 +1706,8 @@ static void on_key_config_request_bb(shared_ptr, shared_ptr uint16_t, uint32_t, const string& data) { check_size_v(data.size(), 0); send_team_and_key_config_bb(c); + c->game_data.account()->newserv_flags &= ~AccountFlag::IN_DRESSING_ROOM; + c->log.info("Cleared dressing room flag for account"); } static void on_player_preview_request_bb(shared_ptr, shared_ptr c, @@ -1899,6 +1901,18 @@ static void on_stream_file_request_bb(shared_ptr, shared_ptr, shared_ptr c, + uint16_t, uint32_t, const string& data) { // EC + const auto& cmd = check_size_t(data); + if (cmd.reason == 2) { + c->game_data.account()->newserv_flags |= AccountFlag::IN_DRESSING_ROOM; + c->log.info("Set dressing room flag for account"); + } else { + c->game_data.account()->newserv_flags &= ~AccountFlag::IN_DRESSING_ROOM; + c->log.info("Cleared dressing room flag for account"); + } +} + static void on_create_character_bb(shared_ptr s, shared_ptr c, uint16_t, uint32_t, const string& data) { const auto& cmd = check_size_t(data); @@ -1925,13 +1939,25 @@ static void on_create_character_bb(shared_ptr s, shared_ptr c->game_data.bb_player_index = cmd.player_index; - try { - c->game_data.create_player(cmd.preview, s->level_table); - } catch (const exception& e) { - string message = string_printf("$C6New character could not be created:\n%s", e.what()); - send_message_box(c, decode_sjis(message)); - return; + if (c->game_data.account()->newserv_flags & AccountFlag::IN_DRESSING_ROOM) { + try { + c->game_data.player()->disp.apply_preview(cmd.preview); + } catch (const exception& e) { + string message = string_printf("$C6Character could not be modified:\n%s", e.what()); + send_message_box(c, decode_sjis(message)); + return; + } + } else { + try { + c->game_data.create_player(cmd.preview, s->level_table); + } catch (const exception& e) { + string message = string_printf("$C6New character could not be created:\n%s", e.what()); + send_message_box(c, decode_sjis(message)); + return; + } } + c->game_data.account()->newserv_flags &= ~AccountFlag::IN_DRESSING_ROOM; + c->log.info("Cleared dressing room flag for account"); send_client_init_bb(c, 0); send_approve_player_choice_bb(c); @@ -2884,7 +2910,7 @@ static on_command_t handlers[0x100][6] = { /* E9 */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* E9 */ /* EA */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_team_command_bb, }, /* EA */ /* EB */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_stream_file_request_bb, }, /* EB */ - /* EC */ {nullptr, nullptr, nullptr, on_create_game_dc_v3, nullptr, on_ignored_command, }, /* EC */ + /* EC */ {nullptr, nullptr, nullptr, on_create_game_dc_v3, nullptr, on_leave_char_select_bb, }, /* EC */ /* ED */ {nullptr, nullptr, nullptr, nullptr, nullptr, on_change_account_data_bb, }, /* ED */ /* EE */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* EE */ /* EF */ {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, }, /* EF */