Scripts/Instance: The Vortex Pinnacle

By Mihapro
This commit is contained in:
Aokromes
2016-07-02 16:06:29 +02:00
parent 17a50fe8ed
commit dc11f9fdd5
8 changed files with 3161 additions and 0 deletions

View File

@@ -0,0 +1,406 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "Player.h"
#include "vortex_pinnacle.h"
enum Spells
{
SPELL_CALL_THE_WIND = 88276, // targets 47305 in hook
SPELL_CHILLING_BREATH = 88322,
// Invisible Stalker
SPELL_CALL_THE_WIND_CHANNEL = 88772, // visual channeling targeting Air Current
// Air Current
SPELL_CALL_THE_WIND_AURA = 88244, // periodically triggers upwind
SPELL_UPWIND_OF_ALTAIRUS = 88282,
SPELL_DOWNWIND_OF_ALTAIRUS = 88286,
// Twister
SPELL_TWISTER_AURA = 88313,
};
enum NPCs
{
NPC_INVISIBLE_STALKER = 42844,
NPC_AIR_CURRENT = 47305,
NPC_TWISTER = 47342,
};
enum Texts
{
SAY_CALL_THE_WIND = 0,
};
enum Events
{
EVENT_NONE,
EVENT_CALL_THE_WIND,
EVENT_CHILLING_BREATH,
// Air Current
EVENT_SET_FACING,
EVENT_CAST_VISUAL,
// Twister
EVENT_MOVE_RANDOM,
};
enum Actions
{
ACTION_CALL_THE_WIND,
};
enum Points
{
POINT_RANDOM,
POINT_TWISTER_MAX = 24,
};
const Position InvisibleStalkerPos = { -1216.12f, 64.026f, 734.2573f };
const Position TwisterSpawnPoints[POINT_TWISTER_MAX] = {
{ -1226.936f, 58.03993f, 734.2574f },
{ -1250.604f, 78.47916f, 729.8842f },
{ -1255.609f, 63.03125f, 729.05f },
{ -1235.368f, 85.2691f, 732.747f },
{ -1245.059f, 61.33333f, 732.6014f },
{ -1237.84f, 72.69965f, 734.2705f },
{ -1190.684f, 69.16666f, 734.2564f },
{ -1194.172f, 54.2066f, 734.2574f },
{ -1215.405f, 65.88541f, 734.2574f },
{ -1236.722f, 48.6632f, 734.2571f },
{ -1193.104f, 82.77431f, 737.7465f },
{ -1210.278f, 80.68056f, 734.2574f },
{ -1202.799f, 68.46702f, 734.2574f },
{ -1224.179f, 76.04688f, 734.2574f },
{ -1244.069f, 92.11979f, 729.0458f },
{ -1211.163f, 53.77778f, 734.2574f },
{ -1198.332f, 106.1181f, 740.7894f },
{ -1203.602f, 93.05209f, 738.5089f },
{ -1242.745f, 37.7257f, 734.257f },
{ -1219.642f, 93.82291f, 737.8855f },
{ -1223.229f, 40.89063f, 734.2574f },
{ -1211.016f, 105.4375f, 740.8424f },
{ -1189.568f, 95.77604f, 740.8668f },
{ -1204.863f, 40.49826f, 734.2564f },
};
// TO-DO:
// - Fix hovering with disabled gravity. Altairus falls down every time position is updated.
// - Add argument to MoveRandom() to manually set i_nextMoveTime in "RandomMovementGenerator.h". This npc needs i_nextMoveTime = 1000.
class boss_altairus : public CreatureScript
{
public:
boss_altairus() : CreatureScript("boss_altairus") { }
struct boss_altairusAI : public BossAI
{
boss_altairusAI(Creature* creature) : BossAI(creature, DATA_ALTAIRUS)
{
//me->SetHover(true);
//me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
}
void Reset() override
{
_Reset();
events.ScheduleEvent(EVENT_CALL_THE_WIND, 6000);
events.ScheduleEvent(EVENT_CHILLING_BREATH, 15000);
}
void EnterCombat(Unit* /*target*/) override
{
_EnterCombat();
me->SummonCreature(NPC_INVISIBLE_STALKER, InvisibleStalkerPos);
if (IsHeroic())
for (int8 i = 0; i < POINT_TWISTER_MAX; i++)
if (Creature* twister = me->SummonCreature(NPC_TWISTER, TwisterSpawnPoints[i]))
twister->GetMotionMaster()->MoveRandom(10.0f);
}
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_CALL_THE_WIND:
DoCast(me, SPELL_CALL_THE_WIND);
Talk(SAY_CALL_THE_WIND);
events.ScheduleEvent(EVENT_CALL_THE_WIND, 20500);
break;
case EVENT_CHILLING_BREATH:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(target, SPELL_CHILLING_BREATH);
events.ScheduleEvent(EVENT_CHILLING_BREATH, 13000);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_altairusAI>(creature);
}
};
// 47305 - Air Current
class npc_air_current : public CreatureScript
{
public:
npc_air_current() : CreatureScript("npc_air_current") { }
struct npc_air_currentAI : public ScriptedAI
{
npc_air_currentAI(Creature* creature) : ScriptedAI(creature)
{
me->SetDisableGravity(true);
}
void SpellHit(Unit* /*unit*/, const SpellInfo* spellInfo) override
{
if (spellInfo->Id != SPELL_CALL_THE_WIND)
return;
DoCast(me, SPELL_CALL_THE_WIND_AURA);
events.ScheduleEvent(EVENT_SET_FACING, 400);
events.ScheduleEvent(EVENT_CAST_VISUAL, 1600);
}
void UpdateAI(uint32 diff) override
{
if (events.Empty())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SET_FACING:
if (Creature* invisibleStalker = me->FindNearestCreature(NPC_INVISIBLE_STALKER, 100.0f))
{
invisibleStalker->CastStop();
invisibleStalker->SetFacingToObject(me);
}
break;
case EVENT_CAST_VISUAL:
if (Creature* invisibleStalker = me->FindNearestCreature(NPC_INVISIBLE_STALKER, 100.0f))
invisibleStalker->CastSpell(me, SPELL_CALL_THE_WIND_CHANNEL);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_air_currentAI>(creature);
}
};
// 88276 - Call The Wind
class spell_call_the_wind : public SpellScriptLoader
{
public:
spell_call_the_wind() : SpellScriptLoader("spell_call_the_wind") { }
class spell_call_the_wind_SpellScript : public SpellScript
{
PrepareSpellScript(spell_call_the_wind_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_CALL_THE_WIND_AURA))
return false;
return true;
}
void FilterTargets(std::list<WorldObject*>& targets)
{
if (targets.empty())
return;
targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_CALL_THE_WIND_AURA));
Trinity::Containers::RandomResizeList(targets, 1);
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_CALL_THE_WIND_AURA);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_call_the_wind_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
OnEffectHitTarget += SpellEffectFn(spell_call_the_wind_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_call_the_wind_SpellScript();
}
};
// 88282 - Upwind of Altairus
class spell_upwind_of_altairus : public SpellScriptLoader
{
public:
spell_upwind_of_altairus() : SpellScriptLoader("spell_upwind_of_altairus") { }
class spell_upwind_of_altairus_SpellScript : public SpellScript
{
PrepareSpellScript(spell_upwind_of_altairus_SpellScript);
void GetDistance()
{
Unit* caster = GetCaster();
if (InstanceScript* instance = caster->GetInstanceScript())
if (Creature* altairus = instance->GetCreature(DATA_ALTAIRUS))
upwindDistance = caster->GetExactDist(altairus);
}
void CheckDistance(SpellEffIndex /*effIndex*/)
{
Unit* target = GetHitUnit();
if (GetCaster()->GetExactDist(target) < upwindDistance)
{
// Upwind of Altairus (applied by default effects)
if (target->HasAura(SPELL_DOWNWIND_OF_ALTAIRUS))
target->RemoveAurasDueToSpell(SPELL_DOWNWIND_OF_ALTAIRUS);
}
else
{
// Downwind of Altairus
PreventHitDefaultEffect(EFFECT_0);
PreventHitDefaultEffect(EFFECT_1);
if (target->HasAura(SPELL_UPWIND_OF_ALTAIRUS))
target->RemoveAurasDueToSpell(SPELL_UPWIND_OF_ALTAIRUS);
target->CastSpell(target, SPELL_DOWNWIND_OF_ALTAIRUS, true);
}
}
void Register() override
{
BeforeCast += SpellCastFn(spell_upwind_of_altairus_SpellScript::GetDistance);
OnEffectHitTarget += SpellEffectFn(spell_upwind_of_altairus_SpellScript::CheckDistance, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
}
private:
float upwindDistance;
};
SpellScript* GetSpellScript() const override
{
return new spell_upwind_of_altairus_SpellScript();
}
};
// 88772 - Call the Wind (visual, channeling on Air Current with Call The Wind aura)
class spell_call_the_wind_channel : public SpellScriptLoader
{
public:
spell_call_the_wind_channel() : SpellScriptLoader("spell_call_the_wind_channel") { }
class spell_call_the_wind_channel_AuraScript : public AuraScript
{
PrepareAuraScript(spell_call_the_wind_channel_AuraScript);
void RemoveCallTheWindAura(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Creature* creature = GetOwner()->ToCreature())
creature->RemoveAurasDueToSpell(SPELL_CALL_THE_WIND_AURA);
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_call_the_wind_channel_AuraScript::RemoveCallTheWindAura, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_call_the_wind_channel_AuraScript();
}
};
// 88322 - Chilling Breath
class spell_chilling_breath : public SpellScriptLoader
{
public:
spell_chilling_breath() : SpellScriptLoader("spell_chilling_breath") { }
class spell_chilling_breath_SpellScript : public SpellScript
{
PrepareSpellScript(spell_chilling_breath_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()));
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_chilling_breath_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_chilling_breath_SpellScript();
}
};
void AddSC_boss_altairus()
{
new boss_altairus();
new npc_air_current();
new spell_call_the_wind();
new spell_upwind_of_altairus();
new spell_call_the_wind_channel();
new spell_chilling_breath();
}

