Co-authored-by: Kelno <3866946+kelno@users.noreply.github.com> Co-authored-by: Peter Keresztes Schmidt <carbenium@outlook.com>
389 lines
14 KiB
C++
389 lines
14 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 "CreatureScript.h"
|
|
#include "ScriptedCreature.h"
|
|
#include "SpellInfo.h"
|
|
#include "oculus.h"
|
|
|
|
enum Spells
|
|
{
|
|
SPELL_EVOCATION = 51602,
|
|
SPELL_SUMMON_MENAGERIE_1 = 50476,
|
|
SPELL_SUMMON_MENAGERIE_2 = 50495,
|
|
SPELL_SUMMON_MENAGERIE_3 = 50496,
|
|
SPELL_TELEPORT = 51112,
|
|
|
|
SPELL_FROSTBOMB = 51103,
|
|
SPELL_TIME_BOMB_N = 51121,
|
|
SPELL_TIME_BOMB_H = 59376,
|
|
SPELL_EMPOWERED_ARCANE_EXPLOSION_N = 51110,
|
|
SPELL_EMPOWERED_ARCANE_EXPLOSION_H = 59377,
|
|
};
|
|
|
|
#define SPELL_EMPOWERED_ARCANE_EXPLOSION DUNGEON_MODE(SPELL_EMPOWERED_ARCANE_EXPLOSION_N, SPELL_EMPOWERED_ARCANE_EXPLOSION_H)
|
|
//#define SPELL_TIME_BOMB DUNGEON_MODE(SPELL_TIME_BOMB_N, SPELL_TIME_BOMB_H)
|
|
|
|
enum UromNPCs
|
|
{
|
|
NPC_PHANTASMAL_CLOUDSCRAPER = 27645,
|
|
NPC_PHANTASMAL_MAMMOTH = 27642,
|
|
NPC_PHANTASMAL_WOLF = 27644,
|
|
|
|
NPC_PHANTASMAL_AIR = 27650,
|
|
NPC_PHANTASMAL_FIRE = 27651,
|
|
NPC_PHANTASMAL_WATER = 27653,
|
|
|
|
NPC_PHANTASMAL_MURLOC = 27649,
|
|
NPC_PHANTASMAL_NAGAL = 27648,
|
|
NPC_PHANTASMAL_OGRE = 27647,
|
|
};
|
|
|
|
enum Events
|
|
{
|
|
EVENT_FROSTBOMB = 1,
|
|
EVENT_TELEPORT_TO_CENTER = 2,
|
|
EVENT_TELE_BACK = 3,
|
|
EVENT_TIME_BOMB = 4,
|
|
};
|
|
|
|
enum Yells
|
|
{
|
|
SAY_SUMMON_1 = 0,
|
|
SAY_SUMMON_2 = 1,
|
|
SAY_SUMMON_3 = 2,
|
|
SAY_AGGRO = 3,
|
|
EMOTE_ARCANE_EXPLOSION = 4,
|
|
SAY_ARCANE_EXPLOSION = 5,
|
|
SAY_DEATH = 6,
|
|
SAY_PLAYER_KILL = 7
|
|
};
|
|
|
|
float summons[3][4] =
|
|
{
|
|
{NPC_PHANTASMAL_AIR, NPC_PHANTASMAL_AIR, NPC_PHANTASMAL_WATER, NPC_PHANTASMAL_FIRE},
|
|
{NPC_PHANTASMAL_OGRE, NPC_PHANTASMAL_OGRE, NPC_PHANTASMAL_NAGAL, NPC_PHANTASMAL_MURLOC},
|
|
{NPC_PHANTASMAL_CLOUDSCRAPER, NPC_PHANTASMAL_CLOUDSCRAPER, NPC_PHANTASMAL_MAMMOTH, NPC_PHANTASMAL_WOLF}
|
|
};
|
|
|
|
float cords[5][4] =
|
|
{
|
|
{1177.47f, 937.722f, 527.405f, 2.21657f},
|
|
{968.66f, 1042.53f, 527.32f, 0.077f},
|
|
{1164.02f, 1170.85f, 527.321f, 3.66f},
|
|
{1118.31f, 1080.377f, 508.361f, 4.25f},
|
|
// There are 4 phases but with the code like this:
|
|
// me->SetHomePosition(cords[phase + 1][0], cords[phase + 1][1], cords[phase + 1][2], cords[phase + 1][3]);
|
|
// lets provide fallback position.
|
|
{1177.47f, 937.722f, 527.405f, 2.21657f}
|
|
};
|
|
|
|
class boss_urom : public CreatureScript
|
|
{
|
|
public:
|
|
boss_urom() : CreatureScript("boss_urom") { }
|
|
|
|
CreatureAI* GetAI(Creature* pCreature) const override
|
|
{
|
|
return GetOculusAI<boss_uromAI>(pCreature);
|
|
}
|
|
|
|
struct boss_uromAI : public ScriptedAI
|
|
{
|
|
boss_uromAI(Creature* c) : ScriptedAI(c)
|
|
{
|
|
pInstance = c->GetInstanceScript();
|
|
}
|
|
|
|
InstanceScript* pInstance;
|
|
EventMap events;
|
|
bool lock, inCenter;
|
|
float x, y, z;
|
|
int32 releaseLockTimer;
|
|
|
|
uint8 GetPhaseByCurrentPosition()
|
|
{
|
|
for (uint8 i = 0; i < 4; ++i)
|
|
if (me->GetDistance(cords[i][0], cords[i][1], cords[i][2]) < 20.0f)
|
|
return i;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Reset() override
|
|
{
|
|
if (pInstance)
|
|
{
|
|
pInstance->SetData(DATA_UROM, NOT_STARTED);
|
|
if (pInstance->GetData(DATA_VAROS) != DONE )
|
|
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
|
else
|
|
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
|
}
|
|
|
|
me->CastSpell(me, SPELL_EVOCATION, true);
|
|
events.Reset();
|
|
lock = false;
|
|
inCenter = false;
|
|
x = 0.0f;
|
|
y = 0.0f;
|
|
z = 0.0f;
|
|
releaseLockTimer = 0;
|
|
me->ApplySpellImmune(0, IMMUNITY_ID, 49838, true);
|
|
}
|
|
|
|
void JustEngagedWith(Unit* /*who*/) override
|
|
{
|
|
if (lock)
|
|
return;
|
|
|
|
uint8 phase = GetPhaseByCurrentPosition();
|
|
if (phase == 3)
|
|
{
|
|
Talk(SAY_AGGRO);
|
|
|
|
if (pInstance)
|
|
pInstance->SetData(DATA_UROM, IN_PROGRESS);
|
|
|
|
me->SetInCombatWithZone();
|
|
me->SetHomePosition(cords[0][0], cords[0][1], cords[0][2], cords[0][3]);
|
|
if (me->FindCurrentSpellBySpellId(SPELL_EVOCATION))
|
|
me->InterruptNonMeleeSpells(false);
|
|
|
|
events.RescheduleEvent(EVENT_FROSTBOMB, 7s, 11s);
|
|
events.RescheduleEvent(EVENT_TELEPORT_TO_CENTER, 30s, 35s);
|
|
events.RescheduleEvent(EVENT_TIME_BOMB, 20s, 25s);
|
|
}
|
|
else
|
|
{
|
|
lock = true;
|
|
|
|
switch (phase)
|
|
{
|
|
case 0:
|
|
Talk(SAY_SUMMON_1);
|
|
me->InterruptNonMeleeSpells(false);
|
|
me->CastSpell(me, SPELL_SUMMON_MENAGERIE_1, false);
|
|
break;
|
|
case 1:
|
|
Talk(SAY_SUMMON_2);
|
|
me->InterruptNonMeleeSpells(false);
|
|
me->CastSpell(me, SPELL_SUMMON_MENAGERIE_2, false);
|
|
break;
|
|
case 2:
|
|
Talk(SAY_SUMMON_3);
|
|
me->InterruptNonMeleeSpells(false);
|
|
me->CastSpell(me, SPELL_SUMMON_MENAGERIE_3, false);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AttackStart(Unit* who) override
|
|
{
|
|
if (lock)
|
|
return;
|
|
|
|
if (me->GetDistance(1103.0f, 1049.0f, 510.0f) < 55.0f)
|
|
ScriptedAI::AttackStart(who);
|
|
}
|
|
|
|
void JustSummoned(Creature* pSummon) override
|
|
{
|
|
pSummon->SetInCombatWithZone();
|
|
if (Unit* v = pSummon->SelectVictim())
|
|
if (pSummon->AI())
|
|
pSummon->AI()->AttackStart(v);
|
|
}
|
|
|
|
void LeaveCombat()
|
|
{
|
|
me->RemoveAllAuras();
|
|
me->GetThreatMgr().ClearAllThreat();
|
|
me->CombatStop(true);
|
|
me->LoadCreaturesAddon(true);
|
|
me->SetLootRecipient(nullptr);
|
|
me->ResetPlayerDamageReq();
|
|
}
|
|
|
|
void JustDied(Unit* /*killer*/) override
|
|
{
|
|
Talk(SAY_DEATH);
|
|
if (pInstance)
|
|
{
|
|
pInstance->SetData(DATA_UROM, DONE);
|
|
}
|
|
|
|
// Body teleportation required only when boss is flying in the center
|
|
if (inCenter)
|
|
{
|
|
me->SetCanFly(false);
|
|
me->SetDisableGravity(false);
|
|
me->NearTeleportTo(x, y, z, 0.0f);
|
|
}
|
|
}
|
|
|
|
void KilledUnit(Unit* /*victim*/) override
|
|
{
|
|
Talk(SAY_PLAYER_KILL);
|
|
}
|
|
|
|
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
|
{
|
|
switch (spell->Id)
|
|
{
|
|
case SPELL_SUMMON_MENAGERIE_1:
|
|
{
|
|
for( uint8 i = 0; i < 4; ++i )
|
|
me->SummonCreature(summons[0][i], cords[0][0] + ((i % 2) ? 4.0f : -4.0f), cords[0][1] + (i < 2 ? 4.0f : -4.0f), cords[0][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000);
|
|
uint8 phase = GetPhaseByCurrentPosition();
|
|
me->SetHomePosition(cords[phase + 1][0], cords[phase + 1][1], cords[phase + 1][2], cords[phase + 1][3]);
|
|
me->DestroyForVisiblePlayers();
|
|
LeaveCombat();
|
|
me->CastSpell(me, SPELL_EVOCATION, true);
|
|
releaseLockTimer = 1;
|
|
}
|
|
break;
|
|
case SPELL_SUMMON_MENAGERIE_2:
|
|
{
|
|
for( uint8 i = 0; i < 4; ++i )
|
|
me->SummonCreature(summons[1][i], cords[1][0] + ((i % 2) ? 4.0f : -4.0f), cords[1][1] + (i < 2 ? 4.0f : -4.0f), cords[1][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000);
|
|
uint8 phase = GetPhaseByCurrentPosition();
|
|
me->SetHomePosition(cords[phase + 1][0], cords[phase + 1][1], cords[phase + 1][2], cords[phase + 1][3]);
|
|
me->DestroyForVisiblePlayers();
|
|
LeaveCombat();
|
|
me->CastSpell(me, SPELL_EVOCATION, true);
|
|
releaseLockTimer = 1;
|
|
}
|
|
break;
|
|
case SPELL_SUMMON_MENAGERIE_3:
|
|
{
|
|
for( uint8 i = 0; i < 4; ++i )
|
|
me->SummonCreature(summons[2][i], cords[2][0] + ((i % 2) ? 4.0f : -4.0f), cords[2][1] + (i < 2 ? 4.0f : -4.0f), cords[2][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000);
|
|
uint8 phase = GetPhaseByCurrentPosition();
|
|
me->SetHomePosition(cords[phase + 1][0], cords[phase + 1][1], cords[phase + 1][2], cords[phase + 1][3]);
|
|
me->DestroyForVisiblePlayers();
|
|
LeaveCombat();
|
|
me->CastSpell(me, SPELL_EVOCATION, true);
|
|
releaseLockTimer = 1;
|
|
}
|
|
break;
|
|
case SPELL_TELEPORT:
|
|
me->GetMotionMaster()->Clear();
|
|
me->GetMotionMaster()->MoveIdle();
|
|
me->StopMoving();
|
|
me->SetControlled(true, UNIT_STATE_ROOT);
|
|
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
|
me->SetCanFly(true);
|
|
me->SetDisableGravity(true);
|
|
me->NearTeleportTo(1103.69f, 1048.76f, 512.279f, 1.16f);
|
|
inCenter = true;
|
|
|
|
Talk(SAY_ARCANE_EXPLOSION);
|
|
Talk(EMOTE_ARCANE_EXPLOSION);
|
|
|
|
//At this point we are still in casting state so we need to clear it for DoCastAOE not to fail
|
|
me->ClearUnitState(UNIT_STATE_CASTING);
|
|
DoCastAOE(DUNGEON_MODE(SPELL_EMPOWERED_ARCANE_EXPLOSION_N, SPELL_EMPOWERED_ARCANE_EXPLOSION_H));
|
|
me->AddUnitState(UNIT_STATE_CASTING);
|
|
events.RescheduleEvent(EVENT_TELE_BACK, DUNGEON_MODE(9s, 7s));
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MoveInLineOfSight(Unit* /*who*/) override {}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
if (releaseLockTimer)
|
|
{
|
|
if (releaseLockTimer >= 5000)
|
|
{
|
|
lock = false;
|
|
if (me->IsInCombat())
|
|
{
|
|
LeaveCombat();
|
|
me->CastSpell(me, SPELL_EVOCATION, true);
|
|
}
|
|
releaseLockTimer = 0;
|
|
}
|
|
else
|
|
releaseLockTimer += diff;
|
|
}
|
|
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
events.Update(diff);
|
|
|
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
return;
|
|
|
|
DoMeleeAttackIfReady();
|
|
|
|
switch (events.ExecuteEvent())
|
|
{
|
|
case 0:
|
|
break;
|
|
case EVENT_FROSTBOMB:
|
|
if (Unit* v = me->GetVictim())
|
|
me->CastSpell(v, SPELL_FROSTBOMB, false);
|
|
events.Repeat(7s, 11s);
|
|
break;
|
|
case EVENT_TIME_BOMB:
|
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
|
|
DoCast(target, DUNGEON_MODE(SPELL_TIME_BOMB_N, SPELL_TIME_BOMB_H));
|
|
events.Repeat(20s, 25s);
|
|
break;
|
|
case EVENT_TELEPORT_TO_CENTER:
|
|
x = me->GetPositionX();
|
|
y = me->GetPositionY();
|
|
z = me->GetPositionZ();
|
|
me->CastSpell(me, SPELL_TELEPORT, false);
|
|
events.Repeat(25s, 30s);
|
|
events.DelayEvents(10s);
|
|
break;
|
|
case EVENT_TELE_BACK:
|
|
me->GetMotionMaster()->MoveIdle();
|
|
me->DisableSpline();
|
|
me->SetCanFly(false);
|
|
me->SetDisableGravity(false);
|
|
me->NearTeleportTo(x, y, z, 0.0f);
|
|
me->SetControlled(false, UNIT_STATE_ROOT);
|
|
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
|
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
|
inCenter = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EnterEvadeMode(EvadeReason why) override
|
|
{
|
|
me->SetCanFly(false);
|
|
me->SetDisableGravity(false);
|
|
me->SetControlled(false, UNIT_STATE_ROOT);
|
|
inCenter = false;
|
|
ScriptedAI::EnterEvadeMode(why);
|
|
}
|
|
};
|
|
};
|
|
|
|
void AddSC_boss_urom()
|
|
{
|
|
new boss_urom();
|
|
}
|