Scripts/VioletHold: rewrote the whole instance

thanks @MitchesD for help

(cherry picked from commit df21162fe44d2ff29c201a9004586f560789c38b)
(cherry picked from commit 3a4f54197c05ce4209c7e659acfd382896607265)
(cherry picked from commit f50df728201849ee7185d33c5a061c91e781c8de)
(cherry picked from commit 95bae7143f0f4bb7d5975f8a61daa3c533f48225)
(cherry picked from commit 5406f82044e7bd6ceb024a67f33c1674400cdc1f)
This commit is contained in:
joschiwald
2015-11-01 13:09:30 +01:00
committed by Shauren
parent 7b684e8813
commit 92b08fc74b
32 changed files with 3261 additions and 3277 deletions
@@ -0,0 +1,150 @@
DELETE FROM `spell_linked_spell` WHERE `spell_trigger`=58694;
DELETE FROM `spell_script_names` WHERE `ScriptName` IN (
'spell_cyanigosa_arcane_vacuum',
'spell_ichoron_splatter',
'spell_ichoron_protective_bubble',
'spell_ichoron_drained',
'spell_ichoron_merge',
'spell_moragg_ray',
'spell_moragg_ray_of_pain',
'spell_moragg_ray_of_suffering',
'spell_xevozz_summon_ethereal_sphere',
'spell_violet_hold_destroy_door_seal',
'spell_violet_hold_portal_periodic',
'spell_violet_hold_teleport_player',
'spell_crystal_activation'
);
INSERT INTO `spell_script_names`(`spell_id`,`ScriptName`) values
(58694,'spell_cyanigosa_arcane_vacuum'),
(54259,'spell_ichoron_splatter'),
(54306,'spell_ichoron_protective_bubble'),
(59820,'spell_ichoron_drained'),
(54269,'spell_ichoron_merge'),
(54438,'spell_moragg_ray'),
(54442,'spell_moragg_ray'),
(59523,'spell_moragg_ray'),
(59524,'spell_moragg_ray'),
(58040,'spell_violet_hold_destroy_door_seal'),
(58008,'spell_violet_hold_portal_periodic'),
(62138,'spell_violet_hold_teleport_player');
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 and `SourceEntry` IN (57912, 57930, 58152, 54258, 54264, 54265, 54266, 54267, 54269);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
(13,1,57912,0,0,31,0,3,29425,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,57930,0,0,31,0,3,30857,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,0,31,0,3,30661,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,1,31,0,3,30662,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,2,31,0,3,30663,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,3,31,0,3,30664,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,4,31,0,3,30665,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,5,31,0,3,30666,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,6,31,0,3,30667,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,7,31,0,3,30668,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,8,31,0,3,30918,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,9,31,0,3,30961,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,10,31,0,3,30962,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,11,31,0,3,30963,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,12,31,0,3,31007,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,13,31,0,3,31008,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,14,31,0,3,31009,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,15,31,0,3,31010,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,16,31,0,3,31118,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,58152,0,17,31,0,3,32191,0,0,0,0,'','Defense System - Arcane Lightning'),
(13,1,54258,0,0,31,0,3,29326,102906,0,0,0,'','Ichoron - Water Globule'),
(13,1,54264,0,0,31,0,3,29326,102905,0,0,0,'','Ichoron - Water Globule'),
(13,1,54265,0,0,31,0,3,29326,102904,0,0,0,'','Ichoron - Water Globule'),
(13,1,54266,0,0,31,0,3,29326,102901,0,0,0,'','Ichoron - Water Globule'),
(13,1,54267,0,0,31,0,3,29326,102902,0,0,0,'','Ichoron - Water Globule'),
(13,1,54269,0,0,31,0,3,29313,0,0,0,0,'','Ichoron - Merge');
UPDATE `creature_template` SET `gossip_menu_id`=9997 WHERE `entry`=30658;
UPDATE `gossip_menu_option` SET `action_menu_id`=9998 WHERE `menu_id`=9997;
UPDATE `creature_template` SET `ScriptName`='npc_violet_hold_teleportation_portal' WHERE `entry`=30679;
UPDATE `creature_template` SET `ScriptName`='npc_violet_hold_teleportation_portal_elite' WHERE `entry`=32174;
UPDATE `creature_template` SET `ScriptName`='npc_violet_hold_teleportation_portal_intro' WHERE `entry`=31011;
UPDATE `creature_template` SET `ScriptName`='npc_violet_hold_defense_system' WHERE `entry`=30837;
UPDATE `creature_template` SET `unit_flags`=832 WHERE `entry` IN (31134, 31506); -- Cyanigosa
UPDATE `creature_template` SET `speed_walk`=2.22222/2.5, `speed_run`=8.0/7.0, `unit_flags`=768 WHERE `entry` IN (31079, 31492); -- Azure Saboteur
UPDATE `creature_template` SET `speed_walk`=4.0/2.5, `speed_run`=12.0/7.0, `unit_flags`=832 WHERE `entry` IN (29266, 31511, 32231, 32552); -- Xevozz
UPDATE `creature_template` SET `speed_walk`=3.0/2.5, `speed_run`=3.0/7.0 WHERE `entry` IN (29271, 31514, 32582, 32583); -- Ethereal Sphere
UPDATE `creature_template` SET `speed_walk`=4.0/2.5, `speed_run`=12.0/7.0, `unit_flags`=832 WHERE `entry` IN (29312, 31509, 32237, 32553); -- Lavanthor
UPDATE `creature_template` SET `speed_walk`=4.0/2.5, `speed_run`=12.0/7.0, `unit_flags`=832 WHERE `entry` IN (29313, 31508, 32234, 32554); -- Ichoron
UPDATE `creature_template` SET `speed_walk`=4.0/2.5, `speed_run`=4.0/7.0, `unit_flags`=33587200 WHERE `entry` IN (29321, 31515); -- Ichor Globule
UPDATE `creature_template` SET `speed_walk`=4.0/2.5, `speed_run`=12.0/7.0, `unit_flags`=832 WHERE `entry` IN (29314, 31512, 32230, 32555); -- Zuramat
UPDATE `creature_template` SET `speed_walk`=4.0/2.5, `speed_run`=10.0/7.0, `unit_flags`=33600 WHERE `entry` IN (29315, 31507, 32226, 32550); -- Erekem
UPDATE `creature_template` SET `speed_walk`=4.0/2.5, `speed_run`=10.0/7.0, `unit_flags`=33600 WHERE `entry` IN (29395, 31513, 32228, 32549); -- Erekem Guard
UPDATE `creature_template` SET `speed_walk`=4.0/2.5, `speed_run`=12.0/7.0, `unit_flags`=33600 WHERE `entry` IN (29316, 31510, 32235, 32551); -- Moragg
UPDATE `creature_template` SET `minlevel`=77, `maxlevel`=77, `ScriptName`='boss_xevozz' WHERE `entry`=32231; -- Xevozz
UPDATE `creature_template` SET `minlevel`=77, `maxlevel`=77, `ScriptName`='boss_lavanthor' WHERE `entry`=32237; -- Lavanthor
UPDATE `creature_template` SET `minlevel`=77, `maxlevel`=77, `ScriptName`='boss_ichoron' WHERE `entry`=32234; -- Ichoron
UPDATE `creature_template` SET `minlevel`=77, `maxlevel`=77, `ScriptName`='boss_zuramat' WHERE `entry`=32230; -- Zuramat
UPDATE `creature_template` SET `minlevel`=77, `maxlevel`=77, `ScriptName`='boss_erekem' WHERE `entry`=32226; -- Erekem
UPDATE `creature_template` SET `minlevel`=76, `maxlevel`=76, `ScriptName`='npc_erekem_guard' WHERE `entry`=32228; -- Erekem Guard
UPDATE `creature_template` SET `minlevel`=77, `maxlevel`=77, `ScriptName`='boss_moragg' WHERE `entry`=32235; -- Moragg
DELETE FROM `smart_scripts` WHERE `entryorguid` IN (29364, 29365); -- Void Sentry
UPDATE `creature_template` SET `flags_extra`=0, `AIName`='', `ScriptName`='npc_void_sentry' WHERE `entry`=29364; -- Void Sentry
UPDATE `creature_template` SET `AIName`='' WHERE `entry`=29365; -- Void Sentry
UPDATE `creature_template` SET `unit_flags`=0, `unit_flags2`=0 WHERE `entry` IN (29364, 31518);
UPDATE `creature_template` SET `unit_flags`=33554432, `unit_flags2`=2080 WHERE `entry` IN (29365, 31519); -- Void Sentry
UPDATE `creature_template` SET `flags_extra`=`flags_extra`|0x1 WHERE `entry` IN (32552, 32553, 32554, 32555, 32550, 32551);
UPDATE `creature_template` SET `mechanic_immune_mask`=536941137 WHERE `entry` IN (32231, 32552, 32237, 32553, 32234, 32554, 32230, 32555, 32226, 32550, 32228, 32549, 32235, 32551);
UPDATE `creature_template` SET `InhabitType`=4, `flags_extra`=128 WHERE `entry`=30837;
UPDATE `creature_template` SET `InhabitType`=4 WHERE `entry` IN (29326, 30896);
UPDATE `creature` SET `modelid`=0, `spawndist`=0, `MovementType`=0 WHERE `id` IN (29326, 30896);
UPDATE `creature_template` SET `AIName`='' WHERE `entry` IN (32226,32228,32230,32231,32234,32235,32237);
DELETE FROM `smart_scripts` WHERE `entryorguid` IN (32226,32228,32230,32231,32234,32235,32237);
DELETE FROM `creature_template_addon` WHERE `entry` IN (30837, 30896, 31079, 29364, 29365, 31518, 31519);
INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `bytes2`, `auras`) VALUES
(30837, 0, 0x3000000, 0x1, '57886 57887'),
(30896, 0, 0x3000000, 0x1, ''),
(31079, 0, 0x0, 0x1, '31635'),
(29364, 0, 0x0, 0x1, '54351 54341'),
(29365, 0, 0x0, 0x1, '54351 54342'),
(31518, 0, 0x0, 0x1, '54351 54341'),
(31519, 0, 0x0, 0x1, '54351 59747');
DELETE FROM `creature_text` WHERE `entry` IN (30658, 32204, 29271);
DELETE FROM `creature_text` WHERE `entry`=29313 AND `groupid`=7;
INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(30658, 0, 0, 'Prison guards, we are leaving! These adventurers are taking over! Go go go!', 14, 0, 100, 5, 0, 0, 31474, 3, 'Lieutenant Sinclari - Intro 1'),
(30658, 1, 0, 'I''m locking the door. Good luck, and thank you for doing this.', 12, 0, 100, 396, 0, 0, 31475, 3, 'Lieutenant Sinclari - Intro 2'),
(30658, 2, 0, 'You did it! You held the Blue Dragonflight back and defeated their commander. Amazing work!', 12, 0, 100, 396, 0, 0, 31694, 3, 'Lieutenant Sinclari - Outro'),
(32204, 0, 0, 'An elite Blue Dragonflight squad appears from the portal!', 41, 0, 100, 0, 0, 0, 32994, 3, 'Lieutenant Sinclari - Blue Dragonflight squad'),
(32204, 1, 0, 'A Portal Guardian defends the new portal!', 41, 0, 100, 0, 0, 0, 32995, 3, 'Lieutenant Sinclari - Portal Guardian'),
(32204, 2, 0, 'A Portal Keeper emerges from the portal!', 41, 0, 100, 0, 0, 0, 32996, 3, 'Lieutenant Sinclari - Portal Keeper'),
(32204, 3, 0, 'Adventurers, the door is beginning to weaken!', 14, 0, 100, 0, 0, 0, 32557, 3, 'Lieutenant Sinclari - Door weaken'),
(32204, 4, 0, 'Only half of the door seal''s strength remains! You must fight on!', 14, 0, 100, 0, 0, 0, 32558, 3, 'Lieutenant Sinclari - Half Door Seal reains'),
(32204, 5, 0, 'The door seal is about to collapse! All is lost if the Blue Dragonflight breaks through the door!', 14, 0, 100, 0, 0, 0, 32559, 3, 'Lieutenant Sinclari - Door Seal broken'),
(29313, 7, 0, '%s''s Protective Bubble shatters!', 41, 0, 100, 0, 0, 0, 30086, 0, 'Ichoron - Emote Shatter'),
(29271, 0, 0, '%s begins to summon!', 41, 0, 100, 0, 0, 0, 30087, 3, 'Ethereal Sphere');
UPDATE `creature_text` SET `sound`=14499 WHERE `entry`=29266 AND `groupid`=0;
UPDATE `creature_text` SET `emote`=396 WHERE `entry`=29266 AND `groupid`=3;
UPDATE `creature_text` SET `emote`=15 WHERE `entry`=29315 AND `groupid`=3;
UPDATE `creature_text` SET `emote`=396 WHERE `entry`=31134 AND `groupid`=3;
DELETE FROM `spell_target_position` WHERE `ID` IN (54102, 54137, 54138, 61337, 61338, 61339, 62139);
INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `VerifiedBuild`) VALUES
(54102, 0, 608, 1854.36, 802.65, 44.3, 12340),
(54137, 0, 608, 1899.18, 824.7, 38.72333, 12340),
(54138, 0, 608, 1891.42, 788.04, 38.64, 12340),
(61337, 0, 608, 1854.36, 802.65, 44.3, 12340),
(61338, 0, 608, 1899.18, 824.7, 38.72333, 12340),
(61339, 0, 608, 1891.42, 788.04, 38.64, 12340),
(62139, 0, 608, 1857.24, 803.877, 44.0085, 12340);
@@ -446,7 +446,13 @@ BossAI::BossAI(Creature* creature, uint32 bossId) : ScriptedAI(creature),
instance(creature->GetInstanceScript()),
summons(creature),
_boundary(instance ? instance->GetBossBoundary(bossId) : NULL),
_bossId(bossId) { }
_bossId(bossId)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void BossAI::_Reset()
{
@@ -457,6 +463,7 @@ void BossAI::_Reset()
me->ResetLootMode();
events.Reset();
summons.DespawnAll();
scheduler.CancelAll();
if (instance)
instance->SetBossState(_bossId, NOT_STARTED);
}
@@ -465,15 +472,13 @@ void BossAI::_JustDied()
{
events.Reset();
summons.DespawnAll();
scheduler.CancelAll();
if (instance)
instance->SetBossState(_bossId, DONE);
}
void BossAI::_EnterCombat()
{
me->SetCombatPulseDelay(5);
me->setActive(true);
DoZoneInCombat();
if (instance)
{
// bosses do not respawn, check only on enter combat
@@ -484,6 +489,11 @@ void BossAI::_EnterCombat()
}
instance->SetBossState(_bossId, IN_PROGRESS);
}
me->SetCombatPulseDelay(5);
me->setActive(true);
DoZoneInCombat();
ScheduleTasks();
}
void BossAI::TeleportCheaters()
@@ -23,6 +23,7 @@
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "InstanceScript.h"
#include "TaskScheduler.h"
#define CAST_AI(a, b) (dynamic_cast<a*>(b))
#define ENSURE_AI(a,b) (EnsureAI<a>(b))
@@ -356,6 +357,8 @@ class BossAI : public ScriptedAI
// is supposed to run more than once
virtual void ExecuteEvent(uint32 /*eventId*/) { }
virtual void ScheduleTasks() { }
void Reset() override { _Reset(); }
void EnterCombat(Unit* /*who*/) override { _EnterCombat(); }
void JustDied(Unit* /*killer*/) override { _JustDied(); }
@@ -382,6 +385,7 @@ class BossAI : public ScriptedAI
EventMap events;
SummonList summons;
TaskScheduler scheduler;
private:
BossBoundaryMap const* const _boundary;
@@ -68,8 +68,8 @@ struct npc_escortAI : public ScriptedAI
void EnterEvadeMode() override;
void UpdateAI(uint32 diff) override; //the "internal" update, calls UpdateEscortAI()
virtual void UpdateEscortAI(uint32 const diff); //used when it's needed to add code in update (abilities, scripted events, etc)
void UpdateAI(uint32 diff) override; // the "internal" update, calls UpdateEscortAI()
virtual void UpdateEscortAI(uint32 diff); // used when it's needed to add code in update (abilities, scripted events, etc)
void MovementInform(uint32, uint32) override;
@@ -9267,6 +9267,17 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
packet.Worldstates.emplace_back(4131, 0); // 10 WORLDSTATE_ALGALON_DESPAWN_TIMER
}
break;
// Violet Hold
case 4415:
if (instance && mapid == 608)
instance->FillInitialWorldStates(packet);
else
{
packet.Worldstates.emplace_back(3816, 0); // 9 WORLD_STATE_VH_SHOW
packet.Worldstates.emplace_back(3815, 100); // 10 WORLD_STATE_VH_PRISON_STATE
packet.Worldstates.emplace_back(3810, 0); // 11 WORLD_STATE_VH_WAVE_COUNT
}
break;
// Halls of Refection
case 4820:
if (instance && mapid == 668)
@@ -319,6 +319,11 @@ bool InstanceScript::SetBossState(uint32 id, EncounterState state)
return false;
}
bool InstanceScript::_SkipCheckRequiredBosses(Player const* player /*= nullptr*/) const
{
return player && player->GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES);
}
void InstanceScript::Load(char const* data)
{
if (!data)
@@ -280,6 +280,8 @@ class InstanceScript : public ZoneScript
void WriteSaveDataBossStates(std::ostringstream& data);
virtual void WriteSaveDataMore(std::ostringstream& /*data*/) { }
bool _SkipCheckRequiredBosses(Player const* player = nullptr) const;
private:
static void LoadObjectData(ObjectData const* creatureData, ObjectInfoMap& objectInfo);
+18
View File
@@ -417,6 +417,24 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool
init.Launch();
}
void MotionMaster::MoveSmoothPath(uint32 pointId, G3D::Vector3 const* pathPoints, size_t pathSize, bool walk)
{
Movement::PointsArray path(pathPoints, pathPoints + pathSize);
Movement::MoveSplineInit init(_owner);
init.MovebyPath(path);
init.SetSmooth();
init.SetWalk(walk);
init.Launch();
// This code is not correct
// EffectMovementGenerator does not affect UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE
// need to call PointMovementGenerator with various pointIds
Mutate(new EffectMovementGenerator(pointId), MOTION_SLOT_ACTIVE);
//Position pos(pathPoints[pathSize - 1].x, pathPoints[pathSize - 1].y, pathPoints[pathSize - 1].z);
//MovePoint(EVENT_CHARGE_PREPATH, pos, false);
}
void MotionMaster::MoveFall(uint32 id /*=0*/)
{
// use larger distance for vmap height search than in most other cases
+1
View File
@@ -185,6 +185,7 @@ class MotionMaster //: private std::stack<MovementGenerator *>
{ MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); }
void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = EVENT_JUMP);
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount);
void MoveSmoothPath(uint32 pointId, G3D::Vector3 const* pathPoints, size_t pathSize, bool walk);
void MoveFall(uint32 id = 0);
void MoveSeekAssistance(float x, float y, float z);
+13
View File
@@ -3228,6 +3228,19 @@ void SpellMgr::LoadSpellInfoCorrections()
//! HACK: This spell break quest complete for alliance and on retail not used °_O
const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->Effect = 0;
break;
// VIOLET HOLD SPELLS
//
case 54258: // Water Globule (Ichoron)
case 54264: // Water Globule (Ichoron)
case 54265: // Water Globule (Ichoron)
case 54266: // Water Globule (Ichoron)
case 54267: // Water Globule (Ichoron)
// in 3.3.5 there is only one radius in dbc which is 0 yards in this case
// use max radius from 4.3.4
const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS);
break;
// ENDOF VIOLET HOLD
//
// ULDUAR SPELLS
//
case 62374: // Pursued (Flame Leviathan)
@@ -361,7 +361,7 @@ public:
}
}
void UpdateEscortAI(const uint32 uiDiff) override
void UpdateEscortAI(uint32 uiDiff) override
{
if (uiPhase)
{
@@ -607,7 +607,7 @@ public:
summoned->AI()->AttackStart(me);
}
void UpdateEscortAI(const uint32 Diff) override
void UpdateEscortAI(uint32 Diff) override
{
if (!UpdateVictim())
{
@@ -568,7 +568,7 @@ public:
}
void UpdateEscortAI(const uint32 diff) override
void UpdateEscortAI(uint32 diff) override
{
DialogueUpdate(diff);
@@ -263,7 +263,7 @@ class npc_onyx_flamecaller : public CreatureScript
}
}
void UpdateEscortAI(uint32 const diff) override
void UpdateEscortAI(uint32 diff) override
{
if (!UpdateVictim())
return;
@@ -18,7 +18,6 @@
#include "InstanceScript.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "WorldSession.h"
#include "gundrak.h"
#include "EventMap.h"
@@ -191,7 +190,7 @@ class instance_gundrak : public InstanceMapScript
bool CheckRequiredBosses(uint32 bossId, Player const* player = nullptr) const override
{
if (player && player->GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES))
if (_SkipCheckRequiredBosses(player))
return true;
switch (bossId)
@@ -1140,7 +1140,7 @@ class npc_crok_scourgebane : public CreatureScript
}
}
void UpdateEscortAI(uint32 const diff) override
void UpdateEscortAI(uint32 diff) override
{
if (_wipeCheckTimer <= diff)
_wipeCheckTimer = 0;
@@ -17,7 +17,6 @@
#include "AccountMgr.h"
#include "InstanceScript.h"
#include "Map.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "PoolMgr.h"
@@ -26,7 +25,6 @@
#include "Transport.h"
#include "TransportMgr.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "icecrown_citadel.h"
enum EventIds
@@ -1118,7 +1116,7 @@ class instance_icecrown_citadel : public InstanceMapScript
bool CheckRequiredBosses(uint32 bossId, Player const* player = nullptr) const override
{
if (player && player->GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES))
if (_SkipCheckRequiredBosses(player))
return true;
switch (bossId)
@@ -437,7 +437,7 @@ public:
return 0;
}
void UpdateEscortAI(const uint32 uiDiff) override
void UpdateEscortAI(uint32 uiDiff) override
{
if (uiPhaseTimer <= uiDiff)
{
@@ -18,7 +18,6 @@
#include "InstanceScript.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "WorldSession.h"
#include "halls_of_stone.h"
DoorData const doorData[] =
@@ -172,7 +171,7 @@ class instance_halls_of_stone : public InstanceMapScript
bool CheckRequiredBosses(uint32 bossId, Player const* player = nullptr) const override
{
if (player && player->GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES))
if (_SkipCheckRequiredBosses(player))
return true;
switch (bossId)
@@ -16,11 +16,13 @@
*/
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "ScriptedCreature.h"
#include "violet_hold.h"
enum Spells
{
SPELL_SUMMON_PLAYER = 21150,
SPELL_ARCANE_VACUUM = 58694,
SPELL_BLIZZARD = 58693,
SPELL_MANA_DESTRUCTION = 59374,
@@ -42,119 +44,91 @@ enum Yells
class boss_cyanigosa : public CreatureScript
{
public:
boss_cyanigosa() : CreatureScript("boss_cyanigosa") { }
public:
boss_cyanigosa() : CreatureScript("boss_cyanigosa") { }
struct boss_cyanigosaAI : public BossAI
{
boss_cyanigosaAI(Creature* creature) : BossAI(creature, DATA_CYANIGOSA)
struct boss_cyanigosaAI : public BossAI
{
Initialize();
}
boss_cyanigosaAI(Creature* creature) : BossAI(creature, DATA_CYANIGOSA) { }
void Initialize()
{
uiArcaneVacuumTimer = 10000;
uiBlizzardTimer = 15000;
uiManaDestructionTimer = 30000;
uiTailSweepTimer = 20000;
uiUncontrollableEnergyTimer = 25000;
}
uint32 uiArcaneVacuumTimer;
uint32 uiBlizzardTimer;
uint32 uiManaDestructionTimer;
uint32 uiTailSweepTimer;
uint32 uiUncontrollableEnergyTimer;
void Reset() override
{
Initialize();
BossAI::Reset();
}
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
if (instance->GetData(DATA_REMOVE_NPC) == 1)
void EnterCombat(Unit* who) override
{
me->DespawnOrUnsummon();
instance->SetData(DATA_REMOVE_NPC, 0);
BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
}
if (!UpdateVictim())
return;
if (uiArcaneVacuumTimer <= diff)
void KilledUnit(Unit* victim) override
{
DoCastAOE(SPELL_ARCANE_VACUUM);
uiArcaneVacuumTimer = 10000;
} else uiArcaneVacuumTimer -= diff;
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
if (uiBlizzardTimer <= diff)
void JustDied(Unit* killer) override
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_BLIZZARD);
uiBlizzardTimer = 15000;
} else uiBlizzardTimer -= diff;
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
if (uiTailSweepTimer <= diff)
{
DoCastVictim(SPELL_TAIL_SWEEP);
uiTailSweepTimer = 20000;
} else uiTailSweepTimer -= diff;
void MoveInLineOfSight(Unit* /*who*/) override { }
if (uiUncontrollableEnergyTimer <= diff)
void UpdateAI(uint32 diff) override
{
DoCastVictim(SPELL_UNCONTROLLABLE_ENERGY);
uiUncontrollableEnergyTimer = 25000;
} else uiUncontrollableEnergyTimer -= diff;
if (!UpdateVictim())
return;
if (IsHeroic())
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void ScheduleTasks() override
{
if (uiManaDestructionTimer <= diff)
scheduler.Schedule(Seconds(10), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_MANA_DESTRUCTION);
uiManaDestructionTimer = 30000;
} else uiManaDestructionTimer -= diff;
DoCastAOE(SPELL_ARCANE_VACUUM);
task.Repeat();
});
scheduler.Schedule(Seconds(15), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true))
DoCast(target, SPELL_BLIZZARD);
task.Repeat();
});
scheduler.Schedule(Seconds(20), [this](TaskContext task)
{
DoCastVictim(SPELL_TAIL_SWEEP);
task.Repeat();
});
scheduler.Schedule(Seconds(25), [this](TaskContext task)
{
DoCastVictim(SPELL_UNCONTROLLABLE_ENERGY);
task.Repeat();
});
if (IsHeroic())
{
scheduler.Schedule(Seconds(30), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true))
DoCast(target, SPELL_MANA_DESTRUCTION);
task.Repeat();
});
}
}
};
DoMeleeAttackIfReady();
}
void JustDied(Unit* killer) override
CreatureAI* GetAI(Creature* creature) const override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
return GetVioletHoldAI<boss_cyanigosaAI>(creature);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_cyanigosaAI>(creature);
}
};
class achievement_defenseless : public AchievementCriteriaScript
{
public:
achievement_defenseless() : AchievementCriteriaScript("achievement_defenseless")
{
}
achievement_defenseless() : AchievementCriteriaScript("achievement_defenseless") { }
bool OnCheck(Player* /*player*/, Unit* target) override
{
@@ -165,10 +139,40 @@ class achievement_defenseless : public AchievementCriteriaScript
if (!instance)
return false;
if (!instance->GetData(DATA_DEFENSELESS))
return false;
return instance->GetData(DATA_DEFENSELESS) != 0;
}
};
return true;
class spell_cyanigosa_arcane_vacuum : public SpellScriptLoader
{
public:
spell_cyanigosa_arcane_vacuum() : SpellScriptLoader("spell_cyanigosa_arcane_vacuum") { }
class spell_cyanigosa_arcane_vacuum_SpellScript : public SpellScript
{
PrepareSpellScript(spell_cyanigosa_arcane_vacuum_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_PLAYER))
return false;
return true;
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_SUMMON_PLAYER, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_cyanigosa_arcane_vacuum_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_cyanigosa_arcane_vacuum_SpellScript();
}
};
@@ -176,4 +180,5 @@ void AddSC_boss_cyanigosa()
{
new boss_cyanigosa();
new achievement_defenseless();
new spell_cyanigosa_arcane_vacuum();
}
@@ -41,269 +41,210 @@ enum Yells
SAY_BOTH_ADDS_KILLED = 5
};
enum ErekemEvents
{
EVENT_EARTH_SHIELD = 1,
EVENT_CHAIN_HEAL,
EVENT_BLOODLUST,
EVENT_LIGHTNING_BOLT,
EVENT_EARTH_SHOCK,
EVENT_WINDFURY,
EVENT_STORMSTRIKE
};
class boss_erekem : public CreatureScript
{
public:
boss_erekem() : CreatureScript("boss_erekem") { }
public:
boss_erekem() : CreatureScript("boss_erekem") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_erekemAI>(creature);
}
struct boss_erekemAI : public ScriptedAI
{
boss_erekemAI(Creature* creature) : ScriptedAI(creature)
struct boss_erekemAI : public BossAI
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
phase = 0;
breakBondsCd = 0;
}
void Reset() override
{
Initialize();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS)
boss_erekemAI(Creature* creature) : BossAI(creature, DATA_EREKEM)
{
if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))
pGuard1->DespawnOrUnsummon();
if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)))
pGuard2->DespawnOrUnsummon();
}
else
{
if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))
{
if (!pGuard1->IsAlive())
pGuard1->Respawn();
}
if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)))
{
if (!pGuard2->IsAlive())
pGuard2->Respawn();
}
Initialize();
}
events.Reset();
}
void JustReachedHome() override
{
if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))
pGuard1->Respawn();
if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)))
pGuard2->Respawn();
}
void AttackStart(Unit* who) override
{
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
if (me->Attack(who, true))
void Initialize()
{
me->AddThreat(who, 0.0f);
me->SetInCombatWith(who);
who->SetInCombatWith(me);
DoStartMovement(who);
if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))
{
pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
if (!pGuard1->GetVictim() && pGuard1->AI())
pGuard1->AI()->AttackStart(who);
}
if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)))
{
pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
if (!pGuard2->GetVictim() && pGuard2->AI())
pGuard2->AI()->AttackStart(who);
}
_phase = 0;
}
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
DoCast(me, SPELL_EARTH_SHIELD);
void Reset() override
{
Initialize();
BossAI::Reset();
me->SetCanDualWield(false);
}
if (GameObject* door = instance->GetGameObject(DATA_EREKEM_CELL))
if (door->GetGoState() == GO_STATE_READY)
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
DoCast(me, SPELL_EARTH_SHIELD);
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type == EFFECT_MOTION_TYPE && pointId == POINT_INTRO)
me->SetFacingTo(4.921828f);
}
void JustReachedHome() override
{
BossAI::JustReachedHome();
instance->SetData(DATA_HANDLE_CELLS, DATA_EREKEM);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
bool CheckGuardAuras(Creature* guard) const
{
static uint32 const MechanicImmunityList =
(1 << MECHANIC_SNARE)
| (1 << MECHANIC_ROOT)
| (1 << MECHANIC_FEAR)
| (1 << MECHANIC_STUN)
| (1 << MECHANIC_SLEEP)
| (1 << MECHANIC_CHARM)
| (1 << MECHANIC_SAPPED)
| (1 << MECHANIC_HORROR)
| (1 << MECHANIC_POLYMORPH)
| (1 << MECHANIC_DISORIENTED)
| (1 << MECHANIC_FREEZE)
| (1 << MECHANIC_TURN);
static std::list<AuraType> const AuraImmunityList =
{
EnterEvadeMode();
SPELL_AURA_MOD_STUN,
SPELL_AURA_MOD_DECREASE_SPEED,
SPELL_AURA_MOD_ROOT,
SPELL_AURA_MOD_CONFUSE,
SPELL_AURA_MOD_FEAR
};
if (guard->HasAuraWithMechanic(MechanicImmunityList))
return true;
for (AuraType type : AuraImmunityList)
if (guard->HasAuraType(type))
return true;
return false;
}
bool CheckGuardAlive() const
{
for (uint32 i = DATA_EREKEM_GUARD_1; i <= DATA_EREKEM_GUARD_2; ++i)
{
if (Creature* guard = ObjectAccessor::GetCreature(*me, instance->GetGuidData(i)))
if (guard->IsAlive())
return true;
}
return false;
}
Unit* GetChainHealTarget() const
{
if (HealthBelowPct(85))
return me;
for (uint32 i = DATA_EREKEM_GUARD_1; i <= DATA_EREKEM_GUARD_2; ++i)
{
if (Creature* guard = ObjectAccessor::GetCreature(*me, instance->GetGuidData(i)))
if (guard->IsAlive() && !guard->HealthAbovePct(75))
return guard;
}
return nullptr;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
}
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_NPC);
events.ScheduleEvent(EVENT_EARTH_SHIELD, 20000);
events.ScheduleEvent(EVENT_BLOODLUST, 15000);
events.ScheduleEvent(EVENT_CHAIN_HEAL, 10000);
events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 2000);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (phase == 0)
if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))
if (_phase == 0 && !CheckGuardAlive())
{
if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)))
{
if (!pGuard1->IsAlive() && !pGuard2->IsAlive())
{
phase = 1;
DoCastVictim(SPELL_STORMSTRIKE);
DoCast(SPELL_WINDFURY);
events.Reset();
events.ScheduleEvent(EVENT_EARTH_SHOCK, urand(2000, 8000));
events.ScheduleEvent(EVENT_WINDFURY, urand(1500, 2000));
events.ScheduleEvent(EVENT_STORMSTRIKE, urand(1500, 2000));
}
}
_phase = 1;
me->SetCanDualWield(true);
DoCast(me, SPELL_WINDFURY, true);
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (breakBondsCd <= 0)
{
if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)))
scheduler.Update(diff, [this]
{
if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)))
{
if (pGuard1->IsAlive())
{
if (pGuard1->HasAuraType(SPELL_AURA_MOD_STUN) || pGuard1->HasAuraType(SPELL_AURA_MOD_ROOT)
|| pGuard1->HasAuraType(SPELL_AURA_MOD_CONFUSE) || pGuard1->HasAuraType(SPELL_AURA_MOD_PACIFY)
|| pGuard1->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED))
{
DoCast(SPELL_BREAK_BONDS);
breakBondsCd = 10000;
return;
}
}
if (pGuard2->IsAlive())
{
if (pGuard2->HasAuraType(SPELL_AURA_MOD_STUN) || pGuard2->HasAuraType(SPELL_AURA_MOD_ROOT)
|| pGuard2->HasAuraType(SPELL_AURA_MOD_CONFUSE) || pGuard2->HasAuraType(SPELL_AURA_MOD_PACIFY)
|| pGuard2->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED))
{
DoCast(SPELL_BREAK_BONDS);
breakBondsCd = 10000;
return;
}
}
}
}
if (_phase == 1)
DoSpellAttackIfReady(SPELL_STORMSTRIKE);
else
DoMeleeAttackIfReady();
});
}
else
breakBondsCd -= diff;
switch (events.ExecuteEvent())
void ScheduleTasks() override
{
case EVENT_EARTH_SHIELD:
scheduler.Schedule(Seconds(20), [this](TaskContext task)
{
if (Unit* ally = DoSelectLowestHpFriendly(30.0f))
DoCast(ally, SPELL_EARTH_SHIELD);
events.ScheduleEvent(EVENT_EARTH_SHIELD, 20000);
break;
case EVENT_BLOODLUST:
task.Repeat(Seconds(20));
});
scheduler.Schedule(Seconds(2), [this](TaskContext task)
{
DoCast(SPELL_BLOODLUST);
events.ScheduleEvent(EVENT_BLOODLUST, urand(35000, 45000));
break;
case EVENT_LIGHTNING_BOLT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
task.Repeat(Seconds(35), Seconds(45));
});
scheduler.Schedule(Seconds(2), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f))
DoCast(target, SPELL_LIGHTNING_BOLT);
events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 2500);
break;
case EVENT_CHAIN_HEAL:
task.Repeat(Milliseconds(2500));
});
scheduler.Schedule(Seconds(10), [this](TaskContext task)
{
if (Unit* ally = DoSelectLowestHpFriendly(40.0f))
DoCast(ally, SPELL_CHAIN_HEAL);
{
Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1));
Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2));
events.ScheduleEvent(EVENT_CHAIN_HEAL, ((pGuard1 && !pGuard1->IsAlive()) || (pGuard2 && !pGuard2->IsAlive()) ? 3000 : 8000 + rand() % 3000));
}
break;
case EVENT_EARTH_SHOCK:
if (!CheckGuardAlive())
task.Repeat(Seconds(3));
else
task.Repeat(Seconds(8), Seconds(11));
});
scheduler.Schedule(Seconds(2), Seconds(8), [this](TaskContext task)
{
DoCastVictim(SPELL_EARTH_SHOCK);
events.ScheduleEvent(EVENT_EARTH_SHOCK, urand(8000, 13000));
break;
case EVENT_WINDFURY:
DoCast(SPELL_WINDFURY);
events.ScheduleEvent(EVENT_WINDFURY, urand(1500, 2000));
break;
case EVENT_STORMSTRIKE:
DoCastVictim(SPELL_STORMSTRIKE);
events.ScheduleEvent(EVENT_STORMSTRIKE, urand(1500, 2000));
break;
default:
break;
task.Repeat(Seconds(8), Seconds(13));
});
scheduler.Schedule(Seconds(0), [this](TaskContext task)
{
for (uint32 i = DATA_EREKEM_GUARD_1; i <= DATA_EREKEM_GUARD_2; ++i)
{
Creature* guard = ObjectAccessor::GetCreature(*me, instance->GetGuidData(i));
if (guard && guard->IsAlive() && CheckGuardAuras(guard))
{
DoCastAOE(SPELL_BREAK_BONDS);
task.Repeat(Seconds(10));
return;
}
}
task.Repeat(Milliseconds(500));
});
}
DoMeleeAttackIfReady();
}
private:
uint8 _phase;
};
private:
EventMap events;
InstanceScript* instance;
uint8 phase;
int32 breakBondsCd;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetVioletHoldAI<boss_erekemAI>(creature);
}
};
enum GuardSpells
@@ -315,85 +256,61 @@ enum GuardSpells
class npc_erekem_guard : public CreatureScript
{
public:
npc_erekem_guard() : CreatureScript("npc_erekem_guard") { }
public:
npc_erekem_guard() : CreatureScript("npc_erekem_guard") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_erekem_guardAI>(creature);
}
struct npc_erekem_guardAI : public ScriptedAI
{
npc_erekem_guardAI(Creature* creature) : ScriptedAI(creature)
struct npc_erekem_guardAI : public ScriptedAI
{
Initialize();
instance = creature->GetInstanceScript();
}
npc_erekem_guardAI(Creature* creature) : ScriptedAI(creature) { }
void Initialize()
{
uiStrikeTimer = urand(4000, 8000);
uiHowlingScreechTimer = urand(8000, 13000);
uiGushingWoundTimer = urand(1000, 3000);
}
uint32 uiGushingWoundTimer;
uint32 uiHowlingScreechTimer;
uint32 uiStrikeTimer;
InstanceScript* instance;
void Reset() override
{
Initialize();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
}
void AttackStart(Unit* who) override
{
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
if (me->Attack(who, true))
void Reset() override
{
me->AddThreat(who, 0.0f);
me->SetInCombatWith(who);
who->SetInCombatWith(me);
DoStartMovement(who);
scheduler.CancelAll();
}
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void EnterCombat(Unit* /*who*/) override
{
DoZoneInCombat();
}
void UpdateAI(uint32 diff) override
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff,
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
}
void ScheduledTasks()
{
scheduler.Schedule(Seconds(4), Seconds(8), [this](TaskContext task)
{
DoCastVictim(SPELL_STRIKE);
task.Repeat(Seconds(4), Seconds(8));
});
scheduler.Schedule(Seconds(8), Seconds(13), [this](TaskContext task)
{
DoCastAOE(SPELL_HOWLING_SCREECH);
task.Repeat(Seconds(8), Seconds(13));
});
scheduler.Schedule(Seconds(1), Seconds(3), [this](TaskContext task)
{
DoCastVictim(SPELL_GUSHING_WOUND);
task.Repeat(Seconds(7), Seconds(12));
});
}
private:
TaskScheduler scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
{
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
if (uiStrikeTimer <= diff)
{
DoCastVictim(SPELL_STRIKE);
uiStrikeTimer = urand(4000, 8000);
} else uiStrikeTimer -= diff;
if (uiHowlingScreechTimer <= diff)
{
DoCastVictim(SPELL_HOWLING_SCREECH);
uiHowlingScreechTimer = urand(8000, 13000);
} else uiHowlingScreechTimer -= diff;
if (uiGushingWoundTimer <= diff)
{
DoCastVictim(SPELL_GUSHING_WOUND);
uiGushingWoundTimer = urand(7000, 12000);
} else uiGushingWoundTimer -= diff;
return GetVioletHoldAI<npc_erekem_guardAI>(creature);
}
};
};
void AddSC_boss_erekem()
@@ -17,26 +17,32 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "violet_hold.h"
enum Spells
{
SPELL_DRAINED = 59820,
SPELL_FRENZY = 54312,
SPELL_PROTECTIVE_BUBBLE = 54306,
SPELL_WATER_BLAST = 54237,
SPELL_WATER_BOLT_VOLLEY = 54241,
SPELL_SPLASH = 59516,
SPELL_SPLATTER = 54259,
SPELL_PROTECTIVE_BUBBLE = 54306,
SPELL_FRENZY = 54312,
SPELL_BURST = 54379,
SPELL_WATER_GLOBULE = 54268,
SPELL_MERGE = 54269,
SPELL_WATER_GLOBULE_VISUAL = 54260
};
SPELL_DRAINED = 59820,
SPELL_THREAT_PROC = 61732,
SPELL_SHRINK = 54297,
enum IchoronCreatures
{
NPC_ICHOR_GLOBULE = 29321,
NPC_ICHORON_SUMMON_TARGET = 29326
SPELL_WATER_GLOBULE_SUMMON_1 = 54258,
SPELL_WATER_GLOBULE_SUMMON_2 = 54264,
SPELL_WATER_GLOBULE_SUMMON_3 = 54265,
SPELL_WATER_GLOBULE_SUMMON_4 = 54266,
SPELL_WATER_GLOBULE_SUMMON_5 = 54267,
SPELL_WATER_GLOBULE_TRANSFORM = 54268,
SPELL_WATER_GLOBULE_VISUAL = 54260,
SPELL_MERGE = 54269,
SPELL_SPLASH = 59516
};
enum Yells
@@ -47,483 +53,412 @@ enum Yells
SAY_SPAWN = 3,
SAY_ENRAGE = 4,
SAY_SHATTER = 5,
SAY_BUBBLE = 6
SAY_BUBBLE = 6,
EMOTE_SHATTER = 7
};
enum Actions
{
ACTION_WATER_ELEMENT_HIT = 1
};
enum IchoronEvents
{
EVENT_WATER_BLAST = 1,
EVENT_WATER_BOLT_VOLLEY
};
enum GlobuleEvents
{
EVENT_GLOBULE_MOVE = 1
ACTION_WATER_GLOBULE_HIT = 1,
ACTION_PROTECTIVE_BUBBLE_SHATTERED = 2,
ACTION_DRAINED = 3
};
enum Misc
{
DATA_GLOBULE_PATH = 0,
DATA_DEHYDRATION = 1
};
#define MAX_GLOBULE_PATHS 10
Position const globulePaths[MAX_GLOBULE_PATHS] =
{
// first target
{ 1861.357f, 804.039f, 44.008f, 6.268f },
{ 1869.375f, 803.976f, 38.781f, 0.009f },
// second target
{ 1888.063f, 763.488f, 47.667f, 1.744f },
{ 1882.865f, 776.385f, 38.824f, 1.882f },
// third target
{ 1935.140f, 817.752f, 52.181f, 1.885f },
{ 1916.642f, 826.337f, 39.139f, 2.851f },
// fourth target
{ 1930.257f, 833.053f, 46.906f, 4.579f },
{ 1916.642f, 826.337f, 39.139f, 2.851f },
// fifth target
{ 1878.248f, 841.883f, 43.334f, 4.717f },
{ 1879.438f, 834.443f, 38.699f, 4.831f }
};
class boss_ichoron : public CreatureScript
{
public:
boss_ichoron() : CreatureScript("boss_ichoron") { }
public:
boss_ichoron() : CreatureScript("boss_ichoron") { }
struct boss_ichoronAI : public ScriptedAI
{
boss_ichoronAI(Creature* creature) : ScriptedAI(creature), m_waterElements(creature)
struct boss_ichoronAI : public BossAI
{
Initialize();
instance = creature->GetInstanceScript();
}
boss_ichoronAI(Creature* creature) : BossAI(creature, DATA_ICHORON)
{
Initialize();
void Initialize()
{
bIsExploded = false;
bIsFrenzy = false;
bIsDrained = false;
dehydration = true;
drainedTimer = 50;
burstTimer = 15000;
}
/// for some reason ichoron can't walk back to it's water basin on evade
me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING);
}
void Reset() override
{
Initialize();
void Initialize()
{
_isFrenzy = false;
_dehydration = true;
}
events.Reset();
me->SetVisible(true);
DespawnWaterElements();
void Reset() override
{
Initialize();
BossAI::Reset();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
}
DoCast(me, SPELL_THREAT_PROC, true);
}
void EnterCombat(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
}
DoCast(me, SPELL_PROTECTIVE_BUBBLE);
void JustReachedHome() override
{
BossAI::JustReachedHome();
instance->SetData(DATA_HANDLE_CELLS, DATA_ICHORON);
}
if (GameObject* door = instance->GetGameObject(DATA_ICHORON_CELL))
if (door->GetGoState() == GO_STATE_READY)
void DoAction(int32 actionId) override
{
switch (actionId)
{
EnterEvadeMode();
return;
}
case ACTION_WATER_GLOBULE_HIT:
if (!me->IsAlive())
break;
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000));
events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000));
}
void AttackStart(Unit* who) override
{
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
if (me->Attack(who, true))
{
me->AddThreat(who, 0.0f);
me->SetInCombatWith(who);
who->SetInCombatWith(me);
DoStartMovement(who);
}
}
void DoAction(int32 param) override
{
if (!me->IsAlive())
return;
switch (param)
{
case ACTION_WATER_ELEMENT_HIT:
{
if (bIsExploded)
DoExplodeCompleted();
me->SetHealth(me->GetHealth() + me->CountPctFromMaxHealth(3));
dehydration = false;
}
break;
}
}
void DespawnWaterElements()
{
m_waterElements.DespawnAll();
}
// call when explode shall stop.
// either when "hit" by a bubble, or when there is no bubble left.
void DoExplodeCompleted()
{
bIsExploded = false;
bIsDrained = false;
if (!HealthBelowPct(25))
{
Talk(SAY_BUBBLE);
DoCast(me, SPELL_PROTECTIVE_BUBBLE, true);
}
me->SetVisible(true);
me->GetMotionMaster()->MoveChase(me->GetVictim());
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_DEHYDRATION)
return dehydration ? 1 : 0;
return 0;
}
void MoveInLineOfSight(Unit* who) override
{
if (!who->ToCreature())
return;
if (who->GetEntry() != NPC_ICHOR_GLOBULE)
return;
if (!me->IsWithinDist(who, 4.0f, false))
return;
if (who->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
return;
who->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
who->CastSpell(who, SPELL_MERGE);
DoAction(ACTION_WATER_ELEMENT_HIT);
who->ToCreature()->DespawnOrUnsummon(1000);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
if (bIsExploded)
{
bIsExploded = false;
me->SetVisible(true);
}
DespawnWaterElements();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
void JustSummoned(Creature* summoned) override
{
summoned->SetSpeed(MOVE_RUN, 0.3f);
m_waterElements.Summon(summoned);
instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID());
}
void SummonedCreatureDespawn(Creature* summoned) override
{
m_waterElements.Despawn(summoned);
if (m_waterElements.empty() && bIsExploded)
{
me->RemoveAllAuras();
DoExplodeCompleted();
}
instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID());
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (!bIsFrenzy && HealthBelowPct(25) && !bIsExploded)
{
Talk(SAY_ENRAGE);
DoCast(me, SPELL_FRENZY, true);
bIsFrenzy = true;
}
if (!bIsFrenzy)
{
if (!bIsExploded)
{
if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE))
me->ModifyHealth(int32(me->CountPctFromMaxHealth(3)));
_dehydration = false;
break;
case ACTION_PROTECTIVE_BUBBLE_SHATTERED:
{
bIsExploded = true;
Talk(SAY_SHATTER);
DoCast(SPELL_BURST);
me->RemoveAllAuras();
burstTimer = 15000;
Talk(EMOTE_SHATTER);
std::list<Creature*> summonTargets;
GetCreatureListWithEntryInGrid(summonTargets, me, NPC_ICHORON_SUMMON_TARGET, 200.0f);
std::list<Creature*>::iterator itr = summonTargets.begin();
DoCastAOE(SPELL_SPLATTER, true);
DoCastAOE(SPELL_BURST, true);
DoCast(me, SPELL_DRAINED, true);
for (uint8 i = 0; i < MAX_GLOBULE_PATHS; i++)
{
std::advance(itr, urand(0, summonTargets.size() - 1)); // I take a random minion in the list
Position targetPos = (*itr)->GetRandomNearPosition(10.0f);
itr = summonTargets.begin();
TempSummon* globule = me->SummonCreature(NPC_ICHOR_GLOBULE, targetPos, TEMPSUMMON_CORPSE_DESPAWN);
DoCast(globule, SPELL_WATER_GLOBULE_VISUAL);
float minDistance = 1000.0f;
uint8 nextPath = 0;
// I move the globules to next position. the 10 positions are in couples, defined in globulePaths, so i have to increase by 2.
for (uint8 gpath = 0; gpath < MAX_GLOBULE_PATHS; gpath += 2)
{
if (globule->GetDistance(globulePaths[gpath]) < minDistance)
{
minDistance = globule->GetDistance(globulePaths[gpath]);
nextPath = gpath;
}
}
globule->GetAI()->SetData(DATA_GLOBULE_PATH, nextPath);
}
return;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_WATER_BLAST:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(target, SPELL_WATER_BLAST);
events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000));
break;
case EVENT_WATER_BOLT_VOLLEY:
DoCast(SPELL_WATER_BOLT_VOLLEY);
events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000));
break;
}
DoMeleeAttackIfReady();
}
else if (!bIsDrained)
{
if (drainedTimer <= 0)
{
bIsDrained = true;
drainedTimer = 50;
uint32 damage = me->CountPctFromMaxHealth(30);
if (me->GetHealth() < damage)
me->SetHealth(me->CountPctFromMaxHealth(1));
else
me->LowerPlayerDamageReq(damage);
me->ModifyHealth(-std::min<int32>(damage, me->GetHealth() - 1));
scheduler.DelayAll(Seconds(15));
break;
}
case ACTION_DRAINED:
if (HealthAbovePct(30))
{
me->SetHealth(me->GetHealth() - damage);
me->LowerPlayerDamageReq(damage);
Talk(SAY_BUBBLE);
DoCast(me, SPELL_PROTECTIVE_BUBBLE, true);
}
DoCast(SPELL_DRAINED);
me->SetVisible(false);
me->AttackStop();
}
else
drainedTimer -= diff;
}
else if (bIsDrained)
{
if (burstTimer <= 0)
{
DoExplodeCompleted();
}
else
burstTimer -= diff;
break;
default:
break;
}
}
else
uint32 GetData(uint32 type) const override
{
if (me->HasUnitState(UNIT_STATE_CASTING))
if (type == DATA_DEHYDRATION)
return _dehydration ? 1 : 0;
return 0;
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (summon->GetEntry() == NPC_ICHOR_GLOBULE)
DoCast(summon, SPELL_WATER_GLOBULE_VISUAL);
}
void SummonedCreatureDespawn(Creature* summon) override
{
BossAI::SummonedCreatureDespawn(summon);
if (summons.empty())
me->RemoveAurasDueToSpell(SPELL_DRAINED, ObjectGuid::Empty, 0, AURA_REMOVE_BY_EXPIRE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
switch (events.ExecuteEvent())
if (!_isFrenzy && HealthBelowPct(25) && !me->HasAura(SPELL_DRAINED))
{
case EVENT_WATER_BLAST:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(target, SPELL_WATER_BLAST);
events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000));
break;
case EVENT_WATER_BOLT_VOLLEY:
DoCast(SPELL_WATER_BOLT_VOLLEY);
events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000));
break;
Talk(SAY_ENRAGE);
DoCast(me, SPELL_FRENZY, true);
_isFrenzy = true;
}
DoMeleeAttackIfReady();
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void ScheduleTasks() override
{
scheduler.Async([this]
{
DoCast(me, SPELL_SHRINK);
DoCast(me, SPELL_PROTECTIVE_BUBBLE);
});
scheduler.Schedule(Seconds(10), Seconds(15), [this](TaskContext task)
{
DoCastAOE(SPELL_WATER_BOLT_VOLLEY);
task.Repeat(Seconds(10), Seconds(15));
});
scheduler.Schedule(Seconds(6), Seconds(9), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f))
DoCast(target, SPELL_WATER_BLAST);
task.Repeat(Seconds(6), Seconds(9));
});
}
private:
bool _isFrenzy;
bool _dehydration;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetVioletHoldAI<boss_ichoronAI>(creature);
}
private:
InstanceScript* instance;
SummonList m_waterElements;
EventMap events;
bool bIsExploded;
bool bIsFrenzy;
bool bIsDrained;
bool dehydration;
int32 drainedTimer;
int32 burstTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_ichoronAI>(creature);
}
};
class npc_ichor_globule : public CreatureScript
{
public:
npc_ichor_globule() : CreatureScript("npc_ichor_globule") { }
public:
npc_ichor_globule() : CreatureScript("npc_ichor_globule") { }
struct npc_ichor_globuleAI : public ScriptedAI
{
npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature)
struct npc_ichor_globuleAI : public ScriptedAI
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
pathId = 0;
}
void Reset() override
{
Initialize();
events.Reset();
DoCast(SPELL_WATER_GLOBULE);
me->SetReactState(REACT_PASSIVE);
}
void SetData(uint32 id, uint32 data) override
{
if (id == DATA_GLOBULE_PATH)
npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature)
{
pathId = data;
me->GetMotionMaster()->MovePoint(0, globulePaths[pathId]);
_instance = creature->GetInstanceScript();
creature->SetReactState(REACT_PASSIVE);
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE)
return;
switch (id)
void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
{
case 0:
me->GetMotionMaster()->Clear();
events.ScheduleEvent(EVENT_GLOBULE_MOVE, 500);
break;
case 1:
me->GetMotionMaster()->Clear();
if (Creature* ichoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON)))
me->GetMotionMaster()->MoveFollow(ichoron, 0.0f, 0.0f);
break;
if (spellInfo->Id == SPELL_WATER_GLOBULE_VISUAL)
{
DoCast(me, SPELL_WATER_GLOBULE_TRANSFORM);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->GetMotionMaster()->MoveFollow(caster, 0.0f, 0.0f);
}
}
}
// on retail spell casted on a creature's death are not casted after death but keeping mob at 1 health, casting it and then letting the mob die.
// this feature should be still implemented
void DamageTaken(Unit* /*attacker*/, uint32 &damage) override
void MovementInform(uint32 type, uint32 id) override
{
if (type != FOLLOW_MOTION_TYPE)
return;
if (_instance->GetObjectGuid(DATA_ICHORON).GetCounter() != id)
return;
me->CastSpell(me, SPELL_MERGE);
me->DespawnOrUnsummon(1);
}
// on retail spell casted on a creature's death are not casted after death but keeping mob at 1 health, casting it and then letting the mob die.
// this feature should be still implemented
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (damage >= me->GetHealth())
DoCastAOE(SPELL_SPLASH);
}
void UpdateAI(uint32 /*diff*/) override { }
private:
InstanceScript* _instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
int32 actualHp = me->GetHealth();
actualHp -= damage;
if (actualHp <= 0)
DoCast(SPELL_SPLASH);
return GetVioletHoldAI<npc_ichor_globuleAI>(creature);
}
};
void UpdateAI(uint32 diff) override
// 59820 - Drained
class spell_ichoron_drained : public SpellScriptLoader
{
public:
spell_ichoron_drained() : SpellScriptLoader("spell_ichoron_drained") { }
class spell_ichoron_drained_AuraScript : public AuraScript
{
events.Update(diff);
PrepareAuraScript(spell_ichoron_drained_AuraScript);
if (events.ExecuteEvent() == EVENT_GLOBULE_MOVE)
me->GetMotionMaster()->MovePoint(1, globulePaths[pathId + 1]);
bool Load() override
{
return GetOwner()->GetEntry() == NPC_ICHORON || GetOwner()->GetEntry() == NPC_DUMMY_ICHORON;
}
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_UNK_31);
GetTarget()->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
}
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_UNK_31);
GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
if (GetTarget()->IsAIEnabled)
GetTarget()->GetAI()->DoAction(ACTION_DRAINED);
}
void Register() override
{
AfterEffectApply += AuraEffectApplyFn(spell_ichoron_drained_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
AfterEffectRemove += AuraEffectRemoveFn(spell_ichoron_drained_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_ichoron_drained_AuraScript();
}
};
private:
InstanceScript* instance;
EventMap events;
uint8 pathId;
};
// 54269 - Merge
class spell_ichoron_merge : public SpellScriptLoader
{
public:
spell_ichoron_merge() : SpellScriptLoader("spell_ichoron_merge") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ichor_globuleAI>(creature);
}
class spell_ichoron_merge_SpellScript : public SpellScript
{
PrepareSpellScript(spell_ichoron_merge_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_SHRINK))
return false;
return true;
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Creature* target = GetHitCreature())
{
if (Aura* aura = target->GetAura(SPELL_SHRINK))
aura->ModStackAmount(-1);
target->AI()->DoAction(ACTION_WATER_GLOBULE_HIT);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_ichoron_merge_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_ichoron_merge_SpellScript();
}
};
// 54306 - Protective Bubble
class spell_ichoron_protective_bubble : public SpellScriptLoader
{
public:
spell_ichoron_protective_bubble() : SpellScriptLoader("spell_ichoron_protective_bubble") { }
class spell_ichoron_protective_bubble_AuraScript : public AuraScript
{
PrepareAuraScript(spell_ichoron_protective_bubble_AuraScript);
bool Load() override
{
return GetOwner()->GetEntry() == NPC_ICHORON || GetOwner()->GetEntry() == NPC_DUMMY_ICHORON;
}
void HandleShatter(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
//if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL)
if (GetAura()->GetCharges() <= 1)
if (GetTarget()->IsAIEnabled)
GetTarget()->GetAI()->DoAction(ACTION_PROTECTIVE_BUBBLE_SHATTERED);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_ichoron_protective_bubble_AuraScript::HandleShatter, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_ichoron_protective_bubble_AuraScript();
}
};
// 54259 - Splatter
class spell_ichoron_splatter : public SpellScriptLoader
{
public:
spell_ichoron_splatter() : SpellScriptLoader("spell_ichoron_splatter") { }
class spell_ichoron_splatter_AuraScript : public AuraScript
{
PrepareAuraScript(spell_ichoron_splatter_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_WATER_GLOBULE_SUMMON_1)
|| !sSpellMgr->GetSpellInfo(SPELL_WATER_GLOBULE_SUMMON_2)
|| !sSpellMgr->GetSpellInfo(SPELL_WATER_GLOBULE_SUMMON_3)
|| !sSpellMgr->GetSpellInfo(SPELL_WATER_GLOBULE_SUMMON_4)
|| !sSpellMgr->GetSpellInfo(SPELL_WATER_GLOBULE_SUMMON_5)
|| !sSpellMgr->GetSpellInfo(SPELL_SHRINK))
return false;
return true;
}
void PeriodicTick(AuraEffect const* /*aurEff*/)
{
PreventDefaultAction();
GetTarget()->CastSpell(GetTarget(), RAND(SPELL_WATER_GLOBULE_SUMMON_1, SPELL_WATER_GLOBULE_SUMMON_2, SPELL_WATER_GLOBULE_SUMMON_3, SPELL_WATER_GLOBULE_SUMMON_4, SPELL_WATER_GLOBULE_SUMMON_5), true);
}
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
if (Aura* aura = GetTarget()->GetAura(SPELL_SHRINK))
aura->ModStackAmount(10);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_ichoron_splatter_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
AfterEffectRemove += AuraEffectRemoveFn(spell_ichoron_splatter_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_ichoron_splatter_AuraScript();
}
};
class achievement_dehydration : public AchievementCriteriaScript
{
public:
achievement_dehydration() : AchievementCriteriaScript("achievement_dehydration")
{
}
achievement_dehydration() : AchievementCriteriaScript("achievement_dehydration") { }
bool OnCheck(Player* /*player*/, Unit* target) override
{
@@ -542,5 +477,9 @@ void AddSC_boss_ichoron()
{
new boss_ichoron();
new npc_ichor_globule();
new spell_ichoron_drained();
new spell_ichoron_merge();
new spell_ichoron_protective_bubble();
new spell_ichoron_splatter();
new achievement_dehydration();
}
@@ -27,130 +27,82 @@ enum Spells
SPELL_LAVA_BURN = 54249
};
enum LavanthorEvents
{
EVENT_CAUTERIZING_FLAMES = 1,
EVENT_FIREBOLT,
EVENT_FLAME_BREATH,
EVENT_LAVA_BURN
};
class boss_lavanthor : public CreatureScript
{
public:
boss_lavanthor() : CreatureScript("boss_lavanthor") { }
public:
boss_lavanthor() : CreatureScript("boss_lavanthor") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_lavanthorAI>(creature);
}
struct boss_lavanthorAI : public ScriptedAI
{
boss_lavanthorAI(Creature* creature) : ScriptedAI(creature)
struct boss_lavanthorAI : public BossAI
{
instance = creature->GetInstanceScript();
}
boss_lavanthorAI(Creature* creature) : BossAI(creature, DATA_LAVANTHOR) { }
void Reset() override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
void Reset() override
{
BossAI::Reset();
}
events.Reset();
}
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
}
void EnterCombat(Unit* /*who*/) override
{
if (GameObject* door = instance->GetGameObject(DATA_LAVANTHOR_CELL))
if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
void JustReachedHome() override
{
BossAI::JustReachedHome();
instance->SetData(DATA_HANDLE_CELLS, DATA_LAVANTHOR);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
}
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
events.ScheduleEvent(EVENT_FIREBOLT, 1000);
events.ScheduleEvent(EVENT_FLAME_BREATH, 5000);
events.ScheduleEvent(EVENT_LAVA_BURN, 10000);
if (IsHeroic())
events.ScheduleEvent(EVENT_CAUTERIZING_FLAMES, 3000);
}
void AttackStart(Unit* who) override
{
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
if (me->Attack(who, true))
{
me->AddThreat(who, 0.0f);
me->SetInCombatWith(who);
who->SetInCombatWith(me);
DoStartMovement(who);
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
void ScheduleTasks() override
{
case EVENT_FIREBOLT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
scheduler.Schedule(Seconds(1), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true))
DoCast(target, SPELL_FIREBOLT);
events.ScheduleEvent(EVENT_FIREBOLT, urand(5000, 13000));
break;
case EVENT_FLAME_BREATH:
DoCast(SPELL_FLAME_BREATH);
events.ScheduleEvent(EVENT_FLAME_BREATH, urand(10000, 15000));
break;
case EVENT_LAVA_BURN:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
task.Repeat(Seconds(5), Seconds(13));
});
scheduler.Schedule(Seconds(5), [this](TaskContext task)
{
DoCastVictim(SPELL_FLAME_BREATH);
task.Repeat(Seconds(10), Seconds(15));
});
scheduler.Schedule(Seconds(10), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f))
DoCast(target, SPELL_LAVA_BURN);
events.ScheduleEvent(EVENT_LAVA_BURN, urand(15000, 23000));
break;
case EVENT_CAUTERIZING_FLAMES:
DoCast(SPELL_CAUTERIZING_FLAMES);
events.ScheduleEvent(EVENT_CAUTERIZING_FLAMES, urand(10000, 16000));
break;
default:
break;
task.Repeat(Seconds(15), Seconds(23));
});
if (IsHeroic())
{
scheduler.Schedule(Seconds(3), [this](TaskContext task)
{
DoCastAOE(SPELL_CAUTERIZING_FLAMES);
task.Repeat(Seconds(10), Seconds(16));
});
}
}
};
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
CreatureAI* GetAI(Creature* creature) const override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
return GetVioletHoldAI<boss_lavanthorAI>(creature);
}
private:
EventMap events;
InstanceScript* instance;
};
};
void AddSC_boss_lavanthor()
@@ -25,8 +25,10 @@ enum Spells
{
SPELL_CORROSIVE_SALIVA = 54527,
SPELL_OPTIC_LINK = 54396,
SPELL_RAY_OF_PAIN = 54438, // NYI missing spelldifficulty
SPELL_RAY_OF_SUFFERING = 54442, // NYI missing spelldifficulty
SPELL_RAY_OF_PAIN = 54438,
SPELL_RAY_OF_PAIN_H = 59523,
SPELL_RAY_OF_SUFFERING = 54442,
SPELL_RAY_OF_SUFFERING_H = 59524,
// Visual
SPELL_OPTIC_LINK_LEVEL_1 = 54393,
@@ -34,191 +36,107 @@ enum Spells
SPELL_OPTIC_LINK_LEVEL_3 = 54395
};
enum MoraggEvents
{
EVENT_CORROSIVE_SALIVA = 1,
EVENT_OPTIC_LINK
};
class boss_moragg : public CreatureScript
{
public:
boss_moragg() : CreatureScript("boss_moragg") { }
public:
boss_moragg() : CreatureScript("boss_moragg") { }
struct boss_moraggAI : public ScriptedAI
{
boss_moraggAI(Creature* creature) : ScriptedAI(creature)
struct boss_moraggAI : public BossAI
{
instance = creature->GetInstanceScript();
}
boss_moraggAI(Creature* creature) : BossAI(creature, DATA_MORAGG) { }
void Reset() override
{
events.Reset();
void Reset() override
{
BossAI::Reset();
}
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
}
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
}
void EnterCombat(Unit* /*who*/) override
{
if (GameObject* door = instance->GetGameObject(DATA_MORAGG_CELL))
if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
void JustReachedHome() override
{
BossAI::JustReachedHome();
instance->SetData(DATA_HANDLE_CELLS, DATA_MORAGG);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
}
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
me->SetInCombatWithZone();
DoCast(SPELL_RAY_OF_PAIN);
DoCast(SPELL_RAY_OF_SUFFERING);
events.ScheduleEvent(EVENT_OPTIC_LINK, 15000);
events.ScheduleEvent(EVENT_CORROSIVE_SALIVA, 5000);
}
void AttackStart(Unit* who) override
{
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
if (me->Attack(who, true))
{
me->AddThreat(who, 0.0f);
me->SetInCombatWith(who);
who->SetInCombatWith(me);
DoStartMovement(who);
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
void ScheduleTasks() override
{
case EVENT_OPTIC_LINK:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
scheduler.Async([this]
{
DoCast(me, DUNGEON_MODE(SPELL_RAY_OF_PAIN, SPELL_RAY_OF_PAIN_H));
DoCast(me, DUNGEON_MODE(SPELL_RAY_OF_SUFFERING, SPELL_RAY_OF_SUFFERING_H));
});
scheduler.Schedule(Seconds(15), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true))
DoCast(target, SPELL_OPTIC_LINK);
events.ScheduleEvent(EVENT_OPTIC_LINK, 25000);
break;
case EVENT_CORROSIVE_SALIVA:
task.Repeat(Seconds(25));
});
scheduler.Schedule(Seconds(5), [this](TaskContext task)
{
DoCastVictim(SPELL_CORROSIVE_SALIVA);
events.ScheduleEvent(EVENT_CORROSIVE_SALIVA, 10000);
break;
default:
break;
task.Repeat(Seconds(10));
});
}
};
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
CreatureAI* GetAI(Creature* creature) const override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
return GetVioletHoldAI<boss_moraggAI>(creature);
}
private:
EventMap events;
InstanceScript* instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_moraggAI>(creature);
}
};
class spell_moragg_ray_of_suffering : public SpellScriptLoader
class spell_moragg_ray : public SpellScriptLoader
{
public:
spell_moragg_ray_of_suffering() : SpellScriptLoader("spell_moragg_ray_of_suffering") { }
public:
spell_moragg_ray() : SpellScriptLoader("spell_moragg_ray") { }
class spell_moragg_ray_of_suffering_AuraScript : public AuraScript
{
PrepareAuraScript(spell_moragg_ray_of_suffering_AuraScript);
void OnPeriodic(AuraEffect const* aurEff)
class spell_moragg_ray_AuraScript : public AuraScript
{
PreventDefaultAction();
std::list<HostileReference*> players = GetTarget()->getThreatManager().getThreatList();
if (!players.empty())
PrepareAuraScript(spell_moragg_ray_AuraScript);
void OnPeriodic(AuraEffect const* aurEff)
{
std::list<HostileReference*>::iterator itr = players.begin();
std::advance(itr, urand(0, players.size() - 1));
PreventDefaultAction();
uint32 triggerSpell = GetSpellInfo()->GetEffect(aurEff->GetEffIndex())->TriggerSpell;
GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_MAX_TARGETS, 1, (*itr)->getTarget(), TRIGGERED_FULL_MASK, NULL, aurEff);
if (!GetTarget()->IsAIEnabled)
return;
if (Unit* target = GetTarget()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true))
{
uint32 triggerSpell = aurEff->GetSpellEffectInfo()->TriggerSpell;
GetTarget()->CastSpell(target, triggerSpell, TRIGGERED_FULL_MASK, nullptr, aurEff);
}
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_ray_of_suffering_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_moragg_ray_of_suffering_AuraScript();
}
};
class spell_moragg_ray_of_pain : public SpellScriptLoader
{
public:
spell_moragg_ray_of_pain() : SpellScriptLoader("spell_moragg_ray_of_pain") { }
class spell_moragg_ray_of_pain_AuraScript : public AuraScript
{
PrepareAuraScript(spell_moragg_ray_of_pain_AuraScript);
void OnPeriodic(AuraEffect const* aurEff)
{
PreventDefaultAction();
std::list<HostileReference*> players = GetTarget()->getThreatManager().getThreatList();
if (!players.empty())
void Register() override
{
std::list<HostileReference*>::iterator itr = players.begin();
std::advance(itr, urand(0, players.size() - 1));
uint32 triggerSpell = GetSpellInfo()->GetEffect(aurEff->GetEffIndex())->TriggerSpell;
GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_MAX_TARGETS, 1, (*itr)->getTarget(), TRIGGERED_FULL_MASK, NULL, aurEff);
OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_ray_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
}
};
void Register() override
AuraScript* GetAuraScript() const override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_ray_of_pain_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
return new spell_moragg_ray_AuraScript();
}
};
AuraScript* GetAuraScript() const override
{
return new spell_moragg_ray_of_pain_AuraScript();
}
};
class spell_moragg_optic_link : public SpellScriptLoader
@@ -232,30 +150,15 @@ public:
void OnPeriodic(AuraEffect const* aurEff)
{
switch (aurEff->GetTickNumber()) // Different visual based on tick
if (Unit* caster = GetCaster())
{
case 1:
case 2:
case 3:
GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff);
break;
case 4:
case 5:
case 6:
case 7:
GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff);
GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_2, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff);
break;
case 8:
case 9:
case 10:
case 11:
GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff);
GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_2, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff);
GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_3, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff);
break;
default:
break;
if (aurEff->GetTickNumber() >= 8)
caster->CastSpell(GetTarget(), SPELL_OPTIC_LINK_LEVEL_3, TRIGGERED_FULL_MASK, nullptr, aurEff);
if (aurEff->GetTickNumber() >= 4)
caster->CastSpell(GetTarget(), SPELL_OPTIC_LINK_LEVEL_2, TRIGGERED_FULL_MASK, nullptr, aurEff);
caster->CastSpell(GetTarget(), SPELL_OPTIC_LINK_LEVEL_1, TRIGGERED_FULL_MASK, nullptr, aurEff);
}
}
@@ -293,7 +196,6 @@ public:
void AddSC_boss_moragg()
{
new boss_moragg();
new spell_moragg_ray_of_suffering();
new spell_moragg_ray_of_pain();
new spell_moragg_ray();
new spell_moragg_optic_link();
}
@@ -22,50 +22,53 @@
#include "Player.h"
#include "violet_hold.h"
/*
* TODO:
* - Implement Ethereal Summon Target
*/
enum Spells
{
SPELL_ARCANE_BARRAGE_VOLLEY = 54202,
SPELL_ARCANE_BUFFET = 54226,
SPELL_SUMMON_ETHEREAL_SPHERE_1 = 54102,
SPELL_SUMMON_ETHEREAL_SPHERE_2 = 61337,
SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138
SPELL_SUMMON_TARGET_VISUAL = 54111
};
static uint32 const EtherealSphereCount = 3;
static uint32 const EtherealSphereSummonSpells[EtherealSphereCount] = { 54102, 54137, 54138 };
static uint32 const EtherealSphereHeroicSummonSpells[EtherealSphereCount] = { 54102, 54137, 54138 };
enum NPCs
{
NPC_ETHEREAL_SPHERE = 29271,
NPC_ETHEREAL_SPHERE2 = 32582
NPC_ETHEREAL_SPHERE2 = 32582,
NPC_ETHEREAL_SUMMON_TARGET = 29276
};
enum CreatureSpells
{
SPELL_ARCANE_POWER = 54160,
H_SPELL_ARCANE_POWER = 59474,
SPELL_MAGIC_PULL = 50770,
SPELL_SUMMON_PLAYERS = 54164,
SPELL_POWER_BALL_VISUAL = 54141,
SPELL_POWER_BALL_DAMAGE_TRIGGER = 54207
SPELL_POWER_BALL_DAMAGE_TRIGGER = 54207,
SPELL_POWER_BALL_DAMAGE_TRIGGER_H = 59476
};
enum Yells
{
// Xevozz
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2,
SAY_SPAWN = 3,
SAY_CHARGED = 4,
SAY_REPEAT_SUMMON = 5,
SAY_SUMMON_ENERGY = 6
};
SAY_SUMMON_ENERGY = 6,
enum XevozzEvents
{
EVENT_ARCANE_BARRAGE = 1,
EVENT_ARCANE_BUFFET,
EVENT_SUMMON_SPHERE,
EVENT_SUMMON_SPHERE_2,
EVENT_RANGE_CHECK,
EVENT_SUMMON_PLAYERS,
EVENT_DESPAWN_SPHERE
// Ethereal Sphere
SAY_ETHEREAL_SPHERE_SUMMON = 0
};
enum SphereActions
@@ -75,319 +78,210 @@ enum SphereActions
class boss_xevozz : public CreatureScript
{
public:
boss_xevozz() : CreatureScript("boss_xevozz") { }
public:
boss_xevozz() : CreatureScript("boss_xevozz") { }
struct boss_xevozzAI : public ScriptedAI
{
boss_xevozzAI(Creature* creature) : ScriptedAI(creature)
struct boss_xevozzAI : public BossAI
{
instance = creature->GetInstanceScript();
}
boss_xevozzAI(Creature* creature) : BossAI(creature, DATA_XEVOZZ) { }
void Reset() override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
DespawnSphere();
events.Reset();
}
void DespawnSphere()
{
std::list<Creature*> assistList;
GetCreatureListWithEntryInGrid(assistList, me, NPC_ETHEREAL_SPHERE, 150.0f);
GetCreatureListWithEntryInGrid(assistList, me, NPC_ETHEREAL_SPHERE2, 150.0f);
if (assistList.empty())
return;
for (std::list<Creature*>::const_iterator iter = assistList.begin(); iter != assistList.end(); ++iter)
void Reset() override
{
if (Creature* pSphere = *iter)
pSphere->Kill(pSphere, false);
BossAI::Reset();
}
}
void JustSummoned(Creature* summoned) override
{
summoned->SetSpeed(MOVE_RUN, 0.5f);
summoned->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f);
}
void AttackStart(Unit* who) override
{
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
if (me->Attack(who, true))
void EnterCombat(Unit* who) override
{
me->AddThreat(who, 0.0f);
me->SetInCombatWith(who);
who->SetInCombatWith(me);
DoStartMovement(who);
BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
}
}
void EnterCombat(Unit* /*who*/) override
{
if (GameObject* door = instance->GetGameObject(DATA_XEVOZZ_CELL))
if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
void JustReachedHome() override
{
BossAI::JustReachedHome();
instance->SetData(DATA_HANDLE_CELLS, DATA_XEVOZZ);
}
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
summon->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void SpellHit(Unit* /*who*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_ARCANE_POWER || spell->Id == H_SPELL_ARCANE_POWER)
Talk(SAY_SUMMON_ENERGY);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
}
Talk(SAY_AGGRO);
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
events.ScheduleEvent(EVENT_SUMMON_SPHERE, 5000);
events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(8000, 10000));
events.ScheduleEvent(EVENT_ARCANE_BUFFET, urand(10000, 11000));
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
DespawnSphere();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
void ScheduleTasks() override
{
instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void SpellHit(Unit* who, const SpellInfo* spell) override
{
if (!who->ToCreature())
return;
if ((spell->Id == SPELL_ARCANE_POWER) || (spell->Id == H_SPELL_ARCANE_POWER))
Talk(SAY_SUMMON_ENERGY);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_ARCANE_BARRAGE:
DoCast(SPELL_ARCANE_BARRAGE_VOLLEY);
events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(8000, 10000));
break;
case EVENT_ARCANE_BUFFET:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(target, SPELL_ARCANE_BUFFET);
events.ScheduleEvent(EVENT_ARCANE_BUFFET, urand(15000, 20000));
break;
case EVENT_SUMMON_SPHERE:
Talk(SAY_REPEAT_SUMMON);
DoCast(SPELL_SUMMON_ETHEREAL_SPHERE_1);
if (IsHeroic())
events.ScheduleEvent(EVENT_SUMMON_SPHERE_2, 2500);
events.ScheduleEvent(EVENT_SUMMON_PLAYERS, urand(33000, 35000));
events.ScheduleEvent(EVENT_SUMMON_SPHERE, urand(45000, 47000));
break;
case EVENT_SUMMON_SPHERE_2:
Talk(SAY_REPEAT_SUMMON);
DoCast(SPELL_SUMMON_ETHEREAL_SPHERE_2);
break;
case EVENT_SUMMON_PLAYERS:
scheduler.Schedule(Seconds(8), Seconds(10), [this](TaskContext task)
{
Creature* sphere = me->FindNearestCreature(NPC_ETHEREAL_SPHERE, 150.0f);
if (!sphere)
sphere = me->FindNearestCreature(NPC_ETHEREAL_SPHERE2, 150.0f);
if (sphere)
sphere->GetAI()->DoAction(ACTION_SUMMON);
break;
}
default:
break;
DoCastAOE(SPELL_ARCANE_BARRAGE_VOLLEY);
task.Repeat(Seconds(8), Seconds(10));
});
scheduler.Schedule(Seconds(10), Seconds(11), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true))
DoCast(target, SPELL_ARCANE_BUFFET);
task.Repeat(Seconds(15), Seconds(20));
});
scheduler.Schedule(Seconds(5), [this](TaskContext task)
{
Talk(SAY_REPEAT_SUMMON);
std::list<uint8> summonSpells = { 0, 1, 2 };
uint8 spell = Trinity::Containers::SelectRandomContainerElement(summonSpells);
DoCast(me, EtherealSphereSummonSpells[spell]);
summonSpells.remove(spell);
if (IsHeroic())
{
spell = Trinity::Containers::SelectRandomContainerElement(summonSpells);
task.Schedule(Milliseconds(2500), [this, spell](TaskContext /*task*/)
{
DoCast(me, EtherealSphereHeroicSummonSpells[spell]);
});
}
task.Schedule(Seconds(33), Seconds(35), [this](TaskContext /*task*/)
{
DummyEntryCheckPredicate pred;
summons.DoAction(ACTION_SUMMON, pred);
});
task.Repeat(Seconds(45), Seconds(47));
});
}
};
DoMeleeAttackIfReady();
CreatureAI* GetAI(Creature* creature) const override
{
return GetVioletHoldAI<boss_xevozzAI>(creature);
}
private:
InstanceScript* instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_xevozzAI>(creature);
}
};
class npc_ethereal_sphere : public CreatureScript
{
public:
npc_ethereal_sphere() : CreatureScript("npc_ethereal_sphere") { }
public:
npc_ethereal_sphere() : CreatureScript("npc_ethereal_sphere") { }
struct npc_ethereal_sphereAI : public ScriptedAI
{
npc_ethereal_sphereAI(Creature* creature) : ScriptedAI(creature)
struct npc_ethereal_sphereAI : public ScriptedAI
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
arcanePower = false;
}
void Reset() override
{
Initialize();
events.Reset();
DoCast(SPELL_POWER_BALL_VISUAL);
DoCast(SPELL_POWER_BALL_DAMAGE_TRIGGER);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->setFaction(16);
events.ScheduleEvent(EVENT_DESPAWN_SPHERE, 40000);
events.ScheduleEvent(EVENT_RANGE_CHECK, 1000);
}
void DoAction(int32 action) override
{
if (action == ACTION_SUMMON)
DoCast(SPELL_SUMMON_PLAYERS);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
npc_ethereal_sphereAI(Creature* creature) : ScriptedAI(creature)
{
case EVENT_RANGE_CHECK:
if (Creature* xevozz = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_XEVOZZ)))
instance = creature->GetInstanceScript();
}
void Reset() override
{
scheduler.CancelAll();
ScheduledTasks();
DoCast(me, SPELL_POWER_BALL_VISUAL);
DoCast(me, DUNGEON_MODE(SPELL_POWER_BALL_DAMAGE_TRIGGER, SPELL_POWER_BALL_DAMAGE_TRIGGER_H));
me->DespawnOrUnsummon(40000);
}
void DoAction(int32 action) override
{
if (action == ACTION_SUMMON)
{
Talk(SAY_ETHEREAL_SPHERE_SUMMON);
DoCastAOE(SPELL_SUMMON_PLAYERS);
}
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
}
void ScheduledTasks()
{
scheduler.Schedule(Seconds(1), [this](TaskContext task)
{
if (Creature* xevozz = instance->GetCreature(DATA_XEVOZZ))
{
if (me->IsWithinDist(xevozz, 3.0f) && !arcanePower)
if (me->IsWithinDist(xevozz, 3.0f))
{
DoCast(SPELL_ARCANE_POWER);
arcanePower = true;
events.ScheduleEvent(EVENT_DESPAWN_SPHERE, 8000);
DoCastAOE(SPELL_ARCANE_POWER);
me->DespawnOrUnsummon(8000);
return;
}
}
events.ScheduleEvent(EVENT_RANGE_CHECK, 1000);
break;
case EVENT_DESPAWN_SPHERE:
me->DespawnOrUnsummon();
break;
task.Repeat();
});
}
private:
InstanceScript* instance;
TaskScheduler scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetVioletHoldAI<npc_ethereal_sphereAI>(creature);
}
private:
InstanceScript* instance;
EventMap events;
bool arcanePower;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ethereal_sphereAI>(creature);
}
};
class spell_xevozz_summon_players : public SpellScriptLoader
{
public:
spell_xevozz_summon_players() : SpellScriptLoader("spell_xevozz_summon_players") { }
public:
spell_xevozz_summon_players() : SpellScriptLoader("spell_xevozz_summon_players") { }
class spell_xevozz_summon_players_SpellScript : public SpellScript
{
PrepareSpellScript(spell_xevozz_summon_players_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
class spell_xevozz_summon_players_SpellScript : public SpellScript
{
Unit* target = GetHitUnit();
PrepareSpellScript(spell_xevozz_summon_players_SpellScript);
if (target)
bool Validate(SpellInfo const* /*spellInfo*/) override
{
Position pos = GetOriginalCaster()->GetPosition();
target->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_xevozz_summon_players_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_xevozz_summon_players_SpellScript();
}
};
class spell_xevozz_summon_ethereal_sphere : public SpellScriptLoader
{
public:
spell_xevozz_summon_ethereal_sphere() : SpellScriptLoader("spell_xevozz_summon_ethereal_sphere") { }
class spell_xevozz_summon_ethereal_sphere_SpellScript : public SpellScript
{
PrepareSpellScript(spell_xevozz_summon_ethereal_sphere_SpellScript);
void HandleScript(SpellDestination& target)
{
Unit* caster = GetOriginalCaster();
Position pos;
float distance = 0.0f;
while (distance < 20.0f)
{
pos = caster->GetRandomNearPosition(60.0f);
distance = caster->GetDistance(pos);
if (!sSpellMgr->GetSpellInfo(SPELL_MAGIC_PULL))
return false;
return true;
}
target.Relocate(pos);
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_MAGIC_PULL, true);
}
void Register() override
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_xevozz_summon_players_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_xevozz_summon_ethereal_sphere_SpellScript::HandleScript, EFFECT_0, TARGET_DEST_DB);
return new spell_xevozz_summon_players_SpellScript();
}
};
SpellScript* GetSpellScript() const override
{
return new spell_xevozz_summon_ethereal_sphere_SpellScript();
}
};
void AddSC_boss_xevozz()
@@ -395,5 +289,4 @@ void AddSC_boss_xevozz()
new boss_xevozz();
new npc_ethereal_sphere();
new spell_xevozz_summon_players();
new spell_xevozz_summon_ethereal_sphere();
}
@@ -25,6 +25,10 @@ enum Spells
SPELL_SUMMON_VOID_SENTRY = 54369,
SPELL_VOID_SHIFT = 54361,
SPELL_VOID_SHIFTED = 54343,
SPELL_ZURAMAT_ADD = 54341,
SPELL_ZURAMAT_ADD_2 = 54342,
SPELL_ZURAMAT_ADD_DUMMY = 54351,
SPELL_SUMMON_VOID_SENTRY_BALL = 58650
};
enum Yells
@@ -39,188 +43,172 @@ enum Yells
enum Misc
{
ACTION_DESPAWN_VOID_SENTRY_BALL = 1,
DATA_VOID_DANCE = 2153
};
enum ZuramatEvents
{
EVENT_VOID_SHIFT = 1,
EVENT_SUMMON_VOID,
EVENT_SHROUD_OF_DARKNESS
};
class boss_zuramat : public CreatureScript
{
public:
boss_zuramat() : CreatureScript("boss_zuramat") { }
public:
boss_zuramat() : CreatureScript("boss_zuramat") { }
struct boss_zuramatAI : public ScriptedAI
{
boss_zuramatAI(Creature* creature) : ScriptedAI(creature), sentries(me)
struct boss_zuramatAI : public BossAI
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
voidDance = true;
}
void DespawnSentries()
{
sentries.DespawnAll();
std::list<Creature*> sentrylist;
GetCreatureListWithEntryInGrid(sentrylist, me, NPC_VOID_SENTRY_BALL, 200.0f);
if (!sentrylist.empty())
for (std::list<Creature*>::const_iterator itr = sentrylist.begin(); itr != sentrylist.end(); ++itr)
(*itr)->DespawnOrUnsummon();
}
void Reset() override
{
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
Initialize();
events.Reset();
DespawnSentries();
}
void AttackStart(Unit* who) override
{
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
if (me->Attack(who, true))
boss_zuramatAI(Creature* creature) : BossAI(creature, DATA_ZURAMAT)
{
me->AddThreat(who, 0.0f);
me->SetInCombatWith(who);
who->SetInCombatWith(me);
DoStartMovement(who);
Initialize();
}
}
void EnterCombat(Unit* /*who*/) override
{
if (GameObject* door = instance->GetGameObject(DATA_ZURAMAT_CELL))
if (door->GetGoState() == GO_STATE_READY)
{
EnterEvadeMode();
void Initialize()
{
_voidDance = true;
}
void Reset() override
{
BossAI::Reset();
Initialize();
}
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
Talk(SAY_AGGRO);
}
void JustReachedHome() override
{
BossAI::JustReachedHome();
instance->SetData(DATA_HANDLE_CELLS, DATA_ZURAMAT);
}
void SummonedCreatureDies(Creature* summon, Unit* /*who*/) override
{
if (summon->GetEntry() == NPC_VOID_SENTRY)
_voidDance = false;
}
void SummonedCreatureDespawn(Creature* summon) override
{
if (summon->GetEntry() == NPC_VOID_SENTRY)
summon->AI()->DoAction(ACTION_DESPAWN_VOID_SENTRY_BALL);
BossAI::SummonedCreatureDespawn(summon);
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_VOID_DANCE)
return _voidDance ? 1 : 0;
return 0;
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
}
Talk(SAY_AGGRO);
if (instance->GetData(DATA_WAVE_COUNT) == 6)
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
me->SetInCombatWithZone();
events.ScheduleEvent(EVENT_SHROUD_OF_DARKNESS, urand(18000, 20000));
events.ScheduleEvent(EVENT_VOID_SHIFT, 9000);
events.ScheduleEvent(EVENT_SUMMON_VOID, 4000);
}
void JustSummoned(Creature* summon) override
{
sentries.Summon(summon);
}
void SummonedCreatureDies(Creature* summoned, Unit* /*who*/) override
{
if (summoned->GetEntry() == NPC_VOID_SENTRY)
voidDance = false;
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_VOID_DANCE)
return voidDance ? 1 : 0;
return 0;
}
void JustDied(Unit* /*killer*/) override
{
instance->SetData(DATA_ZURAMAT, 1);
Talk(SAY_DEATH);
DespawnSentries();
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 7);
}
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
{
instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE);
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SUMMON_VOID:
DoCast(SPELL_SUMMON_VOID_SENTRY);
events.ScheduleEvent(EVENT_SUMMON_VOID, urand(7000, 10000));
break;
case EVENT_VOID_SHIFT:
if (Unit* unit = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(unit, SPELL_VOID_SHIFT);
events.ScheduleEvent(EVENT_VOID_SHIFT, 15000);
break;
case EVENT_SHROUD_OF_DARKNESS:
DoCast(SPELL_SHROUD_OF_DARKNESS);
events.ScheduleEvent(EVENT_SHROUD_OF_DARKNESS, urand(18000, 20000));
break;
default:
break;
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
DoMeleeAttackIfReady();
void ScheduleTasks() override
{
scheduler.Schedule(Seconds(4), [this](TaskContext task)
{
DoCast(me, SPELL_SUMMON_VOID_SENTRY);
task.Repeat(Seconds(7), Seconds(10));
});
scheduler.Schedule(Seconds(9), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, true))
DoCast(target, SPELL_VOID_SHIFT);
task.Repeat(Seconds(15));
});
scheduler.Schedule(Seconds(18), Seconds(20), [this](TaskContext task)
{
DoCast(me, SPELL_SHROUD_OF_DARKNESS);
task.Repeat(Seconds(18), Seconds(20));
});
}
private:
bool _voidDance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetVioletHoldAI<boss_zuramatAI>(creature);
}
};
private:
InstanceScript* instance;
EventMap events;
SummonList sentries;
bool voidDance;
};
class npc_void_sentry : public CreatureScript
{
public:
npc_void_sentry() : CreatureScript("npc_void_sentry") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_zuramatAI>(creature);
}
struct npc_void_sentryAI : public ScriptedAI
{
npc_void_sentryAI(Creature* creature) : ScriptedAI(creature), _summons(creature)
{
me->SetReactState(REACT_PASSIVE);
}
void IsSummonedBy(Unit* /*summoner*/) override
{
me->CastSpell(me, SPELL_SUMMON_VOID_SENTRY_BALL, true);
}
void JustSummoned(Creature* summon) override
{
_summons.Summon(summon);
summon->SetReactState(REACT_PASSIVE);
}
void SummonedCreatureDespawn(Creature* summon) override
{
_summons.Despawn(summon);
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_DESPAWN_VOID_SENTRY_BALL)
_summons.DespawnAll();
}
void JustDied(Unit* /*killer*/) override
{
DoAction(ACTION_DESPAWN_VOID_SENTRY_BALL);
}
private:
SummonList _summons;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetVioletHoldAI<npc_void_sentryAI>(creature);
}
};
class achievement_void_dance : public AchievementCriteriaScript
{
public:
achievement_void_dance() : AchievementCriteriaScript("achievement_void_dance")
{
}
achievement_void_dance() : AchievementCriteriaScript("achievement_void_dance") { }
bool OnCheck(Player* /*player*/, Unit* target) override
{
@@ -238,5 +226,6 @@ class achievement_void_dance : public AchievementCriteriaScript
void AddSC_boss_zuramat()
{
new boss_zuramat();
new npc_void_sentry();
new achievement_void_dance();
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -15,44 +15,56 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEF_VIOLET_HOLD_H
#define DEF_VIOLET_HOLD_H
#ifndef VIOLET_HOLD_H_
#define VIOLET_HOLD_H_
#define VioletHoldScriptName "instance_violet_hold"
#define DataHeader "VH"
uint32 const EncounterCount = 3;
uint32 const EncounterCount = 3 + 6;
// Defined in instance_violet_hold.cpp
extern Position const DefenseSystemLocation;
uint8 const PortalIntroCount = 3;
extern Position const PortalIntroPositions[];
/*
* Violet hold bosses:
*
* 1 - Moragg
* 2 - Erekem
* 3 - Ichoron
* 4 - Lavanthor
* 5 - Xevozz
* 6 - Zuramat
* 7 - Cyanigosa
*/
enum Data
{
// Main encounters
DATA_1ST_BOSS_EVENT,
DATA_2ND_BOSS_EVENT,
DATA_CYANIGOSA,
DATA_1ST_BOSS = 0,
DATA_2ND_BOSS = 1,
DATA_CYANIGOSA = 2,
// Bosses
DATA_MORAGG = 3,
DATA_EREKEM = 4,
DATA_ICHORON = 5,
DATA_LAVANTHOR = 6,
DATA_XEVOZZ = 7,
DATA_ZURAMAT = 8,
// Misc
DATA_MAIN_EVENT_STATE,
DATA_WAVE_COUNT,
DATA_REMOVE_NPC,
DATA_PORTAL_LOCATION,
DATA_DOOR_INTEGRITY,
DATA_NPC_PRESENCE_AT_DOOR,
DATA_NPC_PRESENCE_AT_DOOR_ADD,
DATA_NPC_PRESENCE_AT_DOOR_REMOVE,
DATA_PORTAL_LOCATION,
DATA_START_BOSS_ENCOUNTER,
DATA_FIRST_BOSS,
DATA_SECOND_BOSS,
DATA_ACTIVATE_CRYSTAL,
DATA_MAIN_EVENT_PHASE,
DATA_DEFENSELESS,
// Bosses
DATA_MORAGG,
DATA_EREKEM,
DATA_EREKEM_GUARD_1,
DATA_EREKEM_GUARD_2,
DATA_ICHORON,
DATA_LAVANTHOR,
DATA_XEVOZZ,
DATA_ZURAMAT,
// Cells
DATA_MORAGG_CELL,
@@ -67,43 +79,43 @@ enum Data
// Misc
DATA_MAIN_DOOR,
DATA_SINCLARI,
DATA_TELEPORTATION_PORTAL,
DATA_SABOTEUR_PORTAL,
DATA_ADD_TRASH_MOB,
DATA_DEL_TRASH_MOB
};
enum Bosses
{
BOSS_NONE, // 0 used as marker for not yet randomized
BOSS_MORAGG,
BOSS_EREKEM,
BOSS_ICHORON,
BOSS_LAVANTHOR,
BOSS_XEVOZZ,
BOSS_ZURAMAT,
BOSS_CYANIGOSA
DATA_SINCLARI_TRIGGER,
DATA_HANDLE_CELLS
};
enum CreaturesIds
{
NPC_TELEPORTATION_PORTAL = 31011,
NPC_TELEPORTATION_PORTAL = 30679,
NPC_TELEPORTATION_PORTAL_ELITE = 32174,
NPC_TELEPORTATION_PORTAL_INTRO = 31011,
NPC_PORTAL_GUARDIAN = 30660,
NPC_PORTAL_KEEPER = 30695,
NPC_XEVOZZ = 29266,
NPC_LAVANTHOR = 29312,
NPC_ICHORON = 29313,
NPC_ICHOR_GLOBULE = 29321,
NPC_ICHORON_SUMMON_TARGET = 29326,
NPC_ZURAMAT = 29314,
NPC_VOID_SENTRY = 29364,
NPC_VOID_SENTRY_BALL = 29365,
NPC_EREKEM = 29315,
NPC_EREKEM_GUARD = 29395,
NPC_MORAGG = 29316,
NPC_DUMMY_XEVOZZ = 32231,
NPC_DUMMY_LAVANTHOR = 32237,
NPC_DUMMY_ICHORON = 32234,
NPC_DUMMY_ZURAMAT = 32230,
NPC_DUMMY_EREKEM = 32226,
NPC_DUMMY_EREKEM_GUARD = 32228,
NPC_DUMMY_MORAGG = 32235,
NPC_CYANIGOSA = 31134,
NPC_SINCLARI = 30658,
NPC_SINCLARI_TRIGGER = 32204,
NPC_SABOTEOUR = 31079,
NPC_VIOLET_HOLD_GUARD = 30659,
NPC_DEFENSE_SYSTEM = 30837,
NPC_VOID_SENTRY = 29364,
NPC_VOID_SENTRY_BALL = 29365
NPC_DEFENSE_SYSTEM = 30837
};
enum GameObjectIds
@@ -117,13 +129,13 @@ enum GameObjectIds
GO_EREKEM_GUARD_1_DOOR = 191563,
GO_EREKEM_GUARD_2_DOOR = 191562,
GO_MORAGG_DOOR = 191606,
GO_INTRO_ACTIVATION_CRYSTAL = 193615,
GO_ACTIVATION_CRYSTAL = 193611
GO_ACTIVATION_CRYSTAL = 193611,
GO_INTRO_ACTIVATION_CRYSTAL = 193615
};
enum WorldStateIds
{
WORLD_STATE_VH = 3816,
WORLD_STATE_VH_SHOW = 3816,
WORLD_STATE_VH_PRISON_STATE = 3815,
WORLD_STATE_VH_WAVE_COUNT = 3810,
};
@@ -133,4 +145,16 @@ enum Events
EVENT_ACTIVATE_CRYSTAL = 20001
};
#endif
enum InstanceMisc
{
ACTION_SINCLARI_OUTRO = 1,
POINT_INTRO = 1
};
template<class AI>
inline AI* GetVioletHoldAI(Creature* creature)
{
return GetInstanceAI<AI>(creature, VioletHoldScriptName);
}
#endif // VIOLET_HOLD_H_
@@ -1818,7 +1818,7 @@ public:
player->FailQuest(QUEST_GET_ME_OUTA_HERE);
}
void UpdateEscortAI(const uint32 /*diff*/) override
void UpdateEscortAI(uint32 /*diff*/) override
{
if (GetAttack() && UpdateVictim())
{
@@ -98,7 +98,7 @@ public:
player->FailQuest(QUEST_TRAIL_OF_FIRE);
}
void UpdateEscortAI(const uint32 diff) override
void UpdateEscortAI(uint32 diff) override
{
if (HealthBelowPct(75))
{
@@ -136,7 +136,7 @@ class boss_ambassador_hellmaw : public CreatureScript
Talk(SAY_DEATH);
}
void UpdateEscortAI(uint32 const diff) override
void UpdateEscortAI(uint32 diff) override
{
if (!UpdateVictim())
return;