Merge branch 'master' of github.com:azerothcore/azerothcore-wotlk into Playerbot

This commit is contained in:
Yunfan Li
2023-09-23 22:44:15 +08:00
154 changed files with 7913 additions and 4858 deletions

View File

@@ -290,7 +290,7 @@ public:
bool OnGossipHello(Player* player, GameObject* go) override
{
if (InstanceScript* instance = go->GetInstanceScript())
if (instance->GetData(DATA_EGG_EVENT) != DONE && !player->HasAura(SPELL_MIND_EXHAUSTION))
if (instance->GetData(DATA_EGG_EVENT) != DONE && !player->HasAura(SPELL_MIND_EXHAUSTION) && !player->GetPet())
if (Creature* razor = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_RAZORGORE_THE_UNTAMED)))
{
razor->AI()->SetGUID(player->GetGUID());

View File

@@ -54,9 +54,11 @@ struct boss_curator : public BossAI
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_POWER_BURN, true);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_BURN, true);
ScheduleHealthCheckEvent(15, [&] {
DoCastSelf(SPELL_ARCANE_INFUSION, true);
Talk(SAY_ENRAGE);
me->InterruptNonMeleeSpells(true);
DoCastSelf(SPELL_ARCANE_INFUSION, true);
Talk(SAY_ENRAGE);
});
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA));
}
void KilledUnit(Unit* victim) override
@@ -85,7 +87,7 @@ struct boss_curator : public BossAI
DoCastSelf(SPELL_ASTRAL_DECONSTRUCTION, true);
}).Schedule(10s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, 45.0f, true, false))
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 45.0f, true, false))
{
DoCast(target, SPELL_HATEFUL_BOLT);
}

View File

