diff --git a/sql/updates/world/4.3.4/custom_2017_12_19_02_world.sql b/sql/updates/world/4.3.4/custom_2017_12_19_02_world.sql new file mode 100644 index 00000000000..72d8cedc093 --- /dev/null +++ b/sql/updates/world/4.3.4/custom_2017_12_19_02_world.sql @@ -0,0 +1,88 @@ +-- Siamat +UPDATE `creature_template` SET `difficulty_entry_1`= 51088, `minlevel`= 86, `maxlevel`= 86, `mechanic_immune_mask`= 667893759, `flags_extra`= 536870912, `scriptname`= 'boss_siamat' WHERE `entry`= 44819; +UPDATE `creature_template` SET `minlevel`= 87, `maxlevel`= 87, `faction`= 16, `exp`= 3, `mechanic_immune_mask`= 667893759, `flags_extra`= 536870912 WHERE `entry`= 51088; +-- Servant of Siamat +UPDATE `creature_template` SET `minlevel`= 84, `maxlevel`= 84, `scale`= 1, `mechanic_immune_mask`= 667893759, `flags_extra`= 536870912, `scriptname`= 'npc_siamat_servant_of_siamat' WHERE `entry` IN (45259, 45268, 45269); +UPDATE `creature_template` SET `difficulty_entry_1`= 49256 WHERE `entry`= 45259; +UPDATE `creature_template` SET `difficulty_entry_1`= 49257 WHERE `entry`= 45268; +UPDATE `creature_template` SET `difficulty_entry_1`= 49258 WHERE `entry`= 45269; +UPDATE `creature_template` SET `minlevel`= 85, `maxlevel`= 85, `scale`= 1, `exp`= 3, `faction`= 16, `mechanic_immune_mask`= 667893759, `movementId`= 130, `flags_extra`= 536870912 WHERE `entry` IN (49256, 49257, 49258); +-- Cloud Burst +UPDATE `creature_template` SET `minlevel`= 85, `maxlevel`= 85, `faction`= 14, `unit_flags`= 33554944, `flags_extra`= 131 WHERE `entry`= 44541; +-- Minion of Siamat +UPDATE `creature_template` SET `difficulty_entry_1`= 49260, `minlevel`= 82, `maxlevel`= 82, `flags_extra`= 536870912, `scriptname`= 'npc_siamat_minion_of_siamat' WHERE `entry`= 44704; +UPDATE `creature_template` SET `minlevel`= 83, `maxlevel`= 83, `exp`= 3, `faction`= 16 , `movementId`= 130, `flags_extra`= 536870912 WHERE `entry`= 49260; +-- Minion of Siamat (Tempest Storm trigger) +UPDATE `creature_template` SET `minlevel`= 83, `maxlevel`= 83, `faction`= 16 , `unit_flags`= 33554496, `flags_extra`= 128 | 536870912 WHERE `entry`= 44713; + +DELETE FROM `spell_dbc` WHERE `Id`= 59632; +INSERT INTO `spell_dbc` (`Id`, `DurationIndex`, `Comment`) VALUES +(59632, 21, "Serverside Spell: mod scale 0.1"); + +DELETE FROM `spelleffect_dbc` WHERE `Id`= 160080; +INSERT INTO `spelleffect_dbc` (`Id`, `EffectSpellId`, `Effect`, `EffectApplyAuraName`, `EffectBasePoints`, `EffectIndex`) VALUES +(160080, 59632, 6, 61, -90, 0); + +DELETE FROM `creature_template_addon` WHERE `entry` IN (45259, 45268, 45269, 49256, 49257, 49258, 44541, 44704, 49260, 44713); +INSERT INTO `creature_template_addon` (`entry`, `Auras`) VALUES +(45259, '59632'), +(45268, '59632'), +(45269, '59632'), +(49256, '59632'), +(49257, '59632'), +(49258, '59632'), +(44541, '83048'), +(44704, '59632'), +(49260, '59632'), +(44713, '84512'); + +DELETE FROM `creature_text` WHERE `CreatureID`= 44819; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `comment`) VALUES +(44819, 0, 0, 'I. AM. UNLEASHED!', 14, 0, 100, 0, 0, 20231, 45481, 'Siamat - Intro'), +(44819, 1, 0, 'Winds of the south, rise and come to your master''s aid!', 14, 0, 100, 0, 0, 20227, 45483, 'Siamat - Aggro 1'), +(44819, 1, 1, 'Your city will be buried, your lives forfeit to the elements!', 14, 0, 100, 0, 0, 20230, 45486, 'Siamat - Aggro 2'), +(44819, 2, 0, 'Cower before the tempest storm!', 14, 0, 100, 0, 0, 20228, 45487, 'Siamat - Wailing Winds 1'), +(44819, 2, 1, 'Suffer the storm!', 14, 0, 100, 0, 0, 20229, 45485, 'Siamat - Wailing Winds 2'), +(44819, 3, 0, 'Nothing more than dust in the wind.', 14, 0, 100, 0, 0, 20232, 45482, 'Siamat - Slay'), +(44819, 4, 0, 'The sky... Beckons...', 14, 0, 100, 0, 0, 20226, 45484, 'Siamat - Death'); +UPDATE `creature_text` SET `TextRange`= 2 WHERE `CreatureID`= 44819 AND `GroupID`= 0; + +-- Spell Script Names +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_siamat_thunder_crash', +'spell_siamat_wailing_winds', +'spell_siamat_cloud_burst', +'spell_siamat_wailing_winds_player', +'spell_siamat_wailing_winds_knockback', +'spell_siamat_gathered_storms', +'spell_siamat_absorb_storms'); + +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(84521, 'spell_siamat_thunder_crash'), +(83066, 'spell_siamat_wailing_winds'), +(83790, 'spell_siamat_cloud_burst'), +(83089, 'spell_siamat_wailing_winds_player'), +(83566, 'spell_siamat_wailing_winds_knockback'), +(84987, 'spell_siamat_gathered_storms'), +(83151, 'spell_siamat_absorb_storms'); + +DELETE FROM `conditions` WHERE `SourceEntry`= 83151 AND `SourceTypeOrReferenceId`= 13; +INSERT INTO conditions (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ScriptName`, `Comment`) VALUES +(13, 1, 83151, 0, 0, 31, 0, 3, 44713, 0, 0, 0, '', 'Absorb Storms - Target Minion of Siamat'); + +-- Creature Cloud Burst 44541 SAI +SET @ENTRY := 44541; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`= @ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(@ENTRY, 0, 0, 1, 60, 0, 100, 1, 3000, 3000, 0, 0, 11, 83051, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "Every 0 and 0 ms (for the first time, timer between 3000 and 3000 ms) - Self: Cast spell 83051 on Self // "), +(@ENTRY, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 28, 83048, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, " Linked - Self: Remove aura due to spell 83048 // "), +(@ENTRY, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 41, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, " Linked - Self: Despawn in 5000 ms // "); + +-- Creature Minion of Siamat 44713 SAI +SET @ENTRY := 44713; +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`= @ENTRY; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ENTRY AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(@ENTRY, 0, 0, 1, 60, 0, 100, 1, 1000, 1000, 0, 0, 11, 83406, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, "Every 0 and 0 ms (for the first time, timer between 1000 and 1000 ms) - Self: Cast spell 83406 on Self // "), +(@ENTRY, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 89, 10, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, " Linked - Self: Move in radius 10 yards // "); diff --git a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_siamat.cpp b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_siamat.cpp new file mode 100644 index 00000000000..6d9e6ab6d5c --- /dev/null +++ b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_siamat.cpp @@ -0,0 +1,775 @@ +/* +* 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 "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "Player.h" +#include "lost_city_of_the_tolvir.h" + +enum Texts +{ + SAY_UNLEASHED = 0, + SAY_AGGRO = 1, + SAY_WAILING_WINDS = 2, + SAY_SLAY = 3, + SAY_DEATH = 4 +}; + +enum Spells +{ + // Siamat + SPELL_STATIC_SHOCK_1 = 84546, + SPELL_STATIC_SHOCK_2 = 84555, + SPELL_STATIC_SHOCK_3 = 84556, + SPELL_STORM_BOLT = 73564, + SPELL_DEFLECTING_WINDS = 84589, + SPELL_WAILING_WINDS = 83066, + SPELL_WAILING_WINDS_DAMAGE = 83094, + SPELL_CLOUD_BURST = 83790, + SPELL_CALL_OF_SKY = 84956, + SPELL_STORM_BOLT_PHASE_2 = 91853, + SPELL_ABSORB_STORMS = 83151, + + // Servant of Siamat + SPELL_MOD_SCALE = 59632, + SPELL_THUNDER_CRASH = 84521, + SPELL_LIGHTNING_NOVA = 84544, + SPELL_LIGHTNING_CHARGE = 91872, + + // Minion of Siamat + SPELL_DEPLETION = 84550, + SPELL_CHAIN_LIGHTNING = 83455, + SPELL_TEMPEST_STORM_SUMMON = 83414, + SPELL_TEMPEST_STORM_TRANSFORM = 83170 +}; + +enum Events +{ + // Siamat + EVENT_TALK_UNLEASHED = 1, + EVENT_STATIC_SHOCK, + EVENT_DEFLECTING_WINDS, + EVENT_STORM_BOLT, + EVENT_CLOUD_BURST, + EVENT_CALL_OF_SKY, + EVENT_WAILING_WINDS, + EVENT_ABSORB_STORMS, + EVENT_CHASE_PLAYER, + + // Servant of Siamat + EVENT_REMOVE_SCALE_AURA, + EVENT_SEND_ENCOUNTER_FRAME, + EVENT_ATTACK_PLAYER, + EVENT_THUNDER_CRASH, + EVENT_LIGHTNING_NOVA, + EVENT_LIGHTNING_CHARGE, + EVENT_KILL_SELF, + + // Minion of Siamat + EVENT_CHAIN_LIGHTNING, + + // Tempest Storm + EVENT_MOVE_ARROUND +}; + +enum Phases +{ + PHASE_INTRO = 1, + PHASE_1 = 2, + PHASE_2 = 3 +}; + +enum Actions +{ + ACTION_UNLEASHED = 1 +}; + +class boss_siamat : public CreatureScript +{ + public: + boss_siamat() : CreatureScript("boss_siamat") { } + + struct boss_siamatAI : public BossAI + { + boss_siamatAI(Creature* creature) : BossAI(creature, DATA_SIAMAT) + { + Initialize(); + } + + void Initialize() + { + _lastStaticShockSpellID = 0; + _deadServants = 0; + } + + void Reset() override + { + _Reset(); + Initialize(); + SetCombatMovement(false); + } + + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _EnterCombat(); + events.SetPhase(PHASE_1); + events.ScheduleEvent(EVENT_STATIC_SHOCK, 1, 0, PHASE_1); + events.ScheduleEvent(EVENT_DEFLECTING_WINDS, Seconds(6), 0, PHASE_1); + events.ScheduleEvent(EVENT_STORM_BOLT, Seconds(1), 0, PHASE_1); + events.ScheduleEvent(EVENT_CLOUD_BURST, Seconds(13), PHASE_1); + events.ScheduleEvent(EVENT_CALL_OF_SKY, Seconds(13)); + } + + void JustDied(Unit* /*killer*/) + { + Talk(SAY_DEATH); + DespawnServants(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + _JustDied(); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + summons.DespawnAll(); + DespawnServants(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + _DespawnAtEvade(); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_UNLEASHED: + events.SetPhase(PHASE_INTRO); + events.ScheduleEvent(EVENT_TALK_UNLEASHED, Seconds(15)); + break; + default: + break; + } + } + + void DespawnServants() + { + for (uint8 i = 0; i < 3; i++) + { + if (Creature* servant = instance->GetCreature(DATA_SERVANT_OF_SIAMAT_1 + i)) + { + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, servant); + servant->DespawnOrUnsummon(Milliseconds(100)); + } + } + } + + void JustSummoned(Creature* summon) override + { + switch (summon->GetEntry()) + { + case NPC_SERVANT_OF_SIAMAT_1: + case NPC_SERVANT_OF_SIAMAT_2: + case NPC_SERVANT_OF_SIAMAT_3: + break; + case NPC_CLOUD_BURST: + // needed to prevent that weird imp model showing up that is NOT + // inside the db but still shows up for some reason + summon->SetDisplayId(summon->GetCreatureTemplate()->Modelid2); + break; + default: + summons.Summon(summon); + break; + } + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + switch (summon->GetEntry()) + { + case NPC_SERVANT_OF_SIAMAT_1: + case NPC_SERVANT_OF_SIAMAT_2: + case NPC_SERVANT_OF_SIAMAT_3: + _deadServants++; + if (_deadServants == 3) + { + events.CancelEvent(EVENT_STORM_BOLT); + events.CancelEvent(EVENT_CLOUD_BURST); + events.SetPhase(PHASE_2); + events.ScheduleEvent(EVENT_WAILING_WINDS, 1, 0, PHASE_2); + } + 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_TALK_UNLEASHED: + Talk(SAY_UNLEASHED); + break; + case EVENT_STATIC_SHOCK: + if (_lastStaticShockSpellID == 0) + { + DoCastAOE(SPELL_STATIC_SHOCK_1); + _lastStaticShockSpellID = SPELL_STATIC_SHOCK_1; + events.Repeat(Seconds(45)); + } + else if (_lastStaticShockSpellID == SPELL_STATIC_SHOCK_1) + { + DoCastAOE(SPELL_STATIC_SHOCK_2); + _lastStaticShockSpellID = SPELL_STATIC_SHOCK_2; + events.Repeat(Seconds(45)); + } + else if (_lastStaticShockSpellID == SPELL_STATIC_SHOCK_2) + DoCastAOE(SPELL_STATIC_SHOCK_3); + break; + case EVENT_DEFLECTING_WINDS: + DoCastSelf(SPELL_DEFLECTING_WINDS); + break; + case EVENT_STORM_BOLT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true, 0)) + DoCast(target, events.IsInPhase(PHASE_1) ? SPELL_STORM_BOLT : SPELL_STORM_BOLT_PHASE_2); + + events.Repeat(events.IsInPhase(PHASE_1) ? Seconds(2) + Milliseconds(200) : Seconds(22)); + break; + case EVENT_CLOUD_BURST: + // Why do we need a specific target here when we have TARGET_UNIT_SRC_AREA_ENEMY as target??? + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true, 0)) + DoCast(target, SPELL_CLOUD_BURST, true); + events.Repeat(Seconds(27)); + break; + case EVENT_WAILING_WINDS: + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + Talk(SAY_WAILING_WINDS); + me->RemoveAurasDueToSpell(SPELL_DEFLECTING_WINDS); + DoCastAOE(SPELL_WAILING_WINDS); + events.ScheduleEvent(EVENT_CHASE_PLAYER, Seconds(6)); + events.ScheduleEvent(EVENT_STORM_BOLT, Seconds(19)); + events.ScheduleEvent(EVENT_ABSORB_STORMS, Seconds(14)); + break; + case EVENT_CALL_OF_SKY: + DoCastAOE(SPELL_CALL_OF_SKY, true); + events.Repeat(Seconds(32)); + break; + case EVENT_ABSORB_STORMS: + if (me->FindNearestCreature(NPC_MINION_OF_SIAMAT_STORM, 50.0f, true)) + DoCastAOE(SPELL_ABSORB_STORMS); + events.Repeat(Seconds(32)); + break; + case EVENT_CHASE_PLAYER: + SetCombatMovement(true); + if (me->GetVictim()) + me->GetMotionMaster()->MoveChase(me->GetVictim()); + break; + default: + break; + } + } + if (events.IsInPhase(PHASE_2)) + DoMeleeAttackIfReady(); + } + private: + uint32 _lastStaticShockSpellID; + uint8 _deadServants; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetLostCityOfTheTolvirAI(creature); + } +}; + +class npc_siamat_servant_of_siamat : public CreatureScript +{ + public: + npc_siamat_servant_of_siamat() : CreatureScript("npc_siamat_servant_of_siamat") { } + + struct npc_siamat_servant_of_siamatAI : public ScriptedAI + { + npc_siamat_servant_of_siamatAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + _chargeTriggered = false; + _events.SetPhase(PHASE_INTRO); + + if (_instance->GetBossState(DATA_SIAMAT) != IN_PROGRESS) + me->DespawnOrUnsummon(); + else + _events.ScheduleEvent(EVENT_SEND_ENCOUNTER_FRAME, Seconds(1)); + } + + + void EnterCombat(Unit* /*who*/) override + { + _events.SetPhase(PHASE_1); + _events.ScheduleEvent(EVENT_THUNDER_CRASH, Seconds(11)); + _events.ScheduleEvent(EVENT_LIGHTNING_NOVA, Seconds(13)); + } + + void JustDied(Unit* /*killer*/) override + { + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + me->DespawnOrUnsummon(Seconds(5)); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (me->HealthBelowPct(4) && !_chargeTriggered) + { + if (IsHeroic()) + { + _chargeTriggered = true; + _events.Reset(); + _events.ScheduleEvent(EVENT_LIGHTNING_CHARGE, 1); + } + } + + if (IsHeroic()) + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + } + + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !_events.IsInPhase(PHASE_INTRO)) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_SEND_ENCOUNTER_FRAME: + _instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + _events.ScheduleEvent(EVENT_REMOVE_SCALE_AURA, Seconds(1)); + break; + case EVENT_REMOVE_SCALE_AURA: + me->RemoveAurasDueToSpell(SPELL_MOD_SCALE); + _events.ScheduleEvent(EVENT_ATTACK_PLAYER, Seconds(2)); + break; + case EVENT_ATTACK_PLAYER: + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + break; + case EVENT_THUNDER_CRASH: + DoCastSelf(SPELL_THUNDER_CRASH); + break; + case EVENT_LIGHTNING_NOVA: + DoCastAOE(SPELL_LIGHTNING_NOVA, true); + break; + case EVENT_LIGHTNING_CHARGE: + DoCastAOE(SPELL_LIGHTNING_CHARGE); + _events.ScheduleEvent(EVENT_KILL_SELF, Seconds(2) + Milliseconds(100)); + break; + case EVENT_KILL_SELF: + me->KillSelf(); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + private: + EventMap _events; + InstanceScript* _instance; + bool _chargeTriggered; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetLostCityOfTheTolvirAI(creature); + } +}; + +class npc_siamat_minion_of_siamat : public CreatureScript +{ + public: + npc_siamat_minion_of_siamat() : CreatureScript("npc_siamat_minion_of_siamat") { } + + struct npc_siamat_minion_of_siamatAI : public ScriptedAI + { + npc_siamat_minion_of_siamatAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + // Yes, we need to place it in here. Reset() is still too "late" + void InitializeAI() override + { + me->SetReactState(REACT_PASSIVE); + _transformed = false; + _events.SetPhase(PHASE_INTRO); + _events.ScheduleEvent(EVENT_REMOVE_SCALE_AURA, Seconds(1)); + } + + void EnterCombat(Unit* /*who*/) override + { + _events.SetPhase(PHASE_1); + _events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, Seconds(3)); + } + + void JustSummoned(Creature* summon) override + { + if (Creature* siamat = _instance->GetCreature(DATA_SIAMAT)) + siamat->AI()->JustSummoned(summon); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (me->HealthBelowPct(5) && !_transformed) + { + _events.Reset(); + me->AttackStop(); + me->CastStop(); + me->SetReactState(REACT_PASSIVE); + DoCastSelf(SPELL_TEMPEST_STORM_SUMMON, true); + DoCastSelf(SPELL_TEMPEST_STORM_TRANSFORM); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->DespawnOrUnsummon(Seconds(4)); + _transformed = true; + } + + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + } + + 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_REMOVE_SCALE_AURA: + me->RemoveAurasDueToSpell(SPELL_MOD_SCALE); + DoCastSelf(SPELL_DEPLETION, true); + _events.ScheduleEvent(EVENT_ATTACK_PLAYER, Seconds(1) + Milliseconds(500)); + break; + case EVENT_ATTACK_PLAYER: + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + break; + case EVENT_CHAIN_LIGHTNING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true, 0)) + DoCast(target, SPELL_CHAIN_LIGHTNING); + _events.Repeat(Seconds(1) + Milliseconds(500)); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + private: + EventMap _events; + InstanceScript* _instance; + bool _transformed; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_siamat_minion_of_siamatAI(creature); + } +}; + +class spell_siamat_thunder_crash : public SpellScriptLoader +{ + public: + spell_siamat_thunder_crash() : SpellScriptLoader("spell_siamat_thunder_crash") { } + + class spell_siamat_thunder_crash_AuraScript : public AuraScript + { + PrepareAuraScript(spell_siamat_thunder_crash_AuraScript); + + void HandleTick(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (Unit* caster = GetCaster()) + if (Unit* victim = caster->GetVictim()) + caster->CastSpell(victim, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_siamat_thunder_crash_AuraScript::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_siamat_thunder_crash_AuraScript(); + } +}; + +class spell_siamat_wailing_winds : public SpellScriptLoader +{ + public: + spell_siamat_wailing_winds() : SpellScriptLoader("spell_siamat_wailing_winds") { } + + class spell_siamat_wailing_winds_AuraScript : public AuraScript + { + PrepareAuraScript(spell_siamat_wailing_winds_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(caster, SPELL_WAILING_WINDS_DAMAGE, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_siamat_wailing_winds_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_siamat_wailing_winds_AuraScript(); + } +}; + +class spell_siamat_wailing_winds_player : public SpellScriptLoader +{ +public: + spell_siamat_wailing_winds_player() : SpellScriptLoader("spell_siamat_wailing_winds_player") { } + + class spell_siamat_wailing_winds_player_AuraScript : public AuraScript + { + PrepareAuraScript(spell_siamat_wailing_winds_player_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (GetCaster()) + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* siamat = instance->GetCreature(DATA_SIAMAT)) + siamat->CastSpell(siamat, GetSpellInfo()->Effects[EFFECT_1].TriggerSpell, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_siamat_wailing_winds_player_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_siamat_wailing_winds_player_AuraScript(); + } +}; + +class spell_siamat_wailing_winds_knockback : public SpellScriptLoader +{ +public: + spell_siamat_wailing_winds_knockback() : SpellScriptLoader("spell_siamat_wailing_winds_knockback") { } + + class spell_siamat_wailing_winds_knockback_SpellScript : public SpellScript + { + PrepareSpellScript(spell_siamat_wailing_winds_knockback_SpellScript); + + void EffectScriptEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + if (Unit* victim = GetHitUnit()) + { + float distance = caster->GetDistance2d(caster) * 2; + float ori = frand(0.0f, float(M_PI * 2)); + float randX = victim->GetPositionX() + cos(ori) * distance; + float randY = victim->GetPositionY() + sin(ori) * distance; + float baseSpeed = float(GetSpellInfo()->Effects[EFFECT_1].BasePoints); + + victim->KnockbackFrom(randX, randY, CalculatePct(baseSpeed - distance, 15), 9.0f); + }; + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_siamat_wailing_winds_knockback_SpellScript::EffectScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_siamat_wailing_winds_knockback_SpellScript(); + } +}; + +class spell_siamat_cloud_burst : public SpellScriptLoader +{ +public: + spell_siamat_cloud_burst() : SpellScriptLoader("spell_siamat_cloud_burst") { } + + class spell_siamat_cloud_burst_SpellScript : public SpellScript + { + PrepareSpellScript(spell_siamat_cloud_burst_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_siamat_cloud_burst_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_siamat_cloud_burst_SpellScript(); + } +}; + +class spell_siamat_gathered_storms : public SpellScriptLoader +{ +public: + spell_siamat_gathered_storms() : SpellScriptLoader("spell_siamat_gathered_storms") { } + + class spell_siamat_gathered_storms_SpellScript : public SpellScript + { + PrepareSpellScript(spell_siamat_gathered_storms_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 2); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_siamat_gathered_storms_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_siamat_gathered_storms_SpellScript(); + } +}; + +class spell_siamat_absorb_storms : public SpellScriptLoader +{ + public: + spell_siamat_absorb_storms() : SpellScriptLoader("spell_siamat_absorb_storms") { } + + class spell_siamat_absorb_storms_AuraScript : public AuraScript + { + PrepareAuraScript(spell_siamat_absorb_storms_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (Unit* caster = GetCaster()) + caster->CastSpell(caster, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_siamat_absorb_storms_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + class spell_siamat_absorb_storms_SpellScript : public SpellScript + { + PrepareSpellScript(spell_siamat_absorb_storms_SpellScript); + + void HandleHit(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + { + caster->SetFacingToObject(GetHitUnit()); + if (GetHitUnit()->GetTypeId() == TYPEID_UNIT) + GetHitUnit()->ToCreature()->DespawnOrUnsummon(Seconds(3) + Milliseconds(100)); + } + } + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_siamat_absorb_storms_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_siamat_absorb_storms_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_siamat_absorb_storms_AuraScript(); + } + + SpellScript* GetSpellScript() const + { + return new spell_siamat_absorb_storms_SpellScript(); + } +}; + +void AddSC_boss_siamat() +{ + new boss_siamat(); + new npc_siamat_servant_of_siamat(); + new npc_siamat_minion_of_siamat(); + new spell_siamat_thunder_crash(); + new spell_siamat_wailing_winds(); + new spell_siamat_wailing_winds_player(); + new spell_siamat_wailing_winds_knockback(); + new spell_siamat_cloud_burst(); + new spell_siamat_gathered_storms(); + new spell_siamat_absorb_storms(); +} 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 c6edba02f3e..61427c035df 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 @@ -33,7 +33,10 @@ enum Actions { // Lockmaw and Augh ACTION_AUGH_INTRO = 1, - ACTION_AUGH_ATTACKABLE = 2 + ACTION_AUGH_ATTACKABLE = 2, + + // Siamat + ACTION_UNLEASHED = 1 }; Position const AughSpawnPos = { -11058.91f, -1625.342f, -0.1304993f, 4.782202f }; @@ -48,6 +51,9 @@ 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 }, + { NPC_SERVANT_OF_SIAMAT_1, DATA_SERVANT_OF_SIAMAT_1 }, + { NPC_SERVANT_OF_SIAMAT_2, DATA_SERVANT_OF_SIAMAT_2 }, + { NPC_SERVANT_OF_SIAMAT_3, DATA_SERVANT_OF_SIAMAT_3 }, { 0, 0 } // End }; @@ -116,6 +122,9 @@ class instance_lost_city_of_the_tolvir : public InstanceMapScript platform->EnableCollision(true); } + if (Creature* siamat = GetCreature(DATA_SIAMAT)) + siamat->AI()->DoAction(ACTION_UNLEASHED); + instance->SetZoneWeather(ZONE_ID_LOST_CITY, WEATHER_STATE_HEAVY_RAIN, 1.0f); instance->SummonCreatureGroup(SUMMON_GROUP_WIND_TUNNEL); } 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 db66b5c2038..b2dd32c0f38 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 @@ -37,7 +37,10 @@ enum LCTDataTypes DATA_SIAMAT_PLATFORM = 6, DATA_BLAZE_OF_THE_HEAVENS = 7, DATA_HARBINGER_OF_DARKNESS = 8, - DATA_LOCKMAW_COMBAT_ASSISTANCE = 9 + DATA_LOCKMAW_COMBAT_ASSISTANCE = 9, + DATA_SERVANT_OF_SIAMAT_1 = 10, + DATA_SERVANT_OF_SIAMAT_2 = 11, + DATA_SERVANT_OF_SIAMAT_3 = 11, }; enum LCTCreatureIds @@ -60,7 +63,13 @@ enum LCTCreatureIds NPC_HARBINGER_OF_DARKNESS = 43927, NPC_DUST_FLAIL_FRONT_STALKER = 43655, NPC_ADD_STALKER = 45124, - NPC_AUGH_DART = 45379 + NPC_AUGH_DART = 45379, + NPC_SERVANT_OF_SIAMAT_1 = 45259, + NPC_SERVANT_OF_SIAMAT_2 = 45268, + NPC_SERVANT_OF_SIAMAT_3 = 45269, + NPC_MINION_OF_SIAMAT = 44704, + NPC_MINION_OF_SIAMAT_STORM = 44713, + NPC_CLOUD_BURST = 44541 }; enum LCTGameObjectIds diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp index d03254e618b..09d0a719aa1 100644 --- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp +++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp @@ -96,6 +96,8 @@ void AddSC_instance_zulfarrak(); void AddSC_instance_lost_city_of_the_tolvir(); // Lost City of the Tol'Vir void AddSC_boss_general_husam(); void AddSC_boss_high_prophet_barim(); +void AddSC_boss_lockmaw_and_augh(); +void AddSC_boss_siamat(); void AddSC_instance_halls_of_origination(); //Halls of Origination void AddSC_boss_temple_guardian_anhuur(); void AddSC_boss_earthrager_ptah(); @@ -209,6 +211,8 @@ void AddKalimdorScripts() AddSC_instance_lost_city_of_the_tolvir(); // Lost City of the Tol'Vir AddSC_boss_general_husam(); AddSC_boss_high_prophet_barim(); + AddSC_boss_lockmaw_and_augh(); + AddSC_boss_siamat(); AddSC_instance_halls_of_origination(); //Halls of Origination AddSC_boss_temple_guardian_anhuur(); AddSC_boss_earthrager_ptah();