diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/Entities/Creature/TemporarySummon.h | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 78 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 16 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/StatSystem.cpp | 6 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 1 | ||||
| -rw-r--r-- | src/server/game/Handlers/MiscHandler.cpp | 7 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 17 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_dk.cpp | 303 | 
10 files changed, 416 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/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 9aabed67243..6f0b9f89e44 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1803,6 +1803,8 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /*= true      if (Unit* owner = GetOwner())      {          trigger->setFaction(owner->getFaction()); +        if (owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)) +            trigger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);          // needed for GO casts for proper target validation checks          trigger->SetOwnerGUID(owner->GetGUID());          trigger->CastSpell(target ? target : trigger, spellInfo, triggered, nullptr, nullptr, owner->GetGUID()); 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();  }  | 
