aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp74
-rw-r--r--src/server/game/Entities/Player/Player.h6
-rw-r--r--src/server/game/Spells/Spell.cpp12
-rw-r--r--src/server/game/Spells/Spell.h4
-rw-r--r--src/server/game/Spells/SpellEffects.cpp22
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp123
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();
}