From 9183c1e362dbea6e5a0ae7c890a14a789b59f2f8 Mon Sep 17 00:00:00 2001 From: James Osborne Date: Sun, 7 Jun 2026 15:39:33 -0400 Subject: [PATCH 1/7] Mark Brutal Peeps rooms in game list --- src/SendCommands.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 1522112b..97ee6182 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2178,8 +2178,8 @@ void send_game_menu_t(std::shared_ptr c, bool is_spectator_team_list, bo default: throw std::logic_error("invalid game mode"); } - // On v2, render name in orange if v1 is not allowed - if (is_v2(c->version()) && !l->version_is_allowed(Version::DC_V1)) { + // On v2, render name in orange if v1 is not allowed, or if this is a Brutal Peeps room. + if (is_v2(c->version()) && (!l->version_is_allowed(Version::DC_V1) || (l->brutal_peeps_tier >= 1))) { e.flags |= 0x40; } // On BB, gray out games that can't be joined @@ -2187,7 +2187,12 @@ void send_game_menu_t(std::shared_ptr c, bool is_spectator_team_list, bo e.flags |= 0x04; } } - e.name.encode(l->name, c->language()); + + if ((c->version() == Version::BB_V4) && (l->brutal_peeps_tier >= 1)) { + e.name.encode("$C4" + l->name, c->language()); + } else { + e.name.encode(l->name, c->language()); + } } send_command_vt(c, is_spectator_team_list ? 0xE6 : 0x08, entries.size() - 1, entries); From 7d609b6a40b2e0cba6130208691999f40384f4a9 Mon Sep 17 00:00:00 2001 From: James Osborne Date: Sun, 7 Jun 2026 15:48:38 -0400 Subject: [PATCH 2/7] Restrict PC Brutal Peeps rooms to PC clients --- src/Lobby.cc | 7 +++++++ src/SendCommands.cc | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/src/Lobby.cc b/src/Lobby.cc index 8ff904d9..d1d84ca8 100644 --- a/src/Lobby.cc +++ b/src/Lobby.cc @@ -618,6 +618,13 @@ Lobby::JoinError Lobby::join_error_for_client(std::shared_ptr c, const s return JoinError::VERSION_CONFLICT; } if (this->is_game()) { + // Brutal Peeps PC rooms rely on PC-only BattleParam runtime patching, so don't allow DC V2 clients to join them. + if ((this->brutal_peeps_tier >= 1) && + this->version_is_allowed(Version::PC_V2) && + (c->version() != Version::PC_V2)) { + return JoinError::VERSION_CONFLICT; + } + if (this->check_flag(Flag::QUEST_SELECTION_IN_PROGRESS)) { return JoinError::QUEST_SELECTION_IN_PROGRESS; } diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 97ee6182..0a276db1 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2120,6 +2120,12 @@ void send_game_menu_t(std::shared_ptr c, bool is_spectator_team_list, bo (client_has_debug || (l->check_flag(Lobby::Flag::IS_CLIENT_CUSTOMIZATION) == c->check_flag(Client::Flag::IS_CLIENT_CUSTOMIZATION))) && (l->check_flag(Lobby::Flag::IS_SPECTATOR_TEAM) == is_spectator_team_list) && (!show_tournaments_only || l->tournament_match)) { + // Brutal Peeps PC rooms rely on PC-only BattleParam runtime patching, so don't show them to DC V2 clients. + if ((l->brutal_peeps_tier >= 1) && + l->version_is_allowed(Version::PC_V2) && + (c->version() != Version::PC_V2)) { + continue; + } games.emplace(l); } } From 672a6575a7ad8b922f5ca55babbdaea4317936af Mon Sep 17 00:00:00 2001 From: James Osborne Date: Sun, 7 Jun 2026 15:54:21 -0400 Subject: [PATCH 3/7] Restrict Brutal Peeps rooms to matching client versions --- src/Lobby.cc | 7 ++++--- src/SendCommands.cc | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Lobby.cc b/src/Lobby.cc index d1d84ca8..d82c7930 100644 --- a/src/Lobby.cc +++ b/src/Lobby.cc @@ -618,10 +618,11 @@ Lobby::JoinError Lobby::join_error_for_client(std::shared_ptr c, const s return JoinError::VERSION_CONFLICT; } if (this->is_game()) { - // Brutal Peeps PC rooms rely on PC-only BattleParam runtime patching, so don't allow DC V2 clients to join them. + // Brutal Peeps rooms rely on version-specific BattleParam patching. + // BB Brutal rooms are BB-only; PC Brutal rooms are PC V2-only. if ((this->brutal_peeps_tier >= 1) && - this->version_is_allowed(Version::PC_V2) && - (c->version() != Version::PC_V2)) { + ((this->version_is_allowed(Version::BB_V4) && (c->version() != Version::BB_V4)) || + (this->version_is_allowed(Version::PC_V2) && (c->version() != Version::PC_V2)))) { return JoinError::VERSION_CONFLICT; } diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 0a276db1..78bd52f7 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2120,10 +2120,11 @@ void send_game_menu_t(std::shared_ptr c, bool is_spectator_team_list, bo (client_has_debug || (l->check_flag(Lobby::Flag::IS_CLIENT_CUSTOMIZATION) == c->check_flag(Client::Flag::IS_CLIENT_CUSTOMIZATION))) && (l->check_flag(Lobby::Flag::IS_SPECTATOR_TEAM) == is_spectator_team_list) && (!show_tournaments_only || l->tournament_match)) { - // Brutal Peeps PC rooms rely on PC-only BattleParam runtime patching, so don't show them to DC V2 clients. + // Brutal Peeps rooms rely on version-specific BattleParam patching. + // BB Brutal rooms are BB-only; PC Brutal rooms are PC V2-only. if ((l->brutal_peeps_tier >= 1) && - l->version_is_allowed(Version::PC_V2) && - (c->version() != Version::PC_V2)) { + ((l->version_is_allowed(Version::BB_V4) && (c->version() != Version::BB_V4)) || + (l->version_is_allowed(Version::PC_V2) && (c->version() != Version::PC_V2)))) { continue; } games.emplace(l); From b9cd17d9dc6a071f9d51ce89a2287a182d3f3fe9 Mon Sep 17 00:00:00 2001 From: James Osborne Date: Sun, 7 Jun 2026 16:53:41 -0400 Subject: [PATCH 4/7] Do not use BB color tokens in game list names --- src/SendCommands.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 78bd52f7..9bc086f7 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2195,11 +2195,7 @@ void send_game_menu_t(std::shared_ptr c, bool is_spectator_team_list, bo } } - if ((c->version() == Version::BB_V4) && (l->brutal_peeps_tier >= 1)) { - e.name.encode("$C4" + l->name, c->language()); - } else { - e.name.encode(l->name, c->language()); - } + e.name.encode(l->name, c->language()); } send_command_vt(c, is_spectator_team_list ? 0xE6 : 0x08, entries.size() - 1, entries); From 75653f155c2a0780d7f1dd2f19300b9b6f67aa3c Mon Sep 17 00:00:00 2001 From: James Osborne Date: Sun, 7 Jun 2026 16:56:44 -0400 Subject: [PATCH 5/7] Show Brutal Peeps tier in BB game list --- src/SendCommands.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 9bc086f7..bc3934a8 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2195,7 +2195,11 @@ void send_game_menu_t(std::shared_ptr c, bool is_spectator_team_list, bo } } - e.name.encode(l->name, c->language()); + if ((c->version() == Version::BB_V4) && (l->brutal_peeps_tier >= 1)) { + e.name.encode(std::format("B+{} {}", static_cast(l->brutal_peeps_tier), l->name), c->language()); + } else { + e.name.encode(l->name, c->language()); + } } send_command_vt(c, is_spectator_team_list ? 0xE6 : 0x08, entries.size() - 1, entries); From 2e38c4b12f900b87821bb4e249537e558a0bcf4f Mon Sep 17 00:00:00 2001 From: James Osborne Date: Sun, 7 Jun 2026 17:31:48 -0400 Subject: [PATCH 6/7] Split BB and PC Brutal Peeps patch timing --- src/ReceiveCommands.cc | 10 ++++++++-- src/SendCommands.cc | 42 +++++++++++++++++++++++------------------- src/SendCommands.hh | 2 +- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index e1115f3d..ff3070df 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -2771,7 +2771,9 @@ static asio::awaitable on_10_main_menu(std::shared_ptr c, uint32_t co_await send_auto_patches_if_needed(c); if (c->version() == Version::BB_V4) { - co_await send_brutal_peeps_hp_patch_bb(c, tier); + // BB must patch all online BattleParam files before room creation/area load. + // PC V2 uses the delayed area-load retry path instead. + co_await send_brutal_peeps_hp_patch_bb(c, tier, true); } co_await enable_save_if_needed(c); send_lobby_list(c); @@ -2785,7 +2787,11 @@ static asio::awaitable on_10_main_menu(std::shared_ptr c, uint32_t case MainMenuItemID::GO_TO_LOBBY: { c->selected_brutal_peeps_tier = -1; co_await send_auto_patches_if_needed(c); - co_await send_brutal_peeps_hp_patch_bb(c, -1); + if (c->version() == Version::BB_V4) { + co_await send_brutal_peeps_hp_patch_bb(c, -1, true); + } else if (c->version() == Version::PC_V2) { + co_await send_brutal_peeps_hp_patch_bb(c, -1); + } co_await enable_save_if_needed(c); send_lobby_list(c); if (is_pre_v1(c->version())) { diff --git a/src/SendCommands.cc b/src/SendCommands.cc index bc3934a8..da074834 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -777,7 +777,8 @@ static std::string bb_stream_file_data_for_client(std::shared_ptr c) { static std::vector>>> send_brutal_peeps_hp_patch_bb_now( std::shared_ptr c, - int64_t tier) { + int64_t tier, + bool force_all_tables) { std::vector>>> promises; if (c->version() != Version::BB_V4) { @@ -831,25 +832,28 @@ static std::vector bp_filenames; - auto l = c->lobby.lock(); - if (l && l->is_game()) { - switch (l->episode) { - case Episode::EP1: - bp_filenames.emplace_back("BattleParamEntry_on.dat"); - break; - case Episode::EP2: - bp_filenames.emplace_back("BattleParamEntry_lab_on.dat"); - break; - case Episode::EP4: - bp_filenames.emplace_back("BattleParamEntry_ep4_on.dat"); - break; - default: - break; + + if (!force_all_tables) { + auto l = c->lobby.lock(); + if (l && l->is_game()) { + switch (l->episode) { + case Episode::EP1: + bp_filenames.emplace_back("BattleParamEntry_on.dat"); + break; + case Episode::EP2: + bp_filenames.emplace_back("BattleParamEntry_lab_on.dat"); + break; + case Episode::EP4: + bp_filenames.emplace_back("BattleParamEntry_ep4_on.dat"); + break; + default: + break; + } } } - // Before the room exists, we don't know which episode the player will pick. - // Patch all online BB BattleParam tables so EP2/EP4 HP is already scaled before enemies initialize. + // Before the room exists, or when explicitly requested from the BB ship-menu path, + // patch all online BB BattleParam tables before enemies initialize. if (bp_filenames.empty()) { bp_filenames.emplace_back("BattleParamEntry_on.dat"); bp_filenames.emplace_back("BattleParamEntry_lab_on.dat"); @@ -1251,7 +1255,7 @@ static std::vector send_brutal_peeps_hp_patch_bb(std::shared_ptr c, int64_t tier) { +asio::awaitable send_brutal_peeps_hp_patch_bb(std::shared_ptr c, int64_t tier, bool force_all_tables) { try { co_await prepare_client_for_patches(c); @@ -1261,7 +1265,7 @@ asio::awaitable send_brutal_peeps_hp_patch_bb(std::shared_ptr c, i for (size_t attempt = 1; attempt <= max_attempts; attempt++) { auto promises = is_pc_bp_patch ? send_brutal_peeps_hp_patch_pc_now(c, tier) - : send_brutal_peeps_hp_patch_bb_now(c, tier); + : send_brutal_peeps_hp_patch_bb_now(c, tier, force_all_tables); bool any_zero_return = false; bool any_success = false; diff --git a/src/SendCommands.hh b/src/SendCommands.hh index b09c48cc..a54d3ed9 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -198,7 +198,7 @@ void send_guild_card_header_bb(std::shared_ptr c); void send_guild_card_chunk_bb(std::shared_ptr c, size_t chunk_index); void send_stream_file_index_bb(std::shared_ptr c); void send_stream_file_chunk_bb(std::shared_ptr c, uint32_t chunk_index); -asio::awaitable send_brutal_peeps_hp_patch_bb(std::shared_ptr c, int64_t tier); +asio::awaitable send_brutal_peeps_hp_patch_bb(std::shared_ptr c, int64_t tier, bool force_all_tables = false); void send_approve_player_choice_bb(std::shared_ptr c); void send_complete_player_bb(std::shared_ptr c); From e80275283647c4821b5e679c35621ccfeac72383 Mon Sep 17 00:00:00 2001 From: James Osborne Date: Sun, 7 Jun 2026 18:10:45 -0400 Subject: [PATCH 7/7] Clarify Brutal Peeps room join warnings --- src/ReceiveCommands.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index ff3070df..79aeeb8e 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -3670,6 +3670,27 @@ static void on_joinable_quest_loaded(std::shared_ptr c) { leader_c->expected_game_state_sync_commands.emplace(0x6C00 | (c->lobby_client_id)); leader_c->expected_game_state_sync_commands.emplace(0x6D00 | (c->lobby_client_id)); leader_c->expected_game_state_sync_commands.emplace(0x6E00 | (c->lobby_client_id)); + if (((c->version() == Version::BB_V4) || (c->version() == Version::PC_V2)) && l->is_game()) { + const int8_t room_brutal_peeps_tier = l->brutal_peeps_tier; + const int8_t client_brutal_peeps_tier = c->selected_brutal_peeps_tier; + + if ((room_brutal_peeps_tier >= 1) && (client_brutal_peeps_tier != room_brutal_peeps_tier)) { + send_message_box(c, std::format( + "$C6Must have Brutal Peeps +{} selected\nto join this room.\n\n" + "$C7Use Transfer Ship and select\nBrutal Peeps +{} first.", + static_cast(room_brutal_peeps_tier), + static_cast(room_brutal_peeps_tier))); + return; + } + + if ((room_brutal_peeps_tier < 1) && (client_brutal_peeps_tier >= 1)) { + send_message_box(c, + "$C6Disable Brutal Peeps before\njoining a normal room.\n\n" + "$C7Use Transfer Ship and select\nGo to lobby first."); + return; + } + } + c->log.info_f("Creating game join command queue"); c->game_join_command_queue = std::make_unique>(); } else {