/*
* 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 "ScriptMgr.h"
#include "InstanceScript.h"
#include "SpellScript.h"
#include "SpellInfo.h"
#include "Creature.h"
#include "firelands.h"
#include "GridNotifiers.h"
#include "Vehicle.h"
#include "MotionMaster.h"
enum Spells
{
// Baleroc Trash
SPELL_FLAME_TORRENT = 100795,
SPELL_FIERY_TORMENT = 100797,
SPELL_FIERY_TORMENT_DAMAGE = 100802,
SPELL_EARTHQUAKE = 100724,
SPELL_MAGMA_CONDUIT = 100728,
SPELL_ERUPTION = 100755,
SPELL_SUMMON_MAGMAKIN = 100746,
// Legendary questline
SPELL_SMOULDERING_QUEST_CHECK_A = 101089, // Alliance - Unverified
SPELL_SMOULDERING_QUEST_CHECK_H = 101092 // Horde - Unverified
};
bool DelayedAttackStartEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
_owner->AI()->DoZoneInCombat(_owner);
return true;
}
bool DelayedSpellCastEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
_owner->CastSpell(_target, _spellId, _triggered);
return true;
}
void firelands_bossAI::JustEngagedWith(Unit* target)
{
BossAI::JustEngagedWith(target);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
}
void firelands_bossAI::JustDied(Unit* killer)
{
BossAI::JustDied(killer);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
me->m_Events.AddEventAtOffset(new DelayedSpellCastEvent(me, static_cast(nullptr), SPELL_SMOULDERING_1, false), 2s);
me->m_Events.AddEventAtOffset(new DelayedSpellCastEvent(me, static_cast(nullptr), SPELL_SMOULDERING_2, false), 2s);
}
void firelands_bossAI::EnterEvadeMode(EvadeReason why)
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
// Copy paste ScriptedAI::EnterEvadeMode functionality to exclude Reset function call
if (!_EnterEvadeMode(why))
return;
if (!me->GetVehicle()) // otherwise me will be in evade mode forever
{
if (Unit* owner = me->GetCharmerOrOwner())
{
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), {}, MOTION_SLOT_ACTIVE);
}
else
{
// Required to prevent attacking creatures that are evading and cause them to reenter combat
// Does not apply to MoveFollow
me->AddUnitState(UNIT_STATE_EVADE);
me->GetMotionMaster()->MoveTargetedHome();
}
}
// Copy paste reason
//Reset();
if (me->IsVehicle()) // use the same sequence of addtoworld, aireset may remove all summons!
me->GetVehicleKit()->Reset(true);
_DespawnAtEvade();
}
// http://www.wowhead.com/npc=54161/flame-archon
struct npc_firelands_flame_archon : public ScriptedAI
{
npc_firelands_flame_archon(Creature* creature) : ScriptedAI(creature)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void JustEngagedWith(Unit* /*attacker*/) override
{
scheduler.Schedule(Seconds(10), Seconds(12), [this](TaskContext context)
{
DoCastAOE(SPELL_FLAME_TORRENT);
context.Repeat(Seconds(15), Seconds(17));
});
scheduler.Schedule(Seconds(25), [this](TaskContext context)
{
DoCastAOE(SPELL_FIERY_TORMENT);
context.Repeat(Seconds(45));
});
}
void JustDied(Unit* killer) override
{
scheduler.CancelAll();
ScriptedAI::JustDied(killer);
}
void EnterEvadeMode(EvadeReason why) override
{
scheduler.CancelAll();
ScriptedAI::EnterEvadeMode(why);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
}
private:
TaskScheduler scheduler;
};
// http://www.wowhead.com/npc=54143/molten-flamefather
struct npc_firelands_molten_flamefather : public ScriptedAI
{
npc_firelands_molten_flamefather(Creature* creature) : ScriptedAI(creature)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() != NPC_MAGMA_CONDUIT)
return;
summon->CastSpell(summon, SPELL_SUMMON_MAGMAKIN);
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
if (summon->GetEntry() != NPC_MAGMA_CONDUIT)
return;
summon->DespawnOrUnsummon();
}
void JustEngagedWith(Unit* /*attacker*/) override
{
scheduler.Schedule(Seconds(5), [this](TaskContext context)
{
DoCastAOE(SPELL_MAGMA_CONDUIT);
if (Is25ManRaid())
DoCastAOE(SPELL_MAGMA_CONDUIT);
context.Repeat(Seconds(25));
});
scheduler.Schedule(Milliseconds(12800), [this](TaskContext context)
{
DoCastAOE(SPELL_EARTHQUAKE);
context.Repeat(Milliseconds(32500));
});
}
void JustDied(Unit* killer) override
{
scheduler.CancelAll();
ScriptedAI::JustDied(killer);
}
void EnterEvadeMode(EvadeReason why) override
{
scheduler.CancelAll();
ScriptedAI::EnterEvadeMode(why);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
}
private:
TaskScheduler scheduler;
};
// http://www.wowhead.com/npc=54144/magmakin
struct npc_firelands_magmakin : public ScriptedAI
{
npc_firelands_magmakin(Creature* creature) : ScriptedAI(creature)
{
me->SetCanMelee(false); // DoSpellAttackIfReady
}
void IsSummonedBy(WorldObject* /*summoner*/) override
{
//Not actually sniffed behavior
Unit* target = me->SelectNearestTarget(50.0f, true);
if (!target)
return;
AddThreat(target, 50000000.0f);
// TODO: Fixate mechanic
}
void UpdateAI(uint32 /*diff*/) override
{
if (!UpdateVictim())
return;
DoSpellAttackIfReady(SPELL_ERUPTION);
}
};
// http://www.wowhead.com/spell=100799/fiery-torment
class spell_firelands_fiery_torment : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_FIERY_TORMENT_DAMAGE });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_FIERY_TORMENT_DAMAGE, true);
}
void FilterTargets(std::list& targets)
{
if (targets.empty())
return;
targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), true));
targets.resize(1);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_firelands_fiery_torment::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_firelands_fiery_torment::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
// http://www.wowhead.com/spell=101089/smouldering
// http://www.wowhead.com/spell=101092/smouldering
class spell_firelands_smouldering : public SpellScript
{
void CheckQuestStatus(std::list& targets)
{
uint32 questId = 0;
switch (GetSpellInfo()->Id)
{
case SPELL_SMOULDERING_QUEST_CHECK_A:
questId = QUEST_HEART_OF_FLAME_A;
break;
case SPELL_SMOULDERING_QUEST_CHECK_H:
questId = QUEST_HEART_OF_FLAME_H;
break;
default:
break;
}
bool raidHasQuest = targets.end() != std::find_if(targets.begin(), targets.end(), [questId](WorldObject* worldObject)
{
if (Player* player = worldObject->ToPlayer())
if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE)
return true;
return false;
});
targets.clear();
if (raidHasQuest)
targets.push_back(GetCaster());
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_firelands_smouldering::CheckQuestStatus, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
}
};
// http://www.wowhead.com/spell=101093/smouldering
class spell_firelands_smouldering_aura : public SpellScript
{
void SetTarget(WorldObject*& target)
{
target = GetCaster();
}
void Register() override
{
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_firelands_smouldering_aura::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
}
};
void AddSC_firelands()
{
RegisterFirelandsAI(npc_firelands_flame_archon);
RegisterFirelandsAI(npc_firelands_molten_flamefather);
RegisterFirelandsAI(npc_firelands_magmakin);
RegisterSpellScript(spell_firelands_fiery_torment);
RegisterSpellScript(spell_firelands_smouldering);
RegisterSpellScript(spell_firelands_smouldering_aura);
}