mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-20 06:59:46 -04:00
Scripts/DK: correctly handle Blood Tap
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
-- Blood Tap
|
||||
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_dk_blood_tap';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(45529, 'spell_dk_blood_tap');
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user