@@ -218,13 +218,17 @@ struct boss_netherspite : public BossAI
}
}).Schedule(10s, PORTAL_PHASE, [this](TaskContext context)
{
UpdatePortals();
context.Repeat(1s);
UpdatePortals();
context.Repeat(1s);
}).Schedule(10s, PORTAL_PHASE, [this](TaskContext context)
{
DoCastSelf(SPELL_EMPOWERMENT);
me->AddAura(SPELL_NETHERBURN_AURA, me);
context.Repeat(90s);
DoCastSelf(SPELL_EMPOWERMENT);
me->AddAura(SPELL_NETHERBURN_AURA, me);
context.Repeat(90s);
}).Schedule(15s, PORTAL_PHASE, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_VOIDZONE, 1, 45.0f, true, true);
context.Repeat(15s);
});
Talk(EMOTE_PHASE_PORTAL);
}
@@ -237,13 +241,10 @@ struct boss_netherspite : public BossAI
DoCastSelf(SPELL_BANISH_VISUAL, true);
DoCastSelf(SPELL_BANISH_ROOT, true);
DestroyPortals();
scheduler.Schedule(30s, [this](TaskContext /*context*/)
scheduler.Schedule(30s, [this](TaskContext)
{
if (!me->IsNonMeleeSpellCast(false))
{
SwitchToPortalPhase();
return;
}
SwitchToPortalPhase();
return;
}).Schedule(10s, VANISH_PHASE, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_NETHERBREATH, 0, 40.0f, true);
@@ -270,11 +271,7 @@ struct boss_netherspite : public BossAI
HandleDoors(false);
SwitchToPortalPhase();
DoZoneInCombat();
scheduler.Schedule(15s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_VOIDZONE, 1, 45.0f, true, true);
context.Repeat(15s);
}).Schedule(9min, [this](TaskContext /*context*/)
scheduler.Schedule(9min, [this](TaskContext /*context*/)
{
if (!berserk)
{

View File

@@ -18,6 +18,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "karazhan.h"
enum PrinceSay
@@ -47,11 +48,13 @@ enum Spells
enum creatures
{
NPC_NETHERSPITE_INFERNAL = 17646,
NPC_MALCHEZARS_AXE = 17650,
INFERNAL_MODEL_INVISIBLE = 11686,
SPELL_INFERNAL_RELAY = 33814, // 30835,
EQUIP_ID_AXE = 33542
NPC_NETHERSPITE_INFERNAL = 17646,
NPC_MALCHEZAARS_AXE = 17650,
INFERNAL_MODEL_INVISIBLE = 11686,
SPELL_INFERNAL_RELAY = 33814, // 30835,
SPELL_INFERNAL_RELAY_ONE = 30834,
SPELL_INFERNAL_RELAY_TWO = 30835,
EQUIP_ID_AXE = 33542
};
enum EventGroups
@@ -68,44 +71,19 @@ enum Phases
PHASE_THREE = 3
};
struct InfernalPoint
{
float x, y;
};
#define INFERNAL_Z 275.5f
/*static InfernalPoint InfernalPoints[] =
{
{ -10922.8f, -1985.2f },
{ -10916.2f, -1996.2f },
{ -10932.2f, -2008.1f },
{ -10948.8f, -2022.1f },
{ -10958.7f, -1997.7f },
{ -10971.5f, -1997.5f },
{ -10990.8f, -1995.1f },
{ -10989.8f, -1976.5f },
{ -10971.6f, -1973.0f },
{ -10955.5f, -1974.0f },
{ -10939.6f, -1969.8f },
{ -10958.0f, -1952.2f },
{ -10941.7f, -1954.8f },
{ -10943.1f, -1988.5f },
{ -10948.8f, -2005.1f },
{ -10984.0f, -2019.3f },
{ -10932.8f, -1979.6f },
{ -10935.7f, -1996.0f }
};*/
struct boss_malchezaar : public BossAI
{
boss_malchezaar(Creature* creature) : BossAI(creature, DATA_MALCHEZZAR) { }
boss_malchezaar(Creature* creature) : BossAI(creature, DATA_MALCHEZAAR) { }
std::list<Creature*> relays;
std::list<Creature*> infernalTargets;
void Initialize()
{
_phase = 1;
clearweapons();
positions.clear();
relays.clear();
infernalTargets.clear();
instance->HandleGameObject(instance->GetGuidData(DATA_GO_NETHER_DOOR), true);
}
@@ -145,7 +123,7 @@ struct boss_malchezaar : public BossAI
_phase = PHASE_THREE;
clearweapons();
me->SummonCreature(NPC_MALCHEZARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
me->SummonCreature(NPC_MALCHEZAARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
scheduler.Schedule(20s, 30s, [this](TaskContext context)
{
@@ -174,15 +152,52 @@ struct boss_malchezaar : public BossAI
instance->HandleGameObject(instance->GetGuidData(DATA_GO_NETHER_DOOR), true);
}
void SpawnInfernal(Creature* relay, Creature* target)
{
if (Creature* infernal = relay->SummonCreature(NPC_NETHERSPITE_INFERNAL, target->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 180000))
{
infernal->SetDisplayId(INFERNAL_MODEL_INVISIBLE);
relay->CastSpell(infernal, SPELL_INFERNAL_RELAY);
infernal->SetFaction(me->GetFaction());
infernal->SetControlled(true, UNIT_STATE_ROOT);
relay->CastSpell(infernal, SPELL_INFERNAL_RELAY);
summons.Summon(infernal);
}
}
bool MaxSpawns(std::list<Creature*> spawns)
{
return spawns.size() == 0;
}
Creature* PickTarget(std::list<Creature*> pickList)
{
uint8 index = urand(0, pickList.size()-1);
uint8 counter = 0;
for (Creature* creature : pickList)
{
if (counter == index)
{
return creature;
}
counter++;
}
return nullptr;
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
_JustEngagedWith();
me->GetCreaturesWithEntryInRange(relays, 250.0f, NPC_INFERNAL_RELAY);
me->GetCreaturesWithEntryInRange(infernalTargets, 100.0f, NPC_INFERNAL_TARGET);
instance->HandleGameObject(instance->GetGuidData(DATA_GO_NETHER_DOOR), false);
scheduler.Schedule(30s, [this](TaskContext context)
{
EnfeebleHealthEffect();
DoCastAOE(SPELL_ENFEEBLE);
scheduler.Schedule(9s, [this](TaskContext)
{
@@ -199,23 +214,30 @@ struct boss_malchezaar : public BossAI
context.Repeat();
}).Schedule(40s, [this](TaskContext context)
{
Position pos = me->GetRandomNearPosition(40.0);;
if (Creature* RELAY = me->FindNearestCreature(NPC_RELAY, 100.0f))
if (!MaxSpawns(infernalTargets)) // only spawn infernal when the area is not full
{
if (Creature* infernal = RELAY->SummonCreature(NPC_NETHERSPITE_INFERNAL, pos, TEMPSUMMON_TIMED_DESPAWN, 180000))
Talk(SAY_SUMMON);
if (Creature* infernalRelayOne = relays.back())
{
infernal->SetDisplayId(INFERNAL_MODEL_INVISIBLE);
infernal->SetFaction(me->GetFaction());
infernal->SetControlled(true, UNIT_STATE_ROOT);
RELAY->AI()->DoCast(infernal, SPELL_INFERNAL_RELAY);
summons.Summon(infernal);
if (Creature* infernalRelayTwo = relays.front())
{
infernalRelayOne->CastSpell(infernalRelayTwo, SPELL_INFERNAL_RELAY_ONE, true);
if (Creature* infernalTarget = PickTarget(infernalTargets))
{
infernalTargets.remove(infernalTarget);
SpawnInfernal(infernalRelayTwo, infernalTarget);
scheduler.Schedule(3min, [this, infernalTarget](TaskContext)
{
infernalTargets.push_back(infernalTarget); //adds to list again
});
}
}
}
}
context.Repeat(_phase == PHASE_THREE ? 15s : 45s);
Talk(SAY_SUMMON);
}).Schedule(20s, [this](TaskContext context)
{
DoCastVictim(SPELL_SHADOW_WORD_PAIN);
@@ -224,23 +246,12 @@ struct boss_malchezaar : public BossAI
});
}
void EnfeebleHealthEffect()
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
{
std::list<Unit*> targetList;
SelectTargetList(targetList, 5, SelectTargetMethod::Random, 1, [&](Unit* u) { return u->IsAlive() && u->IsPlayer(); });
if (targetList.empty())
return;
for (auto const& target : targetList)
if (spell->Id == SPELL_ENFEEBLE)
{
if (target)
{
_enfeebleTargets[target->GetGUID()] = target->GetHealth();
me->CastSpell(target, SPELL_ENFEEBLE, true);
target->SetHealth(1);
}
_enfeebleTargets[target->GetGUID()] = target->GetHealth();
target->SetHealth(1);
}
}
@@ -261,7 +272,6 @@ struct boss_malchezaar : public BossAI
private:
uint32 _phase;
std::map<ObjectGuid, uint32> _enfeebleTargets;
std::vector<InfernalPoint*> positions;
};
struct npc_netherspite_infernal : public ScriptedAI
@@ -357,9 +367,43 @@ struct npc_malchezaar_axe : public ScriptedAI
TaskScheduler _scheduler;
};
// 30843 - Enfeeble
class spell_malchezaar_enfeeble : public SpellScript
{
PrepareSpellScript(spell_malchezaar_enfeeble);
bool Load() override
{
return GetCaster()->ToCreature();
}
void FilterTargets(std::list<WorldObject*>& targets)
{
uint8 maxSize = 5;
Unit* caster = GetCaster();
targets.remove_if([caster](WorldObject const* target) -> bool
{
// Should not target current victim.
return caster->GetVictim() == target;
});
if (targets.size() > maxSize)
{
Acore::Containers::RandomResize(targets, maxSize);
}
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_malchezaar_enfeeble::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
void AddSC_boss_malchezaar()
{
RegisterKarazhanCreatureAI(boss_malchezaar);
RegisterKarazhanCreatureAI(npc_malchezaar_axe);
RegisterKarazhanCreatureAI(npc_netherspite_infernal);
RegisterSpellScript(spell_malchezaar_enfeeble);
}

View File

@@ -55,7 +55,6 @@ enum ShadeOfAran
//Creature Spells
SPELL_CIRCULAR_BLIZZARD = 29951,
SPELL_WATERBOLT = 31012,
SPELL_SHADOW_PYRO = 29978,
//Creatures
@@ -77,6 +76,8 @@ enum Groups
GROUP_DRINKING = 1
};
Position const roomCenter = {-11158.f, -1920.f};
Position const elementalPos[4] =
{
{-11168.1f, -1939.29f, 232.092f, 1.46f},
@@ -103,12 +104,10 @@ struct boss_shade_of_aran : public BossAI
uint32 CurrentNormalSpell;
bool Drinking;
void Reset() override
{
BossAI::Reset();
drinkScheduler.CancelAll();
_drinkScheduler.CancelAll();
LastSuperSpell = rand() % 3;
for (uint8 i = 0; i < 3; ++i)
@@ -120,7 +119,7 @@ struct boss_shade_of_aran : public BossAI
_fireCooledDown = true;
_frostCooledDown = true;
Drinking = false;
_drinking = false;
// Not in progress
instance->SetData(DATA_ARAN, NOT_STARTED);
@@ -149,6 +148,23 @@ struct boss_shade_of_aran : public BossAI
});
}
bool CheckAranInRoom()
{
return me->GetDistance2d(roomCenter.GetPositionX(), roomCenter.GetPositionY()) < 45.0f;
}
void AttackStart(Unit* who) override
{
if (who && who->isTargetableForAttack() && me->GetReactState() != REACT_PASSIVE)
{
if (me->Attack(who, false))
{
me->GetMotionMaster()->MoveChase(who, 45.0f, 0);
me->AddThreat(who, 0.0f);
}
}
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_KILL);
@@ -207,9 +223,9 @@ struct boss_shade_of_aran : public BossAI
libraryDoor->SetGoState(GO_STATE_READY);
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
}).Schedule(1ms, [this](TaskContext context)
}).Schedule(1s, [this](TaskContext context)
{
if (!me->IsNonMeleeSpellCast(false))
if (!me->IsNonMeleeSpellCast(false) && !_drinking)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
if (!target)
@@ -242,93 +258,144 @@ struct boss_shade_of_aran : public BossAI
DoCast(target, CurrentNormalSpell);
}
}
context.Repeat(10s);
context.Repeat(2s);
}).Schedule(5s, [this](TaskContext context)
{
switch (urand(0, 1))
if (!_drinking)
{
case 0:
DoCastSelf(SPELL_AOE_CS);
break;
case 1:
DoCastRandomTarget(SPELL_CHAINSOFICE);
break;
switch (urand(0, 1))
{
case 0:
DoCastSelf(SPELL_AOE_CS);
break;
case 1:
DoCastRandomTarget(SPELL_CHAINSOFICE);
break;
}
}
context.Repeat(5s, 20s);
}).Schedule(35s, [this](TaskContext context)
{
uint8 Available[2];
switch (LastSuperSpell)
if (!_drinking)
{
case SUPER_AE:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_FLAME:
Available[0] = SUPER_AE;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_BLIZZARD:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_AE;
break;
}
uint8 Available[2];
LastSuperSpell = Available[urand(0, 1)];
switch (LastSuperSpell)
{
case SUPER_AE:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_FLAME:
Available[0] = SUPER_AE;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_BLIZZARD:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_AE;
break;
}
switch (LastSuperSpell)
{
case SUPER_AE:
Talk(SAY_EXPLOSION);
LastSuperSpell = Available[urand(0, 1)];
DoCastSelf(SPELL_BLINK_CENTER, true);
DoCastSelf(SPELL_PLAYERPULL, true);
DoCastSelf(SPELL_MASSSLOW, true);
DoCastSelf(SPELL_AEXPLOSION, false);
break;
switch (LastSuperSpell)
{
case SUPER_AE:
Talk(SAY_EXPLOSION);
case SUPER_FLAME:
Talk(SAY_FLAMEWREATH);
DoCastSelf(SPELL_BLINK_CENTER, true);
DoCastSelf(SPELL_PLAYERPULL, true);
DoCastSelf(SPELL_MASSSLOW, true);
DoCastSelf(SPELL_AEXPLOSION, false);
break;
scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext)
{
scheduler.CancelGroup(GROUP_FLAMEWREATH);
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
{
for (uint8 i = 0; i < 3; ++i)
case SUPER_FLAME:
Talk(SAY_FLAMEWREATH);
scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext)
{
if (!FlameWreathTarget[i])
continue;
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
scheduler.CancelGroup(GROUP_FLAMEWREATH);
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
{
for (uint8 i = 0; i < 3; ++i)
{
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
FlameWreathTarget[i].Clear();
if (!FlameWreathTarget[i])
continue;
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
{
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
FlameWreathTarget[i].Clear();
}
}
context.Repeat(500ms);
});
FlameWreathTarget[0].Clear();
FlameWreathTarget[1].Clear();
FlameWreathTarget[2].Clear();
FlameWreathEffect();
break;
case SUPER_BLIZZARD:
Talk(SAY_BLIZZARD);
if (Creature* pSpawn = me->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
{
pSpawn->SetFaction(me->GetFaction());
pSpawn->CastSpell(me, SPELL_CIRCULAR_BLIZZARD, false);
}
context.Repeat(500ms);
});
FlameWreathTarget[0].Clear();
FlameWreathTarget[1].Clear();
FlameWreathTarget[2].Clear();
FlameWreathEffect();
break;
case SUPER_BLIZZARD:
Talk(SAY_BLIZZARD);
if (Creature* pSpawn = me->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
{
pSpawn->SetFaction(me->GetFaction());
pSpawn->CastSpell(me, SPELL_CIRCULAR_BLIZZARD, false);
}
break;
break;
}
}
context.Repeat(35s, 40s);
}).Schedule(1s, [this](TaskContext context){
if (me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
{
_drinking = true;
me->InterruptNonMeleeSpells(true);
Talk(SAY_DRINK);
DoCastSelf(SPELL_MASS_POLY, true);
DoCastSelf(SPELL_CONJURE, false);
me->SetReactState(REACT_PASSIVE);
me->SetStandState(UNIT_STAND_STATE_SIT);
DoCastSelf(SPELL_DRINK, true);
_currentHealth = me->GetHealth();
_drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context)
{
//check for damage to interrupt
if (me->GetHealth() < _currentHealth)
{
me->RemoveAurasDueToSpell(SPELL_DRINK);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, false);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
_drinkScheduler.CancelGroup(GROUP_DRINKING);
_drinking = false;
} else
{
context.Repeat(500ms);
}
}).Schedule(10s, GROUP_DRINKING, [this](TaskContext)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, true);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
_drinkScheduler.CancelGroup(GROUP_DRINKING);
_drinking = false;
});
context.Repeat(12s); //semi-arbitrary duration to envelop drinking duration
}
else
{
context.Repeat(1s);
}
}).Schedule(12min, [this](TaskContext context)
{
for (uint32 i = 0; i < 5; ++i)
@@ -384,70 +451,21 @@ struct boss_shade_of_aran : public BossAI
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
drinkScheduler.Update(diff);
_drinkScheduler.Update(diff);
if (!UpdateVictim())
return;
if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
if (!CheckAranInRoom())
{
Drinking = true;
me->InterruptNonMeleeSpells(false);
Talk(SAY_DRINK);
scheduler.DelayAll(10s);
DoCastSelf(SPELL_MASS_POLY, true);
DoCastSelf(SPELL_CONJURE, false);
me->SetReactState(REACT_PASSIVE);
me->SetStandState(UNIT_STAND_STATE_SIT);
DoCastSelf(SPELL_DRINK, true);
_currentHealth = me->GetHealth();
drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context)
{
//check for damage to interrupt
if(CheckDamageDuringDrinking(_currentHealth))
{
Drinking = false;
me->RemoveAurasDueToSpell(SPELL_DRINK);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, false);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
drinkScheduler.CancelGroup(GROUP_DRINKING);
} else {
context.Repeat(500ms);
}
}).Schedule(10s, GROUP_DRINKING, [this](TaskContext)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, true);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
Drinking = false;
drinkScheduler.CancelGroup(GROUP_DRINKING);
});
EnterEvadeMode();
return;
}
if (_arcaneCooledDown && _fireCooledDown && _frostCooledDown && !Drinking)
if (_arcaneCooledDown && _fireCooledDown && _frostCooledDown && !_drinking)
DoMeleeAttackIfReady();
}
bool CheckDamageDuringDrinking(uint32 oldHealth)
{
if (Drinking)
{
if (me->GetHealth() < oldHealth)
{
return true;
}
}
return false;
}
void SpellHit(Unit* /*pAttacker*/, SpellInfo const* Spell) override
{
//We only care about interrupt effects and only if they are durring a spell currently being cast
@@ -476,52 +494,16 @@ struct boss_shade_of_aran : public BossAI
}
}
private:
TaskScheduler drinkScheduler;
TaskScheduler _drinkScheduler;
bool _arcaneCooledDown;
bool _fireCooledDown;
bool _frostCooledDown;
bool _drinking;
uint32 _currentHealth;
};
struct npc_aran_elemental : public ScriptedAI
{
npc_aran_elemental(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastVictim(SPELL_WATERBOLT);
context.Repeat(2s);
});
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
void AddSC_boss_shade_of_aran()
{
RegisterKarazhanCreatureAI(boss_shade_of_aran);
RegisterKarazhanCreatureAI(npc_aran_elemental);
}

