diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 74 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 6 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 12 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 22 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_dk.cpp | 123 |
6 files changed, 190 insertions, 51 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 355c1de617c..54f48802077 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22596,6 +22596,8 @@ void Player::SendInitialPacketsBeforeAddToMap() // SMSG_UPDATE_WORLD_STATE // SMSG_POWER_UPDATE + ResyncRunes(); + SetMovedUnit(this); } @@ -24514,46 +24516,73 @@ void Player::SetRuneCooldown(uint8 index, uint32 cooldown, bool casted /*= false m_runes->runes[index].Cooldown = cooldown; m_runes->SetRuneState(index, (cooldown == 0) ? true : false); + + ResyncRunes(); } void Player::SetRuneConvertAura(uint8 index, AuraEffect const* aura) { - m_runes->runes[index].ConvertAura = aura; + m_runes->runes[index].ConvertAuras.insert(aura); +} + +void Player::RemoveRuneConvertAura(uint8 index, AuraEffect const* aura) +{ + m_runes->runes[index].ConvertAuras.erase(aura); } void Player::AddRuneByAuraEffect(uint8 index, RuneType newType, AuraEffect const* aura) { - SetRuneConvertAura(index, aura); ConvertRune(index, newType); + SetRuneConvertAura(index, aura); + ConvertRune(index, newType); } void Player::RemoveRunesByAuraEffect(AuraEffect const* aura) { - for (uint8 i = 0; i < MAX_RUNES; ++i) + for (uint8 itr = 0; itr < MAX_RUNES; ++itr) { - if (m_runes->runes[i].ConvertAura == aura) - { - ConvertRune(i, GetBaseRune(i)); - SetRuneConvertAura(i, nullptr); - } + RemoveRuneConvertAura(itr, aura); + + if (m_runes->runes[itr].ConvertAuras.empty()) + ConvertRune(itr, GetBaseRune(itr)); } } void Player::RestoreBaseRune(uint8 index) { - AuraEffect const* aura = m_runes->runes[index].ConvertAura; - // If rune was converted by a non-passive aura that still active we should keep it converted - if (aura && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_PASSIVE)) + std::unordered_set<AuraEffect const*>& auras = m_runes->runes[index].ConvertAuras; + + AuraEffect const* aura = nullptr; + for (auto itr = auras.begin(); itr != auras.end() && !aura;) + { + if (AuraEffect const* temp = *itr) + { + if (temp->GetSpellInfo()->HasAttribute(SPELL_ATTR0_PASSIVE)) + { + aura = temp; + auras.erase(itr); + } + else + ++itr; + } + else + itr = auras.erase(itr); + } + + if (!auras.empty()) return; + ConvertRune(index, GetBaseRune(index)); - SetRuneConvertAura(index, nullptr); + // Don't drop passive talents providing rune convertion if (!aura || aura->GetAuraType() != SPELL_AURA_CONVERT_RUNE) return; - for (uint8 i = 0; i < MAX_RUNES; ++i) + + for (uint8 itr = 0; itr < MAX_RUNES; ++itr) { - if (aura == m_runes->runes[i].ConvertAura) + if (m_runes->runes[itr].ConvertAuras.find(aura) != m_runes->runes[itr].ConvertAuras.end()) return; } + aura->GetBase()->Remove(); } @@ -24567,14 +24596,19 @@ void Player::ConvertRune(uint8 index, RuneType newType) SendDirectMessage(&data); } -void Player::ResyncRunes(uint8 count) const +void Player::ResyncRunes() const { - WorldPacket data(SMSG_RESYNC_RUNES, 4 + count * 2); - data << uint32(count); - for (uint32 i = 0; i < count; ++i) + if (GetClass() != CLASS_DEATH_KNIGHT) + return; + + WorldPacket data(SMSG_RESYNC_RUNES, 4 + MAX_RUNES * 2); + data << uint32(MAX_RUNES); + for (uint32 itr = 0; itr < MAX_RUNES; ++itr) { - data << uint8(GetCurrentRune(i)); // rune type - data << uint8(255 - (GetRuneCooldown(i) * 51)); // passed cooldown time (0-255) + data << uint8(GetCurrentRune(itr)); // rune type + + uint32 value = uint32(255) - ((GetRuneCooldown(itr) * uint32(255)) / uint32(RUNE_BASE_COOLDOWN)); + data << uint8(value); // passed cooldown time (0-255) } SendDirectMessage(&data); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 00ee3aa2bf8..16a90dc7e23 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -32,6 +32,7 @@ #include "QuestDef.h" #include <memory> #include <queue> +#include <unordered_set> struct AccessRequirement; struct AchievementEntry; @@ -276,7 +277,7 @@ struct RuneInfo uint8 BaseRune; uint8 CurrentRune; uint32 Cooldown; - AuraEffect const* ConvertAura; + std::unordered_set<AuraEffect const*> ConvertAuras; }; struct Runes @@ -2118,11 +2119,12 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SetCurrentRune(uint8 index, RuneType currentRune) { m_runes->runes[index].CurrentRune = currentRune; } void SetRuneCooldown(uint8 index, uint32 cooldown, bool casted = false); void SetRuneConvertAura(uint8 index, AuraEffect const* aura); + void RemoveRuneConvertAura(uint8 index, AuraEffect const* aura); void AddRuneByAuraEffect(uint8 index, RuneType newType, AuraEffect const* aura); void RemoveRunesByAuraEffect(AuraEffect const* aura); void RestoreBaseRune(uint8 index); void ConvertRune(uint8 index, RuneType newType); - void ResyncRunes(uint8 count) const; + void ResyncRunes() const; void AddRunePower(uint8 index) const; void InitRunes(); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index f9edb30ec30..60e3cb3808f 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4160,7 +4160,7 @@ void Spell::SendSpellGo() castFlags |= CAST_FLAG_PENDING; if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA)) - castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual + castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual if ((m_caster->GetTypeId() == TYPEID_PLAYER || (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet())) @@ -4173,12 +4173,12 @@ void Spell::SendSpellGo() && m_spellInfo->PowerType == POWER_RUNE && !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)) { - castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it - castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list + castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it + castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list } if (m_spellInfo->HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) - castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list + castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list if (m_targets.HasTraj()) castFlags |= CAST_FLAG_ADJUST_MISSILE; @@ -4207,12 +4207,12 @@ void Spell::SendSpellGo() if (castFlags & CAST_FLAG_POWER_LEFT_SELF) castData.RemainingPower = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(m_spellInfo->PowerType); - if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list + if (castFlags & CAST_FLAG_RUNE_LIST && !m_spellInfo->HasAura(SPELL_AURA_CONVERT_RUNE)) // rune cooldowns list { castData.RemainingRunes = boost::in_place(); /// @todo There is a crash caused by a spell with CAST_FLAG_RUNE_LIST cast by a creature - //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster + // The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster if (Player* player = m_caster->ToPlayer()) { uint8 runeMaskInitial = m_runesState; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 08c80d8518e..13d15773e3d 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -540,6 +540,8 @@ class TC_GAME_API Spell uint64 GetDelayMoment() const { return m_delayMoment; } uint64 CalculateDelayMomentForDst() const; void RecalculateDelayMomentForDst(); + uint8 GetRuneState() const { return m_runesState; } + void SetRuneState(uint8 value) { m_runesState = value; } bool IsNeedSendToClient() const; @@ -577,7 +579,7 @@ class TC_GAME_API Spell // e.g. damage around area spell trigered by victim aura and damage enemies of aura caster Unit* m_originalCaster; // cached pointer for m_originalCaster, updated at Spell::UpdatePointers() - //Spell data + // Spell data SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example) WeaponAttackType m_attackType; // For weapon based attack int32 m_powerCost; // Calculated spell cost initialized only in Spell::prepare diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 701c503f8dd..4b68744fc0a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -5036,28 +5036,6 @@ void Spell::EffectActivateRune(SpellEffIndex effIndex) if (count == 0) count = 1; - // Blood Tap - if (m_spellInfo->Id == 45529 && count > 0) - { - for (uint32 l = 0; l + 1 < MAX_RUNES && count > 0; ++l) - { - // Check if both runes are on cd as that is the only time when this needs to come into effect - if ((player->GetRuneCooldown(l) && player->GetBaseRune(l) == RUNE_BLOOD) && (player->GetRuneCooldown(l + 1) && player->GetBaseRune(l + 1) == RUNE_BLOOD)) - { - // Should always update the rune with the lowest cd - if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l + 1)) - ++l; - - player->SetRuneCooldown(l, 0); - --count; - // is needed to push through to the client that the rune is active - player->ResyncRunes(MAX_RUNES); - } - else - break; - } - } - for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j) { if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue)) diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 4c80eb38327..b5d2b8935a5 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -31,10 +31,12 @@ #include "PlayerAI.h" #include "Spell.h" #include "SpellAuraEffects.h" +#include "SpellAuras.h" #include "SpellHistory.h" #include "SpellMgr.h" #include "SpellScript.h" #include "TemporarySummon.h" +#include "Unit.h" enum DeathKnightSpells { @@ -3049,6 +3051,126 @@ public: } }; +#define DKBloodTapScriptName "spell_dk_blood_tap" + +// 45529 - Blood Tap +class spell_dk_blood_tap : public SpellScriptLoader +{ +public: + spell_dk_blood_tap() : SpellScriptLoader(DKBloodTapScriptName) { } + + class spell_dk_blood_tap_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dk_blood_tap_AuraScript); + + public: + spell_dk_blood_tap_AuraScript() + { + _runeIndex = MAX_RUNES; + } + + void SetRuneIndex(uint8 index) + { + _runeIndex = index; + } + + void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + PreventDefaultAction(); + + Player* player = GetTarget()->ToPlayer(); + if (!player) + return; + + if (player->GetClass() != CLASS_DEATH_KNIGHT || _runeIndex == MAX_RUNES) + return; + + player->AddRuneByAuraEffect(_runeIndex, RUNE_DEATH, aurEff); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_dk_blood_tap_AuraScript::HandleApply, EFFECT_1, SPELL_AURA_CONVERT_RUNE, AURA_EFFECT_HANDLE_REAL); + } + + private: + uint8 _runeIndex; + }; + + AuraScript* GetAuraScript() const override + { + return new spell_dk_blood_tap_AuraScript(); + } + + class spell_dk_blood_tap_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_blood_tap_SpellScript); + + public: + spell_dk_blood_tap_SpellScript() + { + _runeIndex = MAX_RUNES; + } + + void HandleEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + Unit* caster = GetCaster(); + if (caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* player = caster->ToPlayer(); + if (player->GetClass() != CLASS_DEATH_KNIGHT) + return; + + // needed later + if (Spell* spell = GetSpell()) + spell->SetRuneState(caster->ToPlayer()->GetRunesState()); + + uint8 resetIndex; + // Rune reset: + // If both runes are on cooldown, reset the shorter one + // If only one rune is on cooldown, reset that rune + if (!player->GetRuneCooldown(1)) + resetIndex = 0; // 1 is ready, so reset 0 (no matter if it's on cd) + else if (!player->GetRuneCooldown(0) || player->GetRuneCooldown(1) < player->GetRuneCooldown(0)) + resetIndex = 1; // 0 is ready, or both are on cd and 1 is shorter, so reset 1 + else + resetIndex = 0; // both are on cd and 0 is shorter, reset 0 + + // if both runes are the same type, transform the same one as above + if (player->GetCurrentRune(0) == player->GetCurrentRune(1)) + _runeIndex = resetIndex; + else // otherwise transform the blood rune + _runeIndex = player->GetCurrentRune(0) == RUNE_BLOOD ? 0 : 1; + + player->SetRuneCooldown(resetIndex, 0); + } + + void SetRuneIndex(SpellEffIndex /*effIndex*/) + { + if (Aura* aura = GetHitAura()) + if (spell_dk_blood_tap_AuraScript* script = aura->GetScript<spell_dk_blood_tap_AuraScript>(DKBloodTapScriptName)) + script->SetRuneIndex(_runeIndex); + } + + void Register() override + { + OnEffectLaunch += SpellEffectFn(spell_dk_blood_tap_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_ACTIVATE_RUNE); + OnEffectHitTarget += SpellEffectFn(spell_dk_blood_tap_SpellScript::SetRuneIndex, EFFECT_1, SPELL_EFFECT_APPLY_AURA); + } + + private: + uint8 _runeIndex; + }; + + SpellScript* GetSpellScript() const override + { + return new spell_dk_blood_tap_SpellScript(); + } +}; + void AddSC_deathknight_spell_scripts() { new spell_dk_acclimation(); @@ -3104,4 +3226,5 @@ void AddSC_deathknight_spell_scripts() new spell_dk_raise_ally_initial(); new spell_dk_raise_ally(); new spell_dk_ghoul_thrash(); + new spell_dk_blood_tap(); } |