diff --git a/sql/updates/world/custom/custom_2018_09_16_01_world.sql b/sql/updates/world/custom/custom_2018_09_16_01_world.sql new file mode 100644 index 0000000000..998bd1a1fd --- /dev/null +++ b/sql/updates/world/custom/custom_2018_09_16_01_world.sql @@ -0,0 +1,29 @@ +-- Template Updates +-- Bloodlord Mandokir +UPDATE `creature_template` SET `ScriptName`= 'boss_bloodlord_mandokir' WHERE `ScriptName`= 'boss_mandokir'; +UPDATE `creature_template` SET `DamageModifier`= 60, `BaseVariance`= 0.5, `mechanic_immune_mask`= 617299839, `mingold`= 20000, `maxgold`= 21000, `lootid`= 52151 WHERE `entry`= 52151; +-- Ohgan +UPDATE `creature_template` SET `ScriptName`= 'npc_mandokir_ohgan' WHERE `ScriptName`= 'npc_ohgan'; +UPDATE `creature_template` SET `DamageModifier`= 60, `BaseVariance`= 0.5, `mechanic_immune_mask`= 617299839 WHERE `entry`= 52157; +-- Chained Spirit +UPDATE `creature_template` SET `ScriptName`= 'npc_mandokir_chained_spirit' WHERE `ScriptName`= 'npc_chained_spirit'; + +-- Template Addons +UPDATE `creature_template_addon` SET `mount`= 34408 WHERE `entry`= 52151; + +-- Loot +DELETE FROM `creature_onkill_reward` WHERE `creature_id`= 52151; +INSERT INTO `creature_onkill_reward` (`creature_id`, `CurrencyId1`, `CurrencyCount1`) VALUES +(52151, 395, 7000); + +DELETE FROM `creature_loot_template` WHERE `Entry`= 52151; +INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Chance`, `LootMode`, `Reference`, `MaxCount`) VALUES +(52151, 521510, 100, 1, 521510, 1); + +DELETE FROM `reference_loot_template` WHERE `Entry`= 521510; +INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Chance`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`) VALUES +(521510, 69609, 0, 1, 1, 1, 1), +(521510, 69607, 0, 1, 1, 1, 1), +(521510, 69605, 0, 1, 1, 1, 1), +(521510, 69606, 0, 1, 1, 1, 1), +(521510, 69608, 0, 1, 1, 1, 1); diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_bloodlord_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_bloodlord_mandokir.cpp new file mode 100644 index 0000000000..aafc9b2c30 --- /dev/null +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_bloodlord_mandokir.cpp @@ -0,0 +1,705 @@ +/* + * Copyright (C) 2008-2018 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "ScriptMgr.h" +#include "GridNotifiers.h" +#include "InstanceScript.h" +#include "MotionMaster.h" +#include "ObjectAccessor.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "zulgurub.h" + +enum Yells +{ + SAY_AGGRO = 0, + SAY_PLAYER_KILL = 1, + SAY_SUMMON_OHGAN = 2, + EMOTE_DEVASTATING_SLAM = 3, + SAY_REANIMATE_OHGAN = 4, + EMOTE_FRENZY = 5, + SAY_FRENZY = 6, + SAY_DEATH = 7 +}; + +enum Spells +{ + // Bloodlord Mandokir + SPELL_BLOODLORD_AURA = 96480, + SPELL_SUMMON_OHGAN = 96717, + SPELL_REANIMATE_OHGAN = 96724, + SPELL_DECAPITATE = 96682, + SPELL_BLOODLETTING = 96776, + SPELL_BLOODLETTING_DAMAGE = 96777, + SPELL_BLOODLETTING_HEAL = 96778, + SPELL_FRENZY = 96800, + SPELL_LEVEL_UP = 96662, + SPELL_DEVASTATING_SLAM = 96740, + SPELL_DEVASTATING_SLAM_TRIGGER = 96761, + SPELL_DEVASTATING_SLAM_DAMAGE = 97385, + SPELL_SPIRIT_VENGEANCE_CANCEL = 96821, + + // Chained Spirit + SPELL_REVIVE = 96484, + + // Ohgan + SPELL_OHGAN_HEART_VISUAL = 96727, + SPELL_PERMANENT_FEIGN_DEATH = 96733, + SPELL_CLEAR_ALL = 28471, + SPELL_OHGAN_ORDERS = 96721, + SPELL_OHGAN_ORDERS_TRIGGER = 96722 +}; + +enum Events +{ + // Bloodlord Mandokir + EVENT_SUMMON_OHGAN = 1, + EVENT_TALK_SUMMON_OHGAN, + EVENT_DECAPITATE, + EVENT_BLOODLETTING, + EVENT_REANIMATE_OHGAN, + EVENT_REANIMATE_OHGAN_COOLDOWN, + EVENT_DEVASTATING_SLAM, + + // Ohgan + EVENT_OHGANS_ORDERS, + EVENT_ATTACK_PLAYERS, +}; + +enum Action +{ + // Bloodlord Mandokir + ACTION_OHGAN_IS_DEATH = 1, + ACTION_START_REVIVE = 2, + + // Chained Spirit + ACTION_REVIVE = 1 +}; + +enum Misc +{ + POINT_START_REVIVE = 1, + DATA_OHGANOT_SO_FAST = 5762, + FACTION_TEMPLATE_CHAINED_SPIRITS = 1665 +}; + +enum SummonGroups +{ + SUMMON_GROUP_CHAINED_SPIRIT = 0 +}; + +struct boss_bloodlord_mandokir : public BossAI +{ + boss_bloodlord_mandokir(Creature* creature) : BossAI(creature, DATA_BLOODLORD_MANDOKIR) { } + + void Reset() override + { + _Reset(); + me->SummonCreatureGroup(SUMMON_GROUP_CHAINED_SPIRIT); + _ohganotSoFast = true; + _reanimateOhganCooldown = false; + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + Talk(SAY_AGGRO); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + + DoCastAOE(SPELL_BLOODLORD_AURA); + events.ScheduleEvent(EVENT_DECAPITATE, 10s); + events.ScheduleEvent(EVENT_BLOODLETTING, 15s); + events.ScheduleEvent(EVENT_SUMMON_OHGAN, 20s); + events.ScheduleEvent(EVENT_DEVASTATING_SLAM, 25s); + + for (ObjectGuid guid : summons) + if (Creature* creature = ObjectAccessor::GetCreature(*me, guid)) + if (creature->GetEntry() == NPC_CHAINED_SPIRIT) + creature->SetFaction(FACTION_TEMPLATE_CHAINED_SPIRITS); + } + + void JustDied(Unit* /*killer*/) override + { + DoCastAOE(SPELL_SPIRIT_VENGEANCE_CANCEL, true); + _JustDied(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLOODLETTING); + Talk(SAY_DEATH); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + summons.DespawnAll(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLOODLETTING); + DoCastAOE(SPELL_SPIRIT_VENGEANCE_CANCEL, true); + _DespawnAtEvade(); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + { + Talk(SAY_PLAYER_KILL); + DoCastSelf(SPELL_LEVEL_UP, true); + _reviveGUID = victim->GetGUID(); + DoAction(ACTION_START_REVIVE); + } + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + if (summon->GetEntry() == NPC_DEVASTATING_SLAM) + { + DoCastSelf(SPELL_DEVASTATING_SLAM); + me->SetFacingToObject(summon); + + float angle = me->GetAngle(summon); + + // 31 casts in total - 11 in the center line and 10 on the outer lines + for (uint8 i = 1; i < 12; i++) + { + float angleOffset = i > 1 ? -0.3f : 0.0f; + + for (uint8 j = 0; j < (i > 1 ? 3 : 1); j++) + { + float x = me->GetPositionX() + cos(angle + angleOffset) * (i * 6.0f); + float y = me->GetPositionY() + sin(angle + angleOffset) * (i * 6.0f); + float z = me->GetPositionZ(); + angleOffset += 0.3f; + me->CastSpell(x, y, z, SPELL_DEVASTATING_SLAM_DAMAGE, true); + } + } + } + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (me->HealthBelowPctDamaged(20, damage) && !me->HasAura(SPELL_FRENZY)) + { + DoCast(me, SPELL_FRENZY, true); + Talk(SAY_FRENZY); + Talk(EMOTE_FRENZY); + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_OHGAN_IS_DEATH: + events.ScheduleEvent(EVENT_REANIMATE_OHGAN, 4s); + _ohganotSoFast = false; + break; + case ACTION_START_REVIVE: + { + std::list creatures; + GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f); + creatures.remove_if(Trinity::AnyDeadUnitCheck()); + creatures.remove_if(Trinity::UnitAuraCheck(true, SPELL_OHGAN_ORDERS_TRIGGER)); + Trinity::Containers::RandomResize(creatures, 1); + if (creatures.empty()) + return; + + for (Creature* chainedSpirit : creatures) + { + chainedSpirit->AI()->SetGUID(_reviveGUID); + chainedSpirit->AI()->DoAction(ACTION_REVIVE); + _reviveGUID.Clear(); + } + break; + } + default: + break; + + } + } + + uint32 GetData(uint32 type) const override + { + if (type == DATA_OHGANOT_SO_FAST) + return _ohganotSoFast; + + return 0; + } + + void SetGUID(ObjectGuid const& guid, int32 /*id = 0 **/) override + { + _reviveGUID = guid; + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SUMMON_OHGAN: + me->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); + DoCast(me, SPELL_SUMMON_OHGAN, true); + events.ScheduleEvent(EVENT_TALK_SUMMON_OHGAN, 2s + 400ms); + break; + case EVENT_TALK_SUMMON_OHGAN: + Talk(SAY_SUMMON_OHGAN); + if (Creature* ohgan = instance->GetCreature(DATA_OHGAN)) + ohgan->HandleEmoteCommand(EMOTE_ONESHOT_MOUNT_SPECIAL); + break; + case EVENT_DECAPITATE: + DoCastAOE(SPELL_DECAPITATE); + events.Repeat(me->HasAura(SPELL_FRENZY) ? 17s + 500ms : 35s); + break; + case EVENT_BLOODLETTING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCast(target, SPELL_BLOODLETTING, true); + + events.Repeat(25s); + break; + case EVENT_REANIMATE_OHGAN: + if (_reanimateOhganCooldown) + events.Repeat(1s); + else + { + DoCastAOE(SPELL_REANIMATE_OHGAN); + Talk(SAY_REANIMATE_OHGAN); + // Cooldown + _reanimateOhganCooldown = true; + events.ScheduleEvent(EVENT_REANIMATE_OHGAN_COOLDOWN, 20s); + } + break; + case EVENT_REANIMATE_OHGAN_COOLDOWN: + _reanimateOhganCooldown = false; + break; + case EVENT_DEVASTATING_SLAM: + DoCastAOE(SPELL_DEVASTATING_SLAM_TRIGGER); + events.Repeat(30s); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + +private: + bool _ohganotSoFast; + bool _reanimateOhganCooldown; + ObjectGuid _reviveGUID; +}; + +struct npc_mandokir_ohgan : public ScriptedAI +{ + npc_mandokir_ohgan(Creature* creature) : ScriptedAI(creature), _instance(me->GetInstanceScript()) + { + Initialize(); + } + + void Initialize() + { + _allowPlayerCombat = false; + me->SetReactState(REACT_PASSIVE); + } + + void IsSummonedBy(Unit* /*summoner*/) override + { + _events.ScheduleEvent(EVENT_OHGANS_ORDERS, 4s + 500ms); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (damage >= me->GetHealth()) + { + damage = 0; + me->AttackStop(); + me->SetHealth(0); + me->SetTarget(ObjectGuid::Empty); + DoCast(me, SPELL_CLEAR_ALL, true); + DoCast(me, SPELL_PERMANENT_FEIGN_DEATH); + + if (Creature* mandokir = _instance->GetCreature(DATA_BLOODLORD_MANDOKIR)) + mandokir->AI()->DoAction(ACTION_OHGAN_IS_DEATH); + } + } + + void KilledUnit(Unit* victim) override + { + if (Creature* creature = victim->ToCreature()) + { + if (creature->GetEntry() == NPC_CHAINED_SPIRIT) + { + _events.ScheduleEvent(EVENT_ATTACK_PLAYERS, 1s); + DoCastAOE(SPELL_OHGAN_ORDERS); + } + } + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (target && spell->Id == SPELL_OHGAN_ORDERS) + _events.CancelEvent(EVENT_ATTACK_PLAYERS); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && _allowPlayerCombat) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_OHGANS_ORDERS: + DoCastAOE(SPELL_OHGAN_ORDERS); + break; + case EVENT_ATTACK_PLAYERS: + _allowPlayerCombat = true; + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* _instance; + EventMap _events; + bool _allowPlayerCombat; +}; + +struct npc_mandokir_chained_spirit : public PassiveAI +{ + npc_mandokir_chained_spirit(Creature* creature) : PassiveAI(creature), _instance(me->GetInstanceScript()) { } + + void Reset() override + { + me->AddUnitMovementFlag(MOVEMENTFLAG_HOVER); + _revivePlayerGUID.Clear(); + } + + void SetGUID(ObjectGuid const& guid, int32 /*id = 0 */) override + { + _revivePlayerGUID = guid; + } + + void DoAction(int32 action) override + { + if (action == ACTION_REVIVE) + { + Position pos; + if (Player* target = ObjectAccessor::GetPlayer(*me, _revivePlayerGUID)) + { + target->GetNearPoint(me, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, 5.0f, target->GetAngle(me)); + me->GetMotionMaster()->MovePoint(POINT_START_REVIVE, pos); + } + } + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE || !_revivePlayerGUID) + return; + + if (pointId == POINT_START_REVIVE) + { + if (Player* target = ObjectAccessor::GetPlayer(*me, _revivePlayerGUID)) + DoCast(target, SPELL_REVIVE); + + me->DespawnOrUnsummon(2s); + } + } + + void JustDied(Unit* /*killer*/) override + { + // We died before we could revive our player, so let another spirit do the job + if (!_revivePlayerGUID.IsEmpty()) + { + if (Player* target = ObjectAccessor::GetPlayer(*me, _revivePlayerGUID)) + { + if (Creature* mandokir = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BLOODLORD_MANDOKIR))) + { + mandokir->GetAI()->SetGUID(target->GetGUID()); + mandokir->GetAI()->DoAction(ACTION_START_REVIVE); + } + } + } + me->DespawnOrUnsummon(4s); + } + + void UpdateAI(uint32 /*diff*/) override { } + +private: + InstanceScript * _instance; + ObjectGuid _revivePlayerGUID; +}; + +class NonVictimTargetSelector +{ + public: + NonVictimTargetSelector(Creature* me) : _me(me) { } + + bool operator() (WorldObject* target) + { + if (Unit* victim = _me->GetVictim()) + return victim == target; + + return true; + } + + Creature* _me; +}; + +class spell_mandokir_decapitate : public SpellScript +{ + PrepareSpellScript(spell_mandokir_decapitate); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + targets.remove_if(NonVictimTargetSelector(GetCaster()->ToCreature())); + + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + if (Player* target = GetHitPlayer()) + caster->CastSpell(target, uint32(GetEffectValue()), true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mandokir_decapitate::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_mandokir_decapitate::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +class spell_mandokir_bloodletting : public AuraScript +{ + PrepareAuraScript(spell_mandokir_bloodletting); + + bool Validate(SpellInfo const* /*spell*/) override + { + return ValidateSpellInfo( + { + SPELL_BLOODLETTING_DAMAGE, + SPELL_BLOODLETTING_HEAL + }); + } + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + Unit* target = GetTarget(); + Unit* caster = GetCaster(); + if (!caster) + return; + + int32 damage = std::max(7500, target->CountPctFromCurHealth(aurEff->GetAmount())); + + caster->CastCustomSpell(target, SPELL_BLOODLETTING_DAMAGE, &damage, 0, 0, true); + target->CastCustomSpell(caster, SPELL_BLOODLETTING_HEAL, &damage, 0, 0, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mandokir_bloodletting::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } +}; + +class spell_mandokir_spirit_vengeance_cancel : public SpellScript +{ + PrepareSpellScript(spell_mandokir_spirit_vengeance_cancel); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Player* target = GetHitPlayer()) + target->RemoveAura(uint32(GetEffectValue())); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mandokir_spirit_vengeance_cancel::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + OnEffectHitTarget += SpellEffectFn(spell_mandokir_spirit_vengeance_cancel::HandleScript, EFFECT_1, SPELL_EFFECT_DUMMY); + } +}; + +class spell_mandokir_devastating_slam : public SpellScript +{ + PrepareSpellScript(spell_mandokir_devastating_slam); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + targets.remove_if(NonVictimTargetSelector(GetCaster()->ToCreature())); + + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleSummon(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].TriggerSpell, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mandokir_devastating_slam::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_mandokir_devastating_slam::HandleSummon, EFFECT_0, SPELL_EFFECT_FORCE_CAST); + } +}; + +class spell_mandokir_ohgan_orders : public SpellScript +{ + PrepareSpellScript(spell_mandokir_ohgan_orders); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + if (Unit* target = GetHitUnit()) + caster->CastSpell(target, uint32(GetEffectValue()), true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mandokir_ohgan_orders::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_mandokir_ohgan_orders::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +class spell_mandokir_ohgan_orders_trigger : public SpellScript +{ + PrepareSpellScript(spell_mandokir_ohgan_orders_trigger); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + // Enabling melee attacks to kill the spirits + caster->ClearUnitState(UNIT_STATE_CASTING); + + if (Creature* creature = caster->ToCreature()) + if (creature->IsAIEnabled) + creature->AI()->AttackStart(GetHitUnit()); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mandokir_ohgan_orders_trigger::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +class spell_mandokir_reanimate_ohgan : public SpellScript +{ + PrepareSpellScript(spell_mandokir_reanimate_ohgan); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->RemoveAura(SPELL_PERMANENT_FEIGN_DEATH); + target->CastSpell(target, SPELL_OHGAN_HEART_VISUAL, true); + target->CastSpell(target, SPELL_OHGAN_ORDERS, true); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mandokir_reanimate_ohgan::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +class spell_clear_all : public SpellScript +{ + PrepareSpellScript(spell_clear_all); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + caster->RemoveAllAurasOnDeath(); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_clear_all::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +class achievement_ohganot_so_fast : public AchievementCriteriaScript +{ + public: + achievement_ohganot_so_fast() : AchievementCriteriaScript("achievement_ohganot_so_fast") { } + + bool OnCheck(Player* /*player*/, Unit* target) + { + return target && target->GetAI()->GetData(DATA_OHGANOT_SO_FAST); + } +}; + +void AddSC_boss_mandokir() +{ + RegisterZulGurubCreatureAI(boss_bloodlord_mandokir); + RegisterZulGurubCreatureAI(npc_mandokir_ohgan); + RegisterZulGurubCreatureAI(npc_mandokir_chained_spirit); + RegisterSpellScript(spell_mandokir_decapitate); + RegisterAuraScript(spell_mandokir_bloodletting); + RegisterSpellScript(spell_mandokir_spirit_vengeance_cancel); + RegisterSpellScript(spell_mandokir_devastating_slam); + RegisterSpellScript(spell_mandokir_ohgan_orders); + RegisterSpellScript(spell_mandokir_ohgan_orders_trigger); + RegisterSpellScript(spell_mandokir_reanimate_ohgan); + RegisterSpellScript(spell_clear_all); + new achievement_ohganot_so_fast(); +} diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp deleted file mode 100644 index 64f5ef4d08..0000000000 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ /dev/null @@ -1,773 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "ScriptMgr.h" -#include "GridNotifiers.h" -#include "InstanceScript.h" -#include "MotionMaster.h" -#include "ObjectAccessor.h" -#include "Player.h" -#include "ScriptedCreature.h" -#include "SpellAuraEffects.h" -#include "SpellScript.h" -#include "zulgurub.h" - -enum Yells -{ - SAY_AGGRO = 0, - SAY_PLAYER_KILL = 1, - SAY_DISMOUNT_OHGAN = 2, - EMOTE_DEVASTATING_SLAM = 3, - SAY_REANIMATE_OHGAN = 4, - EMOTE_FRENZY = 5, - SAY_FRENZY = 6, - SAY_DEATH = 7 -}; - -enum Spells -{ - // Bloodlord Mandokir - SPELL_BLOODLORD_AURA = 96480, - SPELL_SUMMON_OHGAN = 96717, - SPELL_REANIMATE_OHGAN = 96724, - SPELL_DECAPITATE = 96682, - SPELL_BLOODLETTING = 96776, - SPELL_BLOODLETTING_DAMAGE = 96777, - SPELL_BLOODLETTING_HEAL = 96778, - SPELL_FRENZY = 96800, - SPELL_LEVEL_UP = 96662, - SPELL_DEVASTATING_SLAM = 96740, - SPELL_DEVASTATING_SLAM_TRIGGER = 96761, - SPELL_DEVASTATING_SLAM_DAMAGE = 97385, - SPELL_SPIRIT_VENGEANCE_CANCEL = 96821, - - // Chained Spirit - SPELL_REVIVE = 96484, - - // Ohgan - SPELL_OHGAN_HEART_VISUAL = 96727, - SPELL_PERMANENT_FEIGN_DEATH = 96733, - SPELL_CLEAR_ALL = 28471, - SPELL_OHGAN_ORDERS = 96721, - SPELL_OHGAN_ORDERS_TRIGGER = 96722 -}; - -enum Events -{ - // Bloodlord Mandokir - EVENT_SUMMON_OHGAN = 1, - EVENT_DECAPITATE = 2, - EVENT_BLOODLETTING = 3, - EVENT_REANIMATE_OHGAN = 4, - EVENT_REANIMATE_OHGAN_COOLDOWN = 5, - EVENT_DEVASTATING_SLAM = 6 -}; - -enum Action -{ - // Bloodlord Mandokir - ACTION_OHGAN_IS_DEATH = 1, - ACTION_START_REVIVE = 2, - - // Chained Spirit - ACTION_REVIVE = 1 -}; - -enum Misc -{ - POINT_START_REVIVE = 1, - - DATA_OHGANOT_SO_FAST = 5762 -}; - -enum SummonGroups -{ - SUMMON_GROUP_CHAINED_SPIRIT = 0 -}; - -class boss_mandokir : public CreatureScript -{ - public: - - boss_mandokir() : CreatureScript("boss_mandokir") { } - - struct boss_mandokirAI : public BossAI - { - boss_mandokirAI(Creature* creature) : BossAI(creature, DATA_BLOODLORD_MANDOKIR) { } - - void Reset() override - { - DoCastAOE(SPELL_SPIRIT_VENGEANCE_CANCEL); - - _Reset(); - - me->SummonCreatureGroup(SUMMON_GROUP_CHAINED_SPIRIT); - _ohganotSoFast = true; - _reanimateOhganCooldown = false; - _reviveGUID.Clear(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - Talk(SAY_AGGRO); - - DoCastAOE(SPELL_BLOODLORD_AURA); - - if (!summons.empty()) - { - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) - { - if (Creature* chainedSpirit = ObjectAccessor::GetCreature(*me, *itr)) - if (chainedSpirit->GetEntry() == NPC_CHAINED_SPIRIT && chainedSpirit->AI()) - chainedSpirit->SetFaction(FACTION_NONE); - } - } - - events.ScheduleEvent(EVENT_DECAPITATE, 10000); - events.ScheduleEvent(EVENT_BLOODLETTING, 15000); - events.ScheduleEvent(EVENT_SUMMON_OHGAN, 20000); - events.ScheduleEvent(EVENT_DEVASTATING_SLAM, 25000); - } - - void JustDied(Unit* /*killer*/) override - { - DoCastAOE(SPELL_SPIRIT_VENGEANCE_CANCEL); - _JustDied(); - Talk(SAY_DEATH); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - { - Talk(SAY_PLAYER_KILL); - DoCast(SPELL_LEVEL_UP); - _reviveGUID = victim->GetGUID(); - DoAction(ACTION_START_REVIVE); - } - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (me->HealthBelowPctDamaged(20, damage) && !me->HasAura(SPELL_FRENZY)) - { - DoCast(me, SPELL_FRENZY, true); - Talk(SAY_FRENZY); - Talk(EMOTE_FRENZY); - } - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_OHGAN_IS_DEATH: - events.ScheduleEvent(EVENT_REANIMATE_OHGAN, 4000); - _ohganotSoFast = false; - break; - case ACTION_START_REVIVE: - { - std::list creatures; - GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f); - creatures.remove_if(Trinity::AnyDeadUnitCheck()); - creatures.remove_if(Trinity::UnitAuraCheck(true, SPELL_OHGAN_ORDERS_TRIGGER)); - Trinity::Containers::RandomResize(creatures, 1); - if (creatures.empty()) - return; - - for (Creature* chainedSpirit : creatures) - { - chainedSpirit->AI()->SetGUID(_reviveGUID); - chainedSpirit->AI()->DoAction(ACTION_REVIVE); - _reviveGUID.Clear(); - } - break; - } - default: - break; - - } - } - - uint32 GetData(uint32 type) const override - { - if (type == DATA_OHGANOT_SO_FAST) - return _ohganotSoFast; - - return 0; - } - - void SetGUID(ObjectGuid const& guid, int32 /*id = 0 **/) override - { - _reviveGUID = guid; - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SUMMON_OHGAN: - me->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); - DoCast(me, SPELL_SUMMON_OHGAN, true); - break; - case EVENT_DECAPITATE: - DoCastAOE(SPELL_DECAPITATE); - events.ScheduleEvent(EVENT_DECAPITATE, me->HasAura(SPELL_FRENZY) ? 17500 : 35000); - break; - case EVENT_BLOODLETTING: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true)) - { - DoCast(target, SPELL_BLOODLETTING, true); - me->ClearUnitState(UNIT_STATE_CASTING); - } - events.ScheduleEvent(EVENT_BLOODLETTING, 25000); - break; - case EVENT_REANIMATE_OHGAN: - if (_reanimateOhganCooldown) - events.ScheduleEvent(EVENT_REANIMATE_OHGAN, 1000); - else - { - DoCastAOE(SPELL_REANIMATE_OHGAN); - Talk(SAY_REANIMATE_OHGAN); - // Cooldown - _reanimateOhganCooldown = true; - events.ScheduleEvent(EVENT_REANIMATE_OHGAN_COOLDOWN, 20000); - } - break; - case EVENT_REANIMATE_OHGAN_COOLDOWN: - _reanimateOhganCooldown = false; - break; - case EVENT_DEVASTATING_SLAM: - DoCastAOE(SPELL_DEVASTATING_SLAM_TRIGGER); - events.ScheduleEvent(EVENT_DEVASTATING_SLAM, 30000); - break; - default: - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); - } - - private: - bool _ohganotSoFast; - bool _reanimateOhganCooldown; - ObjectGuid _reviveGUID; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulGurubAI(creature); - } -}; - -class npc_ohgan : public CreatureScript -{ - public: - npc_ohgan() : CreatureScript("npc_ohgan") { } - - struct npc_ohganAI : public ScriptedAI - { - npc_ohganAI(Creature* creature) : ScriptedAI(creature) - { - _instance = me->GetInstanceScript(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - DoCastAOE(SPELL_OHGAN_ORDERS, true); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (damage >= me->GetHealth()) - { - damage = 0; - me->AttackStop(); - me->SetHealth(0); - me->SetTarget(ObjectGuid::Empty); - DoCast(me, SPELL_CLEAR_ALL, true); - DoCast(me, SPELL_PERMANENT_FEIGN_DEATH); - - if (Creature* mandokir = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BLOODLORD_MANDOKIR))) - mandokir->AI()->DoAction(ACTION_OHGAN_IS_DEATH); - } - } - - void KilledUnit(Unit* victim) override - { - if (Creature* creature = victim->ToCreature()) - { - if (creature->GetEntry() == NPC_CHAINED_SPIRIT) - DoCastAOE(SPELL_OHGAN_ORDERS, true); - } - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulGurubAI(creature); - } -}; - -class npc_chained_spirit : public CreatureScript -{ - public: - npc_chained_spirit() : CreatureScript("npc_chained_spirit") { } - - struct npc_chained_spiritAI : public ScriptedAI - { - npc_chained_spiritAI(Creature* creature) : ScriptedAI(creature) - { - _instance = me->GetInstanceScript(); - me->AddUnitMovementFlag(MOVEMENTFLAG_HOVER); - me->SetReactState(REACT_PASSIVE); // correct? - } - - void Reset() override - { - _revivePlayerGUID.Clear(); - } - - void SetGUID(ObjectGuid const& guid, int32 /*id = 0 */) override - { - _revivePlayerGUID = guid; - } - - void DoAction(int32 action) override - { - if (action == ACTION_REVIVE) - { - Position pos; - if (Player* target = ObjectAccessor::GetPlayer(*me, _revivePlayerGUID)) - { - target->GetNearPoint(me, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, 5.0f, target->GetAngle(me)); - me->GetMotionMaster()->MovePoint(POINT_START_REVIVE, pos); - } - } - } - - void MovementInform(uint32 type, uint32 pointId) override - { - if (type != POINT_MOTION_TYPE || !_revivePlayerGUID) - return; - - if (pointId == POINT_START_REVIVE) - { - if (Player* target = ObjectAccessor::GetPlayer(*me, _revivePlayerGUID)) - DoCast(target, SPELL_REVIVE); - - me->DespawnOrUnsummon(2000); - } - } - - void JustDied(Unit* /*killer*/) override - { - Player* target = ObjectAccessor::GetPlayer(*me, _revivePlayerGUID); - if (!target || target->IsAlive()) - return; - - if (Creature* mandokir = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BLOODLORD_MANDOKIR))) - { - mandokir->GetAI()->SetGUID(target->GetGUID()); - mandokir->GetAI()->DoAction(ACTION_START_REVIVE); - } - - me->DespawnOrUnsummon(); - } - - void UpdateAI(uint32 /*diff*/) override { } - - private: - InstanceScript* _instance; - ObjectGuid _revivePlayerGUID; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulGurubAI(creature); - } -}; - -class spell_mandokir_decapitate : public SpellScriptLoader -{ - public: - spell_mandokir_decapitate() : SpellScriptLoader("spell_mandokir_decapitate") { } - - class spell_mandokir_decapitate_SpellScript : public SpellScript - { - PrepareSpellScript(spell_mandokir_decapitate_SpellScript); - - void FilterTargets(std::list& targets) - { - if (targets.empty()) - return; - - WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); - targets.clear(); - targets.push_back(target); - } - - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* caster = GetCaster(); - if (Player* target = GetHitPlayer()) - caster->CastSpell(target, uint32(GetEffectValue()), true); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mandokir_decapitate_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget += SpellEffectFn(spell_mandokir_decapitate_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_mandokir_decapitate_SpellScript(); - } -}; - -class spell_mandokir_bloodletting : public SpellScriptLoader -{ - public: - spell_mandokir_bloodletting() : SpellScriptLoader("spell_mandokir_bloodletting") { } - - class spell_mandokir_bloodletting_AuraScript : public AuraScript - { - PrepareAuraScript(spell_mandokir_bloodletting_AuraScript); - - bool Validate(SpellInfo const* /*spell*/) override - { - return ValidateSpellInfo({ SPELL_BLOODLETTING_DAMAGE, SPELL_BLOODLETTING_HEAL }); - } - - void HandleEffectPeriodic(AuraEffect const* aurEff) - { - Unit* target = GetTarget(); - Unit* caster = GetCaster(); - if (!caster) - return; - - int32 damage = std::max(7500, target->CountPctFromCurHealth(aurEff->GetAmount())); - - caster->CastCustomSpell(target, SPELL_BLOODLETTING_DAMAGE, &damage, 0, 0, true); - target->CastCustomSpell(caster, SPELL_BLOODLETTING_HEAL, &damage, 0, 0, true); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_mandokir_bloodletting_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_mandokir_bloodletting_AuraScript(); - } -}; - -class spell_mandokir_spirit_vengeance_cancel : public SpellScriptLoader -{ - public: - spell_mandokir_spirit_vengeance_cancel() : SpellScriptLoader("spell_mandokir_spirit_vengeance_cancel") { } - - class spell_mandokir_spirit_vengeance_cancel_SpellScript : public SpellScript - { - PrepareSpellScript(spell_mandokir_spirit_vengeance_cancel_SpellScript); - - void HandleScript(SpellEffIndex /*effIndex*/) - { - if (Player* target = GetHitPlayer()) - target->RemoveAura(uint32(GetEffectValue())); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_mandokir_spirit_vengeance_cancel_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - OnEffectHitTarget += SpellEffectFn(spell_mandokir_spirit_vengeance_cancel_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_mandokir_spirit_vengeance_cancel_SpellScript(); - } -}; - -class DevastatingSlamTargetSelector -{ - public: - DevastatingSlamTargetSelector(Creature* me, const Unit* victim) : _me(me), _victim(victim) {} - - bool operator() (WorldObject* target) - { - if (target == _victim && _me->getThreatManager().getThreatList().size() > 1) - return true; - - if (target->GetTypeId() != TYPEID_PLAYER) - return true; - - return false; - } - - Creature* _me; - Unit const* _victim; -}; - -class spell_mandokir_devastating_slam : public SpellScriptLoader -{ - public: - spell_mandokir_devastating_slam() : SpellScriptLoader("spell_mandokir_devastating_slam") { } - - class spell_mandokir_devastating_slam_SpellScript : public SpellScript - { - PrepareSpellScript(spell_mandokir_devastating_slam_SpellScript); - - void FilterTargets(std::list& targets) - { - targets.remove_if(DevastatingSlamTargetSelector(GetCaster()->ToCreature(), GetCaster()->GetVictim())); - if (targets.empty()) - return; - - WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); - targets.clear(); - targets.push_back(target); - } - - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* caster = GetCaster(); - float angle = 0.0f; - float x, y, z; - - if (Player* target = GetHitPlayer()) - { - caster->AttackStop(); - caster->SetOrientation(caster->GetAngle(target)); - caster->SetFacingTo(caster->GetAngle(target)); - - caster->CastSpell(caster, SPELL_DEVASTATING_SLAM, false); - - // HACK: Need better way for pos calculation - for (uint8 i = 0; i <= 50; ++i) - { - angle = float(rand_norm()) * static_cast(M_PI * 35.0f / 180.0f) - static_cast(M_PI * 17.5f / 180.0f); - caster->GetClosePoint(x, y, z, 4.0f, frand(-2.5f, 50.0f), angle); - - caster->CastSpell(x, y, z, SPELL_DEVASTATING_SLAM_DAMAGE, true); - } - } - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mandokir_devastating_slam_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget += SpellEffectFn(spell_mandokir_devastating_slam_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_FORCE_CAST); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_mandokir_devastating_slam_SpellScript(); - } -}; - -class spell_mandokir_ohgan_orders : public SpellScriptLoader -{ - public: - spell_mandokir_ohgan_orders() : SpellScriptLoader("spell_mandokir_ohgan_orders") { } - - class spell_mandokir_ohgan_orders_SpellScript : public SpellScript - { - PrepareSpellScript(spell_mandokir_ohgan_orders_SpellScript); - - void FilterTargets(std::list& targets) - { - if (targets.empty()) - return; - - WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); - targets.clear(); - targets.push_back(target); - } - - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* caster = GetCaster(); - if (Unit* target = GetHitUnit()) - caster->CastSpell(target, uint32(GetEffectValue()), true); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mandokir_ohgan_orders_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - OnEffectHitTarget += SpellEffectFn(spell_mandokir_ohgan_orders_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_mandokir_ohgan_orders_SpellScript(); - } -}; - -class spell_mandokir_ohgan_orders_trigger : public SpellScriptLoader -{ - public: - spell_mandokir_ohgan_orders_trigger() : SpellScriptLoader("spell_mandokir_ohgan_orders_trigger") { } - - class spell_mandokir_ohgan_orders_trigger_AuraScript : public AuraScript - { - PrepareAuraScript(spell_mandokir_ohgan_orders_trigger_AuraScript); - - void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - if (Unit* caster = GetCaster()) - { - // HACK: research better way - caster->ClearUnitState(UNIT_STATE_CASTING); - caster->GetMotionMaster()->Clear(); - caster->DeleteThreatList(); - caster->AddThreat(target, 50000000.0f); - caster->TauntApply(target); - } - } - - void Register() override - { - AfterEffectApply += AuraEffectApplyFn(spell_mandokir_ohgan_orders_trigger_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_mandokir_ohgan_orders_trigger_AuraScript(); - } -}; - -class spell_mandokir_reanimate_ohgan : public SpellScriptLoader -{ - public: - spell_mandokir_reanimate_ohgan() : SpellScriptLoader("spell_mandokir_reanimate_ohgan") { } - - class spell_mandokir_reanimate_ohgan_SpellScript : public SpellScript - { - PrepareSpellScript(spell_mandokir_reanimate_ohgan_SpellScript); - - void HandleScript(SpellEffIndex /*effIndex*/) - { - if (Unit* target = GetHitUnit()) - { - target->RemoveAura(SPELL_PERMANENT_FEIGN_DEATH); - target->CastSpell(target, SPELL_OHGAN_HEART_VISUAL, true); - target->CastSpell((Unit*)nullptr, SPELL_OHGAN_ORDERS, true); - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_mandokir_reanimate_ohgan_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_mandokir_reanimate_ohgan_SpellScript(); - } -}; - -class spell_clear_all : public SpellScriptLoader -{ - public: - spell_clear_all() : SpellScriptLoader("spell_clear_all") { } - - class spell_clear_all_SpellScript : public SpellScript - { - PrepareSpellScript(spell_clear_all_SpellScript); - - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* caster = GetCaster(); - caster->RemoveAllAurasOnDeath(); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_clear_all_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_clear_all_SpellScript(); - } -}; - -class achievement_ohganot_so_fast : public AchievementCriteriaScript -{ - public: - achievement_ohganot_so_fast() : AchievementCriteriaScript("achievement_ohganot_so_fast") { } - - bool OnCheck(Player* /*player*/, Unit* target) - { - return target && target->GetAI()->GetData(DATA_OHGANOT_SO_FAST); - } -}; - -void AddSC_boss_mandokir() -{ - new boss_mandokir(); - new npc_ohgan(); - new npc_chained_spirit(); - new spell_mandokir_decapitate(); - new spell_mandokir_bloodletting(); - new spell_mandokir_spirit_vengeance_cancel(); - new spell_mandokir_devastating_slam(); - new spell_mandokir_ohgan_orders(); - new spell_mandokir_ohgan_orders_trigger(); - new spell_mandokir_reanimate_ohgan(); - new spell_clear_all(); - new achievement_ohganot_so_fast(); -} diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp index 906bc90a93..f8e18b27ec 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp @@ -28,7 +28,8 @@ ObjectData const creatureData[] = { BOSS_BLOODLORD_MANDOKIR, DATA_BLOODLORD_MANDOKIR }, { BOSS_KILNARA, DATA_KILNARA }, { BOSS_ZANZIL, DATA_ZANZIL }, - { BOSS_JINDO_THE_GODBREAKER, DATA_JINDO_THE_GODBREAKER } + { BOSS_JINDO_THE_GODBREAKER, DATA_JINDO_THE_GODBREAKER }, + { NPC_OHGAN, DATA_OHGAN } }; DoorData const doorData[] = @@ -67,6 +68,10 @@ class instance_zulgurub : public InstanceMapScript if (Creature* venoxis = GetCreature(DATA_HIGH_PRIEST_VENOXIS)) venoxis->AI()->JustSummoned(creature); break; + case NPC_DEVASTATING_SLAM: + if (Creature* mandokir = GetCreature(DATA_BLOODLORD_MANDOKIR)) + mandokir->AI()->JustSummoned(creature); + break; default: break; } diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h b/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h index 8a9c5b7fa8..3e43db3bcf 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h +++ b/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h @@ -28,6 +28,7 @@ uint32 const EncounterCount = 5; enum ZGDataTypes { + // Bosses DATA_HIGH_PRIEST_VENOXIS = 0, DATA_BLOODLORD_MANDOKIR = 1, DATA_KILNARA = 2, @@ -40,12 +41,16 @@ enum ZGDataTypes DATA_WUSHOOLAY = 7, DATA_GRILEK = 8, + // Bloodlord Mandokir + DATA_OHGAN = 9, + // Jin'do the Godbreaker - DATA_JINDOR_TRIGGER, + DATA_JINDOR_TRIGGER }; enum ZGCreatureIds { + // Bosses BOSS_HIGH_PRIEST_VENOXIS = 52155, BOSS_BLOODLORD_MANDOKIR = 52151, BOSS_KILNARA = 52059, @@ -68,6 +73,7 @@ enum ZGCreatureIds // Bloodlord Mandokir NPC_CHAINED_SPIRIT = 52156, NPC_OHGAN = 52157, + NPC_DEVASTATING_SLAM = 52324, // Jin'do the Godbreaker NPC_JINDO_TRIGGER = 52150,