EverWrath/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp
IntelligentQuantum ab4ee71762
feat(Core/Maps): AreaBoundary (#10525)
* cherry-picked commit (2da458c56d)
2022-04-15 14:10:41 +02:00

979 lines
35 KiB
C++

/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GridNotifiers.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "icecrown_citadel.h"
enum Texts
{
SAY_PRECIOUS_DIES = 0,
SAY_AGGRO = 1,
EMOTE_SLIME_SPRAY = 2,
SAY_SLIME_SPRAY = 3,
EMOTE_UNSTABLE_EXPLOSION = 4,
SAY_UNSTABLE_EXPLOSION = 5,
SAY_KILL = 6,
SAY_BERSERK = 7,
SAY_DEATH = 8,
EMOTE_MUTATED_INFECTION = 9,
SAY_ROTFACE_OOZE_FLOOD = 2, // professor
EMOTE_PRECIOUS_ZOMBIES = 0,
};
enum Spells
{
// Rotface
SPELL_SLIME_SPRAY = 69508, // every 20 seconds
SPELL_MUTATED_INFECTION = 69674, // hastens every 1:30
SPELL_VILE_GAS_H = 69240,
// Ooze Flood
SPELL_OOZE_FLOOD_VISUAL = 69785,
SPELL_OOZE_FLOOD_PERIODIC = 69788,
// Oozes
SPELL_LITTLE_OOZE_COMBINE = 69537, // combine 2 Small Oozes
SPELL_LARGE_OOZE_COMBINE = 69552, // combine 2 Large Oozes
SPELL_LARGE_OOZE_BUFF_COMBINE = 69611, // combine Large and Small Ooze
SPELL_OOZE_MERGE = 69889, // 2 Small Oozes summon a Large Ooze
SPELL_WEAK_RADIATING_OOZE = 69750, // passive damage aura - small
SPELL_RADIATING_OOZE = 69760, // passive damage aura - large
SPELL_UNSTABLE_OOZE = 69558, // damage boost and counter for explosion
SPELL_GREEN_ABOMINATION_HITTIN__YA_PROC = 70001, // prevents getting hit by infection
SPELL_UNSTABLE_OOZE_EXPLOSION = 69839,
SPELL_STICKY_OOZE = 69774,
SPELL_UNSTABLE_OOZE_EXPLOSION_TRIGGER = 69832,
// Precious
SPELL_MORTAL_WOUND = 71127,
SPELL_DECIMATE = 71123,
SPELL_AWAKEN_PLAGUED_ZOMBIES = 71159,
};
#define MUTATED_INFECTION RAID_MODE<int32>(69674, 71224, 73022, 73023)
enum Events
{
EVENT_NONE,
// Rotface
EVENT_UNROOT,
EVENT_SLIME_SPRAY,
EVENT_HASTEN_INFECTIONS,
EVENT_MUTATED_INFECTION,
EVENT_ROTFACE_OOZE_FLOOD,
EVENT_ROTFACE_VILE_GAS,
EVENT_STICKY_OOZE,
// Precious
EVENT_DECIMATE,
EVENT_MORTAL_WOUND,
EVENT_SUMMON_ZOMBIES,
};
uint32 const oozeFloodSpells[4] = {69782, 69796, 69798, 69801};
uint32 getOozeFloodSpellIndex(uint32 id)
{
switch (id)
{
case 69782:
return 0;
case 69796:
return 1;
case 69798:
return 2;
case 69801:
return 3;
}
return 0;
}
struct RotfaceHeightCheck
{
RotfaceHeightCheck() {}
bool operator()(Creature* stalker) const
{
return stalker->GetPositionZ() < 365.0f;
}
};
class boss_rotface : public CreatureScript
{
public:
boss_rotface() : CreatureScript("boss_rotface") { }
struct boss_rotfaceAI : public BossAI
{
boss_rotfaceAI(Creature* creature) : BossAI(creature, DATA_ROTFACE)
{
}
uint32 infectionCooldown;
ObjectGuid _oozeFloodDummyGUIDs[4][2];
uint8 _oozeFloodStage;
void Reset() override
{
infectionCooldown = 14000;
for (uint8 i = 0; i < 4; ++i)
for (uint8 j = 0; j < 2; ++j)
_oozeFloodDummyGUIDs[i][j].Clear();
_oozeFloodStage = 0;
_Reset();
events.Reset();
}
void EnterCombat(Unit* who) override
{
if (!instance->CheckRequiredBosses(DATA_ROTFACE, who->ToPlayer()))
{
EnterEvadeMode(EVADE_REASON_OTHER);
instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT);
return;
}
// schedule events
events.Reset();
events.ScheduleEvent(EVENT_SLIME_SPRAY, 20000);
events.ScheduleEvent(EVENT_HASTEN_INFECTIONS, 90000);
events.ScheduleEvent(EVENT_MUTATED_INFECTION, 14000);
events.ScheduleEvent(EVENT_ROTFACE_OOZE_FLOOD, 8000);
if (IsHeroic())
events.ScheduleEvent(EVENT_ROTFACE_VILE_GAS, urand(15000, 20000));
me->setActive(true);
Talk(SAY_AGGRO);
DoZoneInCombat();
if (Creature* professor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_PROFESSOR_PUTRICIDE)))
professor->AI()->DoAction(ACTION_ROTFACE_COMBAT);
instance->SetData(DATA_OOZE_DANCE_ACHIEVEMENT, uint32(true)); // reset
// randomize ooze flood
_oozeFloodStage = urand(0, 3);
std::list<Creature*> list;
GetCreatureListWithEntryInGrid(list, me, NPC_PUDDLE_STALKER, 60.0f);
list.remove_if(RotfaceHeightCheck()); // remove from the list all on the ground
for (std::list<Creature*>::const_iterator itr = list.begin(); itr != list.end(); ++itr)
{
uint32 index = me->GetHomePosition().GetAngle(*itr) / (M_PI / 2.0f);
if (index > 3) index = 3;
if (_oozeFloodDummyGUIDs[index][0])
_oozeFloodDummyGUIDs[index][1] = (*itr)->GetGUID();
else
_oozeFloodDummyGUIDs[index][0] = (*itr)->GetGUID();
}
}
void JustDied(Unit* /*killer*/) override
{
instance->DoRemoveAurasDueToSpellOnPlayers(MUTATED_INFECTION);
_JustDied();
Talk(SAY_DEATH);
if (Creature* professor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_PROFESSOR_PUTRICIDE)))
professor->AI()->DoAction(ACTION_ROTFACE_DEATH);
}
void JustReachedHome() override
{
_JustReachedHome();
instance->SetBossState(DATA_ROTFACE, FAIL);
}
void JustSummoned(Creature* summon) override
{
if (me->IsAlive() && me->IsInCombat() && !me->IsInEvadeMode())
summons.Summon(summon);
else
summon->DespawnOrUnsummon(1);
}
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_KILL);
}
void EnterEvadeMode(EvadeReason why) override
{
me->SetControlled(false, UNIT_STATE_ROOT);
me->DisableRotate(false);
ScriptedAI::EnterEvadeMode(why);
if (Creature* professor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_PROFESSOR_PUTRICIDE)))
professor->AI()->EnterEvadeMode(why);
}
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
{
switch (spell->Id)
{
case SPELL_SLIME_SPRAY:
Talk(SAY_SLIME_SPRAY);
break;
case 69507: // Slime Spray damage
case 71213:
case 73189:
case 73190:
if (Player* p = target->ToPlayer())
if (p->GetQuestStatus(QUEST_RESIDUE_RENDEZVOUS_10) == QUEST_STATUS_INCOMPLETE || p->GetQuestStatus(QUEST_RESIDUE_RENDEZVOUS_25) == QUEST_STATUS_INCOMPLETE)
p->CastSpell(p, SPELL_GREEN_BLIGHT_RESIDUE, true);
break;
case 69782:
case 69796:
case 69798:
case 69801:
{
uint32 index = getOozeFloodSpellIndex(spell->Id);
if (target->GetGUID() == _oozeFloodDummyGUIDs[index][0] || target->GetGUID() == _oozeFloodDummyGUIDs[index][1])
target->CastSpell((Unit*)nullptr, spell->Effects[0].CalcValue(), false);
}
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() || !CheckInRoom())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_UNROOT:
me->SetControlled(false, UNIT_STATE_ROOT);
me->DisableRotate(false);
break;
case EVENT_SLIME_SPRAY:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, NonTankTargetSelector(me)))
{
if (Creature* c = me->SummonCreature(NPC_OOZE_SPRAY_STALKER, *target, TEMPSUMMON_TIMED_DESPAWN, 8000))
{
me->SetOrientation(me->GetAngle(c));
me->SetControlled(true, UNIT_STATE_ROOT);
me->DisableRotate(true);
me->SetFacingTo(me->GetAngle(c));
me->SendMovementFlagUpdate();
Talk(EMOTE_SLIME_SPRAY);
me->CastSpell(c, SPELL_SLIME_SPRAY, false);
}
}
events.DelayEvents(1);
events.ScheduleEvent(EVENT_SLIME_SPRAY, 20000);
events.ScheduleEvent(EVENT_UNROOT, 0);
break;
case EVENT_HASTEN_INFECTIONS:
if (infectionCooldown >= 8000)
{
infectionCooldown -= 2000;
events.ScheduleEvent(EVENT_HASTEN_INFECTIONS, 90000);
}
break;
case EVENT_MUTATED_INFECTION:
me->CastCustomSpell(SPELL_MUTATED_INFECTION, SPELLVALUE_MAX_TARGETS, 1, nullptr, false);
events.ScheduleEvent(EVENT_MUTATED_INFECTION, infectionCooldown);
break;
case EVENT_ROTFACE_OOZE_FLOOD:
if (Creature* professor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_PROFESSOR_PUTRICIDE)))
{
professor->AI()->Talk(SAY_ROTFACE_OOZE_FLOOD);
me->CastSpell((Unit*)nullptr, oozeFloodSpells[_oozeFloodStage], true);
if (++_oozeFloodStage == 4)
_oozeFloodStage = 0;
}
events.ScheduleEvent(EVENT_ROTFACE_OOZE_FLOOD, 25000);
break;
case EVENT_ROTFACE_VILE_GAS:
{
std::list<Unit*> targets;
uint32 minTargets = RAID_MODE<uint32>(3, 8, 3, 8);
SelectTargetList(targets, minTargets, SelectTargetMethod::Random, -5.0f, true);
float minDist = 0.0f;
if (targets.size() >= minTargets)
minDist = -5.0f;
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, minDist, true))
if (Creature* professor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_PROFESSOR_PUTRICIDE)))
professor->CastSpell(target, SPELL_VILE_GAS_H, true); // triggered, to skip LoS check
}
events.ScheduleEvent(EVENT_ROTFACE_VILE_GAS, urand(15000, 20000));
break;
default:
break;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetIcecrownCitadelAI<boss_rotfaceAI>(creature);
}
};
class npc_little_ooze : public CreatureScript
{
public:
npc_little_ooze() : CreatureScript("npc_little_ooze") { }
struct npc_little_oozeAI : public ScriptedAI
{
npc_little_oozeAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript())
{
firstUpdate = true;
if (Creature* rotface = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ROTFACE)))
rotface->AI()->JustSummoned(me);
}
bool firstUpdate;
EventMap events;
InstanceScript* instance;
void IsSummonedBy(Unit* summoner) override
{
if (!summoner)
return;
me->AddThreat(summoner, 500000.0f);
AttackStart(summoner);
}
void JustDied(Unit* /*killer*/) override
{
if (Creature* rotface = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ROTFACE)))
rotface->AI()->SummonedCreatureDespawn(me);
me->DespawnOrUnsummon(0);
}
void UpdateAI(uint32 diff) override
{
if (firstUpdate)
{
firstUpdate = false;
me->CastSpell(me, SPELL_LITTLE_OOZE_COMBINE, true);
me->CastSpell(me, SPELL_WEAK_RADIATING_OOZE, true);
events.Reset();
events.ScheduleEvent(EVENT_STICKY_OOZE, 5000);
DoResetThreat();
me->SetInCombatWithZone();
if (TempSummon* ts = me->ToTempSummon())
if (Unit* summoner = ts->GetSummonerUnit())
{
me->AddThreat(summoner, 500000.0f);
AttackStart(summoner);
}
}
if (!UpdateVictim())
return;
events.Update(diff);
if (events.ExecuteEvent() == EVENT_STICKY_OOZE)
{
me->CastSpell(me->GetVictim(), SPELL_STICKY_OOZE, false);
events.ScheduleEvent(EVENT_STICKY_OOZE, 15000);
}
DoMeleeAttackIfReady();
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->SetInCombatWithZone();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetIcecrownCitadelAI<npc_little_oozeAI>(creature);
}
};
class npc_big_ooze : public CreatureScript
{
public:
npc_big_ooze() : CreatureScript("npc_big_ooze") { }
struct npc_big_oozeAI : public ScriptedAI
{
npc_big_oozeAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript())
{
firstUpdate = true;
if (Creature* rotface = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ROTFACE)))
rotface->AI()->JustSummoned(me);
}
bool firstUpdate;
EventMap events;
InstanceScript* instance;
void IsSummonedBy(Unit* /*summoner*/) override
{
if (Player* p = me->SelectNearestPlayer(100.0f))
AttackStart(p);
}
void JustDied(Unit* /*killer*/) override
{
if (Creature* rotface = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ROTFACE)))
rotface->AI()->SummonedCreatureDespawn(me);
me->DespawnOrUnsummon();
}
void DoAction(int32 action) override
{
if (action == EVENT_STICKY_OOZE)
events.CancelEvent(EVENT_STICKY_OOZE);
}
void UpdateAI(uint32 diff) override
{
if (firstUpdate)
{
firstUpdate = false;
me->CastSpell(me, SPELL_LARGE_OOZE_COMBINE, true);
me->CastSpell(me, SPELL_LARGE_OOZE_BUFF_COMBINE, true);
me->CastSpell(me, SPELL_RADIATING_OOZE, true);
me->CastSpell(me, SPELL_UNSTABLE_OOZE, true);
me->CastSpell(me, SPELL_GREEN_ABOMINATION_HITTIN__YA_PROC, true);
events.Reset();
events.ScheduleEvent(EVENT_STICKY_OOZE, 5000);
DoResetThreat();
me->SetInCombatWithZone();
if (Player* p = me->SelectNearestPlayer(100.0f))
AttackStart(p);
}
if (!UpdateVictim())
return;
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_STICKY_OOZE:
me->CastSpell(me->GetVictim(), SPELL_STICKY_OOZE, false);
events.ScheduleEvent(EVENT_STICKY_OOZE, 15000);
default:
break;
}
if (me->IsVisible())
DoMeleeAttackIfReady();
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->SetInCombatWithZone();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetIcecrownCitadelAI<npc_big_oozeAI>(creature);
}
};
class spell_rotface_mutated_infection : public SpellScriptLoader
{
public:
spell_rotface_mutated_infection() : SpellScriptLoader("spell_rotface_mutated_infection") { }
class spell_rotface_mutated_infection_SpellScript : public SpellScript
{
PrepareSpellScript(spell_rotface_mutated_infection_SpellScript);
bool Load() override
{
_target = nullptr;
return true;
}
void FilterTargets(std::list<WorldObject*>& targets)
{
// remove targets with this aura already
// tank is not on this list
targets.remove_if(Acore::UnitAuraCheck(true, GetSpellInfo()->Id));
targets.remove(GetCaster()->GetVictim());
if (targets.empty())
return;
WorldObject* target = Acore::Containers::SelectRandomContainerElement(targets);
targets.clear();
targets.push_back(target);
_target = target;
}
void ReplaceTargets(std::list<WorldObject*>& targets)
{
targets.clear();
if (_target)
targets.push_back(_target);
}
void NotifyTargets()
{
if (Creature* caster = GetCaster()->ToCreature())
if (Unit* target = GetHitUnit())
caster->AI()->Talk(EMOTE_MUTATED_INFECTION, target);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::ReplaceTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rotface_mutated_infection_SpellScript::ReplaceTargets, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY);
AfterHit += SpellHitFn(spell_rotface_mutated_infection_SpellScript::NotifyTargets);
}
WorldObject* _target;
};
class spell_rotface_mutated_infection_AuraScript : public AuraScript
{
PrepareAuraScript(spell_rotface_mutated_infection_AuraScript);
void ExtraRemoveEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->CastSpell(GetTarget(), GetSpellInfo()->Effects[2].CalcValue(), true);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_rotface_mutated_infection_AuraScript::ExtraRemoveEffect, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_rotface_mutated_infection_SpellScript();
}
AuraScript* GetAuraScript() const override
{
return new spell_rotface_mutated_infection_AuraScript();
}
};
class spell_rotface_little_ooze_combine : public SpellScriptLoader
{
public:
spell_rotface_little_ooze_combine() : SpellScriptLoader("spell_rotface_little_ooze_combine") { }
class spell_rotface_little_ooze_combine_SpellScript : public SpellScript
{
PrepareSpellScript(spell_rotface_little_ooze_combine_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
// little targetting little
if (!GetHitCreature() || !GetHitCreature()->IsAlive())
return;
GetCaster()->RemoveAurasDueToSpell(SPELL_LITTLE_OOZE_COMBINE);
GetHitCreature()->RemoveAurasDueToSpell(SPELL_LITTLE_OOZE_COMBINE);
GetHitCreature()->CastSpell(GetCaster(), SPELL_OOZE_MERGE, true);
GetHitCreature()->DespawnOrUnsummon();
if (GetCaster()->ToCreature())
GetCaster()->ToCreature()->DespawnOrUnsummon();
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_rotface_little_ooze_combine_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_rotface_little_ooze_combine_SpellScript();
}
};
class spell_rotface_large_ooze_combine : public SpellScriptLoader
{
public:
spell_rotface_large_ooze_combine() : SpellScriptLoader("spell_rotface_large_ooze_combine") { }
class spell_rotface_large_ooze_combine_SpellScript : public SpellScript
{
PrepareSpellScript(spell_rotface_large_ooze_combine_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
// large targetting large
if (!GetHitCreature() || !GetHitCreature()->IsAlive())
return;
uint8 casterStack = 1;
uint8 targetStack = 1;
Aura* casterAura = GetCaster()->GetAura(SPELL_UNSTABLE_OOZE);
if (casterAura)
casterStack = casterAura->GetStackAmount();
Aura* targetAura = GetHitCreature()->GetAura(SPELL_UNSTABLE_OOZE);
if (targetAura)
targetStack = targetAura->GetStackAmount();
uint8 newStack = casterStack + targetStack;
if (newStack > 5)
newStack = 5;
if (casterAura)
casterAura->SetStackAmount(newStack);
else
{
GetCaster()->CastSpell(GetCaster(), SPELL_UNSTABLE_OOZE, true);
if (Aura* aur = GetCaster()->GetAura(SPELL_UNSTABLE_OOZE))
aur->SetStackAmount(newStack);
}
// red color!
if (newStack >= 4)
GetCaster()->CastSpell(GetCaster(), 69844, true);
// explode!
if (newStack >= 5)
{
GetCaster()->RemoveAurasDueToSpell(SPELL_LARGE_OOZE_BUFF_COMBINE);
GetCaster()->RemoveAurasDueToSpell(SPELL_LARGE_OOZE_COMBINE);
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
if (Creature* rotface = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_ROTFACE)))
if (rotface->IsAlive())
{
if (GetCaster()->GetTypeId() == TYPEID_UNIT)
GetCaster()->ToCreature()->AI()->Talk(EMOTE_UNSTABLE_EXPLOSION);
rotface->AI()->Talk(SAY_UNSTABLE_EXPLOSION);
}
if (Creature* cre = GetCaster()->ToCreature())
cre->AI()->DoAction(EVENT_STICKY_OOZE);
GetCaster()->CastSpell(GetCaster(), SPELL_UNSTABLE_OOZE_EXPLOSION, false, nullptr, nullptr, GetCaster()->GetGUID());
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
instance->SetData(DATA_OOZE_DANCE_ACHIEVEMENT, uint32(false));
}
GetHitCreature()->RemoveAurasDueToSpell(SPELL_LARGE_OOZE_BUFF_COMBINE);
GetHitCreature()->RemoveAurasDueToSpell(SPELL_LARGE_OOZE_COMBINE);
GetHitCreature()->DespawnOrUnsummon();
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_rotface_large_ooze_combine_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_rotface_large_ooze_combine_SpellScript();
}
};
class spell_rotface_large_ooze_buff_combine : public SpellScriptLoader
{
public:
spell_rotface_large_ooze_buff_combine() : SpellScriptLoader("spell_rotface_large_ooze_buff_combine") { }
class spell_rotface_large_ooze_buff_combine_SpellScript : public SpellScript
{
PrepareSpellScript(spell_rotface_large_ooze_buff_combine_SpellScript);
void HandleScript(SpellEffIndex /*effIndex*/)
{
// large targetting little
if (!GetHitCreature() || !GetHitCreature()->IsAlive())
return;
if (Aura* unstable = GetCaster()->GetAura(SPELL_UNSTABLE_OOZE))
{
uint8 newStack = uint8(unstable->GetStackAmount() + 1);
unstable->SetStackAmount(newStack);
// red color!
if (newStack >= 4)
GetCaster()->CastSpell(GetCaster(), 69844, true);
// explode!
if (newStack >= 5)
{
GetCaster()->RemoveAurasDueToSpell(SPELL_LARGE_OOZE_BUFF_COMBINE);
GetCaster()->RemoveAurasDueToSpell(SPELL_LARGE_OOZE_COMBINE);
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
if (Creature* rotface = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_ROTFACE)))
if (rotface->IsAlive())
{
if (GetCaster()->GetTypeId() == TYPEID_UNIT)
GetCaster()->ToCreature()->AI()->Talk(EMOTE_UNSTABLE_EXPLOSION);
rotface->AI()->Talk(SAY_UNSTABLE_EXPLOSION);
}
if (Creature* cre = GetCaster()->ToCreature())
cre->AI()->DoAction(EVENT_STICKY_OOZE);
GetCaster()->CastSpell(GetCaster(), SPELL_UNSTABLE_OOZE_EXPLOSION, false, nullptr, nullptr, GetCaster()->GetGUID());
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
instance->SetData(DATA_OOZE_DANCE_ACHIEVEMENT, uint32(false));
}
}
GetHitCreature()->RemoveAurasDueToSpell(SPELL_LITTLE_OOZE_COMBINE);
GetHitCreature()->DespawnOrUnsummon();
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_rotface_large_ooze_buff_combine_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_rotface_large_ooze_buff_combine_SpellScript();
}
};
class spell_rotface_unstable_ooze_explosion_init : public SpellScriptLoader
{
public:
spell_rotface_unstable_ooze_explosion_init() : SpellScriptLoader("spell_rotface_unstable_ooze_explosion_init") { }
class spell_rotface_unstable_ooze_explosion_init_SpellScript : public SpellScript
{
PrepareSpellScript(spell_rotface_unstable_ooze_explosion_init_SpellScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_UNSTABLE_OOZE_EXPLOSION_TRIGGER });
}
void HandleCast(SpellEffIndex effIndex)
{
PreventHitEffect(effIndex);
if (!GetHitUnit())
return;
float x, y, z;
GetHitUnit()->GetPosition(x, y, z);
Creature* dummy = GetCaster()->SummonCreature(NPC_UNSTABLE_EXPLOSION_STALKER, x, y, z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000);
GetCaster()->CastSpell(dummy, SPELL_UNSTABLE_OOZE_EXPLOSION_TRIGGER, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_rotface_unstable_ooze_explosion_init_SpellScript::HandleCast, EFFECT_0, SPELL_EFFECT_FORCE_CAST);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_rotface_unstable_ooze_explosion_init_SpellScript();
}
};
class spell_rotface_unstable_ooze_explosion : public SpellScriptLoader
{
public:
spell_rotface_unstable_ooze_explosion() : SpellScriptLoader("spell_rotface_unstable_ooze_explosion") { }
class spell_rotface_unstable_ooze_explosion_SpellScript : public SpellScript
{
PrepareSpellScript(spell_rotface_unstable_ooze_explosion_SpellScript);
void CheckTarget(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(EFFECT_0);
if (!GetExplTargetDest())
return;
uint32 triggered_spell_id = GetSpellInfo()->Effects[effIndex].TriggerSpell;
float x, y, z;
GetExplTargetDest()->GetPosition(x, y, z);
// let Rotface handle the cast - caster dies before this executes
if (InstanceScript* script = GetCaster()->GetInstanceScript())
if (Creature* rotface = script->instance->GetCreature(script->GetGuidData(DATA_ROTFACE)))
rotface->CastSpell(x, y, z, triggered_spell_id, true/*, nullptr, nullptr, GetCaster()->GetGUID()*/); // caster not available on clientside, no log in such case
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_rotface_unstable_ooze_explosion_SpellScript::CheckTarget, EFFECT_0, SPELL_EFFECT_TRIGGER_MISSILE);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_rotface_unstable_ooze_explosion_SpellScript();
}
};
class spell_rotface_unstable_ooze_explosion_suicide : public SpellScriptLoader
{
public:
spell_rotface_unstable_ooze_explosion_suicide() : SpellScriptLoader("spell_rotface_unstable_ooze_explosion_suicide") { }
class spell_rotface_unstable_ooze_explosion_suicide_AuraScript : public AuraScript
{
PrepareAuraScript(spell_rotface_unstable_ooze_explosion_suicide_AuraScript);
void DespawnSelf(AuraEffect const* /*aurEff*/)
{
PreventDefaultAction();
Unit* target = GetTarget();
if (target->GetTypeId() != TYPEID_UNIT)
return;
target->SetVisible(false);
target->RemoveAllAuras();
//target->ToCreature()->DespawnOrUnsummon();
target->ToCreature()->DespawnOrUnsummon(60000);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_rotface_unstable_ooze_explosion_suicide_AuraScript::DespawnSelf, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_rotface_unstable_ooze_explosion_suicide_AuraScript();
}
};
class npc_precious_icc : public CreatureScript
{
public:
npc_precious_icc() : CreatureScript("npc_precious_icc") { }
struct npc_precious_iccAI : public ScriptedAI
{
npc_precious_iccAI(Creature* creature) : ScriptedAI(creature), summons(me) {}
void Reset() override
{
events.Reset();
summons.DespawnAll();
}
void EnterCombat(Unit* /*target*/) override
{
me->setActive(true);
events.ScheduleEvent(EVENT_DECIMATE, urand(20000, 25000));
events.ScheduleEvent(EVENT_MORTAL_WOUND, urand(1500, 2500));
events.ScheduleEvent(EVENT_SUMMON_ZOMBIES, urand(25000, 30000));
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
summon->AI()->AttackStart(target);
}
void SummonedCreatureDespawn(Creature* summon) override
{
summons.Despawn(summon);
}
void JustDied(Unit* /*killer*/) override
{
summons.DespawnAll();
if (InstanceScript* _instance = me->GetInstanceScript())
if (Creature* rotface = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ROTFACE)))
if (rotface->IsAlive())
rotface->AI()->Talk(SAY_PRECIOUS_DIES);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DECIMATE:
me->CastSpell(me->GetVictim(), SPELL_DECIMATE, false);
events.ScheduleEvent(EVENT_DECIMATE, urand(20000, 25000));
break;
case EVENT_MORTAL_WOUND:
me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
events.ScheduleEvent(EVENT_MORTAL_WOUND, urand(1500, 2500));
break;
case EVENT_SUMMON_ZOMBIES:
Talk(EMOTE_PRECIOUS_ZOMBIES);
for (uint32 i = 0; i < 11; ++i)
me->CastSpell(me, SPELL_AWAKEN_PLAGUED_ZOMBIES, true);
events.ScheduleEvent(EVENT_SUMMON_ZOMBIES, urand(20000, 25000));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
EventMap events;
SummonList summons;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetIcecrownCitadelAI<npc_precious_iccAI>(creature);
}
};
void AddSC_boss_rotface()
{
new boss_rotface();
new npc_little_ooze();
new npc_big_ooze();
new spell_rotface_mutated_infection();
new spell_rotface_little_ooze_combine();
new spell_rotface_large_ooze_combine();
new spell_rotface_large_ooze_buff_combine();
new spell_rotface_unstable_ooze_explosion_init();
new spell_rotface_unstable_ooze_explosion();
new spell_rotface_unstable_ooze_explosion_suicide();
new npc_precious_icc();
}