/*
* This file is part of the TrinityCore 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
* 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
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "AreaTrigger.h"
#include "AreaTriggerAI.h"
#include "InstanceScript.h"
#include "Map.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "atal_dazar.h"
enum RezanSpells
{
SPELL_TAIL_SELECTOR = 255372,
SPELL_TAIL_DAMAGE = 255373,
SPELL_SERRATED_TEETH = 255434,
SPELL_DEVOUR = 255421,
SPELL_TERRIFYING_VISAGE = 255371,
SPELL_REVERSE_CAST_RIDE_VEHICLE = 258344,
SPELL_PURSUIT = 257407,
SPELL_RIDE_VEHICLE = 46598,
SPELL_PILE_OF_BONES_AT_SPAWN = 256608,
SPELL_PILE_OF_BONES_AT_SLOW = 256606,
SPELL_PILE_OF_BONES_TRIGGER_SPAWN = 256634,
SPELL_PILE_OF_BONES_SLOW = 257483,
SPELL_BOSS_EMOTE_AT_TARGET = 255600
};
enum RezanEvents
{
EVENT_TERRIFYING_VISAGE = 1,
EVENT_TAIL,
EVENT_SERRATED_TEETH,
EVENT_PURSUIT
};
enum RezanTexts
{
SAY_REANIMATED_RAPTOR_WARNING = 0,
SAY_REANIMATED_RAPTOR_SUMMONER = 1,
SAY_TERRIFYING_VISAGE = 2,
SAY_PURSUIT = 3
};
constexpr Position PilesOfBonesPosition[]
{
{ -814.344f, 2241.63f, 641.538f },
{ -868.391f, 2245.54f, 642.03f },
{ -887.726f, 2242.22f, 642.04f },
{ -846.66f, 2247.46f, 641.774f },
{ -902.443f, 2238.86f, 642.331f },
{ -829.602f, 2247.23f, 641.842f },
{ -793.8f, 2239.09f, 641.832f },
{ -859.222f, 2256.25f, 643.136f },
{ -871.375f, 2258.77f, 643.438f },
{ -804.901f, 2254.52f, 641.964f },
{ -884.057f, 2257.15f, 642.643f },
{ -818.212f, 2259.57f, 642.465f },
{ -830.214f, 2265.17f, 642.486f },
{ -897.104f, 2259.22f, 641.901f },
{ -874.649f, 2273.9f, 642.642f },
{ -809.342f, 2272.22f, 641.905f },
{ -821.203f, 2279.28f, 642.488f },
{ -893.123f, 2276.57f, 642.583f },
{ -848.333f, 2288.46f, 642.486f },
{ -797.328f, 2282.58f, 641.182f },
{ -900.995f, 2285.5f, 641.773f },
{ -804.385f, 2293.2f, 641.488f },
{ -895.255f, 2298.0f, 642.486f },
{ -880.141f, 2301.81f, 642.501f },
{ -826.514f, 2306.46f, 642.699f },
{ -871.58f, 2311.03f, 642.487f },
{ -803.264f, 2310.29f, 641.707f },
{ -817.41f, 2313.88f, 641.638f },
{ -889.821f, 2315.4f, 642.486f },
{ -834.929f, 2321.18f, 643.028f },
{ -861.599f, 2322.33f, 642.5f },
{ -872.771f, 2324.00f, 642.77f },
{ -825.752f, 2329.17f, 642.247f },
{ -810.163f, 2327.19f, 641.401f },
{ -884.835f, 2331.72f, 642.487f },
{ -843.49f, 2335.39f, 642.765f },
{ -895.611f, 2334.97f, 642.425f },
{ -874.451f, 2340.77f, 643.405f },
{ -817.785f, 2342.43f, 641.914f },
{ -861.078f, 2344.69f, 642.685f },
{ -838.155f, 2345.16f, 642.733f },
{ -869.793f, 2352.61f, 642.515f }
};
// 122963 - Rezan
struct boss_rezan : public BossAI
{
boss_rezan(Creature* creature) : BossAI(creature, DATA_REZAN) { }
void JustAppeared() override
{
for (Position const& spawnPoint : PilesOfBonesPosition)
{
me->CastSpell(spawnPoint, SPELL_PILE_OF_BONES_AT_SPAWN, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
me->CastSpell(spawnPoint, SPELL_PILE_OF_BONES_AT_SLOW, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
}
void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
{
if (apply && who->ToPlayer())
DoCast(who, SPELL_DEVOUR, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
_EnterEvadeMode();
_DespawnAtEvade();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
events.ScheduleEvent(EVENT_TERRIFYING_VISAGE, 12200ms);
events.ScheduleEvent(EVENT_TAIL, 6100ms);
events.ScheduleEvent(EVENT_SERRATED_TEETH, 8500ms);
events.ScheduleEvent(EVENT_PURSUIT, 21900ms);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_TERRIFYING_VISAGE:
{
DoCastSelf(SPELL_TERRIFYING_VISAGE);
Talk(SAY_TERRIFYING_VISAGE);
events.Repeat(35500ms);
break;
}
case EVENT_TAIL:
{
DoCastSelf(SPELL_TAIL_SELECTOR);
events.Repeat(15800ms, 18200ms);
break;
}
case EVENT_SERRATED_TEETH:
{
DoCastVictim(SPELL_SERRATED_TEETH);
events.Repeat(34100ms);
break;
}
case EVENT_PURSUIT:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
DoCast(target, SPELL_BOSS_EMOTE_AT_TARGET, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
DoCast(target, SPELL_PURSUIT, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
events.Repeat(35200ms);
break;
}
default:
break;
}
}
};
// 255372 - Tail
class spell_rezan_tail_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_TAIL_DAMAGE });
}
void HandleHitTarget(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_TAIL_DAMAGE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_rezan_tail_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 255421 - Devour
class spell_rezan_devour : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_RIDE_VEHICLE });
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) const
{
if (Unit* caster = GetCaster())
caster->RemoveAura(SPELL_RIDE_VEHICLE);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_rezan_devour::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
// 257407 - Pursuit
class spell_rezan_pursuit : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_REVERSE_CAST_RIDE_VEHICLE });
}
void HandlePeriodic(AuraEffect const* aurEff) const
{
if (Unit* caster = GetCaster())
caster->CastSpell(GetTarget(), SPELL_REVERSE_CAST_RIDE_VEHICLE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringAura = aurEff
});
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_rezan_pursuit::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// 255600 - Boss Emote Passed Points 0 @ Target
class spell_rezan_boss_emote_at_target : public SpellScript
{
void HandleHitTarget(SpellEffIndex /*effIndex*/) const
{
if (Creature* casterCreature = GetCaster()->ToCreature())
casterCreature->AI()->Talk(SAY_PURSUIT, GetHitUnit());
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_rezan_boss_emote_at_target::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 257483 - Pile of Bones
class spell_rezan_pile_of_bones_slow : public AuraScript
{
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude) const
{
isPeriodic = true;
amplitude = GetDuration();
}
void OnUpdate(AuraEffect* /*aurEff*/)
{
if (!ModStackAmount(-1))
RefreshDuration();
}
void Register() override
{
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_rezan_pile_of_bones_slow::CalcPeriodic, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED);
OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_rezan_pile_of_bones_slow::OnUpdate, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED);
}
};
// 255371 - Terrifying Visage
class spell_rezan_terrifying_visage : public SpellScript
{
void FilterTargets(std::list& targets) const
{
targets.remove_if([this](WorldObject* target) -> bool
{
return !GetCaster()->IsWithinLOSInMap(target);
});
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rezan_terrifying_visage::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
// 256608 - Pile of Bones
struct at_rezan_pile_of_bones_spawn_raptor : AreaTriggerAI
{
at_rezan_pile_of_bones_spawn_raptor(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
void OnUnitEnter(Unit* unit) override
{
InstanceScript* instance = at->GetInstanceScript();
if (!instance)
return;
Creature* rezan = instance->GetCreature(DATA_REZAN);
if (!rezan || !rezan->IsInCombat())
return;
if (unit == rezan && !rezan->GetMap()->IsHeroicOrHigher())
return;
if (!unit->IsPlayer() && unit != rezan)
return;
rezan->CastSpell(at->GetPosition(), SPELL_PILE_OF_BONES_TRIGGER_SPAWN, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
rezan->AI()->Talk(SAY_REANIMATED_RAPTOR_WARNING);
rezan->AI()->Talk(SAY_REANIMATED_RAPTOR_SUMMONER, unit);
at->Remove();
}
};
// 256606 - Pile of Bones
struct at_rezan_pile_of_bones_slow : AreaTriggerAI
{
at_rezan_pile_of_bones_slow(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
void OnUnitEnter(Unit* unit) override
{
InstanceScript* instance = at->GetInstanceScript();
if (!instance)
return;
Creature* rezan = instance->GetCreature(DATA_REZAN);
if (!rezan || !rezan->IsInCombat())
return;
if (!unit->IsPlayer())
return;
if (unit->GetMap()->IsHeroicOrHigher())
{
CastSpellExtraArgs args(TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
args.AddSpellMod(SPELLVALUE_AURA_STACK, 3);
unit->CastSpell(unit, SPELL_PILE_OF_BONES_SLOW, args);
}
else
unit->CastSpell(unit, SPELL_PILE_OF_BONES_SLOW, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
at->Remove();
}
};
void AddSC_boss_rezan()
{
RegisterAtalDazarCreatureAI(boss_rezan);
RegisterSpellScript(spell_rezan_tail_selector);
RegisterSpellScript(spell_rezan_devour);
RegisterSpellScript(spell_rezan_pursuit);
RegisterSpellScript(spell_rezan_boss_emote_at_target);
RegisterSpellScript(spell_rezan_terrifying_visage);
RegisterSpellScript(spell_rezan_pile_of_bones_slow);
RegisterAreaTriggerAI(at_rezan_pile_of_bones_spawn_raptor);
RegisterAreaTriggerAI(at_rezan_pile_of_bones_slow);
}