/* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by the * Free Software Foundation; either version 3 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 Affero 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 "ScriptedCreature.h" #include "SpellInfo.h" #include "zulaman.h" enum Spells { SPELL_DUAL_WIELD = 29651, SPELL_SABER_LASH = 43267, SPELL_FRENZY = 43139, SPELL_FLAMESHOCK = 43303, SPELL_EARTHSHOCK = 43305, SPELL_TRANSFORM_SPLIT = 43142, SPELL_TRANSFORM_SPLIT2 = 43573, SPELL_TRANSFORM_MERGE = 43271, SPELL_SUMMON_LYNX = 43143, SPELL_SUMMON_TOTEM = 43302, SPELL_BERSERK = 45078, SPELL_LYNX_FRENZY = 43290, // Used by Spirit Lynx SPELL_SHRED_ARMOR = 43243 // Used by Spirit Lynx }; enum Hal_CreatureIds { NPC_SPIRIT_LYNX = 24143, NPC_TOTEM = 24224 }; enum PhaseHalazzi { PHASE_NONE = 0, PHASE_LYNX = 1, PHASE_SPLIT = 2, PHASE_HUMAN = 3, PHASE_MERGE = 4, PHASE_ENRAGE = 5 }; enum Yells { SAY_AGGRO = 0, SAY_SABER = 1, SAY_SPLIT = 2, SAY_MERGE = 3, SAY_KILL = 4, SAY_DEATH = 5, SAY_BERSERK = 6 }; class boss_halazzi : public CreatureScript { public: boss_halazzi() : CreatureScript("boss_halazzi") { } struct boss_halazziAI : public ScriptedAI { boss_halazziAI(Creature* creature) : ScriptedAI(creature), summons(me) { instance = creature->GetInstanceScript(); } InstanceScript* instance; SummonList summons; PhaseHalazzi Phase; uint32 FrenzyTimer; uint32 SaberlashTimer; uint32 ShockTimer; uint32 TotemTimer; uint32 CheckTimer; uint32 BerserkTimer; uint32 TransformCount; ObjectGuid LynxGUID; void Reset() override { instance->SetData(DATA_HALAZZIEVENT, NOT_STARTED); summons.DespawnAll(); LynxGUID.Clear(); TransformCount = 0; BerserkTimer = 600000; CheckTimer = 1000; DoCast(me, SPELL_DUAL_WIELD, true); Phase = PHASE_NONE; EnterPhase(PHASE_LYNX); } void EnterCombat(Unit* /*who*/) override { instance->SetData(DATA_HALAZZIEVENT, IN_PROGRESS); Talk(SAY_AGGRO); EnterPhase(PHASE_LYNX); } void JustSummoned(Creature* summon) override { summon->AI()->AttackStart(me->GetVictim()); if (summon->GetEntry() == NPC_SPIRIT_LYNX) LynxGUID = summon->GetGUID(); summons.Summon(summon); } void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { if (damage >= me->GetHealth() && Phase != PHASE_ENRAGE) damage = 0; } void SpellHit(Unit*, SpellInfo const* spell) override { if (spell->Id == SPELL_TRANSFORM_SPLIT2) EnterPhase(PHASE_HUMAN); } void AttackStart(Unit* who) override { if (Phase != PHASE_MERGE) ScriptedAI::AttackStart(who); } void EnterPhase(PhaseHalazzi NextPhase) { switch (NextPhase) { case PHASE_LYNX: case PHASE_ENRAGE: if (Phase == PHASE_MERGE) { DoCast(me, SPELL_TRANSFORM_MERGE, true); me->Attack(me->GetVictim(), true); me->GetMotionMaster()->MoveChase(me->GetVictim()); } if (Creature* Lynx = ObjectAccessor::GetCreature(*me, LynxGUID)) Lynx->DisappearAndDie(); me->SetMaxHealth(600000); me->SetHealth(600000 - 150000 * TransformCount); FrenzyTimer = 16000; SaberlashTimer = 20000; ShockTimer = 10000; TotemTimer = 12000; break; case PHASE_SPLIT: Talk(SAY_SPLIT); DoCast(me, SPELL_TRANSFORM_SPLIT, true); break; case PHASE_HUMAN: //DoCast(me, SPELL_SUMMON_LYNX, true); DoSpawnCreature(NPC_SPIRIT_LYNX, 5, 5, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); me->SetMaxHealth(400000); me->SetHealth(400000); ShockTimer = 10000; TotemTimer = 12000; break; case PHASE_MERGE: if (Unit* pLynx = ObjectAccessor::GetUnit(*me, LynxGUID)) { Talk(SAY_MERGE); pLynx->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); pLynx->GetMotionMaster()->Clear(); pLynx->GetMotionMaster()->MoveFollow(me, 0, 0); me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveFollow(pLynx, 0, 0); ++TransformCount; } break; default: break; } Phase = NextPhase; } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; if (BerserkTimer <= diff) { Talk(SAY_BERSERK); DoCast(me, SPELL_BERSERK, true); BerserkTimer = 60000; } else BerserkTimer -= diff; if (Phase == PHASE_LYNX || Phase == PHASE_ENRAGE) { if (SaberlashTimer <= diff) { // A tank with more than 490 defense skills should receive no critical hit //DoCast(me, 41296, true); DoCastVictim(SPELL_SABER_LASH, true); //me->RemoveAurasDueToSpell(41296); SaberlashTimer = 30000; } else SaberlashTimer -= diff; if (FrenzyTimer <= diff) { DoCast(me, SPELL_FRENZY); FrenzyTimer = urand(10000, 15000); } else FrenzyTimer -= diff; if (Phase == PHASE_LYNX) { if (CheckTimer <= diff) { if (HealthBelowPct(25 * (3 - TransformCount))) EnterPhase(PHASE_SPLIT); CheckTimer = 1000; } else CheckTimer -= diff; } } if (Phase == PHASE_HUMAN || Phase == PHASE_ENRAGE) { if (TotemTimer <= diff) { DoCast(me, SPELL_SUMMON_TOTEM); TotemTimer = 20000; } else TotemTimer -= diff; if (ShockTimer <= diff) { if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) { if (target->IsNonMeleeSpellCast(false)) DoCast(target, SPELL_EARTHSHOCK); else DoCast(target, SPELL_FLAMESHOCK); ShockTimer = urand(10000, 15000); } } else ShockTimer -= diff; if (Phase == PHASE_HUMAN) { if (CheckTimer <= diff) { if (!HealthAbovePct(20) /*HealthBelowPct(10)*/) EnterPhase(PHASE_MERGE); else { Unit* Lynx = ObjectAccessor::GetUnit(*me, LynxGUID); if (Lynx && !Lynx->HealthAbovePct(20) /*Lynx->HealthBelowPct(10)*/) EnterPhase(PHASE_MERGE); } CheckTimer = 1000; } else CheckTimer -= diff; } } if (Phase == PHASE_MERGE) { if (CheckTimer <= diff) { Unit* Lynx = ObjectAccessor::GetUnit(*me, LynxGUID); if (Lynx) { Lynx->GetMotionMaster()->MoveFollow(me, 0, 0); me->GetMotionMaster()->MoveFollow(Lynx, 0, 0); if (me->IsWithinDistInMap(Lynx, 6.0f)) { if (TransformCount < 3) EnterPhase(PHASE_LYNX); else EnterPhase(PHASE_ENRAGE); } } CheckTimer = 1000; } else CheckTimer -= diff; } DoMeleeAttackIfReady(); } void KilledUnit(Unit* victim) override { if (victim->GetTypeId() != TYPEID_PLAYER) return; Talk(SAY_KILL); } void JustDied(Unit* /*killer*/) override { instance->SetData(DATA_HALAZZIEVENT, DONE); Talk(SAY_DEATH); } }; CreatureAI* GetAI(Creature* creature) const override { return GetZulAmanAI(creature); } }; // Spirits Lynx AI class npc_halazzi_lynx : public CreatureScript { public: npc_halazzi_lynx() : CreatureScript("npc_halazzi_lynx") { } struct npc_halazzi_lynxAI : public ScriptedAI { npc_halazzi_lynxAI(Creature* creature) : ScriptedAI(creature) { } uint32 FrenzyTimer; uint32 shredder_timer; void Reset() override { FrenzyTimer = urand(30000, 50000); //frenzy every 30-50 seconds shredder_timer = 4000; } void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { if (damage >= me->GetHealth()) damage = 0; } void AttackStart(Unit* who) override { if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) ScriptedAI::AttackStart(who); } void EnterCombat(Unit* /*who*/) override {/*DoZoneInCombat();*/ } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; if (FrenzyTimer <= diff) { DoCast(me, SPELL_LYNX_FRENZY); FrenzyTimer = urand(30000, 50000); //frenzy every 30-50 seconds } else FrenzyTimer -= diff; if (shredder_timer <= diff) { DoCastVictim(SPELL_SHRED_ARMOR); shredder_timer = 4000; } else shredder_timer -= diff; DoMeleeAttackIfReady(); } }; CreatureAI* GetAI(Creature* creature) const override { return GetZulAmanAI(creature); } }; void AddSC_boss_halazzi() { new boss_halazzi(); new npc_halazzi_lynx(); }