Scripts/Serpentshrine Cavern: Move to BossAI

This commit is contained in:
Shauren
2022-09-20 19:53:50 +02:00
parent c0c8c3bf5d
commit 400d7e20d0
8 changed files with 2540 additions and 2854 deletions

View File

@@ -80,327 +80,304 @@ enum HydrossTheUnstable
#define SPAWN_X_DIFF4 12.577011f
#define SPAWN_Y_DIFF4 4.72702f
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, BOSS_HYDROSS_THE_UNSTABLE)
{
return GetSerpentshrineCavernAI<boss_hydross_the_unstableAI>(creature);
Initialize();
}
struct boss_hydross_the_unstableAI : public ScriptedAI
void Initialize()
{
boss_hydross_the_unstableAI(Creature* creature) : ScriptedAI(creature), Summons(me)
beams[0].Clear();
beams[1].Clear();
PosCheck_Timer = 2500;
MarkOfHydross_Timer = 15000;
MarkOfCorruption_Timer = 15000;
WaterTomb_Timer = 7000;
VileSludge_Timer = 7000;
MarkOfHydross_Count = 0;
MarkOfCorruption_Count = 0;
EnrageTimer = 600000;
CorruptedForm = false;
beam = false;
}
ObjectGuid beams[2];
uint32 PosCheck_Timer;
uint32 MarkOfHydross_Timer;
uint32 MarkOfCorruption_Timer;
uint32 WaterTomb_Timer;
uint32 VileSludge_Timer;
uint32 MarkOfHydross_Count;
uint32 MarkOfCorruption_Count;
uint32 EnrageTimer;
bool CorruptedForm;
bool beam;
void Reset() override
{
DeSummonBeams();
Initialize();
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->SetDisplayId(MODEL_CLEAN);
_Reset();
}
void SummonBeams()
{
Creature* beamer = me->SummonCreature(ENTRY_BEAM_DUMMY, -258.333f, -356.34f, 22.0499f, 5.90835f, TEMPSUMMON_CORPSE_DESPAWN);
if (beamer)
{
Initialize();
instance = creature->GetInstanceScript();
beamer->CastSpell(me, SPELL_BLUE_BEAM, true);
beamer->SetDisplayId(11686); //invisible
beams[0] = beamer->GetGUID();
}
void Initialize()
beamer = me->SummonCreature(ENTRY_BEAM_DUMMY, -219.918f, -371.308f, 22.0042f, 2.73072f, TEMPSUMMON_CORPSE_DESPAWN);
if (beamer)
{
beams[0].Clear();
beams[1].Clear();
PosCheck_Timer = 2500;
MarkOfHydross_Timer = 15000;
MarkOfCorruption_Timer = 15000;
WaterTomb_Timer = 7000;
VileSludge_Timer = 7000;
MarkOfHydross_Count = 0;
MarkOfCorruption_Count = 0;
EnrageTimer = 600000;
CorruptedForm = false;
beam = false;
beamer->CastSpell(me, SPELL_BLUE_BEAM, true);
beamer->SetDisplayId(11686); //invisible
beams[1] = beamer->GetGUID();
}
}
InstanceScript* instance;
ObjectGuid beams[2];
uint32 PosCheck_Timer;
uint32 MarkOfHydross_Timer;
uint32 MarkOfCorruption_Timer;
uint32 WaterTomb_Timer;
uint32 VileSludge_Timer;
uint32 MarkOfHydross_Count;
uint32 MarkOfCorruption_Count;
uint32 EnrageTimer;
bool CorruptedForm;
bool beam;
SummonList Summons;
void Reset() override
void DeSummonBeams()
{
for (uint8 i = 0; i < 2; ++i)
{
DeSummonBeams();
Initialize();
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->SetDisplayId(MODEL_CLEAN);
instance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, NOT_STARTED);
Summons.DespawnAll();
if (Creature* mob = ObjectAccessor::GetCreature(*me, beams[i]))
mob->DespawnOrUnsummon();
}
}
void SummonBeams()
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
_JustEngagedWith(who);
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(CorruptedForm ? SAY_CORRUPT_SLAY : SAY_CLEAN_SLAY);
}
void JustSummoned(Creature* summoned) override
{
if (summoned->GetEntry() == ENTRY_PURE_SPAWN)
summoned->CastSpell(summoned, SPELL_ELEMENTAL_SPAWNIN, true);
if (summoned->GetEntry() == ENTRY_TAINTED_SPAWN)
summoned->CastSpell(summoned, SPELL_ELEMENTAL_SPAWNIN, true);
BossAI::JustSummoned(summoned);
}
void JustDied(Unit* /*killer*/) override
{
Talk(CorruptedForm ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH);
_JustDied();
}
void UpdateAI(uint32 diff) override
{
if (!beam)
{
Creature* beamer = me->SummonCreature(ENTRY_BEAM_DUMMY, -258.333f, -356.34f, 22.0499f, 5.90835f, TEMPSUMMON_CORPSE_DESPAWN);
if (beamer)
SummonBeams();
beam = true;
}
//Return since we have no target
if (!UpdateVictim())
return;
// corrupted form
if (CorruptedForm)
{
//MarkOfCorruption_Timer
if (MarkOfCorruption_Timer <= diff)
{
beamer->CastSpell(me, SPELL_BLUE_BEAM, true);
beamer->SetDisplayId(11686); //invisible
beams[0] = beamer->GetGUID();
}
beamer = me->SummonCreature(ENTRY_BEAM_DUMMY, -219.918f, -371.308f, 22.0042f, 2.73072f, TEMPSUMMON_CORPSE_DESPAWN);
if (beamer)
{
beamer->CastSpell(me, SPELL_BLUE_BEAM, true);
beamer->SetDisplayId(11686); //invisible
beams[1] = beamer->GetGUID();
}
}
void DeSummonBeams()
{
for (uint8 i = 0; i < 2; ++i)
{
if (Creature* mob = ObjectAccessor::GetCreature(*me, beams[i]))
mob->DespawnOrUnsummon();
}
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
instance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, IN_PROGRESS);
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(CorruptedForm ? SAY_CORRUPT_SLAY : SAY_CLEAN_SLAY);
}
void JustSummoned(Creature* summoned) override
{
if (summoned->GetEntry() == ENTRY_PURE_SPAWN)
{
summoned->CastSpell(summoned, SPELL_ELEMENTAL_SPAWNIN, true);
Summons.Summon(summoned);
}
if (summoned->GetEntry() == ENTRY_TAINTED_SPAWN)
{
summoned->CastSpell(summoned, SPELL_ELEMENTAL_SPAWNIN, true);
Summons.Summon(summoned);
}
}
void SummonedCreatureDespawn(Creature* summon) override
{
Summons.Despawn(summon);
}
void JustDied(Unit* /*killer*/) override
{
Talk(CorruptedForm ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH);
instance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, DONE);
Summons.DespawnAll();
}
void UpdateAI(uint32 diff) override
{
if (!beam)
{
SummonBeams();
beam = true;
}
//Return since we have no target
if (!UpdateVictim())
return;
// corrupted form
if (CorruptedForm)
{
//MarkOfCorruption_Timer
if (MarkOfCorruption_Timer <= diff)
if (MarkOfCorruption_Count <= 5)
{
if (MarkOfCorruption_Count <= 5)
uint32 mark_spell = 0;
switch (MarkOfCorruption_Count)
{
uint32 mark_spell = 0;
case 0:
mark_spell = SPELL_MARK_OF_CORRUPTION1;
break;
switch (MarkOfCorruption_Count)
{
case 0:
mark_spell = SPELL_MARK_OF_CORRUPTION1;
break;
case 1:
mark_spell = SPELL_MARK_OF_CORRUPTION2;
break;
case 1:
mark_spell = SPELL_MARK_OF_CORRUPTION2;
break;
case 2:
mark_spell = SPELL_MARK_OF_CORRUPTION3;
break;
case 2:
mark_spell = SPELL_MARK_OF_CORRUPTION3;
break;
case 3:
mark_spell = SPELL_MARK_OF_CORRUPTION4;
break;
case 3:
mark_spell = SPELL_MARK_OF_CORRUPTION4;
break;
case 4:
mark_spell = SPELL_MARK_OF_CORRUPTION5;
break;
case 4:
mark_spell = SPELL_MARK_OF_CORRUPTION5;
break;
case 5:
mark_spell = SPELL_MARK_OF_CORRUPTION6;
break;
}
DoCastVictim(mark_spell);
if (MarkOfCorruption_Count < 5)
++MarkOfCorruption_Count;
case 5:
mark_spell = SPELL_MARK_OF_CORRUPTION6;
break;
}
MarkOfCorruption_Timer = 15000;
} else MarkOfCorruption_Timer -= diff;
DoCastVictim(mark_spell);
//VileSludge_Timer
if (VileSludge_Timer <= diff)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
DoCast(target, SPELL_VILE_SLUDGE);
if (MarkOfCorruption_Count < 5)
++MarkOfCorruption_Count;
}
VileSludge_Timer = 15000;
} else VileSludge_Timer -= diff;
MarkOfCorruption_Timer = 15000;
} else MarkOfCorruption_Timer -= diff;
//PosCheck_Timer
if (PosCheck_Timer <= diff)
{
if (me->IsWithinDist2d(HYDROSS_X, HYDROSS_Y, SWITCH_RADIUS))
{
// switch to clean form
me->SetDisplayId(MODEL_CLEAN);
CorruptedForm = false;
MarkOfHydross_Count = 0;
Talk(SAY_SWITCH_TO_CLEAN);
ResetThreatList();
SummonBeams();
// spawn 4 adds
DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
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);
}
PosCheck_Timer = 2500;
} else PosCheck_Timer -=diff;
}
// clean form
else
//VileSludge_Timer
if (VileSludge_Timer <= diff)
{
//MarkOfHydross_Timer
if (MarkOfHydross_Timer <= diff)
{
if (MarkOfHydross_Count <= 5)
{
uint32 mark_spell = 0;
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
DoCast(target, SPELL_VILE_SLUDGE);
switch (MarkOfHydross_Count)
{
case 0:
mark_spell = SPELL_MARK_OF_HYDROSS1;
break;
VileSludge_Timer = 15000;
} else VileSludge_Timer -= diff;
case 1:
mark_spell = SPELL_MARK_OF_HYDROSS2;
break;
case 2:
mark_spell = SPELL_MARK_OF_HYDROSS3;
break;
case 3:
mark_spell = SPELL_MARK_OF_HYDROSS4;
break;
case 4:
mark_spell = SPELL_MARK_OF_HYDROSS5;
break;
case 5:
mark_spell = SPELL_MARK_OF_HYDROSS6;
break;
}
DoCastVictim(mark_spell);
if (MarkOfHydross_Count < 5)
++MarkOfHydross_Count;
}
MarkOfHydross_Timer = 15000;
} else MarkOfHydross_Timer -= diff;
//WaterTomb_Timer
if (WaterTomb_Timer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
if (target)
DoCast(target, SPELL_WATER_TOMB);
WaterTomb_Timer = 7000;
} else WaterTomb_Timer -= diff;
//PosCheck_Timer
if (PosCheck_Timer <= diff)
{
if (!me->IsWithinDist2d(HYDROSS_X, HYDROSS_Y, SWITCH_RADIUS))
{
// switch to corrupted form
me->SetDisplayId(MODEL_CORRUPT);
MarkOfCorruption_Count = 0;
CorruptedForm = true;
Talk(SAY_SWITCH_TO_CORRUPT);
ResetThreatList();
DeSummonBeams();
// spawn 4 adds
DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false);
}
PosCheck_Timer = 2500;
} else PosCheck_Timer -=diff;
}
//EnrageTimer
if (EnrageTimer <= diff)
//PosCheck_Timer
if (PosCheck_Timer <= diff)
{
DoCast(me, SPELL_ENRAGE);
EnrageTimer = 60000;
} else EnrageTimer -= diff;
if (me->IsWithinDist2d(HYDROSS_X, HYDROSS_Y, SWITCH_RADIUS))
{
// switch to clean form
me->SetDisplayId(MODEL_CLEAN);
CorruptedForm = false;
MarkOfHydross_Count = 0;
DoMeleeAttackIfReady();
Talk(SAY_SWITCH_TO_CLEAN);
ResetThreatList();
SummonBeams();
// spawn 4 adds
DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
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);
}
PosCheck_Timer = 2500;
} else PosCheck_Timer -=diff;
}
};
// clean form
else
{
//MarkOfHydross_Timer
if (MarkOfHydross_Timer <= diff)
{
if (MarkOfHydross_Count <= 5)
{
uint32 mark_spell = 0;
switch (MarkOfHydross_Count)
{
case 0:
mark_spell = SPELL_MARK_OF_HYDROSS1;
break;
case 1:
mark_spell = SPELL_MARK_OF_HYDROSS2;
break;
case 2:
mark_spell = SPELL_MARK_OF_HYDROSS3;
break;
case 3:
mark_spell = SPELL_MARK_OF_HYDROSS4;
break;
case 4:
mark_spell = SPELL_MARK_OF_HYDROSS5;
break;
case 5:
mark_spell = SPELL_MARK_OF_HYDROSS6;
break;
}
DoCastVictim(mark_spell);
if (MarkOfHydross_Count < 5)
++MarkOfHydross_Count;
}
MarkOfHydross_Timer = 15000;
} else MarkOfHydross_Timer -= diff;
//WaterTomb_Timer
if (WaterTomb_Timer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
if (target)
DoCast(target, SPELL_WATER_TOMB);
WaterTomb_Timer = 7000;
} else WaterTomb_Timer -= diff;
//PosCheck_Timer
if (PosCheck_Timer <= diff)
{
if (!me->IsWithinDist2d(HYDROSS_X, HYDROSS_Y, SWITCH_RADIUS))
{
// switch to corrupted form
me->SetDisplayId(MODEL_CORRUPT);
MarkOfCorruption_Count = 0;
CorruptedForm = true;
Talk(SAY_SWITCH_TO_CORRUPT);
ResetThreatList();
DeSummonBeams();
// spawn 4 adds
DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s);
me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false);
}
PosCheck_Timer = 2500;
} else PosCheck_Timer -=diff;
}
//EnrageTimer
if (EnrageTimer <= diff)
{
DoCast(me, SPELL_ENRAGE);
EnrageTimer = 60000;
} else EnrageTimer -= diff;
DoMeleeAttackIfReady();
}
};
void AddSC_boss_hydross_the_unstable()
{
new boss_hydross_the_unstable();
RegisterSerpentshrineCavernCreatureAI(boss_hydross_the_unstable);
}

