Scripts/VP: reworked Grandvizier Ertan encounter

* optimized code
* updated code to new scripting model
* updated texts with broadcast text entries
* fixed some visual threat issues caused by Ertan's Vortex by hitting players with their damage spell
This commit is contained in:
Ovahlord
2019-08-12 21:00:53 +02:00
parent 134e15614e
commit 1ec85e3212
5 changed files with 227 additions and 257 deletions

View File

@@ -0,0 +1,33 @@
UPDATE `creature_template` SET `ScriptName`= 'npc_ertan_ertans_vortex' WHERE `entry`= 46007;
DELETE FROM `creature_template_addon` WHERE `entry`= 46007;
INSERT INTO `creature_template_addon` (`entry`, `auras`) VALUES
(46007, '86267');
DELETE FROM `spell_script_names` WHERE `ScriptName` IN
('spell_storms_edge_script',
'spell_storms_edge',
'spell_ertan_storms_edge',
'spell_ertan_storms_edge_script');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(86284, 'spell_ertan_storms_edge'),
(86311, 'spell_ertan_storms_edge'),
(86299, 'spell_ertan_storms_edge_script');
DELETE FROM `creature_template_movement` WHERE `CreatureId` IN (43878, 43879);
INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Flight`, `Swim`, `Rooted`) VALUES
(43878, 0, 1, 0, 1),
(43879, 0, 1, 0, 1);
DELETE FROM `spell_custom_attr` WHERE `entry` IN (86299, 86309, 93992);
INSERT INTO `spell_custom_attr` (`entry`, `attributes`) VALUES
(86299, 0x00000010),
(86309, 0x00000010),
(93992, 0x00000010);
DELETE FROM `creature_text` WHERE `CreatureID` IN (43878, 45704);
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `comment`) VALUES
(43878, 0, 0, 'Filthy beasts! Your presence in Skywall will not be tolerated!', 14, 0, 100, 0, 0, 20876, 49570, 'Grandvizier Ertan - Aggro'),
(43878, 1, 0, '%s retracts her cyclone shield!', 41, 0, 100, 0, 0, 0, 47800, 'Grandvizier Ertan - Announce Storms Edge'),
(45704, 0, 0, '%s realizes it''s been spotted and quickly plays dead!', 16, 0, 100, 0, 0, 0, 46485, 'Lurking Tempest');

View File

@@ -25,64 +25,52 @@
enum Spells
{
SPELL_STORMS_EDGE_AURA = 86295,
// Grandvizier Ertan
SPELL_STORMS_EDGE_PERIODIC = 86295,
SPELL_LIGHTNING_BOLT = 86331,
SPELL_SUMMON_TEMPEST = 86340,
SPELL_STORMS_EDGE_VISUAL = 86329,
SPELL_STORMS_EDGE_CYCLONE_SHIELD_AURA = 86310, // periodically triggers 86311
// Ertan's Vortex
SPELL_CYCLONE_SHIELD = 86267,
SPELL_CYCLONE_SHIELD_TRIGGER = 86292,
SPELL_STORMS_EDGE_SCRIPT = 86299, // targets closest cyclone and makes it cast SPELL_STORMS_EDGE_DAMAGE on caster
// SPELL_STORMS_EDGE_DAMAGE = 86309,
};
enum NPCs
{
NPC_ERTANS_VORTEX = 46007,
SPELL_STORMS_EDGE_PERIODIC_2 = 86310,
SPELL_STORMS_EDGE_TRIGGERED_1 = 86284,
SPELL_STORMS_EDGE_SCRIPT = 86299
};
enum Texts
{
SAY_AGGRO = 0,
SAY_STORMS_EDGE = 1,
};
enum Actions
{
ACTION_STORMS_EDGE = 1,
// Grand Vizier Ertan
SAY_AGGRO = 0,
SAY_ANNOUNCE_STORMS_EDGE = 1
};
enum Events
{
EVENT_NONE,
EVENT_SUMMON_TEMPEST,
EVENT_STORMS_EDGE_SPAWN,
// Grandvizier Ertan
EVENT_SUMMON_TEMPEST = 1,
EVENT_STORMS_EDGE,
EVENT_STORMS_EDGE_AURA,
EVENT_STORMS_EDGE_END,
EVENT_END_STORMS_EDGE,
EVENT_LIGHTNING_BOLT,
// Ertan's Vortex
EVENT_MOVE_POINT,
EVENT_MOVE_POINT
};
enum Actions
{
// Ertan's Vortex
ACTION_STORMS_EDGE = 1
};
enum Points
{
POINT_ERTANS_VORTEX_S = 0,
POINT_ERTANS_VORTEX_SW = 1,
POINT_ERTANS_VORTEX_W = 2,
POINT_ERTANS_VORTEX_NW = 3,
POINT_ERTANS_VORTEX_N = 4,
POINT_ERTANS_VORTEX_NE = 5,
POINT_ERTANS_VORTEX_E = 6,
POINT_ERTANS_VORTEX_SE = 7,
POINT_ERTANS_VORTEX_MAX = 8,
POINT_NONE,
// Ertan's Vortex
POINT_NONE = 0,
POINT_ROTATE = 1
};
const Position ErtansVortexPoints[POINT_ERTANS_VORTEX_MAX] =
#define MAX_VORTEX_POINTS 8
const Position ErtansVortexPoints[MAX_VORTEX_POINTS] =
{
{ -744.889f, 3.98611f, 635.6728f }, // South
{ -737.552f, 21.592f, 635.6728f }, // South-West
@@ -94,7 +82,7 @@ const Position ErtansVortexPoints[POINT_ERTANS_VORTEX_MAX] =
{ -737.649f, -13.5347f, 635.6728f }, // South-East
};
const Position ErtansVortexMiddlePoints[POINT_ERTANS_VORTEX_MAX] =
const Position ErtansVortexMiddlePoints[MAX_VORTEX_POINTS] =
{
{ -724.3819f, 2.915083f, 635.6728f }, // South
{ -724.0161f, 6.648534f, 635.6728f }, // South-West
@@ -106,247 +94,192 @@ const Position ErtansVortexMiddlePoints[POINT_ERTANS_VORTEX_MAX] =
{ -721.9816f, -0.05864143f, 635.6728f }, // South-East
};
class boss_grand_vizier_ertan : public CreatureScript
struct boss_grand_vizier_ertan : public BossAI
{
public:
boss_grand_vizier_ertan() : CreatureScript("boss_grand_vizier_ertan") { }
boss_grand_vizier_ertan(Creature* creature) : BossAI(creature, DATA_GRAND_VIZIER_ERTAN) { }
struct boss_grand_vizier_ertanAI : public BossAI
{
boss_grand_vizier_ertanAI(Creature* creature) : BossAI(creature, DATA_GRAND_VIZIER_ERTAN)
{
me->SetDisableGravity(true);
SetCombatMovement(false);
}
void JustEngagedWith(Unit* /*target*/) override
{
_JustEngagedWith();
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
SummonErtansVortexes();
DoCast(me, SPELL_STORMS_EDGE_AURA);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_STORMS_EDGE_SPAWN, 400);
events.ScheduleEvent(EVENT_STORMS_EDGE, 23000);
if (IsHeroic())
events.ScheduleEvent(EVENT_SUMMON_TEMPEST, 17000);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
_EnterEvadeMode();
_DespawnAtEvade();
}
void JustDied(Unit* /*killer*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_JustDied();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SUMMON_TEMPEST:
DoCast(me, SPELL_SUMMON_TEMPEST);
events.ScheduleEvent(EVENT_SUMMON_TEMPEST, 17000);
break;
case EVENT_STORMS_EDGE:
{
DoCast(me, SPELL_STORMS_EDGE_VISUAL);
EntryCheckPredicate pred(NPC_ERTANS_VORTEX);
summons.DoAction(ACTION_STORMS_EDGE, pred, 8);
Talk(SAY_STORMS_EDGE);
events.ScheduleEvent(EVENT_STORMS_EDGE_AURA, 3000);
events.ScheduleEvent(EVENT_STORMS_EDGE, 32000);
break;
}
case EVENT_STORMS_EDGE_AURA:
me->RemoveAurasDueToSpell(SPELL_STORMS_EDGE_AURA);
DoCast(me, SPELL_STORMS_EDGE_CYCLONE_SHIELD_AURA);
events.ScheduleEvent(EVENT_STORMS_EDGE_END, 6000);
break;
case EVENT_STORMS_EDGE_END:
me->RemoveAurasDueToSpell(SPELL_STORMS_EDGE_CYCLONE_SHIELD_AURA);
DoCast(me, SPELL_STORMS_EDGE_AURA);
break;
default:
break;
}
}
DoSpellAttackIfReady(SPELL_LIGHTNING_BOLT);
}
private:
void SummonErtansVortexes() // Summons Ertan's Vortex at each point and makes them move to the next point
{
for (int8 i = 0; i < POINT_ERTANS_VORTEX_MAX; i++)
{
if (Creature* ertansVortex = me->SummonCreature(NPC_ERTANS_VORTEX, ErtansVortexPoints[i]))
{
if (i == POINT_ERTANS_VORTEX_SE)
ertansVortex->GetMotionMaster()->MovePoint(POINT_ERTANS_VORTEX_S, ErtansVortexPoints[POINT_ERTANS_VORTEX_S]);
else
ertansVortex->GetMotionMaster()->MovePoint(i + 1, ErtansVortexPoints[i + 1]);
}
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetVortexPinnacleAI<boss_grand_vizier_ertanAI>(creature);
}
};
// 46007 - Ertan's Vortex
class npc_ertans_vortex : public CreatureScript
{
public:
npc_ertans_vortex() : CreatureScript("npc_ertans_vortex") { }
struct npc_ertans_vortexAI : public PassiveAI
void JustEngagedWith(Unit* /*target*/) override
{
npc_ertans_vortexAI(Creature* creature) : PassiveAI(creature)
{
Initialize();
}
_JustEngagedWith();
DoCastSelf(SPELL_STORMS_EDGE_PERIODIC);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
Talk(SAY_AGGRO);
void Initialize()
{
_currentPointId = 0;
}
for (uint8 i = 0; i < MAX_VORTEX_POINTS; i++)
if (Creature * ertansVortex = me->SummonCreature(NPC_ERTANS_VORTEX, ErtansVortexPoints[i]))
ertansVortex->GetMotionMaster()->MovePoint(POINT_ROTATE + i, ErtansVortexPoints[i + 1 < MAX_VORTEX_POINTS ? i + 1 : 0]);
void IsSummonedBy(Unit* /*summoner*/) override
{
DoCast(me, SPELL_CYCLONE_SHIELD, true);
}
events.ScheduleEvent(EVENT_STORMS_EDGE, 24s);
events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 1ms);
if (IsHeroic())
events.ScheduleEvent(EVENT_SUMMON_TEMPEST, 16s, 17s);
}
void DoAction(int32 action) override
{
if (action == ACTION_STORMS_EDGE)
{
me->GetMotionMaster()->MovePoint(POINT_NONE, ErtansVortexMiddlePoints[_currentPointId]);
events.ScheduleEvent(EVENT_MOVE_POINT, 9000);
}
}
void MovementInform(uint32 movementType, uint32 pointId) override
{
if (movementType != POINT_MOTION_TYPE || pointId == POINT_NONE)
return;
if (pointId < POINT_ERTANS_VORTEX_SE)
_currentPointId = pointId + 1;
else
_currentPointId = POINT_ERTANS_VORTEX_S;
events.ScheduleEvent(EVENT_MOVE_POINT, 1);
};
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_MOVE_POINT:
me->GetMotionMaster()->MovePoint(_currentPointId, ErtansVortexPoints[_currentPointId]);
break;
default:
break;
}
}
}
private:
EventMap events;
uint32 _currentPointId;
};
CreatureAI* GetAI(Creature* creature) const override
void EnterEvadeMode(EvadeReason /*why*/) override
{
return GetVortexPinnacleAI<npc_ertans_vortexAI>(creature);
_EnterEvadeMode();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
_DespawnAtEvade();
}
void JustDied(Unit* /*killer*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_JustDied();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SUMMON_TEMPEST:
DoCast(me, SPELL_SUMMON_TEMPEST);
events.Repeat(17s);
break;
case EVENT_STORMS_EDGE:
{
Talk(SAY_ANNOUNCE_STORMS_EDGE);
DoCastSelf(SPELL_STORMS_EDGE_VISUAL);
EntryCheckPredicate pred(NPC_ERTANS_VORTEX);
summons.DoAction(ACTION_STORMS_EDGE, pred, 8);
events.ScheduleEvent(EVENT_STORMS_EDGE_AURA, 3s);
events.Repeat(31s);
break;
}
case EVENT_STORMS_EDGE_AURA:
me->RemoveAurasDueToSpell(SPELL_STORMS_EDGE_PERIODIC);
DoCastSelf(SPELL_STORMS_EDGE_PERIODIC_2);
events.ScheduleEvent(EVENT_END_STORMS_EDGE, 6s);
break;
case EVENT_END_STORMS_EDGE:
me->RemoveAurasDueToSpell(SPELL_STORMS_EDGE_PERIODIC_2);
DoCastSelf(SPELL_STORMS_EDGE_PERIODIC);
break;
case EVENT_LIGHTNING_BOLT:
DoCastVictim(SPELL_LIGHTNING_BOLT);
events.Repeat(2s + 400ms);
break;
default:
break;
}
}
}
};
// 86284 - Storm's Edge (targets players outside cyclone ring/further than 25 yards and makes them cast 86299)
// 86311 - Storm's Edge (targets all players and makes them cast 86299)
class spell_storms_edge : public SpellScriptLoader
struct npc_ertan_ertans_vortex : public NullCreatureAI
{
public:
spell_storms_edge() : SpellScriptLoader("spell_storms_edge") { }
npc_ertan_ertans_vortex(Creature* creature) : NullCreatureAI(creature), _nextPointId(0) { }
class spell_storms_edge_SpellScript : public SpellScript
void DoAction(int32 action) override
{
PrepareSpellScript(spell_storms_edge_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
switch (action)
{
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_STORMS_EDGE_SCRIPT, true);
case ACTION_STORMS_EDGE:
me->GetMotionMaster()->MovePoint(POINT_NONE, ErtansVortexMiddlePoints[_nextPointId]);
_events.ScheduleEvent(EVENT_MOVE_POINT, 9s);
break;
default:
break;
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_storms_edge_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
void MovementInform(uint32 movementType, uint32 pointId) override
{
if (movementType != POINT_MOTION_TYPE || pointId == POINT_NONE)
return;
_nextPointId = pointId < MAX_VORTEX_POINTS ? pointId : 0;
_events.ScheduleEvent(EVENT_MOVE_POINT, 1ms);
};
SpellScript* GetSpellScript() const override
void UpdateAI(uint32 diff) override
{
return new spell_storms_edge_SpellScript();
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_MOVE_POINT:
me->GetMotionMaster()->MovePoint(_nextPointId + 1, ErtansVortexPoints[_nextPointId]);
break;
default:
break;
}
}
}
private:
EventMap _events;
uint32 _nextPointId;
};
class spell_ertan_storms_edge : public SpellScript
{
PrepareSpellScript(spell_ertan_storms_edge);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_STORMS_EDGE_TRIGGERED_1,
SPELL_STORMS_EDGE_SCRIPT
});
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
Unit* target = GetHitUnit();
Unit* caster = GetCaster();
if (!caster)
return;
if (GetSpellInfo()->Id == SPELL_STORMS_EDGE_TRIGGERED_1)
{
if (caster->GetExactDist2d(target) > GetEffectValue())
target->CastSpell(target, SPELL_STORMS_EDGE_SCRIPT, true);
}
else
target->CastSpell(target, SPELL_STORMS_EDGE_SCRIPT, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_ertan_storms_edge::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 86299 - Storm's Edge (targets closest Ertan's Vortex and makes it cast 86309 on caster)
class spell_storms_edge_script : public SpellScriptLoader
class spell_ertan_storms_edge_script : public SpellScript
{
public:
spell_storms_edge_script() : SpellScriptLoader("spell_storms_edge_script") { }
PrepareSpellScript(spell_ertan_storms_edge_script);
class spell_storms_edge_script_SpellScript : public SpellScript
void HandleScript(SpellEffIndex /*effIndex*/)
{
PrepareSpellScript(spell_storms_edge_script_SpellScript);
if (Unit* caster = GetCaster())
GetHitUnit()->CastSpell(caster, uint32(GetEffectValue()), true);
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastSpell(GetCaster(), uint32(GetEffectValue()), true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_storms_edge_script_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_storms_edge_script_SpellScript();
OnEffectHitTarget += SpellEffectFn(spell_ertan_storms_edge_script::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_boss_grand_vizier_ertan()
{
new boss_grand_vizier_ertan();
new npc_ertans_vortex();
new spell_storms_edge();
new spell_storms_edge_script();
RegisterVortexPinnacleCreatureAI(boss_grand_vizier_ertan);
RegisterVortexPinnacleCreatureAI(npc_ertan_ertans_vortex);
RegisterSpellScript(spell_ertan_storms_edge);
RegisterSpellScript(spell_ertan_storms_edge_script);
}

View File

@@ -85,9 +85,9 @@ Position const SecondPrismGroundingFieldPoints[PrismGroundingFieldPoints] =
ObjectData const creatureData[] =
{
{ NPC_GRAND_VIZIER_ERTAN, DATA_GRAND_VIZIER_ERTAN },
{ NPC_ALTAIRUS, DATA_ALTAIRUS },
{ NPC_ASAAD, DATA_ASAAD },
{ BOSS_GRAND_VIZIER_ERTAN, DATA_GRAND_VIZIER_ERTAN },
{ BOSS_ALTAIRUS, DATA_ALTAIRUS },
{ BOSS_ASAAD, DATA_ASAAD },
{ 0, 0 } // END
};

View File

@@ -145,7 +145,7 @@ public:
void IsSummonedBy(Unit* summoner) override
{
if (Creature* creature = summoner->ToCreature())
ertan = (creature->GetEntry() == NPC_GRAND_VIZIER_ERTAN);
ertan = (creature->GetEntry() == BOSS_GRAND_VIZIER_ERTAN);
}
void MoveInLineOfSight(Unit* who) override

View File

@@ -48,12 +48,16 @@ enum DataTypes
DATA_SLIPSTREAM_11,
};
enum Misc
enum VPCreatureIds
{
// Bosses
NPC_GRAND_VIZIER_ERTAN = 43878,
NPC_ALTAIRUS = 43873,
NPC_ASAAD = 43875,
BOSS_GRAND_VIZIER_ERTAN = 43878,
BOSS_ALTAIRUS = 43873,
BOSS_ASAAD = 43875,
// Encounter Related Data
/*Grandvizier Ertan*/
NPC_ERTANS_VORTEX = 46007,
NPC_INVISIBLE_STALKER = 42844,
NPC_AIR_CURRENT = 47305,