mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-25 22:56:24 +00:00
Merge branch 'master' into Playerbot
# Conflicts: # src/server/game/Entities/Player/Player.cpp # src/server/game/Entities/Player/Player.h # src/server/game/Entities/Unit/Unit.h
This commit is contained in:
@@ -40,7 +40,7 @@ public:
|
||||
static ChatCommandTable achievementCommandTable =
|
||||
{
|
||||
{ "add", HandleAchievementAddCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "checkall", HandleAchievementCheckAllCommand, SEC_ADMINISTRATOR, Console::No }
|
||||
{ "checkall", HandleAchievementCheckAllCommand, SEC_ADMINISTRATOR, Console::Yes }
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
@@ -63,17 +63,33 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleAchievementCheckAllCommand(ChatHandler* handler)
|
||||
static bool HandleAchievementCheckAllCommand(ChatHandler* handler, Optional<PlayerIdentifier> player)
|
||||
{
|
||||
Player* target = handler->getSelectedPlayer();
|
||||
if (!target)
|
||||
if (!player)
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
player = PlayerIdentifier::FromTarget(handler);
|
||||
}
|
||||
|
||||
if (!player)
|
||||
{
|
||||
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
target->CheckAllAchievementCriteria();
|
||||
if (player->IsConnected())
|
||||
{
|
||||
if (Player* target = player->GetConnectedPlayer())
|
||||
target->CheckAllAchievementCriteria();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt->SetData(0, uint16(AT_LOGIN_CHECK_ACHIEVS));
|
||||
stmt->SetData(1, player->GetGUID().GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -43,7 +43,8 @@ enum BWLEncounter
|
||||
DATA_NEFARIAN_TROOPS = 10,
|
||||
|
||||
// Doors
|
||||
DATA_GO_CHROMAGGUS_DOOR = 11
|
||||
DATA_GO_CHROMAGGUS_DOOR = 11,
|
||||
DATA_GO_CHROMAGGUS_DOOR_EXIT= 12
|
||||
};
|
||||
|
||||
enum BWLCreatureIds
|
||||
@@ -92,7 +93,8 @@ enum BWLGameObjectIds
|
||||
GO_PORTCULLIS_THREEDRAGONS = 179115,
|
||||
GO_CHROMAGGUS_LEVER = 179148,
|
||||
GO_PORTCULLIS_CHROMAGGUS = 179116,
|
||||
GO_PORTCULLIS_NEFARIAN = 179117,
|
||||
GO_PORTCULLIS_CHROMAGGUS_EXIT = 179117,
|
||||
GO_PORTCULLIS_NEFARIAN = 176966,
|
||||
GO_SUPPRESSION_DEVICE = 179784
|
||||
};
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
Acore::Containers::RandomResize(_breathSpells, 2);
|
||||
|
||||
// Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed.
|
||||
creature->SetReactState(REACT_PASSIVE);
|
||||
creature->SetImmuneToAll(true);
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
{
|
||||
_playerGUID = guid;
|
||||
// Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed.
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetImmuneToAll(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,9 @@ DoorData const doorData[] =
|
||||
{ GO_PORTCULLIS_RAZORGORE_ROOM, DATA_RAZORGORE_THE_UNTAMED, DOOR_TYPE_ROOM, }, // ID 176964 || GUID 75158
|
||||
{ GO_PORTCULLIS_VAELASTRASZ, DATA_VAELASTRAZ_THE_CORRUPT, DOOR_TYPE_PASSAGE }, // ID 175185 || GUID 7229
|
||||
{ GO_PORTCULLIS_BROODLORD, DATA_BROODLORD_LASHLAYER, DOOR_TYPE_PASSAGE }, // ID 179365 || GUID 75159
|
||||
{ GO_PORTCULLIS_NEFARIAN, DATA_CHROMAGGUS, DOOR_TYPE_PASSAGE }, // ID 179116 || GUID 75161
|
||||
{ GO_PORTCULLIS_NEFARIAN, DATA_NEFARIAN, DOOR_TYPE_ROOM }, // ID 179117 || GUID 75164
|
||||
{ GO_PORTCULLIS_CHROMAGGUS_EXIT,DATA_CHROMAGGUS, DOOR_TYPE_PASSAGE }, // ID 179117 || GUID 75164
|
||||
{ GO_PORTCULLIS_CHROMAGGUS_EXIT,DATA_NEFARIAN, DOOR_TYPE_ROOM }, // ID 179117 || GUID 75164
|
||||
{ GO_PORTCULLIS_NEFARIAN, DATA_NEFARIAN, DOOR_TYPE_ROOM }, // ID 176966
|
||||
{ 0, 0, DOOR_TYPE_ROOM } // END
|
||||
};
|
||||
|
||||
@@ -45,12 +46,13 @@ ObjectData const creatureData[] =
|
||||
{ NPC_GRETHOK, DATA_GRETHOK },
|
||||
{ NPC_NEFARIAN_TROOPS, DATA_NEFARIAN_TROOPS },
|
||||
{ NPC_VICTOR_NEFARIUS, DATA_LORD_VICTOR_NEFARIUS },
|
||||
{ NPC_CHROMAGGUS, DATA_CHROMAGGUS }
|
||||
{ NPC_CHROMAGGUS, DATA_CHROMAGGUS },
|
||||
};
|
||||
|
||||
ObjectData const objectData[] =
|
||||
{
|
||||
{ GO_PORTCULLIS_CHROMAGGUS, DATA_GO_CHROMAGGUS_DOOR }
|
||||
{ GO_PORTCULLIS_CHROMAGGUS, DATA_GO_CHROMAGGUS_DOOR },
|
||||
{ GO_PORTCULLIS_CHROMAGGUS_EXIT, DATA_GO_CHROMAGGUS_DOOR_EXIT }
|
||||
};
|
||||
|
||||
Position const SummonPosition[8] =
|
||||
|
||||
@@ -1220,33 +1220,6 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
class spell_q12779_an_end_to_all_things : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_q12779_an_end_to_all_things() : SpellScriptLoader("spell_q12779_an_end_to_all_things") { }
|
||||
|
||||
class spell_q12779_an_end_to_all_things_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q12779_an_end_to_all_things_SpellScript);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (GetHitUnit())
|
||||
GetHitUnit()->CastSpell(GetCaster(), GetEffectValue(), true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_q12779_an_end_to_all_things_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_q12779_an_end_to_all_things_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_the_scarlet_enclave_c2()
|
||||
{
|
||||
new npc_crusade_persuaded();
|
||||
@@ -1254,7 +1227,4 @@ void AddSC_the_scarlet_enclave_c2()
|
||||
new npc_koltira_deathweaver();
|
||||
new npc_high_inquisitor_valroth();
|
||||
new npc_a_special_surprise();
|
||||
|
||||
// Xinef: Should be in chapter III
|
||||
new spell_q12779_an_end_to_all_things();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
|
||||
class spell_q12779_an_end_to_all_things : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q12779_an_end_to_all_things);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (GetHitUnit())
|
||||
GetHitUnit()->CastSpell(GetCaster(), GetEffectValue(), true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_q12779_an_end_to_all_things::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_the_scarlet_enclave_c3()
|
||||
{
|
||||
RegisterSpellScript(spell_q12779_an_end_to_all_things);
|
||||
}
|
||||
@@ -168,18 +168,20 @@ class spell_pagles_point_cast : public SpellScript
|
||||
{
|
||||
if (InstanceScript* instanceScript = caster->GetInstanceScript())
|
||||
{
|
||||
if (!instanceScript->GetData(DATA_GAHZRANKA))
|
||||
if (!instanceScript->GetData(DATA_GAHZRANKA) && !caster->FindNearestCreature(NPC_GAHZRANKA, 50.0f))
|
||||
{
|
||||
caster->m_Events.AddEventAtOffset([caster]()
|
||||
{
|
||||
if (GameObject* lure = caster->SummonGameObject(GAMEOBJECT_MUDSKUNK_LURE, -11688.5f, -1737.74f, 10.409842f, 1.f, 0.f, 0.f, 0.f, 0.f, 30 * IN_MILLISECONDS))
|
||||
{
|
||||
caster->m_Events.AddEventAtOffset([caster, lure]()
|
||||
lure->DespawnOrUnsummon(5s);
|
||||
caster->m_Events.AddEventAtOffset([caster]()
|
||||
{
|
||||
if (lure)
|
||||
lure->DespawnOrUnsummon();
|
||||
caster->CastSpell(caster, SPELL_SPLASH, true);
|
||||
caster->SummonCreature(NPC_GAHZRANKA, -11688.5f, -1723.74f, -5.78f, 0.f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5 * DAY * IN_MILLISECONDS);
|
||||
if (!caster->FindNearestCreature(NPC_GAHZRANKA, 50.0f))
|
||||
{
|
||||
caster->CastSpell(caster, SPELL_SPLASH, true);
|
||||
caster->SummonCreature(NPC_GAHZRANKA, -11688.5f, -1723.74f, -5.78f, 0.f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5 * DAY * IN_MILLISECONDS);
|
||||
}
|
||||
}, 5s);
|
||||
}
|
||||
}, 2s);
|
||||
|
||||
@@ -719,11 +719,14 @@ public:
|
||||
{
|
||||
if (Unit* target = GetTarget())
|
||||
{
|
||||
if (Creature* caster = GetCaster()->ToCreature())
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (caster->IsAIEnabled)
|
||||
if (Creature* cCaster = caster->ToCreature())
|
||||
{
|
||||
caster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE);
|
||||
if (cCaster->IsAIEnabled)
|
||||
{
|
||||
cCaster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ void AddSC_instance_molten_core();
|
||||
void AddSC_the_scarlet_enclave(); //Scarlet Enclave
|
||||
void AddSC_the_scarlet_enclave_c1();
|
||||
void AddSC_the_scarlet_enclave_c2();
|
||||
void AddSC_the_scarlet_enclave_c3();
|
||||
void AddSC_the_scarlet_enclave_c5();
|
||||
void AddSC_instance_scarlet_monastery(); //Scarlet Monastery
|
||||
void AddSC_boss_kirtonos_the_herald();
|
||||
@@ -247,6 +248,7 @@ void AddEasternKingdomsScripts()
|
||||
AddSC_the_scarlet_enclave(); //Scarlet Enclave
|
||||
AddSC_the_scarlet_enclave_c1();
|
||||
AddSC_the_scarlet_enclave_c2();
|
||||
AddSC_the_scarlet_enclave_c3();
|
||||
AddSC_the_scarlet_enclave_c5();
|
||||
AddSC_instance_scarlet_monastery(); //Scarlet Monastery
|
||||
AddSC_boss_kirtonos_the_herald();
|
||||
|
||||
@@ -18,281 +18,427 @@
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "ruins_of_ahnqiraj.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_STINGER_SPRAY = 25749,
|
||||
SPELL_POISON_STINGER = 25748,
|
||||
SPELL_PARALYZE = 25725,
|
||||
SPELL_FRENZY = 8269,
|
||||
SPELL_LASH = 25852,
|
||||
SPELL_FEED = 25721
|
||||
SPELL_STINGER_SPRAY = 25749,
|
||||
SPELL_POISON_STINGER = 25748,
|
||||
SPELL_PARALYZE = 25725,
|
||||
SPELL_FRENZY = 8269,
|
||||
SPELL_LASH = 25852,
|
||||
SPELL_FEED = 25721,
|
||||
SPELL_THRASH = 3391,
|
||||
|
||||
// Server-side spells
|
||||
SPELL_SUMMON_LARVA_A = 26538,
|
||||
SPELL_SUMMON_LARVA_B = 26539,
|
||||
SPELL_LARVA_AGGRO_EFFECT = 25724, // Unknown purpose
|
||||
SPELL_LARVA_FEAR_EFFECT = 25726, // Unknown purpose
|
||||
SPELL_SUMMON_HIVEZARA_SWARMER = 25708,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_1 = 25709,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_2 = 25825,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_3 = 25826,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_4 = 25827,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_5 = 25828,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_TRIGGER = 25830,
|
||||
SPELL_HIVEZARA_SWARMER_START_LOOP = 25711,
|
||||
SPELL_HIVEZARA_SWARMER_LOOP_1 = 25833,
|
||||
SPELL_HIVEZARA_SWARMER_LOOP_2 = 25834,
|
||||
SPELL_HIVEZARA_SWARMER_LOOP_3 = 25835,
|
||||
SPELL_HIVEZARA_SWARMER_SWARM = 25844
|
||||
};
|
||||
|
||||
enum Events
|
||||
enum Misc
|
||||
{
|
||||
EVENT_STINGER_SPRAY = 1,
|
||||
EVENT_POISON_STINGER = 2,
|
||||
EVENT_SUMMON_SWARMER = 3,
|
||||
EVENT_SWARMER_ATTACK = 4,
|
||||
EVENT_PARALYZE = 5,
|
||||
EVENT_LASH = 6
|
||||
MAX_SWARMER_COUNT = 28,
|
||||
ACTION_SWARMER_SWARM = 1,
|
||||
};
|
||||
|
||||
enum Emotes
|
||||
{
|
||||
EMOTE_FRENZY = 0
|
||||
EMOTE_FRENZY = 0
|
||||
};
|
||||
|
||||
enum Phases
|
||||
{
|
||||
PHASE_AIR = 0,
|
||||
PHASE_GROUND = 1
|
||||
PHASE_AIR = 0,
|
||||
PHASE_GROUND = 1
|
||||
};
|
||||
|
||||
enum Points
|
||||
{
|
||||
POINT_AIR = 0,
|
||||
POINT_GROUND = 1,
|
||||
POINT_PARALYZE = 2
|
||||
POINT_AIR = 0,
|
||||
POINT_GROUND = 2,
|
||||
POINT_PARALYZE = 2
|
||||
};
|
||||
|
||||
const Position AyamissAirPos = { -9689.292f, 1547.912f, 48.02729f, 0.0f };
|
||||
const Position AltarPos = { -9717.18f, 1517.72f, 27.4677f, 0.0f };
|
||||
/// @todo These below are probably incorrect, taken from SD2
|
||||
const Position SwarmerPos = { -9647.352f, 1578.062f, 55.32f, 0.0f };
|
||||
const Position LarvaPos[2] =
|
||||
{
|
||||
{ -9674.4707f, 1528.4133f, 22.457f, 0.0f },
|
||||
{ -9701.6005f, 1566.9993f, 24.118f, 0.0f }
|
||||
};
|
||||
const Position AyamissAirPos = { -9689.292f, 1547.912f, 48.02729f, 0.0f };
|
||||
const Position AltarPos = { -9717.18f, 1517.72f, 27.4677f, 0.0f };
|
||||
|
||||
class boss_ayamiss : public CreatureScript
|
||||
struct boss_ayamiss : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_ayamiss() : CreatureScript("boss_ayamiss") { }
|
||||
boss_ayamiss(Creature* creature) : BossAI(creature, DATA_AYAMISS) { homePos = creature->GetHomePosition(); }
|
||||
|
||||
struct boss_ayamissAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_ayamissAI(Creature* creature) : BossAI(creature, DATA_AYAMISS) {}
|
||||
BossAI::Reset();
|
||||
_phase = PHASE_AIR;
|
||||
_enraged = false;
|
||||
SetCombatMovement(false);
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void JustSummoned(Creature* who) override
|
||||
{
|
||||
switch (who->GetEntry())
|
||||
{
|
||||
_Reset();
|
||||
_phase = PHASE_AIR;
|
||||
_enraged = false;
|
||||
SetCombatMovement(false);
|
||||
case NPC_HIVEZARA_SWARMER:
|
||||
who->CastSpell(who, SPELL_HIVEZARA_SWARMER_TELEPORT_TRIGGER, true);
|
||||
_swarmers.push_back(who->GetGUID());
|
||||
break;
|
||||
case NPC_HIVEZARA_LARVA:
|
||||
who->GetMotionMaster()->MovePoint(POINT_PARALYZE, AltarPos);
|
||||
break;
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* who) override
|
||||
summons.Summon(who);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_AIR)
|
||||
{
|
||||
switch (who->GetEntry())
|
||||
me->AddUnitState(UNIT_STATE_ROOT);
|
||||
}
|
||||
else if (type == WAYPOINT_MOTION_TYPE && id == POINT_GROUND)
|
||||
{
|
||||
SetCombatMovement(true);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
case NPC_SWARMER:
|
||||
_swarmers.push_back(who->GetGUID());
|
||||
break;
|
||||
case NPC_LARVA:
|
||||
who->GetMotionMaster()->MovePoint(POINT_PARALYZE, AltarPos);
|
||||
break;
|
||||
case NPC_HORNET:
|
||||
if (me->GetVictim())
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
}
|
||||
|
||||
}, 1s);
|
||||
}
|
||||
}
|
||||
|
||||
void ScheduleTasks()
|
||||
{
|
||||
_scheduler.Schedule(20s, 30s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_STINGER_SPRAY);
|
||||
context.Repeat(15s, 20s);
|
||||
}).Schedule(5s, [this](TaskContext context) {
|
||||
DoCastVictim(SPELL_POISON_STINGER);
|
||||
context.SetGroup(PHASE_AIR);
|
||||
context.Repeat(2s, 3s);
|
||||
}).Schedule(5s, [this](TaskContext context) {
|
||||
DoCastAOE(SPELL_SUMMON_HIVEZARA_SWARMER, true);
|
||||
|
||||
if (_swarmers.size() >= MAX_SWARMER_COUNT)
|
||||
{
|
||||
DoCastAOE(SPELL_HIVEZARA_SWARMER_SWARM, true);
|
||||
}
|
||||
|
||||
context.Repeat(RAND(2400ms, 3600ms));
|
||||
}).Schedule(15s, [this](TaskContext context) {
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true))
|
||||
{
|
||||
DoCast(target, SPELL_PARALYZE, true);
|
||||
instance->SetGuidData(DATA_PARALYZED, target->GetGUID());
|
||||
DoCastAOE(RAND(SPELL_SUMMON_LARVA_A, SPELL_SUMMON_LARVA_B), true);
|
||||
}
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_SWARMER_SWARM)
|
||||
{
|
||||
for (ObjectGuid const& guid : _swarmers)
|
||||
{
|
||||
if (Creature* swarmer = me->GetMap()->GetCreature(guid))
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
|
||||
{
|
||||
who->AI()->AttackStart(target);
|
||||
swarmer->AI()->AttackStart(target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case POINT_AIR:
|
||||
me->AddUnitState(UNIT_STATE_ROOT);
|
||||
break;
|
||||
case POINT_GROUND:
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_swarmers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
me->ClearUnitState(UNIT_STATE_ROOT);
|
||||
BossAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* attacker) override
|
||||
{
|
||||
BossAI::EnterCombat(attacker);
|
||||
events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(20000, 30000));
|
||||
events.ScheduleEvent(EVENT_POISON_STINGER, 5000);
|
||||
events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000);
|
||||
events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000);
|
||||
events.ScheduleEvent(EVENT_PARALYZE, 15000);
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (_phase == PHASE_AIR && me->GetHealthPct() < 70.0f)
|
||||
{
|
||||
_phase = PHASE_GROUND;
|
||||
SetCombatMovement(true);
|
||||
me->ClearUnitState(UNIT_STATE_ROOT);
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
Position VictimPos = me->GetVictim()->GetPosition();
|
||||
me->GetMotionMaster()->MovePoint(POINT_GROUND, VictimPos);
|
||||
events.ScheduleEvent(EVENT_LASH, urand(5000, 8000));
|
||||
events.CancelEvent(EVENT_POISON_STINGER);
|
||||
DoResetThreat();
|
||||
}
|
||||
if (!_enraged && me->GetHealthPct() < 20.0f)
|
||||
{
|
||||
DoCastSelf(SPELL_FRENZY);
|
||||
Talk(EMOTE_FRENZY);
|
||||
_enraged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_STINGER_SPRAY:
|
||||
DoCastSelf(SPELL_STINGER_SPRAY);
|
||||
events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(15000, 20000));
|
||||
break;
|
||||
case EVENT_POISON_STINGER:
|
||||
DoCastVictim(SPELL_POISON_STINGER);
|
||||
events.ScheduleEvent(EVENT_POISON_STINGER, urand(2000, 3000));
|
||||
break;
|
||||
case EVENT_PARALYZE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true))
|
||||
{
|
||||
DoCast(target, SPELL_PARALYZE);
|
||||
instance->SetGuidData(DATA_PARALYZED, target->GetGUID());
|
||||
uint8 Index = urand(0, 1);
|
||||
me->SummonCreature(NPC_LARVA, LarvaPos[Index], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_PARALYZE, 15000);
|
||||
break;
|
||||
case EVENT_SWARMER_ATTACK:
|
||||
for (ObjectGuid const& guid : _swarmers)
|
||||
{
|
||||
if (Creature* swarmer = me->GetMap()->GetCreature(guid))
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
|
||||
{
|
||||
swarmer->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
_swarmers.clear();
|
||||
events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000);
|
||||
break;
|
||||
case EVENT_SUMMON_SWARMER:
|
||||
{
|
||||
Position Pos = me->GetRandomPoint(SwarmerPos, 80.0f);
|
||||
me->SummonCreature(NPC_SWARMER, Pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
|
||||
events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000);
|
||||
break;
|
||||
}
|
||||
case EVENT_LASH:
|
||||
DoCastVictim(SPELL_LASH);
|
||||
events.ScheduleEvent(EVENT_LASH, urand(8000, 15000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
GuidList _swarmers;
|
||||
uint8 _phase;
|
||||
bool _enraged;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
return GetRuinsOfAhnQirajAI<boss_ayamissAI>(creature);
|
||||
me->ClearUnitState(UNIT_STATE_ROOT);
|
||||
me->SetHomePosition(homePos);
|
||||
BossAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* attacker) override
|
||||
{
|
||||
BossAI::EnterCombat(attacker);
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos);
|
||||
ScheduleTasks();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (_phase == PHASE_AIR && me->HealthBelowPctDamaged(70, damage))
|
||||
{
|
||||
_phase = PHASE_GROUND;
|
||||
me->ClearUnitState(UNIT_STATE_ROOT);
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
|
||||
DoResetThreat();
|
||||
|
||||
_scheduler.Schedule(5s, 8s, [this](TaskContext context) {
|
||||
DoCastVictim(SPELL_LASH);
|
||||
context.Repeat(8s, 15s);
|
||||
}).Schedule(16s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_THRASH);
|
||||
context.Repeat();
|
||||
});
|
||||
|
||||
_scheduler.DelayAll(5s);
|
||||
_scheduler.CancelGroup(PHASE_AIR);
|
||||
}
|
||||
|
||||
if (!_enraged && me->HealthBelowPctDamaged(20, damage))
|
||||
{
|
||||
DoCastSelf(SPELL_FRENZY);
|
||||
Talk(EMOTE_FRENZY);
|
||||
_enraged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff,
|
||||
std::bind(&BossAI::DoMeleeAttackIfReady, this));
|
||||
}
|
||||
private:
|
||||
GuidList _swarmers;
|
||||
uint8 _phase;
|
||||
bool _enraged;
|
||||
TaskScheduler _scheduler;
|
||||
Position homePos;
|
||||
};
|
||||
|
||||
struct npc_hive_zara_larva : public ScriptedAI
|
||||
{
|
||||
npc_hive_zara_larva(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_instance = me->GetInstanceScript();
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_PARALYZE)
|
||||
{
|
||||
if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED)))
|
||||
{
|
||||
DoCast(target, SPELL_FEED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
if (Creature* ayamiss = _instance->GetCreature(DATA_AYAMISS))
|
||||
{
|
||||
ayamiss->AI()->JustSummoned(summon);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
|
||||
return;
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* victim) override
|
||||
{
|
||||
if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
|
||||
return;
|
||||
|
||||
ScriptedAI::AttackStart(victim);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
|
||||
return;
|
||||
|
||||
ScriptedAI::UpdateAI(diff);
|
||||
}
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
struct npc_hive_zara_swarmer : public ScriptedAI
|
||||
{
|
||||
npc_hive_zara_swarmer(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void PathEndReached(uint32 /*pathId*/) override
|
||||
{
|
||||
// Delay is required because we are calling the movement generator from inside the pathing hook.
|
||||
// If we issue another call here, it will be flushed before it is executed.
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
DoCastSelf(SPELL_HIVEZARA_SWARMER_START_LOOP);
|
||||
}, 1s);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_hive_zara_larva : public CreatureScript
|
||||
struct WaspTeleportData
|
||||
{
|
||||
public:
|
||||
npc_hive_zara_larva() : CreatureScript("npc_hive_zara_larva") { }
|
||||
uint32 spellId;
|
||||
uint32 pathId;
|
||||
};
|
||||
|
||||
struct npc_hive_zara_larvaAI : public ScriptedAI
|
||||
class spell_ayamiss_swarmer_teleport_trigger : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_ayamiss_swarmer_teleport_trigger);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
npc_hive_zara_larvaAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_instance = me->GetInstanceScript();
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE)
|
||||
{
|
||||
if (id == POINT_PARALYZE)
|
||||
{
|
||||
if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED)))
|
||||
{
|
||||
DoCast(target, SPELL_FEED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
{
|
||||
if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
|
||||
return;
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* victim) override
|
||||
{
|
||||
if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
|
||||
return;
|
||||
|
||||
ScriptedAI::AttackStart(victim);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
|
||||
return;
|
||||
|
||||
ScriptedAI::UpdateAI(diff);
|
||||
}
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetRuinsOfAhnQirajAI<npc_hive_zara_larvaAI>(creature);
|
||||
return ValidateSpellInfo
|
||||
( {
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_1, SPELL_HIVEZARA_SWARMER_TELEPORT_2,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_3, SPELL_HIVEZARA_SWARMER_TELEPORT_4,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_5
|
||||
});
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
WaspTeleportData telData[5] =
|
||||
{
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_1, NPC_HIVEZARA_SWARMER * 10 },
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_2, (NPC_HIVEZARA_SWARMER + 1) * 10 },
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_3, (NPC_HIVEZARA_SWARMER + 2) * 10 },
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_4, (NPC_HIVEZARA_SWARMER + 3) * 10 },
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_5, (NPC_HIVEZARA_SWARMER + 4) * 10 }
|
||||
};
|
||||
|
||||
WaspTeleportData data = Acore::Containers::SelectRandomContainerElement(telData);
|
||||
caster->CastSpell((Unit*)nullptr, data.spellId, true);
|
||||
|
||||
uint32 pathId = data.pathId;
|
||||
caster->m_Events.AddEventAtOffset([caster, pathId]()
|
||||
{
|
||||
caster->GetMotionMaster()->MovePath(pathId, false);
|
||||
}, 1s);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_teleport_trigger::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_ayamiss_swarmer_swarm : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_ayamiss_swarmer_swarm);
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetEntry() == NPC_AYAMISS;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetCaster()->ToCreature()->AI()->DoAction(ACTION_SWARMER_SWARM);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_swarm::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_ayamiss_swarmer_start_loop : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_ayamiss_swarmer_start_loop);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_HIVEZARA_SWARMER_LOOP_1, SPELL_HIVEZARA_SWARMER_LOOP_2, SPELL_HIVEZARA_SWARMER_LOOP_3 });
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetEntry() == NPC_HIVEZARA_SWARMER;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
uint32 loopSpells[3] = { SPELL_HIVEZARA_SWARMER_LOOP_1, SPELL_HIVEZARA_SWARMER_LOOP_2, SPELL_HIVEZARA_SWARMER_LOOP_3 };
|
||||
GetCaster()->CastSpell((Unit*)nullptr, Acore::Containers::SelectRandomContainerElement(loopSpells));
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_start_loop::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_gen_ayamiss_swarmer_loop: public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_ayamiss_swarmer_loop);
|
||||
|
||||
public:
|
||||
spell_gen_ayamiss_swarmer_loop(uint32 pathId) : SpellScript(), _pathId(pathId) { }
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetEntry() == NPC_HIVEZARA_SWARMER;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetCaster()->ToCreature()->GetMotionMaster()->Clear();
|
||||
GetCaster()->ToCreature()->GetMotionMaster()->MovePath(_pathId, false);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_gen_ayamiss_swarmer_loop::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _pathId;
|
||||
};
|
||||
|
||||
void AddSC_boss_ayamiss()
|
||||
{
|
||||
new boss_ayamiss();
|
||||
new npc_hive_zara_larva();
|
||||
RegisterRuinsOfAhnQirajCreatureAI(boss_ayamiss);
|
||||
RegisterRuinsOfAhnQirajCreatureAI(npc_hive_zara_larva);
|
||||
RegisterRuinsOfAhnQirajCreatureAI(npc_hive_zara_swarmer);
|
||||
RegisterSpellScript(spell_ayamiss_swarmer_teleport_trigger);
|
||||
RegisterSpellScript(spell_ayamiss_swarmer_swarm);
|
||||
RegisterSpellScript(spell_ayamiss_swarmer_start_loop);
|
||||
RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_1", (NPC_HIVEZARA_SWARMER + 5) * 10);
|
||||
RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_2", (NPC_HIVEZARA_SWARMER + 6) * 10);
|
||||
RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_3", (NPC_HIVEZARA_SWARMER + 7) * 10);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ struct boss_buru : public BossAI
|
||||
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
_EnterCombat();
|
||||
BossAI::EnterCombat(who);
|
||||
Talk(EMOTE_TARGET, who);
|
||||
DoCastSelf(SPELL_THORNS);
|
||||
ManipulateEggs(true);
|
||||
|
||||
@@ -28,14 +28,16 @@ enum Spells
|
||||
SPELL_SAND_TRAP = 25648,
|
||||
SPELL_ENRAGE = 26527,
|
||||
SPELL_SUMMON_PLAYER = 26446,
|
||||
SPELL_WIDE_SLASH = 25814
|
||||
SPELL_WIDE_SLASH = 25814,
|
||||
SPELL_THRASH = 3391
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_MORTAL_WOUND = 1,
|
||||
EVENT_SAND_TRAP = 2,
|
||||
EVENT_WIDE_SLASH = 3
|
||||
EVENT_WIDE_SLASH = 3,
|
||||
EVENT_THRASH = 4
|
||||
};
|
||||
|
||||
enum Texts
|
||||
@@ -47,6 +49,12 @@ struct boss_kurinnaxx : public BossAI
|
||||
{
|
||||
boss_kurinnaxx(Creature* creature) : BossAI(creature, DATA_KURINNAXX) {}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
me->m_CombatDistance = 50.0f;
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
@@ -54,6 +62,7 @@ struct boss_kurinnaxx : public BossAI
|
||||
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8s, 10s);
|
||||
events.ScheduleEvent(EVENT_SAND_TRAP, 5s, 15s);
|
||||
events.ScheduleEvent(EVENT_WIDE_SLASH, 10s, 15s);
|
||||
events.ScheduleEvent(EVENT_THRASH, 16s);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
@@ -108,6 +117,10 @@ struct boss_kurinnaxx : public BossAI
|
||||
DoCastSelf(SPELL_WIDE_SLASH);
|
||||
events.ScheduleEvent(EVENT_WIDE_SLASH, 12s, 15s);
|
||||
break;
|
||||
case EVENT_THRASH:
|
||||
DoCastSelf(SPELL_THRASH);
|
||||
events.ScheduleEvent(EVENT_THRASH, 16s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@ struct boss_moam : public BossAI
|
||||
{
|
||||
BossAI::EnterCombat(who);
|
||||
Talk(EMOTE_AGGRO);
|
||||
events.ScheduleEvent(EVENT_STONE_PHASE, 90000);
|
||||
events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 9000);
|
||||
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 3000);
|
||||
events.ScheduleEvent(EVENT_STONE_PHASE, 90s);
|
||||
events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 9s);
|
||||
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 3s);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -113,20 +113,20 @@ struct boss_moam : public BossAI
|
||||
DoCastAOE(SPELL_SUMMON_MANA_FIENDS);
|
||||
DoCastSelf(SPELL_ENERGIZE);
|
||||
events.CancelEvent(EVENT_SPELL_DRAIN_MANA);
|
||||
events.ScheduleEvent(EVENT_STONE_PHASE_END, 90000);
|
||||
events.ScheduleEvent(EVENT_STONE_PHASE_END, 90s);
|
||||
break;
|
||||
case EVENT_STONE_PHASE_END:
|
||||
me->RemoveAurasDueToSpell(SPELL_ENERGIZE);
|
||||
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000));
|
||||
events.ScheduleEvent(EVENT_STONE_PHASE, 90000);
|
||||
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 2s, 6s);
|
||||
events.ScheduleEvent(EVENT_STONE_PHASE, 90s);
|
||||
break;
|
||||
case EVENT_SPELL_DRAIN_MANA:
|
||||
DoCastAOE(SPELL_DRAIN_MANA_SERVERSIDE);
|
||||
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000));
|
||||
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 2s, 6s);
|
||||
break;
|
||||
case EVENT_SPELL_TRAMPLE:
|
||||
DoCastAOE(SPELL_TRAMPLE);
|
||||
events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 15000);
|
||||
events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 15s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -148,6 +148,11 @@ class spell_moam_mana_drain_filter : public SpellScript
|
||||
{
|
||||
return !target->IsPlayer() || target->ToPlayer()->getPowerType() != POWER_MANA;
|
||||
});
|
||||
|
||||
if (!targets.empty())
|
||||
{
|
||||
Acore::Containers::RandomResize(targets, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
@@ -160,7 +165,7 @@ class spell_moam_mana_drain_filter : public SpellScript
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_moam_mana_drain_filter::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_moam_mana_drain_filter::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_moam_mana_drain_filter::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
#include "ruins_of_ahnqiraj.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
@@ -35,12 +36,20 @@ enum Texts
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CURSE_OF_TONGUES = 25195,
|
||||
SPELL_ENVELOPING_WINDS = 25189,
|
||||
SPELL_WAR_STOMP = 25188,
|
||||
SPELL_STRENGHT_OF_OSSIRIAN = 25176,
|
||||
SPELL_SAND_STORM = 25160,
|
||||
SPELL_SUMMON_CRYSTAL = 25192
|
||||
SPELL_CURSE_OF_TONGUES = 25195,
|
||||
SPELL_ENVELOPING_WINDS = 25189,
|
||||
SPELL_WAR_STOMP = 25188,
|
||||
SPELL_STRENGHT_OF_OSSIRIAN = 25176,
|
||||
SPELL_SAND_STORM = 25160,
|
||||
SPELL_SUMMON_CRYSTAL = 25192,
|
||||
SPELL_SUMMON_SMALL_OBSIDIAN_CHUNK = 27627, // Server-side
|
||||
|
||||
// Crystal
|
||||
SPELL_FIRE_WEAKNESS = 25177,
|
||||
SPELL_FROST_WEAKNESS = 25178,
|
||||
SPELL_NATURE_WEAKNESS = 25180,
|
||||
SPELL_ARCANE_WEAKNESS = 25181,
|
||||
SPELL_SHADOW_WEAKNESS = 25183
|
||||
};
|
||||
|
||||
enum Actions
|
||||
@@ -55,25 +64,27 @@ enum Events
|
||||
EVENT_STOMP = 3
|
||||
};
|
||||
|
||||
uint8 const NUM_CRYSTALS = 9;
|
||||
uint8 const NUM_CRYSTALS = 11;
|
||||
Position CrystalCoordinates[NUM_CRYSTALS] =
|
||||
{
|
||||
{ -9394.230469f, 1951.808594f, 85.97733f, 0.0f },
|
||||
{ -9357.931641f, 1930.596802f, 85.556198f, 0.0f },
|
||||
{ -9383.113281f, 2011.042725f, 85.556389f, 0.0f },
|
||||
{ -9243.36f, 1979.04f, 85.556f, 0.0f },
|
||||
{ -9281.68f, 1886.66f, 85.5558f, 0.0f },
|
||||
{ -9241.8f, 1806.39f, 85.5557f, 0.0f },
|
||||
{ -9366.78f, 1781.76f, 85.5561f, 0.0f },
|
||||
{ -9430.37f, 1786.86f, 85.557f, 0.0f },
|
||||
{ -9406.73f, 1863.13f, 85.5558f, 0.0f }
|
||||
{ -9388.4404296875f, 1940.20996093750f, 85.6390991210937f, 3.17650008201599f },
|
||||
{ -9357.8603515625f, 1929.07995605469f, 85.6390991210937f, 1.06465005874634f },
|
||||
{ -9383.2900390625f, 2012.68005371094f, 85.6511001586914f, 2.93214988708496f },
|
||||
{ -9248.4101562500f, 1974.82995605469f, 85.6390991210937f, 5.89920997619629f },
|
||||
{ -9432.4003906250f, 1782.53002929687f, 85.6390991210937f, 5.86430978775024f },
|
||||
{ -9299.7304687500f, 1748.44995117187f, 85.6390991210937f, 1.44861996173859f },
|
||||
{ -9406.0996093750f, 1862.38000488281f, 85.6390991210937f, 6.23082017898560f },
|
||||
{ -9506.1904296875f, 1865.56994628906f, 85.6390991210937f, 4.27606010437012f },
|
||||
{ -9282.0800781250f, 1887.33996582031f, 85.6390991210937f, 2.00712990760803f },
|
||||
{ -9244.4101562500f, 1808.97998046875f, 85.6390991210937f, 5.63741016387939f },
|
||||
{ -9367.1699218750f, 1780.89001464844f, 85.6390991210937f, 1.90241003036499f }
|
||||
};
|
||||
|
||||
float roomRadius = 165.0f;
|
||||
uint8 const NUM_TORNADOS = 2;
|
||||
Position initialCrystalPosition = { -9407.7197265625f, 1960.2099609375f, 85.6390991210937f, 1.11700999736786f };
|
||||
|
||||
uint8 const NUM_WEAKNESS = 5;
|
||||
uint32 const spellWeakness[NUM_WEAKNESS] = { 25177, 25178, 25180, 25181, 25183 };
|
||||
Position const RoomCenter = { -9343.041992f, 1923.278198f, 85.555984f, 0.0 };
|
||||
uint32 const spellWeakness[NUM_WEAKNESS] =
|
||||
{ SPELL_FIRE_WEAKNESS, SPELL_FROST_WEAKNESS, SPELL_NATURE_WEAKNESS, SPELL_ARCANE_WEAKNESS, SPELL_SHADOW_WEAKNESS };
|
||||
|
||||
struct boss_ossirian : public BossAI
|
||||
{
|
||||
@@ -82,36 +93,103 @@ struct boss_ossirian : public BossAI
|
||||
_saidIntro = false;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void InitializeAI() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
_crystalIterator = 0;
|
||||
_triggerGUID.Clear();
|
||||
_crystalGUID.Clear();
|
||||
}
|
||||
Reset();
|
||||
|
||||
void SpellHit(Unit* caster, SpellInfo const* spell) override
|
||||
{
|
||||
for (uint8 weakness : spellWeakness)
|
||||
if (Creature* trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, initialCrystalPosition))
|
||||
{
|
||||
if (spell->Id == weakness)
|
||||
_triggerGUID[0] = trigger->GetGUID();
|
||||
if (GameObject* crystal = trigger->SummonGameObject(GO_OSSIRIAN_CRYSTAL,
|
||||
initialCrystalPosition.GetPositionX(),
|
||||
initialCrystalPosition.GetPositionY(),
|
||||
initialCrystalPosition.GetPositionZ(),
|
||||
0, 0, 0, 0, 0, uint32(-1)))
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_STRENGHT_OF_OSSIRIAN);
|
||||
((TempSummon*)caster)->UnSummon();
|
||||
SpawnNextCrystal();
|
||||
_crystalGUID[0] = crystal->GetGUID();
|
||||
crystal->SetOwnerGUID(ObjectGuid::Empty);
|
||||
crystal->RemoveGameObjectFlag(GO_FLAG_IN_USE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
|
||||
_crystalIterator = urand(0, NUM_CRYSTALS - 1);
|
||||
_triggerGUID[1].Clear();
|
||||
_crystalGUID[1].Clear();
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
{
|
||||
if (me->IsVisible())
|
||||
{
|
||||
Creature* trigger = me->GetMap()->GetCreature(_triggerGUID[0]);
|
||||
if (trigger)
|
||||
{
|
||||
trigger->DespawnOrUnsummon();
|
||||
if (GameObject* crystal = me->GetMap()->GetGameObject(_crystalGUID[0]))
|
||||
crystal->Delete();
|
||||
}
|
||||
|
||||
trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, initialCrystalPosition);
|
||||
if (trigger)
|
||||
{
|
||||
_triggerGUID[0] = trigger->GetGUID();
|
||||
if (GameObject* crystal = trigger->SummonGameObject(GO_OSSIRIAN_CRYSTAL,
|
||||
initialCrystalPosition.GetPositionX(),
|
||||
initialCrystalPosition.GetPositionY(),
|
||||
initialCrystalPosition.GetPositionZ(),
|
||||
0, 0, 0, 0, 0, uint32(-1)))
|
||||
{
|
||||
_crystalGUID[0] = crystal->GetGUID();
|
||||
crystal->SetOwnerGUID(ObjectGuid::Empty);
|
||||
crystal->RemoveGameObjectFlag(GO_FLAG_IN_USE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHit(Unit* caster, SpellInfo const* spell) override
|
||||
{
|
||||
for (uint32 weakness : spellWeakness)
|
||||
{
|
||||
if (spell->Id == weakness)
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_STRENGHT_OF_OSSIRIAN);
|
||||
|
||||
if (caster->GetGUID() == _triggerGUID[1])
|
||||
{
|
||||
if (Creature* creatureCaster = caster->ToCreature())
|
||||
{
|
||||
creatureCaster->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid guid, int32 action) override
|
||||
{
|
||||
if (action == ACTION_TRIGGER_WEAKNESS)
|
||||
{
|
||||
if (Creature* trigger = me->GetMap()->GetCreature(_triggerGUID))
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
{
|
||||
if (!trigger->HasUnitState(UNIT_STATE_CASTING))
|
||||
if (_crystalGUID[i] == guid)
|
||||
{
|
||||
trigger->CastSpell(trigger, spellWeakness[urand(0, 4)], false);
|
||||
if (Creature* trigger = me->GetMap()->GetCreature(_triggerGUID[i]))
|
||||
{
|
||||
if (!trigger->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
trigger->CastSpell(trigger, spellWeakness[urand(0, 4)], false);
|
||||
}
|
||||
}
|
||||
|
||||
SpawnNextCrystal();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,77 +211,55 @@ struct boss_ossirian : public BossAI
|
||||
|
||||
WorldPackets::Misc::Weather weather(WEATHER_STATE_HEAVY_SANDSTORM, 1.0f);
|
||||
map->SendToPlayers(weather.Write());
|
||||
for (uint8 i = 0; i < NUM_TORNADOS; ++i)
|
||||
{
|
||||
Position Point = me->GetRandomPoint(RoomCenter, roomRadius);
|
||||
if (Creature* Tornado = me->GetMap()->SummonCreature(NPC_SAND_VORTEX, Point))
|
||||
{
|
||||
Tornado->CastSpell(Tornado, SPELL_SAND_STORM, true);
|
||||
}
|
||||
}
|
||||
|
||||
SpawnNextCrystal();
|
||||
}
|
||||
|
||||
void SummonedCreatureDespawn(Creature* summon) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
|
||||
if (GameObject* crystal = GetClosestGameObjectWithEntry(summon, GO_OSSIRIAN_CRYSTAL, 5.0f))
|
||||
{
|
||||
crystal->Delete();
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
Cleanup();
|
||||
summons.DespawnAll();
|
||||
BossAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Cleanup();
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
if (GameObject* crystal = me->GetMap()->GetGameObject(_crystalGUID))
|
||||
{
|
||||
crystal->Use(me);
|
||||
}
|
||||
|
||||
std::list<Creature*> vortexes;
|
||||
me->GetCreaturesWithEntryInRange(vortexes, 200.f, NPC_SAND_VORTEX);
|
||||
for (Creature* vortex : vortexes)
|
||||
vortex->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void SpawnNextCrystal()
|
||||
{
|
||||
if (_crystalIterator == NUM_CRYSTALS)
|
||||
_crystalIterator = 0;
|
||||
|
||||
if (Creature* trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, CrystalCoordinates[_crystalIterator]))
|
||||
if (Creature* trigger = me->SummonCreature(NPC_OSSIRIAN_TRIGGER, CrystalCoordinates[_crystalIterator]))
|
||||
{
|
||||
_triggerGUID = trigger->GetGUID();
|
||||
_triggerGUID[1] = trigger->GetGUID();
|
||||
if (GameObject* crystal = trigger->SummonGameObject(GO_OSSIRIAN_CRYSTAL,
|
||||
CrystalCoordinates[_crystalIterator].GetPositionX(),
|
||||
CrystalCoordinates[_crystalIterator].GetPositionY(),
|
||||
CrystalCoordinates[_crystalIterator].GetPositionZ(),
|
||||
0, 0, 0, 0, 0, uint32(-1)))
|
||||
{
|
||||
_crystalGUID = crystal->GetGUID();
|
||||
_crystalGUID[1] = crystal->GetGUID();
|
||||
++_crystalIterator;
|
||||
crystal->SetOwnerGUID(ObjectGuid::Empty);
|
||||
crystal->RemoveGameObjectFlag(GO_FLAG_IN_USE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
{
|
||||
if (!_saidIntro)
|
||||
{
|
||||
Talk(SAY_INTRO);
|
||||
_saidIntro = true;
|
||||
}
|
||||
|
||||
BossAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
@@ -220,7 +276,7 @@ struct boss_ossirian : public BossAI
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8 weakness : spellWeakness)
|
||||
for (uint32 weakness : spellWeakness)
|
||||
{
|
||||
if (me->HasAura(weakness))
|
||||
{
|
||||
@@ -260,8 +316,8 @@ struct boss_ossirian : public BossAI
|
||||
}
|
||||
|
||||
protected:
|
||||
ObjectGuid _triggerGUID;
|
||||
ObjectGuid _crystalGUID;
|
||||
std::array<ObjectGuid, 2> _triggerGUID;
|
||||
std::array<ObjectGuid, 2> _crystalGUID;
|
||||
uint8 _crystalIterator;
|
||||
bool _saidIntro;
|
||||
};
|
||||
@@ -271,18 +327,18 @@ class go_ossirian_crystal : public GameObjectScript
|
||||
public:
|
||||
go_ossirian_crystal() : GameObjectScript("go_ossirian_crystal") { }
|
||||
|
||||
bool OnGossipHello(Player* player, GameObject* /*go*/) override
|
||||
bool OnGossipHello(Player* player, GameObject* go) override
|
||||
{
|
||||
InstanceScript* instance = player->GetInstanceScript();
|
||||
if (!instance)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
Creature* ossirian = instance->GetCreature(DATA_OSSIRIAN);
|
||||
if (!ossirian || instance->GetBossState(DATA_OSSIRIAN) != IN_PROGRESS)
|
||||
return false;
|
||||
if (!ossirian)
|
||||
return true;
|
||||
|
||||
ossirian->AI()->DoAction(ACTION_TRIGGER_WEAKNESS);
|
||||
return true;
|
||||
ossirian->AI()->SetGUID(go->GetGUID(), ACTION_TRIGGER_WEAKNESS);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -348,6 +404,11 @@ struct npc_anubisath_guardian : public ScriptedAI
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_SMALL_OBSIDIAN_CHUNK, true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
@@ -363,9 +424,28 @@ private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
class spell_crystal_weakness : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_crystal_weakness);
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
targets.remove_if([&](WorldObject const* target) -> bool
|
||||
{
|
||||
return target->GetEntry() != NPC_OSSIRIAN;
|
||||
});
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_crystal_weakness::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENTRY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_ossirian()
|
||||
{
|
||||
RegisterRuinsOfAhnQirajCreatureAI(boss_ossirian);
|
||||
new go_ossirian_crystal();
|
||||
RegisterCreatureAI(npc_anubisath_guardian);
|
||||
RegisterSpellScript(spell_crystal_weakness);
|
||||
}
|
||||
|
||||
@@ -46,71 +46,60 @@ enum Events
|
||||
EVENT_CHANGE_AGGRO = 3,
|
||||
};
|
||||
|
||||
class boss_rajaxx : public CreatureScript
|
||||
struct boss_rajaxx : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_rajaxx() : CreatureScript("boss_rajaxx") { }
|
||||
boss_rajaxx(Creature* creature) : BossAI(creature, DATA_RAJAXX) { }
|
||||
|
||||
struct boss_rajaxxAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_rajaxxAI(Creature* creature) : BossAI(creature, DATA_RAJAXX) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
enraged = false;
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*victim*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_DISARM, 10000);
|
||||
events.ScheduleEvent(EVENT_THUNDERCRASH, 12000);
|
||||
}
|
||||
|
||||
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_DISARM:
|
||||
DoCastVictim(SPELL_DISARM);
|
||||
events.ScheduleEvent(EVENT_DISARM, 22000);
|
||||
break;
|
||||
case EVENT_THUNDERCRASH:
|
||||
DoCast(me, SPELL_THUNDERCRASH);
|
||||
events.ScheduleEvent(EVENT_THUNDERCRASH, 21000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
bool enraged;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetRuinsOfAhnQirajAI<boss_rajaxxAI>(creature);
|
||||
BossAI::Reset();
|
||||
enraged = false;
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*victim*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_DISARM, 10s);
|
||||
events.ScheduleEvent(EVENT_THUNDERCRASH, 12s);
|
||||
}
|
||||
|
||||
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_DISARM:
|
||||
DoCastVictim(SPELL_DISARM);
|
||||
events.ScheduleEvent(EVENT_DISARM, 22s);
|
||||
break;
|
||||
case EVENT_THUNDERCRASH:
|
||||
DoCastSelf(SPELL_THUNDERCRASH);
|
||||
events.ScheduleEvent(EVENT_THUNDERCRASH, 21s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
bool enraged;
|
||||
};
|
||||
|
||||
class spell_rajaxx_thundercrash : public SpellScript
|
||||
@@ -136,6 +125,6 @@ class spell_rajaxx_thundercrash : public SpellScript
|
||||
|
||||
void AddSC_boss_rajaxx()
|
||||
{
|
||||
new boss_rajaxx();
|
||||
RegisterRuinsOfAhnQirajCreatureAI(boss_rajaxx);
|
||||
RegisterSpellScript(spell_rajaxx_thundercrash);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ ObjectData const creatureData[] =
|
||||
{ NPC_BURU, DATA_BURU },
|
||||
{ NPC_KURINNAXX, DATA_KURINNAXX },
|
||||
{ NPC_RAJAXX, DATA_RAJAXX },
|
||||
{ NPC_AYAMISS, DATA_AYAMISS },
|
||||
{ NPC_OSSIRIAN, DATA_OSSIRIAN },
|
||||
{ NPC_QUUEZ, DATA_QUUEZ },
|
||||
{ NPC_TUUBID, DATA_TUUBID },
|
||||
@@ -36,14 +37,17 @@ ObjectData const creatureData[] =
|
||||
{ NPC_ZERRAN, DATA_ZERRAN },
|
||||
};
|
||||
|
||||
enum RajaxxText
|
||||
enum RajaxxWaveEvent
|
||||
{
|
||||
SAY_WAVE3 = 0,
|
||||
SAY_WAVE4 = 1,
|
||||
SAY_WAVE5 = 2,
|
||||
SAY_WAVE6 = 3,
|
||||
SAY_WAVE7 = 4,
|
||||
SAY_ENGAGE = 5
|
||||
SAY_ENGAGE = 5,
|
||||
|
||||
DATA_RAJAXX_WAVE_ENGAGED = 1,
|
||||
GROUP_RAJAXX_WAVE_TIMER = 1
|
||||
};
|
||||
|
||||
std::array<uint32, 8> RajaxxWavesData[] =
|
||||
@@ -90,12 +94,13 @@ public:
|
||||
case NPC_BURU:
|
||||
_buruGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_AYAMISS:
|
||||
_ayamissGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_OSSIRIAN:
|
||||
_ossirianGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_SAND_VORTEX:
|
||||
_sandVortexes.push_back(creature->GetGUID());
|
||||
creature->SetVisible(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +135,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 /*data*/) override
|
||||
{
|
||||
if (type == DATA_RAJAXX_WAVE_ENGAGED)
|
||||
{
|
||||
_scheduler.CancelGroup(GROUP_RAJAXX_WAVE_TIMER);
|
||||
_scheduler.Schedule(2min, [this](TaskContext context)
|
||||
{
|
||||
CallNextRajaxxLeader();
|
||||
context.SetGroup(GROUP_RAJAXX_WAVE_TIMER);
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void OnUnitDeath(Unit* unit) override
|
||||
{
|
||||
if (Creature* creature = unit->ToCreature())
|
||||
@@ -151,7 +170,7 @@ public:
|
||||
_scheduler.Schedule(1s, [this, formation](TaskContext /*context*/) {
|
||||
if (!formation->IsAnyMemberAlive())
|
||||
{
|
||||
CallNextRajaxxLeader();
|
||||
CallNextRajaxxLeader(true);
|
||||
}
|
||||
});
|
||||
break;
|
||||
@@ -174,6 +193,31 @@ public:
|
||||
_paralyzedGUID = data;
|
||||
}
|
||||
|
||||
bool SetBossState(uint32 type, EncounterState state) override
|
||||
{
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DATA_OSSIRIAN:
|
||||
{
|
||||
for (ObjectGuid const& guid : _sandVortexes)
|
||||
{
|
||||
if (Creature* sandVortex = instance->GetCreature(guid))
|
||||
{
|
||||
sandVortex->SetVisible(state == IN_PROGRESS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 type) const override
|
||||
{
|
||||
switch (type)
|
||||
@@ -186,8 +230,6 @@ public:
|
||||
return _moamGUID;
|
||||
case DATA_BURU:
|
||||
return _buruGUID;
|
||||
case DATA_AYAMISS:
|
||||
return _ayamissGUID;
|
||||
case DATA_OSSIRIAN:
|
||||
return _ossirianGUID;
|
||||
case DATA_PARALYZED:
|
||||
@@ -240,17 +282,20 @@ public:
|
||||
OUT_LOAD_INST_DATA_COMPLETE;
|
||||
}
|
||||
|
||||
void CallNextRajaxxLeader()
|
||||
void CallNextRajaxxLeader(bool announce = false)
|
||||
{
|
||||
++_rajaxWaveCounter;
|
||||
|
||||
if (Creature* nextLeader = GetCreature(RajaxxWavesData[_rajaxWaveCounter].at(0)))
|
||||
{
|
||||
if (_rajaxWaveCounter >= 2)
|
||||
if (announce)
|
||||
{
|
||||
if (Creature* rajaxx = GetCreature(DATA_RAJAXX))
|
||||
if (_rajaxWaveCounter >= 2)
|
||||
{
|
||||
rajaxx->AI()->Talk(RajaxxWavesData[_rajaxWaveCounter].at(1));
|
||||
if (Creature* rajaxx = GetCreature(DATA_RAJAXX))
|
||||
{
|
||||
rajaxx->AI()->Talk(RajaxxWavesData[_rajaxWaveCounter].at(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,6 +313,7 @@ public:
|
||||
void ResetRajaxxWaves()
|
||||
{
|
||||
_rajaxWaveCounter = 0;
|
||||
_scheduler.CancelAll();
|
||||
for (auto const& data : RajaxxWavesData)
|
||||
{
|
||||
if (Creature* creature = GetCreature(data.at(0)))
|
||||
@@ -285,9 +331,9 @@ public:
|
||||
ObjectGuid _rajaxxGUID;
|
||||
ObjectGuid _moamGUID;
|
||||
ObjectGuid _buruGUID;
|
||||
ObjectGuid _ayamissGUID;
|
||||
ObjectGuid _ossirianGUID;
|
||||
ObjectGuid _paralyzedGUID;
|
||||
GuidVector _sandVortexes;
|
||||
uint32 _rajaxWaveCounter;
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 "ruins_of_ahnqiraj.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_HIVEZARA_CATALYST = 25187,
|
||||
SPELL_STINGER_CHARGE_NORMAL = 25190,
|
||||
SPELL_STINGER_CHARGE_BUFFED = 25191
|
||||
};
|
||||
|
||||
struct npc_hivezara_stinger : public ScriptedAI
|
||||
{
|
||||
npc_hivezara_stinger(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
DoCast(who ,who->HasAura(SPELL_HIVEZARA_CATALYST) ? SPELL_STINGER_CHARGE_BUFFED : SPELL_STINGER_CHARGE_NORMAL, true);
|
||||
|
||||
_scheduler.Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* u)
|
||||
{
|
||||
return u && !u->IsPet() && u->IsWithinDist2d(me, 20.f) && u->HasAura(SPELL_HIVEZARA_CATALYST);
|
||||
});
|
||||
if (!target)
|
||||
{
|
||||
target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* u)
|
||||
{
|
||||
return u && !u->IsPet() && u->IsWithinDist2d(me, 20.f);
|
||||
});
|
||||
}
|
||||
|
||||
if (target)
|
||||
{
|
||||
DoCast(target, target->HasAura(SPELL_HIVEZARA_CATALYST) ? SPELL_STINGER_CHARGE_BUFFED : SPELL_STINGER_CHARGE_NORMAL, true);
|
||||
}
|
||||
|
||||
context.Repeat(4500ms, 6500ms);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_scheduler.Update(diff,
|
||||
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
void AddSC_ruins_of_ahnqiraj()
|
||||
{
|
||||
RegisterRuinsOfAhnQirajCreatureAI(npc_hivezara_stinger);
|
||||
}
|
||||
@@ -60,9 +60,6 @@ enum Creatures
|
||||
NPC_OSSIRIAN_TRIGGER = 15590,
|
||||
NPC_HATCHLING = 15521,
|
||||
NPC_BURU_EGG = 15514,
|
||||
NPC_LARVA = 15555,
|
||||
NPC_SWARMER = 15546,
|
||||
NPC_HORNET = 15934,
|
||||
|
||||
// Rajaxx
|
||||
NPC_QUUEZ = 15391,
|
||||
|
||||
@@ -137,9 +137,9 @@ public:
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 /*id*/) override
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
if (type != POINT_MOTION_TYPE || id != POINT_CONSUME)
|
||||
return;
|
||||
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
@@ -153,6 +153,7 @@ public:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
if (Unit* target = me->GetVictim())
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveChase(target);
|
||||
AttackStart(target);
|
||||
}
|
||||
@@ -195,7 +196,7 @@ public:
|
||||
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (me->HealthBelowPctDamaged(1, damage) && instance->GetData(DATA_BUG_TRIO_DEATH) < 2 && who->GetGUID() != me->GetGUID())
|
||||
if (me->HealthBelowPctDamaged(1, damage) && instance->GetData(DATA_BUG_TRIO_DEATH) < 2 && who->GetGUID() != me->GetGUID() && !dying)
|
||||
{
|
||||
damage = 0;
|
||||
if (isEating)
|
||||
@@ -205,6 +206,7 @@ public:
|
||||
me->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetControlled(true, UNIT_STATE_ROOT);
|
||||
dying = true;
|
||||
|
||||
DoFinalSpell();
|
||||
|
||||
@@ -236,7 +238,7 @@ public:
|
||||
|
||||
_scheduler.Schedule(4s, [this](TaskContext /*context*/)
|
||||
{
|
||||
if (!me->IsInEvadeMode())
|
||||
if (!me->IsInEvadeMode() && instance->GetData(DATA_BUG_TRIO_DEATH) < 2)
|
||||
{
|
||||
DoCastSelf(SPELL_BLOODY_DEATH, true);
|
||||
Talk(EMOTE_DEVOURED);
|
||||
@@ -452,9 +454,9 @@ class spell_vem_vengeance : public SpellScript
|
||||
|
||||
void AddSC_bug_trio()
|
||||
{
|
||||
RegisterCreatureAI(boss_kri);
|
||||
RegisterCreatureAI(boss_vem);
|
||||
RegisterCreatureAI(boss_yauj);
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_kri);
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_vem);
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_yauj);
|
||||
RegisterSpellScript(spell_vem_knockback);
|
||||
RegisterSpellScript(spell_vem_vengeance);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,154 +15,118 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Fankriss
|
||||
SD%Complete: 100
|
||||
SDComment: sound not implemented
|
||||
SDCategory: Temple of Ahn'Qiraj
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "temple_of_ahnqiraj.h"
|
||||
|
||||
#define SOUND_SENTENCE_YOU 8588
|
||||
#define SOUND_SERVE_TO 8589
|
||||
#define SOUND_LAWS 8590
|
||||
#define SOUND_TRESPASS 8591
|
||||
#define SOUND_WILL_BE 8592
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_MORTAL_WOUND = 25646,
|
||||
SPELL_ROOT = 28858,
|
||||
SPELL_ENTANGLE_RIGHT = 720,
|
||||
SPELL_ENTANGLE_CENTER = 731,
|
||||
SPELL_ENTANGLE_LEFT = 1121,
|
||||
|
||||
// Enrage for his spawns
|
||||
SPELL_ENRAGE = 28798
|
||||
SPELL_SUMMON_WORM_1 = 518,
|
||||
SPELL_SUMMON_WORM_2 = 25831,
|
||||
SPELL_SUMMON_WORM_3 = 25832
|
||||
};
|
||||
|
||||
class boss_fankriss : public CreatureScript
|
||||
enum Misc
|
||||
{
|
||||
public:
|
||||
boss_fankriss() : CreatureScript("boss_fankriss") { }
|
||||
MAX_HATCHLING_SPAWN = 4,
|
||||
NPC_VEKNISS_HATCHLING = 15962
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
const std::array<Position, 3> hatchlingsSpawnPoints
|
||||
{
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_fankrissAI>(creature);
|
||||
{ -8043.6f, 1254.1f, -84.3f }, // Right
|
||||
{ -8003.0f, 1222.9f, -82.1f }, // Center
|
||||
{ -8022.3f, 1149.0f, -89.1f } // Left
|
||||
}
|
||||
};
|
||||
|
||||
const std::array<uint32, 3> entangleSpells = { SPELL_ENTANGLE_RIGHT, SPELL_ENTANGLE_CENTER, SPELL_ENTANGLE_LEFT };
|
||||
|
||||
struct boss_fankriss : public BossAI
|
||||
{
|
||||
boss_fankriss(Creature* creature) : BossAI(creature, DATA_FANKRISS) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
summonWormSpells = { SPELL_SUMMON_WORM_1, SPELL_SUMMON_WORM_2, SPELL_SUMMON_WORM_3};
|
||||
|
||||
BossAI::Reset();
|
||||
}
|
||||
|
||||
struct boss_fankrissAI : public ScriptedAI
|
||||
void SummonWorms()
|
||||
{
|
||||
boss_fankrissAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
uint32 amount = urand(1, 3);
|
||||
Acore::Containers::RandomResize(summonWormSpells, amount);
|
||||
for (uint32 summonSpell : summonWormSpells)
|
||||
DoCastAOE(summonSpell, true);
|
||||
summonWormSpells = { SPELL_SUMMON_WORM_1, SPELL_SUMMON_WORM_2, SPELL_SUMMON_WORM_3 };
|
||||
}
|
||||
|
||||
void SummonSpawn()
|
||||
void SummonHatchlingWaves()
|
||||
{
|
||||
for (Position spawnPos : hatchlingsSpawnPoints)
|
||||
{
|
||||
Rand = 10 + (rand() % 10);
|
||||
switch (rand() % 2)
|
||||
for (uint8 i = 0; i < MAX_HATCHLING_SPAWN; i++)
|
||||
{
|
||||
case 0:
|
||||
RandX = 0.0f - Rand;
|
||||
break;
|
||||
case 1:
|
||||
RandX = 0.0f + Rand;
|
||||
break;
|
||||
Position randSpawn = me->GetRandomPoint(spawnPos, 10.f);
|
||||
me->SummonCreature(NPC_VEKNISS_HATCHLING, randSpawn, TEMPSUMMON_CORPSE_DESPAWN);
|
||||
}
|
||||
|
||||
Rand = 10 + (rand() % 10);
|
||||
switch (rand() % 2)
|
||||
{
|
||||
case 0:
|
||||
RandY = 0.0f - Rand;
|
||||
break;
|
||||
case 1:
|
||||
RandY = 0.0f + Rand;
|
||||
break;
|
||||
}
|
||||
Rand = 0;
|
||||
DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
}
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
BossAI::EnterCombat(who);
|
||||
|
||||
_scheduler.Schedule(4s, 8s, [this](TaskContext context) {
|
||||
_scheduler
|
||||
.Schedule(7s, 14s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_MORTAL_WOUND);
|
||||
context.Repeat();
|
||||
}).Schedule(15s, 45s, [this](TaskContext context) {
|
||||
switch (urand(0, 2))
|
||||
})
|
||||
.Schedule(30s, 50s, [this](TaskContext context)
|
||||
{
|
||||
SummonWorms();
|
||||
context.Repeat(22s, 70s);
|
||||
})
|
||||
.Schedule(15s, 20s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true))
|
||||
{
|
||||
case 0:
|
||||
SummonSpawn();
|
||||
break;
|
||||
case 1:
|
||||
SummonSpawn();
|
||||
SummonSpawn();
|
||||
break;
|
||||
case 2:
|
||||
SummonSpawn();
|
||||
SummonSpawn();
|
||||
SummonSpawn();
|
||||
break;
|
||||
uint32 spellId = Acore::Containers::SelectRandomContainerElement(entangleSpells);
|
||||
DoCast(target, spellId);
|
||||
}
|
||||
context.Repeat(30s, 60s);
|
||||
}).Schedule(15s, 45s, [this](TaskContext context) {
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_ROOT);
|
||||
|
||||
if (DoGetThreat(target))
|
||||
DoModifyThreatPercent(target, -100);
|
||||
|
||||
switch (urand(0, 2))
|
||||
{
|
||||
case 0:
|
||||
DoTeleportPlayer(target, -8106.0142f, 1289.2900f, -74.419533f, 5.112f);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
break;
|
||||
case 1:
|
||||
DoTeleportPlayer(target, -7990.135354f, 1155.1907f, -78.849319f, 2.608f);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
break;
|
||||
case 2:
|
||||
DoTeleportPlayer(target, -8159.7753f, 1127.9064f, -76.868660f, 0.675f);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context.Repeat(45s, 60s);
|
||||
SummonHatchlingWaves();
|
||||
context.Repeat(25s, 55s);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff,
|
||||
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
|
||||
}
|
||||
_scheduler.Update(diff,
|
||||
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
int Rand;
|
||||
float RandX;
|
||||
float RandY;
|
||||
};
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
std::vector<uint32> summonWormSpells;
|
||||
};
|
||||
|
||||
void AddSC_boss_fankriss()
|
||||
{
|
||||
new boss_fankriss();
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_fankriss);
|
||||
}
|
||||
|
||||
@@ -41,115 +41,104 @@ enum Huhuran
|
||||
SPELL_WYVERN_STING_DAMAGE = 26233
|
||||
};
|
||||
|
||||
class boss_huhuran : public CreatureScript
|
||||
struct boss_huhuran : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_huhuran() : CreatureScript("boss_huhuran") { }
|
||||
boss_huhuran(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
uint32 Frenzy_Timer;
|
||||
uint32 Wyvern_Timer;
|
||||
uint32 Spit_Timer;
|
||||
uint32 PoisonBolt_Timer;
|
||||
uint32 NoxiousPoison_Timer;
|
||||
uint32 FrenzyBack_Timer;
|
||||
|
||||
bool Frenzy;
|
||||
bool Berserk;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_huhuranAI>(creature);
|
||||
Frenzy_Timer = urand(25000, 35000);
|
||||
Wyvern_Timer = urand(18000, 28000);
|
||||
Spit_Timer = 8000;
|
||||
PoisonBolt_Timer = 4000;
|
||||
NoxiousPoison_Timer = urand(10000, 20000);
|
||||
FrenzyBack_Timer = 15000;
|
||||
|
||||
Frenzy = false;
|
||||
Berserk = false;
|
||||
}
|
||||
|
||||
struct boss_huhuranAI : public ScriptedAI
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
boss_huhuranAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
uint32 Frenzy_Timer;
|
||||
uint32 Wyvern_Timer;
|
||||
uint32 Spit_Timer;
|
||||
uint32 PoisonBolt_Timer;
|
||||
uint32 NoxiousPoison_Timer;
|
||||
uint32 FrenzyBack_Timer;
|
||||
|
||||
bool Frenzy;
|
||||
bool Berserk;
|
||||
|
||||
void Reset() override
|
||||
//Frenzy_Timer
|
||||
if (!Frenzy && Frenzy_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_FRENZY);
|
||||
Talk(EMOTE_FRENZY_KILL);
|
||||
Frenzy = true;
|
||||
PoisonBolt_Timer = 3000;
|
||||
Frenzy_Timer = urand(25000, 35000);
|
||||
Wyvern_Timer = urand(18000, 28000);
|
||||
Spit_Timer = 8000;
|
||||
PoisonBolt_Timer = 4000;
|
||||
NoxiousPoison_Timer = urand(10000, 20000);
|
||||
FrenzyBack_Timer = 15000;
|
||||
|
||||
Frenzy = false;
|
||||
Berserk = false;
|
||||
}
|
||||
else Frenzy_Timer -= diff;
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
// Wyvern Timer
|
||||
if (Wyvern_Timer <= diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//Frenzy_Timer
|
||||
if (!Frenzy && Frenzy_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_FRENZY);
|
||||
Talk(EMOTE_FRENZY_KILL);
|
||||
Frenzy = true;
|
||||
PoisonBolt_Timer = 3000;
|
||||
Frenzy_Timer = urand(25000, 35000);
|
||||
}
|
||||
else Frenzy_Timer -= diff;
|
||||
|
||||
// Wyvern Timer
|
||||
if (Wyvern_Timer <= diff)
|
||||
{
|
||||
DoCastAOE(SPELL_WYVERNSTING);
|
||||
Wyvern_Timer = urand(15000, 32000);
|
||||
}
|
||||
else Wyvern_Timer -= diff;
|
||||
|
||||
//Spit Timer
|
||||
if (Spit_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_ACIDSPIT);
|
||||
Spit_Timer = urand(5000, 10000);
|
||||
}
|
||||
else Spit_Timer -= diff;
|
||||
|
||||
//NoxiousPoison_Timer
|
||||
if (NoxiousPoison_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_NOXIOUSPOISON);
|
||||
NoxiousPoison_Timer = urand(12000, 24000);
|
||||
}
|
||||
else NoxiousPoison_Timer -= diff;
|
||||
|
||||
//PoisonBolt only if frenzy or berserk
|
||||
if (Frenzy || Berserk)
|
||||
{
|
||||
if (PoisonBolt_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_POISONBOLT);
|
||||
PoisonBolt_Timer = 3000;
|
||||
}
|
||||
else PoisonBolt_Timer -= diff;
|
||||
}
|
||||
|
||||
//FrenzyBack_Timer
|
||||
if (Frenzy && FrenzyBack_Timer <= diff)
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
Frenzy = false;
|
||||
FrenzyBack_Timer = 15000;
|
||||
}
|
||||
else FrenzyBack_Timer -= diff;
|
||||
|
||||
if (!Berserk && HealthBelowPct(31))
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
Talk(EMOTE_BERSERK);
|
||||
DoCast(me, SPELL_BERSERK);
|
||||
Berserk = true;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
DoCastAOE(SPELL_WYVERNSTING);
|
||||
Wyvern_Timer = urand(15000, 32000);
|
||||
}
|
||||
};
|
||||
else Wyvern_Timer -= diff;
|
||||
|
||||
//Spit Timer
|
||||
if (Spit_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_ACIDSPIT);
|
||||
Spit_Timer = urand(5000, 10000);
|
||||
}
|
||||
else Spit_Timer -= diff;
|
||||
|
||||
//NoxiousPoison_Timer
|
||||
if (NoxiousPoison_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_NOXIOUSPOISON);
|
||||
NoxiousPoison_Timer = urand(12000, 24000);
|
||||
}
|
||||
else NoxiousPoison_Timer -= diff;
|
||||
|
||||
//PoisonBolt only if frenzy or berserk
|
||||
if (Frenzy || Berserk)
|
||||
{
|
||||
if (PoisonBolt_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_POISONBOLT);
|
||||
PoisonBolt_Timer = 3000;
|
||||
}
|
||||
else PoisonBolt_Timer -= diff;
|
||||
}
|
||||
|
||||
//FrenzyBack_Timer
|
||||
if (Frenzy && FrenzyBack_Timer <= diff)
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
Frenzy = false;
|
||||
FrenzyBack_Timer = 15000;
|
||||
}
|
||||
else FrenzyBack_Timer -= diff;
|
||||
|
||||
if (!Berserk && HealthBelowPct(31))
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
Talk(EMOTE_BERSERK);
|
||||
DoCast(me, SPELL_BERSERK);
|
||||
Berserk = true;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
// 26180 - Wyvern Sting
|
||||
@@ -173,6 +162,6 @@ class spell_huhuran_wyvern_sting : public AuraScript
|
||||
|
||||
void AddSC_boss_huhuran()
|
||||
{
|
||||
new boss_huhuran();
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_huhuran);
|
||||
RegisterSpellScript(spell_huhuran_wyvern_sting);
|
||||
}
|
||||
|
||||
@@ -15,188 +15,360 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Ouro
|
||||
SD%Complete: 85
|
||||
SDComment: No model for submerging. Currently just invisible.
|
||||
SDCategory: Temple of Ahn'Qiraj
|
||||
EndScriptData */
|
||||
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "temple_of_ahnqiraj.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// Ouro
|
||||
SPELL_SWEEP = 26103,
|
||||
SPELL_SANDBLAST = 26102,
|
||||
SPELL_SAND_BLAST = 26102,
|
||||
SPELL_GROUND_RUPTURE = 26100,
|
||||
SPELL_BIRTH = 26262, // The Birth Animation
|
||||
SPELL_BERSERK = 26615,
|
||||
SPELL_BOULDER = 26616,
|
||||
SPELL_OURO_SUBMERGE_VISUAL = 26063,
|
||||
SPELL_SUMMON_SANDWORM_BASE = 26133,
|
||||
|
||||
// Misc - Mounds, Ouro Spawner
|
||||
SPELL_BIRTH = 26586,
|
||||
SPELL_DIRTMOUND_PASSIVE = 26092,
|
||||
SPELL_SUMMON_OURO = 26061
|
||||
SPELL_SUMMON_OURO = 26061,
|
||||
SPELL_SUMMON_OURO_MOUNDS = 26058,
|
||||
SPELL_QUAKE = 26093,
|
||||
SPELL_SUMMON_SCARABS = 26060,
|
||||
SPELL_SUMMON_OURO_AURA = 26642,
|
||||
SPELL_DREAM_FOG = 24780
|
||||
};
|
||||
|
||||
class npc_ouro_spawner : public CreatureScript
|
||||
enum Misc
|
||||
{
|
||||
public:
|
||||
npc_ouro_spawner() : CreatureScript("npc_ouro_spawner") {}
|
||||
GROUP_EMERGED = 0,
|
||||
GROUP_PHASE_TRANSITION = 1,
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const
|
||||
{
|
||||
return new npc_ouro_spawnerAI(creature);
|
||||
}
|
||||
NPC_DIRT_MOUND = 15712,
|
||||
GO_SANDWORM_BASE = 180795,
|
||||
|
||||
struct npc_ouro_spawnerAI : public ScriptedAI
|
||||
{
|
||||
npc_ouro_spawnerAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
bool hasSummoned;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
hasSummoned = false;
|
||||
DoCast(me, SPELL_DIRTMOUND_PASSIVE);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
// Spawn Ouro on LoS check
|
||||
if (!hasSummoned && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 40.0f))
|
||||
{
|
||||
DoCast(me, SPELL_SUMMON_OURO);
|
||||
hasSummoned = true;
|
||||
}
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* creature) override
|
||||
{
|
||||
// Despawn when Ouro is spawned
|
||||
if (creature->GetEntry() == NPC_OURO)
|
||||
{
|
||||
creature->SetInCombatWithZone();
|
||||
creature->CastSpell(creature, SPELL_BIRTH, false);
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
DATA_OURO_HEALTH = 0
|
||||
};
|
||||
|
||||
class boss_ouro : public CreatureScript
|
||||
struct npc_ouro_spawner : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_ouro() : CreatureScript("boss_ouro") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
npc_ouro_spawner(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_ouroAI>(creature);
|
||||
Reset();
|
||||
}
|
||||
|
||||
struct boss_ouroAI : public ScriptedAI
|
||||
bool hasSummoned;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
boss_ouroAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
hasSummoned = false;
|
||||
DoCastSelf(SPELL_DIRTMOUND_PASSIVE);
|
||||
}
|
||||
|
||||
uint32 Sweep_Timer;
|
||||
uint32 SandBlast_Timer;
|
||||
uint32 Submerge_Timer;
|
||||
uint32 Back_Timer;
|
||||
uint32 ChangeTarget_Timer;
|
||||
uint32 Spawn_Timer;
|
||||
|
||||
bool Enrage;
|
||||
bool Submerged;
|
||||
|
||||
void Reset() override
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
// Spawn Ouro on LoS check
|
||||
if (!hasSummoned && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 40.0f) && !who->ToPlayer()->IsGameMaster())
|
||||
{
|
||||
Sweep_Timer = urand(5000, 10000);
|
||||
SandBlast_Timer = urand(20000, 35000);
|
||||
Submerge_Timer = urand(90000, 150000);
|
||||
Back_Timer = urand(30000, 45000);
|
||||
ChangeTarget_Timer = urand(5000, 8000);
|
||||
Spawn_Timer = urand(10000, 20000);
|
||||
|
||||
Enrage = false;
|
||||
Submerged = false;
|
||||
DoCastSelf(SPELL_SUMMON_OURO);
|
||||
hasSummoned = true;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* creature) override
|
||||
{
|
||||
// Despawn when Ouro is spawned
|
||||
if (creature->GetEntry() == NPC_OURO)
|
||||
{
|
||||
DoCastVictim(SPELL_BIRTH);
|
||||
creature->SetInCombatWithZone();
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct boss_ouro : public BossAI
|
||||
{
|
||||
boss_ouro(Creature* creature) : BossAI(creature, DATA_OURO)
|
||||
{
|
||||
SetCombatMovement(false);
|
||||
me->SetControlled(true, UNIT_STATE_ROOT);
|
||||
_scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); });
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (me->HealthBelowPctDamaged(20, damage) && !_enraged)
|
||||
{
|
||||
DoCastSelf(SPELL_BERSERK, true);
|
||||
_enraged = true;
|
||||
_scheduler.CancelGroup(GROUP_PHASE_TRANSITION);
|
||||
_scheduler.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
if (!IsPlayerWithinMeleeRange())
|
||||
DoSpellAttackToRandomTargetIfReady(SPELL_BOULDER);
|
||||
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(20s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_OURO_MOUNDS, true);
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Submerge()
|
||||
{
|
||||
me->AttackStop();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
|
||||
_submergeMelee = 0;
|
||||
_submerged = true;
|
||||
DoCastSelf(SPELL_OURO_SUBMERGE_VISUAL);
|
||||
_scheduler.CancelGroup(GROUP_EMERGED);
|
||||
_scheduler.CancelGroup(GROUP_PHASE_TRANSITION);
|
||||
|
||||
if (GameObject* base = me->FindNearestGameObject(GO_SANDWORM_BASE, 10.f))
|
||||
{
|
||||
base->Use(me);
|
||||
base->DespawnOrUnsummon(6s);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
DoCastSelf(SPELL_SUMMON_OURO_MOUNDS, true);
|
||||
// According to sniffs, Ouro uses his mounds to respawn. The health management could be a little scuffed.
|
||||
std::list<Creature*> ouroMounds;
|
||||
me->GetCreatureListWithEntryInGrid(ouroMounds, NPC_DIRT_MOUND, 200.f);
|
||||
if (!ouroMounds.empty()) // This can't be possible, but just to be sure.
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
//Sweep_Timer
|
||||
if (!Submerged && Sweep_Timer <= diff)
|
||||
if (Creature* mound = Acore::Containers::SelectRandomContainerElement(ouroMounds))
|
||||
{
|
||||
DoCastVictim(SPELL_SWEEP);
|
||||
Sweep_Timer = urand(15000, 30000);
|
||||
mound->AddAura(SPELL_SUMMON_OURO_AURA, mound);
|
||||
mound->AI()->SetData(DATA_OURO_HEALTH, me->GetHealth());
|
||||
}
|
||||
else Sweep_Timer -= diff;
|
||||
|
||||
//SandBlast_Timer
|
||||
if (!Submerged && SandBlast_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SANDBLAST);
|
||||
SandBlast_Timer = urand(20000, 35000);
|
||||
}
|
||||
else SandBlast_Timer -= diff;
|
||||
|
||||
//Submerge_Timer
|
||||
if (!Submerged && Submerge_Timer <= diff)
|
||||
{
|
||||
//Cast
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
DoCast(me, SPELL_DIRTMOUND_PASSIVE);
|
||||
|
||||
Submerged = true;
|
||||
Back_Timer = urand(30000, 45000);
|
||||
}
|
||||
else Submerge_Timer -= diff;
|
||||
|
||||
//ChangeTarget_Timer
|
||||
if (Submerged && ChangeTarget_Timer <= diff)
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
|
||||
|
||||
if (target)
|
||||
me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation());
|
||||
|
||||
ChangeTarget_Timer = urand(10000, 20000);
|
||||
}
|
||||
else ChangeTarget_Timer -= diff;
|
||||
|
||||
//Back_Timer
|
||||
if (Submerged && Back_Timer <= diff)
|
||||
{
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetFaction(FACTION_MONSTER);
|
||||
|
||||
DoCastVictim(SPELL_GROUND_RUPTURE);
|
||||
|
||||
Submerged = false;
|
||||
Submerge_Timer = urand(60000, 120000);
|
||||
}
|
||||
else Back_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
me->DespawnOrUnsummon(1000);
|
||||
}
|
||||
|
||||
void CastGroundRupture()
|
||||
{
|
||||
std::list<WorldObject*> targets;
|
||||
Acore::AllWorldObjectsInRange checker(me, 10.0f);
|
||||
Acore::WorldObjectListSearcher<Acore::AllWorldObjectsInRange> searcher(me, targets, checker);
|
||||
Cell::VisitAllObjects(me, searcher, 10.0f);
|
||||
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
if (Unit* unitTarget = target->ToUnit())
|
||||
{
|
||||
if (unitTarget->IsHostileTo(me))
|
||||
DoCast(unitTarget, SPELL_GROUND_RUPTURE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_SAND_BLAST && target)
|
||||
me->GetThreatMgr().modifyThreatPercent(target, 100);
|
||||
}
|
||||
|
||||
void Emerge()
|
||||
{
|
||||
DoCastSelf(SPELL_BIRTH);
|
||||
DoCastSelf(SPELL_SUMMON_SANDWORM_BASE, true);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
CastGroundRupture();
|
||||
_scheduler
|
||||
.Schedule(20s, GROUP_EMERGED, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SAND_BLAST);
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(22s, GROUP_EMERGED, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SWEEP);
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(90s, GROUP_PHASE_TRANSITION, [this](TaskContext /*context*/)
|
||||
{
|
||||
Submerge();
|
||||
})
|
||||
.Schedule(3s, GROUP_PHASE_TRANSITION, [this](TaskContext context)
|
||||
{
|
||||
if (!IsPlayerWithinMeleeRange() && !_submerged)
|
||||
{
|
||||
if (_submergeMelee < 10)
|
||||
{
|
||||
_submergeMelee++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_enraged)
|
||||
Submerge();
|
||||
_submergeMelee = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_submergeMelee = 0;
|
||||
}
|
||||
|
||||
if (!_submerged)
|
||||
context.Repeat(1s);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
instance->SetBossState(DATA_OURO, NOT_STARTED);
|
||||
_scheduler.CancelAll();
|
||||
_submergeMelee = 0;
|
||||
_submerged = false;
|
||||
_enraged = false;
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
DoCastSelf(SPELL_OURO_SUBMERGE_VISUAL);
|
||||
me->DespawnOrUnsummon(1000);
|
||||
// Remove after the header file is sorted with the bosses first.
|
||||
if (Creature* ouroSpawner = instance->GetCreature(DATA_OURO_SPAWNER))
|
||||
ouroSpawner->Respawn();
|
||||
instance->SetBossState(DATA_OURO, FAIL);
|
||||
if (GameObject* base = me->FindNearestGameObject(GO_SANDWORM_BASE, 200.f))
|
||||
base->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
Emerge();
|
||||
|
||||
BossAI::EnterCombat(who);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, [this]
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
TaskScheduler _scheduler;
|
||||
bool _enraged;
|
||||
uint8 _submergeMelee;
|
||||
bool _submerged;
|
||||
|
||||
bool IsPlayerWithinMeleeRange() const
|
||||
{
|
||||
return me->IsWithinMeleeRange(me->GetVictim());
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_dirt_mound : ScriptedAI
|
||||
{
|
||||
npc_dirt_mound(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* creature) override
|
||||
{
|
||||
if (creature->GetEntry() == NPC_OURO)
|
||||
{
|
||||
creature->SetInCombatWithZone();
|
||||
creature->SetHealth(_ouroHealth);
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
{
|
||||
if (type == DATA_OURO_HEALTH)
|
||||
_ouroHealth = data;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
DoZoneInCombat();
|
||||
_scheduler.Schedule(30s, [this](TaskContext /*context*/)
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_SCARABS, true);
|
||||
me->DespawnOrUnsummon(1000);
|
||||
})
|
||||
.Schedule(100ms, [this](TaskContext context)
|
||||
{
|
||||
ChaseNewTarget();
|
||||
context.Repeat(5s, 10s);
|
||||
});
|
||||
}
|
||||
|
||||
void ChaseNewTarget()
|
||||
{
|
||||
DoResetThreat();
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 200.f, true))
|
||||
{
|
||||
me->AddThreat(target, 1000000.f);
|
||||
AttackStart(target);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
DoCastSelf(SPELL_DIRTMOUND_PASSIVE, true);
|
||||
DoCastSelf(SPELL_DREAM_FOG, true);
|
||||
DoCastSelf(SPELL_QUAKE, true);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
if (_instance)
|
||||
{
|
||||
_instance->SetBossState(DATA_OURO, FAIL);
|
||||
|
||||
// Remove after the header file is sorted with the bosses first.
|
||||
if (Creature* ouroSpawner = _instance->GetCreature(DATA_OURO_SPAWNER))
|
||||
ouroSpawner->Respawn();
|
||||
}
|
||||
|
||||
if (GameObject* base = me->FindNearestGameObject(GO_SANDWORM_BASE, 200.f))
|
||||
base->DespawnOrUnsummon();
|
||||
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
protected:
|
||||
TaskScheduler _scheduler;
|
||||
uint32 _ouroHealth;
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
void AddSC_boss_ouro()
|
||||
{
|
||||
new npc_ouro_spawner();
|
||||
new boss_ouro();
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_ouro_spawner);
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_ouro);
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_dirt_mound);
|
||||
}
|
||||
|
||||
@@ -15,301 +15,314 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Sartura
|
||||
SD%Complete: 95
|
||||
SDComment:
|
||||
SDCategory: Temple of Ahn'Qiraj
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "temple_of_ahnqiraj.h"
|
||||
|
||||
enum Sartura
|
||||
enum Says
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_DEATH = 2,
|
||||
|
||||
SPELL_WHIRLWIND = 26083,
|
||||
SPELL_ENRAGE = 8269,
|
||||
SPELL_BERSERK = 27680,
|
||||
|
||||
//Guard Spell
|
||||
SPELL_WHIRLWINDADD = 26038,
|
||||
SPELL_KNOCKBACK = 26027
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_DEATH = 2
|
||||
};
|
||||
|
||||
class boss_sartura : public CreatureScript
|
||||
enum Spells
|
||||
{
|
||||
public:
|
||||
boss_sartura() : CreatureScript("boss_sartura") { }
|
||||
// Battleguard Sartura
|
||||
SPELL_WHIRLWIND = 26083, // MechanicImmunity->Stunned (15sec)
|
||||
SPELL_ENRAGE = 8269,
|
||||
SPELL_BERSERK = 27680,
|
||||
SPELL_SUNDERING_CLEAVE = 25174,
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_sarturaAI>(creature);
|
||||
}
|
||||
|
||||
struct boss_sarturaAI : public ScriptedAI
|
||||
{
|
||||
boss_sarturaAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 WhirlWind_Timer;
|
||||
uint32 WhirlWindRandom_Timer;
|
||||
uint32 WhirlWindEnd_Timer;
|
||||
uint32 AggroReset_Timer;
|
||||
uint32 AggroResetEnd_Timer;
|
||||
uint32 EnrageHard_Timer;
|
||||
|
||||
bool Enraged;
|
||||
bool EnragedHard;
|
||||
bool WhirlWind;
|
||||
bool AggroReset;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
WhirlWind_Timer = 30000;
|
||||
WhirlWindRandom_Timer = urand(3000, 7000);
|
||||
WhirlWindEnd_Timer = 15000;
|
||||
AggroReset_Timer = urand(45000, 55000);
|
||||
AggroResetEnd_Timer = 5000;
|
||||
EnrageHard_Timer = 10 * 60000;
|
||||
|
||||
WhirlWind = false;
|
||||
AggroReset = false;
|
||||
Enraged = false;
|
||||
EnragedHard = false;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (WhirlWind)
|
||||
{
|
||||
if (WhirlWindRandom_Timer <= diff)
|
||||
{
|
||||
//Attack random Gamers
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
|
||||
{
|
||||
me->AddThreat(target, 1.0f);
|
||||
me->TauntApply(target);
|
||||
AttackStart(target);
|
||||
}
|
||||
WhirlWindRandom_Timer = urand(3000, 7000);
|
||||
}
|
||||
else WhirlWindRandom_Timer -= diff;
|
||||
|
||||
if (WhirlWindEnd_Timer <= diff)
|
||||
{
|
||||
WhirlWind = false;
|
||||
WhirlWind_Timer = urand(25000, 40000);
|
||||
}
|
||||
else WhirlWindEnd_Timer -= diff;
|
||||
}
|
||||
|
||||
if (!WhirlWind)
|
||||
{
|
||||
if (WhirlWind_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_WHIRLWIND);
|
||||
WhirlWind = true;
|
||||
WhirlWindEnd_Timer = 15000;
|
||||
}
|
||||
else WhirlWind_Timer -= diff;
|
||||
|
||||
if (AggroReset_Timer <= diff)
|
||||
{
|
||||
//Attack random Gamers
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
|
||||
{
|
||||
me->AddThreat(target, 1.0f);
|
||||
me->TauntApply(target);
|
||||
AttackStart(target);
|
||||
}
|
||||
AggroReset = true;
|
||||
AggroReset_Timer = urand(2000, 5000);
|
||||
}
|
||||
else AggroReset_Timer -= diff;
|
||||
|
||||
if (AggroReset)
|
||||
{
|
||||
if (AggroResetEnd_Timer <= diff)
|
||||
{
|
||||
AggroReset = false;
|
||||
AggroResetEnd_Timer = 5000;
|
||||
AggroReset_Timer = urand(35000, 45000);
|
||||
}
|
||||
else AggroResetEnd_Timer -= diff;
|
||||
}
|
||||
|
||||
//If she is 20% enrage
|
||||
if (!Enraged)
|
||||
{
|
||||
if (!HealthAbovePct(20) && !me->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
DoCast(me, SPELL_ENRAGE, true);
|
||||
Enraged = true;
|
||||
}
|
||||
}
|
||||
|
||||
//After 10 minutes hard enrage
|
||||
if (!EnragedHard)
|
||||
{
|
||||
if (EnrageHard_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_BERSERK, true);
|
||||
EnragedHard = true;
|
||||
}
|
||||
else EnrageHard_Timer -= diff;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
};
|
||||
// Sartura's Royal Guard
|
||||
SPELL_GUARD_WHIRLWIND = 26038,
|
||||
SPELL_GUARD_KNOCKBACK = 26027
|
||||
};
|
||||
|
||||
class npc_sartura_royal_guard : public CreatureScript
|
||||
enum events
|
||||
{
|
||||
public:
|
||||
npc_sartura_royal_guard() : CreatureScript("npc_sartura_royal_guard") { }
|
||||
// Battleguard Sartura
|
||||
EVENT_SARTURA_WHIRLWIND = 1,
|
||||
EVENT_SARTURA_WHIRLWIND_RANDOM = 2,
|
||||
EVENT_SARTURA_WHIRLWIND_END = 3,
|
||||
EVENT_SPELL_BERSERK = 4,
|
||||
EVENT_SARTURA_AGGRO_RESET = 5,
|
||||
EVENT_SARTURA_AGGRO_RESET_END = 6,
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
// Sartura's Royal Guard
|
||||
EVENT_GUARD_WHIRLWIND = 7,
|
||||
EVENT_GUARD_WHIRLWIND_RANDOM = 8,
|
||||
EVENT_GUARD_WHIRLWIND_END = 9,
|
||||
EVENT_GUARD_KNOCKBACK = 10,
|
||||
EVENT_GUARD_AGGRO_RESET = 11,
|
||||
EVENT_GUARD_AGGRO_RESET_END = 12
|
||||
};
|
||||
|
||||
struct boss_sartura : public BossAI
|
||||
{
|
||||
boss_sartura(Creature* creature) : BossAI(creature, DATA_SARTURA) {}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<npc_sartura_royal_guardAI>(creature);
|
||||
_Reset();
|
||||
whirlwind = false;
|
||||
enraged = false;
|
||||
berserked = false;
|
||||
aggroReset = false;
|
||||
MinionReset();
|
||||
_savedTargetGUID.Clear();
|
||||
_savedTargetThreat = 0.f;
|
||||
}
|
||||
|
||||
struct npc_sartura_royal_guardAI : public ScriptedAI
|
||||
void MinionReset()
|
||||
{
|
||||
npc_sartura_royal_guardAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 WhirlWind_Timer;
|
||||
uint32 WhirlWindRandom_Timer;
|
||||
uint32 WhirlWindEnd_Timer;
|
||||
uint32 AggroReset_Timer;
|
||||
uint32 AggroResetEnd_Timer;
|
||||
uint32 KnockBack_Timer;
|
||||
|
||||
bool WhirlWind;
|
||||
bool AggroReset;
|
||||
|
||||
void Reset() override
|
||||
std::list<Creature*> royalGuards;
|
||||
me->GetCreaturesWithEntryInRange(royalGuards, 200.0f, NPC_SARTURA_ROYAL_GUARD);
|
||||
for (Creature* minion : royalGuards)
|
||||
{
|
||||
WhirlWind_Timer = 30000;
|
||||
WhirlWindRandom_Timer = urand(3000, 7000);
|
||||
WhirlWindEnd_Timer = 15000;
|
||||
AggroReset_Timer = urand(45000, 55000);
|
||||
AggroResetEnd_Timer = 5000;
|
||||
KnockBack_Timer = 10000;
|
||||
|
||||
WhirlWind = false;
|
||||
AggroReset = false;
|
||||
minion->Respawn();
|
||||
}
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
BossAI::EnterCombat(who);
|
||||
Talk(SAY_AGGRO);
|
||||
events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, 30000);
|
||||
events.ScheduleEvent(EVENT_SARTURA_AGGRO_RESET, urand(45000, 55000));
|
||||
events.ScheduleEvent(EVENT_SPELL_BERSERK, 10 * 60000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (!enraged && HealthBelowPct(20))
|
||||
{
|
||||
DoCastSelf(SPELL_ENRAGE);
|
||||
enraged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id != SPELL_SUNDERING_CLEAVE)
|
||||
return;
|
||||
|
||||
me->RemoveAura(SPELL_SUNDERING_CLEAVE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!WhirlWind && WhirlWind_Timer <= diff)
|
||||
switch (eventId)
|
||||
{
|
||||
DoCast(me, SPELL_WHIRLWINDADD);
|
||||
WhirlWind = true;
|
||||
WhirlWind_Timer = urand(25000, 40000);
|
||||
WhirlWindEnd_Timer = 15000;
|
||||
}
|
||||
else WhirlWind_Timer -= diff;
|
||||
|
||||
if (WhirlWind)
|
||||
{
|
||||
if (WhirlWindRandom_Timer <= diff)
|
||||
{
|
||||
//Attack random Gamers
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
|
||||
case EVENT_SARTURA_WHIRLWIND:
|
||||
DoCastSelf(SPELL_WHIRLWIND, true);
|
||||
whirlwind = true;
|
||||
events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND_RANDOM, urand(3000, 7000));
|
||||
events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND_END, 15000);
|
||||
break;
|
||||
case EVENT_SARTURA_WHIRLWIND_RANDOM:
|
||||
if (whirlwind == true)
|
||||
{
|
||||
me->AddThreat(target, 1.0f);
|
||||
me->TauntApply(target);
|
||||
AttackStart(target);
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
|
||||
{
|
||||
me->AddThreat(target, 1.0f);
|
||||
me->TauntApply(target);
|
||||
AttackStart(target);
|
||||
}
|
||||
events.RepeatEvent(urand(3000, 7000));
|
||||
}
|
||||
|
||||
WhirlWindRandom_Timer = urand(3000, 7000);
|
||||
}
|
||||
else WhirlWindRandom_Timer -= diff;
|
||||
|
||||
if (WhirlWindEnd_Timer <= diff)
|
||||
{
|
||||
WhirlWind = false;
|
||||
}
|
||||
else WhirlWindEnd_Timer -= diff;
|
||||
}
|
||||
|
||||
if (!WhirlWind)
|
||||
{
|
||||
if (AggroReset_Timer <= diff)
|
||||
{
|
||||
//Attack random Gamers
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
|
||||
break;
|
||||
case EVENT_SARTURA_WHIRLWIND_END:
|
||||
events.CancelEvent(EVENT_SARTURA_WHIRLWIND_RANDOM);
|
||||
whirlwind = false;
|
||||
events.ScheduleEvent(EVENT_SARTURA_WHIRLWIND, urand(25000, 40000));
|
||||
break;
|
||||
case EVENT_SARTURA_AGGRO_RESET:
|
||||
if (aggroReset == false)
|
||||
{
|
||||
me->AddThreat(target, 1.0f);
|
||||
me->TauntApply(target);
|
||||
AttackStart(target);
|
||||
if (Unit* originalTarget = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
_savedTargetGUID = originalTarget->GetGUID();
|
||||
_savedTargetThreat = me->GetThreatMgr().getThreat(originalTarget);
|
||||
me->GetThreatMgr().modifyThreatPercent(originalTarget, -100);
|
||||
}
|
||||
aggroReset = true;
|
||||
events.ScheduleEvent(EVENT_SARTURA_AGGRO_RESET_END, 5000);
|
||||
}
|
||||
|
||||
AggroReset = true;
|
||||
AggroReset_Timer = urand(2000, 5000);
|
||||
}
|
||||
else AggroReset_Timer -= diff;
|
||||
|
||||
if (KnockBack_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_WHIRLWINDADD);
|
||||
KnockBack_Timer = urand(10000, 20000);
|
||||
}
|
||||
else KnockBack_Timer -= diff;
|
||||
else
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
|
||||
{
|
||||
me->AddThreat(target, 1.0f);
|
||||
me->TauntApply(target);
|
||||
AttackStart(target);
|
||||
}
|
||||
}
|
||||
events.RepeatEvent(urand(1000, 2000));
|
||||
break;
|
||||
case EVENT_SARTURA_AGGRO_RESET_END:
|
||||
events.CancelEvent(EVENT_SARTURA_AGGRO_RESET);
|
||||
if (Unit* originalTarget = ObjectAccessor::GetUnit(*me, _savedTargetGUID))
|
||||
{
|
||||
me->GetThreatMgr().addThreat(originalTarget, _savedTargetThreat);
|
||||
_savedTargetGUID.Clear();
|
||||
}
|
||||
aggroReset = false;
|
||||
events.RescheduleEvent(EVENT_SARTURA_AGGRO_RESET, urand(30000, 40000));
|
||||
break;
|
||||
case EVENT_SPELL_BERSERK:
|
||||
if (!berserked)
|
||||
{
|
||||
DoCastSelf(SPELL_BERSERK);
|
||||
berserked = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (AggroReset)
|
||||
{
|
||||
if (AggroResetEnd_Timer <= diff)
|
||||
{
|
||||
AggroReset = false;
|
||||
AggroResetEnd_Timer = 5000;
|
||||
AggroReset_Timer = urand(30000, 40000);
|
||||
}
|
||||
else AggroResetEnd_Timer -= diff;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
};
|
||||
private:
|
||||
bool whirlwind;
|
||||
bool enraged;
|
||||
bool berserked;
|
||||
bool aggroReset;
|
||||
ObjectGuid _savedTargetGUID;
|
||||
float _savedTargetThreat;
|
||||
};
|
||||
|
||||
struct npc_sartura_royal_guard : public ScriptedAI
|
||||
{
|
||||
npc_sartura_royal_guard(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
whirlwind = false;
|
||||
aggroReset = false;
|
||||
_savedTargetGUID.Clear();
|
||||
_savedTargetThreat = 0.f;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_GUARD_WHIRLWIND, 30000);
|
||||
events.ScheduleEvent(EVENT_GUARD_AGGRO_RESET, urand(45000, 55000));
|
||||
events.ScheduleEvent(EVENT_GUARD_KNOCKBACK, 10000);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id != SPELL_SUNDERING_CLEAVE)
|
||||
return;
|
||||
|
||||
me->RemoveAura(SPELL_SUNDERING_CLEAVE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventid = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventid)
|
||||
{
|
||||
case EVENT_GUARD_WHIRLWIND:
|
||||
DoCastSelf(SPELL_GUARD_WHIRLWIND);
|
||||
whirlwind = true;
|
||||
events.ScheduleEvent(EVENT_GUARD_WHIRLWIND_RANDOM, urand(3000, 7000));
|
||||
events.ScheduleEvent(EVENT_GUARD_WHIRLWIND_END, 15000);
|
||||
break;
|
||||
case EVENT_GUARD_WHIRLWIND_RANDOM:
|
||||
if (whirlwind == true)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
|
||||
{
|
||||
me->AddThreat(target, 1.0f);
|
||||
me->TauntApply(target);
|
||||
AttackStart(target);
|
||||
}
|
||||
events.RepeatEvent(urand(3000, 7000));
|
||||
}
|
||||
break;
|
||||
case EVENT_GUARD_WHIRLWIND_END:
|
||||
events.CancelEvent(EVENT_GUARD_WHIRLWIND_RANDOM);
|
||||
whirlwind = false;
|
||||
events.ScheduleEvent(EVENT_GUARD_WHIRLWIND, urand(25000, 40000));
|
||||
break;
|
||||
case EVENT_GUARD_AGGRO_RESET:
|
||||
if (aggroReset == true)
|
||||
{
|
||||
if (Unit* originalTarget = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
_savedTargetGUID = originalTarget->GetGUID();
|
||||
_savedTargetThreat = me->GetThreatMgr().getThreat(originalTarget);
|
||||
me->GetThreatMgr().modifyThreatPercent(originalTarget, -100);
|
||||
}
|
||||
aggroReset = true;
|
||||
events.ScheduleEvent(EVENT_GUARD_AGGRO_RESET_END, 5000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true))
|
||||
{
|
||||
me->AddThreat(target, 1.0f);
|
||||
me->TauntApply(target);
|
||||
AttackStart(target);
|
||||
}
|
||||
}
|
||||
events.RepeatEvent(urand(1000, 2000));
|
||||
break;
|
||||
case EVENT_GUARD_AGGRO_RESET_END:
|
||||
events.CancelEvent(EVENT_GUARD_AGGRO_RESET);
|
||||
if (Unit* originalTarget = ObjectAccessor::GetUnit(*me, _savedTargetGUID))
|
||||
{
|
||||
me->GetThreatMgr().addThreat(originalTarget, _savedTargetThreat);
|
||||
_savedTargetGUID.Clear();
|
||||
}
|
||||
aggroReset = false;
|
||||
events.RescheduleEvent(EVENT_GUARD_AGGRO_RESET, urand(30000, 40000));
|
||||
break;
|
||||
case EVENT_GUARD_KNOCKBACK:
|
||||
DoCastVictim(SPELL_GUARD_KNOCKBACK);
|
||||
events.RepeatEvent(urand(10000, 20000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
bool whirlwind;
|
||||
bool aggroReset;
|
||||
ObjectGuid _savedTargetGUID;
|
||||
float _savedTargetThreat;
|
||||
};
|
||||
|
||||
void AddSC_boss_sartura()
|
||||
{
|
||||
new boss_sartura();
|
||||
new npc_sartura_royal_guard();
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_sartura);
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_sartura_royal_guard);
|
||||
}
|
||||
|
||||
@@ -47,183 +47,161 @@ enum Events
|
||||
|
||||
uint32 const BlinkSpells[3] = { 4801, 8195, 20449 };
|
||||
|
||||
class boss_skeram : public CreatureScript
|
||||
struct boss_skeram : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_skeram() : CreatureScript("boss_skeram") { }
|
||||
boss_skeram(Creature* creature) : BossAI(creature, DATA_SKERAM) { }
|
||||
|
||||
struct boss_skeramAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_skeramAI(Creature* creature) : BossAI(creature, DATA_SKERAM) { }
|
||||
_Reset();
|
||||
_flag = 0;
|
||||
_hpct = 75.0f;
|
||||
me->SetVisible(true);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
ScriptedAI::EnterEvadeMode(why);
|
||||
if (me->IsSummon())
|
||||
((TempSummon*)me)->UnSummon();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* creature) override
|
||||
{
|
||||
// Shift the boss and images (Get it? *Shift*?)
|
||||
uint8 rand = 0;
|
||||
if (_flag != 0)
|
||||
{
|
||||
_Reset();
|
||||
_flag = 0;
|
||||
_hpct = 75.0f;
|
||||
me->SetVisible(true);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
ScriptedAI::EnterEvadeMode(why);
|
||||
if (me->IsSummon())
|
||||
((TempSummon*)me)->UnSummon();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* creature) override
|
||||
{
|
||||
// Shift the boss and images (Get it? *Shift*?)
|
||||
uint8 rand = 0;
|
||||
if (_flag != 0)
|
||||
{
|
||||
while (_flag & (1 << rand))
|
||||
rand = urand(0, 2);
|
||||
DoCast(me, BlinkSpells[rand]);
|
||||
_flag |= (1 << rand);
|
||||
_flag |= (1 << 7);
|
||||
}
|
||||
|
||||
while (_flag & (1 << rand))
|
||||
rand = urand(0, 2);
|
||||
creature->CastSpell(creature, BlinkSpells[rand]);
|
||||
DoCast(me, BlinkSpells[rand]);
|
||||
_flag |= (1 << rand);
|
||||
|
||||
if (_flag & (1 << 7))
|
||||
_flag = 0;
|
||||
|
||||
float ImageHealthPct;
|
||||
|
||||
if (me->GetHealthPct() < 25.0f)
|
||||
ImageHealthPct = 0.50f;
|
||||
else if (me->GetHealthPct() < 50.0f)
|
||||
ImageHealthPct = 0.20f;
|
||||
else
|
||||
ImageHealthPct = 0.10f;
|
||||
|
||||
creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct);
|
||||
creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f));
|
||||
BossAI::JustSummoned(creature);
|
||||
_flag |= (1 << 7);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (!me->IsSummon())
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
else
|
||||
me->RemoveCorpse();
|
||||
}
|
||||
while (_flag & (1 << rand))
|
||||
rand = urand(0, 2);
|
||||
creature->CastSpell(creature, BlinkSpells[rand]);
|
||||
_flag |= (1 << rand);
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.Reset();
|
||||
if (_flag & (1 << 7))
|
||||
_flag = 0;
|
||||
|
||||
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(6000, 12000));
|
||||
events.ScheduleEvent(EVENT_FULLFILMENT, 15000);
|
||||
events.ScheduleEvent(EVENT_BLINK, urand(30000, 45000));
|
||||
events.ScheduleEvent(EVENT_EARTH_SHOCK, 2000);
|
||||
float ImageHealthPct;
|
||||
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
if (me->GetHealthPct() < 25.0f)
|
||||
ImageHealthPct = 0.50f;
|
||||
else if (me->GetHealthPct() < 50.0f)
|
||||
ImageHealthPct = 0.20f;
|
||||
else
|
||||
ImageHealthPct = 0.10f;
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ARCANE_EXPLOSION:
|
||||
DoCastAOE(SPELL_ARCANE_EXPLOSION, true);
|
||||
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(8000, 18000));
|
||||
break;
|
||||
case EVENT_FULLFILMENT:
|
||||
/// @todo For some weird reason boss does not cast this
|
||||
// Spell actually works, tested in duel
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true), SPELL_TRUE_FULFILLMENT, true);
|
||||
events.ScheduleEvent(EVENT_FULLFILMENT, urand(20000, 30000));
|
||||
break;
|
||||
case EVENT_BLINK:
|
||||
DoCast(me, BlinkSpells[urand(0, 2)]);
|
||||
DoResetThreat();
|
||||
me->SetVisible(true);
|
||||
events.ScheduleEvent(EVENT_BLINK, urand(10000, 30000));
|
||||
break;
|
||||
case EVENT_EARTH_SHOCK:
|
||||
DoCastVictim(SPELL_EARTH_SHOCK);
|
||||
events.ScheduleEvent(EVENT_EARTH_SHOCK, 2000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!me->IsSummon() && me->GetHealthPct() < _hpct)
|
||||
{
|
||||
DoCast(me, SPELL_SUMMON_IMAGES, true);
|
||||
Talk(SAY_SPLIT);
|
||||
_hpct -= 25.0f;
|
||||
me->SetVisible(false);
|
||||
events.RescheduleEvent(EVENT_BLINK, 2000);
|
||||
}
|
||||
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
events.RescheduleEvent(EVENT_EARTH_SHOCK, 2000);
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
float _hpct;
|
||||
uint8 _flag;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_skeramAI>(creature);
|
||||
creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct);
|
||||
creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f));
|
||||
BossAI::JustSummoned(creature);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (!me->IsSummon())
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
else
|
||||
me->RemoveCorpse();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.Reset();
|
||||
|
||||
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 6s, 12s);
|
||||
events.ScheduleEvent(EVENT_FULLFILMENT, 15s);
|
||||
events.ScheduleEvent(EVENT_BLINK, 30s, 45s);
|
||||
events.ScheduleEvent(EVENT_EARTH_SHOCK, 2s);
|
||||
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ARCANE_EXPLOSION:
|
||||
DoCastAOE(SPELL_ARCANE_EXPLOSION, true);
|
||||
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 8s, 18s);
|
||||
break;
|
||||
case EVENT_FULLFILMENT:
|
||||
/// @todo For some weird reason boss does not cast this
|
||||
// Spell actually works, tested in duel
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true), SPELL_TRUE_FULFILLMENT, true);
|
||||
events.ScheduleEvent(EVENT_FULLFILMENT, 20s, 30s);
|
||||
break;
|
||||
case EVENT_BLINK:
|
||||
DoCast(me, BlinkSpells[urand(0, 2)]);
|
||||
DoResetThreat();
|
||||
me->SetVisible(true);
|
||||
events.ScheduleEvent(EVENT_BLINK, 10s, 30s);
|
||||
break;
|
||||
case EVENT_EARTH_SHOCK:
|
||||
DoCastVictim(SPELL_EARTH_SHOCK);
|
||||
events.ScheduleEvent(EVENT_EARTH_SHOCK, 2s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!me->IsSummon() && me->GetHealthPct() < _hpct)
|
||||
{
|
||||
DoCast(me, SPELL_SUMMON_IMAGES, true);
|
||||
Talk(SAY_SPLIT);
|
||||
_hpct -= 25.0f;
|
||||
me->SetVisible(false);
|
||||
events.RescheduleEvent(EVENT_BLINK, 2s);
|
||||
}
|
||||
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
events.RescheduleEvent(EVENT_EARTH_SHOCK, 2s);
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
float _hpct;
|
||||
uint8 _flag;
|
||||
};
|
||||
|
||||
class spell_skeram_arcane_explosion : public SpellScriptLoader
|
||||
class spell_skeram_arcane_explosion : public SpellScript
|
||||
{
|
||||
public:
|
||||
spell_skeram_arcane_explosion() : SpellScriptLoader("spell_skeram_arcane_explosion") { }
|
||||
PrepareSpellScript(spell_skeram_arcane_explosion);
|
||||
|
||||
class spell_skeram_arcane_explosion_SpellScript : public SpellScript
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
PrepareSpellScript(spell_skeram_arcane_explosion_SpellScript);
|
||||
targets.remove_if(PlayerOrPetCheck());
|
||||
}
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
targets.remove_if(PlayerOrPetCheck());
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_skeram_arcane_explosion_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
void Register() override
|
||||
{
|
||||
return new spell_skeram_arcane_explosion_SpellScript();
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_skeram_arcane_explosion::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_skeram()
|
||||
{
|
||||
new boss_skeram();
|
||||
new spell_skeram_arcane_explosion();
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_skeram);
|
||||
RegisterSpellScript(spell_skeram_arcane_explosion);
|
||||
}
|
||||
|
||||
@@ -377,223 +377,203 @@ struct boss_twinemperorsAI : public ScriptedAI
|
||||
}
|
||||
};
|
||||
|
||||
class boss_veknilash : public CreatureScript
|
||||
struct boss_veknilash : public boss_twinemperorsAI
|
||||
{
|
||||
public:
|
||||
boss_veknilash() : CreatureScript("boss_veknilash") { }
|
||||
boss_veknilash(Creature* creature) : boss_twinemperorsAI(creature) { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
bool IAmVeklor() override { return false; }
|
||||
|
||||
uint32 UpperCut_Timer;
|
||||
uint32 UnbalancingStrike_Timer;
|
||||
uint32 Scarabs_Timer;
|
||||
int Rand;
|
||||
int RandX;
|
||||
int RandY;
|
||||
|
||||
Creature* Summoned;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_veknilashAI>(creature);
|
||||
TwinReset();
|
||||
UpperCut_Timer = urand(14000, 29000);
|
||||
UnbalancingStrike_Timer = urand(8000, 18000);
|
||||
Scarabs_Timer = urand(7000, 14000);
|
||||
|
||||
//Added. Can be removed if its included in DB.
|
||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true);
|
||||
}
|
||||
|
||||
struct boss_veknilashAI : public boss_twinemperorsAI
|
||||
void CastSpellOnBug(Creature* target) override
|
||||
{
|
||||
bool IAmVeklor() override {return false;}
|
||||
boss_veknilashAI(Creature* creature) : boss_twinemperorsAI(creature) { }
|
||||
target->SetFaction(FACTION_MONSTER);
|
||||
target->AI()->AttackStart(me->GetThreatMgr().getHostileTarget());
|
||||
target->AddAura(SPELL_MUTATE_BUG, target);
|
||||
target->SetFullHealth();
|
||||
}
|
||||
|
||||
uint32 UpperCut_Timer;
|
||||
uint32 UnbalancingStrike_Timer;
|
||||
uint32 Scarabs_Timer;
|
||||
int Rand;
|
||||
int RandX;
|
||||
int RandY;
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
Creature* Summoned;
|
||||
if (!TryActivateAfterTTelep(diff))
|
||||
return;
|
||||
|
||||
void Reset() override
|
||||
//UnbalancingStrike_Timer
|
||||
if (UnbalancingStrike_Timer <= diff)
|
||||
{
|
||||
TwinReset();
|
||||
UpperCut_Timer = urand(14000, 29000);
|
||||
UnbalancingStrike_Timer = urand(8000, 18000);
|
||||
Scarabs_Timer = urand(7000, 14000);
|
||||
|
||||
//Added. Can be removed if its included in DB.
|
||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true);
|
||||
DoCastVictim(SPELL_UNBALANCING_STRIKE);
|
||||
UnbalancingStrike_Timer = 8000 + rand() % 12000;
|
||||
}
|
||||
else UnbalancingStrike_Timer -= diff;
|
||||
|
||||
void CastSpellOnBug(Creature* target) override
|
||||
if (UpperCut_Timer <= diff)
|
||||
{
|
||||
target->SetFaction(FACTION_MONSTER);
|
||||
target->AI()->AttackStart(me->GetThreatMgr().getHostileTarget());
|
||||
target->AddAura(SPELL_MUTATE_BUG, target);
|
||||
target->SetFullHealth();
|
||||
Unit* randomMelee = SelectTarget(SelectTargetMethod::Random, 0, NOMINAL_MELEE_RANGE, true);
|
||||
if (randomMelee)
|
||||
DoCast(randomMelee, SPELL_UPPERCUT);
|
||||
UpperCut_Timer = 15000 + rand() % 15000;
|
||||
}
|
||||
else UpperCut_Timer -= diff;
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
HandleBugs(diff);
|
||||
|
||||
//Heal brother when 60yrds close
|
||||
TryHealBrother(diff);
|
||||
|
||||
//Teleporting to brother
|
||||
if (Teleport_Timer <= diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!TryActivateAfterTTelep(diff))
|
||||
return;
|
||||
|
||||
//UnbalancingStrike_Timer
|
||||
if (UnbalancingStrike_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_UNBALANCING_STRIKE);
|
||||
UnbalancingStrike_Timer = 8000 + rand() % 12000;
|
||||
}
|
||||
else UnbalancingStrike_Timer -= diff;
|
||||
|
||||
if (UpperCut_Timer <= diff)
|
||||
{
|
||||
Unit* randomMelee = SelectTarget(SelectTargetMethod::Random, 0, NOMINAL_MELEE_RANGE, true);
|
||||
if (randomMelee)
|
||||
DoCast(randomMelee, SPELL_UPPERCUT);
|
||||
UpperCut_Timer = 15000 + rand() % 15000;
|
||||
}
|
||||
else UpperCut_Timer -= diff;
|
||||
|
||||
HandleBugs(diff);
|
||||
|
||||
//Heal brother when 60yrds close
|
||||
TryHealBrother(diff);
|
||||
|
||||
//Teleporting to brother
|
||||
if (Teleport_Timer <= diff)
|
||||
{
|
||||
TeleportToMyBrother();
|
||||
}
|
||||
else Teleport_Timer -= diff;
|
||||
|
||||
CheckEnrage(diff);
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
TeleportToMyBrother();
|
||||
}
|
||||
};
|
||||
else Teleport_Timer -= diff;
|
||||
|
||||
CheckEnrage(diff);
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
class boss_veklor : public CreatureScript
|
||||
struct boss_veklor : public boss_twinemperorsAI
|
||||
{
|
||||
public:
|
||||
boss_veklor() : CreatureScript("boss_veklor") { }
|
||||
boss_veklor(Creature* creature) : boss_twinemperorsAI(creature) { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
bool IAmVeklor() override { return true; }
|
||||
|
||||
uint32 ShadowBolt_Timer;
|
||||
uint32 Blizzard_Timer;
|
||||
uint32 ArcaneBurst_Timer;
|
||||
uint32 Scorpions_Timer;
|
||||
int Rand;
|
||||
int RandX;
|
||||
|
||||
Creature* Summoned;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_veklorAI>(creature);
|
||||
TwinReset();
|
||||
ShadowBolt_Timer = 0;
|
||||
Blizzard_Timer = urand(15000, 20000);
|
||||
ArcaneBurst_Timer = 1000;
|
||||
Scorpions_Timer = urand(7000, 14000);
|
||||
|
||||
//Added. Can be removed if its included in DB.
|
||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true);
|
||||
}
|
||||
|
||||
struct boss_veklorAI : public boss_twinemperorsAI
|
||||
void CastSpellOnBug(Creature* target) override
|
||||
{
|
||||
bool IAmVeklor() override {return true;}
|
||||
boss_veklorAI(Creature* creature) : boss_twinemperorsAI(creature) { }
|
||||
target->SetFaction(FACTION_MONSTER);
|
||||
target->AddAura(SPELL_EXPLODEBUG, target);
|
||||
target->SetFullHealth();
|
||||
}
|
||||
|
||||
uint32 ShadowBolt_Timer;
|
||||
uint32 Blizzard_Timer;
|
||||
uint32 ArcaneBurst_Timer;
|
||||
uint32 Scorpions_Timer;
|
||||
int Rand;
|
||||
int RandX;
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
Creature* Summoned;
|
||||
// reset arcane burst after teleport - we need to do this because
|
||||
// when VL jumps to VN's location there will be a warrior who will get only 2s to run away
|
||||
// which is almost impossible
|
||||
if (AfterTeleport)
|
||||
ArcaneBurst_Timer = 5000;
|
||||
if (!TryActivateAfterTTelep(diff))
|
||||
return;
|
||||
|
||||
void Reset() override
|
||||
//ShadowBolt_Timer
|
||||
if (ShadowBolt_Timer <= diff)
|
||||
{
|
||||
TwinReset();
|
||||
ShadowBolt_Timer = 0;
|
||||
Blizzard_Timer = urand(15000, 20000);
|
||||
ArcaneBurst_Timer = 1000;
|
||||
Scorpions_Timer = urand(7000, 14000);
|
||||
|
||||
//Added. Can be removed if its included in DB.
|
||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true);
|
||||
if (!me->IsWithinDist(me->GetVictim(), 45.0f))
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), VEKLOR_DIST, 0);
|
||||
else
|
||||
DoCastVictim(SPELL_SHADOWBOLT);
|
||||
ShadowBolt_Timer = 2000;
|
||||
}
|
||||
else ShadowBolt_Timer -= diff;
|
||||
|
||||
void CastSpellOnBug(Creature* target) override
|
||||
//Blizzard_Timer
|
||||
if (Blizzard_Timer <= diff)
|
||||
{
|
||||
target->SetFaction(FACTION_MONSTER);
|
||||
target->AddAura(SPELL_EXPLODEBUG, target);
|
||||
target->SetFullHealth();
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45, true);
|
||||
if (target)
|
||||
{
|
||||
DoCast(target, SPELL_BLIZZARD);
|
||||
}
|
||||
Blizzard_Timer = 15000 + rand() % 15000;
|
||||
}
|
||||
else Blizzard_Timer -= diff;
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
if (ArcaneBurst_Timer <= diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
// reset arcane burst after teleport - we need to do this because
|
||||
// when VL jumps to VN's location there will be a warrior who will get only 2s to run away
|
||||
// which is almost impossible
|
||||
if (AfterTeleport)
|
||||
Unit* mvic;
|
||||
if ((mvic = SelectTarget(SelectTargetMethod::MaxDistance, 0, NOMINAL_MELEE_RANGE, true)) != nullptr)
|
||||
{
|
||||
DoCast(mvic, SPELL_ARCANEBURST);
|
||||
ArcaneBurst_Timer = 5000;
|
||||
if (!TryActivateAfterTTelep(diff))
|
||||
return;
|
||||
|
||||
//ShadowBolt_Timer
|
||||
if (ShadowBolt_Timer <= diff)
|
||||
{
|
||||
if (!me->IsWithinDist(me->GetVictim(), 45.0f))
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), VEKLOR_DIST, 0);
|
||||
else
|
||||
DoCastVictim(SPELL_SHADOWBOLT);
|
||||
ShadowBolt_Timer = 2000;
|
||||
}
|
||||
else ShadowBolt_Timer -= diff;
|
||||
|
||||
//Blizzard_Timer
|
||||
if (Blizzard_Timer <= diff)
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45, true);
|
||||
if (target)
|
||||
{
|
||||
DoCast(target, SPELL_BLIZZARD);
|
||||
}
|
||||
Blizzard_Timer = 15000 + rand() % 15000;
|
||||
}
|
||||
else Blizzard_Timer -= diff;
|
||||
|
||||
if (ArcaneBurst_Timer <= diff)
|
||||
{
|
||||
Unit* mvic;
|
||||
if ((mvic = SelectTarget(SelectTargetMethod::MaxDistance, 0, NOMINAL_MELEE_RANGE, true)) != nullptr)
|
||||
{
|
||||
DoCast(mvic, SPELL_ARCANEBURST);
|
||||
ArcaneBurst_Timer = 5000;
|
||||
}
|
||||
}
|
||||
else ArcaneBurst_Timer -= diff;
|
||||
|
||||
HandleBugs(diff);
|
||||
|
||||
//Heal brother when 60yrds close
|
||||
TryHealBrother(diff);
|
||||
|
||||
//Teleporting to brother
|
||||
if (Teleport_Timer <= diff)
|
||||
{
|
||||
TeleportToMyBrother();
|
||||
}
|
||||
else Teleport_Timer -= diff;
|
||||
|
||||
CheckEnrage(diff);
|
||||
|
||||
//VL doesn't melee
|
||||
//DoMeleeAttackIfReady();
|
||||
}
|
||||
else ArcaneBurst_Timer -= diff;
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
HandleBugs(diff);
|
||||
|
||||
//Heal brother when 60yrds close
|
||||
TryHealBrother(diff);
|
||||
|
||||
//Teleporting to brother
|
||||
if (Teleport_Timer <= diff)
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
TeleportToMyBrother();
|
||||
}
|
||||
else Teleport_Timer -= diff;
|
||||
|
||||
if (who->isTargetableForAttack())
|
||||
CheckEnrage(diff);
|
||||
|
||||
//VL doesn't melee
|
||||
//DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (who->isTargetableForAttack())
|
||||
{
|
||||
// VL doesn't melee
|
||||
if (me->Attack(who, false))
|
||||
{
|
||||
// VL doesn't melee
|
||||
if (me->Attack(who, false))
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0);
|
||||
me->AddThreat(who, 0.0f);
|
||||
}
|
||||
me->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0);
|
||||
me->AddThreat(who, 0.0f);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_twinemperors()
|
||||
{
|
||||
new boss_veknilash();
|
||||
new boss_veklor();
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_veknilash);
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_veklor);
|
||||
}
|
||||
|
||||
@@ -84,223 +84,201 @@ enum MovePoints
|
||||
Position const ViscidusCoord = { -7992.36f, 908.19f, -52.62f, 1.68f }; /// @todo Visci isn't in room middle
|
||||
float const RoomRadius = 40.0f; /// @todo Not sure if its correct
|
||||
|
||||
class boss_viscidus : public CreatureScript
|
||||
struct boss_viscidus : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_viscidus() : CreatureScript("boss_viscidus") { }
|
||||
boss_viscidus(Creature* creature) : BossAI(creature, DATA_VISCIDUS) { }
|
||||
|
||||
struct boss_viscidusAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_viscidusAI(Creature* creature) : BossAI(creature, DATA_VISCIDUS) { }
|
||||
_Reset();
|
||||
_hitcounter = 0;
|
||||
_phase = PHASE_FROST;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void DamageTaken(Unit* attacker, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (!attacker || _phase != PHASE_MELEE)
|
||||
return;
|
||||
|
||||
++_hitcounter;
|
||||
|
||||
if (attacker->HasUnitState(UNIT_STATE_MELEE_ATTACKING) && _hitcounter >= HITCOUNTER_EXPLODE)
|
||||
{
|
||||
_Reset();
|
||||
_hitcounter = 0;
|
||||
_phase = PHASE_FROST;
|
||||
Talk(EMOTE_EXPLODE);
|
||||
events.Reset();
|
||||
_phase = PHASE_GLOB;
|
||||
DoCast(me, SPELL_VISCIDUS_EXPLODE);
|
||||
me->SetVisible(false);
|
||||
me->RemoveAura(SPELL_TOXIN);
|
||||
me->RemoveAura(SPELL_VISCIDUS_FREEZE);
|
||||
|
||||
uint8 NumGlobes = me->GetHealthPct() / 5.0f;
|
||||
for (uint8 i = 0; i < NumGlobes; ++i)
|
||||
{
|
||||
float Angle = i * 2 * M_PI / NumGlobes;
|
||||
float X = ViscidusCoord.GetPositionX() + std::cos(Angle) * RoomRadius;
|
||||
float Y = ViscidusCoord.GetPositionY() + std::sin(Angle) * RoomRadius;
|
||||
float Z = -35.0f;
|
||||
|
||||
if (TempSummon* Glob = me->SummonCreature(NPC_GLOB_OF_VISCIDUS, X, Y, Z))
|
||||
{
|
||||
Glob->UpdateAllowedPositionZ(X, Y, Z);
|
||||
Glob->NearTeleportTo(X, Y, Z, 0.0f);
|
||||
Glob->GetMotionMaster()->MovePoint(ROOM_CENTER, ViscidusCoord);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_hitcounter == HITCOUNTER_SHATTER)
|
||||
Talk(EMOTE_SHATTER);
|
||||
else if (_hitcounter == HITCOUNTER_CRACK)
|
||||
Talk(EMOTE_CRACK);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* attacker, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
{
|
||||
if ((spell->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST && me->GetHealthPct() > 5.0f)
|
||||
{
|
||||
if (!attacker || _phase != PHASE_MELEE)
|
||||
return;
|
||||
|
||||
++_hitcounter;
|
||||
|
||||
if (attacker->HasUnitState(UNIT_STATE_MELEE_ATTACKING) && _hitcounter >= HITCOUNTER_EXPLODE)
|
||||
if (_hitcounter >= HITCOUNTER_FREEZE)
|
||||
{
|
||||
Talk(EMOTE_EXPLODE);
|
||||
events.Reset();
|
||||
_phase = PHASE_GLOB;
|
||||
DoCast(me, SPELL_VISCIDUS_EXPLODE);
|
||||
me->SetVisible(false);
|
||||
me->RemoveAura(SPELL_TOXIN);
|
||||
me->RemoveAura(SPELL_VISCIDUS_FREEZE);
|
||||
|
||||
uint8 NumGlobes = me->GetHealthPct() / 5.0f;
|
||||
for (uint8 i = 0; i < NumGlobes; ++i)
|
||||
{
|
||||
float Angle = i * 2 * M_PI / NumGlobes;
|
||||
float X = ViscidusCoord.GetPositionX() + std::cos(Angle) * RoomRadius;
|
||||
float Y = ViscidusCoord.GetPositionY() + std::sin(Angle) * RoomRadius;
|
||||
float Z = -35.0f;
|
||||
|
||||
if (TempSummon* Glob = me->SummonCreature(NPC_GLOB_OF_VISCIDUS, X, Y, Z))
|
||||
{
|
||||
Glob->UpdateAllowedPositionZ(X, Y, Z);
|
||||
Glob->NearTeleportTo(X, Y, Z, 0.0f);
|
||||
Glob->GetMotionMaster()->MovePoint(ROOM_CENTER, ViscidusCoord);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_hitcounter == HITCOUNTER_SHATTER)
|
||||
Talk(EMOTE_SHATTER);
|
||||
else if (_hitcounter == HITCOUNTER_CRACK)
|
||||
Talk(EMOTE_CRACK);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
{
|
||||
if ((spell->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST && me->GetHealthPct() > 5.0f)
|
||||
{
|
||||
++_hitcounter;
|
||||
|
||||
if (_hitcounter >= HITCOUNTER_FREEZE)
|
||||
{
|
||||
_hitcounter = 0;
|
||||
Talk(EMOTE_FROZEN);
|
||||
_phase = PHASE_MELEE;
|
||||
DoCast(me, SPELL_VISCIDUS_FREEZE);
|
||||
me->RemoveAura(SPELL_VISCIDUS_SLOWED_MORE);
|
||||
events.ScheduleEvent(EVENT_RESET_PHASE, 15000);
|
||||
}
|
||||
else if (_hitcounter >= HITCOUNTER_SLOW_MORE)
|
||||
{
|
||||
Talk(EMOTE_FREEZE);
|
||||
me->RemoveAura(SPELL_VISCIDUS_SLOWED);
|
||||
DoCast(me, SPELL_VISCIDUS_SLOWED_MORE);
|
||||
}
|
||||
else if (_hitcounter >= HITCOUNTER_SLOW)
|
||||
{
|
||||
Talk(EMOTE_SLOW);
|
||||
DoCast(me, SPELL_VISCIDUS_SLOWED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.Reset();
|
||||
InitSpells();
|
||||
}
|
||||
|
||||
void InitSpells()
|
||||
{
|
||||
DoCast(me, SPELL_TOXIN);
|
||||
events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, urand(10000, 15000));
|
||||
events.ScheduleEvent(EVENT_POISON_SHOCK, urand(7000, 12000));
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
summons.DespawnAll();
|
||||
ScriptedAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
DoCast(me, SPELL_VISCIDUS_SUICIDE);
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (_phase == PHASE_GLOB && summons.empty())
|
||||
{
|
||||
DoResetThreat();
|
||||
me->NearTeleportTo(ViscidusCoord.GetPositionX(),
|
||||
ViscidusCoord.GetPositionY(),
|
||||
ViscidusCoord.GetPositionZ(),
|
||||
ViscidusCoord.GetOrientation());
|
||||
|
||||
_hitcounter = 0;
|
||||
_phase = PHASE_FROST;
|
||||
InitSpells();
|
||||
me->SetVisible(true);
|
||||
Talk(EMOTE_FROZEN);
|
||||
_phase = PHASE_MELEE;
|
||||
DoCast(me, SPELL_VISCIDUS_FREEZE);
|
||||
me->RemoveAura(SPELL_VISCIDUS_SLOWED_MORE);
|
||||
events.ScheduleEvent(EVENT_RESET_PHASE, 15000);
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
else if (_hitcounter >= HITCOUNTER_SLOW_MORE)
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_POISONBOLT_VOLLEY:
|
||||
DoCast(me, SPELL_POISONBOLT_VOLLEY);
|
||||
events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, urand(10000, 15000));
|
||||
break;
|
||||
case EVENT_POISON_SHOCK:
|
||||
DoCast(me, SPELL_POISON_SHOCK);
|
||||
events.ScheduleEvent(EVENT_POISON_SHOCK, urand(7000, 12000));
|
||||
break;
|
||||
case EVENT_RESET_PHASE:
|
||||
_hitcounter = 0;
|
||||
_phase = PHASE_FROST;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Talk(EMOTE_FREEZE);
|
||||
me->RemoveAura(SPELL_VISCIDUS_SLOWED);
|
||||
DoCast(me, SPELL_VISCIDUS_SLOWED_MORE);
|
||||
}
|
||||
else if (_hitcounter >= HITCOUNTER_SLOW)
|
||||
{
|
||||
Talk(EMOTE_SLOW);
|
||||
DoCast(me, SPELL_VISCIDUS_SLOWED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_phase != PHASE_GLOB)
|
||||
DoMeleeAttackIfReady();
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.Reset();
|
||||
InitSpells();
|
||||
}
|
||||
|
||||
void InitSpells()
|
||||
{
|
||||
DoCast(me, SPELL_TOXIN);
|
||||
events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, 10s, 15s);
|
||||
events.ScheduleEvent(EVENT_POISON_SHOCK, 7s, 12s);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
summons.DespawnAll();
|
||||
ScriptedAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
DoCast(me, SPELL_VISCIDUS_SUICIDE);
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (_phase == PHASE_GLOB && summons.empty())
|
||||
{
|
||||
DoResetThreat();
|
||||
me->NearTeleportTo(ViscidusCoord.GetPositionX(),
|
||||
ViscidusCoord.GetPositionY(),
|
||||
ViscidusCoord.GetPositionZ(),
|
||||
ViscidusCoord.GetOrientation());
|
||||
|
||||
_hitcounter = 0;
|
||||
_phase = PHASE_FROST;
|
||||
InitSpells();
|
||||
me->SetVisible(true);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 _hitcounter;
|
||||
Phases _phase;
|
||||
};
|
||||
events.Update(diff);
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<boss_viscidusAI>(creature);
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_POISONBOLT_VOLLEY:
|
||||
DoCast(me, SPELL_POISONBOLT_VOLLEY);
|
||||
events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, 10s, 15s);
|
||||
break;
|
||||
case EVENT_POISON_SHOCK:
|
||||
DoCast(me, SPELL_POISON_SHOCK);
|
||||
events.ScheduleEvent(EVENT_POISON_SHOCK, 7s, 12s);
|
||||
break;
|
||||
case EVENT_RESET_PHASE:
|
||||
_hitcounter = 0;
|
||||
_phase = PHASE_FROST;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_phase != PHASE_GLOB)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 _hitcounter;
|
||||
Phases _phase;
|
||||
};
|
||||
|
||||
class npc_glob_of_viscidus : public CreatureScript
|
||||
struct boss_glob_of_viscidus : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_glob_of_viscidus() : CreatureScript("boss_glob_of_viscidus") { }
|
||||
boss_glob_of_viscidus(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
struct npc_glob_of_viscidusAI : public ScriptedAI
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
npc_glob_of_viscidusAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
InstanceScript* instance = me->GetInstanceScript();
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
if (Creature* viscidus = me->GetMap()->GetCreature(instance->GetGuidData(DATA_VISCIDUS)))
|
||||
{
|
||||
InstanceScript* Instance = me->GetInstanceScript();
|
||||
if (BossAI* viscidusAI = dynamic_cast<BossAI*>(viscidus->GetAI()))
|
||||
viscidusAI->SummonedCreatureDespawn(me);
|
||||
|
||||
if (Creature* Viscidus = me->GetMap()->GetCreature(Instance->GetGuidData(DATA_VISCIDUS)))
|
||||
if (viscidus->IsAlive() && viscidus->GetHealthPct() < 5.0f)
|
||||
{
|
||||
if (BossAI* ViscidusAI = dynamic_cast<BossAI*>(Viscidus->GetAI()))
|
||||
ViscidusAI->SummonedCreatureDespawn(me);
|
||||
|
||||
if (Viscidus->IsAlive() && Viscidus->GetHealthPct() < 5.0f)
|
||||
{
|
||||
Viscidus->SetVisible(true);
|
||||
Unit::Kill(Viscidus->GetVictim(), Viscidus);
|
||||
}
|
||||
else
|
||||
{
|
||||
Viscidus->SetHealth(Viscidus->GetHealth() - Viscidus->GetMaxHealth() / 20);
|
||||
Viscidus->CastSpell(Viscidus, SPELL_VISCIDUS_SHRINKS);
|
||||
}
|
||||
viscidus->SetVisible(true);
|
||||
Unit::Kill(viscidus->GetVictim(), viscidus);
|
||||
}
|
||||
else
|
||||
{
|
||||
viscidus->SetHealth(viscidus->GetHealth() - viscidus->GetMaxHealth() / 20);
|
||||
viscidus->CastSpell(viscidus, SPELL_VISCIDUS_SHRINKS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 /*type*/, uint32 id) override
|
||||
{
|
||||
if (id == ROOM_CENTER)
|
||||
{
|
||||
DoCast(me, SPELL_REJOIN_VISCIDUS);
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
summon->UnSummon();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void MovementInform(uint32 /*type*/, uint32 id) override
|
||||
{
|
||||
return GetTempleOfAhnQirajAI<npc_glob_of_viscidusAI>(creature);
|
||||
if (id == ROOM_CENTER)
|
||||
{
|
||||
DoCast(me, SPELL_REJOIN_VISCIDUS);
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
summon->UnSummon();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_viscidus()
|
||||
{
|
||||
new boss_viscidus();
|
||||
new npc_glob_of_viscidus();
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_viscidus);
|
||||
RegisterTempleOfAhnQirajCreatureAI(boss_glob_of_viscidus);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ EndScriptData */
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_SARTURA, DATA_SARTURA },
|
||||
{ NPC_EYE_OF_CTHUN, DATA_EYE_OF_CTHUN }
|
||||
{ NPC_EYE_OF_CTHUN, DATA_EYE_OF_CTHUN },
|
||||
{ NPC_OURO_SPAWNER, DATA_OURO_SPAWNER }
|
||||
};
|
||||
|
||||
class instance_temple_of_ahnqiraj : public InstanceMapScript
|
||||
@@ -102,6 +103,10 @@ public:
|
||||
case NPC_VISCIDUS:
|
||||
ViscidusGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_OURO_SPAWNER:
|
||||
if (GetBossState(DATA_OURO) != DONE)
|
||||
creature->Respawn();
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
@@ -177,6 +182,27 @@ public:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetBossState(uint32 type, EncounterState state) override
|
||||
{
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DATA_OURO:
|
||||
if (state == FAIL)
|
||||
{
|
||||
if (Creature* ouroSpawner = GetCreature(DATA_OURO))
|
||||
ouroSpawner->Respawn();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -34,25 +34,33 @@ EndScriptData */
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_MENDING_BUFF = 2147,
|
||||
SPELL_MENDING_BUFF = 2147,
|
||||
|
||||
SPELL_KNOCK_BUFF = 21737,
|
||||
SPELL_KNOCK = 25778,
|
||||
SPELL_MANAB_BUFF = 812,
|
||||
SPELL_MANAB = 25779,
|
||||
SPELL_KNOCK_BUFF = 21737,
|
||||
SPELL_KNOCK = 25778,
|
||||
SPELL_MANAB_BUFF = 812,
|
||||
SPELL_MANAB = 25779,
|
||||
|
||||
SPELL_REFLECTAF_BUFF = 13022,
|
||||
SPELL_REFLECTSFr_BUFF = 19595,
|
||||
SPELL_THORNS_BUFF = 25777,
|
||||
SPELL_REFLECTAF_BUFF = 13022,
|
||||
SPELL_REFLECTSFr_BUFF = 19595,
|
||||
SPELL_THORNS_BUFF = 25777,
|
||||
|
||||
SPELL_THUNDER_BUFF = 2834,
|
||||
SPELL_THUNDER = 8732,
|
||||
SPELL_THUNDER_BUFF = 2834,
|
||||
SPELL_THUNDER = 8732,
|
||||
|
||||
SPELL_MSTRIKE_BUFF = 9347,
|
||||
SPELL_MSTRIKE = 24573,
|
||||
SPELL_MSTRIKE_BUFF = 9347,
|
||||
SPELL_MSTRIKE = 24573,
|
||||
|
||||
SPELL_STORM_BUFF = 2148,
|
||||
SPELL_STORM = 26546
|
||||
SPELL_STORM_BUFF = 2148,
|
||||
SPELL_STORM = 26546,
|
||||
|
||||
SPELL_SUMMON_SMALL_OBSIDIAN_CHUNK = 27627, // Server-side
|
||||
|
||||
SPELL_TRANSFER_POWER = 2400,
|
||||
SPELL_HEAL_BRETHEN = 26565,
|
||||
SPELL_ENRAGE = 8599,
|
||||
|
||||
TALK_ENRAGE = 0
|
||||
};
|
||||
|
||||
class npc_anubisath_sentinel : public CreatureScript
|
||||
@@ -245,6 +253,7 @@ public:
|
||||
}
|
||||
ClearBuddyList();
|
||||
gatherOthersWhenAggro = true;
|
||||
_enraged = false;
|
||||
}
|
||||
|
||||
void GainSentinelAbility(uint32 id)
|
||||
@@ -261,6 +270,20 @@ public:
|
||||
DoZoneInCombat();
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_TRANSFER_POWER)
|
||||
{
|
||||
if (Creature* sentinel = target->ToCreature())
|
||||
{
|
||||
if (sentinel->IsAIEnabled)
|
||||
{
|
||||
CAST_AI(aqsentinelAI, sentinel->AI())->GainSentinelAbility(ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
for (int ni = 0; ni < 3; ++ni)
|
||||
@@ -270,10 +293,26 @@ public:
|
||||
continue;
|
||||
if (sent->isDead())
|
||||
continue;
|
||||
sent->ModifyHealth(int32(sent->CountPctFromMaxHealth(50)));
|
||||
CAST_AI(aqsentinelAI, sent->AI())->GainSentinelAbility(ability);
|
||||
DoCast(sent, SPELL_HEAL_BRETHEN, true);
|
||||
DoCast(sent, SPELL_TRANSFER_POWER, true);
|
||||
}
|
||||
|
||||
DoCastSelf(SPELL_SUMMON_SMALL_OBSIDIAN_CHUNK, true);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
|
||||
{
|
||||
if (!_enraged && me->HealthBelowPctDamaged(50, damage))
|
||||
{
|
||||
_enraged = true;
|
||||
damage = 0;
|
||||
DoCastSelf(SPELL_ENRAGE, true);
|
||||
Talk(TALK_ENRAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool _enraged;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,10 @@ enum DataTypes
|
||||
DATA_VEKNILASH = 9,
|
||||
DATA_VEKNILASHISDEAD = 10,
|
||||
DATA_VEKNILASH_DEATH = 11,
|
||||
DATA_BUG_TRIO_DEATH = 14,
|
||||
DATA_FANKRISS = 12,
|
||||
DATA_OURO = 13,
|
||||
DATA_OURO_SPAWNER = 14,
|
||||
DATA_BUG_TRIO_DEATH = 15,
|
||||
DATA_CTHUN_PHASE = 20,
|
||||
DATA_VISCIDUS = 21,
|
||||
DATA_SARTURA = 22,
|
||||
@@ -55,7 +58,7 @@ enum Creatures
|
||||
NPC_GIANT_EYE_TENTACLE = 15334,
|
||||
NPC_FLESH_TENTACLE = 15802,
|
||||
NPC_GIANT_PORTAL = 15910,
|
||||
|
||||
NPC_SARTURA_ROYAL_GUARD = 15984,
|
||||
NPC_VISCIDUS = 15299,
|
||||
NPC_GLOB_OF_VISCIDUS = 15667,
|
||||
|
||||
@@ -66,6 +69,7 @@ enum Creatures
|
||||
NPC_VEKLOR = 15276,
|
||||
NPC_VEKNILASH = 15275,
|
||||
NPC_OURO = 15517,
|
||||
NPC_OURO_SPAWNER = 15957,
|
||||
NPC_SARTURA = 15516
|
||||
};
|
||||
|
||||
@@ -75,4 +79,6 @@ inline AI* GetTempleOfAhnQirajAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, TempleOfAhnQirajScriptName);
|
||||
}
|
||||
|
||||
#define RegisterTempleOfAhnQirajCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetTempleOfAhnQirajAI)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -57,6 +57,7 @@ void AddSC_boss_moam();
|
||||
void AddSC_boss_buru();
|
||||
void AddSC_boss_ayamiss();
|
||||
void AddSC_boss_ossirian();
|
||||
void AddSC_ruins_of_ahnqiraj();
|
||||
void AddSC_instance_ruins_of_ahnqiraj();
|
||||
void AddSC_boss_cthun(); //Temple of ahn'qiraj
|
||||
void AddSC_boss_viscidus();
|
||||
@@ -139,6 +140,7 @@ void AddKalimdorScripts()
|
||||
AddSC_boss_buru();
|
||||
AddSC_boss_ayamiss();
|
||||
AddSC_boss_ossirian();
|
||||
AddSC_ruins_of_ahnqiraj();
|
||||
AddSC_instance_ruins_of_ahnqiraj();
|
||||
AddSC_boss_cthun(); //Temple of ahn'qiraj
|
||||
AddSC_boss_viscidus();
|
||||
|
||||
@@ -118,11 +118,11 @@ public:
|
||||
if( pInstance )
|
||||
pInstance->SetData(TYPE_JARAXXUS, NOT_STARTED);
|
||||
|
||||
// checked for safety
|
||||
while( Creature* c = me->FindNearestCreature(NPC_INFERNAL_VOLCANO, 500.0f, true) )
|
||||
c->DespawnOrUnsummon();
|
||||
while( Creature* c = me->FindNearestCreature(NPC_NETHER_PORTAL, 500.0f, true) )
|
||||
c->DespawnOrUnsummon();
|
||||
std::list<Creature*> creatures;
|
||||
me->GetCreatureListWithEntryInGrid(creatures, NPC_INFERNAL_VOLCANO, 500.f);
|
||||
me->GetCreatureListWithEntryInGrid(creatures, NPC_NETHER_PORTAL, 500.f);
|
||||
for (Creature* creature : creatures)
|
||||
creature->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
|
||||
@@ -1199,7 +1199,7 @@ class spell_gen_adaptive_warding : public AuraScript
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
if (eventInfo.GetSpellInfo())
|
||||
if (!eventInfo.GetSpellInfo())
|
||||
return false;
|
||||
|
||||
// find Mage Armor
|
||||
|
||||
@@ -666,10 +666,13 @@ class spell_hun_readiness : public SpellScript
|
||||
&& spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER
|
||||
&& spellInfo->Id != SPELL_HUNTER_READINESS
|
||||
&& spellInfo->Id != SPELL_HUNTER_BESTIAL_WRATH
|
||||
&& spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU
|
||||
&& spellInfo->GetRecoveryTime() > 0)
|
||||
&& spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU)
|
||||
{
|
||||
caster->RemoveSpellCooldown(spellInfo->Id, itr->second.needSendToClient);
|
||||
if (spellInfo->RecoveryTime > 0)
|
||||
caster->RemoveSpellCooldown(spellInfo->Id, itr->second.needSendToClient);
|
||||
|
||||
if (spellInfo->CategoryRecoveryTime > 0)
|
||||
caster->RemoveCategoryCooldown(spellInfo->GetCategory());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,9 +428,26 @@ class spell_pri_lightwell_renew : public AuraScript
|
||||
}
|
||||
}
|
||||
|
||||
void HandleUpdateSpellclick(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Player* player = GetTarget()->ToPlayer())
|
||||
{
|
||||
UpdateData data;
|
||||
WorldPacket packet;
|
||||
caster->BuildValuesUpdateBlockForPlayer(&data, player);
|
||||
data.BuildPacket(&packet);
|
||||
player->SendDirectMessage(&packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pri_lightwell_renew::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_HEAL);
|
||||
AfterEffectApply += AuraEffectApplyFn(spell_pri_lightwell_renew::HandleUpdateSpellclick, EFFECT_0, SPELL_AURA_PERIODIC_HEAL, AURA_EFFECT_HANDLE_REAL);
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_pri_lightwell_renew::HandleUpdateSpellclick, EFFECT_0, SPELL_AURA_PERIODIC_HEAL, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Spell.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
//
|
||||
// Emerald Dragon NPCs and IDs (kept here for reference)
|
||||
@@ -34,6 +35,9 @@ enum EmeraldDragonNPC
|
||||
DRAGON_LETHON = 14888,
|
||||
DRAGON_EMERISS = 14889,
|
||||
DRAGON_TAERAR = 14890,
|
||||
|
||||
GUID_DRAGON = 1,
|
||||
GUID_FOG_TARGET = 2
|
||||
};
|
||||
|
||||
//
|
||||
@@ -64,6 +68,7 @@ enum Events
|
||||
EVENT_SEEPING_FOG = 1,
|
||||
EVENT_NOXIOUS_BREATH,
|
||||
EVENT_TAIL_SWEEP,
|
||||
EVENT_SUMMON_PLAYER,
|
||||
|
||||
// Ysondre
|
||||
EVENT_LIGHTNING_WAVE,
|
||||
@@ -102,6 +107,7 @@ struct emerald_dragonAI : public WorldBossAI
|
||||
events.ScheduleEvent(EVENT_TAIL_SWEEP, 4000);
|
||||
events.ScheduleEvent(EVENT_NOXIOUS_BREATH, urand(7500, 15000));
|
||||
events.ScheduleEvent(EVENT_SEEPING_FOG, urand(12500, 20000));
|
||||
events.ScheduleEvent(EVENT_SUMMON_PLAYER, 1s);
|
||||
}
|
||||
|
||||
// Target killed during encounter, mark them as suspectible for Aura Of Nature
|
||||
@@ -133,6 +139,20 @@ struct emerald_dragonAI : public WorldBossAI
|
||||
DoCast(me, SPELL_TAIL_SWEEP);
|
||||
events.ScheduleEvent(EVENT_TAIL_SWEEP, 2000);
|
||||
break;
|
||||
case EVENT_SUMMON_PLAYER:
|
||||
if (Unit* target = me->GetVictim())
|
||||
if (!target->IsWithinRange(me, 50.f))
|
||||
DoCast(target, SPELL_SUMMON_PLAYER);
|
||||
events.ScheduleEvent(EVENT_SUMMON_PLAYER, 500ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
if (summon->GetEntry() == NPC_DREAM_FOG)
|
||||
{
|
||||
summon->AI()->SetGUID(me->GetGUID(), GUID_DRAGON);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,9 +169,6 @@ struct emerald_dragonAI : public WorldBossAI
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
ExecuteEvent(eventId);
|
||||
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, -50.0f, true))
|
||||
DoCast(target, SPELL_SUMMON_PLAYER);
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
@@ -167,13 +184,66 @@ public:
|
||||
|
||||
struct npc_dream_fogAI : public ScriptedAI
|
||||
{
|
||||
npc_dream_fogAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
}
|
||||
npc_dream_fogAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_roamTimer = 0;
|
||||
ScheduleEvents();
|
||||
}
|
||||
|
||||
void ScheduleEvents()
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
|
||||
_scheduler.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
// Chase target, but don't attack - otherwise just roam around
|
||||
if (Unit* chaseTarget = GetRandomUnitFromDragonThreatList())
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveFollow(chaseTarget, 0.02f, 0.0f);
|
||||
_targetGUID = chaseTarget->GetGUID();
|
||||
context.Repeat(15s, 30s);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveRandom(25.0f);
|
||||
context.Repeat(2500ms);
|
||||
}
|
||||
|
||||
// Seeping fog movement is slow enough for a player to be able to walk backwards and still outpace it
|
||||
me->SetWalk(true);
|
||||
me->SetSpeed(MOVE_WALK, 0.75f);
|
||||
});
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid guid, int32 type) override
|
||||
{
|
||||
if (type == GUID_DRAGON)
|
||||
{
|
||||
_dragonGUID = guid;
|
||||
}
|
||||
else if (type == GUID_FOG_TARGET)
|
||||
{
|
||||
if (guid == _targetGUID)
|
||||
{
|
||||
ScheduleEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Unit* GetRandomUnitFromDragonThreatList()
|
||||
{
|
||||
if (Creature* dragon = ObjectAccessor::GetCreature(*me, _dragonGUID))
|
||||
{
|
||||
if (dragon->GetAI())
|
||||
{
|
||||
return dragon->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -181,31 +251,13 @@ public:
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!_roamTimer)
|
||||
{
|
||||
// Chase target, but don't attack - otherwise just roam around
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
|
||||
{
|
||||
_roamTimer = urand(15000, 30000);
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveChase(target, 0.2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
_roamTimer = 2500;
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveRandom(25.0f);
|
||||
}
|
||||
// Seeping fog movement is slow enough for a player to be able to walk backwards and still outpace it
|
||||
me->SetWalk(true);
|
||||
me->SetSpeed(MOVE_WALK, 0.75f);
|
||||
}
|
||||
else
|
||||
_roamTimer -= diff;
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _roamTimer;
|
||||
ObjectGuid _targetGUID;
|
||||
ObjectGuid _dragonGUID;
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -609,6 +661,7 @@ public:
|
||||
++_stage;
|
||||
}
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
@@ -687,6 +740,17 @@ public:
|
||||
{
|
||||
PrepareSpellScript(spell_dream_fog_sleep_SpellScript);
|
||||
|
||||
void HandleEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
caster->GetAI()->SetGUID(target->GetGUID(), GUID_FOG_TARGET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
targets.remove_if(Acore::UnitAuraCheck(true, SPELL_SLEEP));
|
||||
@@ -694,6 +758,7 @@ public:
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_dream_fog_sleep_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_dream_fog_sleep_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -394,6 +394,14 @@ public:
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (attacker == me)
|
||||
{
|
||||
me->LowerPlayerDamageReq(damage);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*Caster*/, SpellInfo const* Spell) override
|
||||
{
|
||||
uint32 serpentStings[12] = { 1978, 13549, 13550, 13551, 13552, 13553, 13554, 13555, 25295, 27016, 49000, 49001 };
|
||||
@@ -1173,6 +1181,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (attacker == me)
|
||||
{
|
||||
me->LowerPlayerDamageReq(damage);
|
||||
}
|
||||
}
|
||||
|
||||
void ScheduleEncounterStart(ObjectGuid playerGUID)
|
||||
{
|
||||
PrepareForEncounter();
|
||||
|
||||
Reference in New Issue
Block a user