Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/Entities/Creature/Creature.cpp
#	src/server/game/Entities/Creature/Creature.h
#	src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
This commit is contained in:
郑佩茹
2022-07-27 09:11:50 -06:00
140 changed files with 6677 additions and 4753 deletions

View File

@@ -186,6 +186,7 @@ public:
static ChatCommandTable npcCommandTable =
{
{ "info", HandleNpcInfoCommand, SEC_GAMEMASTER, Console::No },
{ "guid", HandleNpcGuidCommand, SEC_GAMEMASTER, Console::No },
{ "near", HandleNpcNearCommand, SEC_GAMEMASTER, Console::No },
{ "move", HandleNpcMoveCommand, SEC_GAMEMASTER, Console::No },
{ "playemote", HandleNpcPlayEmoteCommand, SEC_GAMEMASTER, Console::No },
@@ -652,6 +653,36 @@ public:
return true;
}
static bool HandleNpcGuidCommand(ChatHandler* handler)
{
Creature* target = handler->getSelectedCreature();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
uint32 faction = target->GetFaction();
uint32 npcflags = target->GetNpcFlags();
uint32 displayid = target->GetDisplayId();
uint32 nativeid = target->GetNativeDisplayId();
uint32 entry = target->GetEntry();
uint32 id1 = 0;
uint32 id2 = 0;
uint32 id3 = 0;
if (CreatureData const* cData = target->GetCreatureData())
{
id1 = cData->id1;
id2 = cData->id2;
id3 = cData->id3;
}
handler->PSendSysMessage(LANG_NPCINFO_CHAR, target->GetSpawnId(), target->GetGUID().GetCounter(), entry, id1, id2, id3, displayid, nativeid, faction, npcflags);
return true;
}
static bool HandleNpcNearCommand(ChatHandler* handler, Optional<float> dist)
{

View File

@@ -122,7 +122,7 @@ public:
events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_SUMMON_PROWLERS, 6000, 0, PHASE_ALL);
events.ScheduleEvent(EVENT_MARK_OF_ARLOKK, urand(9000, 11000), 0, PHASE_ALL);
events.ScheduleEvent(EVENT_TRANSFORM, urand(15000, 20000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_TRANSFORM, 30000, 0, PHASE_ONE);
Talk(SAY_AGGRO);
// Sets up list of Panther spawners to cast on
@@ -249,7 +249,7 @@ public:
case EVENT_VANISH_2:
DoCastSelf(SPELL_VANISH);
DoCastSelf(SPELL_SUPER_INVIS);
events.ScheduleEvent(EVENT_VISIBLE, urand(7000, 10000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_VISIBLE, urand(41000, 47000), 0, PHASE_ONE);
break;
case EVENT_VISIBLE:
me->SetReactState(REACT_AGGRESSIVE);
@@ -259,7 +259,7 @@ public:
me->RemoveAura(SPELL_SUPER_INVIS);
me->RemoveAura(SPELL_VANISH);
events.ScheduleEvent(EVENT_RAVAGE, urand(10000, 14000), 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, urand(15000, 18000), 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, urand(30000, 40000), 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
break;
@@ -276,7 +276,7 @@ public:
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(4000, 7000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_TRANSFORM, urand(16000, 20000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_TRANSFORM, 30000, 0, PHASE_ONE);
events.SetPhase(PHASE_ONE);
break;
}

View File

@@ -68,6 +68,9 @@ struct boss_jindo : public BossAI
events.ScheduleEvent(EVENT_TELEPORT, 5000);
Talk(SAY_AGGRO);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
_scheduler.CancelAll();
}
void JustSummoned(Creature* summon) override
@@ -76,14 +79,15 @@ struct boss_jindo : public BossAI
switch (summon->GetEntry())
{
case NPC_BRAIN_WASH_TOTEM:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
{
summon->CastSpell(target, summon->m_spells[0], true);
}
break;
default:
break;
case NPC_BRAIN_WASH_TOTEM:
summon->SetReactState(REACT_PASSIVE);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, me->GetThreatMgr().getThreatList().size() > 1 ? 1 : 0))
{
summon->CastSpell(target, summon->m_spells[0], true);
}
break;
default:
break;
}
}
@@ -91,20 +95,22 @@ struct boss_jindo : public BossAI
{
if (_EnterEvadeMode(evadeReason))
{
me->AddUnitState(UNIT_STATE_EVADE);
Reset();
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DANCE);
me->m_Events.AddEventAtOffset([&]()
_scheduler.Schedule(4s, [this](TaskContext /*context*/)
{
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
me->AddUnitState(UNIT_STATE_EVADE);
me->GetMotionMaster()->MoveTargetedHome();
}, 4s);
});
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
if (!UpdateVictim())
return;
@@ -153,6 +159,9 @@ struct boss_jindo : public BossAI
return true;
}
private:
TaskScheduler _scheduler;
};
//Healing Ward
@@ -282,11 +291,23 @@ class spell_delusions_of_jindo : public SpellScript
}
};
struct npc_brain_wash_totem : public ScriptedAI
{
npc_brain_wash_totem(Creature* creature) : ScriptedAI(creature)
{
}
void EnterEvadeMode(EvadeReason /*evadeReason*/) override
{
}
};
void AddSC_boss_jindo()
{
RegisterZulGurubCreatureAI(boss_jindo);
RegisterZulGurubCreatureAI(npc_healing_ward);
RegisterZulGurubCreatureAI(npc_shade_of_jindo);
RegisterZulGurubCreatureAI(npc_brain_wash_totem);
RegisterSpellScript(spell_random_aggro);
RegisterSpellScript(spell_delusions_of_jindo);
}

View File

@@ -286,7 +286,7 @@ public:
if (_chargeTarget.first == hatedUnit->GetGUID())
{
// Do not count DOTs/HOTs
if (!threatSpell || !threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT))
if (!(threatSpell && (threatSpell->HasAura(SPELL_AURA_DAMAGE_SHIELD) || threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT))))
{
_chargeTarget.second += threat;
}
@@ -313,6 +313,12 @@ public:
}
}
bool OnTeleportUnreacheablePlayer(Player* player) override
{
DoCast(player, SPELL_SUMMON_PLAYER, true);
return true;
}
void DoMeleeAttackIfReady(bool ignoreCasting)
{
if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING))

View File

@@ -91,8 +91,6 @@ public:
default:
break;
}
InstanceScript::OnCreatureCreate(creature);
}
void OnGameObjectCreate(GameObject* go) override

View File

@@ -25,7 +25,6 @@ enum Spells
SPELL_STINGER_SPRAY = 25749,
SPELL_POISON_STINGER = 25748,
SPELL_PARALYZE = 25725,
SPELL_TRASH = 3391,
SPELL_FRENZY = 8269,
SPELL_LASH = 25852,
SPELL_FEED = 25721
@@ -38,8 +37,7 @@ enum Events
EVENT_SUMMON_SWARMER = 3,
EVENT_SWARMER_ATTACK = 4,
EVENT_PARALYZE = 5,
EVENT_LASH = 6,
EVENT_TRASH = 7
EVENT_LASH = 6
};
enum Emotes
@@ -77,9 +75,7 @@ public:
struct boss_ayamissAI : public BossAI
{
boss_ayamissAI(Creature* creature) : BossAI(creature, DATA_AYAMISS)
{
}
boss_ayamissAI(Creature* creature) : BossAI(creature, DATA_AYAMISS) {}
void Reset() override
{
@@ -101,7 +97,9 @@ public:
break;
case NPC_HORNET:
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
{
who->AI()->AttackStart(target);
}
break;
}
}
@@ -116,7 +114,7 @@ public:
me->AddUnitState(UNIT_STATE_ROOT);
break;
case POINT_GROUND:
me->ClearUnitState(UNIT_STATE_ROOT);
me->GetMotionMaster()->MoveChase(me->GetVictim());
break;
}
}
@@ -131,55 +129,51 @@ public:
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);
if (_phase == PHASE_AIR && me->GetHealthPct() < 70.0f)
{
_phase = PHASE_GROUND;
SetCombatMovement(true);
me->SetCanFly(false);
Position VictimPos = me->GetVictim()->GetPosition();
me->GetMotionMaster()->MovePoint(POINT_GROUND, VictimPos);
DoResetThreat();
events.ScheduleEvent(EVENT_LASH, urand(5000, 8000));
events.ScheduleEvent(EVENT_TRASH, urand(3000, 6000));
events.CancelEvent(EVENT_POISON_STINGER);
}
else
{
DoMeleeAttackIfReady();
}
if (!_enraged && me->GetHealthPct() < 20.0f)
{
DoCast(me, SPELL_FRENZY);
Talk(EMOTE_FRENZY);
_enraged = true;
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_STINGER_SPRAY:
DoCast(me, SPELL_STINGER_SPRAY);
DoCastSelf(SPELL_STINGER_SPRAY);
events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(15000, 20000));
break;
case EVENT_POISON_STINGER:
@@ -198,30 +192,32 @@ public:
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);
me->SummonCreature(NPC_SWARMER, Pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000);
break;
}
case EVENT_TRASH:
DoCastVictim(SPELL_TRASH);
events.ScheduleEvent(EVENT_TRASH, urand(5000, 7000));
break;
case EVENT_LASH:
DoCastVictim(SPELL_LASH);
events.ScheduleEvent(EVENT_LASH, urand(8000, 15000));
break;
}
}
DoMeleeAttackIfReady();
}
private:
GuidList _swarmers;
@@ -250,9 +246,15 @@ public:
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); // Omnomnom
{
DoCast(target, SPELL_FEED);
}
}
}
}
void MoveInLineOfSight(Unit* who) override