View File

@@ -52,7 +52,6 @@ enum Spells
enum Creatures
{
NPC_DEMONCHAINS = 17248,
NPC_FIENDISHIMP = 17267,
NPC_PORTAL = 17265
};
@@ -146,64 +145,6 @@ private:
ObjectGuid sacrificeGUID;
};
struct npc_fiendish_portal : public PassiveAI
{
npc_fiendish_portal(Creature* creature) : PassiveAI(creature), summons(me) {}
void Reset() override
{
DespawnAllImp();
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
DoZoneInCombat(summon);
}
void DespawnAllImp()
{
summons.DespawnAll();
}
private:
SummonList summons;
};
struct npc_fiendish_imp : public ScriptedAI
{
npc_fiendish_imp(Creature* creature) : ScriptedAI(creature) {}
void Reset() override
{
_scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastVictim(SPELL_FIREBOLT);
context.Repeat(2200ms);
});
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
};
struct boss_terestian_illhoof : public BossAI
{
boss_terestian_illhoof(Creature* creature) : BossAI(creature, DATA_TERESTIAN)
@@ -218,20 +159,6 @@ struct boss_terestian_illhoof : public BossAI
{
_Reset();
SummonKilrek();
portalsCount = 0;
berserk = false;
for (uint8 i = 0; i < 2; ++i)
{
if (portalGUID[i])
{
if (Creature* pPortal = ObjectAccessor::GetCreature(*me, portalGUID[i]))
{
pPortal->AI()->Reset();
pPortal->DespawnOrUnsummon();
}
portalGUID[i].Clear();
}
}
}
void SummonKilrek()
@@ -256,10 +183,13 @@ struct boss_terestian_illhoof : public BossAI
DoZoneInCombat();
scheduler.Schedule(30s, [this](TaskContext context)
{
if (Unit * target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, false))
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, false))
{
DoCast(target, SPELL_SACRIFICE, true);
target->CastSpell(target, SPELL_SUMMON_DEMONCHAINS, true);
target->m_Events.AddEventAtOffset([target] {
target->CastSpell(target, SPELL_SUMMON_DEMONCHAINS, true);
}, 1s);
Talk(SAY_SACRIFICE);
context.Repeat(30s);
}
@@ -267,31 +197,15 @@ struct boss_terestian_illhoof : public BossAI
{
DoCastVictim(SPELL_SHADOW_BOLT);
context.Repeat(10s);
}).Schedule(10s, [this](TaskContext context)
}).Schedule(10s, [this](TaskContext)
{
if (!portalGUID[0])
{
DoCastVictim(SPELL_FIENDISH_PORTAL);
}
if (!portalGUID[1])
{
DoCastVictim(SPELL_FIENDISH_PORTAL_1);
}
if (portalGUID[0] && portalGUID[1])
{
if (Creature* pPortal = ObjectAccessor::GetCreature(*me, portalGUID[urand(0, 1)]))
{
pPortal->CastSpell(me->GetVictim(), SPELL_SUMMON_FIENDISIMP);
}
context.Repeat(5s);
}
DoCastAOE(SPELL_FIENDISH_PORTAL);
}).Schedule(11s, [this](TaskContext)
{
DoCastAOE(SPELL_FIENDISH_PORTAL_1);
}).Schedule(10min, [this](TaskContext /*context*/)
{
if (!berserk)
{
DoCastSelf(SPELL_BERSERK);
berserk = true;
}
DoCastSelf(SPELL_BERSERK);
});
}
@@ -299,13 +213,14 @@ struct boss_terestian_illhoof : public BossAI
{
if (summoned->GetEntry() == NPC_PORTAL)
{
portalGUID[portalsCount] = summoned->GetGUID();
++portalsCount;
summoned->SetReactState(REACT_PASSIVE);
if (summoned->GetUInt32Value(UNIT_CREATED_BY_SPELL) == SPELL_FIENDISH_PORTAL_1)
{
Talk(SAY_SUMMON);
}
}
summons.Summon(summoned);
}
void KilledUnit(Unit* victim) override
@@ -318,44 +233,14 @@ struct boss_terestian_illhoof : public BossAI
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
for (uint8 i = 0; i < 2; ++i)
{
if (portalGUID[i])
{
if (Creature* pPortal = ObjectAccessor::GetCreature((*me), portalGUID[i]))
{
pPortal->AI()->Reset();
pPortal->DespawnOrUnsummon();
}
portalGUID[i].Clear();
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
private:
bool berserk;
ObjectGuid portalGUID[2];
uint8 portalsCount;
};
void AddSC_boss_terestian_illhoof()
{
RegisterKarazhanCreatureAI(boss_terestian_illhoof);
RegisterKarazhanCreatureAI(npc_fiendish_imp);
RegisterKarazhanCreatureAI(npc_fiendish_portal);
RegisterKarazhanCreatureAI(npc_kilrek);
RegisterKarazhanCreatureAI(npc_demon_chain);
}

View File

@@ -508,7 +508,7 @@ struct boss_strawman : public ScriptedAI
void SpellHit(Unit* /*caster*/, SpellInfo const* Spell) override
{
if ((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && (!(rand() % 10)))
if ((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && roll_chance_i(10))
{
/*
if (not direct damage(aoe, dot))

View File

@@ -44,6 +44,7 @@ ObjectData const creatureData[] =
{ NPC_ROMULO, DATA_ROMULO },
{ NPC_JULIANNE, DATA_JULIANNE },
{ NPC_NIGHTBANE, DATA_NIGHTBANE },
{ NPC_TERESTIAN_ILLHOOF, DATA_TERESTIAN },
{ 0, 0 }
};
@@ -122,6 +123,16 @@ public:
case NPC_ECHO_OF_MEDIVH:
_echoOfMedivhGUID = creature->GetGUID();
break;
case NPC_FIENDISH_IMP:
if (Creature* terestrian = GetCreature(DATA_TERESTIAN))
{
if (terestrian->AI())
{
terestrian->AI()->JustSummoned(creature);
creature->SetInCombatWithZone();
}
}
break;
default:
break;
}
@@ -252,7 +263,6 @@ public:
piece->NearTeleportTo(x, y, z, o);
piece->AI()->DoAction(ACTION_CHESS_PIECE_RESET_ORIENTATION);
piece->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
piece->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
piece->AI()->Reset();
}
}

View File

@@ -37,7 +37,7 @@ enum KZDataTypes
DATA_TERESTIAN = 7,
DATA_NETHERSPITE = 8,
DATA_CHESS_EVENT = 9,
DATA_MALCHEZZAR = 10,
DATA_MALCHEZAAR = 10,
DATA_NIGHTBANE = 11,
DATA_SERVANT_QUARTERS = 12,
DATA_OPERA_OZ_DEATHCOUNT = 13,
@@ -117,6 +117,7 @@ enum KZCreatures
NPC_ROAR = 17546,
NPC_STRAWMAN = 17543,
NPC_TINHEAD = 17547,
NPC_FIENDISH_IMP = 17267,
// Chess Event
NPC_ECHO_OF_MEDIVH = 16816,
@@ -132,7 +133,12 @@ enum KZCreatures
NPC_ROOK_A = 21160,
NPC_KING_H = 21752,
NPC_KING_A = 21684,
NPC_CHESS_EVENT_MEDIVH_CHEAT_FIRES = 22521
NPC_CHESS_EVENT_MEDIVH_CHEAT_FIRES = 22521,
// Malchezaar Helpers
NPC_INFERNAL_TARGET = 17644,
NPC_INFERNAL_RELAY = 17645
};
enum KZGameObjectIds

View File

@@ -16,9 +16,18 @@
*/
#include "InstanceScript.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "magisters_terrace.h"
ObjectData const creatureData[] =
{
{ NPC_KALECGOS, DATA_KALECGOS },
{ 0, 0 }
};
Position const KalecgosSpawnPos = { 164.3747f, -397.1197f, 2.151798f, 1.66219f };
class instance_magisters_terrace : public InstanceMapScript
{
public:
@@ -29,6 +38,7 @@ public:
instance_magisters_terrace_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
LoadObjectData(creatureData, nullptr);
}
uint32 Encounter[MAX_ENCOUNTER];
@@ -69,6 +79,24 @@ public:
return 0;
}
void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override
{
if (eventId == EVENT_SPAWN_KALECGOS)
{
if (!GetCreature(DATA_KALECGOS) && !scheduler.IsGroupScheduled(DATA_KALECGOS))
{
scheduler.Schedule(1min, 1min, DATA_KALECGOS,[this](TaskContext)
{
if (Creature* kalecgos = instance->SummonCreature(NPC_KALECGOS, KalecgosSpawnPos))
{
kalecgos->GetMotionMaster()->MovePath(PATH_KALECGOS_FLIGHT, false);
kalecgos->AI()->Talk(SAY_KALECGOS_SPAWN);
}
});
}
}
}
void SetData(uint32 identifier, uint32 data) override
{
switch (identifier)
@@ -116,6 +144,8 @@ public:
kael->AI()->JustSummoned(creature);
break;
}
InstanceScript::OnCreatureCreate(creature);
}
void OnGameObjectCreate(GameObject* go) override
@@ -184,7 +214,53 @@ public:
}
};
enum Spells
{
SPELL_KALECGOS_TRANSFORM = 44670,
SPELL_TRANSFORM_VISUAL = 24085,
SPELL_CAMERA_SHAKE = 44762,
SPELL_ORB_KILL_CREDIT = 46307
};
enum MovementPoints
{
POINT_ID_PREPARE_LANDING = 6
};
struct npc_kalecgos : public ScriptedAI
{
npc_kalecgos(Creature* creature) : ScriptedAI(creature) { }
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != WAYPOINT_MOTION_TYPE)
return;
if (pointId == POINT_ID_PREPARE_LANDING)
{
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
me->SetDisableGravity(false);
me->SetHover(false);
me->m_Events.AddEventAtOffset([this]()
{
DoCastAOE(SPELL_CAMERA_SHAKE);
me->SetObjectScale(0.6f);
me->m_Events.AddEventAtOffset([this]()
{
DoCastSelf(SPELL_ORB_KILL_CREDIT, true);
DoCastSelf(SPELL_TRANSFORM_VISUAL);
DoCastSelf(SPELL_KALECGOS_TRANSFORM);
me->UpdateEntry(NPC_HUMAN_KALECGOS);
}, 1s);
}, 2s);
}
}
};
void AddSC_instance_magisters_terrace()
{
new instance_magisters_terrace();
RegisterMagistersTerraceCreatureAI(npc_kalecgos);
}

