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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user