/*
* 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 "AreaTriggerAI.h"
#include "CellImpl.h"
#include "Creature.h"
#include "GridNotifiersImpl.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "MoveSpline.h"
#include "ObjectAccessor.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "atal_dazar.h"
enum VolkaalSpells
{
SPELL_SOUL_ANCHOR = 259537,
SPELL_BAD_VOODOO = 250192,
SPELL_RAPID_DECAY = 250241,
SPELL_RAPID_DECAY_TARGET = 250694,
SPELL_RAPID_DECAY_RANDOM = 250697,
SPELL_TOXIC_POOL = 250585,
SPELL_REANIMATE = 259531,
SPELL_TOXIC_LEAP_SELECTOR = 250708,
SPELL_TOXIC_LEAP = 250258,
SPELL_TOXIC_LEAP_DAMAGE = 250259,
SPELL_NOXIOUS_STENCH = 259572,
SPELL_LINGERING_NAUSEA = 250372
};
enum VolkaalEvents
{
EVENT_TOXIC_LEAP = 1,
EVENT_NOXIOUS_STENCH,
};
enum VolkaalActions
{
ACTION_TOTEMS_DIED = 1
};
enum VolkaalSummonGroups
{
SUMMON_GROUP_VOLKAAL_TOTEMS = 0
};
enum VolkaalTexts
{
SAY_AGGRO = 0,
SAY_DECAY = 1,
SAY_DIED = 2,
SAY_SLAY = 3,
SAY_WIPE = 4
};
// 122965 - Vol'kaal
struct boss_volkaal : public BossAI
{
boss_volkaal(Creature* creature) : BossAI(creature, DATA_VOLKAAL), _toxicLeapCount(1), _leaping(false) { }
void JustAppeared() override
{
me->SummonCreatureGroup(SUMMON_GROUP_VOLKAAL_TOTEMS);
}
void Reset() override
{
_Reset();
_toxicLeapCount = 1;
_leaping = false;
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
Talk(SAY_WIPE);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
_EnterEvadeMode();
_DespawnAtEvade();
}
void KilledUnit(Unit* victim) override
{
if (!victim->IsPlayer())
return;
Talk(SAY_SLAY);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
for (ObjectGuid summonGuid : summons)
{
if (Creature * totem = ObjectAccessor::GetCreature(*me, summonGuid))
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, totem, 2);
}
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_TOXIC_LEAP, 2200ms);
events.ScheduleEvent(EVENT_NOXIOUS_STENCH, 5800ms);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
Talk(SAY_DIED);
}
void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Id == SPELL_RAPID_DECAY)
{
Talk(SAY_DECAY);
events.CancelEvent(EVENT_TOXIC_LEAP);
}
}
void MovementInform(uint32 /*type*/, uint32 id) override
{
if (id == EVENT_JUMP)
{
DoCastSelf(SPELL_TOXIC_LEAP_DAMAGE);
_leaping = false;
}
}
void DoAction(int32 action) override
{
if (action == ACTION_TOTEMS_DIED)
{
for (ObjectGuid summonGuid : summons)
{
if (Creature* totem = ObjectAccessor::GetCreature(*me, summonGuid))
{
totem->SetUnkillable(false);
totem->KillSelf();
}
}
}
}
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_TOXIC_LEAP:
{
_leaping = true;
DoCast(SPELL_TOXIC_LEAP_SELECTOR);
_toxicLeapCount++;
if (_toxicLeapCount % 3 == 2)
events.Repeat(8500ms);
else
events.Repeat(6s);
break;
}
case EVENT_NOXIOUS_STENCH:
{
if (!_leaping)
{
DoCast(SPELL_NOXIOUS_STENCH);
events.Repeat(19400ms);
}
else
events.Repeat(100ms);
break;
}
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
}
private:
uint32 _toxicLeapCount;
bool _leaping;
};
// 125977 - Reanimation Totem
struct npc_volkaal_reanimation_totem : public ScriptedAI
{
npc_volkaal_reanimation_totem(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
if (IsHeroicOrHigher())
me->SetUnkillable(true);
}
void JustEngagedWith(Unit* /*who*/) override
{
InstanceScript* instance = me->GetInstanceScript();
if (!instance)
return;
if (Creature* volkaal = instance->GetCreature(DATA_VOLKAAL))
volkaal->AI()->DoZoneInCombat();
}
void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
{
if (me->GetHealth() <= damage)
{
if (IsHeroicOrHigher())
{
DoCastSelf(SPELL_SOUL_ANCHOR);
DoCastSelf(SPELL_REANIMATE);
}
}
}
void JustDied(Unit* /*killer*/) override
{
InstanceScript* instance = me->GetInstanceScript();
if (!instance)
return;
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
};
// 250372 - Lingering Nausea
class spell_volkaal_lingering_nausea : public AuraScript
{
void HandlePeriodic(AuraEffect const* aurEff) const
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
caster->CastSpell(target, aurEff->GetAmount(), CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringAura = aurEff
});
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_volkaal_lingering_nausea::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// 250368 - Noxious Stench
class spell_volkaal_noxious_stench : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo ({ SPELL_LINGERING_NAUSEA });
}
void HandleDummy(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_LINGERING_NAUSEA, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_volkaal_noxious_stench::HandleDummy, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
// 250708 - Toxic Leap
class spell_volkaal_toxic_leap_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_TOXIC_LEAP });
}
void HandleScript(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_TOXIC_LEAP);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_volkaal_toxic_leap_selector::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 250258 - Toxic Leap
class spell_volkaal_toxic_leap : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_TOXIC_LEAP });
}
void HandleHit(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
float dist = GetCaster()->GetExactDist(GetHitDest());
float jumpGravity = 159500.0f / (dist * dist); // constant based on calculating avg of inverse from multiple leaps
GetCaster()->GetMotionMaster()->MoveJumpWithGravity(*GetHitDest(), 50, jumpGravity, EVENT_JUMP);
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_volkaal_toxic_leap::HandleHit, EFFECT_1, SPELL_EFFECT_JUMP_CHARGE);
}
};
// 250229 - Soul Anchor
class spell_volkaal_soul_anchor : public SpellScript
{
void SelectTotem(std::list& targets) const
{
if (targets.empty())
{
InstanceScript* instance = GetCaster()->GetInstanceScript();
if (!instance)
return;
if (Creature* volkaal = instance->GetCreature(DATA_VOLKAAL))
volkaal->AI()->DoAction(ACTION_TOTEMS_DIED);
Unit* caster = GetCaster();
caster->RemoveAurasDueToSpell(SPELL_BAD_VOODOO);
caster->CastSpell(caster, SPELL_RAPID_DECAY, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_volkaal_soul_anchor::SelectTotem, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
}
};
// 259531 - Reanimate
class spell_volkaal_reanimate : public SpellScript
{
void HandleScript(SpellEffIndex /*effIndex*/) const
{
GetCaster()->RemoveAurasDueToSpell(SPELL_SOUL_ANCHOR);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_volkaal_reanimate::HandleScript, EFFECT_0, SPELL_EFFECT_HEAL_PCT);
}
};
// 250241 - Rapid Decay
class spell_volkaal_rapid_decay : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo ({ SPELL_RAPID_DECAY_TARGET, SPELL_RAPID_DECAY_RANDOM });
}
void HandleToxicPool(AuraEffect const* aurEff) const
{
Unit* caster = GetCaster();
if (!caster)
return;
float range = 100.0f;
Player* player = nullptr;
Trinity::AnyUnitInObjectRangeCheck check(caster, range);
Trinity::PlayerSearcher searcher(caster, player, check);
Cell::VisitWorldObjects(caster, searcher, range);
CastSpellExtraArgs args;
args.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR;
args.TriggeringAura = aurEff;
caster->CastSpell(player->GetPosition(), SPELL_RAPID_DECAY_TARGET, args);
// not present in 11.0.7
//caster->CastSpell(caster, SPELL_RAPID_DECAY_RANDOM, args);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_volkaal_rapid_decay::HandleToxicPool, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
}
};
// 250696 - Rapid Decay
// ID - 11243
struct at_volkaal_rapid_decay : AreaTriggerAI
{
at_volkaal_rapid_decay(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
void OnUnitEnter(Unit* unit) override
{
if (!unit->IsPlayer())
return;
unit->CastSpell(unit, SPELL_TOXIC_POOL, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
{
unit->RemoveAurasDueToSpell(SPELL_TOXIC_POOL);
}
};
void AddSC_boss_volkaal()
{
RegisterAtalDazarCreatureAI(boss_volkaal);
RegisterAtalDazarCreatureAI(npc_volkaal_reanimation_totem);
RegisterSpellScript(spell_volkaal_lingering_nausea);
RegisterSpellScript(spell_volkaal_noxious_stench);
RegisterSpellScript(spell_volkaal_toxic_leap_selector);
RegisterSpellScript(spell_volkaal_toxic_leap);
RegisterSpellScript(spell_volkaal_soul_anchor);
RegisterSpellScript(spell_volkaal_reanimate);
RegisterSpellScript(spell_volkaal_rapid_decay);
RegisterAreaTriggerAI(at_volkaal_rapid_decay);
}