From 0c87f040f63b3f92b294fac39bdee3cde40ec71c Mon Sep 17 00:00:00 2001 From: BlaMacfly <165155133+BlaMacfly@users.noreply.github.com> Date: Sat, 12 Sep 2026 23:02:02 +0200 Subject: [PATCH] Difficulte : traiter CMSG_TOGGLE_DIFFICULTY, le mode heroique des vieux raids Signalement Discord : impossible de passer les Terres de feu en heroique, le client repondait qu on ne remplissait pas les conditions. Aucun rapport avec un deblocage par kill. Les raids d avant Warlords n utilisent pas CMSG_SET_RAID_DIFFICULTY pour ce bouton : le client envoie CMSG_TOGGLE_DIFFICULTY, sans preciser de difficulte, et attend la bascule normal <-> heroique a taille de raid constante. L opcode etait declare STATUS_UNHANDLED et jete a la reception, d ou le refus cote client. C est aussi pourquoi le 10 <-> 25 fonctionnait : ce bouton passe par l autre opcode. Handler ecrit avec les memes garde-fous que le changement de difficulte ordinaire. Reste a faire : la bascule depuis l interieur de l instance, le vrai comportement de Cataclysm -- IsDynamicDifficultyMap existe dans les DB2 mais n est utilise nulle part. --- src/server/game/Handlers/MiscHandler.cpp | 62 ++++++++++++++++++++ src/server/game/Server/Packets/MiscPackets.h | 10 ++++ src/server/game/Server/Protocol/Opcodes.cpp | 2 +- src/server/game/Server/WorldSession.h | 2 + 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 2de8b42..75d10b1 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -993,6 +993,68 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDiff } } +// Les raids d'avant Warlords ne passent pas par CMSG_SET_RAID_DIFFICULTY pour le mode +// heroique : le client envoie CMSG_TOGGLE_DIFFICULTY, sans rien preciser, et attend que +// le serveur bascule entre normal et heroique en conservant la taille du raid. Cet +// opcode n'etait pas traite du tout, si bien que le client repondait « vous ne remplissez +// pas les conditions requises » -- impossible de monter les Terres de feu en heroique. +void WorldSession::HandleToggleDifficultyOpcode(WorldPackets::Misc::ToggleDifficulty& /*toggleDifficulty*/) +{ + Difficulty difficultyID; + switch (_player->GetLegacyRaidDifficultyID()) + { + case DIFFICULTY_10_N: difficultyID = DIFFICULTY_10_HC; break; + case DIFFICULTY_25_N: difficultyID = DIFFICULTY_25_HC; break; + case DIFFICULTY_10_HC: difficultyID = DIFFICULTY_10_N; break; + case DIFFICULTY_25_HC: difficultyID = DIFFICULTY_25_N; break; + default: + return; + } + + // Memes garde-fous que le changement de difficulte ordinaire : on ne bascule pas + // depuis l'interieur d'une instance, et seul le chef decide pour le groupe. + Map* map = _player->FindMap(); + if (map && map->IsDungeon()) + { + TC_LOG_DEBUG("network", "WorldSession::HandleToggleDifficultyOpcode: player (Name: %s, %s) tried to toggle the difficulty while inside an instance!", + _player->GetName().c_str(), _player->GetGUID().ToString().c_str()); + return; + } + + Group* group = _player->GetGroup(); + if (group) + { + if (!group->IsLeader(_player->GetGUID())) + return; + + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* groupGuy = itr->GetSource(); + if (!groupGuy) + continue; + + if (!groupGuy->IsInMap(groupGuy)) + return; + + if (groupGuy->GetMap()->IsRaid()) + { + TC_LOG_DEBUG("network", "WorldSession::HandleToggleDifficultyOpcode: %s tried to toggle the difficulty while group member (Name: %s, %s) is inside!", + _player->GetGUID().ToString().c_str(), groupGuy->GetName().c_str(), groupGuy->GetGUID().ToString().c_str()); + return; + } + } + + group->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, true, _player); + group->SetLegacyRaidDifficultyID(difficultyID); + } + else + { + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, true); + _player->SetLegacyRaidDifficultyID(difficultyID); + _player->SendRaidDifficulty(true); + } +} + void WorldSession::HandleSetTaxiBenchmark(WorldPackets::Misc::SetTaxiBenchmarkMode& packet) { _player->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK, packet.Enable); diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index fc61555..529b81d 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -300,6 +300,16 @@ namespace WorldPackets uint8 Legacy = 0; }; + // Le bouton « heroique » des raids d'avant Warlords : aucune difficulte n'est + // transmise, le client demande simplement la bascule normal <-> heroique. + class ToggleDifficulty final : public ClientPacket + { + public: + ToggleDifficulty(WorldPacket&& packet) : ClientPacket(CMSG_TOGGLE_DIFFICULTY, std::move(packet)) { } + + void Read() override { } + }; + class DungeonDifficultySet final : public ServerPacket { public: diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index c20472e..8e139f7 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -830,7 +830,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_TIME_SYNC_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleTimeSyncResponse); DEFINE_HANDLER(CMSG_TIME_SYNC_RESPONSE_DROPPED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TIME_SYNC_RESPONSE_FAILED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_TOGGLE_DIFFICULTY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_TOGGLE_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleToggleDifficultyOpcode); DEFINE_HANDLER(CMSG_TOGGLE_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTogglePvP); DEFINE_HANDLER(CMSG_TOTEM_DESTROYED, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTotemDestroyed); DEFINE_HANDLER(CMSG_TRADE_SKILL_SET_FAVORITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 45a8dad..862a085 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -569,6 +569,7 @@ namespace WorldPackets class TutorialSetFlag; class SetDungeonDifficulty; class SetRaidDifficulty; + class ToggleDifficulty; class PortGraveyard; class ReclaimCorpse; class RepopRequest; @@ -1727,6 +1728,7 @@ class TC_GAME_API WorldSession void HandleFarSightOpcode(WorldPackets::Misc::FarSight& packet); void HandleSetDungeonDifficultyOpcode(WorldPackets::Misc::SetDungeonDifficulty& setDungeonDifficulty); void HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDifficulty& setRaidDifficulty); + void HandleToggleDifficultyOpcode(WorldPackets::Misc::ToggleDifficulty& toggleDifficulty); void HandleSetTitleOpcode(WorldPackets::Character::SetTitle& packet); void HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& packet); void HandleDiscardedTimeSyncAcks(WorldPackets::Misc::DiscardedTimeSyncAcks& packet);