aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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();
}