View File

@@ -0,0 +1,775 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "vortex_pinnacle.h"
enum Spells
{
SPELL_SUMMON_SKYFALL_STAR = 96260, // summons 52019
SPELL_CHAIN_LIGHTNING = 87622,
SPELL_SOTS_TARGETING = 86632,
SPELL_STATIC_CLING = 87618,
SPELL_UNSTABLE_GROUNDING_FIELD = 86911, // 20 sec channel, visual
SPELL_SUPREMACY_OF_THE_STORM_TELEPORT = 87328,
SPELL_SUPREMACY_OF_THE_STORM = 86930,
// Skyfall Star
SPELL_ARCANE_BARRAGE_AURA = 87845,
// Storm Target
SPELL_SOTS_SUMMON = 86658,
// Unstable Grounding Field
SPELL_SOTS_TRIGGER = 86926,
SPELL_STORM_RUNE_BEAM_AA = 86981,
SPELL_STORM_RUNE_BEAM_A = 86921,
SPELL_STORM_RUNE_BEAM_B = 86923,
SPELL_STORM_RUNE_BEAM_C = 86925,
SPELL_STORM_SUMMON_GROUNDING_FIELD = 87518,
// Grounding Field
SPELL_GROUNDING_FIELD_VISUAL_BEAMS = 87517,
};
enum NPCs
{
NPC_SKYFALL_STAR = 52019,
NPC_STORM_TARGET = 46387,
NPC_UNSTABLE_GROUNDING_FIELD = 46492,
};
enum Texts
{
SAY_AGGRO = 0,
SAY_SOTS_EMOTE = 1,
SAY_SOTS = 2,
SAY_DEATH = 3,
};
enum Actions
{
ACTION_NONE,
ACTION_SOTS_TARGET,
ACTION_SUPREMACY_OF_THE_STORM,
};
enum Events
{
EVENT_NONE,
EVENT_SUMMON_SKYFALL_STAR,
EVENT_CHAIN_LIGHTNING,
EVENT_STATIC_CLING,
EVENT_SOTS,
EVENT_SOTS_START,
EVENT_SOTS_END,
EVENT_ATTACK,
// Storm Target
EVENT_SOTS_SUMMON,
// Unstable Grounding Field npc
EVENT_STORM_ASSAD_CHANNEL,
EVENT_STORM_RUNE_BEAM_AA,
EVENT_STORM_MOVE_B,
EVENT_STORM_MOVE_C,
EVENT_STORM_MOVE_A,
EVENT_STORM_ASAAD_TELEPORT,
// Grounding Field npc
EVENT_GROUNDING_FIELD_VISUAL_BEAMS,
};
enum Points
{
POINT_STORM_A,
POINT_STORM_B,
POINT_STORM_C,
};
uint32 const StormTargetPositions = 39;
Position const StormTargetPositionData[StormTargetPositions] =
{
{ -633.771f, 490.976f, 646.7143f, 3.141593f }, // 56889
{ -625.688f, 501.934f, 646.7143f, 3.141593f }, // 56890
{ -620.226f, 490.892f, 646.7143f, 3.141593f }, // 56891
{ -649.906f, 494.905f, 646.7143f, 3.141593f }, // 56892
{ -643.214f, 503.953f, 646.7143f, 3.141593f }, // 56893
{ -640.542f, 487.474f, 646.7143f, 3.141593f }, // 56894
{ -637.839f, 516.186f, 646.7143f, 1.099557f }, // 56895
{ -634.068f, 507.51f, 646.7143f, 1.099557f }, // 56896
{ -650.894f, 509.323f, 646.7143f, 1.099557f }, // 56897
{ -637.01f, 530.09f, 646.7143f, 1.099557f }, // 56898
{ -632.167f, 521.153f, 646.7143f, 1.099557f }, // 56899
{ -646.939f, 519.566f, 646.7143f, 1.099557f }, // 56900
{ -628.512f, 516.988f, 646.7143f, 1.099557f }, // 56901
{ -622.184f, 507.908f, 646.7143f, 1.099557f }, // 56902
{ -633.148f, 499.762f, 646.7143f, 1.099557f }, // 56903
{ -615.528f, 515.944f, 646.7143f, 1.099557f }, // 56904
{ -609.41f, 504.675f, 646.7143f, 1.099557f }, // 56905
{ -618.748f, 501.946f, 646.7143f, 1.099557f }, // 56906
{ -600.986f, 522.576f, 646.7143f, 1.099557f }, // 56907
{ -594.96f, 507.582f, 646.7143f, 1.099557f }, // 56908
{ -605.094f, 509.141f, 646.7143f, 1.099557f }, // 56909
{ -617.269f, 521.168f, 646.7143f, 0.0f }, // 56910
{ -606.75f, 530.002f, 646.7143f, 0.0f }, // 56911
{ -608.832f, 515.175f, 646.7143f, 0.0f }, // 56912
{ -627.957f, 529.927f, 646.7143f, 0.0f }, // 56913
{ -616.997f, 530.564f, 646.7143f, 0.0f }, // 56914
{ -621.91f, 517.644f, 646.7143f, 0.0f }, // 56915
{ -604.839f, 485.186f, 646.7143f, 3.141593f }, // 56916
{ -616.885f, 496.186f, 646.7143f, 3.141593f }, // 56917
{ -606.833f, 500.078f, 646.7143f, 3.141593f }, // 56918
{ -600.387f, 482.604f, 646.7143f, 3.141593f }, // 56919
{ -602.899f, 497.245f, 646.7143f, 3.141593f }, // 56920
{ -592.599f, 500.392f, 646.7143f, 3.141593f }, // 56921
{ -622.946f, 483.113f, 646.7143f, 3.141593f }, // 56922
{ -613.104f, 488.776f, 646.7143f, 3.141593f }, // 56923
{ -606.915f, 477.097f, 646.7143f, 3.141593f }, // 56924
{ -640.717f, 480.623f, 646.7143f, 3.141593f }, // 56925
{ -627.049f, 486.917f, 646.7143f, 3.141593f }, // 56926
{ -623.059f, 476.104f, 646.7143f, 3.141593f }, // 56927
};
class boss_asaad : public CreatureScript
{
public:
boss_asaad() : CreatureScript("boss_asaad") { }
struct boss_asaadAI : public BossAI
{
boss_asaadAI(Creature* creature) : BossAI(creature, DATA_ASAAD) { }
void Reset() override
{
_Reset();
me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(EVENT_SUMMON_SKYFALL_STAR, 11000);
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 14500);
events.ScheduleEvent(EVENT_SOTS, 18000);
if (IsHeroic())
events.ScheduleEvent(EVENT_STATIC_CLING, 10800);
}
void EnterCombat(Unit* /*target*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
// Spawn Storm Targets
for (uint32 i = 0; i < StormTargetPositions; i++)
if (Creature* stormTarget = me->SummonCreature(NPC_STORM_TARGET, StormTargetPositionData[i]))
stormTargetGUIDs.push_back(stormTarget->GetGUID());
}
void JustSummoned(Creature* creature) override
{
if (creature->GetEntry() == NPC_SKYFALL_STAR)
{
creature->SetReactState(REACT_PASSIVE);
creature->SetInCombatWithZone();
creature->CastSpell(creature, SPELL_ARCANE_BARRAGE_AURA);
}
BossAI::JustSummoned(creature);
}
void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) override
{
if (spellInfo->Id != SPELL_SOTS_TARGETING || target->GetEntry() != NPC_STORM_TARGET)
return;
stormTargetA = target->ToCreature();
for (uint32 i = 0; i < StormTargetPositions; i++)
{
if (stormTargetGUIDs[i] != target->GetGUID())
continue;
stormTargetB = ObjectAccessor::GetCreature(*me, stormTargetGUIDs[i % 3 == 0 ? i + 1 : (i % 3 == 1 ? i - 1 : i - 2)]);
stormTargetC = ObjectAccessor::GetCreature(*me, stormTargetGUIDs[i % 3 == 0 ? i + 2 : (i % 3 == 1 ? i + 1 : i - 1)]);
ASSERT(stormTargetB);
ASSERT(stormTargetC);
break;
}
}
void DoAction(int32 action) override
{
if (action != ACTION_SUPREMACY_OF_THE_STORM)
return;
me->CastStop();
me->SetDisableGravity(true);
DoCast(me, SPELL_SUPREMACY_OF_THE_STORM_TELEPORT);
DoCast(me, SPELL_SUPREMACY_OF_THE_STORM);
events.ScheduleEvent(EVENT_SOTS_END, 6000);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
_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_STATIC_CLING:
DoCast(me, SPELL_STATIC_CLING);
events.ScheduleEvent(EVENT_STATIC_CLING, 16000);
break;
case EVENT_SUMMON_SKYFALL_STAR:
DoCast(me, SPELL_SUMMON_SKYFALL_STAR);
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 14500);
break;
case EVENT_CHAIN_LIGHTNING:
DoCast(me, SPELL_CHAIN_LIGHTNING);
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 14500);
break;
case EVENT_SOTS:
Talk(SAY_SOTS_EMOTE);
events.Reset();
events.ScheduleEvent(EVENT_SOTS_START, 200);
events.ScheduleEvent(EVENT_SOTS, 45800);
break;
case EVENT_SOTS_START:
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
Talk(SAY_SOTS);
DoCast(me, SPELL_SOTS_TARGETING);
break;
case EVENT_SOTS_END:
ResetStormTargets();
me->SetDisableGravity(false);
events.ScheduleEvent(EVENT_ATTACK, 2000);
break;
case EVENT_ATTACK:
me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 100);
events.ScheduleEvent(EVENT_STATIC_CLING, 2000);
events.ScheduleEvent(EVENT_SUMMON_SKYFALL_STAR, 3500);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
Creature* GetSelectedStormTarget(uint32 point)
{
if (point == POINT_STORM_A)
return stormTargetA;
if (point == POINT_STORM_B)
return stormTargetB;
if (point == POINT_STORM_C)
return stormTargetC;
return NULL;
}
Position GetTriangleCenterPosition()
{
Position pos;
pos.m_positionX = (stormTargetA->GetPositionX() + stormTargetB->GetPositionX() + stormTargetC->GetPositionX()) / 3;
pos.m_positionY = (stormTargetA->GetPositionY() + stormTargetB->GetPositionY() + stormTargetC->GetPositionY()) / 3;
pos.m_positionZ = stormTargetA->GetPositionZ() + 8.0f;
return pos;
}
void ResetStormTargets()
{
stormTargetA->CastStop();
stormTargetB->CastStop();
stormTargetC->CastStop();
}
private:
GuidVector stormTargetGUIDs;
Creature* stormTargetA;
Creature* stormTargetB;
Creature* stormTargetC;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_asaadAI>(creature);
}
};
typedef boss_asaad::boss_asaadAI AsaadAI;
// 46387 - Storm Target
class npc_storm_target : public CreatureScript
{
public:
npc_storm_target() : CreatureScript("npc_storm_target") { }
struct npc_storm_targetAI : public ScriptedAI
{
npc_storm_targetAI(Creature* creature) : ScriptedAI(creature) { }
void DoAction(int32 action) override
{
if (action != ACTION_SOTS_TARGET)
return;
events.ScheduleEvent(EVENT_SOTS_SUMMON, 400);
}
void JustSummoned(Creature* creature) override
{
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* asaad = instance->GetCreature(DATA_ASAAD))
ENSURE_AI(AsaadAI, asaad->AI())->JustSummoned(creature);
}
void UpdateAI(uint32 diff) override
{
if (events.Empty())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SOTS_SUMMON:
DoCast(me, SPELL_SOTS_SUMMON);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_storm_targetAI>(creature);
}
};
// 46492 - Unstable Grounding Field
class npc_unstable_grounding_field : public CreatureScript
{
public:
npc_unstable_grounding_field() : CreatureScript("npc_unstable_grounding_field") { }
struct npc_unstable_grounding_fieldAI : public ScriptedAI
{
npc_unstable_grounding_fieldAI(Creature* creature) : ScriptedAI(creature)
{
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* asaad = instance->GetCreature(DATA_ASAAD))
asaadAI = CAST_AI(AsaadAI, asaad->AI());
me->SetWalk(true);
events.ScheduleEvent(EVENT_STORM_ASSAD_CHANNEL, 400);
}
void MovementInform(uint32 movementType, uint32 pointId) override
{
if (movementType != POINT_MOTION_TYPE)
return;
switch (pointId)
{
case POINT_STORM_B:
if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_B))
stormTargetB->CastSpell((Unit*)NULL, SPELL_STORM_RUNE_BEAM_A);
events.ScheduleEvent(EVENT_STORM_MOVE_C, 1200);
break;
case POINT_STORM_C:
if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_C))
stormTargetB->CastSpell((Unit*)NULL, SPELL_STORM_RUNE_BEAM_B);
events.ScheduleEvent(EVENT_STORM_MOVE_A, 1200);
break;
case POINT_STORM_A:
{
if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_A))
stormTargetB->CastSpell((Unit*)NULL, SPELL_STORM_RUNE_BEAM_C);
DoCast(me, SPELL_STORM_SUMMON_GROUNDING_FIELD);
Position pos = asaadAI->GetTriangleCenterPosition();
me->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), SPELL_STORM_SUMMON_GROUNDING_FIELD, true);
events.ScheduleEvent(EVENT_STORM_ASAAD_TELEPORT, 500);
break;
}
default:
break;
}
};
void UpdateAI(uint32 diff) override
{
if (events.Empty())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_STORM_ASSAD_CHANNEL:
DoCast(me, SPELL_SOTS_TRIGGER);
events.ScheduleEvent(EVENT_STORM_RUNE_BEAM_AA, 400);
break;
case EVENT_STORM_RUNE_BEAM_AA:
DoCast(me, SPELL_STORM_RUNE_BEAM_AA);
events.ScheduleEvent(EVENT_STORM_MOVE_B, 800);
break;
case EVENT_STORM_MOVE_B:
if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_B))
me->GetMotionMaster()->MovePoint(POINT_STORM_B, stormTargetB->GetPosition());
break;
case EVENT_STORM_MOVE_C:
DoCast(me, SPELL_STORM_RUNE_BEAM_B);
if (Creature* stormTargetC = asaadAI->GetSelectedStormTarget(POINT_STORM_C))
me->GetMotionMaster()->MovePoint(POINT_STORM_C, stormTargetC->GetPosition());
break;
case EVENT_STORM_MOVE_A:
me->CastStop();
DoCast(me, SPELL_STORM_RUNE_BEAM_C);
if (Creature* stormTargetA = asaadAI->GetSelectedStormTarget(POINT_STORM_A))
me->GetMotionMaster()->MovePoint(POINT_STORM_A, stormTargetA->GetPosition());
break;
case EVENT_STORM_ASAAD_TELEPORT:
asaadAI->DoAction(ACTION_SUPREMACY_OF_THE_STORM);
me->DespawnOrUnsummon(700);
break;
default:
break;
}
}
}
private:
AsaadAI* asaadAI;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_unstable_grounding_fieldAI>(creature);
}
};
// 47000 - Grounding Field
class npc_asaad_grounding_field : public CreatureScript
{
public:
npc_asaad_grounding_field() : CreatureScript("npc_asaad_grounding_field") { }
struct npc_asaad_grounding_fieldAI : public ScriptedAI
{
npc_asaad_grounding_fieldAI(Creature* creature) : ScriptedAI(creature)
{
me->SetDisableGravity(true);
events.ScheduleEvent(EVENT_GROUNDING_FIELD_VISUAL_BEAMS, 500);
}
void UpdateAI(uint32 diff) override
{
if (events.Empty())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_GROUNDING_FIELD_VISUAL_BEAMS:
DoCast(me, SPELL_GROUNDING_FIELD_VISUAL_BEAMS);
me->DespawnOrUnsummon(6000);
break;
default:
break;
}
}
}
private:
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_asaad_grounding_fieldAI>(creature);
}
};
// 86632 - SOTS Targeting
class spell_sots_targeting : public SpellScriptLoader
{
public:
spell_sots_targeting() : SpellScriptLoader("spell_sots_targeting") { }
class spell_sots_targeting_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sots_targeting_SpellScript);
void SelectRandom(std::list<WorldObject*>& targets)
{
Trinity::Containers::RandomResizeList(targets, 1);
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
if (Creature* creature = GetHitCreature())
creature->GetAI()->DoAction(ACTION_SOTS_TARGET);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sots_targeting_SpellScript::SelectRandom, EFFECT_0, TARGET_UNIT_DEST_AREA_ENTRY);
OnEffectHitTarget += SpellEffectFn(spell_sots_targeting_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sots_targeting_SpellScript();
}
};
// 86926 - SOTS Trigger (makes Asaad channel Unstable Grounding Field)
class spell_sots_trigger : public SpellScriptLoader
{
public:
spell_sots_trigger() : SpellScriptLoader("spell_sots_trigger") { }
class spell_sots_trigger_SpellScript : public SpellScript
{
PrepareSpellScript(spell_sots_trigger_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_UNSTABLE_GROUNDING_FIELD))
return false;
return true;
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_UNSTABLE_GROUNDING_FIELD, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_sots_trigger_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sots_trigger_SpellScript();
}
};
// 86981 - Storm Rune Beam AA
// 86921 - Storm Rune Beam A
// 86923 - Storm Rune Beam B
// 86925 - Storm Rune Beam C
class spell_storm_rune_beam : public SpellScriptLoader
{
public:
spell_storm_rune_beam() : SpellScriptLoader("spell_storm_rune_beam") { }
class spell_storm_rune_beam_SpellScript : public SpellScript
{
PrepareSpellScript(spell_storm_rune_beam_SpellScript);
void SetTarget(WorldObject*& target)
{
InstanceScript* instance = GetCaster()->GetInstanceScript();
if (!instance)
return;
Creature* asaad = instance->GetCreature(DATA_ASAAD);
if (!asaad)
return;
switch (GetSpellInfo()->Id)
{
case SPELL_STORM_RUNE_BEAM_AA:
case SPELL_STORM_RUNE_BEAM_A:
target = ENSURE_AI(AsaadAI, asaad->AI())->GetSelectedStormTarget(POINT_STORM_A);
break;
case SPELL_STORM_RUNE_BEAM_B:
target = ENSURE_AI(AsaadAI, asaad->AI())->GetSelectedStormTarget(POINT_STORM_B);
break;
case SPELL_STORM_RUNE_BEAM_C:
target = ENSURE_AI(AsaadAI, asaad->AI())->GetSelectedStormTarget(POINT_STORM_C);
break;
default:
break;
}
}
void Register() override
{
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_storm_rune_beam_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_storm_rune_beam_SpellScript();
}
};
// 87517 - Grounding Field Visual Beams
class spell_grounding_field_visual_beams : public SpellScriptLoader
{
public:
spell_grounding_field_visual_beams() : SpellScriptLoader("spell_grounding_field_visual_beams") { }
class spell_grounding_field_visual_beams_SpellScript : public SpellScript
{
PrepareSpellScript(spell_grounding_field_visual_beams_SpellScript);
void SetTargetA(WorldObject*& target)
{
target = GetStormTarget(POINT_STORM_A);
}
void SetTargetB(WorldObject*& target)
{
target = GetStormTarget(POINT_STORM_B);
}
void SetTargetC(WorldObject*& target)
{
target = GetStormTarget(POINT_STORM_C);
}
void Register() override
{
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_grounding_field_visual_beams_SpellScript::SetTargetA, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_grounding_field_visual_beams_SpellScript::SetTargetB, EFFECT_1, TARGET_UNIT_NEARBY_ENTRY);
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_grounding_field_visual_beams_SpellScript::SetTargetC, EFFECT_2, TARGET_UNIT_NEARBY_ENTRY);
}
private:
Creature* GetStormTarget(uint32 point)
{
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
if (Creature* asaad = instance->GetCreature(DATA_ASAAD))
return ENSURE_AI(AsaadAI, asaad->AI())->GetSelectedStormTarget(point);
return NULL;
}
};
SpellScript* GetSpellScript() const override
{
return new spell_grounding_field_visual_beams_SpellScript();
}
};
// 87553/93994 - Supremacy of the Storm (massive aoe damage)
class spell_supremacy_of_the_storm : public SpellScriptLoader
{
public:
spell_supremacy_of_the_storm() : SpellScriptLoader("spell_supremacy_of_the_storm") { }
class spell_supremacy_of_the_storm_SpellScript : public SpellScript
{
PrepareSpellScript(spell_supremacy_of_the_storm_SpellScript);
void FilterTargets(std::list<WorldObject*>& targets)
{
InstanceScript* instance = GetCaster()->GetInstanceScript();
if (!instance)
return;
Creature* asaad = instance->GetCreature(DATA_ASAAD);
if (!asaad)
return;
AsaadAI* asaadAI = CAST_AI(AsaadAI, asaad->AI());
if (Creature* stormTargetA = asaadAI->GetSelectedStormTarget(POINT_STORM_A))
if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_B))
if (Creature* stormTargetC = asaadAI->GetSelectedStormTarget(POINT_STORM_C))
targets.remove_if(TargetInTriangleCheck(false, stormTargetA->GetPosition(), stormTargetB->GetPosition(), stormTargetC->GetPosition()));
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_supremacy_of_the_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_supremacy_of_the_storm_SpellScript();
}
};
void AddSC_boss_asaad()
{
new boss_asaad();
new npc_storm_target();
new npc_unstable_grounding_field();
new npc_asaad_grounding_field();
new spell_sots_targeting();
new spell_sots_trigger();
new spell_storm_rune_beam();
new spell_grounding_field_visual_beams();
new spell_supremacy_of_the_storm();
}

View File

@@ -0,0 +1,337 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "Player.h"
#include "vortex_pinnacle.h"
enum Spells
{
SPELL_STORMS_EDGE_AURA = 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,
};
enum Texts
{
SAY_AGGRO = 0,
SAY_STORMS_EDGE = 1,
};
enum Actions
{
ACTION_STORMS_EDGE,
};
enum Events
{
EVENT_NONE,
EVENT_SUMMON_TEMPEST,
EVENT_STORMS_EDGE_SPAWN,
EVENT_STORMS_EDGE,
EVENT_STORMS_EDGE_AURA,
EVENT_STORMS_EDGE_END,
// Ertan's Vortex
EVENT_MOVE_POINT,
};
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,
};
const Position ErtansVortexPoints[POINT_ERTANS_VORTEX_MAX] =
{
{ -744.889f, 3.98611f, 635.6728f }, // South
{ -737.552f, 21.592f, 635.6728f }, // South-West
{ -719.802f, 28.8351f, 635.6728f }, // West
{ -702.144f, 21.9878f, 635.6728f }, // North-West
{ -694.911f, 4.16493f, 635.6728f }, // North
{ -702.212f, -13.6806f, 635.6728f }, // North-East
{ -719.934f, -20.9497f, 635.6728f }, // East
{ -737.649f, -13.5347f, 635.6728f }, // South-East
};
const Position ErtansVortexMiddlePoints[POINT_ERTANS_VORTEX_MAX] =
{
{ -724.3819f, 2.915083f, 635.6728f }, // South
{ -724.0161f, 6.648534f, 635.6728f }, // South-West
{ -721.1381f, 9.082433f, 635.6728f }, // West
{ -716.7177f, 8.423817f, 635.6728f }, // North-West
{ -714.6548f, 5.146466f, 635.6728f }, // North
{ -715.2417f, 1.857746f, 635.6728f }, // North-East
{ -718.2345f, -0.4830246f, 635.6728f }, // East
{ -721.9816f, -0.05864143f, 635.6728f }, // South-East
};
class boss_grand_vizier_ertan : public CreatureScript
{
public:
boss_grand_vizier_ertan() : CreatureScript("boss_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 Reset() override
{
_Reset();
// Should have, but gets stuck in evade mode...
//me->AddUnitState(UNIT_STATE_ROOT);
events.ScheduleEvent(EVENT_STORMS_EDGE_SPAWN, 400);
events.ScheduleEvent(EVENT_STORMS_EDGE, 23000);
if (IsHeroic())
events.ScheduleEvent(EVENT_SUMMON_TEMPEST, 17000);
}
void EnterCombat(Unit* /*target*/) override
{
_EnterCombat();
SummonErtansVortexes();
DoCast(me, SPELL_STORMS_EDGE_AURA);
Talk(SAY_AGGRO);
}
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);
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 GetInstanceAI<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 ScriptedAI
{
npc_ertans_vortexAI(Creature* creature) : ScriptedAI(creature)
{
currentPointId = 0;
DoCast(me, SPELL_CYCLONE_SHIELD);
}
void DoAction(int32 action) override
{
if (action != ACTION_STORMS_EDGE)
return;
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
{
if (events.Empty())
return;
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
{
return GetInstanceAI<npc_ertans_vortexAI>(creature);
}
};
// 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
{
public:
spell_storms_edge() : SpellScriptLoader("spell_storms_edge") { }
class spell_storms_edge_SpellScript : public SpellScript
{
PrepareSpellScript(spell_storms_edge_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_STORMS_EDGE_SCRIPT, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_storms_edge_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_storms_edge_SpellScript();
}
};
// 86299 - Storm's Edge (targets closest Ertan's Vortex and makes it cast 86309 on caster)
class spell_storms_edge_script : public SpellScriptLoader
{
public:
spell_storms_edge_script() : SpellScriptLoader("spell_storms_edge_script") { }
class spell_storms_edge_script_SpellScript : public SpellScript
{
PrepareSpellScript(spell_storms_edge_script_SpellScript);
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
{
return new spell_storms_edge_script_SpellScript();
}
};
void AddSC_boss_grand_vizier_ertan()
{
new boss_grand_vizier_ertan();
new npc_ertans_vortex();
new spell_storms_edge();
new spell_storms_edge_script();
}

View File

@@ -0,0 +1,230 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "Player.h"
#include "CreatureGroups.h"
#include "Vehicle.h"
#include "InstanceScript.h"
#include "vortex_pinnacle.h"
#define MAX_ENCOUNTER 3
/* The Vortex Pinnacle encounters:
0 - Grand Vizier Ertan
1 - Altairus
2 - Asaad
*/
struct Slipstream
{
uint32 entry;
uint32 vehicleId;
Position position;
uint32 data;
uint32 bossData; // boss that has to die/be dead for Slipstream to spawn
};
Slipstream const SlipstreamData[Slipstreams] =
{
// Grand Vizier Ertan Slipstreams
{ NPC_SLIPSTREAM, 1111, { -775.517f, -70.9323f, 640.3123f, 0.0f }, DATA_SLIPSTREAM_1, DATA_GRAND_VIZIER_ERTAN },
{ NPC_SLIPSTREAM, 1112, { -848.227f, -68.724f, 654.2203f, 0.0f }, DATA_SLIPSTREAM_2, DATA_GRAND_VIZIER_ERTAN },
{ NPC_SLIPSTREAM, 1113, { -844.885f, -205.135f, 660.7083f, 0.0f }, DATA_SLIPSTREAM_3, DATA_GRAND_VIZIER_ERTAN },
// Grand Vizier Ertan Slipstream Landing Zone
{ NPC_SLIPSTREAM_LANDING_ZONE, 1114, { -906.08f, -176.514f, 664.5053f, 2.86234f }, 0, DATA_GRAND_VIZIER_ERTAN },
// Altairus Slipstreams
{ NPC_SLIPSTREAM, 1111, { -1190.88f, 125.203f, 737.6243f, 0.0f }, DATA_SLIPSTREAM_4, DATA_ALTAIRUS },
{ NPC_SLIPSTREAM, 1112, { -1138.55f, 178.524f, 711.4943f, 0.0f }, DATA_SLIPSTREAM_5, DATA_ALTAIRUS },
{ NPC_SLIPSTREAM, 1149, { -1245.21f, 230.986f, 690.6083f, 0.0f }, DATA_SLIPSTREAM_6, DATA_ALTAIRUS },
{ NPC_SLIPSTREAM, 1150, { -1282.07f, 344.856f, 660.9873f, 0.0f }, DATA_SLIPSTREAM_7, DATA_ALTAIRUS },
{ NPC_SLIPSTREAM, 1113, { -1229.64f, 412.26f, 641.2933f, 0.0f }, DATA_SLIPSTREAM_8, DATA_ALTAIRUS },
// Altairus Slipstream Landing Zone
{ NPC_SLIPSTREAM_LANDING_ZONE, 1114, { -1193.67f, 472.835f, 634.8653f, 0.5061455f }, 0, DATA_ALTAIRUS },
// Asaad Slipstream
{ NPC_SLIPSTREAM, 1551, { -746.9566f, 529.1406f, 644.8316f, 0.0f }, DATA_SLIPSTREAM_9, DATA_ASAAD },
// Entrance Slipstreams
{ NPC_SLIPSTREAM, 1305, { -310.4583f, -29.74479f, 625.0833f, 0.0f }, DATA_SLIPSTREAM_10, DATA_GRAND_VIZIER_ERTAN },
{ NPC_SLIPSTREAM, 1306, { -382.441f, 42.31597f, 625.0833f, 0.0f }, DATA_SLIPSTREAM_11, DATA_ALTAIRUS },
};
Position const SouthZephyrSummonLocation = { -1070.639f, 432.2814f, 647.0389f, 6.15166f };
Position const NorthZephyrSummonLocation = { -781.4438f, 491.1446f, 698.0991f, 0.3193802f };
Position const FirstPrismGroundingFieldTop = { -1008.997f, 474.3663f, 708.1033f, 0.0f };
Position const FirstPrismGroundingFieldPoints[PrismGroundingFieldPoints] =
{
{ -990.934f, 466.7552f, 700.0436f, 0.0f },
{ -1021.677f, 461.6684f, 700.1023f, 0.0f },
{ -1016.434f, 492.8455f, 700.0325f, 0.0f },
};
Position const SecondPrismGroundingFieldTop = { -829.7674f, 477.9531f, 708.1063f, 4.328416f };
Position const SecondPrismGroundingFieldPoints[PrismGroundingFieldPoints] =
{
{ -851.3368f, 469.3629f, 700.0286f, 4.328416f },
{ -820.2327f, 468.5017f, 700.1062f, 4.328416f },
{ -821.4792f, 500.3004f, 700.0289f, 4.328416f },
};
ObjectData const creatureData[] =
{
{ NPC_ALTAIRUS, DATA_ALTAIRUS },
{ NPC_ASAAD, DATA_ASAAD },
{ 0, 0 }
};
class instance_vortex_pinnacle : public InstanceMapScript
{
public:
instance_vortex_pinnacle() : InstanceMapScript(SCScriptName, 657) { }
struct instance_vortex_pinnacle_InstanceScript : public InstanceScript
{
instance_vortex_pinnacle_InstanceScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(MAX_ENCOUNTER);
LoadObjectData(creatureData, nullptr);
CheckSlipstreams();
SummonGroundingFieldPrism(FirstPrismGroundingFieldTop, FirstPrismGroundingFieldPoints);
SummonGroundingFieldPrism(SecondPrismGroundingFieldTop, SecondPrismGroundingFieldPoints);
events.ScheduleEvent(EVENT_SUMMON_ZEPHYRS, 0);
}
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_HOWLING_GALE:
creature->SetReactState(REACT_PASSIVE);
break;
default:
break;
}
InstanceScript::OnCreatureCreate(creature);
}
bool SetBossState(uint32 type, EncounterState state) override
{
InstanceScript::SetBossState(type, state);
// Spawn Slipstreams
if (state == DONE)
SummonSlipstreams(type);
return true;
}
void Update(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SUMMON_ZEPHYRS: // Summon Zephyrs every 10 seconds. There is no sniff data about trigger npc or spells that would handle summoning.
if (TempSummon* zephyr = instance->SummonCreature(NPC_ZEPHYR, SouthZephyrSummonLocation))
zephyr->GetMotionMaster()->MovePath(PATH_ZEPHYR_SOUTH, false);
if (TempSummon* zephyr = instance->SummonCreature(NPC_ZEPHYR, NorthZephyrSummonLocation))
zephyr->GetMotionMaster()->MovePath(PATH_ZEPHYR_NORTH, false);
events.ScheduleEvent(EVENT_SUMMON_ZEPHYRS, 10000);
break;
default:
break;
}
}
}
private:
// Check which Slipstreams can be spawned on script init
void CheckSlipstreams()
{
if (GetBossState(DATA_GRAND_VIZIER_ERTAN) == DONE)
SummonSlipstreams(DATA_GRAND_VIZIER_ERTAN);
if (GetBossState(DATA_ALTAIRUS) == DONE)
SummonSlipstreams(DATA_ALTAIRUS);
if (GetBossState(DATA_ASAAD) == DONE)
SummonSlipstreams(DATA_ASAAD);
}
// Spawns Slipstreams belonging bossType
void SummonSlipstreams(uint32 bossType)
{
for (uint8 i = 0; i < Slipstreams; ++i)
{
if (SlipstreamData[i].bossData != bossType)
continue;
TempSummon* summon = instance->SummonCreature(SlipstreamData[i].entry, SlipstreamData[i].position);
if (!summon)
continue;
AddObject(summon, SlipstreamData[i].data, true);
if (SlipstreamData[i].data == DATA_SLIPSTREAM_1 || SlipstreamData[i].data == DATA_SLIPSTREAM_4 ||
SlipstreamData[i].data == DATA_SLIPSTREAM_10 || SlipstreamData[i].data == DATA_SLIPSTREAM_11)
{
summon->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, summon->GetPackGUID().size() + 4);
data << summon->GetPackGUID();
data << uint32(SlipstreamData[i].vehicleId);
summon->SendMessageToSet(&data, true);
}
}
// Spawns Grounding Field prism
void SummonGroundingFieldPrism(Position positionTop, const Position positionPoints[PrismGroundingFieldPoints])
{
// Spawn lower three grounding fields
TempSummon* points[PrismGroundingFieldPoints];
for (uint32 i = 0; i < PrismGroundingFieldPoints; i++)
points[i] = instance->SummonCreature(NPC_GROUNDING_FIELD, positionPoints[i]);
// If all three grounding fields spawned, cast beams and spawn the upper grounding field
if (points[0] && points[1] && points[2])
{
points[1]->CastSpell(points[0], SPELL_BEAM_A, true);
points[2]->CastSpell(points[1], SPELL_BEAM_B, true);
points[0]->CastSpell(points[2], SPELL_BEAM_C, true);
if (TempSummon* top = instance->SummonCreature(NPC_GROUNDING_FIELD, positionTop))
top->ToCreature()->GetAI()->DoAction(ACTION_GROUNDING_FIELD_TOP);
}
}
EventMap events;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_vortex_pinnacle_InstanceScript(map);
}
};
void AddSC_instance_vortex_pinnacle()
{
new instance_vortex_pinnacle();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEF_VORTEX_PINNACLE_H
#define DEF_VORTEX_PINNACLE_H
#define SCScriptName "instance_vortex_pinnacle"
#define DataHeader "VP"
#include "G3D/Vector3.h"
#include "G3D/Triangle.h"
#include "G3D/Plane.h"
#include "G3D/CollisionDetection.h"
uint32 const Slipstreams = 13;
uint32 const PrismGroundingFieldPoints = 3;
enum DataTypes
{
// Encounter States/Boss GUIDs
DATA_GRAND_VIZIER_ERTAN,
DATA_ALTAIRUS,
DATA_ASAAD,
// Additional Data
DATA_SLIPSTREAM,
DATA_SLIPSTREAM_1,
DATA_SLIPSTREAM_2,
DATA_SLIPSTREAM_3,
DATA_SLIPSTREAM_4,
DATA_SLIPSTREAM_5,
DATA_SLIPSTREAM_6,
DATA_SLIPSTREAM_7,
DATA_SLIPSTREAM_8,
DATA_SLIPSTREAM_9,
DATA_SLIPSTREAM_10,
DATA_SLIPSTREAM_11,
};
enum Misc
{
NPC_GRAND_VIZIER_ERTAN = 43878,
NPC_ALTAIRUS = 43873,
NPC_ASAAD = 43875,
NPC_SLIPSTREAM = 45455,
NPC_SLIPSTREAM_LANDING_ZONE = 45504,
NPC_HOWLING_GALE = 45572,
// Grounding Field
NPC_GROUNDING_FIELD = 47085,
SPELL_BEAM_A = 87721,
SPELL_BEAM_B = 87722,
SPELL_BEAM_C = 87723,
ACTION_GROUNDING_FIELD_TOP = 1,
// Zephyr
NPC_ZEPHYR = 45991,
EVENT_SUMMON_ZEPHYRS = 1,
PATH_ZEPHYR_SOUTH = 4599100,
PATH_ZEPHYR_NORTH = 4599101,
};
class TargetInTriangleCheck
{
public:
TargetInTriangleCheck(bool negate, Position positionA, Position positionB, Position positionC)
: negate(negate), positionA(positionA), positionB(positionB), positionC(positionC) { }
bool operator()(WorldObject* target) const
{
return negate != IsInTriangle(target);
}
private:
bool IsInTriangle(WorldObject* target) const
{
G3D::Triangle const triangle(PositionToVector3(positionA), PositionToVector3(positionB), PositionToVector3(positionC));
G3D::Vector3 const vector(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
float b[3];
return G3D::CollisionDetection::isPointInsideTriangle(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), triangle.normal(), vector, b, triangle.primaryAxis());
}
G3D::Vector3 PositionToVector3(Position const& position) const
{
return G3D::Vector3(position.GetPositionX(), position.GetPositionY(), position.GetPositionZ());
}
bool const negate;
Position const positionA;
Position const positionB;
Position const positionC;
};
#endif // DEF_VORTEX_PINNACLE_H