View File

@@ -32,7 +32,9 @@ enum MTData
DATA_VEXALLUS_EVENT = 1,
DATA_DELRISSA_EVENT = 2,
DATA_KAELTHAS_EVENT = 3,
MAX_ENCOUNTER = 4
MAX_ENCOUNTER = 4,
DATA_KALECGOS = 5
};
enum MTCreatures
@@ -41,7 +43,9 @@ enum MTCreatures
NPC_FEL_CRYSTAL = 24722,
NPC_KAEL_THAS = 24664,
NPC_PHOENIX = 21362,
NPC_PHOENIX_EGG = 21364
NPC_PHOENIX_EGG = 21364,
NPC_KALECGOS = 24844,
NPC_HUMAN_KALECGOS = 24848
};
enum MTGameObjects
@@ -54,10 +58,27 @@ enum MTGameObjects
GO_ESCAPE_ORB = 188173
};
enum InstanceEventIds
{
EVENT_SPAWN_KALECGOS = 16547
};
enum InstanceText
{
SAY_KALECGOS_SPAWN = 0
};
enum MovementData
{
PATH_KALECGOS_FLIGHT = 248440
};
template <class AI, class T>
inline AI* GetMagistersTerraceAI(T* obj)
{
return GetInstanceAI<AI>(obj, MTScriptName);
}
#define RegisterMagistersTerraceCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetMagistersTerraceAI)
#endif

View File

