diff options
-rw-r--r-- | sql/updates/world/2016_01_08_00_world.sql | 18 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/TemporarySummon.h | 5 | ||||
-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, 432 insertions, 24 deletions
diff --git a/sql/updates/world/2016_01_08_00_world.sql b/sql/updates/world/2016_01_08_00_world.sql new file mode 100644 index 00000000000..55ed3ddf336 --- /dev/null +++ b/sql/updates/world/2016_01_08_00_world.sql @@ -0,0 +1,18 @@ +UPDATE `creature_template` SET +`spell1` = 62225, -- Claw +`spell2` = 47480, -- Thrash +`spell3` = 47481, -- Gnaw +`spell4` = 47482, -- Leap +`spell5` = 47484, -- Huddle +`spell6` = 47496 -- Explode +WHERE `entry` = 30230; + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_dk_raise_ally_initial', 'spell_dk_raise_ally', 'spell_dk_ghoul_thrash'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(61999, 'spell_dk_raise_ally_initial'), +(46619, 'spell_dk_raise_ally'), +(47480, 'spell_dk_ghoul_thrash'); + +DELETE FROM `spell_dbc` WHERE `Id`=62214; +INSERT INTO `spell_dbc` (`Id`,`Attributes`,`AttributesEx`,`AttributesEx2`,`AttributesEx3`,`AttributesEx4`,`AttributesEx5`,`AttributesEx6`,`DurationIndex`,`RangeIndex`,`Effect1`,`EffectImplicitTargetA1`,`EffectApplyAuraName1`,`Comment`) VALUES +(62214,0xA9800100,0x10000420,0x10084005,0x00130000,0x00800080,0x00060008,0x00001404,21,13,6,25,279,'Mirror Name'); 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(); } |