diff --git a/sql/updates/world/4.3.4/2017_12_27_00_world.sql b/sql/updates/world/4.3.4/2017_12_27_00_world.sql new file mode 100644 index 00000000000..d3c5399ac37 --- /dev/null +++ b/sql/updates/world/4.3.4/2017_12_27_00_world.sql @@ -0,0 +1,41 @@ +-- Lockmaw +UPDATE `creature_template` SET `difficulty_entry_1`= 49043, `mechanic_immune_mask`= 667893759, `scriptname`= 'boss_lockmaw' WHERE `entry`= 43614; +UPDATE `creature_template` SET `minlevel`= 87, `maxlevel`= 87, `faction`= 16, `exp`= 3, `mechanic_immune_mask`= 667893759 WHERE `entry`= 49043; +-- Dust Flail Front +UPDATE `creature_template` SET `minlevel`= 80, `maxlevel`= 80, `faction`= 14, `unit_flags`= 33554944, `flags_extra`= 128 WHERE `entry`= 43655; +-- Dust Flail Back +UPDATE `creature_template` SET `minlevel`= 85, `maxlevel`= 85, `faction`= 14, `unit_flags`= 33554944, `flags_extra`= 128 WHERE `entry`= 43650; +-- Frenzied Crocolisk +UPDATE `creature_template` SET `minlevel`= 84, `maxlevel`= 84, `difficulty_entry_1`= 49311, `flags_extra`= 256, `scriptname`= 'npc_lockmaw_frenzied_crocolisk' WHERE `entry`= 43658; +UPDATE `creature_template` SET `minlevel`= 85, `maxlevel`= 85, `faction`= 16, `exp`= 3, `flags_extra`= 256 WHERE `entry`= 49311; +-- Augh 1 and 2 +UPDATE `creature_template` SET `unit_flags`= 32832, `mechanic_immune_mask`= 667893759, `scriptname`= 'npc_lockmaw_augh' WHERE `entry` IN (45379, 45378); +-- Augh +UPDATE `creature_template` SET `mechanic_immune_mask`= 667893759, `scriptname`= 'boss_augh' WHERE `entry`= 49045; +-- Add Stalker +UPDATE `creature_template` SET `unit_flags`= 33554432, `flags_extra`= 131 WHERE `entry`= 45124; + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_lockmaw_paralytic_blow_dart', +'spell_lockmaw_scent_of_blood', +'spell_lockmaw_random_aggro_taunt'); + +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(84799, 'spell_lockmaw_paralytic_blow_dart'), +(89989, 'spell_lockmaw_paralytic_blow_dart'), +(81690, 'spell_lockmaw_scent_of_blood'), +(89998, 'spell_lockmaw_scent_of_blood'), +(50230, 'spell_lockmaw_random_aggro_taunt'); + +DELETE FROM `creature_template_addon` WHERE `entry`= 43650; +INSERT INTO `creature_template_addon` (`entry`, `Auras`) VALUES +(43650, '81646'); + +DELETE FROM `creature_text` WHERE `CreatureID`= 49045; +INSERT INTO `creature_text` (`CreatureID`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `comment`) VALUES +(49045, 0, 0, 'Augh appears from the distance!', 41, 0, 0, 0, 0, 0, 50638, 'Augh - Intro 1'), +(49045, 1, 0, 'GAAAH! How you kill croc?!', 12, 0, 0, 53, 0, 0, 49169, 'Augh - Intro 2'), +(49045, 2, 0, 'Augh smart! Augh already steal treasure while you no looking!', 12, 0, 0, 1, 0, 0, 49170, 'Augh - Intro 3'), +(49045, 3, 0, 'Augh da boss! Oh yeah!', 12, 0, 0, 0, 0, 0, 49171, 'Augh Taunt'), +(49045, 4, 0, 'Augh steal your treasure. Uhn uhn uhnnn!', 12, 0, 0, 0, 0, 0, 49173, 'Augh Taunt'), +(49045, 5, 0, 'Who bad?! Augh bad!! Ugn!', 12, 0, 0, 0, 0, 0, 49172, 'Augh Taunt'); diff --git a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_lockmaw_and_augh.cpp b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_lockmaw_and_augh.cpp new file mode 100644 index 00000000000..937b30df057 --- /dev/null +++ b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_lockmaw_and_augh.cpp @@ -0,0 +1,619 @@ +/* +* Copyright (C) 2008-2017 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 "lost_city_of_the_tolvir.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" + +enum Texts +{ + // Augh Boss + SAY_ANNOUNCE_AUGH_APPEAR = 0, + SAY_AUGH_INTRO_1 = 1, + SAY_AUGH_INTRO_2 = 2, + SAY_AUGH_TAUNT_1 = 3, + SAY_AUGH_TAUNT_2 = 4, + SAY_AUGH_TAUNT_3 = 5 +}; + +enum Spells +{ + // Lockmaw + SPELL_VISCOUS_POISON = 81630, + SPELL_SCENT_OF_BLOOD = 81690, + SPELL_SCENT_OF_BLOOD_HC = 89998, + SPELL_DUST_FLAIL_DUMMY = 81652, + SPELL_DUST_FLAIL = 81642, + SPELL_VENOMOUS_RAGE = 81706, + + // Frenzied Crocolisk + SPELL_STEALTHED = 84244, + + // Augh (Combat Assistance) + SPELL_PARALYTIC_BLOW_DART = 84799, + SPELL_SMOKE_BOMB = 84768, + SPELL_RANDOM_AGGRO_TAUNT = 50230, + SPELL_WHIRLWIND = 84784, + + // Augh (Heroic Boss) + SPELL_DRAGONS_BREATH = 83776, + SPELL_FRENZY = 91415, + SPELL_WHIRLWIND_BOSS = 91408 +}; + +enum Events +{ + // Lockmaw + EVENT_VISCOUS_POISON = 1, + EVENT_SCENT_OF_BLOOD, + EVENT_DUST_FLAIL, + EVENT_MAKE_AGGRESSIVE, + EVENT_SUMMON_CROCOLISK, + EVENT_SUMMON_AUGH, + + // Frenzied Crocolisk + EVENT_FIND_PLAYER_TARGET, + + // Augh (Assistance) + EVENT_ROAR_EMOTE, + EVENT_PARALYTIC_BLOW_DART, + EVENT_SMOKE_BOMB, + EVENT_WHIRLWIND, + EVENT_RANDOM_AGGRO, + EVENT_ATTACK_STOP, + + // Augh Boss + EVENT_MOVE_HOME_POS, + EVENT_TALK_INTRO_1, + EVENT_TALK_INTRO_2, + EVENT_PLAY_EMOTE, + EVENT_MAKE_ATTACKABLE, + EVENT_TALK_TAUNT_1, + EVENT_TALK_TAUNT_2, + EVENT_TALK_TAUNT_3, + EVENT_DRAGONS_BREATH + +}; + +enum Phases +{ + PHASE_INTRO = 1, + PHASE_COMBAT +}; + +enum Actions +{ + ACTION_AUGH_INTRO = 1, + ACTION_AUGH_ATTACKABLE = 2 +}; + +Position const AughMovePoint = { -11062.5f, -1662.39f, 0.7606202f, 0.8028514f }; + +class ScentOfBloodTargetSelector : public std::unary_function +{ +public: + ScentOfBloodTargetSelector() { } + + bool operator()(Unit* unit) const + { + return (!unit->HasAura(SPELL_SCENT_OF_BLOOD) || !unit->HasAura(SPELL_SCENT_OF_BLOOD_HC)); + } +}; + +class boss_lockmaw : public CreatureScript +{ + public: + boss_lockmaw() : CreatureScript("boss_lockmaw") { } + + struct boss_lockmawAI : public BossAI + { + boss_lockmawAI(Creature* creature) : BossAI(creature, DATA_LOCKMAW) + { + Initialize(); + } + + void Initialize() + { + _enraged = false; + _lastSpellID = 0; + } + + void Reset() override + { + instance->SetBossState(DATA_LOCKMAW_AND_AUGH, NOT_STARTED); + instance->SetData(DATA_LOCKMAW_COMBAT_ASSISTANCE, ASSISTANCE_NONE); + _Reset(); + Initialize(); + } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + events.ScheduleEvent(EVENT_VISCOUS_POISON, Seconds(6)); + events.ScheduleEvent(EVENT_SCENT_OF_BLOOD, Seconds(6)); + events.ScheduleEvent(EVENT_DUST_FLAIL, Seconds(8)); + events.ScheduleEvent(EVENT_SUMMON_AUGH, Seconds(6)); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + summons.DespawnAll(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + _DespawnAtEvade(); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + + if (summon->GetEntry() == NPC_DUST_FLAIL_FRONT_STALKER) + { + me->SetReactState(REACT_PASSIVE); + me->StopMoving(); + me->AttackStop(); + me->SetFacingToObject(summon); + DoCastSelf(SPELL_DUST_FLAIL); + events.ScheduleEvent(EVENT_MAKE_AGGRESSIVE, Seconds(5)); + } + } + + void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override + { + if (me->HealthBelowPct(30) && !_enraged) + { + DoCastSelf(SPELL_VENOMOUS_RAGE, true); + _enraged = true; + } + } + + 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_VISCOUS_POISON: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true, 0)) + DoCast(target, SPELL_VISCOUS_POISON); + events.Repeat(Seconds(26)); + break; + case EVENT_SCENT_OF_BLOOD: + DoCastAOE(SPELL_SCENT_OF_BLOOD, true); + events.ScheduleEvent(EVENT_SCENT_OF_BLOOD, Seconds(30)); + events.ScheduleEvent(EVENT_SUMMON_CROCOLISK, Milliseconds(100)); + break; + case EVENT_SUMMON_CROCOLISK: + instance->SetData(DATA_LOCKMAW_COMBAT_ASSISTANCE, ASSISTANCE_SUMMON_CROCOLISKS); + break; + case EVENT_DUST_FLAIL: + DoCastAOE(SPELL_DUST_FLAIL_DUMMY, true); + events.Repeat(Seconds(39)); + break; + case EVENT_MAKE_AGGRESSIVE: + me->SetReactState(REACT_AGGRESSIVE); + break; + case EVENT_SUMMON_AUGH: + if (_lastSpellID != SPELL_SUMMON_AUGH_DART) + { + _lastSpellID = SPELL_SUMMON_AUGH_DART; + instance->SetData(DATA_LOCKMAW_COMBAT_ASSISTANCE, ASSISTANCE_SUMMON_AUGH_DART); + events.Repeat(Seconds(20)); + } + else + { + _lastSpellID = SPELL_SUMMON_AUGH_WHIRLWIND; + instance->SetData(DATA_LOCKMAW_COMBAT_ASSISTANCE, ASSISTANCE_SUMMON_AUGH_WHIRLWIND); + events.Repeat(Seconds(40)); + } + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + private: + bool _enraged; + uint32 _lastSpellID; + }; + CreatureAI* GetAI(Creature* creature) const + { + return GetLostCityOfTheTolvirAI(creature); + } +}; + +class boss_augh : public CreatureScript +{ + public: + boss_augh() : CreatureScript("boss_augh") { } + + struct boss_aughAI : public BossAI + { + boss_aughAI(Creature* creature) : BossAI(creature, DATA_AUGH) { } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + me->HandleEmoteCommand(EMOTE_ONESHOT_NONE); + events.SetPhase(PHASE_COMBAT); + DoCastSelf(SPELL_FRENZY); + events.ScheduleEvent(EVENT_PARALYTIC_BLOW_DART, Seconds(8)); + events.ScheduleEvent(EVENT_WHIRLWIND, Seconds(9)); + events.ScheduleEvent(EVENT_DRAGONS_BREATH, Seconds(6)); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + instance->SetBossState(DATA_AUGH, FAIL); + _DespawnAtEvade(); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_AUGH_INTRO: + me->SetReactState(REACT_PASSIVE); + Talk(SAY_ANNOUNCE_AUGH_APPEAR); + events.SetPhase(PHASE_INTRO); + events.ScheduleEvent(EVENT_MOVE_HOME_POS, Seconds(1)); + break; + case ACTION_AUGH_ATTACKABLE: + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_MOVE_HOME_POS: + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(0, AughMovePoint, true); + events.ScheduleEvent(EVENT_TALK_INTRO_1, Seconds(10) + Milliseconds(500), 0, PHASE_INTRO); + break; + case EVENT_TALK_INTRO_1: + me->SetFacingTo(AughMovePoint.GetOrientation()); + Talk(SAY_AUGH_INTRO_1); + events.ScheduleEvent(EVENT_TALK_INTRO_2, Seconds(4), 0, PHASE_INTRO); + break; + case EVENT_TALK_INTRO_2: + Talk(SAY_AUGH_INTRO_2); + events.ScheduleEvent(EVENT_PLAY_EMOTE, Seconds(3), 0, PHASE_INTRO); + break; + case EVENT_PLAY_EMOTE: + me->HandleEmoteCommand(EMOTE_STATE_SPELL_CHANNEL_OMNI); + events.ScheduleEvent(EVENT_MAKE_ATTACKABLE, Seconds(4), 0, PHASE_INTRO); + events.ScheduleEvent(EVENT_TALK_TAUNT_1, Seconds(5), PHASE_INTRO); + break; + case EVENT_MAKE_ATTACKABLE: + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + break; + case EVENT_TALK_TAUNT_1: + Talk(SAY_AUGH_TAUNT_1); + events.ScheduleEvent(EVENT_TALK_TAUNT_2, Seconds(5), 0, PHASE_INTRO); + break; + case EVENT_TALK_TAUNT_2: + Talk(SAY_AUGH_TAUNT_2); + events.ScheduleEvent(EVENT_TALK_TAUNT_3, Seconds(5), 0, PHASE_INTRO); + break; + case EVENT_TALK_TAUNT_3: + Talk(SAY_AUGH_TAUNT_3); + break; + case EVENT_PARALYTIC_BLOW_DART: + DoCastAOE(SPELL_PARALYTIC_BLOW_DART); + events.Repeat(Seconds(10), Seconds(15)); + break; + case EVENT_WHIRLWIND: + DoCastAOE(SPELL_RANDOM_AGGRO_TAUNT, true); + DoCastSelf(SPELL_WHIRLWIND_BOSS); + events.Repeat(Seconds(29)); + break; + case EVENT_DRAGONS_BREATH: + DoCastAOE(SPELL_DRAGONS_BREATH); + events.Repeat(Seconds(28)); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + }; + CreatureAI* GetAI(Creature* creature) const + { + return GetLostCityOfTheTolvirAI(creature); + } +}; + +class npc_lockmaw_frenzied_crocolisk : public CreatureScript +{ + public: + npc_lockmaw_frenzied_crocolisk() : CreatureScript("npc_lockmaw_frenzied_crocolisk") { } + + struct npc_lockmaw_frenzied_crocoliskAI : public ScriptedAI + { + npc_lockmaw_frenzied_crocoliskAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(Seconds(5)); + } + + void IsSummonedBy(Unit* summoner) override + { + if (Creature* lockmaw = _instance->GetCreature(DATA_LOCKMAW)) + lockmaw->AI()->JustSummoned(me); + me->SetReactState(REACT_PASSIVE); + DoZoneInCombat(); + _events.ScheduleEvent(EVENT_FIND_PLAYER_TARGET, Seconds(1)); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FIND_PLAYER_TARGET: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, ScentOfBloodTargetSelector())) + { + DoCastSelf(SPELL_STEALTHED); + me->AI()->AttackStart(target); + me->AddThreat(target, 50000000.0f); + } + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetLostCityOfTheTolvirAI(creature); + } +}; + +class npc_lockmaw_augh : public CreatureScript +{ + public: + npc_lockmaw_augh() : CreatureScript("npc_lockmaw_augh") { } + + struct npc_lockmaw_aughAI : public ScriptedAI + { + npc_lockmaw_aughAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void IsSummonedBy(Unit* /*summoner*/) override + { + if (Creature* lockmaw = _instance->GetCreature(DATA_LOCKMAW)) + lockmaw->AI()->JustSummoned(me); + + DoCastSelf(SPELL_STEALTHED, true); + + if (me->GetEntry() == NPC_AUGH_DART) + { + me->SetReactState(REACT_PASSIVE); + _events.ScheduleEvent(EVENT_ROAR_EMOTE, Seconds(7)); + _events.ScheduleEvent(EVENT_PARALYTIC_BLOW_DART, Seconds(8)); + _events.ScheduleEvent(EVENT_SMOKE_BOMB, Seconds(12)); + } + else + _events.ScheduleEvent(EVENT_WHIRLWIND, Seconds(4)); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + // There is indeed now immunity aura... + damage = 0; + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ROAR_EMOTE: + me->HandleEmoteCommand(EMOTE_ONESHOT_BATTLE_ROAR); + break; + case EVENT_PARALYTIC_BLOW_DART: + DoCastAOE(SPELL_PARALYTIC_BLOW_DART); + break; + case EVENT_SMOKE_BOMB: + DoCastSelf(SPELL_SMOKE_BOMB); + me->DespawnOrUnsummon(Seconds(3)); + break; + case EVENT_WHIRLWIND: + DoCastAOE(SPELL_RANDOM_AGGRO_TAUNT, true); + DoCastSelf(SPELL_WHIRLWIND); + _events.ScheduleEvent(EVENT_RANDOM_AGGRO, Seconds(10)); + break; + case EVENT_RANDOM_AGGRO: + DoCastAOE(SPELL_RANDOM_AGGRO_TAUNT, true); + _events.ScheduleEvent(EVENT_ATTACK_STOP, Seconds(10)); + break; + case EVENT_ATTACK_STOP: + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->DespawnOrUnsummon(Seconds(6)); + break; + default: + break; + } + } + } + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetLostCityOfTheTolvirAI(creature); + } +}; + +class spell_lockmaw_scent_of_blood : public SpellScriptLoader +{ + public: + spell_lockmaw_scent_of_blood() : SpellScriptLoader("spell_lockmaw_scent_of_blood") { } + + class spell_lockmaw_scent_of_blood_SpellScript : public SpellScript + { + PrepareSpellScript(spell_lockmaw_scent_of_blood_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_lockmaw_scent_of_blood_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_lockmaw_scent_of_blood_SpellScript(); + } +}; + +class spell_lockmaw_paralytic_blow_dart : public SpellScriptLoader +{ + public: + spell_lockmaw_paralytic_blow_dart() : SpellScriptLoader("spell_lockmaw_paralytic_blow_dart") { } + + class spell_lockmaw_paralytic_blow_dart_SpellScript : public SpellScript + { + PrepareSpellScript(spell_lockmaw_paralytic_blow_dart_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_lockmaw_paralytic_blow_dart_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_lockmaw_paralytic_blow_dart_SpellScript(); + } +}; + +class spell_lockmaw_random_aggro_taunt : public SpellScriptLoader +{ + public: + spell_lockmaw_random_aggro_taunt() : SpellScriptLoader("spell_lockmaw_random_aggro_taunt") { } + + class spell_lockmaw_random_aggro_taunt_SpellScript : public SpellScript + { + PrepareSpellScript(spell_lockmaw_random_aggro_taunt_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void EffectScriptEffect(SpellEffIndex /*effIndex*/) + { + GetHitPlayer()->CastSpell(GetCaster(), GetSpellInfo()->Effects[EFFECT_0].BasePoints, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_lockmaw_random_aggro_taunt_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_lockmaw_random_aggro_taunt_SpellScript::EffectScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_lockmaw_random_aggro_taunt_SpellScript(); + } +}; + +void AddSC_boss_lockmaw_and_augh() +{ + new boss_lockmaw(); + new boss_augh(); + new npc_lockmaw_frenzied_crocolisk(); + new npc_lockmaw_augh(); + new spell_lockmaw_scent_of_blood(); + new spell_lockmaw_paralytic_blow_dart(); + new spell_lockmaw_random_aggro_taunt(); +} diff --git a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/instance_lost_city_of_the_tolvir.cpp b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/instance_lost_city_of_the_tolvir.cpp index ea3be9c72c2..992b482dca6 100644 --- a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/instance_lost_city_of_the_tolvir.cpp +++ b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/instance_lost_city_of_the_tolvir.cpp @@ -19,6 +19,26 @@ #include "InstanceScript.h" #include "lost_city_of_the_tolvir.h" +enum TimedEvents +{ + EVENT_SPAWN_AUGH = 1 +}; + +enum SummonGroups +{ + SUMMON_GROUP_WIND_TUNNEL = 0 +}; + +enum Actions +{ + // Lockmaw and Augh + ACTION_AUGH_INTRO = 1, + ACTION_AUGH_ATTACKABLE = 2 +}; + +Position const AughSpawnPos = { -11058.91f, -1625.342f, -0.1304993f, 4.782202f }; +Position const AughHomePos = { -11062.5f, -1662.39f, 0.7606202f, 0.8028514f }; + ObjectData const creatureData[] = { { BOSS_GENERAL_HUSAM, DATA_GENERAL_HUSAM }, @@ -28,7 +48,7 @@ ObjectData const creatureData[] = { BOSS_SIAMAT, DATA_SIAMAT }, { NPC_BLAZE_OF_THE_HEAVENS, DATA_BLAZE_OF_THE_HEAVENS }, { NPC_HARBINGER_OF_DARKNESS, DATA_HARBINGER_OF_DARKNESS }, - { 0, 0 } // End + { 0, 0 } // End }; ObjectData const gameObjectData[] = @@ -39,31 +59,155 @@ ObjectData const gameObjectData[] = class instance_lost_city_of_the_tolvir : public InstanceMapScript { -public: - instance_lost_city_of_the_tolvir() : InstanceMapScript(LCTScriptName, 755) { } + public: + instance_lost_city_of_the_tolvir() : InstanceMapScript(LCTScriptName, 755) { } - struct instance_lost_city_of_the_tolvir_InstanceMapScript : public InstanceScript - { - instance_lost_city_of_the_tolvir_InstanceMapScript(Map* map) : InstanceScript(map) + struct instance_lost_city_of_the_tolvir_InstanceMapScript : public InstanceScript { - SetHeaders(DataHeader); - SetBossNumber(EncounterCount); - LoadObjectData(creatureData, gameObjectData); - } + instance_lost_city_of_the_tolvir_InstanceMapScript(Map* map) : InstanceScript(map) + { + SetHeaders(DataHeader); + SetBossNumber(EncounterCount); + LoadObjectData(creatureData, gameObjectData); + Initialize(); + } - bool SetBossState(uint32 type, EncounterState state) override + void Initialize() + { + _heroicAughSpawned = false; + } + + void OnCreatureCreate(Creature* creature) override + { + InstanceScript::OnCreatureCreate(creature); + + if (creature->GetEntry() == NPC_ADD_STALKER) + addStalkerGUIDs.push_back(creature->GetGUID()); + } + + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case DATA_LOCKMAW: + if (!instance->IsHeroic() && state == DONE) + SetBossState(DATA_LOCKMAW_AND_AUGH, DONE); + else if (instance->IsHeroic() && state == DONE && !_heroicAughSpawned) + _events.ScheduleEvent(EVENT_SPAWN_AUGH, Seconds(4)); + break; + case DATA_AUGH: // Since Augh is summoned, we need to handle his respawn here + if (state == DONE) + SetBossState(DATA_LOCKMAW_AND_AUGH, DONE); + else if (state == FAIL) + _events.ScheduleEvent(EVENT_SPAWN_AUGH, Seconds(30)); + break; + case DATA_GENERAL_HUSAM: + case DATA_LOCKMAW_AND_AUGH: + case DATA_HIGH_PROPHET_BARIM: + if (state == DONE && CheckSiamatsPlatform()) + { + if (GameObject* platform = GetGameObject(DATA_SIAMAT_PLATFORM)) + { + platform->setActive(true); + platform->SetDestructibleState(GO_DESTRUCTIBLE_DESTROYED); + platform->EnableCollision(true); + } + + instance->SetZoneWeather(ZONE_ID_LOST_CITY, WEATHER_STATE_HEAVY_RAIN, 1.0f); + instance->SummonCreatureGroup(SUMMON_GROUP_WIND_TUNNEL); + } + break; + default: + break; + } + return true; + } + + void SetData(uint32 data, uint32 value) override + { + switch (data) + { + case DATA_LOCKMAW_COMBAT_ASSISTANCE: + switch (value) + { + case ASSISTANCE_SUMMON_AUGH_DART: + if (Unit* stalker = instance->GetCreature(Trinity::Containers::SelectRandomContainerElement(addStalkerGUIDs))) + stalker->CastSpell(stalker, SPELL_SUMMON_AUGH_DART); + SetData(DATA_LOCKMAW_COMBAT_ASSISTANCE, ASSISTANCE_NONE); + break; + case ASSISTANCE_SUMMON_AUGH_WHIRLWIND: + if (Unit* stalker = instance->GetCreature(Trinity::Containers::SelectRandomContainerElement(addStalkerGUIDs))) + stalker->CastSpell(stalker, SPELL_SUMMON_AUGH_WHIRLWIND); + SetData(DATA_LOCKMAW_COMBAT_ASSISTANCE, ASSISTANCE_NONE); + break; + case ASSISTANCE_SUMMON_CROCOLISKS: + { + GuidVector tempList = addStalkerGUIDs; + if (!tempList.empty()) + { + Trinity::Containers::RandomResize(tempList, 4); + for (auto itr = tempList.begin(); itr != tempList.end(); itr++) + if (Unit* stalker = instance->GetCreature(*itr)) + stalker->CastSpell(stalker, SPELL_SUMMON_CROCOLISK); + } + SetData(DATA_LOCKMAW_COMBAT_ASSISTANCE, ASSISTANCE_NONE); + break; + } + default: + break; + } + break; + default: + break; + } + } + + bool CheckSiamatsPlatform() + { + for (LCTDataTypes boss : { DATA_GENERAL_HUSAM, DATA_LOCKMAW_AND_AUGH, DATA_HIGH_PROPHET_BARIM }) + if (GetBossState(boss) != DONE) + return false; + return true; + } + + void Update(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SPAWN_AUGH: + if (!_heroicAughSpawned) + { + if (Creature* augh = instance->SummonCreature(BOSS_AUGH, AughSpawnPos)) + augh->AI()->DoAction(ACTION_AUGH_INTRO); + _heroicAughSpawned = true; + } + else if (_heroicAughSpawned) + if (Creature* augh = instance->SummonCreature(BOSS_AUGH, AughHomePos)) + augh->AI()->DoAction(ACTION_AUGH_ATTACKABLE); + break; + default: + break; + } + } + } + + protected: + EventMap events; + bool heroicAughSpawned; + GuidVector addStalkerGUIDs; + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override { - if (!InstanceScript::SetBossState(type, state)) - return false; - - return true; + return new instance_lost_city_of_the_tolvir_InstanceMapScript(map); } - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const override - { - return new instance_lost_city_of_the_tolvir_InstanceMapScript(map); - } }; void AddSC_instance_lost_city_of_the_tolvir() diff --git a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/lost_city_of_the_tolvir.h b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/lost_city_of_the_tolvir.h index 1107ed69346..db66b5c2038 100644 --- a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/lost_city_of_the_tolvir.h +++ b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/lost_city_of_the_tolvir.h @@ -21,21 +21,23 @@ #define LCTScriptName "instance_lost_city_of_the_tolvir" #define DataHeader "LCT" -uint32 const EncounterCount = 4; +uint32 const EncounterCount = 6; enum LCTDataTypes { // Encounter States - DATA_GENERAL_HUSAM = 1, - DATA_LOCKMAW = 2, - DATA_AUGH = 3, - DATA_HIGH_PROPHET_BARIM = 4, - DATA_SIAMAT = 5, + DATA_GENERAL_HUSAM = 0, + DATA_LOCKMAW_AND_AUGH = 1, + DATA_HIGH_PROPHET_BARIM = 2, + DATA_SIAMAT = 3, + DATA_LOCKMAW = 4, + DATA_AUGH = 5, // Additional Data - DATA_SIAMAT_PLATFORM = 6, - DATA_BLAZE_OF_THE_HEAVENS = 7, - DATA_HARBINGER_OF_DARKNESS = 8, + DATA_SIAMAT_PLATFORM = 6, + DATA_BLAZE_OF_THE_HEAVENS = 7, + DATA_HARBINGER_OF_DARKNESS = 8, + DATA_LOCKMAW_COMBAT_ASSISTANCE = 9 }; enum LCTCreatureIds @@ -56,6 +58,9 @@ enum LCTCreatureIds NPC_BLAZE_OF_THE_HEAVENS = 48906, NPC_SOUL_FRAGMENT = 43934, NPC_HARBINGER_OF_DARKNESS = 43927, + NPC_DUST_FLAIL_FRONT_STALKER = 43655, + NPC_ADD_STALKER = 45124, + NPC_AUGH_DART = 45379 }; enum LCTGameObjectIds @@ -63,6 +68,23 @@ enum LCTGameObjectIds GO_SIAMAT_PLATFORM = 205365 }; +enum LCTSpells +{ + SPELL_SUMMON_CROCOLISK = 84242, + SPELL_SUMMON_AUGH_DART = 84809, + SPELL_SUMMON_AUGH_WHIRLWIND = 84808 +}; + +enum LCTMisc +{ + ZONE_ID_LOST_CITY = 5396, + + ASSISTANCE_NONE = 0, + ASSISTANCE_SUMMON_AUGH_DART = 1, + ASSISTANCE_SUMMON_AUGH_WHIRLWIND = 2, + ASSISTANCE_SUMMON_CROCOLISKS = 3 +}; + template AI* GetLostCityOfTheTolvirAI(Creature* creature) {