View File

@@ -80,409 +80,361 @@ float AddPos[9][3] =
{42.471519f, -445.115295f, -19.769423f}
};
class boss_the_lurker_below : public CreatureScript
struct boss_the_lurker_below : public BossAI
{
public:
boss_the_lurker_below() : CreatureScript("boss_the_lurker_below") { }
CreatureAI* GetAI(Creature* creature) const override
boss_the_lurker_below(Creature* creature) : BossAI(creature, BOSS_THE_LURKER_BELOW)
{
return GetSerpentshrineCavernAI<boss_the_lurker_belowAI>(creature);
Initialize();
SetCombatMovement(false);
}
struct boss_the_lurker_belowAI : public ScriptedAI
void Initialize()
{
boss_the_lurker_belowAI(Creature* creature) : ScriptedAI(creature), Summons(me)
SpoutAnimTimer = 1000;
RotTimer = 0;
WaterboltTimer = 15000; // give time to get in range when fight starts
SpoutTimer = 45000;
WhirlTimer = 18000; // after avery spout
PhaseTimer = 120000;
GeyserTimer = rand32() % 5000 + 15000;
CheckTimer = 15000; // give time to get in range when fight starts
WaitTimer = 60000; // never reached
WaitTimer2 = 60000; // never reached
Submerged = true; // will be false at combat start
Spawned = false;
InRange = false;
CanStartEvent = false;
}
bool Spawned;
bool Submerged;
bool InRange;
bool CanStartEvent;
uint32 RotTimer;
uint32 SpoutAnimTimer;
uint32 WaterboltTimer;
uint32 SpoutTimer;
uint32 WhirlTimer;
uint32 PhaseTimer;
uint32 GeyserTimer;
uint32 CheckTimer;
uint32 WaitTimer;
uint32 WaitTimer2;
bool CheckCanStart()//check if players fished
{
if (instance->GetData(DATA_STRANGE_POOL) == NOT_STARTED)
return false;
return true;
}
void Reset() override
{
me->SetSwim(true);
me->SetDisableGravity(true);
Initialize();
_Reset();
instance->SetData(DATA_STRANGE_POOL, NOT_STARTED);
DoCast(me, SPELL_SUBMERGE); // submerge anim
me->SetVisible(false); // we start invis under water, submerged
me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
me->SetImmuneToPC(true);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SetData(DATA_STRANGE_POOL, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* who) override
{
if (!CanStartEvent) // boss is invisible, don't attack
return;
if (!me->GetVictim() && who->IsValidAttackTarget(me))
{
Initialize();
SetCombatMovement(false);
instance = creature->GetInstanceScript();
float attackRadius = me->GetAttackDistance(who);
if (me->IsWithinDistInMap(who, attackRadius))
AttackStart(who);
}
}
void Initialize()
void MovementInform(uint32 type, uint32 /*id*/) override
{
if (type == ROTATE_MOTION_TYPE)
me->SetReactState(REACT_AGGRESSIVE);
}
void UpdateAI(uint32 diff) override
{
if (!CanStartEvent) // boss is invisible, don't attack
{
SpoutAnimTimer = 1000;
RotTimer = 0;
WaterboltTimer = 15000; // give time to get in range when fight starts
SpoutTimer = 45000;
WhirlTimer = 18000; // after avery spout
PhaseTimer = 120000;
GeyserTimer = rand32() % 5000 + 15000;
CheckTimer = 15000; // give time to get in range when fight starts
WaitTimer = 60000; // never reached
WaitTimer2 = 60000; // never reached
Submerged = true; // will be false at combat start
Spawned = false;
InRange = false;
CanStartEvent = false;
}
InstanceScript* instance;
SummonList Summons;
bool Spawned;
bool Submerged;
bool InRange;
bool CanStartEvent;
uint32 RotTimer;
uint32 SpoutAnimTimer;
uint32 WaterboltTimer;
uint32 SpoutTimer;
uint32 WhirlTimer;
uint32 PhaseTimer;
uint32 GeyserTimer;
uint32 CheckTimer;
uint32 WaitTimer;
uint32 WaitTimer2;
bool CheckCanStart()//check if players fished
{
if (instance->GetData(DATA_STRANGE_POOL) == NOT_STARTED)
return false;
return true;
}
void Reset() override
{
me->SetSwim(true);
me->SetDisableGravity(true);
Initialize();
Summons.DespawnAll();
instance->SetData(DATA_THELURKERBELOWEVENT, NOT_STARTED);
instance->SetData(DATA_STRANGE_POOL, NOT_STARTED);
DoCast(me, SPELL_SUBMERGE); // submerge anim
me->SetVisible(false); // we start invis under water, submerged
me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
me->SetImmuneToPC(true);
}
void JustDied(Unit* /*killer*/) override
{
instance->SetData(DATA_THELURKERBELOWEVENT, DONE);
instance->SetData(DATA_STRANGE_POOL, IN_PROGRESS);
Summons.DespawnAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
instance->SetData(DATA_THELURKERBELOWEVENT, IN_PROGRESS);
}
void MoveInLineOfSight(Unit* who) override
{
if (!CanStartEvent) // boss is invisible, don't attack
return;
if (!me->GetVictim() && who->IsValidAttackTarget(me))
if (CheckCanStart())
{
float attackRadius = me->GetAttackDistance(who);
if (me->IsWithinDistInMap(who, attackRadius))
AttackStart(who);
}
}
void MovementInform(uint32 type, uint32 /*id*/) override
{
if (type == ROTATE_MOTION_TYPE)
me->SetReactState(REACT_AGGRESSIVE);
}
void UpdateAI(uint32 diff) override
{
if (!CanStartEvent) // boss is invisible, don't attack
{
if (CheckCanStart())
if (Submerged)
{
if (Submerged)
{
me->SetVisible(true);
Submerged = false;
WaitTimer2 = 500;
}
else if (WaitTimer2 <= diff) // wait 500ms before emerge anim
{
me->RemoveAllAuras();
me->SetEmoteState(EMOTE_ONESHOT_NONE);
DoCast(me, SPELL_EMERGE, false);
WaitTimer2 = 60000; // never reached
WaitTimer = 3000;
}
else
WaitTimer2 -= diff;
if (WaitTimer <= diff) // wait 3secs for emerge anim, then attack
{
WaitTimer = 3000;
CanStartEvent = true; // fresh fished from pool
me->SetImmuneToPC(false);
me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
}
else
WaitTimer -= diff;
me->SetVisible(true);
Submerged = false;
WaitTimer2 = 500;
}
else if (WaitTimer2 <= diff) // wait 500ms before emerge anim
{
me->RemoveAllAuras();
me->SetEmoteState(EMOTE_ONESHOT_NONE);
DoCast(me, SPELL_EMERGE, false);
WaitTimer2 = 60000; // never reached
WaitTimer = 3000;
}
else
WaitTimer2 -= diff;
if (WaitTimer <= diff) // wait 3secs for emerge anim, then attack
{
WaitTimer = 3000;
CanStartEvent = true; // fresh fished from pool
me->SetImmuneToPC(false);
me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
}
else
WaitTimer -= diff;
}
return;
}
if (!me->IsThreatened()) // check if should evade
{
if (me->IsEngaged())
EnterEvadeMode();
return;
}
if (!Submerged)
{
if (PhaseTimer <= diff)
{
me->InterruptNonMeleeSpells(false);
DoCast(me, SPELL_SUBMERGE);
PhaseTimer = 60000; // 60secs submerged
Submerged = true;
}
else
PhaseTimer -= diff;
if (SpoutTimer <= diff)
{
Talk(EMOTE_SPOUT);
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MoveRotate(0, 20000, urand(0, 1) ? ROTATE_DIRECTION_LEFT : ROTATE_DIRECTION_RIGHT);
SpoutTimer = 45000;
WhirlTimer = 20000; // whirl directly after spout
RotTimer = 20000;
return;
}
else
SpoutTimer -= diff;
if (!me->IsThreatened()) // check if should evade
// Whirl directly after a Spout and at random times
if (WhirlTimer <= diff)
{
if (me->IsEngaged())
EnterEvadeMode();
return;
WhirlTimer = 18000;
DoCast(me, SPELL_WHIRL);
}
if (!Submerged)
else
WhirlTimer -= diff;
if (CheckTimer <= diff) // check if there are players in melee range
{
if (PhaseTimer <= diff)
InRange = false;
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
if (!PlayerList.isEmpty())
{
me->InterruptNonMeleeSpells(false);
DoCast(me, SPELL_SUBMERGE);
PhaseTimer = 60000; // 60secs submerged
Submerged = true;
}
else
PhaseTimer -= diff;
if (SpoutTimer <= diff)
{
Talk(EMOTE_SPOUT);
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MoveRotate(0, 20000, urand(0, 1) ? ROTATE_DIRECTION_LEFT : ROTATE_DIRECTION_RIGHT);
SpoutTimer = 45000;
WhirlTimer = 20000; // whirl directly after spout
RotTimer = 20000;
return;
}
else
SpoutTimer -= diff;
// Whirl directly after a Spout and at random times
if (WhirlTimer <= diff)
{
WhirlTimer = 18000;
DoCast(me, SPELL_WHIRL);
}
else
WhirlTimer -= diff;
if (CheckTimer <= diff) // check if there are players in melee range
{
InRange = false;
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
if (!PlayerList.isEmpty())
{
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (me->IsWithinMeleeRange(i->GetSource()))
InRange = true;
}
}
CheckTimer = 2000;
}
else
CheckTimer -= diff;
if (RotTimer)
{
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (i->GetSource() && i->GetSource()->IsAlive() && me->HasInArc(diff/20000.f*float(M_PI)*2.f, i->GetSource()) && me->IsWithinDist(i->GetSource(), SPOUT_DIST) && !i->GetSource()->IsInWater())
DoCast(i->GetSource(), SPELL_SPOUT, true); // only knock back players in arc, in 100yards, not in water
if (me->IsWithinMeleeRange(i->GetSource()))
InRange = true;
}
}
CheckTimer = 2000;
}
else
CheckTimer -= diff;
if (SpoutAnimTimer <= diff)
{
DoCast(me, SPELL_SPOUT_ANIM, true);
SpoutAnimTimer = 1000;
} else SpoutAnimTimer -= diff;
if (RotTimer <= diff)
{
RotTimer = 0;
}
else
RotTimer -= diff;
return;
if (RotTimer)
{
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (i->GetSource() && i->GetSource()->IsAlive() && me->HasInArc(diff/20000.f*float(M_PI)*2.f, i->GetSource()) && me->IsWithinDist(i->GetSource(), SPOUT_DIST) && !i->GetSource()->IsInWater())
DoCast(i->GetSource(), SPELL_SPOUT, true); // only knock back players in arc, in 100yards, not in water
}
if (GeyserTimer <= diff)
if (SpoutAnimTimer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
DoCast(me, SPELL_SPOUT_ANIM, true);
SpoutAnimTimer = 1000;
} else SpoutAnimTimer -= diff;
if (RotTimer <= diff)
{
RotTimer = 0;
}
else
RotTimer -= diff;
return;
}
if (GeyserTimer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
if (!target && me->GetVictim())
target = me->GetVictim();
if (target)
DoCast(target, SPELL_GEYSER, true);
GeyserTimer = rand32() % 5000 + 15000;
}
else
GeyserTimer -= diff;
if (!InRange) // if on players in melee range cast Waterbolt
{
if (WaterboltTimer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (!target && me->GetVictim())
target = me->GetVictim();
if (target)
DoCast(target, SPELL_GEYSER, true);
GeyserTimer = rand32() % 5000 + 15000;
DoCast(target, SPELL_WATERBOLT, true);
WaterboltTimer = 3000;
}
else
GeyserTimer -= diff;
if (!InRange) // if on players in melee range cast Waterbolt
{
if (WaterboltTimer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (!target && me->GetVictim())
target = me->GetVictim();
if (target)
DoCast(target, SPELL_WATERBOLT, true);
WaterboltTimer = 3000;
}
else
WaterboltTimer -= diff;
}
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
WaterboltTimer -= diff;
}
else // submerged
{
if (PhaseTimer <= diff)
{
Submerged = false;
me->InterruptNonMeleeSpells(false); // shouldn't be any
me->RemoveAllAuras();
me->SetImmuneToPC(false);
me->SetEmoteState(EMOTE_ONESHOT_NONE);
DoCast(me, SPELL_EMERGE, true);
Spawned = false;
SpoutTimer = 3000; // directly cast Spout after emerging!
PhaseTimer = 120000;
return;
}
else
PhaseTimer -= diff;
if (!me->IsThreatened()) // check if should evade
{
EnterEvadeMode();
return;
}
if (!me->IsInCombat())
DoZoneInCombat();
if (!Spawned)
{
me->ReplaceAllUnitFlags(UNIT_FLAG_IMMUNE_TO_PC);
// spawn adds
for (uint8 i = 0; i < 9; ++i)
if (Creature* summoned = me->SummonCreature(i < 6 ? NPC_COILFANG_AMBUSHER : NPC_COILFANG_GUARDIAN, AddPos[i][0], AddPos[i][1], AddPos[i][2], 0, TEMPSUMMON_CORPSE_DESPAWN))
Summons.Summon(summoned);
Spawned = true;
}
}
}
};
};
class npc_coilfang_ambusher : public CreatureScript
{
public:
npc_coilfang_ambusher() : CreatureScript("npc_coilfang_ambusher") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetSerpentshrineCavernAI<npc_coilfang_ambusherAI>(creature);
}
struct npc_coilfang_ambusherAI : public ScriptedAI
{
npc_coilfang_ambusherAI(Creature* creature) : ScriptedAI(creature)
{
Initialize();
SetCombatMovement(false);
}
void Initialize()
{
MultiShotTimer = 10000;
ShootBowTimer = 4000;
}
uint32 MultiShotTimer;
uint32 ShootBowTimer;
void Reset() override
{
Initialize();
}
void MoveInLineOfSight(Unit* who) override
{
if (!who || me->GetVictim())
if (!UpdateVictim())
return;
if (who->isInAccessiblePlaceFor(me) && me->IsValidAttackTarget(who) && me->IsWithinDistInMap(who, 45))
AttackStart(who);
}
DoMeleeAttackIfReady();
void UpdateAI(uint32 diff) override
}
else // submerged
{
if (MultiShotTimer <= diff)
if (PhaseTimer <= diff)
{
if (me->GetVictim())
DoCastVictim(SPELL_SPREAD_SHOT, true);
Submerged = false;
me->InterruptNonMeleeSpells(false); // shouldn't be any
me->RemoveAllAuras();
me->SetImmuneToPC(false);
me->SetEmoteState(EMOTE_ONESHOT_NONE);
DoCast(me, SPELL_EMERGE, true);
Spawned = false;
SpoutTimer = 3000; // directly cast Spout after emerging!
PhaseTimer = 120000;
return;
}
else
PhaseTimer -= diff;
MultiShotTimer = 10000 + rand32() % 10000;
ShootBowTimer += 1500; // add global cooldown
} else MultiShotTimer -= diff;
if (ShootBowTimer <= diff)
if (!me->IsThreatened()) // check if should evade
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_SHOOT, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(1100));
ShootBowTimer = 4000 + rand32() % 5000;
MultiShotTimer += 1500; // add global cooldown
} else ShootBowTimer -= diff;
EnterEvadeMode();
return;
}
if (!me->IsInCombat())
DoZoneInCombat();
if (!Spawned)
{
me->ReplaceAllUnitFlags(UNIT_FLAG_IMMUNE_TO_PC);
// spawn adds
for (uint8 i = 0; i < 9; ++i)
me->SummonCreature(i < 6 ? NPC_COILFANG_AMBUSHER : NPC_COILFANG_GUARDIAN, AddPos[i][0], AddPos[i][1], AddPos[i][2], 0, TEMPSUMMON_CORPSE_DESPAWN);
Spawned = true;
}
}
};
}
};
struct npc_coilfang_ambusher : public ScriptedAI
{
npc_coilfang_ambusher(Creature* creature) : ScriptedAI(creature)
{
Initialize();
SetCombatMovement(false);
}
void Initialize()
{
MultiShotTimer = 10000;
ShootBowTimer = 4000;
}
uint32 MultiShotTimer;
uint32 ShootBowTimer;
void Reset() override
{
Initialize();
}
void MoveInLineOfSight(Unit* who) override
{
if (!who || me->GetVictim())
return;
if (who->isInAccessiblePlaceFor(me) && me->IsValidAttackTarget(who) && me->IsWithinDistInMap(who, 45))
AttackStart(who);
}
void UpdateAI(uint32 diff) override
{
if (MultiShotTimer <= diff)
{
if (me->GetVictim())
DoCastVictim(SPELL_SPREAD_SHOT, true);
MultiShotTimer = 10000 + rand32() % 10000;
ShootBowTimer += 1500; // add global cooldown
} else MultiShotTimer -= diff;
if (ShootBowTimer <= diff)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_SHOOT, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(1100));
ShootBowTimer = 4000 + rand32() % 5000;
MultiShotTimer += 1500; // add global cooldown
} else ShootBowTimer -= diff;
}
};
class go_strange_pool : public GameObjectScript
struct go_strange_pool : public GameObjectAI
{
public:
go_strange_pool() : GameObjectScript("go_strange_pool") { }
go_strange_pool(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { }
struct go_strange_poolAI : public GameObjectAI
InstanceScript* instance;
bool OnGossipHello(Player* player) override
{
// 25%
if (!urand(0, 3))
{
go_strange_poolAI(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { }
InstanceScript* instance;
bool OnGossipHello(Player* player) override
if (instance->GetData(DATA_STRANGE_POOL) == NOT_STARTED)
{
// 25%
if (!urand(0, 3))
{
if (instance->GetData(DATA_STRANGE_POOL) == NOT_STARTED)
{
me->CastSpell(player, 54587);
instance->SetData(DATA_STRANGE_POOL, IN_PROGRESS);
}
return true;
}
return false;
me->CastSpell(player, 54587);
instance->SetData(DATA_STRANGE_POOL, IN_PROGRESS);
}
};
GameObjectAI* GetAI(GameObject* go) const override
{
return GetSerpentshrineCavernAI<go_strange_poolAI>(go);
return true;
}
return false;
}
};
void AddSC_boss_the_lurker_below()
{
new boss_the_lurker_below();
new npc_coilfang_ambusher();
new go_strange_pool();
RegisterSerpentshrineCavernCreatureAI(boss_the_lurker_below);
RegisterSerpentshrineCavernCreatureAI(npc_coilfang_ambusher);
RegisterSerpentshrineCavernGameObjectAI(go_strange_pool);
}

View File

@@ -86,286 +86,253 @@ float MurlocCords[10][4] =
};
//Morogrim Tidewalker AI
class boss_morogrim_tidewalker : public CreatureScript
struct boss_morogrim_tidewalker : public BossAI
{
public:
boss_morogrim_tidewalker() : CreatureScript("boss_morogrim_tidewalker") { }
CreatureAI* GetAI(Creature* creature) const override
boss_morogrim_tidewalker(Creature* creature) : BossAI(creature, BOSS_MOROGRIM_TIDEWALKER)
{
return GetSerpentshrineCavernAI<boss_morogrim_tidewalkerAI>(creature);
Initialize();
Playercount = 0;
counter = 0;
}
struct boss_morogrim_tidewalkerAI : public ScriptedAI
void Initialize()
{
boss_morogrim_tidewalkerAI(Creature* creature) : ScriptedAI(creature)
TidalWave_Timer = 10000;
WateryGrave_Timer = 30000;
Earthquake_Timer = 40000;
WateryGlobules_Timer = 0;
globulespell[0] = SPELL_SUMMON_WATER_GLOBULE_1;
globulespell[1] = SPELL_SUMMON_WATER_GLOBULE_2;
globulespell[2] = SPELL_SUMMON_WATER_GLOBULE_3;
globulespell[3] = SPELL_SUMMON_WATER_GLOBULE_4;
Earthquake = false;
Phase2 = false;
}
uint32 TidalWave_Timer;
uint32 WateryGrave_Timer;
uint32 Earthquake_Timer;
uint32 WateryGlobules_Timer;
uint32 globulespell[4];
int8 Playercount;
int8 counter;
bool Earthquake;
bool Phase2;
void Reset() override
{
Initialize();
_Reset();
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
_JustDied();
}
void JustEngagedWith(Unit* who) override
{
Playercount = me->GetMap()->GetPlayers().getSize();
Talk(SAY_AGGRO);
_JustEngagedWith(who);
}
void ApplyWateryGrave(Unit* player, uint8 i)
{
switch (i)
{
Initialize();
instance = creature->GetInstanceScript();
Playercount = 0;
counter = 0;
case 0: player->CastSpell(player, SPELL_WATERY_GRAVE_1, true); break;
case 1: player->CastSpell(player, SPELL_WATERY_GRAVE_2, true); break;
case 2: player->CastSpell(player, SPELL_WATERY_GRAVE_3, true); break;
case 3: player->CastSpell(player, SPELL_WATERY_GRAVE_4, true); break;
}
}
void Initialize()
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
//Earthquake_Timer
if (Earthquake_Timer <= diff)
{
TidalWave_Timer = 10000;
WateryGrave_Timer = 30000;
Earthquake_Timer = 40000;
WateryGlobules_Timer = 0;
globulespell[0] = SPELL_SUMMON_WATER_GLOBULE_1;
globulespell[1] = SPELL_SUMMON_WATER_GLOBULE_2;
globulespell[2] = SPELL_SUMMON_WATER_GLOBULE_3;
globulespell[3] = SPELL_SUMMON_WATER_GLOBULE_4;
Earthquake = false;
Phase2 = false;
}
InstanceScript* instance;
uint32 TidalWave_Timer;
uint32 WateryGrave_Timer;
uint32 Earthquake_Timer;
uint32 WateryGlobules_Timer;
uint32 globulespell[4];
int8 Playercount;
int8 counter;
bool Earthquake;
bool Phase2;
void Reset() override
{
Initialize();
instance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, NOT_STARTED);
}
void StartEvent()
{
Talk(SAY_AGGRO);
instance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, IN_PROGRESS);
}
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_SLAY);
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
instance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, DONE);
}
void JustEngagedWith(Unit* /*who*/) override
{
Playercount = me->GetMap()->GetPlayers().getSize();
StartEvent();
}
void ApplyWateryGrave(Unit* player, uint8 i)
{
switch (i)
if (!Earthquake)
{
case 0: player->CastSpell(player, SPELL_WATERY_GRAVE_1, true); break;
case 1: player->CastSpell(player, SPELL_WATERY_GRAVE_2, true); break;
case 2: player->CastSpell(player, SPELL_WATERY_GRAVE_3, true); break;
case 3: player->CastSpell(player, SPELL_WATERY_GRAVE_4, true); break;
}
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
//Earthquake_Timer
if (Earthquake_Timer <= diff)
{
if (!Earthquake)
{
DoCastVictim(SPELL_EARTHQUAKE);
Earthquake = true;
Earthquake_Timer = 10000;
}
else
{
Talk(SAY_SUMMON);
for (uint8 i = 0; i < 10; ++i)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
if (Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10s))
Murloc->AI()->AttackStart(target);
}
Talk(EMOTE_EARTHQUAKE);
Earthquake = false;
Earthquake_Timer = 40000 + rand32() % 5000;
}
} else Earthquake_Timer -= diff;
//TidalWave_Timer
if (TidalWave_Timer <= diff)
{
DoCastVictim(SPELL_TIDAL_WAVE);
TidalWave_Timer = 20000;
} else TidalWave_Timer -= diff;
if (!Phase2)
{
//WateryGrave_Timer
if (WateryGrave_Timer <= diff)
{
//Teleport 4 players under the waterfalls
GuidSet targets;
GuidSet::const_iterator itr = targets.begin();
for (uint8 i = 0; i < 4; ++i)
{
counter = 0;
Unit* target;
do
{
target = SelectTarget(SelectTargetMethod::Random, 1, 50, true); //target players only
if (counter < Playercount)
break;
if (target)
itr = targets.find(target->GetGUID());
++counter;
} while (itr != targets.end());
if (target)
{
targets.insert(target->GetGUID());
ApplyWateryGrave(target, i);
}
}
Talk(SAY_SUMMON_BUBL);
Talk(EMOTE_WATERY_GRAVE);
WateryGrave_Timer = 30000;
} else WateryGrave_Timer -= diff;
//Start Phase2
if (HealthBelowPct(25))
Phase2 = true;
DoCastVictim(SPELL_EARTHQUAKE);
Earthquake = true;
Earthquake_Timer = 10000;
}
else
{
//WateryGlobules_Timer
if (WateryGlobules_Timer <= diff)
Talk(SAY_SUMMON);
for (uint8 i = 0; i < 10; ++i)
{
GuidSet globules;
GuidSet::const_iterator itr = globules.begin();
for (uint8 g = 0; g < 4; g++) //one unit can't cast more than one spell per update, so some players have to cast for us XD
{
counter = 0;
Unit* pGlobuleTarget;
do
{
pGlobuleTarget = SelectTarget(SelectTargetMethod::Random, 0, 50, true);
if (pGlobuleTarget)
itr = globules.find(pGlobuleTarget->GetGUID());
if (counter > Playercount)
break;
++counter;
} while (itr != globules.end());
if (pGlobuleTarget)
{
globules.insert(pGlobuleTarget->GetGUID());
pGlobuleTarget->CastSpell(pGlobuleTarget, globulespell[g], true);
}
}
Talk(EMOTE_WATERY_GLOBULES);
WateryGlobules_Timer = 25000;
} else WateryGlobules_Timer -= diff;
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
if (Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10s))
Murloc->AI()->AttackStart(target);
}
Talk(EMOTE_EARTHQUAKE);
Earthquake = false;
Earthquake_Timer = 40000 + rand32() % 5000;
}
} else Earthquake_Timer -= diff;
DoMeleeAttackIfReady();
//TidalWave_Timer
if (TidalWave_Timer <= diff)
{
DoCastVictim(SPELL_TIDAL_WAVE);
TidalWave_Timer = 20000;
} else TidalWave_Timer -= diff;
if (!Phase2)
{
//WateryGrave_Timer
if (WateryGrave_Timer <= diff)
{
//Teleport 4 players under the waterfalls
GuidSet targets;
GuidSet::const_iterator itr = targets.begin();
for (uint8 i = 0; i < 4; ++i)
{
counter = 0;
Unit* target;
do
{
target = SelectTarget(SelectTargetMethod::Random, 1, 50, true); //target players only
if (counter < Playercount)
break;
if (target)
itr = targets.find(target->GetGUID());
++counter;
} while (itr != targets.end());
if (target)
{
targets.insert(target->GetGUID());
ApplyWateryGrave(target, i);
}
}
Talk(SAY_SUMMON_BUBL);
Talk(EMOTE_WATERY_GRAVE);
WateryGrave_Timer = 30000;
} else WateryGrave_Timer -= diff;
//Start Phase2
if (HealthBelowPct(25))
Phase2 = true;
}
};
else
{
//WateryGlobules_Timer
if (WateryGlobules_Timer <= diff)
{
GuidSet globules;
GuidSet::const_iterator itr = globules.begin();
for (uint8 g = 0; g < 4; g++) //one unit can't cast more than one spell per update, so some players have to cast for us XD
{
counter = 0;
Unit* pGlobuleTarget;
do
{
pGlobuleTarget = SelectTarget(SelectTargetMethod::Random, 0, 50, true);
if (pGlobuleTarget)
itr = globules.find(pGlobuleTarget->GetGUID());
if (counter > Playercount)
break;
++counter;
} while (itr != globules.end());
if (pGlobuleTarget)
{
globules.insert(pGlobuleTarget->GetGUID());
pGlobuleTarget->CastSpell(pGlobuleTarget, globulespell[g], true);
}
}
Talk(EMOTE_WATERY_GLOBULES);
WateryGlobules_Timer = 25000;
} else WateryGlobules_Timer -= diff;
}
DoMeleeAttackIfReady();
}
};
class npc_water_globule : public CreatureScript
struct npc_water_globule : public ScriptedAI
{
public:
npc_water_globule() : CreatureScript("npc_water_globule") { }
CreatureAI* GetAI(Creature* creature) const override
npc_water_globule(Creature* creature) : ScriptedAI(creature)
{
return GetSerpentshrineCavernAI<npc_water_globuleAI>(creature);
Initialize();
}
struct npc_water_globuleAI : public ScriptedAI
void Initialize()
{
npc_water_globuleAI(Creature* creature) : ScriptedAI(creature)
Check_Timer = 1000;
}
uint32 Check_Timer;
void Reset() override
{
Initialize();
me->SetFaction(FACTION_MONSTER);
}
void JustEngagedWith(Unit* /*who*/) override { }
void MoveInLineOfSight(Unit* who) override
{
if (!who || me->GetVictim())
return;
if (me->CanCreatureAttack(who))
{
Initialize();
//no attack radius check - it attacks the first target that moves in his los
//who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
}
void Initialize()
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
if (Check_Timer <= diff)
{
Check_Timer = 1000;
}
uint32 Check_Timer;
void Reset() override
{
Initialize();
me->SetFaction(FACTION_MONSTER);
}
void JustEngagedWith(Unit* /*who*/) override { }
void MoveInLineOfSight(Unit* who) override
{
if (!who || me->GetVictim())
return;
if (me->CanCreatureAttack(who))
if (me->IsWithinDistInMap(me->GetVictim(), 5))
{
//no attack radius check - it attacks the first target that moves in his los
//who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
DoCastVictim(SPELL_GLOBULE_EXPLOSION);
//despawn
me->DespawnOrUnsummon();
return;
}
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
if (Check_Timer <= diff)
{
if (me->IsWithinDistInMap(me->GetVictim(), 5))
{
DoCastVictim(SPELL_GLOBULE_EXPLOSION);
//despawn
me->DespawnOrUnsummon();
return;
}
Check_Timer = 500;
} else Check_Timer -= diff;
//do NOT deal any melee damage to the target.
}
};
Check_Timer = 500;
} else Check_Timer -= diff;
//do NOT deal any melee damage to the target.
}
};
void AddSC_boss_morogrim_tidewalker()
{
new boss_morogrim_tidewalker();
new npc_water_globule();
RegisterSerpentshrineCavernCreatureAI(boss_morogrim_tidewalker);
RegisterSerpentshrineCavernCreatureAI(npc_water_globule);
}

