/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your 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 "CreatureScript.h"
#include "PassiveAI.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "gruuls_lair.h"
#include "SpellAuraEffects.h"
enum Yells
{
SAY_AGGRO = 0,
SAY_SLAM = 1,
SAY_SHATTER = 2,
SAY_SLAY = 3,
SAY_DEATH = 4,
EMOTE_GROW = 5
};
enum Spells
{
SPELL_GROWTH = 36300,
SPELL_CAVE_IN = 36240,
SPELL_GROUND_SLAM = 33525,
SPELL_REVERBERATION = 36297,
SPELL_HURTFUL_STRIKE = 33813,
SPELL_SHATTER = 33654,
SPELL_LOOK_AROUND = 33965,
// Ground Slam spells
SPELL_SUMMON_TRACTOR_BEAM_CREATOR = 33496,
SPELL_TRACTOR_BEAM_PULL = 33497,
SPELL_SUMMON_TRACTOR_BEAM_1 = 33495,
SPELL_SUMMON_TRACTOR_BEAM_2 = 33514,
SPELL_SUMMON_TRACTOR_BEAM_3 = 33515,
SPELL_SUMMON_TRACTOR_BEAM_4 = 33516,
SPELL_SUMMON_TRACTOR_BEAM_5 = 33517,
SPELL_SUMMON_TRACTOR_BEAM_6 = 33518,
SPELL_SUMMON_TRACTOR_BEAM_7 = 33519,
SPELL_SUMMON_TRACTOR_BEAM_8 = 33520,
SPELL_SHATTER_EFFECT = 33671,
SPELL_STONED = 33652,
};
struct boss_gruul : public BossAI
{
boss_gruul(Creature* creature) : BossAI(creature, DATA_GRUUL) { }
void Reset() override
{
_Reset();
_recentlySpoken = false;
_caveInTimer = 29s;
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
Talk(SAY_AGGRO);
scheduler.Schedule(30300ms, [this](TaskContext context)
{
Talk(EMOTE_GROW);
DoCastSelf(SPELL_GROWTH);
context.Repeat(30300ms);
}).Schedule(_caveInTimer, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_CAVE_IN);
if (_caveInTimer > 4s)
{
_caveInTimer = _caveInTimer - 1500ms;
}
context.Repeat(_caveInTimer);
}).Schedule(39900ms, 55700ms, [this](TaskContext context)
{
DoCastSelf(SPELL_REVERBERATION);
context.Repeat(39900ms, 55700ms);
}).Schedule(5600ms, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, 5.0f, false, false))
{
DoCast(target, SPELL_HURTFUL_STRIKE);
}
else
{
DoCastVictim(SPELL_HURTFUL_STRIKE);
}
context.Repeat(8400ms);
}).Schedule(35s, [this](TaskContext context)
{
Talk(SAY_SLAM);
DoCastSelf(SPELL_GROUND_SLAM);
scheduler.DelayAll(9701ms);
scheduler.Schedule(9700ms, [this](TaskContext)
{
Talk(SAY_SHATTER);
me->RemoveAurasDueToSpell(SPELL_LOOK_AROUND);
DoCastSelf(SPELL_SHATTER);
});
context.Repeat(60s);
});
}
void KilledUnit(Unit* /*who*/) override
{
if (!_recentlySpoken)
{
Talk(SAY_SLAY);
_recentlySpoken = true;
}
scheduler.Schedule(5s, [this](TaskContext)
{
_recentlySpoken = false;
});
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (!me->HasUnitState(UNIT_STATE_ROOT))
{
DoMeleeAttackIfReady();
}
}
private:
std::chrono::milliseconds _caveInTimer;
bool _recentlySpoken;
};
struct npc_invisible_tractor_beam_source : public NullCreatureAI
{
npc_invisible_tractor_beam_source(Creature* creature) : NullCreatureAI(creature) { }
void IsSummonedBy(WorldObject* summoner) override
{
if (Unit* summonerUnit = summoner->ToUnit())
{
DoCast(summonerUnit, SPELL_TRACTOR_BEAM_PULL, true);
}
}
};
class spell_gruul_ground_slam : public SpellScript
{
PrepareSpellScript(spell_gruul_ground_slam);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SUMMON_TRACTOR_BEAM_CREATOR });
}
void ApplyStun()
{
if (Unit* caster = GetCaster())
{
caster->CastSpell(caster, SPELL_LOOK_AROUND, true);
}
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
{
target->CastSpell(target, SPELL_SUMMON_TRACTOR_BEAM_CREATOR, true);
}
}
void Register() override
{
AfterCast += SpellCastFn(spell_gruul_ground_slam::ApplyStun);
OnEffectHitTarget += SpellEffectFn(spell_gruul_ground_slam::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_tractor_beam_creator : public SpellScript
{
PrepareSpellScript(spell_tractor_beam_creator);
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
std::vector tractorBeamSummons = { SPELL_SUMMON_TRACTOR_BEAM_1, SPELL_SUMMON_TRACTOR_BEAM_2, SPELL_SUMMON_TRACTOR_BEAM_3, SPELL_SUMMON_TRACTOR_BEAM_4,
SPELL_SUMMON_TRACTOR_BEAM_5, SPELL_SUMMON_TRACTOR_BEAM_6, SPELL_SUMMON_TRACTOR_BEAM_7, SPELL_SUMMON_TRACTOR_BEAM_8 };
uint32 randomTractorSpellID = Acore::Containers::SelectRandomContainerElement(tractorBeamSummons);
caster->CastSpell(caster, randomTractorSpellID, true);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_tractor_beam_creator::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_gruul_ground_slam_trigger : public AuraScript
{
PrepareAuraScript(spell_gruul_ground_slam_trigger);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_STONED });
}
void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
if (GetUnitOwner()->GetAuraCount(GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell) == 5)
{
GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_STONED, true);
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_gruul_ground_slam_trigger::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_gruul_shatter : public SpellScript
{
PrepareSpellScript(spell_gruul_shatter);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SHATTER_EFFECT });
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
{
target->RemoveAurasDueToSpell(SPELL_STONED);
if (target->IsPlayer())
{
target->CastSpell((Unit*)nullptr, SPELL_SHATTER_EFFECT, true);
}
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_gruul_shatter::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_gruul_shatter_effect : public SpellScript
{
PrepareSpellScript(spell_gruul_shatter_effect);
void CalculateDamage()
{
if (!GetHitUnit())
{
return;
}
float radius = GetSpellInfo()->Effects[EFFECT_0].CalcRadius(GetCaster());
if (!radius)
{
return;
}
float distance = GetCaster()->GetDistance2d(GetHitUnit());
if (distance > 1.0f)
{
SetHitDamage(int32(GetHitDamage() * ((radius - distance) / radius)));
}
}
void Register() override
{
OnHit += SpellHitFn(spell_gruul_shatter_effect::CalculateDamage);
}
};
void AddSC_boss_gruul()
{
RegisterGruulsLairAI(boss_gruul);
RegisterGruulsLairAI(npc_invisible_tractor_beam_source);
RegisterSpellScript(spell_gruul_ground_slam);
RegisterSpellScript(spell_tractor_beam_creator);
RegisterSpellScript(spell_gruul_ground_slam_trigger);
RegisterSpellScript(spell_gruul_shatter);
RegisterSpellScript(spell_gruul_shatter_effect);
}