From 8e35ae2152ba22e07c9a10d7e43463faab173b40 Mon Sep 17 00:00:00 2001 From: codestothestars Date: Sat, 26 Aug 2023 13:31:12 -0400 Subject: [PATCH] Enable using self-resurrection spells on 1.5 client (#2182) * Correct comment position * Enable self-resurrection spells for 1.5 client Fixes build errors related to self-resurrection and enables self- resurrection to work on the 1.5 client, per the 1.6 patch notes. > Self-resurrection spells show their name on the button in the release > spirit dialog. The update field PLAYER_SELF_RES_SPELL did not exist in patch 1.5, and so the ID of the self-resurrection spell was not sent to the client. Decompiled 1.5 client code shows that it instead checks the player flag 0x1000 (currently PLAYER_FLAGS_PARTIAL_PLAY_TIME) to determine whether the player can self-resurrect, meaning this flag was repurposed on or after patch 1.6. As this means we cannot store the spell ID in the player's update fields, for these clients we instead store the ID purely server-side to read after the player dies. --- src/game/Handlers/SpellHandler.cpp | 14 ++++++++++++++ src/game/Objects/Player.cpp | 28 +++++++++++++++++++++++++--- src/game/Objects/Player.h | 13 +++++++++++-- src/game/Objects/Unit.cpp | 24 ++++++++++++++++++++++-- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/game/Handlers/SpellHandler.cpp b/src/game/Handlers/SpellHandler.cpp index 28fb6e2acf4..e34af6aa0a4 100644 --- a/src/game/Handlers/SpellHandler.cpp +++ b/src/game/Handlers/SpellHandler.cpp @@ -496,6 +496,9 @@ void WorldSession::HandleCancelChanneling(WorldPacket& recv_data) void WorldSession::HandleSelfResOpcode(WorldPacket& /*recv_data*/) { +// World of Warcraft Client Patch 1.6.0 (2005-07-12) +// - Self-resurrection spells show their name on the button in the release spirit dialog. +#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1 if (_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)) { SpellEntry const* spellInfo = sSpellMgr.GetSpellEntry(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)); @@ -504,4 +507,15 @@ void WorldSession::HandleSelfResOpcode(WorldPacket& /*recv_data*/) _player->SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); } +#else + if (_player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT)) + { + SpellEntry const* spellInfo = sSpellMgr.GetSpellEntry(_player->GetResurrectionSpellId()); + if (spellInfo) + _player->CastSpell(_player, spellInfo, false); + + _player->SetResurrectionSpellId(0); + _player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT); + } +#endif } diff --git a/src/game/Objects/Player.cpp b/src/game/Objects/Player.cpp index 6eca06527a4..c27e35f06ae 100644 --- a/src/game/Objects/Player.cpp +++ b/src/game/Objects/Player.cpp @@ -701,6 +701,10 @@ Player::Player(WorldSession* session) : Unit(), m_lastFromClientCastedSpellID = 0; +#if SUPPORTED_CLIENT_BUILD < CLIENT_BUILD_1_6_1 + m_resurrectionSpellId = 0; +#endif + // Anti undermap m_undermapPosValid = false; session->InitCheatData(this); @@ -1933,12 +1937,18 @@ void Player::SetDeathState(DeathState s) if (ObjectGuid lootGuid = GetLootGuid()) GetSession()->DoLootRelease(lootGuid); +// World of Warcraft Client Patch 1.6.0 (2005-07-12) +// - Self-resurrection spells show their name on the button in the release spirit dialog. +#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1 // save value before aura remove in Unit::SetDeathState ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL); +#else + ressSpellId = GetResurrectionSpellId(); +#endif // passive spell if (!ressSpellId) - ressSpellId = GetResurrectionSpellId(); + ressSpellId = SelectResurrectionSpellId(); if (m_zoneScript) m_zoneScript->OnPlayerDeath(this); @@ -1948,12 +1958,24 @@ void Player::SetDeathState(DeathState s) // restore resurrection spell id for player after aura remove if (s == JUST_DIED && cur && ressSpellId) + { +#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1 SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); +#else + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT); + SetResurrectionSpellId(ressSpellId); +#endif + } if (IsAlive() && !cur) { - //clear aura case after resurrection by another way (spells will be applied before next death) + //clear self-resurrection state after resurrection by another way (spells will be applied before next death) +#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1 SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); +#else + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT); + SetResurrectionSpellId(0); +#endif UpdatePvPContested(false, true); } @@ -20012,7 +20034,7 @@ void Player::RemoveItemDependentAurasAndCasts(Item* pItem) } } -uint32 Player::GetResurrectionSpellId() const +uint32 Player::SelectResurrectionSpellId() const { // search priceless resurrection possibilities uint32 prio = 0; diff --git a/src/game/Objects/Player.h b/src/game/Objects/Player.h index e72535c6a5d..8f988e16f49 100644 --- a/src/game/Objects/Player.h +++ b/src/game/Objects/Player.h @@ -321,6 +321,9 @@ enum PlayerFlags PLAYER_FLAGS_PVP_DESIRED = 0x00000200, // Stores player's permanent PvP flag preference PLAYER_FLAGS_HIDE_HELM = 0x00000400, PLAYER_FLAGS_HIDE_CLOAK = 0x00000800, +#if SUPPORTED_CLIENT_BUILD < CLIENT_BUILD_1_6_1 + PLAYER_FLAGS_CAN_SELF_RESURRECT = 0x00001000, +#endif PLAYER_FLAGS_PARTIAL_PLAY_TIME = 0x00001000, // played long time PLAYER_FLAGS_NO_PLAY_TIME = 0x00002000, // played too long time PLAYER_FLAGS_UNK15 = 0x00004000, @@ -1501,7 +1504,9 @@ class Player final: public Unit SpellModList m_spellMods[MAX_SPELLMOD]; uint32 m_lastFromClientCastedSpellID; std::map m_itemSetEffects; - +#if SUPPORTED_CLIENT_BUILD < CLIENT_BUILD_1_6_1 + uint32 m_resurrectionSpellId; +#endif bool IsNeedCastPassiveLikeSpellAtLearn(SpellEntry const* spellInfo) const; void SendInitialSpells() const; bool AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled); @@ -2263,7 +2268,11 @@ class Player final: public Unit void SpawnCorpseBones(); Corpse* CreateCorpse(); void KillPlayer(); - uint32 GetResurrectionSpellId() const; +#if SUPPORTED_CLIENT_BUILD < CLIENT_BUILD_1_6_1 + uint32 GetResurrectionSpellId() const { return m_resurrectionSpellId; } + void SetResurrectionSpellId(uint32 resurrectionSpellId) { m_resurrectionSpellId = resurrectionSpellId; } +#endif + uint32 SelectResurrectionSpellId() const; void ResurrectPlayer(float restore_percent, bool applySickness = false); void BuildPlayerRepop(); void RepopAtGraveyard(); diff --git a/src/game/Objects/Unit.cpp b/src/game/Objects/Unit.cpp index bd617e6b81b..ef2ac17c981 100644 --- a/src/game/Objects/Unit.cpp +++ b/src/game/Objects/Unit.cpp @@ -1107,9 +1107,17 @@ void Unit::Kill(Unit* pVictim, SpellEntry const* spellProto, bool durabilityLoss pVictim->SetHealth(0); DEBUG_FILTER_LOG(LOG_FILTER_DAMAGE, "SET JUST_DIED"); pVictim->SetDeathState(JUST_DIED); - // Nostalrius: Instantly send values update for health + +// World of Warcraft Client Patch 1.6.0 (2005-07-12) +// - Self-resurrection spells show their name on the button in the release spirit dialog. +#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1 if (pPlayerVictim && pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL)) pVictim->DirectSendPublicValueUpdate(PLAYER_SELF_RES_SPELL); +#else + if (pPlayerVictim && pVictim->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT)) + pVictim->DirectSendPublicValueUpdate(PLAYER_FLAGS); +#endif + // Nostalrius: Instantly send values update for health pVictim->DirectSendPublicValueUpdate(UNIT_FIELD_HEALTH); } else @@ -1135,15 +1143,27 @@ void Unit::Kill(Unit* pVictim, SpellEntry const* spellProto, bool durabilityLoss if (spiritOfRedemtionTalentImmune) { // save value before aura remove - uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL); + uint32 ressSpellId = 0; +#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1 + ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL); if (!ressSpellId) + ressSpellId = ((Player*)pVictim)->SelectResurrectionSpellId(); +#else + if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT)) ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId(); +#endif //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) pVictim->RemoveAllAurasOnDeath(); // restore for use at real death +#if SUPPORTED_CLIENT_BUILD >= CLIENT_BUILD_1_6_1 pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); +#else + pPlayerVictim->SetResurrectionSpellId(ressSpellId); + if (ressSpellId) + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CAN_SELF_RESURRECT); +#endif // FORM_SPIRITOFREDEMPTION and related auras pVictim->AddAura(27827, ADD_AURA_NO_OPTION, pVictim);