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:
郑佩茹
2022-08-16 16:13:26 -06:00
159 changed files with 5246 additions and 2794 deletions

View File

@@ -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;
}
};

View File

@@ -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
};

View File

@@ -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);
}
}

View File

@@ -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] =

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}
}
}
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);
}
};

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
};
};

View File

@@ -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;
};
};

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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());
}
}
}

View File

@@ -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);
}
};

View File

@@ -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);
}
};

View File

@@ -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();