aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorccrs <crs_92_19@hotmail.com>2015-06-02 04:57:14 +0200
committerShauren <shauren.trinity@gmail.com>2016-01-08 00:10:15 +0100
commite5d4005cc6f4450ba9cf3ab14b5b60daf3b3b889 (patch)
tree8da58aa6b683e31ce7e8c99101bbc9d2585a1dbb /src
parent91fa2154e892c1cc6d7769e39c50afce74c836fc (diff)
Core/Spells: Fixed Raise Ally
thx @Nayd for sniffs :) thx @Shauren for helping to find all spell involved * There is no implementation for stats update on Puppet class (only on Guardian) so same SummonProperty as Raise Dead Ghoul (non pet) is used. (Default SummonProperties set category to SUMMON_CATEGORY_PUPPET) * Override the Summon Effect to enable charm and stats scaling. * PlayerAI is used to handle unaura on ghoul despawn or dead. It's necessary due to the fact that all script hooks on ScriptedCreature are called on an unactive CreatureAI, resulting in creature being unable to handle unaura calls. * Create UpdateAI call for Player class * Stats scaling is based on forum and wowhead comments, they recall this ghoul as a copy of the other one (same stats). * Spellscript for Ghoul spell Thrash Closes #82 Closes #14830
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Creature/TemporarySummon.h5
-rw-r--r--src/server/game/Entities/Player/Player.cpp78
-rw-r--r--src/server/game/Entities/Player/Player.h16
-rw-r--r--src/server/game/Entities/Unit/StatSystem.cpp6
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp5
-rw-r--r--src/server/game/Entities/Unit/Unit.h1
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp7
-rw-r--r--src/server/game/Spells/Spell.cpp17
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp303
9 files changed, 414 insertions, 24 deletions
diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h
index afca851974a..6d058f405a8 100644
--- a/src/server/game/Entities/Creature/TemporarySummon.h
+++ b/src/server/game/Entities/Creature/TemporarySummon.h
@@ -72,9 +72,10 @@ class Minion : public TempSummon
Unit* GetOwner() const { return m_owner; }
float GetFollowAngle() const override { return m_followAngle; }
void SetFollowAngle(float angle) { m_followAngle = angle; }
- bool IsPetGhoul() const {return GetEntry() == 26125;} // Ghoul may be guardian or pet
- bool IsSpiritWolf() const {return GetEntry() == 29264;} // Spirit wolf from feral spirits
+ bool IsPetGhoul() const { return GetEntry() == 26125; } // Ghoul may be guardian or pet
+ bool IsSpiritWolf() const { return GetEntry() == 29264; } // Spirit wolf from feral spirits
bool IsGuardianPet() const;
+ bool IsRisenAlly() const { return GetEntry() == 30230; }
protected:
Unit* const m_owner;
float m_followAngle;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 52291cb6bf5..4fdf25e41c3 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1242,6 +1242,9 @@ void Player::Update(uint32 p_time)
if (charmer->GetTypeId() == TYPEID_UNIT && charmer->IsAlive())
UpdateCharmedAI();
+ if (GetAI() && IsAIEnabled)
+ GetAI()->UpdateAI(p_time);
+
// Update items that have just a limited lifetime
if (now > m_Last_tick)
UpdateItemDuration(uint32(now - m_Last_tick));
@@ -1476,8 +1479,8 @@ void Player::Update(uint32 p_time)
_pendingBindTimer -= p_time;
}
- // not auto-free ghost from body in instances
- if (m_deathTimer > 0 && !GetBaseMap()->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION))
+ // not auto-free ghost from body in instances or if its affected by risen ally
+ if (m_deathTimer > 0 && !GetBaseMap()->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION) && !IsGhouled())
{
if (p_time >= m_deathTimer)
{
@@ -2157,7 +2160,7 @@ bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) co
return true;
if (spellInfo->Effects[index].IsEffect(SPELL_EFFECT_ATTACK_ME))
return true;
-
+
return Unit::IsImmunedToSpellEffect(spellInfo, index);
}
@@ -4731,6 +4734,32 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
}
}
+void Player::SendGhoulResurrectRequest(Player* target)
+{
+ target->m_ghoulResurrectPlayerGUID = GetGUID();
+
+ WorldPacket data(SMSG_RESURRECT_REQUEST, 8 + 4 + 1 + 1);
+ data << uint64(GetGUID());
+ data << uint32(0);
+ data << uint8(0);
+ data << uint8(0);
+ target->GetSession()->SendPacket(&data);
+}
+
+void Player::GhoulResurrect()
+{
+ CastSpell(this, 46619 /*SPELL_DK_RAISE_ALLY*/, true, nullptr, nullptr, m_ghoulResurrectPlayerGUID);
+
+ m_ghoulResurrectPlayerGUID = ObjectGuid::Empty;
+}
+
+void Player::RemoveGhoul()
+{
+ if (IsGhouled())
+ if (Creature* ghoul = ObjectAccessor::GetCreature(*this, m_ghoulResurrectGhoulGUID))
+ ghoul->DespawnOrUnsummon(); // Raise Ally aura will handle unauras
+}
+
void Player::KillPlayer()
{
if (IsFlying() && !GetTransport())
@@ -18682,7 +18711,7 @@ bool Player::CheckInstanceValidity(bool /*isLogin*/)
// game masters' instances are always valid
if (IsGameMaster())
return true;
-
+
// non-instances are always valid
Map* map = GetMap();
if (!map || !map->IsDungeon())
@@ -20156,6 +20185,12 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
void Player::StopCastingCharm()
{
+ if (IsGhouled())
+ {
+ RemoveGhoul();
+ return;
+ }
+
Unit* charm = GetCharm();
if (!charm)
return;
@@ -21508,6 +21543,14 @@ void Player::setResurrectRequestData(ObjectGuid guid, uint32 mapId, float X, flo
m_resurrectHealth = health;
m_resurrectMana = mana;
}
+
+void Player::clearResurrectRequestData()
+{
+ setResurrectRequestData(ObjectGuid::Empty, 0, 0.0f, 0.0f, 0.0f, 0, 0);
+
+ m_ghoulResurrectPlayerGUID = ObjectGuid::Empty;
+ m_ghoulResurrectGhoulGUID = ObjectGuid::Empty;
+}
//slot to be excluded while counting
bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot)
{
@@ -23410,6 +23453,8 @@ uint32 Player::GetBaseWeaponSkillValue(WeaponAttackType attType) const
void Player::ResurrectUsingRequestData()
{
+ RemoveGhoul();
+
/// Teleport before resurrecting by player, otherwise the player might get attacked from creatures near his corpse
TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation());
@@ -23854,6 +23899,31 @@ void Player::SetViewpoint(WorldObject* target, bool apply)
//WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0);
//GetSession()->SendPacket(&data);
}
+
+ // HACK: Make sure update for PLAYER_FARSIGHT is received before SMSG_PET_SPELLS to properly hide "Release spirit" dialog
+ if (target->GetTypeId() == TYPEID_UNIT && static_cast<Unit*>(target)->HasUnitTypeMask(UNIT_MASK_MINION) && static_cast<Minion*>(target)->IsRisenAlly())
+ {
+ if (apply)
+ {
+ UpdateDataMapType update_players;
+ BuildUpdate(update_players);
+ WorldPacket packet;
+ for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
+ {
+ iter->second.BuildPacket(&packet);
+ iter->first->GetSession()->SendPacket(&packet);
+ packet.clear();
+ }
+ }
+ else
+ {
+ m_deathTimer = 6 * MINUTE * IN_MILLISECONDS;
+
+ // Reset "Release spirit" timer clientside
+ WorldPacket data(SMSG_FORCED_DEATH_UPDATE);
+ SendDirectMessage(&data);
+ }
+ }
}
WorldObject* Player::GetViewpoint() const
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 32a4fec27f2..e7af827e9c7 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1576,7 +1576,7 @@ class Player : public Unit, public GridObject<Player>
void UpdatePotionCooldown(Spell* spell = NULL);
void setResurrectRequestData(ObjectGuid guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana);
- void clearResurrectRequestData() { setResurrectRequestData(ObjectGuid::Empty, 0, 0.0f, 0.0f, 0.0f, 0, 0); }
+ void clearResurrectRequestData();
bool isResurrectRequestedBy(ObjectGuid guid) const { return !m_resurrectGUID.IsEmpty() && m_resurrectGUID == guid; }
bool isResurrectRequested() const { return !m_resurrectGUID.IsEmpty(); }
void ResurrectUsingRequestData();
@@ -1770,6 +1770,15 @@ class Player : public Unit, public GridObject<Player>
void ResurrectPlayer(float restore_percent, bool applySickness = false);
void BuildPlayerRepop();
void RepopAtGraveyard();
+ void SendGhoulResurrectRequest(Player* target);
+ bool IsValidGhoulResurrectRequest(ObjectGuid guid)
+ {
+ return !m_ghoulResurrectPlayerGUID.IsEmpty() && m_ghoulResurrectPlayerGUID == guid;
+ }
+ void GhoulResurrect();
+ void SetGhoulResurrectGhoulGUID(ObjectGuid guid) { m_ghoulResurrectGhoulGUID = guid; }
+ ObjectGuid GetGhoulResurrectGhoulGUID() { return m_ghoulResurrectGhoulGUID; }
+ void RemoveGhoul();
void DurabilityLossAll(double percent, bool inventory);
void DurabilityLoss(Item* item, double percent);
@@ -2403,6 +2412,9 @@ class Player : public Unit, public GridObject<Player>
float m_resurrectX, m_resurrectY, m_resurrectZ;
uint32 m_resurrectHealth, m_resurrectMana;
+ ObjectGuid m_ghoulResurrectPlayerGUID;
+ ObjectGuid m_ghoulResurrectGhoulGUID;
+
WorldSession* m_session;
typedef std::list<Channel*> JoinedChannelsList;
@@ -2502,7 +2514,7 @@ class Player : public Unit, public GridObject<Player>
bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; }
void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; }
void ScheduleDelayedOperation(uint32 operation) { if (operation < DELAYED_END) m_DelayedOperations |= operation; }
-
+
bool IsInstanceLoginGameMasterException() const;
MapReference m_mapRef;
diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp
index 775a3c96c46..a8e13a9f7db 100644
--- a/src/server/game/Entities/Unit/StatSystem.cpp
+++ b/src/server/game/Entities/Unit/StatSystem.cpp
@@ -499,7 +499,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
if (getClass() == CLASS_SHAMAN || getClass() == CLASS_PALADIN) // mental quickness
UpdateSpellDamageAndHealingBonus();
- if (pet && pet->IsPetGhoul()) // At melee attack power change for DK pet
+ if (pet && (pet->IsPetGhoul() || pet->IsRisenAlly())) // At melee attack power change for DK pet
pet->UpdateAttackPowerAndDamage();
if (guardian && guardian->IsSpiritWolf()) // At melee attack power change for Shaman feral spirit
@@ -1113,7 +1113,7 @@ bool Guardian::UpdateStats(Stats stat)
Unit* owner = GetOwner();
// Handle Death Knight Glyphs and Talents
float mod = 0.75f;
- if (IsPetGhoul() && (stat == STAT_STAMINA || stat == STAT_STRENGTH))
+ if ((IsPetGhoul() || IsRisenAlly()) && (stat == STAT_STAMINA || stat == STAT_STRENGTH))
{
if (stat == STAT_STAMINA)
mod = 0.3f; // Default Owner's Stamina scale
@@ -1329,7 +1329,7 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged)
bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f * mod;
SetBonusDamage(int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f * mod));
}
- else if (IsPetGhoul()) //ghouls benefit from deathknight's attack power (may be summon pet or not)
+ else if (IsPetGhoul() || IsRisenAlly()) //ghouls benefit from deathknight's attack power (may be summon pet or not)
{
bonusAP = owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.22f;
SetBonusDamage(int32(owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.1287f));
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index fcd2535dad9..261f4faf1a8 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -9395,7 +9395,7 @@ void Unit::SetMinion(Minion *minion, bool apply)
minion->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
// Ghoul pets have energy instead of mana (is anywhere better place for this code?)
- if (minion->IsPetGhoul())
+ if (minion->IsPetGhoul() || minion->IsRisenAlly())
minion->setPowerType(POWER_ENERGY);
// Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
@@ -13625,6 +13625,9 @@ void Unit::RemoveFromWorld()
RemoveAreaAurasDueToLeaveWorld();
+ if (IsCharmed())
+ RemoveCharmedBy(nullptr);
+
if (GetCharmerGUID())
{
TC_LOG_FATAL("entities.unit", "Unit %u has charmer guid when removed from world", GetEntry());
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 8fc93f24351..90d312f422a 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1598,6 +1598,7 @@ class Unit : public WorldObject
bool IsAlive() const { return (m_deathState == ALIVE); }
bool isDying() const { return (m_deathState == JUST_DIED); }
bool isDead() const { return (m_deathState == DEAD || m_deathState == CORPSE); }
+ bool IsGhouled() const { return HasAura(46619 /*SPELL_DK_RAISE_ALLY*/); }
DeathState getDeathState() const { return m_deathState; }
virtual void setDeathState(DeathState s); // overwrited in Creature/Player/Pet
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index e4ee057d6ea..758d5af83f7 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -71,6 +71,7 @@ void WorldSession::HandleRepopRequestOpcode(WorldPacket& recvData)
}
//this is spirit release confirm?
+ GetPlayer()->RemoveGhoul();
GetPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
GetPlayer()->BuildPlayerRepop();
GetPlayer()->RepopAtGraveyard();
@@ -776,6 +777,12 @@ void WorldSession::HandleResurrectResponseOpcode(WorldPacket& recvData)
return;
}
+ if (GetPlayer()->IsValidGhoulResurrectRequest(guid))
+ {
+ GetPlayer()->GhoulResurrect();
+ return;
+ }
+
if (!GetPlayer()->isResurrectRequestedBy(guid))
return;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index cb573f4ec3d..c677187e3d4 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -4207,21 +4207,16 @@ void Spell::SendResurrectRequest(Player* target)
{
// get resurrector name for creature resurrections, otherwise packet will be not accepted
// for player resurrections the name is looked up by guid
- std::string const sentName(m_caster->GetTypeId() == TYPEID_PLAYER
- ? ""
- : m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex()));
+ std::string const sentName(m_caster->GetTypeId() == TYPEID_PLAYER ?
+ "" : m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex()));
- WorldPacket data(SMSG_RESURRECT_REQUEST, (8+4+sentName.size()+1+1+1+4));
+ WorldPacket data(SMSG_RESURRECT_REQUEST, 8 + 4 + sentName.size() + 1 + 1 + 1);
data << uint64(m_caster->GetGUID());
data << uint32(sentName.size() + 1);
-
data << sentName;
- data << uint8(0); // null terminator
-
- data << uint8(m_caster->GetTypeId() == TYPEID_PLAYER ? 0 : 1); // "you'll be afflicted with resurrection sickness"
+ data << uint8(m_caster->IsSpiritHealer()); // "you'll be afflicted with resurrection sickness"
// override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute
- if (m_spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_RESURRECTION_TIMER))
- data << uint32(0);
+ data << uint8(!m_spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_RESURRECTION_TIMER));
target->GetSession()->SendPacket(&data);
}
@@ -5512,7 +5507,7 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
// dead owner (pets still alive when owners ressed?)
if (Unit* owner = m_caster->GetCharmerOrOwner())
- if (!owner->IsAlive())
+ if (!owner->IsAlive() && !owner->IsGhouled())
return SPELL_FAILED_CASTER_DEAD;
if (!target && m_targets.GetUnitTarget())
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 59caf4b7f7b..193ec7cbb02 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -22,6 +22,7 @@
*/
#include "Player.h"
+#include "UnitAI.h"
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
@@ -63,7 +64,10 @@ enum DeathKnightSpells
SPELL_DK_UNHOLY_PRESENCE = 48265,
SPELL_DK_UNHOLY_PRESENCE_TRIGGERED = 49772,
SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189,
- SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284
+ SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284,
+ SPELL_DK_RAISE_ALLY_INITIAL = 61999,
+ SPELL_DK_RAISE_ALLY = 46619,
+ SPELL_DK_GHOUL_THRASH = 47480
};
enum DeathKnightSpellIcons
@@ -1699,6 +1703,300 @@ public:
}
};
+enum RaiseAllyMisc
+{
+ TEXT_RISE_ALLY = 33055,
+
+ SPELL_DK_RISEN_GHOUL_SELF_STUN = 47466,
+ SPELL_DK_RISEN_GHOUL_SPAWN__IN = 47448,
+ SPELL_DK_SUMMON_HEAL = 36492,
+ SPELL_DK_DEATH_KNIGHT_RUNE_WEAPON_SCALING_02 = 51906,
+ SPELL_DK_DEATH_KNIGHT_PET_SCALING_01 = 54566,
+ SPELL_DK_DEATH_KNIGHT_PET_SCALING_03 = 61697,
+ SPELL_DK_MIRROR_NAME = 62224,
+ SPELL_DK_MIRROR_NAME_TRIGGERED = 62214,
+ SPELL_DK_PET_SCALING___MASTER_SPELL_03___INTELLECT_SPIRIT_RESILIENCE = 67557,
+ SPELL_DK_PET_SCALING___MASTER_SPELL_06___SPELL_HIT_EXPERTISE_SPELL_PENETRATION = 67561,
+
+ SPELL_GHOUL_FRENZY = 62218,
+
+ NPC_RISEN_ALLY = 30230
+};
+
+// 61999 - Raise Ally Initial
+class spell_dk_raise_ally_initial : public SpellScriptLoader
+{
+public:
+ spell_dk_raise_ally_initial() : SpellScriptLoader("spell_dk_raise_ally_initial") { }
+
+ class spell_dk_raise_ally_initial_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_dk_raise_ally_initial_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY_INITIAL))
+ return false;
+ return true;
+ }
+
+ SpellCastResult CheckCast()
+ {
+ // Raise Ally cannot be casted on alive players
+ Unit* target = GetExplTargetUnit();
+ if (target && target->IsAlive())
+ return SPELL_FAILED_TARGET_NOT_DEAD;
+ else if (GetCaster()->ToPlayer()->InArena())
+ return SPELL_FAILED_NOT_IN_ARENA;
+ else if (target->IsGhouled())
+ return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
+
+ return SPELL_CAST_OK;
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ Player* caster = GetCaster()->ToPlayer();
+ Player* target = GetHitPlayer();
+ if (caster && target)
+ caster->SendGhoulResurrectRequest(target);
+ }
+
+ void Register() override
+ {
+ OnCheckCast += SpellCheckCastFn(spell_dk_raise_ally_initial_SpellScript::CheckCast);
+ OnEffectHitTarget += SpellEffectFn(spell_dk_raise_ally_initial_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_dk_raise_ally_initial_SpellScript();
+ }
+};
+
+class player_ghoulAI : public PlayerAI
+{
+ public:
+ player_ghoulAI(Player* player, ObjectGuid ghoulGUID) : PlayerAI(player), _ghoulGUID(ghoulGUID) { }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (Creature* ghoul = ObjectAccessor::GetCreature(*me, _ghoulGUID))
+ {
+ if (!ghoul->IsAlive())
+ me->RemoveAura(SPELL_DK_RAISE_ALLY);
+ }
+ else
+ me->RemoveAura(SPELL_DK_RAISE_ALLY);
+ }
+
+ private:
+ ObjectGuid _ghoulGUID;
+};
+
+// 46619 - Raise Ally
+class spell_dk_raise_ally : public SpellScriptLoader
+{
+public:
+ spell_dk_raise_ally() : SpellScriptLoader("spell_dk_raise_ally") { }
+
+ class spell_dk_raise_ally_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_dk_raise_ally_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY))
+ return false;
+ return true;
+ }
+
+ void SendText()
+ {
+ Player* caster = GetCaster()->ToPlayer();
+ Unit* original = GetOriginalCaster();
+ if (caster && original)
+ original->Whisper(TEXT_RISE_ALLY, caster, true);
+ }
+
+ void HandleSummon(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ Unit* caster = GetCaster();
+ Unit* originalCaster = GetOriginalCaster();
+ if (!originalCaster)
+ return;
+
+ uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue);
+
+ //! HACK - StatSystem needs further develop to enable update on Puppet stats
+ // Using same summon properties as Raise Dead 46585 (Guardian) - EffectMiscValueB = 829
+ SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(829);
+
+ uint32 duration = uint32(GetSpellInfo()->GetDuration());
+ Position pos = caster->GetPosition();
+
+ TempSummon* summon = originalCaster->GetMap()->SummonCreature(entry, pos, properties, duration, originalCaster, GetSpellInfo()->Id);
+ if (!summon)
+ return;
+
+ //! Leaving this here as it's necessary if statsystem problem is solved
+ /*
+ Default SUMMON_CATEGORY_PUPPET behaviour sets possesor as originalCaster,
+ in this case we need caster as possesor and originalCaster as owner
+ */
+ //summon->RemoveCharmedBy(NULL);
+
+ summon->SetCharmedBy(caster, CHARM_TYPE_POSSESS);
+
+ summon->CastSpell(summon, SPELL_DK_RISEN_GHOUL_SELF_STUN, true);
+ summon->CastSpell(summon, SPELL_DK_RISEN_GHOUL_SPAWN__IN, true);
+ summon->CastSpell(summon, SPELL_DK_SUMMON_HEAL, true);
+ summon->CastSpell(caster, SPELL_DK_MIRROR_NAME, true);
+ caster->CastSpell(summon, SPELL_DK_MIRROR_NAME_TRIGGERED, true);
+ summon->CastSpell(summon, SPELL_DK_DEATH_KNIGHT_RUNE_WEAPON_SCALING_02, true);
+ summon->CastSpell(summon, SPELL_DK_DEATH_KNIGHT_PET_SCALING_01, true);
+ summon->CastSpell(summon, SPELL_DK_DEATH_KNIGHT_PET_SCALING_03, true);
+ summon->CastSpell(summon, SPELL_DK_PET_SCALING___MASTER_SPELL_03___INTELLECT_SPIRIT_RESILIENCE, true);
+ summon->CastSpell(summon, SPELL_DK_PET_SCALING___MASTER_SPELL_06___SPELL_HIT_EXPERTISE_SPELL_PENETRATION, true);
+
+ // SMSG_POWER_UPDATE is sent
+ summon->SetMaxPower(POWER_ENERGY, 100);
+
+ if (Player* player = GetCaster()->ToPlayer())
+ player->SetGhoulResurrectGhoulGUID(summon->GetGUID());
+ }
+
+ void Register() override
+ {
+ AfterHit += SpellHitFn(spell_dk_raise_ally_SpellScript::SendText);
+ OnEffectHit += SpellEffectFn(spell_dk_raise_ally_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_dk_raise_ally_SpellScript();
+ }
+
+ class spell_dk_raise_ally_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_raise_ally_AuraScript);
+
+ public:
+ spell_dk_raise_ally_AuraScript()
+ {
+ oldAI = nullptr;
+ oldAIState = false;
+ }
+
+ private:
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_ALLY))
+ return false;
+ return true;
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Player* player = GetTarget()->ToPlayer();
+ if (!player || player->GetGhoulResurrectGhoulGUID().IsEmpty())
+ return;
+
+ oldAI = player->GetAI();
+ oldAIState = player->IsAIEnabled;
+ player->SetAI(new player_ghoulAI(player, player->GetGhoulResurrectGhoulGUID()));
+ player->IsAIEnabled = true;
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Player* player = GetTarget()->ToPlayer();
+ if (!player)
+ return;
+
+ player->IsAIEnabled = oldAIState;
+ UnitAI* thisAI = player->GetAI();
+ player->SetAI(oldAI);
+ delete thisAI;
+
+ // Dismiss ghoul if necessary
+ if (Creature* ghoul = ObjectAccessor::GetCreature(*player, player->GetGhoulResurrectGhoulGUID()))
+ {
+ ghoul->RemoveCharmedBy(nullptr);
+ ghoul->DespawnOrUnsummon(1000);
+ }
+
+ player->SetGhoulResurrectGhoulGUID(ObjectGuid::Empty);
+ player->RemoveAura(SPELL_GHOUL_FRENZY);
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_dk_raise_ally_AuraScript::OnApply, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_dk_raise_ally_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+
+ UnitAI* oldAI;
+ bool oldAIState;
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_dk_raise_ally_AuraScript();
+ }
+};
+
+// 47480 - Thrash
+class spell_dk_ghoul_thrash : public SpellScriptLoader
+{
+public:
+ spell_dk_ghoul_thrash() : SpellScriptLoader("spell_dk_ghoul_thrash") { }
+
+ class spell_dk_ghoul_thrash_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_dk_ghoul_thrash_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_GHOUL_THRASH))
+ return false;
+ return true;
+ }
+
+ void CalcDamage()
+ {
+ if (Aura* aur = GetCaster()->GetAura(SPELL_GHOUL_FRENZY))
+ {
+ int32 damage = GetHitDamage();
+ damage += int32(GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK) * 0.05f * aur->GetStackAmount());
+ aur->Remove();
+ SetHitDamage(damage);
+ }
+
+ /*
+ Also remove aura from charmer
+ SPELL_GHOUL_FRENZY (62218) - Targets (1, 27) (TARGET_UNIT_CASTER, TARGET_UNIT_MASTER)
+ */
+ if (Unit* charmer = GetCaster()->GetCharmer())
+ charmer->RemoveAura(SPELL_GHOUL_FRENZY);
+ }
+
+ void Register() override
+ {
+ OnHit += SpellHitFn(spell_dk_ghoul_thrash_SpellScript::CalcDamage);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_dk_ghoul_thrash_SpellScript();
+ }
+};
+
void AddSC_deathknight_spell_scripts()
{
new spell_dk_anti_magic_shell_raid();
@@ -1729,4 +2027,7 @@ void AddSC_deathknight_spell_scripts()
new spell_dk_vampiric_blood();
new spell_dk_will_of_the_necropolis();
new spell_dk_death_grip_initial();
+ new spell_dk_raise_ally_initial();
+ new spell_dk_raise_ally();
+ new spell_dk_ghoul_thrash();
}