@@ -695,106 +695,6 @@ class npc_fairbanks : public CreatureScript
public:
npc_fairbanks() : CreatureScript("npc_fairbanks") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
AddGossipItemFor(player, 0, "Curse? What's going on here, Fairbanks?", GOSSIP_SENDER_MAIN, 1);
SendGossipMenuFor(player, 100100, creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*Sender*/, uint32 uiAction) override
{
ClearGossipMenuFor(player);
switch (uiAction)
{
case 1:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "Mograine?", GOSSIP_SENDER_MAIN, 2);
SendGossipMenuFor(player, 100101, creature->GetGUID());
return true;
case 2:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "What do you mean?", GOSSIP_SENDER_MAIN, 3);
SendGossipMenuFor(player, 100102, creature->GetGUID());
return true;
case 3:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "I still do not fully understand.", GOSSIP_SENDER_MAIN, 4);
SendGossipMenuFor(player, 100103, creature->GetGUID());
return true;
case 4:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "Incredible story. So how did he die?", GOSSIP_SENDER_MAIN, 5);
SendGossipMenuFor(player, 100104, creature->GetGUID());
return true;
case 5:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "You mean...", GOSSIP_SENDER_MAIN, 6);
SendGossipMenuFor(player, 100105, creature->GetGUID());
return true;
case 6:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "How do you know all of this?", GOSSIP_SENDER_MAIN, 7);
SendGossipMenuFor(player, 100106, creature->GetGUID());
return true;
case 7:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "A thousand? For one man?", GOSSIP_SENDER_MAIN, 8);
SendGossipMenuFor(player, 100107, creature->GetGUID());
return true;
case 8:
creature->HandleEmoteCommand(5);
AddGossipItemFor(player, 0, "Yet? Yet what?", GOSSIP_SENDER_MAIN, 9);
SendGossipMenuFor(player, 100108, creature->GetGUID());
return true;
case 9:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "And did he?", GOSSIP_SENDER_MAIN, 10);
SendGossipMenuFor(player, 100109, creature->GetGUID());
return true;
case 10:
creature->HandleEmoteCommand(274);
AddGossipItemFor(player, 0, "Continue please, Fairbanks.", GOSSIP_SENDER_MAIN, 11);
SendGossipMenuFor(player, 100110, creature->GetGUID());
return true;
case 11:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "You mean...", GOSSIP_SENDER_MAIN, 12);
SendGossipMenuFor(player, 100111, creature->GetGUID());
return true;
case 12:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "You were right, Fairbanks. That is tragic.", GOSSIP_SENDER_MAIN, 13);
SendGossipMenuFor(player, 100112, creature->GetGUID());
return true;
case 13:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "And you did...", GOSSIP_SENDER_MAIN, 14);
SendGossipMenuFor(player, 100113, creature->GetGUID());
return true;
case 14:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "You tell an incredible tale, Fairbanks. What of the blade? Is it beyond redemption?", GOSSIP_SENDER_MAIN, 15);
SendGossipMenuFor(player, 100114, creature->GetGUID());
return true;
case 15:
creature->HandleEmoteCommand(1);
AddGossipItemFor(player, 0, "But his son is dead.", GOSSIP_SENDER_MAIN, 16);
SendGossipMenuFor(player, 100115, creature->GetGUID());
return true;
case 16:
SendGossipMenuFor(player, 100116, creature->GetGUID());
/// @todo: we need to play these 3 emote in sequence, we play only the last one right now.
creature->HandleEmoteCommand(274);
creature->HandleEmoteCommand(1);
creature->HandleEmoteCommand(397);
return true;
}
return true;
}
struct npc_fairbanksAI : public SmartAI
{
npc_fairbanksAI(Creature* creature) : SmartAI(creature) { }
@@ -812,7 +712,6 @@ public:
{
me->SetFaction(FACTION_FRIENDLY);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetSheath(SHEATH_STATE_UNARMED);
me->CastSpell(me, 57767, true);
me->SetDisplayId(16179);
me->SetFacingToObject(player);

View File

@@ -154,8 +154,8 @@ public:
switch (type)
{
case DATA_RAJAXX_WAVE_ENGAGED:
_scheduler.CancelGroup(GROUP_RAJAXX_WAVE_TIMER);
_scheduler.Schedule(2min, [this](TaskContext context)
scheduler.CancelGroup(GROUP_RAJAXX_WAVE_TIMER);
scheduler.Schedule(2min, [this](TaskContext context)
{
CallNextRajaxxLeader();
context.SetGroup(GROUP_RAJAXX_WAVE_TIMER);
@@ -195,8 +195,8 @@ public:
case NPC_YEGGETH:
case NPC_PAKKON:
case NPC_ZERRAN:
_scheduler.CancelAll();
_scheduler.Schedule(1s, [this, formation](TaskContext /*context*/)
scheduler.CancelAll();
scheduler.Schedule(1s, [this, formation](TaskContext /*context*/)
{
if (!formation->IsAnyMemberAlive())
{
@@ -212,11 +212,6 @@ public:
}
}
void Update(uint32 diff) override
{
_scheduler.Update(diff);
}
void SetGuidData(uint32 type, ObjectGuid data) override
{
if (type == DATA_PARALYZED)
@@ -285,7 +280,7 @@ public:
void ResetRajaxxWaves()
{
_rajaxWaveCounter = 0;
_scheduler.CancelAll();
scheduler.CancelAll();
for (auto const& data : RajaxxWavesData)
{
if (Creature* creature = GetCreature(data.at(0)))
@@ -308,7 +303,6 @@ public:
ObjectGuid _andorovGUID;
uint32 _rajaxWaveCounter;
uint8 _buruPhase;
TaskScheduler _scheduler;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override

View File

@@ -210,15 +210,9 @@ public:
return true;
}
void Update(uint32 diff) override
{
scheduler.Update(diff);
}
private:
GuidVector CThunGraspGUIDs;
uint32 BugTrioDeathCount;
TaskScheduler scheduler;
};
};

View File

@@ -1,7 +1,18 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
* 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/>.
*/
/* ScriptData

View File

@@ -175,6 +175,7 @@ enum Kerlonian
SPELL_SLEEP_VISUAL = 25148,
SPELL_AWAKEN = 17536,
SPELL_BEAR_FORM = 18309,
QUEST_SLEEPER_AWAKENED = 5321,
NPC_LILADRIS = 11219 //attackers entries unknown
};
@@ -194,6 +195,8 @@ public:
void Reset() override
{
FallAsleepTimer = urand(10000, 45000);
DoCastSelf(SPELL_BEAR_FORM);
}
void MoveInLineOfSight(Unit* who) override

View File

@@ -69,219 +69,185 @@ enum Misc
{
GROUP_ABILITIES = 1,
NPC_PURE_SPAWN_OF_HYDROSS = 22035,
EVENT_SPELL_MARK_OF_CORRUPTION1 = 1,
EVENT_SPELL_MARK_OF_CORRUPTION2 = 2,
EVENT_SPELL_MARK_OF_CORRUPTION3 = 3,
EVENT_SPELL_MARK_OF_CORRUPTION4 = 4,
EVENT_SPELL_MARK_OF_CORRUPTION5 = 5,
EVENT_SPELL_MARK_OF_CORRUPTION6 = 6,
EVENT_SPELL_MARK_OF_HYDROSS1 = 7,
EVENT_SPELL_MARK_OF_HYDROSS2 = 8,
EVENT_SPELL_MARK_OF_HYDROSS3 = 9,
EVENT_SPELL_MARK_OF_HYDROSS4 = 10,
EVENT_SPELL_MARK_OF_HYDROSS5 = 11,
EVENT_SPELL_MARK_OF_HYDROSS6 = 12,
EVENT_SPELL_WATER_TOMB = 13,
EVENT_SPELL_VILE_SLUDGE = 14,
EVENT_SPELL_ENRAGE = 15,
EVENT_CHECK_AURA = 16,
EVENT_KILL_TALK = 17
};
class boss_hydross_the_unstable : public CreatureScript
struct boss_hydross_the_unstable : public BossAI
{
public:
boss_hydross_the_unstable() : CreatureScript("boss_hydross_the_unstable") { }
CreatureAI* GetAI(Creature* creature) const override
boss_hydross_the_unstable(Creature* creature) : BossAI(creature, DATA_HYDROSS_THE_UNSTABLE)
{
return GetSerpentShrineAI<boss_hydross_the_unstableAI>(creature);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_hydross_the_unstableAI : public BossAI
void Reset() override
{
boss_hydross_the_unstableAI(Creature* creature) : BossAI(creature, DATA_HYDROSS_THE_UNSTABLE)
BossAI::Reset();
_recentlySpoken = false;
}
void JustReachedHome() override
{
BossAI::JustReachedHome();
if (!me->HasAura(SPELL_BLUE_BEAM))
{
me->RemoveAurasDueToSpell(SPELL_CLEANSING_FIELD_AURA);
}
}
void SetForm(bool corrupt, bool initial)
{
scheduler.CancelGroup(GROUP_ABILITIES);
DoResetThreatList();
if (corrupt)
{
me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
DoCastSelf(SPELL_CORRUPTION, true);
scheduler.Schedule(0s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_CORRUPTION1);
}).Schedule(15s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_CORRUPTION2);
}).Schedule(30s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_CORRUPTION3);
}).Schedule(45s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_CORRUPTION4);
}).Schedule(60s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_CORRUPTION5);
}).Schedule(75s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_CORRUPTION6);
}).Schedule(12150ms, GROUP_ABILITIES, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_VILE_SLUDGE, true);
context.Repeat(9700ms, 32800ms);
});
}
else
{
me->SetMeleeDamageSchool(SPELL_SCHOOL_FROST);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false);
me->RemoveAurasDueToSpell(SPELL_CORRUPTION);
scheduler.Schedule(0s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_HYDROSS1);
}).Schedule(15s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_HYDROSS2);
}).Schedule(30s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_HYDROSS3);
}).Schedule(45s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_HYDROSS4);
}).Schedule(60s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_HYDROSS5);
}).Schedule(75s, GROUP_ABILITIES, [this](TaskContext)
{
DoCastSelf(SPELL_MARK_OF_HYDROSS6);
}).Schedule(12150ms, GROUP_ABILITIES, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_WATER_TOMB, true);
context.Repeat(9700ms, 32800ms);
});
}
void Reset() override
if (initial)
{
BossAI::Reset();
return;
}
void JustReachedHome() override
if (corrupt)
{
BossAI::JustReachedHome();
if (!me->HasAura(SPELL_BLUE_BEAM))
me->RemoveAurasDueToSpell(SPELL_CLEANSING_FIELD_AURA);
}
void SetForm(bool corrupt, bool initial)
{
events.CancelEventGroup(GROUP_ABILITIES);
DoResetThreatList();
if (corrupt)
Talk(SAY_SWITCH_TO_CORRUPT);
for (uint32 spellId = SPELL_SUMMON_CORRUPTED1; spellId <= SPELL_SUMMON_CORRUPTED4; ++spellId)
{
me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
me->CastSpell(me, SPELL_CORRUPTION, true);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION1, 0, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION2, 15000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION3, 30000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION4, 45000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION5, 60000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION6, 75000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_VILE_SLUDGE, 7000, GROUP_ABILITIES);
}
else
{
me->SetMeleeDamageSchool(SPELL_SCHOOL_FROST);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false);
me->RemoveAurasDueToSpell(SPELL_CORRUPTION);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS1, 0, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS2, 15000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS3, 30000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS4, 45000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS5, 60000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS6, 75000, GROUP_ABILITIES);
events.ScheduleEvent(EVENT_SPELL_WATER_TOMB, 7000, GROUP_ABILITIES);
}
if (initial)
return;
if (corrupt)
{
Talk(SAY_SWITCH_TO_CORRUPT);
for (uint32 i = SPELL_SUMMON_CORRUPTED1; i <= SPELL_SUMMON_CORRUPTED4; ++i)
me->CastSpell(me, i, true);
}
else
{
Talk(SAY_SWITCH_TO_CLEAN);
for (uint32 i = SPELL_SUMMON_PURIFIED1; i <= SPELL_SUMMON_PURIFIED4; ++i)
me->CastSpell(me, i, true);
DoCastSelf(spellId, true);
}
}
void JustEngagedWith(Unit* who) override
else
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 600000);
events.ScheduleEvent(EVENT_CHECK_AURA, 1000);
SetForm(false, true);
}
void KilledUnit(Unit* /*victim*/) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
Talk(SAY_SWITCH_TO_CLEAN);
for (uint32 spellId = SPELL_SUMMON_PURIFIED1; spellId <= SPELL_SUMMON_PURIFIED4; ++spellId)
{
Talk(me->HasAura(SPELL_CORRUPTION) ? SAY_CORRUPT_SLAY : SAY_CLEAN_SLAY);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
DoCastSelf(spellId, true);
}
}
}
void JustSummoned(Creature* summon) override
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
SetForm(false, true);
scheduler.Schedule(1s, [this](TaskContext context)
{
summons.Summon(summon);
summon->CastSpell(summon, SPELL_ELEMENTAL_SPAWNIN, true);
summon->SetInCombatWithZone();
if (summon->GetEntry() == NPC_PURE_SPAWN_OF_HYDROSS)
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
else
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
}
void SummonedCreatureDespawn(Creature* summon) override
{
summons.Despawn(summon);
}
void JustDied(Unit* killer) override
{
Talk(me->HasAura(SPELL_CORRUPTION) ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH);
BossAI::JustDied(killer);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
if (me->HasAura(SPELL_BLUE_BEAM) == me->HasAura(SPELL_CORRUPTION))
{
case EVENT_CHECK_AURA:
if (me->HasAura(SPELL_BLUE_BEAM) == me->HasAura(SPELL_CORRUPTION))
SetForm(!me->HasAura(SPELL_BLUE_BEAM), false);
events.ScheduleEvent(EVENT_CHECK_AURA, 1000);
break;
case EVENT_SPELL_ENRAGE:
me->CastSpell(me, SPELL_ENRAGE, true);
break;
case EVENT_SPELL_MARK_OF_HYDROSS1:
me->CastSpell(me, SPELL_MARK_OF_HYDROSS1, false);
break;
case EVENT_SPELL_MARK_OF_HYDROSS2:
me->CastSpell(me, SPELL_MARK_OF_HYDROSS2, false);
break;
case EVENT_SPELL_MARK_OF_HYDROSS3:
me->CastSpell(me, SPELL_MARK_OF_HYDROSS3, false);
break;
case EVENT_SPELL_MARK_OF_HYDROSS4:
me->CastSpell(me, SPELL_MARK_OF_HYDROSS4, false);
break;
case EVENT_SPELL_MARK_OF_HYDROSS5:
me->CastSpell(me, SPELL_MARK_OF_HYDROSS5, false);
break;
case EVENT_SPELL_MARK_OF_HYDROSS6:
me->CastSpell(me, SPELL_MARK_OF_HYDROSS6, false);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS6, 15000, GROUP_ABILITIES);
break;
case EVENT_SPELL_MARK_OF_CORRUPTION1:
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION1, false);
break;
case EVENT_SPELL_MARK_OF_CORRUPTION2:
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION2, false);
break;
case EVENT_SPELL_MARK_OF_CORRUPTION3:
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION3, false);
break;
case EVENT_SPELL_MARK_OF_CORRUPTION4:
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION4, false);
break;
case EVENT_SPELL_MARK_OF_CORRUPTION5:
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION5, false);
break;
case EVENT_SPELL_MARK_OF_CORRUPTION6:
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION6, false);
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION6, 15000, GROUP_ABILITIES);
break;
case EVENT_SPELL_WATER_TOMB:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
me->CastSpell(target, SPELL_WATER_TOMB, false);
events.ScheduleEvent(EVENT_SPELL_WATER_TOMB, 7000, GROUP_ABILITIES);
break;
case EVENT_SPELL_VILE_SLUDGE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
me->CastSpell(target, SPELL_VILE_SLUDGE, false);
events.ScheduleEvent(EVENT_SPELL_VILE_SLUDGE, 15000, GROUP_ABILITIES);
break;
SetForm(!me->HasAura(SPELL_BLUE_BEAM), false);
}
context.Repeat(1s);
}).Schedule(10min, [this](TaskContext)
{
DoCastSelf(SPELL_ENRAGE, true);
});
}
DoMeleeAttackIfReady();
void KilledUnit(Unit* /*victim*/) override
{
if (!_recentlySpoken)
{
Talk(me->HasAura(SPELL_CORRUPTION) ? SAY_CORRUPT_SLAY : SAY_CLEAN_SLAY);
_recentlySpoken = true;
}
};
scheduler.Schedule(6s, [this](TaskContext)
{
_recentlySpoken = false;
});
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->CastSpell(summon, SPELL_ELEMENTAL_SPAWNIN, true);
summon->SetInCombatWithZone();
if (summon->GetEntry() == NPC_PURE_SPAWN_OF_HYDROSS)
{
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
}
else
{
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
}
}
void SummonedCreatureDespawn(Creature* summon) override
{
summons.Despawn(summon);
}
void JustDied(Unit* killer) override
{
Talk(me->HasAura(SPELL_CORRUPTION) ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH);
BossAI::JustDied(killer);
}
private:
bool _recentlySpoken;
};
class spell_hydross_cleansing_field_aura : public SpellScriptLoader
@@ -377,7 +343,7 @@ public:
void AddSC_boss_hydross_the_unstable()
{
new boss_hydross_the_unstable();
RegisterSerpentShrineAI(boss_hydross_the_unstable);
new spell_hydross_cleansing_field_aura();
new spell_hydross_cleansing_field_command();
new spell_hydross_mark_of_hydross();

View File

@@ -1,14 +1,14 @@
/*
* Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
* 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 General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* 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 General Public License for
* 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

View File

@@ -55,8 +55,10 @@ enum Spells
SPELL_QUAKE_KNOCKBACK = 30571,
SPELL_COLLAPSE_DAMAGE = 36449,
SPELL_CAMERA_SHAKE = 36455,
SPELL_DEBRIS_TARGET = 30629,
SPELL_DEBRIS_SPAWN = 30630,
SPELL_DEBRIS_DAMAGE = 30631,
SPELL_DEBRIS_VISUAL = 30632,
SPELL_DEBRIS_DAMAGE = 30631
};
enum Groups
@@ -70,26 +72,9 @@ enum Actions
ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT = 1
};
class DealDebrisDamage : public BasicEvent
{
public:
DealDebrisDamage(Creature& creature, ObjectGuid targetGUID) : _owner(creature), _targetGUID(targetGUID) { }
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
{
if (Unit* target = ObjectAccessor::GetUnit(_owner, _targetGUID))
target->CastSpell(target, SPELL_DEBRIS_DAMAGE, true, nullptr, nullptr, _owner.GetGUID());
return true;
}
private:
Creature& _owner;
ObjectGuid _targetGUID;
};
struct boss_magtheridon : public BossAI
{
boss_magtheridon(Creature* creature) : BossAI(creature, TYPE_MAGTHERIDON)
boss_magtheridon(Creature* creature) : BossAI(creature, DATA_MAGTHERIDON)
{
scheduler.SetValidator([this]
{
@@ -137,11 +122,7 @@ struct boss_magtheridon : public BossAI
_currentPhase = 0;
scheduler.Schedule(20s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
{
target->CastSpell(target, SPELL_DEBRIS_VISUAL, true, nullptr, nullptr, me->GetGUID());
me->m_Events.AddEvent(new DealDebrisDamage(*me, target->GetGUID()), me->m_Events.CalculateTime(5000));
}
DoCastAOE(SPELL_DEBRIS_TARGET);
context.Repeat(20s);
});
});
@@ -170,7 +151,7 @@ struct boss_magtheridon : public BossAI
void ScheduleCombatEvents()
{
me->GetThreatMgr().ClearAllThreat();
DoResetThreatList();
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(false);
me->SetReactState(REACT_AGGRESSIVE);
@@ -248,7 +229,7 @@ struct boss_magtheridon : public BossAI
BossAI::JustEngagedWith(who);
Talk(SAY_EMOTE_BEGIN);
instance->DoForAllMinions(TYPE_MAGTHERIDON, [&](Creature* creature) {
instance->DoForAllMinions(DATA_MAGTHERIDON, [&](Creature* creature) {
creature->SetInCombatWithZone();
});
@@ -289,6 +270,37 @@ private:
TaskScheduler _interruptScheduler;
};
struct npc_target_trigger : public ScriptedAI
{
npc_target_trigger(Creature* creature) : ScriptedAI(creature), _cast(false)
{
me->SetReactState(REACT_PASSIVE);
}
void Reset() override
{
if (!_cast)
{
DoCastSelf(SPELL_DEBRIS_VISUAL);
_cast = true;
_scheduler.Schedule(5s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_DEBRIS_DAMAGE);
me->DespawnOrUnsummon(6000);
});
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
protected:
TaskScheduler _scheduler;
bool _cast;
};
class spell_magtheridon_blaze : public SpellScript
{
PrepareSpellScript(spell_magtheridon_blaze);
@@ -348,6 +360,33 @@ class spell_magtheridon_quake : public SpellScript
}
};
class spell_magtheridon_debris_target_selector : public SpellScript
{
PrepareSpellScript(spell_magtheridon_debris_target_selector);
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if([&](WorldObject* target) -> bool
{
return target->GetEntry() != NPC_TARGET_TRIGGER;
});
Acore::Containers::RandomResize(targets, 1);
}
void HandleHit()
{
if (Unit* target = GetHitUnit())
target->CastSpell(target, SPELL_DEBRIS_SPAWN);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_magtheridon_debris_target_selector::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
OnHit += SpellHitFn(spell_magtheridon_debris_target_selector::HandleHit);
}
};
class go_manticron_cube : public GameObjectScript
{
public:
@@ -369,8 +408,10 @@ public:
void AddSC_boss_magtheridon()
{
RegisterMagtheridonsLairCreatureAI(boss_magtheridon);
RegisterMagtheridonsLairCreatureAI(npc_target_trigger);
RegisterSpellScript(spell_magtheridon_blaze);
RegisterSpellScript(spell_magtheridon_shadow_grasp);
RegisterSpellScript(spell_magtheridon_quake);
RegisterSpellScript(spell_magtheridon_debris_target_selector);
new go_manticron_cube();
}

View File

@@ -21,18 +21,18 @@
BossBoundaryData const boundaries =
{
{ TYPE_MAGTHERIDON, new CircleBoundary(Position(-18.70f, 2.24f), 52.30) }
{ DATA_MAGTHERIDON, new CircleBoundary(Position(-18.70f, 2.24f), 52.30) }
};
DoorData const doorData[] =
{
{ GO_MAGTHERIDON_DOORS, TYPE_MAGTHERIDON, DOOR_TYPE_ROOM },
{ GO_MAGTHERIDON_DOORS, DATA_MAGTHERIDON, DOOR_TYPE_ROOM },
{ 0, 0, DOOR_TYPE_ROOM } // END
};
MinionData const minionData[] =
{
{ NPC_HELLFIRE_CHANNELER, TYPE_MAGTHERIDON }
{ NPC_HELLFIRE_CHANNELER, DATA_MAGTHERIDON }
};
class instance_magtheridons_lair : public InstanceMapScript
@@ -133,7 +133,7 @@ public:
if (!InstanceScript::SetBossState(id, state))
return false;
if (id == TYPE_MAGTHERIDON)
if (id == DATA_MAGTHERIDON)
{
if (state == IN_PROGRESS)
{
@@ -163,7 +163,7 @@ public:
switch (type)
{
case DATA_CHANNELER_COMBAT:
if (GetBossState(TYPE_MAGTHERIDON) != IN_PROGRESS)
if (GetBossState(DATA_MAGTHERIDON) != IN_PROGRESS)
if (Creature* magtheridon = instance->GetCreature(_magtheridonGUID))
magtheridon->SetInCombatWithZone();
break;

View File

@@ -27,7 +27,7 @@
enum DataTypes
{
TYPE_MAGTHERIDON = 0,
DATA_MAGTHERIDON = 0,
MAX_ENCOUNTER = 1,
DATA_CHANNELER_COMBAT = 10,
@@ -41,6 +41,7 @@ enum NpcIds
NPC_HELLFIRE_CHANNELER = 17256,
NPC_HELLFIRE_WARDER = 18829,
NPC_HELLFIRE_RAID_TRIGGER = 17376,
NPC_TARGET_TRIGGER = 17474
};
enum GoIds

View File

@@ -29,107 +29,94 @@ enum voidReaver
SPELL_POUNDING = 34162,
SPELL_ARCANE_ORB = 34172,
SPELL_KNOCK_AWAY = 25778,
SPELL_BERSERK = 26662,
EVENT_SPELL_POUNDING = 1,
EVENT_SPELL_ARCANEORB = 2,
EVENT_SPELL_KNOCK_AWAY = 3,
EVENT_SPELL_BERSERK = 4
SPELL_BERSERK = 26662
};
class boss_void_reaver : public CreatureScript
enum Groups
{
public:
boss_void_reaver() : CreatureScript("boss_void_reaver") { }
GROUP_ARCANE_ORB = 1
};
struct boss_void_reaverAI : public BossAI
struct boss_void_reaver : public BossAI
{
boss_void_reaver(Creature* creature) : BossAI(creature, DATA_REAVER)
{
boss_void_reaverAI(Creature* creature) : BossAI(creature, DATA_REAVER)
scheduler.SetValidator([this]
{
me->ApplySpellImmune(0, IMMUNITY_DISPEL, DISPEL_POISON, true);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEALTH_LEECH, true);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_DRAIN, true);
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_LEECH, true);
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_MANA_LEECH, true);
}
return !me->HasUnitState(UNIT_STATE_CASTING);
});
void Reset() override
{
BossAI::Reset();
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER && roll_chance_i(50))
Talk(SAY_SLAY);
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SPELL_POUNDING, 15000);
events.ScheduleEvent(EVENT_SPELL_ARCANEORB, 3000);
events.ScheduleEvent(EVENT_SPELL_KNOCK_AWAY, 30000);
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000);
me->CallForHelp(105.0f);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_BERSERK:
me->CastSpell(me, SPELL_BERSERK, true);
break;
case EVENT_SPELL_POUNDING:
Talk(SAY_POUNDING);
me->CastSpell(me, SPELL_POUNDING, false);
events.ScheduleEvent(EVENT_SPELL_POUNDING, 15000);
break;
case EVENT_SPELL_ARCANEORB:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, -18.0f, true))
me->CastSpell(target, SPELL_ARCANE_ORB, false);
else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 20.0f, true))
me->CastSpell(target, SPELL_ARCANE_ORB, false);
events.ScheduleEvent(EVENT_SPELL_ARCANEORB, 4000);
break;
case EVENT_SPELL_KNOCK_AWAY:
me->CastSpell(me->GetVictim(), SPELL_KNOCK_AWAY, false);
events.ScheduleEvent(EVENT_SPELL_POUNDING, 25000);
break;
}
DoMeleeAttackIfReady();
}
bool CheckEvadeIfOutOfCombatArea() const override
{
return me->GetDistance2d(432.59f, 371.93f) > 105.0f;
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetTheEyeAI<boss_void_reaverAI>(creature);
me->ApplySpellImmune(0, IMMUNITY_DISPEL, DISPEL_POISON, true);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEALTH_LEECH, true);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_DRAIN, true);
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_LEECH, true);
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_MANA_LEECH, true);
}
void Reset() override
{
BossAI::Reset();
_recentlySpoken = false;
}
void KilledUnit(Unit* /*victim*/) override
{
if (!_recentlySpoken)
{
Talk(SAY_SLAY);
_recentlySpoken = true;
scheduler.Schedule(5s, [this](TaskContext)
{
_recentlySpoken = false;
});
}
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
me->CallForHelp(105.0f);
scheduler.Schedule(10min, [this](TaskContext)
{
DoCastSelf(SPELL_BERSERK);
}).Schedule(15s, [this](TaskContext context)
{
Talk(SAY_POUNDING);
DoCastSelf(SPELL_POUNDING);
scheduler.DelayGroup(GROUP_ARCANE_ORB, 3s);
context.Repeat(15s);
}).Schedule(3s, GROUP_ARCANE_ORB, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, -18.0f, true))
me->CastSpell(target, SPELL_ARCANE_ORB, false);
else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 20.0f, true))
me->CastSpell(target, SPELL_ARCANE_ORB, false);
context.Repeat(3s);
}).Schedule(30s, [this](TaskContext context)
{
DoCastVictim(SPELL_KNOCK_AWAY);
context.Repeat(25s);
});
}
bool CheckEvadeIfOutOfCombatArea() const override
{
return me->GetDistance2d(432.59f, 371.93f) > 105.0f;
}
private:
bool _recentlySpoken;
};
void AddSC_boss_void_reaver()
{
new boss_void_reaver();
RegisterTheEyeAI(boss_void_reaver);
}