View File

@@ -96,7 +96,7 @@ class instance_serpent_shrine : public InstanceMapScript
instance_serpentshrine_cavern_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
SetBossNumber(MAX_ENCOUNTER);
StrangePool = 0;
Water = WATERSTATE_FRENZY;
@@ -112,15 +112,6 @@ class instance_serpent_shrine : public InstanceMapScript
TrashCount = 0;
}
bool IsEncounterInProgress() const override
{
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
if (m_auiEncounter[i] == IN_PROGRESS)
return true;
return false;
}
void Update(uint32 diff) override
{
//Water checks
@@ -298,32 +289,6 @@ class instance_serpent_shrine : public InstanceMapScript
case DATA_WATER:
Water = data;
break;
case DATA_HYDROSSTHEUNSTABLEEVENT:
m_auiEncounter[0] = data;
break;
case DATA_LEOTHERASTHEBLINDEVENT:
m_auiEncounter[1] = data;
break;
case DATA_THELURKERBELOWEVENT:
m_auiEncounter[2] = data;
break;
case DATA_KARATHRESSEVENT:
m_auiEncounter[3] = data;
break;
case DATA_MOROGRIMTIDEWALKEREVENT:
m_auiEncounter[4] = data;
break;
//Lady Vashj
case DATA_LADYVASHJEVENT:
if (data == NOT_STARTED)
{
ShieldGeneratorDeactivated[0] = false;
ShieldGeneratorDeactivated[1] = false;
ShieldGeneratorDeactivated[2] = false;
ShieldGeneratorDeactivated[3] = false;
}
m_auiEncounter[5] = data;
break;
case DATA_SHIELDGENERATOR1:
ShieldGeneratorDeactivated[0] = data != 0;
break;
@@ -339,28 +304,28 @@ class instance_serpent_shrine : public InstanceMapScript
default:
break;
}
}
if (data == DONE)
SaveToDB();
bool SetBossState(uint32 id, EncounterState state) override
{
if (!InstanceScript::SetBossState(id, state))
return false;
if (id == BOSS_LADY_VASHJ && state == NOT_STARTED)
{
ShieldGeneratorDeactivated[0] = false;
ShieldGeneratorDeactivated[1] = false;
ShieldGeneratorDeactivated[2] = false;
ShieldGeneratorDeactivated[3] = false;
}
return true;
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_HYDROSSTHEUNSTABLEEVENT:
return m_auiEncounter[0];
case DATA_LEOTHERASTHEBLINDEVENT:
return m_auiEncounter[1];
case DATA_THELURKERBELOWEVENT:
return m_auiEncounter[2];
case DATA_KARATHRESSEVENT:
return m_auiEncounter[3];
case DATA_MOROGRIMTIDEWALKEREVENT:
return m_auiEncounter[4];
//Lady Vashj
case DATA_LADYVASHJEVENT:
return m_auiEncounter[5];
case DATA_SHIELDGENERATOR1:
return ShieldGeneratorDeactivated[0];
case DATA_SHIELDGENERATOR2:
@@ -384,34 +349,14 @@ class instance_serpent_shrine : public InstanceMapScript
return 0;
}
std::string GetSaveData() override
void WriteSaveDataMore(std::ostringstream& stream) override
{
OUT_SAVE_INST_DATA;
std::ostringstream stream;
stream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' '
<< m_auiEncounter[3] << ' ' << m_auiEncounter[4] << ' ' << m_auiEncounter[5] << ' ' << TrashCount;
OUT_SAVE_INST_DATA_COMPLETE;
return stream.str();
stream << TrashCount;
}
void Load(char const* in) override
void ReadSaveDataMore(std::istringstream& stream) override
{
if (!in)
{
OUT_LOAD_INST_DATA_FAIL;
return;
}
OUT_LOAD_INST_DATA(in);
std::istringstream stream(in);
stream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]
>> m_auiEncounter[4] >> m_auiEncounter[5] >> TrashCount;
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead.
m_auiEncounter[i] = NOT_STARTED;
OUT_LOAD_INST_DATA_COMPLETE;
stream >> TrashCount;
}
private:
@@ -435,7 +380,6 @@ class instance_serpent_shrine : public InstanceMapScript
uint32 TrashCount;
bool ShieldGeneratorDeactivated[4];
uint32 m_auiEncounter[MAX_ENCOUNTER];
bool DoSpawnFrenzy;
};