View File

@@ -18,6 +18,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "TaskScheduler.h"
#include "ruins_of_ahnqiraj.h"
enum Emotes
@@ -36,7 +37,8 @@ enum Spells
SPELL_SUMMON_HATCHLING = 1881,
SPELL_EXPLODE = 19593,
SPELL_EXPLODE_2 = 5255,
SPELL_BURU_EGG_TRIGGER = 26646
SPELL_BURU_EGG_TRIGGER = 26646,
SPELL_CREATURE_SPECIAL = 7155, // from sniffs
};
enum Events
@@ -45,7 +47,7 @@ enum Events
EVENT_GATHERING_SPEED = 2,
EVENT_FULL_SPEED = 3,
EVENT_CREEPING_PLAGUE = 4,
EVENT_RESPAWN_EGG = 5
EVENT_RESPAWN_EGG = 5,
};
enum Phases
@@ -54,228 +56,229 @@ enum Phases
PHASE_TRANSFORM = 1
};
enum Actions
struct boss_buru : public BossAI
{
ACTION_EXPLODE = 0
};
boss_buru(Creature* creature) : BossAI(creature, DATA_BURU) {}
class boss_buru : public CreatureScript
{
public:
boss_buru() : CreatureScript("boss_buru") { }
struct boss_buruAI : public BossAI
void EnterEvadeMode(EvadeReason why) override
{
boss_buruAI(Creature* creature) : BossAI(creature, DATA_BURU)
BossAI::EnterEvadeMode(why);
DoCastSelf(SPELL_FULL_SPEED, true);
ManipulateEggs(true);
_eggs.clear();
}
void ManipulateEggs(bool respawn)
{
std::list<Creature*> eggs;
me->GetCreaturesWithEntryInRange(eggs, 150.0f, NPC_BURU_EGG);
for (Creature* egg : eggs)
respawn ? egg->Respawn() : Unit::Kill(me, egg);
}
void EnterCombat(Unit* who) override
{
_EnterCombat();
Talk(EMOTE_TARGET, who);
DoCastSelf(SPELL_THORNS);
ManipulateEggs(true);
me->RemoveAurasDueToSpell(SPELL_FULL_SPEED);
events.ScheduleEvent(EVENT_DISMEMBER, 5s);
events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s);
events.ScheduleEvent(EVENT_FULL_SPEED, 60s);
_phase = PHASE_EGG;
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_CREATURE_SPECIAL)
ChaseNewVictim();
}
void JustDied(Unit* /*killer*/) override
{
if (InstanceScript* pInstance = me->GetInstanceScript())
{
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_CREEPING_PLAGUE);
}
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
ChaseNewVictim();
}
void ChaseNewVictim()
{
if (_phase != PHASE_EGG)
return;
me->RemoveAurasDueToSpell(SPELL_FULL_SPEED);
me->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED);
events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s);
events.ScheduleEvent(EVENT_FULL_SPEED, 60s);
if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 0.f, true))
{
DoResetThreat();
AttackStart(victim);
me->AddThreat(victim, 1000000.f);
Talk(EMOTE_TARGET, victim);
}
}
void SetGUID(ObjectGuid const guid, int32 /*type*/) override
{
_eggs.push_back(guid);
events.ScheduleEvent(EVENT_RESPAWN_EGG, 120s);
}
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (attacker->GetEntry() != NPC_BURU_EGG && _phase == PHASE_EGG)
{
damage = damage * 0.01f; // 99% dmg resist
}
void EnterEvadeMode(EvadeReason why) override
if (me->HealthBelowPctDamaged(20, damage) && _phase == PHASE_EGG)
{
BossAI::EnterEvadeMode(why);
for (ObjectGuid const& guid : Eggs)
if (Creature* egg = me->GetMap()->GetCreature(guid))
egg->Respawn();
Eggs.clear();
DoCastSelf(SPELL_FULL_SPEED, true);
ManipulateEggs(false);
me->RemoveAurasDueToSpell(SPELL_THORNS);
events.Reset();
_phase = PHASE_TRANSFORM;
DoResetThreat();
events.ScheduleEvent(EVENT_CREEPING_PLAGUE, 2s);
DoCastSelf(SPELL_BURU_TRANSFORM);
}
}
void EnterCombat(Unit* who) override
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
_EnterCombat();
Talk(EMOTE_TARGET, who);
DoCast(me, SPELL_THORNS);
events.ScheduleEvent(EVENT_DISMEMBER, 5000);
events.ScheduleEvent(EVENT_GATHERING_SPEED, 9000);
events.ScheduleEvent(EVENT_FULL_SPEED, 60000);
_phase = PHASE_EGG;
}
void DoAction(int32 action) override
{
if (action == ACTION_EXPLODE)
if (_phase == PHASE_EGG)
Unit::DealDamage(me, me, 45000);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
ChaseNewVictim();
}
void ChaseNewVictim()
{
if (_phase != PHASE_EGG)
return;
me->RemoveAurasDueToSpell(SPELL_FULL_SPEED);
me->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED);
events.ScheduleEvent(EVENT_GATHERING_SPEED, 9000);
events.ScheduleEvent(EVENT_FULL_SPEED, 60000);
if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
switch (eventId)
{
DoResetThreat();
AttackStart(victim);
Talk(EMOTE_TARGET, victim);
case EVENT_DISMEMBER:
DoCastVictim(SPELL_DISMEMBER);
events.ScheduleEvent(EVENT_DISMEMBER, 5s);
break;
case EVENT_GATHERING_SPEED:
DoCastSelf(SPELL_GATHERING_SPEED);
events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s);
break;
case EVENT_FULL_SPEED:
DoCastSelf(SPELL_FULL_SPEED);
break;
case EVENT_CREEPING_PLAGUE:
DoCastAOE(SPELL_CREEPING_PLAGUE);
events.ScheduleEvent(EVENT_CREEPING_PLAGUE, 6s);
break;
case EVENT_RESPAWN_EGG:
if (Creature* egg = me->GetMap()->GetCreature(*_eggs.begin()))
egg->Respawn();
_eggs.pop_front();
break;
default:
break;
}
}
void ManageRespawn(ObjectGuid EggGUID)
DoMeleeAttackIfReady();
}
private:
uint8 _phase;
GuidList _eggs;
};
struct npc_buru_egg : public ScriptedAI
{
npc_buru_egg(Creature* creature) : ScriptedAI(creature)
{
_instance = me->GetInstanceScript();
SetCombatMovement(false);
me->SetReactState(REACT_PASSIVE);
}
void EnterCombat(Unit* attacker) override
{
if (Creature* buru = _instance->GetCreature(DATA_BURU))
{
ChaseNewVictim();
Eggs.push_back(EggGUID);
events.ScheduleEvent(EVENT_RESPAWN_EGG, 100000);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
if (!buru->IsInCombat())
{
switch (eventId)
buru->AI()->AttackStart(attacker);
}
}
}
void JustSummoned(Creature* who) override
{
if (who->GetEntry() == NPC_HATCHLING)
{
if (Creature* buru = _instance->GetCreature(DATA_BURU))
{
if (Unit* target = buru->AI()->SelectTarget(SelectTargetMethod::Random))
{
case EVENT_DISMEMBER:
DoCastVictim(SPELL_DISMEMBER);
events.ScheduleEvent(EVENT_DISMEMBER, 5000);
break;
case EVENT_GATHERING_SPEED:
DoCast(me, SPELL_GATHERING_SPEED);
events.ScheduleEvent(EVENT_GATHERING_SPEED, 9000);
break;
case EVENT_FULL_SPEED:
DoCast(me, SPELL_FULL_SPEED);
break;
case EVENT_CREEPING_PLAGUE:
DoCast(me, SPELL_CREEPING_PLAGUE);
events.ScheduleEvent(EVENT_CREEPING_PLAGUE, 6000);
break;
case EVENT_RESPAWN_EGG:
if (Creature* egg = me->GetMap()->GetCreature(*Eggs.begin()))
{
egg->Respawn();
Eggs.pop_front();
}
break;
default:
break;
who->AI()->AttackStart(target);
}
}
}
}
if (me->GetHealthPct() < 20.0f && _phase == PHASE_EGG)
void JustDied(Unit* killer) override
{
DoCastSelf(SPELL_SUMMON_HATCHLING, true);
if (killer->GetEntry() != NPC_BURU)
{
if (Creature* buru = _instance->GetCreature(DATA_BURU))
{
DoCast(me, SPELL_BURU_TRANSFORM); // Enrage
DoCast(me, SPELL_FULL_SPEED, true);
me->RemoveAurasDueToSpell(SPELL_THORNS);
_phase = PHASE_TRANSFORM;
DoCastSelf(SPELL_EXPLODE);
DoCastSelf(SPELL_BURU_EGG_TRIGGER, true);
buru->CastSpell(buru, SPELL_CREATURE_SPECIAL, true);
if (buru->GetAI())
buru->AI()->SetGUID(me->GetGUID());
}
DoMeleeAttackIfReady();
}
private:
uint8 _phase;
GuidList Eggs;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetRuinsOfAhnQirajAI<boss_buruAI>(creature);
}
private:
InstanceScript* _instance;
};
class npc_buru_egg : public CreatureScript
class spell_egg_explosion : public SpellScript
{
public:
npc_buru_egg() : CreatureScript("npc_buru_egg") { }
PrepareSpellScript(spell_egg_explosion);
struct npc_buru_eggAI : public ScriptedAI
void HandleDummyHitTarget(SpellEffIndex /*effIndex*/)
{
npc_buru_eggAI(Creature* creature) : ScriptedAI(creature)
if (Unit* target = GetHitUnit())
{
_instance = me->GetInstanceScript();
SetCombatMovement(false);
int32 damage = 0;
if (target->IsPlayer())
damage = -16 * GetCaster()->GetDistance(target) + 500;
else if (target->GetEntry() == NPC_BURU && target->HasAura(SPELL_THORNS))
damage = target->GetMaxHealth() * 7.f / 100;
GetCaster()->CastCustomSpell(target, SPELL_EXPLODE_2, &damage, nullptr, nullptr, true);
}
void EnterCombat(Unit* attacker) override
{
if (Creature* buru = me->GetMap()->GetCreature(_instance->GetGuidData(DATA_BURU)))
if (!buru->IsInCombat())
buru->AI()->AttackStart(attacker);
}
void JustSummoned(Creature* who) override
{
if (who->GetEntry() == NPC_HATCHLING)
if (Creature* buru = me->GetMap()->GetCreature(_instance->GetGuidData(DATA_BURU)))
if (Unit* target = buru->AI()->SelectTarget(SelectTargetMethod::Random))
who->AI()->AttackStart(target);
}
void JustDied(Unit* /*killer*/) override
{
DoCastAOE(SPELL_EXPLODE, true);
DoCastAOE(SPELL_EXPLODE_2, true); // Unknown purpose
DoCast(me, SPELL_SUMMON_HATCHLING, true);
if (Creature* buru = me->GetMap()->GetCreature(_instance->GetGuidData(DATA_BURU)))
if (boss_buru::boss_buruAI* buruAI = dynamic_cast<boss_buru::boss_buruAI*>(buru->AI()))
buruAI->ManageRespawn(me->GetGUID());
}
private:
InstanceScript* _instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetRuinsOfAhnQirajAI<npc_buru_eggAI>(creature);
}
};
class spell_egg_explosion : public SpellScriptLoader
{
public:
spell_egg_explosion() : SpellScriptLoader("spell_egg_explosion") { }
class spell_egg_explosion_SpellScript : public SpellScript
void Register() override
{
PrepareSpellScript(spell_egg_explosion_SpellScript);
void HandleAfterCast()
{
if (Creature* buru = GetCaster()->FindNearestCreature(NPC_BURU, 5.f))
buru->AI()->DoAction(ACTION_EXPLODE);
}
void HandleDummyHitTarget(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
Unit::DealDamage(GetCaster(), target, -16 * GetCaster()->GetDistance(target) + 500);
}
void Register() override
{
AfterCast += SpellCastFn(spell_egg_explosion_SpellScript::HandleAfterCast);
OnEffectHitTarget += SpellEffectFn(spell_egg_explosion_SpellScript::HandleDummyHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_egg_explosion_SpellScript();
OnEffectHitTarget += SpellEffectFn(spell_egg_explosion::HandleDummyHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
void AddSC_boss_buru()
{
new boss_buru();
new npc_buru_egg();
new spell_egg_explosion();
RegisterRuinsOfAhnQirajCreatureAI(boss_buru);
RegisterRuinsOfAhnQirajCreatureAI(npc_buru_egg);
RegisterSpellScript(spell_egg_explosion);
}

View File

@@ -16,121 +16,134 @@
*/
#include "CreatureTextMgr.h"
#include "GameObjectAI.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "ruins_of_ahnqiraj.h"
enum Spells
{
SPELL_MORTALWOUND = 25646,
SPELL_SANDTRAP = 25648,
SPELL_MORTAL_WOUND = 25646,
SPELL_SAND_TRAP = 25648,
SPELL_ENRAGE = 26527,
SPELL_SUMMON_PLAYER = 26446,
SPELL_TRASH = 3391, // Should perhaps be triggered by an aura? Couldn't find any though
SPELL_WIDE_SLASH = 25814
};
enum Events
{
EVENT_MORTAL_WOUND = 1,
EVENT_SANDTRAP = 2,
EVENT_TRASH = 3,
EVENT_WIDE_SLASH = 4
EVENT_SAND_TRAP = 2,
EVENT_WIDE_SLASH = 3
};
enum Texts
{
SAY_KURINAXX_DEATH = 5, // Yelled by Ossirian the Unscarred
SAY_KURINNAXX_DEATH = 5 // Yell by 'Ossirian the Unscarred'
};
class boss_kurinnaxx : public CreatureScript
struct boss_kurinnaxx : public BossAI
{
public:
boss_kurinnaxx() : CreatureScript("boss_kurinnaxx") { }
boss_kurinnaxx(Creature* creature) : BossAI(creature, DATA_KURINNAXX) {}
struct boss_kurinnaxxAI : public BossAI
void Reset() override
{
boss_kurinnaxxAI(Creature* creature) : BossAI(creature, DATA_KURINNAXX)
{
}
void Reset() override
{
_Reset();
_enraged = false;
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8000);
events.ScheduleEvent(EVENT_SANDTRAP, urand(5000, 15000));
events.ScheduleEvent(EVENT_TRASH, 1000);
events.ScheduleEvent(EVENT_WIDE_SLASH, 11000);
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
{
if (!_enraged && HealthBelowPct(30))
{
DoCast(me, SPELL_ENRAGE);
_enraged = true;
}
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
if (Creature* Ossirian = me->GetMap()->GetCreature(instance->GetGuidData(DATA_OSSIRIAN)))
sCreatureTextMgr->SendChat(Ossirian, SAY_KURINAXX_DEATH, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
}
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_MORTAL_WOUND:
DoCastVictim(SPELL_MORTALWOUND);
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8000);
break;
case EVENT_SANDTRAP:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
target->CastSpell(target, SPELL_SANDTRAP, true);
else if (Unit* victim = me->GetVictim())
victim->CastSpell(victim, SPELL_SANDTRAP, true);
events.ScheduleEvent(EVENT_SANDTRAP, urand(5000, 15000));
break;
case EVENT_WIDE_SLASH:
DoCast(me, SPELL_WIDE_SLASH);
events.ScheduleEvent(EVENT_WIDE_SLASH, 11000);
break;
case EVENT_TRASH:
DoCast(me, SPELL_TRASH);
events.ScheduleEvent(EVENT_WIDE_SLASH, 16000);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool _enraged;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetRuinsOfAhnQirajAI<boss_kurinnaxxAI>(creature);
BossAI::Reset();
_enraged = false;
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8s, 10s);
events.ScheduleEvent(EVENT_SAND_TRAP, 5s, 15s);
events.ScheduleEvent(EVENT_WIDE_SLASH, 10s, 15s);
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
{
if (!_enraged && HealthBelowPct(30))
{
DoCastSelf(SPELL_ENRAGE);
_enraged = true;
}
}
void JustDied(Unit* killer) override
{
if (killer)
killer->GetMap()->LoadGrid(-9502.80f, 2042.65f); // Ossirian grid
if (Creature* ossirian = instance->GetCreature(DATA_OSSIRIAN))
{
ossirian->setActive(true);
if (ossirian->GetAI())
ossirian->AI()->Talk(SAY_KURINNAXX_DEATH);
}
BossAI::JustDied(killer);
}
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_MORTAL_WOUND:
DoCastVictim(SPELL_MORTAL_WOUND);
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8s, 10s);
break;
case EVENT_SAND_TRAP:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.f, true))
{
target->CastSpell(target, SPELL_SAND_TRAP, true, nullptr, nullptr, me->GetGUID());
}
events.ScheduleEvent(EVENT_SAND_TRAP, 5s, 15s);
break;
case EVENT_WIDE_SLASH:
DoCastSelf(SPELL_WIDE_SLASH);
events.ScheduleEvent(EVENT_WIDE_SLASH, 12s, 15s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool _enraged;
};
struct go_sand_trap : public GameObjectAI
{
go_sand_trap(GameObject* go) : GameObjectAI(go) { }
void Reset() override
{
_scheduler.Schedule(5s, [this](TaskContext /*context*/)
{
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* kurinnaxx = instance->GetCreature(DATA_KURINNAXX))
me->Use(kurinnaxx);
});
}
void UpdateAI(uint32 const diff) override
{
_scheduler.Update(diff);
}
protected:
TaskScheduler _scheduler;
};
void AddSC_boss_kurinnaxx()
{
new boss_kurinnaxx();
RegisterRuinsOfAhnQirajCreatureAI(boss_kurinnaxx);
RegisterGameObjectAI(go_sand_trap);
}

View File

@@ -15,173 +15,180 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "ruins_of_ahnqiraj.h"
enum Texts
{
EMOTE_AGGRO = 0,
EMOTE_MANA_FULL = 1
EMOTE_AGGRO = 0,
EMOTE_MANA_FULL = 1,
EMOTE_STONE_PHASE = 2
};
enum Spells
{
SPELL_TRAMPLE = 15550,
SPELL_DRAIN_MANA_SERVERSIDE = 25676,
SPELL_DRAIN_MANA = 25671,
SPELL_ARCANE_ERUPTION = 25672,
SPELL_SUMMON_MANA_FIENDS = 25684,
SPELL_SUMMON_MANA_FIEND_1 = 25681, // TARGET_DEST_CASTER_FRONT
SPELL_SUMMON_MANA_FIEND_2 = 25682, // TARGET_DEST_CASTER_LEFT
SPELL_SUMMON_MANA_FIEND_3 = 25683, // TARGET_DEST_CASTER_RIGHT
SPELL_ENERGIZE = 25685
SPELL_ENERGIZE = 25685,
SPELL_LARGE_OBSIDIAN_CHUNK = 27630 // Server-side
};
enum Events
{
EVENT_TRAMPLE = 1,
EVENT_DRAIN_MANA = 2,
EVENT_STONE_PHASE = 3,
EVENT_STONE_PHASE_END = 4,
EVENT_WIDE_SLASH = 5,
EVENT_SPELL_TRAMPLE = 1,
EVENT_SPELL_DRAIN_MANA = 2,
EVENT_STONE_PHASE = 3,
EVENT_STONE_PHASE_END = 4
};
enum Actions
struct boss_moam : public BossAI
{
ACTION_STONE_PHASE_START = 1,
ACTION_STONE_PHASE_END = 2,
};
boss_moam(Creature* creature) : BossAI(creature, DATA_MOAM) {}
class boss_moam : public CreatureScript
{
public:
boss_moam() : CreatureScript("boss_moam") { }
struct boss_moamAI : public BossAI
void Reset() override
{
boss_moamAI(Creature* creature) : BossAI(creature, DATA_MOAM)
{
}
_Reset();
me->SetPower(POWER_MANA, 0);
me->SetRegeneratingPower(false);
}
void Reset() override
{
_Reset();
me->SetPower(POWER_MANA, 0);
_isStonePhase = false;
events.ScheduleEvent(EVENT_STONE_PHASE, 90000);
//events.ScheduleEvent(EVENT_WIDE_SLASH, 11000);
}
void EnterCombat(Unit* who) override
{
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);
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
void JustDied(Unit* /*killer*/) override
{
_JustDied();
DoCastAOE(SPELL_LARGE_OBSIDIAN_CHUNK, true);
}
void SummonedCreatureDies(Creature* /*creature*/, Unit* /*killer*/) override
{
if (!summons.IsAnyCreatureAlive() && me->HasAura(SPELL_ENERGIZE))
{
if (!_isStonePhase && HealthBelowPct(45))
events.RescheduleEvent(EVENT_STONE_PHASE_END, 1s);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->GetPower(POWER_MANA) == me->GetMaxPower(POWER_MANA))
{
if (me->HasAura(SPELL_ENERGIZE))
{
_isStonePhase = true;
DoAction(ACTION_STONE_PHASE_START);
me->RemoveAurasDueToSpell(SPELL_ENERGIZE);
events.RescheduleEvent(EVENT_STONE_PHASE_END, 1s);
}
Talk(EMOTE_MANA_FULL);
DoCastAOE(SPELL_ARCANE_ERUPTION);
}
void DoAction(int32 action) override
while (uint32 eventId = events.ExecuteEvent())
{
switch (action)
switch (eventId)
{
case ACTION_STONE_PHASE_END:
{
me->RemoveAurasDueToSpell(SPELL_ENERGIZE);
events.ScheduleEvent(EVENT_STONE_PHASE, 90000);
_isStonePhase = false;
break;
}
case ACTION_STONE_PHASE_START:
{
DoCast(me, SPELL_SUMMON_MANA_FIEND_1);
DoCast(me, SPELL_SUMMON_MANA_FIEND_2);
DoCast(me, SPELL_SUMMON_MANA_FIEND_3);
DoCast(me, SPELL_ENERGIZE);
events.ScheduleEvent(EVENT_STONE_PHASE_END, 90000);
break;
}
case EVENT_STONE_PHASE:
Talk(EMOTE_STONE_PHASE);
DoCastAOE(SPELL_SUMMON_MANA_FIENDS);
DoCastSelf(SPELL_ENERGIZE);
events.CancelEvent(EVENT_SPELL_DRAIN_MANA);
events.ScheduleEvent(EVENT_STONE_PHASE_END, 90000);
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);
break;
case EVENT_SPELL_DRAIN_MANA:
DoCastAOE(SPELL_DRAIN_MANA_SERVERSIDE);
events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000));
break;
case EVENT_SPELL_TRAMPLE:
DoCastAOE(SPELL_TRAMPLE);
events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 15000);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
};
events.Update(diff);
// 25676 - Drain Mana (server-side)
class spell_moam_mana_drain_filter : public SpellScript
{
PrepareSpellScript(spell_moam_mana_drain_filter);
if (me->GetPower(POWER_MANA) == me->GetMaxPower(POWER_MANA))
{
if (_isStonePhase)
DoAction(ACTION_STONE_PHASE_END);
DoCastAOE(SPELL_ARCANE_ERUPTION);
me->SetPower(POWER_MANA, 0);
}
if (_isStonePhase)
{
if (events.ExecuteEvent() == EVENT_STONE_PHASE_END)
DoAction(ACTION_STONE_PHASE_END);
return;
}
// Messing up mana-drain channel
//if (me->HasUnitState(UNIT_STATE_CASTING))
// return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_STONE_PHASE:
DoAction(ACTION_STONE_PHASE_START);
break;
case EVENT_DRAIN_MANA:
{
std::list<Unit*> targetList;
{
const std::list<HostileReference*>& threatlist = me->GetThreatMgr().getThreatList();
for (std::list<HostileReference*>::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
if ((*itr)->getTarget()->GetTypeId() == TYPEID_PLAYER && (*itr)->getTarget()->getPowerType() == POWER_MANA)
targetList.push_back((*itr)->getTarget());
}
Acore::Containers::RandomResize(targetList, 5);
for (std::list<Unit*>::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
DoCast(*itr, SPELL_DRAIN_MANA);
events.ScheduleEvent(EVENT_DRAIN_MANA, urand(5000, 15000));
break;
}/*
case EVENT_WIDE_SLASH:
DoCast(me, SPELL_WIDE_SLASH);
events.ScheduleEvent(EVENT_WIDE_SLASH, 11000);
break;
case EVENT_TRASH:
DoCast(me, SPELL_TRASH);
events.ScheduleEvent(EVENT_WIDE_SLASH, 16000);
break;*/
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool _isStonePhase;
};
CreatureAI* GetAI(Creature* creature) const override
void FilterTargets(std::list<WorldObject*>& targets)
{
return GetRuinsOfAhnQirajAI<boss_moamAI>(creature);
targets.remove_if([&](WorldObject* target) -> bool
{
return !target->IsPlayer() || target->ToPlayer()->getPowerType() != POWER_MANA;
});
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
caster->CastSpell(GetHitUnit(), SPELL_DRAIN_MANA, true);
}
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_moam_mana_drain_filter::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_moam_mana_drain_filter::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 25684 - Summon Mana Fiends (server-side)
class spell_moam_summon_mana_fiends : public SpellScript
{
PrepareSpellScript(spell_moam_summon_mana_fiends);
void HandleScript(SpellEffIndex /*effIndex*/)
{
const uint32 spellIds[3] = { SPELL_SUMMON_MANA_FIEND_1, SPELL_SUMMON_MANA_FIEND_2, SPELL_SUMMON_MANA_FIEND_3 };
for (uint32 spellId : spellIds)
{
GetCaster()->CastSpell((Unit*)nullptr, spellId, true);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_moam_summon_mana_fiends::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_boss_moam()
{
new boss_moam();
RegisterRuinsOfAhnQirajCreatureAI(boss_moam);
RegisterSpellScript(spell_moam_mana_drain_filter);
RegisterSpellScript(spell_moam_summon_mana_fiends);
}

View File

@@ -22,255 +22,248 @@
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "ruins_of_ahnqiraj.h"
#include "TaskScheduler.h"
enum Texts
{
SAY_SUPREME = 0,
SAY_INTRO = 1,
SAY_AGGRO = 2,
SAY_SLAY = 3,
SAY_DEATH = 4
SAY_SUPREME = 0,
SAY_INTRO = 1,
SAY_AGGRO = 2,
SAY_SLAY = 3,
SAY_DEATH = 4
};
enum Spells
{
SPELL_SILENCE = 25195,
SPELL_CYCLONE = 25189,
SPELL_STOMP = 25188,
SPELL_SUPREME = 25176,
SPELL_SUMMON = 20477,
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
};
enum Actions
{
ACTION_TRIGGER_WEAKNESS = 1
ACTION_TRIGGER_WEAKNESS = 1
};
enum Events
{
EVENT_SILENCE = 1,
EVENT_CYCLONE = 2,
EVENT_STOMP = 3
EVENT_SILENCE = 1,
EVENT_CYCLONE = 2,
EVENT_STOMP = 3
};
uint8 const NUM_CRYSTALS = 9;
// You spin me right round, baby
// right round like a record, baby
// right round round round
Position CrystalCoordinates[NUM_CRYSTALS] =
{
{ -9394.230469f, 1951.808594f, 85.97733f, 0.0f },
{ -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 }
{ -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 }
};
float RoomRadius = 165.0f;
uint8 const NUM_TORNADOS = 5; /// @todo This number is completly random!
float roomRadius = 165.0f;
uint8 const NUM_TORNADOS = 2;
uint8 const NUM_WEAKNESS = 5;
uint32 const SpellWeakness[NUM_WEAKNESS] = { 25177, 25178, 25180, 25181, 25183 };
uint32 const spellWeakness[NUM_WEAKNESS] = { 25177, 25178, 25180, 25181, 25183 };
Position const RoomCenter = { -9343.041992f, 1923.278198f, 85.555984f, 0.0 };
class boss_ossirian : public CreatureScript
struct boss_ossirian : public BossAI
{
public:
boss_ossirian() : CreatureScript("boss_ossirian") { }
struct boss_ossirianAI : public BossAI
boss_ossirian(Creature* creature) : BossAI(creature, DATA_OSSIRIAN)
{
boss_ossirianAI(Creature* creature) : BossAI(creature, DATA_OSSIRIAN)
{
SaidIntro = false;
}
ObjectGuid TriggerGUID;
ObjectGuid CrystalGUID;
uint8 CrystalIterator;
bool SaidIntro;
void Reset() override
{
_Reset();
CrystalIterator = 0;
TriggerGUID.Clear();
CrystalGUID.Clear();
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
for (uint8 i = 0; i < NUM_WEAKNESS; ++i)
{
if (spell->Id == SpellWeakness[i])
{
me->RemoveAurasDueToSpell(SPELL_SUPREME);
((TempSummon*)caster)->UnSummon();
SpawnNextCrystal();
}
}
}
void DoAction(int32 action) override
{
if (action == ACTION_TRIGGER_WEAKNESS)
if (Creature* Trigger = me->GetMap()->GetCreature(TriggerGUID))
if (!Trigger->HasUnitState(UNIT_STATE_CASTING))
Trigger->CastSpell(Trigger, SpellWeakness[urand(0, 4)], false);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.Reset();
events.ScheduleEvent(EVENT_SILENCE, 30000);
events.ScheduleEvent(EVENT_CYCLONE, 20000);
events.ScheduleEvent(EVENT_STOMP, 30000);
DoCast(me, SPELL_SUPREME);
Talk(SAY_AGGRO);
Map* map = me->GetMap();
if (!map->IsDungeon())
return;
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 KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
void EnterEvadeMode(EvadeReason why) override
{
Cleanup();
summons.DespawnAll();
BossAI::EnterEvadeMode(why);
}
void JustDied(Unit* /*killer*/) override
{
Cleanup();
_JustDied();
}
void Cleanup()
{
if (GameObject* Crystal = me->GetMap()->GetGameObject(CrystalGUID))
Crystal->Use(me);
}
void SpawnNextCrystal()
{
if (CrystalIterator == NUM_CRYSTALS)
CrystalIterator = 0;
if (Creature* Trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, CrystalCoordinates[CrystalIterator]))
{
TriggerGUID = 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();
++CrystalIterator;
Crystal->SetOwnerGUID(ObjectGuid::Empty);
}
}
}
void MoveInLineOfSight(Unit* who) override
{
if (!SaidIntro)
{
Talk(SAY_INTRO);
SaidIntro = true;
}
BossAI::MoveInLineOfSight(who);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
// No kiting!
if (me->GetDistance(me->GetVictim()) > 60.00f && me->GetDistance(me->GetVictim()) < 120.00f)
DoCastVictim(SPELL_SUMMON);
bool ApplySupreme = true;
if (me->HasAura(SPELL_SUPREME))
ApplySupreme = false;
else
{
for (uint8 i = 0; i < NUM_WEAKNESS; ++i)
{
if (me->HasAura(SpellWeakness[i]))
{
ApplySupreme = false;
break;
}
}
}
if (ApplySupreme)
{
DoCast(me, SPELL_SUPREME);
Talk(SAY_SUPREME);
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SILENCE:
DoCast(me, SPELL_SILENCE);
events.ScheduleEvent(EVENT_SILENCE, urand(20000, 30000));
break;
case EVENT_CYCLONE:
DoCastVictim(SPELL_CYCLONE);
events.ScheduleEvent(EVENT_CYCLONE, 20000);
break;
case EVENT_STOMP:
DoCast(me, SPELL_STOMP);
events.ScheduleEvent(EVENT_STOMP, 30000);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetRuinsOfAhnQirajAI<boss_ossirianAI>(creature);
_saidIntro = false;
}
void Reset() override
{
BossAI::Reset();
_crystalIterator = 0;
_triggerGUID.Clear();
_crystalGUID.Clear();
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
for (uint8 weakness : spellWeakness)
{
if (spell->Id == weakness)
{
me->RemoveAurasDueToSpell(SPELL_STRENGHT_OF_OSSIRIAN);
((TempSummon*)caster)->UnSummon();
SpawnNextCrystal();
}
}
}
void DoAction(int32 action) override
{
if (action == ACTION_TRIGGER_WEAKNESS)
{
if (Creature* trigger = me->GetMap()->GetCreature(_triggerGUID))
{
if (!trigger->HasUnitState(UNIT_STATE_CASTING))
{
trigger->CastSpell(trigger, spellWeakness[urand(0, 4)], false);
}
}
}
}
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
events.Reset();
events.ScheduleEvent(EVENT_SILENCE, 30s);
events.ScheduleEvent(EVENT_CYCLONE, 20s);
events.ScheduleEvent(EVENT_STOMP, 30s);
DoCastSelf(SPELL_STRENGHT_OF_OSSIRIAN);
Talk(SAY_AGGRO);
Map* map = me->GetMap();
if (!map->IsDungeon())
return;
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 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]))
{
_triggerGUID = 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();
++_crystalIterator;
crystal->SetOwnerGUID(ObjectGuid::Empty);
}
}
}
void MoveInLineOfSight(Unit* who) override
{
if (!_saidIntro)
{
Talk(SAY_INTRO);
_saidIntro = true;
}
BossAI::MoveInLineOfSight(who);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
bool applySupreme = true;
if (me->HasAura(SPELL_STRENGHT_OF_OSSIRIAN))
{
applySupreme = false;
}
else
{
for (uint8 weakness : spellWeakness)
{
if (me->HasAura(weakness))
{
applySupreme = false;
break;
}
}
}
if (applySupreme)
{
DoCastSelf(SPELL_STRENGHT_OF_OSSIRIAN);
Talk(SAY_SUPREME);
}
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SILENCE:
DoCastAOE(SPELL_CURSE_OF_TONGUES);
events.ScheduleEvent(EVENT_SILENCE, 20s, 30s);
break;
case EVENT_CYCLONE:
DoCastVictim(SPELL_ENVELOPING_WINDS);
events.ScheduleEvent(EVENT_CYCLONE, 20s);
break;
case EVENT_STOMP:
DoCastAOE(SPELL_WAR_STOMP);
events.ScheduleEvent(EVENT_STOMP, 30s);
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
protected:
ObjectGuid _triggerGUID;
ObjectGuid _crystalGUID;
uint8 _crystalIterator;
bool _saidIntro;
};
class go_ossirian_crystal : public GameObjectScript
@@ -280,21 +273,99 @@ public:
bool OnGossipHello(Player* player, GameObject* /*go*/) override
{
InstanceScript* Instance = player->GetInstanceScript();
if (!Instance)
InstanceScript* instance = player->GetInstanceScript();
if (!instance)
return false;
Creature* Ossirian = player->FindNearestCreature(NPC_OSSIRIAN, 30.0f);
if (!Ossirian || Instance->GetBossState(DATA_OSSIRIAN) != IN_PROGRESS)
Creature* ossirian = instance->GetCreature(DATA_OSSIRIAN);
if (!ossirian || instance->GetBossState(DATA_OSSIRIAN) != IN_PROGRESS)
return false;
Ossirian->AI()->DoAction(ACTION_TRIGGER_WEAKNESS);
ossirian->AI()->DoAction(ACTION_TRIGGER_WEAKNESS);
return true;
}
};
enum AnubisathGuardian
{
SPELL_METEOR = 24340,
SPELL_PLAGUE = 22997,
SPELL_SHADOW_STORM = 2148,
SPELL_THUNDER_CLAP = 2834,
SPELL_REFLECT_ARCANE_FIRE = 13022,
SPELL_REFLECT_FROST_SHADOW = 19595,
SPELL_ENRAGE = 8599,
SPELL_EXPLODE = 25698,
SPELL_SUMMON_ANUB_SWARMGUARD = 17430,
SPELL_SUMMON_ANUB_WARRIOR = 17431,
};
struct npc_anubisath_guardian : public ScriptedAI
{
npc_anubisath_guardian(Creature* creature) : ScriptedAI(creature)
{
_spells[0] = RAND(SPELL_SHADOW_STORM, SPELL_THUNDER_CLAP);
_spells[1] = RAND(SPELL_REFLECT_ARCANE_FIRE, SPELL_REFLECT_FROST_SHADOW);
}
void Reset() override
{
_enraged = false;
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void EnterCombat(Unit* /*who*/) override
{
DoCastSelf(_spells[0]);
DoCastSelf(_spells[1]);
_scheduler.CancelAll();
uint32 spell = RAND(SPELL_METEOR, SPELL_PLAGUE);
_scheduler.Schedule(10s, [this, spell](TaskContext context) {
DoCastRandomTarget(spell);
context.Repeat(10s, 15s);
});
spell = RAND(SPELL_SUMMON_ANUB_SWARMGUARD, SPELL_SUMMON_ANUB_WARRIOR);
_scheduler.Schedule(10s, [this, spell](TaskContext context) {
DoCastAOE(spell);
context.Repeat(10s, 15s);
});
}
void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType /* damagetype */, SpellSchoolMask /*damageSchoolMask*/) override
{
if (!_enraged && me->HealthBelowPctDamaged(10, damage))
{
_enraged = true;
DoCastSelf(RAND(SPELL_ENRAGE, SPELL_EXPLODE), true);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_scheduler.Update(diff,
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
}
private:
bool _enraged;
uint32 _spells[2];
TaskScheduler _scheduler;
};
void AddSC_boss_ossirian()
{
new boss_ossirian();
RegisterRuinsOfAhnQirajCreatureAI(boss_ossirian);
new go_ossirian_crystal();
RegisterCreatureAI(npc_anubisath_guardian);
}

View File

@@ -22,16 +22,6 @@
enum Yells
{
// The time of our retribution is at hand! Let darkness reign in the hearts of our enemies! Sound: 8645 Emote: 35
SAY_ANDOROV_INTRO = 0, // Before for the first wave
SAY_ANDOROV_ATTACK = 1, // Beginning the event
SAY_WAVE3 = 0,
SAY_WAVE4 = 1,
SAY_WAVE5 = 2,
SAY_WAVE6 = 3,
SAY_WAVE7 = 4,
SAY_INTRO = 5,
SAY_UNK1 = 6,
SAY_UNK2 = 7,
SAY_UNK3 = 8,
@@ -63,27 +53,25 @@ public:
struct boss_rajaxxAI : public BossAI
{
boss_rajaxxAI(Creature* creature) : BossAI(creature, DATA_RAJAXX)
{
}
boss_rajaxxAI(Creature* creature) : BossAI(creature, DATA_RAJAXX) { }
void Reset() override
{
_Reset();
enraged = false;
events.ScheduleEvent(EVENT_DISARM, 10000);
events.ScheduleEvent(EVENT_THUNDERCRASH, 12000);
}
void JustDied(Unit* /*killer*/) override
{
//SAY_DEATH
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

View File

@@ -15,10 +15,49 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureGroups.h"
#include "InstanceScript.h"
#include "ScriptMgr.h"
#include "TaskScheduler.h"
#include "ruins_of_ahnqiraj.h"
ObjectData const creatureData[] =
{
{ NPC_BURU, DATA_BURU },
{ NPC_KURINNAXX, DATA_KURINNAXX },
{ NPC_RAJAXX, DATA_RAJAXX },
{ NPC_OSSIRIAN, DATA_OSSIRIAN },
{ NPC_QUUEZ, DATA_QUUEZ },
{ NPC_TUUBID, DATA_TUUBID },
{ NPC_DRENN, DATA_DRENN },
{ NPC_XURREM, DATA_XURREM },
{ NPC_YEGGETH, DATA_YEGGETH },
{ NPC_PAKKON, DATA_PAKKON },
{ NPC_ZERRAN, DATA_ZERRAN },
};
enum RajaxxText
{
SAY_WAVE3 = 0,
SAY_WAVE4 = 1,
SAY_WAVE5 = 2,
SAY_WAVE6 = 3,
SAY_WAVE7 = 4,
SAY_ENGAGE = 5
};
std::array<uint32, 8> RajaxxWavesData[] =
{
{ DATA_QUUEZ, 0 },
{ DATA_TUUBID, 0 },
{ DATA_DRENN, SAY_WAVE3 },
{ DATA_XURREM, SAY_WAVE4 },
{ DATA_YEGGETH, SAY_WAVE5 },
{ DATA_PAKKON, SAY_WAVE6 },
{ DATA_ZERRAN, SAY_WAVE7 },
{ DATA_RAJAXX, SAY_ENGAGE }
};
class instance_ruins_of_ahnqiraj : public InstanceMapScript
{
public:
@@ -29,14 +68,18 @@ public:
instance_ruins_of_ahnqiraj_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetBossNumber(NUM_ENCOUNTER);
LoadObjectData(creatureData, nullptr);
_rajaxWaveCounter = 0;
}
void OnCreatureCreate(Creature* creature) override
{
InstanceScript::OnCreatureCreate(creature);
switch (creature->GetEntry())
{
case NPC_KURINAXX:
_kurinaxxGUID = creature->GetGUID();
case NPC_KURINNAXX:
_kurinnaxxGUID = creature->GetGUID();
break;
case NPC_RAJAXX:
_rajaxxGUID = creature->GetGUID();
@@ -56,12 +99,73 @@ public:
}
}
bool SetBossState(uint32 bossId, EncounterState state) override
void OnCreatureEvade(Creature* creature) override
{
if (!InstanceScript::SetBossState(bossId, state))
return false;
if (CreatureGroup* formation = creature->GetFormation())
{
if (Creature* leader = formation->GetLeader())
{
switch (leader->GetEntry())
{
case NPC_QUUEZ:
case NPC_TUUBID:
case NPC_DRENN:
case NPC_XURREM:
case NPC_YEGGETH:
case NPC_PAKKON:
case NPC_ZERRAN:
if (!formation->IsFormationInCombat())
{
ResetRajaxxWaves();
}
break;
default:
break;
}
}
}
else if (creature->GetEntry() == NPC_RAJAXX)
{
ResetRajaxxWaves();
}
}
return true;
void OnUnitDeath(Unit* unit) override
{
if (Creature* creature = unit->ToCreature())
{
if (CreatureGroup* formation = creature->GetFormation())
{
if (Creature* leader = formation->GetLeader())
{
switch (leader->GetEntry())
{
case NPC_QUUEZ:
case NPC_TUUBID:
case NPC_DRENN:
case NPC_XURREM:
case NPC_YEGGETH:
case NPC_PAKKON:
case NPC_ZERRAN:
_scheduler.CancelAll();
_scheduler.Schedule(1s, [this, formation](TaskContext /*context*/) {
if (!formation->IsAnyMemberAlive())
{
CallNextRajaxxLeader();
}
});
break;
default:
break;
}
}
}
}
}
void Update(uint32 diff) override
{
_scheduler.Update(diff);
}
void SetGuidData(uint32 type, ObjectGuid data) override
@@ -75,7 +179,7 @@ public:
switch (type)
{
case DATA_KURINNAXX:
return _kurinaxxGUID;
return _kurinnaxxGUID;
case DATA_RAJAXX:
return _rajaxxGUID;
case DATA_MOAM:
@@ -136,14 +240,56 @@ public:
OUT_LOAD_INST_DATA_COMPLETE;
}
void CallNextRajaxxLeader()
{
++_rajaxWaveCounter;
if (Creature* nextLeader = GetCreature(RajaxxWavesData[_rajaxWaveCounter].at(0)))
{
if (_rajaxWaveCounter >= 2)
{
if (Creature* rajaxx = GetCreature(DATA_RAJAXX))
{
rajaxx->AI()->Talk(RajaxxWavesData[_rajaxWaveCounter].at(1));
}
}
if (nextLeader->IsAlive())
{
nextLeader->SetInCombatWithZone();
}
else
{
CallNextRajaxxLeader();
}
}
}
void ResetRajaxxWaves()
{
_rajaxWaveCounter = 0;
for (auto const& data : RajaxxWavesData)
{
if (Creature* creature = GetCreature(data.at(0)))
{
if (CreatureGroup* group = creature->GetFormation())
{
group->RespawnFormation(true);
}
}
}
}
private:
ObjectGuid _kurinaxxGUID;
ObjectGuid _kurinnaxxGUID;
ObjectGuid _rajaxxGUID;
ObjectGuid _moamGUID;
ObjectGuid _buruGUID;
ObjectGuid _ayamissGUID;
ObjectGuid _ossirianGUID;
ObjectGuid _paralyzedGUID;
uint32 _rajaxWaveCounter;
TaskScheduler _scheduler;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override

View File

@@ -32,12 +32,22 @@ enum DataTypes
DATA_OSSIRIAN = 5,
NUM_ENCOUNTER = 6,
DATA_PARALYZED = 7
DATA_PARALYZED = 7,
DATA_QUUEZ = 8,
DATA_TUUBID = 9,
DATA_DRENN = 10,
DATA_XURREM = 11,
DATA_YEGGETH = 12,
DATA_PAKKON = 13,
DATA_ZERRAN = 14,
DATA_ENGAGED_FORMATION = 1
};
enum Creatures
{
NPC_KURINAXX = 15348,
NPC_KURINNAXX = 15348,
NPC_RAJAXX = 15341,
NPC_MOAM = 15340,
NPC_BURU = 15370,
@@ -49,9 +59,19 @@ enum Creatures
NPC_SAND_VORTEX = 15428,
NPC_OSSIRIAN_TRIGGER = 15590,
NPC_HATCHLING = 15521,
NPC_BURU_EGG = 15514,
NPC_LARVA = 15555,
NPC_SWARMER = 15546,
NPC_HORNET = 15934
NPC_HORNET = 15934,
// Rajaxx
NPC_QUUEZ = 15391,
NPC_TUUBID = 15392,
NPC_DRENN = 15389,
NPC_XURREM = 15390,
NPC_YEGGETH = 15386,
NPC_PAKKON = 15388,
NPC_ZERRAN = 15385
};
enum GameObjects
@@ -65,4 +85,6 @@ inline AI* GetRuinsOfAhnQirajAI(T* obj)
return GetInstanceAI<AI>(obj, RuinsOfAhnQirajScriptName);
}
#define RegisterRuinsOfAhnQirajCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetRuinsOfAhnQirajAI)
#endif

View File

@@ -195,6 +195,18 @@ public:
instance->SetData(DATA_CTHUN_PHASE, PHASE_EYE_GREEN_BEAM);
}
void MoveInLineOfSight(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER && !me->IsInCombat())
{
// Z checks are necessary here because AQ maps do funky stuff.
if (me->IsWithinLOSInMap(who) && me->IsWithinDist2d(who, 50.0f) && who->GetPositionZ() > 100.0f)
{
AttackStart(who);
}
}
}
void DoAction(int32 action) override
{
if (action == ACTION_SPAWN_EYE_TENTACLES)
@@ -367,6 +379,7 @@ public:
me->InterruptNonMeleeSpells(true);
me->RemoveAllAuras();
_scheduler.CancelAll();
break;
case PHASE_CTHUN_DONE:
@@ -819,13 +832,11 @@ public:
}
}
void DoAction(int32 param) override
void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override
{
switch (param)
if (creature->GetEntry() == NPC_FLESH_TENTACLE)
{
case ACTION_FLESH_TENTACLE_KILLED:
++FleshTentaclesKilled;
break;
++FleshTentaclesKilled;
}
}
};
@@ -1178,33 +1189,6 @@ public:
};
};
class npc_giant_flesh_tentacle : public CreatureScript
{
public:
npc_giant_flesh_tentacle() : CreatureScript("npc_giant_flesh_tentacle") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new flesh_tentacleAI(creature);
}
struct flesh_tentacleAI : public ScriptedAI
{
flesh_tentacleAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
}
void JustDied(Unit* /*killer*/) override
{
if (TempSummon* summon = me->ToTempSummon())
if (Unit* summoner = summon->GetSummonerUnit())
if (summoner->IsAIEnabled)
summoner->GetAI()->DoAction(ACTION_FLESH_TENTACLE_KILLED);
}
};
};
//GetAIs
void AddSC_boss_cthun()
@@ -1215,5 +1199,4 @@ void AddSC_boss_cthun()
new npc_claw_tentacle();
new npc_giant_claw_tentacle();
new npc_giant_eye_tentacle();
new npc_giant_flesh_tentacle();
}