View File

@@ -65,4 +65,6 @@ inline AI* GetTheEyeAI(T* obj)
return GetInstanceAI<AI>(obj, TheEyeScriptName);
}
#define RegisterTheEyeAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetTheEyeAI)
#endif

View File

@@ -22,6 +22,8 @@
#include "ScriptedEscortAI.h"
#include "ScriptedGossip.h"
#include "SpellInfo.h"
#include "SpellAuras.h"
#include "SpellScript.h"
// Ours
enum saeed
@@ -697,9 +699,6 @@ public:
{
Drained = true;
int32 uHpPct = int32(me->GetHealthPct());
me->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY);
me->SetHealth(me->CountPctFromMaxHealth(uHpPct));
me->LowerPlayerDamageReq(me->GetMaxHealth() - me->GetHealth());
me->SetInCombatWith(player);
@@ -911,6 +910,45 @@ public:
}
};
class spell_q10190_battery_recharging_blaster : public SpellScript
{
PrepareSpellScript(spell_q10190_battery_recharging_blaster);
SpellCastResult CheckCast()
{
if (Unit* target = GetExplTargetUnit())
if (target->GetHealthPct() <= 25.0f)
return SPELL_CAST_OK;
return SPELL_FAILED_BAD_TARGETS;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_q10190_battery_recharging_blaster::CheckCast);
}
};
class spell_q10190_battery_recharging_blaster_aura : public AuraScript
{
PrepareAuraScript(spell_q10190_battery_recharging_blaster_aura);
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
return;
if (Creature* phasehunter = GetTarget()->ToCreature())
if (phasehunter->GetEntry() == NPC_PHASE_HUNTER_ENTRY)
phasehunter->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY);
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_q10190_battery_recharging_blaster_aura::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_netherstorm()
{
// Ours
@@ -922,5 +960,5 @@ void AddSC_netherstorm()
new npc_phase_hunter();
new npc_bessy();
new npc_maxx_a_million_escort();
RegisterSpellAndAuraScriptPair(spell_q10190_battery_recharging_blaster, spell_q10190_battery_recharging_blaster_aura);
}