View File

@@ -30,33 +30,37 @@ enum SSWaterEventState
WATERSTATE_SCALDING = 2
};
enum SSBosses
{
BOSS_HYDROSS_THE_UNSTABLE = 0,
BOSS_THE_LURKER_BELOW = 1,
BOSS_LEOTHERAS_THE_BLIND = 2,
BOSS_FATHOM_LORD_KARATHRESS = 3,
BOSS_MOROGRIM_TIDEWALKER = 4,
BOSS_LADY_VASHJ = 5
};
enum SSDataTypes
{
DATA_CANSTARTPHASE3 = 1,
DATA_CARIBDIS = 2,
DATA_HYDROSSTHEUNSTABLEEVENT = 3,
DATA_KARATHRESS = 4,
DATA_KARATHRESSEVENT = 5,
DATA_KARATHRESSEVENT_STARTER = 6,
DATA_LADYVASHJ = 7,
DATA_LADYVASHJEVENT = 8,
DATA_LEOTHERASTHEBLINDEVENT = 9,
DATA_MOROGRIMTIDEWALKEREVENT = 10,
DATA_SHARKKIS = 11,
DATA_SHIELDGENERATOR1 = 12,
DATA_SHIELDGENERATOR2 = 13,
DATA_SHIELDGENERATOR3 = 14,
DATA_SHIELDGENERATOR4 = 15,
DATA_THELURKERBELOW = 16,
DATA_THELURKERBELOWEVENT = 17,
DATA_TIDALVESS = 18,
DATA_FATHOMLORDKARATHRESSEVENT = 19,
DATA_LEOTHERAS = 20,
DATA_LEOTHERAS_EVENT_STARTER = 21,
DATA_CONTROL_CONSOLE = 22,
DATA_STRANGE_POOL = 23,
DATA_WATER = 24,
DATA_TRASH = 25,
DATA_KARATHRESS = 3,
DATA_KARATHRESSEVENT_STARTER = 4,
DATA_LADYVASHJ = 5,
DATA_SHARKKIS = 6,
DATA_SHIELDGENERATOR1 = 7,
DATA_SHIELDGENERATOR2 = 8,
DATA_SHIELDGENERATOR3 = 9,
DATA_SHIELDGENERATOR4 = 10,
DATA_THELURKERBELOW = 11,
DATA_TIDALVESS = 12,
DATA_FATHOMLORDKARATHRESSEVENT = 13,
DATA_LEOTHERAS = 14,
DATA_LEOTHERAS_EVENT_STARTER = 15,
DATA_CONTROL_CONSOLE = 16,
DATA_STRANGE_POOL = 17,
DATA_WATER = 18,
DATA_TRASH = 19,
};
template <class AI, class T>
@@ -65,4 +69,7 @@ inline AI* GetSerpentshrineCavernAI(T* obj)
return GetInstanceAI<AI>(obj, SSCScriptName);
}
#define RegisterSerpentshrineCavernCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSerpentshrineCavernAI)
#define RegisterSerpentshrineCavernGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetSerpentshrineCavernAI)
#endif