View File

@@ -24,6 +24,7 @@ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "temple_of_ahnqiraj.h"
#define SOUND_SENTENCE_YOU 8588
@@ -34,7 +35,7 @@ EndScriptData */
enum Spells
{
SPELL_MORTAL_WOUND = 28467,
SPELL_MORTAL_WOUND = 25646,
SPELL_ROOT = 28858,
// Enrage for his spawns
@@ -55,28 +56,8 @@ public:
{
boss_fankrissAI(Creature* creature) : ScriptedAI(creature) { }
uint32 MortalWound_Timer;
uint32 SpawnHatchlings_Timer;
uint32 SpawnSpawns_Timer;
int Rand;
float RandX;
float RandY;
Creature* Hatchling;
Creature* Spawn;
void Reset() override
void SummonSpawn()
{
MortalWound_Timer = urand(10000, 15000);
SpawnHatchlings_Timer = urand(6000, 12000);
SpawnSpawns_Timer = urand(15000, 45000);
}
void SummonSpawn(Unit* victim)
{
if (!victim)
return;
Rand = 10 + (rand() % 10);
switch (rand() % 2)
{
@@ -99,13 +80,68 @@ public:
break;
}
Rand = 0;
Spawn = DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
if (Spawn)
Spawn->AI()->AttackStart(victim);
DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
}
void EnterCombat(Unit* /*who*/) override
{
_scheduler.CancelAll();
_scheduler.Schedule(4s, 8s, [this](TaskContext context) {
DoCastVictim(SPELL_MORTAL_WOUND);
context.Repeat();
}).Schedule(15s, 45s, [this](TaskContext context) {
switch (urand(0, 2))
{
case 0:
SummonSpawn();
break;
case 1:
SummonSpawn();
SummonSpawn();
break;
case 2:
SummonSpawn();
SummonSpawn();
SummonSpawn();
break;
}
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);
});
}
void UpdateAI(uint32 diff) override
@@ -114,105 +150,15 @@ public:
if (!UpdateVictim())
return;
//MortalWound_Timer
if (MortalWound_Timer <= diff)
{
DoCastVictim(SPELL_MORTAL_WOUND);
MortalWound_Timer = urand(10000, 20000);
}
else MortalWound_Timer -= diff;
//Summon 1-3 Spawns of Fankriss at random time.
if (SpawnSpawns_Timer <= diff)
{
switch (urand(0, 2))
{
case 0:
SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0));
break;
case 1:
SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0));
SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0));
break;
case 2:
SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0));
SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0));
SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0));
break;
}
SpawnSpawns_Timer = urand(30000, 60000);
}
else SpawnSpawns_Timer -= diff;
// Teleporting Random Target to one of the three tunnels and spawn 4 hatchlings near the gamer.
//We will only telport if fankriss has more than 3% of hp so teleported gamers can always loot.
if (HealthAbovePct(3))
{
if (SpawnHatchlings_Timer <= diff)
{
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);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
break;
case 1:
DoTeleportPlayer(target, -7990.135354f, 1155.1907f, -78.849319f, 2.608f);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
break;
case 2:
DoTeleportPlayer(target, -8159.7753f, 1127.9064f, -76.868660f, 0.675f);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Hatchling)
Hatchling->AI()->AttackStart(target);
break;
}
}
SpawnHatchlings_Timer = urand(45000, 60000);
}
else SpawnHatchlings_Timer -= diff;
}
DoMeleeAttackIfReady();
_scheduler.Update(diff,
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
}
private:
TaskScheduler _scheduler;
int Rand;
float RandX;
float RandY;
};
};