View File

@@ -146,6 +146,18 @@ class spell_dk_raise_ally : public SpellScript
{
PrepareSpellScript(spell_dk_raise_ally);
SpellCastResult CheckCast()
{
Player* unitTarget = GetHitPlayer();
if (!unitTarget)
return SPELL_FAILED_BAD_TARGETS;
if (unitTarget->IsAlive()) // not discovered attributeEx5?
return SPELL_FAILED_TARGET_NOT_DEAD;
return SPELL_CAST_OK;
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
if (Player* unitTarget = GetHitPlayer())
@@ -237,6 +249,7 @@ class spell_dk_raise_ally : public SpellScript
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_dk_raise_ally::CheckCast);
OnEffectHitTarget += SpellEffectFn(spell_dk_raise_ally::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};

View File

@@ -302,7 +302,8 @@ private:
enum Spell
{
PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235
PAL_SPELL_ARDENT_DEFENDER_DEBUFF = 66233,
PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235
};
bool Validate(SpellInfo const* /*spellInfo*/) override
@@ -329,7 +330,7 @@ private:
int32 remainingHealth = victim->GetHealth() - dmgInfo.GetDamage();
uint32 allowedHealth = victim->CountPctFromMaxHealth(35);
// If damage kills us
if (remainingHealth <= 0 && !victim->ToPlayer()->HasSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL))
if (remainingHealth <= 0 && !victim->ToPlayer()->HasAura(PAL_SPELL_ARDENT_DEFENDER_DEBUFF))
{
// Cast healing spell, completely avoid damage
absorbAmount = dmgInfo.GetDamage();
@@ -344,7 +345,6 @@ private:
int32 healAmount = int32(victim->CountPctFromMaxHealth(uint32(healPct * pctFromDefense)));
victim->CastCustomSpell(PAL_SPELL_ARDENT_DEFENDER_HEAL, SPELLVALUE_BASE_POINT0, healAmount, victim, true, nullptr, aurEff);
victim->ToPlayer()->AddSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, 120000);
}
else if (remainingHealth < int32(allowedHealth))
{

View File

@@ -19,12 +19,7 @@
#include "Group.h"
#include "Guild.h"
#include "ScriptMgr.h"
#define LOG_CHAT(TYPE, ...) \
if (lang != LANG_ADDON) \
LOG_DEBUG("chat.log." TYPE, __VA_ARGS__); \
else \
LOG_DEBUG("chat.log.addon." TYPE, __VA_ARGS__);
#include "Log.h"
class ChatLogScript : public PlayerScript
{
@@ -36,66 +31,67 @@ public:
switch (type)
{
case CHAT_MSG_SAY:
LOG_CHAT("say", "Player {} says (language {}): {}",
LOG_INFO("chat.say", "Player {} says (language {}): {}",
player->GetName(), lang, msg);
break;
case CHAT_MSG_EMOTE:
LOG_CHAT("emote", "Player {} emotes: {}",
LOG_INFO("chat.emote", "Player {} emotes: {}",
player->GetName(), msg);
break;
case CHAT_MSG_YELL:
LOG_CHAT("yell", "Player {} yells (language {}): {}",
LOG_INFO("chat.yell", "Player {} yells (language {}): {}",
player->GetName(), lang, msg);
break;
}
}
void OnChat(Player* player, uint32 /*type*/, uint32 lang, std::string& msg, Player* receiver) override
void OnChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Player* receiver) override
{
LOG_CHAT("whisper", "Player {} tells {}: {}",
LOG_INFO("chat.whisper", "Player {} tells {}: {}",
player->GetName(), receiver ? receiver->GetName() : "<unknown>", msg);
}
void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) override
{
std::string str = lang != LANG_ADDON ? "chat." : "chat.addon.";
//! NOTE:
//! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER"
switch (type)
{
case CHAT_MSG_PARTY:
LOG_CHAT("party", "Player {} tells group with leader {}: {}",
LOG_INFO(str + "party", "Player {} tells group with leader {}: {}",
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
break;
case CHAT_MSG_PARTY_LEADER:
LOG_CHAT("party", "Leader {} tells group: {}",
LOG_INFO(str + "party", "Leader {} tells group: {}",
player->GetName(), msg);
break;
case CHAT_MSG_RAID:
LOG_CHAT("raid", "Player {} tells raid with leader {}: {}",
LOG_INFO(str + "raid", "Player {} tells raid with leader {}: {}",
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
break;
case CHAT_MSG_RAID_LEADER:
LOG_CHAT("raid", "Leader player {} tells raid: {}",
LOG_INFO(str + "raid", "Leader player {} tells raid: {}",
player->GetName(), msg);
break;
case CHAT_MSG_RAID_WARNING:
LOG_CHAT("raid", "Leader player {} warns raid with: {}",
LOG_INFO(str + "raid", "Leader player {} sends raid warning: {}",
player->GetName(), msg);
break;
case CHAT_MSG_BATTLEGROUND:
LOG_CHAT("bg", "Player {} tells battleground with leader {}: {}",
LOG_INFO(str + "bg", "Player {} tells battleground with leader {}: {}",
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
break;
case CHAT_MSG_BATTLEGROUND_LEADER:
LOG_CHAT("bg", "Leader player {} tells battleground: {}",
LOG_INFO(str + "bg", "Leader player {} tells battleground: {}",
player->GetName(), msg);
break;
}
@@ -103,21 +99,22 @@ public:
void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) override
{
std::string str = lang != LANG_ADDON ? "chat." : "chat.addon.";
switch (type)
{
case CHAT_MSG_GUILD:
LOG_CHAT("guild", "Player {} tells guild {}: {}",
LOG_INFO(str + "guild", "Player {} tells guild {}: {}",
player->GetName(), guild ? guild->GetName() : "<unknown>", msg);
break;
case CHAT_MSG_OFFICER:
LOG_CHAT("guild.officer", "Player {} tells guild {} officers: {}",
LOG_INFO(str + "guild.officer", "Player {} tells guild {} officers: {}",
player->GetName(), guild ? guild->GetName() : "<unknown>", msg);
break;
}
}
void OnChat(Player* player, uint32 /*type*/, uint32 lang, std::string& msg, Channel* channel) override
void OnChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Channel* channel) override
{
bool isSystem = channel &&
(channel->HasFlag(CHANNEL_FLAG_TRADE) ||
@@ -127,13 +124,15 @@ public:
if (isSystem)
{
LOG_CHAT("system", "Player {} tells channel {}: {}",
LOG_INFO("chat.channel", "Player {} tells channel {}: {}",
player->GetName(), channel->GetName(), msg);
}
else
{
// Allow to log custom channels. i.e. world channel
// in that case set config: Logger.channel.world=6,Chat
std::string channelName = channel ? channel->GetName() : "<unknown>";
LOG_CHAT("channel." + channelName, "Player {} tells channel {}: {}",
LOG_INFO("chat.channel." + channelName, "Player {} tells channel {}: {}",
player->GetName(), channelName, msg);
}
}