View File

@@ -24,6 +24,7 @@ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "temple_of_ahnqiraj.h"
enum Huhuran
@@ -36,7 +37,8 @@ enum Huhuran
SPELL_POISONBOLT = 26052,
SPELL_NOXIOUSPOISON = 26053,
SPELL_WYVERNSTING = 26180,
SPELL_ACIDSPIT = 26050
SPELL_ACIDSPIT = 26050,
SPELL_WYVERN_STING_DAMAGE = 26233
};
class boss_huhuran : public CreatureScript
@@ -76,10 +78,6 @@ public:
Berserk = false;
}
void EnterCombat(Unit* /*who*/) override
{
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
@@ -100,8 +98,7 @@ public:
// Wyvern Timer
if (Wyvern_Timer <= diff)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
DoCast(target, SPELL_WYVERNSTING);
DoCastAOE(SPELL_WYVERNSTING);
Wyvern_Timer = urand(15000, 32000);
}
else Wyvern_Timer -= diff;
@@ -155,7 +152,27 @@ public:
};
};
// 26180 - Wyvern Sting
class spell_huhuran_wyvern_sting : public AuraScript
{
PrepareAuraScript(spell_huhuran_wyvern_sting);
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* caster = GetCaster())
{
caster->CastCustomSpell(SPELL_WYVERN_STING_DAMAGE, SPELLVALUE_BASE_POINT0, 3000, GetUnitOwner(), true);
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_huhuran_wyvern_sting::HandleRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_huhuran()
{
new boss_huhuran();
RegisterSpellScript(spell_huhuran_wyvern_sting);
}

View File

@@ -58,6 +58,7 @@ public:
void Reset() override
{
_Reset();
_flag = 0;
_hpct = 75.0f;
me->SetVisible(true);
@@ -96,9 +97,6 @@ public:
if (_flag & (1 << 7))
_flag = 0;
if (Unit* Target = SelectTarget(SelectTargetMethod::Random))
creature->AI()->AttackStart(Target);
float ImageHealthPct;
if (me->GetHealthPct() < 25.0f)
@@ -110,12 +108,16 @@ public:
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();
}
@@ -169,7 +171,7 @@ public:
if (!me->IsSummon() && me->GetHealthPct() < _hpct)
{
DoCast(me, SPELL_SUMMON_IMAGES);
DoCast(me, SPELL_SUMMON_IMAGES, true);
Talk(SAY_SPLIT);
_hpct -= 25.0f;
me->SetVisible(false);

View File

@@ -4472,6 +4472,104 @@ class spell_gen_remove_impairing_auras : public SpellScript
}
};
enum AQSpells
{
SPELL_CONSUME_LEECH_AQ20 = 25373,
SPELL_CONSUME_LEECH_HEAL_AQ20 = 25378,
SPELL_CONSUME_SPIT_OUT = 25383,
SPELL_HIVEZARA_CATALYST = 25187
};
class spell_gen_consume : public AuraScript
{
PrepareAuraScript(spell_gen_consume);
public:
spell_gen_consume(uint32 spellId1, uint32 spellId2) : AuraScript(), _spellId1(spellId1), _spellId2(spellId2) { }
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ _spellId1, _spellId2 });
}
void HandleProc(AuraEffect* /*aurEff*/)
{
if (Unit* caster = GetCaster())
{
if (!caster->IsAlive())
{
GetUnitOwner()->RemoveAurasDueToSpell(GetSpellInfo()->Id);
return;
}
caster->CastSpell(GetUnitOwner(), _spellId1, true);
}
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication())
{
if (Unit* caster = GetCaster())
{
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH)
{
caster->CastSpell(caster, _spellId2, true);
}
else if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
{
caster->CastSpell(GetTarget(), SPELL_CONSUME_SPIT_OUT, true);
}
}
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_gen_consume::AfterRemove, EFFECT_1, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_gen_consume::HandleProc, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
private:
uint32 _spellId1;
uint32 _spellId2;
};
class spell_gen_apply_aura_after_expiration : public AuraScript
{
PrepareAuraScript(spell_gen_apply_aura_after_expiration);
public:
spell_gen_apply_aura_after_expiration(uint32 spellId, uint32 effect, uint32 aura) : AuraScript(), _spellId(spellId), _effect(effect), _aura(aura) { }
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ _spellId });
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication() && GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
{
if (Unit* caster = GetCaster())
{
caster->CastSpell(GetTarget(), _spellId, true);
}
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_gen_apply_aura_after_expiration::AfterRemove, _effect, _aura, AURA_EFFECT_HANDLE_REAL);
}
private:
uint32 _spellId;
uint32 _effect;
uint32 _aura;
};
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_silithyst);
@@ -4569,6 +4667,7 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_teleporting);
RegisterSpellScript(spell_gen_ds_flush_knockback);
RegisterSpellScriptWithArgs(spell_gen_count_pct_from_max_hp, "spell_gen_default_count_pct_from_max_hp");
RegisterSpellScriptWithArgs(spell_gen_count_pct_from_max_hp, "spell_gen_10pct_count_pct_from_max_hp", 10);
RegisterSpellScriptWithArgs(spell_gen_count_pct_from_max_hp, "spell_gen_50pct_count_pct_from_max_hp", 50);
RegisterSpellScriptWithArgs(spell_gen_count_pct_from_max_hp, "spell_gen_100pct_count_pct_from_max_hp", 100);
RegisterSpellScript(spell_gen_despawn_self);
@@ -4605,4 +4704,6 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_holiday_buff_food);
RegisterSpellScript(spell_gen_arcane_charge);
RegisterSpellScript(spell_gen_remove_impairing_auras);
RegisterSpellScriptWithArgs(spell_gen_consume, "spell_consume_aq20", SPELL_CONSUME_LEECH_AQ20, SPELL_CONSUME_LEECH_HEAL_AQ20);
RegisterSpellScriptWithArgs(spell_gen_apply_aura_after_expiration, "spell_itch_aq20", SPELL_HIVEZARA_CATALYST, EFFECT_0, SPELL_AURA_DUMMY);
}

View File

@@ -842,22 +842,17 @@ class spell_pri_vampiric_touch : public AuraScript
bool CheckProc(ProcEventInfo& eventInfo)
{
if (!eventInfo.GetActionTarget() || GetOwner()->GetGUID() != eventInfo.GetActionTarget()->GetGUID())
return false;
if (eventInfo.GetTypeMask() & PROC_FLAG_KILLED)
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
{
if (spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (spellInfo->SpellFamilyFlags[0] & 0x00002000))
{
return true;
}
}
return false;
}
return eventInfo.GetActionTarget()->IsAlive();
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo || spellInfo->SpellFamilyName != SPELLFAMILY_PRIEST || !(spellInfo->SpellFamilyFlags[0] & 0x00002000))
{
return false;
}
return true;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)

View File

@@ -21,6 +21,7 @@
* Scriptnames of files in this file should be prefixed with "spell_warl_".
*/
#include "Pet.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "SpellAuraEffects.h"
@@ -1229,6 +1230,45 @@ class spell_warl_shadowburn : public AuraScript
}
};
class spell_warl_glyph_of_felguard : public AuraScript
{
PrepareAuraScript(spell_warl_glyph_of_felguard);
void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_FELGUARD)
{
pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true);
}
}
}
}
void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
if (Pet* pet = player->GetPet())
{
if (pet->GetEntry() == NPC_FELGUARD)
{
pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), false);
}
}
}
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_warl_glyph_of_felguard::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_warl_glyph_of_felguard::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_warlock_spell_scripts()
{
RegisterSpellScript(spell_warl_eye_of_kilrogg);
@@ -1260,4 +1300,5 @@ void AddSC_warlock_spell_scripts()
RegisterSpellScript(spell_warl_unstable_affliction);
RegisterSpellScript(spell_warl_drain_soul);
RegisterSpellScript(spell_warl_shadowburn);
RegisterSpellScript(spell_warl_glyph_of_felguard);
}