/*
* 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 .
*/
/* ScriptData
SDName: Netherstorm
SD%Complete: 80
SDComment: Quest support: 10337, 10652 (special flight paths), 10198, 10191
SDCategory: Netherstorm
EndScriptData */
/* ContentData
npc_commander_dawnforge
EndContentData */
#include "ScriptMgr.h"
#include "Containers.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
/*######
## npc_commander_dawnforge
######*/
// The Speech of Dawnforge, Ardonis & Pathaleon
enum CommanderDawnforgeData
{
SAY_COMMANDER_DAWNFORGE_1 = 0,
SAY_COMMANDER_DAWNFORGE_2 = 1,
SAY_COMMANDER_DAWNFORGE_3 = 2,
SAY_COMMANDER_DAWNFORGE_4 = 3,
SAY_COMMANDER_DAWNFORGE_5 = 4,
SAY_ARCANIST_ARDONIS_1 = 0,
SAY_ARCANIST_ARDONIS_2 = 1,
SAY_PATHALEON_CULATOR_IMAGE_1 = 0,
SAY_PATHALEON_CULATOR_IMAGE_2 = 1,
SAY_PATHALEON_CULATOR_IMAGE_2_1 = 2,
SAY_PATHALEON_CULATOR_IMAGE_2_2 = 3,
QUEST_INFO_GATHERING = 10198,
SPELL_SUNFURY_DISGUISE = 34603,
};
// Entries of Arcanist Ardonis, Commander Dawnforge, Pathaleon the Curators Image
const uint32 CreatureEntry[3] =
{
19830, // Ardonis
19831, // Dawnforge
21504 // Pathaleon
};
class npc_commander_dawnforge : public CreatureScript
{
public:
npc_commander_dawnforge() : CreatureScript("npc_commander_dawnforge") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_commander_dawnforgeAI(creature);
}
struct npc_commander_dawnforgeAI : public ScriptedAI
{
npc_commander_dawnforgeAI(Creature* creature) : ScriptedAI(creature)
{
Initialize();
}
void Initialize()
{
PlayerGUID.Clear();
ardonisGUID.Clear();
pathaleonGUID.Clear();
Phase = 1;
PhaseSubphase = 0;
Phase_Timer = 4000;
isEvent = false;
}
ObjectGuid PlayerGUID;
ObjectGuid ardonisGUID;
ObjectGuid pathaleonGUID;
uint32 Phase;
uint32 PhaseSubphase;
uint32 Phase_Timer;
bool isEvent;
void Reset() override
{
Initialize();
}
void JustEngagedWith(Unit* /*who*/) override { }
void JustSummoned(Creature* summoned) override
{
pathaleonGUID = summoned->GetGUID();
}
// Emote Ardonis and Pathaleon
void Turn_to_Pathaleons_Image()
{
Creature* ardonis = ObjectAccessor::GetCreature(*me, ardonisGUID);
Creature* pathaleon = ObjectAccessor::GetCreature(*me, pathaleonGUID);
if (!ardonis || !pathaleon)
return;
// Turn Dawnforge
me->SetFacingToObject(pathaleon);
// Turn Ardonis
ardonis->SetFacingToObject(pathaleon);
//Set them to kneel
me->SetStandState(UNIT_STAND_STATE_KNEEL);
ardonis->SetStandState(UNIT_STAND_STATE_KNEEL);
}
//Set them back to each other
void Turn_to_eachother()
{
if (Unit* ardonis = ObjectAccessor::GetUnit(*me, ardonisGUID))
{
// Turn Dawnforge
me->SetFacingToObject(ardonis);
// Turn Ardonis
ardonis->SetFacingToObject(me);
//Set state
me->SetStandState(UNIT_STAND_STATE_STAND);
ardonis->SetStandState(UNIT_STAND_STATE_STAND);
}
}
bool CanStartEvent(Player* player)
{
if (!isEvent)
{
Creature* ardonis = me->FindNearestCreature(CreatureEntry[0], 10.0f);
if (!ardonis)
return false;
ardonisGUID = ardonis->GetGUID();
PlayerGUID = player->GetGUID();
isEvent = true;
Turn_to_eachother();
return true;
}
TC_LOG_DEBUG("scripts", "npc_commander_dawnforge event already in progress, need to wait.");
return false;
}
void UpdateAI(uint32 diff) override
{
//Is event even running?
if (!isEvent)
return;
//Phase timing
if (Phase_Timer >= diff)
{
Phase_Timer -= diff;
return;
}
Creature* ardonis = ObjectAccessor::GetCreature(*me, ardonisGUID);
Creature* pathaleon = ObjectAccessor::GetCreature(*me, pathaleonGUID);
Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);
if (!ardonis || !player)
{
Reset();
return;
}
if (Phase > 4 && !pathaleon)
{
Reset();
return;
}
//Phase 1 Dawnforge say
switch (Phase)
{
case 1:
Talk(SAY_COMMANDER_DAWNFORGE_1);
++Phase;
Phase_Timer = 16000;
break;
//Phase 2 Ardonis say
case 2:
ardonis->AI()->Talk(SAY_ARCANIST_ARDONIS_1);
++Phase;
Phase_Timer = 16000;
break;
//Phase 3 Dawnforge say
case 3:
Talk(SAY_COMMANDER_DAWNFORGE_2);
++Phase;
Phase_Timer = 16000;
break;
//Phase 4 Pathaleon spawns up to phase 9
case 4:
//spawn pathaleon's image
me->SummonCreature(CreatureEntry[2], 2325.851563f, 2799.534668f, 133.084229f, 6.038996f, TEMPSUMMON_TIMED_DESPAWN, 90s);
++Phase;
Phase_Timer = 500;
break;
//Phase 5 Pathaleon say
case 5:
pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_1);
++Phase;
Phase_Timer = 6000;
break;
//Phase 6
case 6:
switch (PhaseSubphase)
{
//Subphase 1: Turn Dawnforge and Ardonis
case 0:
Turn_to_Pathaleons_Image();
++PhaseSubphase;
Phase_Timer = 8000;
break;
//Subphase 2 Dawnforge say
case 1:
Talk(SAY_COMMANDER_DAWNFORGE_3);
PhaseSubphase = 0;
++Phase;
Phase_Timer = 8000;
break;
}
break;
//Phase 7 Pathaleons say 3 Sentence, every sentence need a subphase
case 7:
switch (PhaseSubphase)
{
//Subphase 1
case 0:
pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2);
++PhaseSubphase;
Phase_Timer = 12000;
break;
//Subphase 2
case 1:
pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2_1);
++PhaseSubphase;
Phase_Timer = 16000;
break;
//Subphase 3
case 2:
pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2_2);
PhaseSubphase = 0;
++Phase;
Phase_Timer = 10000;
break;
}
break;
//Phase 8 Dawnforge & Ardonis say
case 8:
Talk(SAY_COMMANDER_DAWNFORGE_4);
ardonis->AI()->Talk(SAY_ARCANIST_ARDONIS_2);
++Phase;
Phase_Timer = 4000;
break;
//Phase 9 Pathaleons Despawn, Reset Dawnforge & Ardonis angle
case 9:
Turn_to_eachother();
//hide pathaleon, unit will despawn shortly
pathaleon->SetVisible(false);
PhaseSubphase = 0;
++Phase;
Phase_Timer = 3000;
break;
//Phase 10 Dawnforge say
case 10:
Talk(SAY_COMMANDER_DAWNFORGE_5);
player->AreaExploredOrEventHappens(QUEST_INFO_GATHERING);
Reset();
break;
}
}
};
};
class at_commander_dawnforge : public AreaTriggerScript
{
public:
at_commander_dawnforge() : AreaTriggerScript("at_commander_dawnforge") { }
bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
{
//if player lost aura or not have at all, we should not try start event.
if (!player->HasAura(SPELL_SUNFURY_DISGUISE))
return false;
if (player->IsAlive() && player->GetQuestStatus(QUEST_INFO_GATHERING) == QUEST_STATUS_INCOMPLETE)
{
Creature* Dawnforge = player->FindNearestCreature(CreatureEntry[1], 30.0f);
if (!Dawnforge)
return false;
if (ENSURE_AI(npc_commander_dawnforge::npc_commander_dawnforgeAI, Dawnforge->AI())->CanStartEvent(player))
return true;
}
return false;
}
};
/*######
## npc_phase_hunter
######*/
enum PhaseHunterData
{
QUEST_RECHARGING_THE_BATTERIES = 10190,
NPC_PHASE_HUNTER_ENTRY = 18879,
NPC_DRAINED_PHASE_HUNTER_ENTRY = 19595,
EMOTE_WEAK = 0,
// Spells
SPELL_RECHARGING_BATTERY = 34219,
SPELL_PHASE_SLIP = 36574,
SPELL_MANA_BURN = 13321,
SPELL_MATERIALIZE = 34804,
SPELL_DE_MATERIALIZE = 34814,
};
class npc_phase_hunter : public CreatureScript
{
public:
npc_phase_hunter() : CreatureScript("npc_phase_hunter") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_phase_hunterAI(creature);
}
struct npc_phase_hunterAI : public ScriptedAI
{
npc_phase_hunterAI(Creature* creature) : ScriptedAI(creature)
{
Weak = false;
Materialize = false;
Drained = false;
WeakPercent = 25;
ManaBurnTimer = 5000;
}
bool Weak;
bool Materialize;
bool Drained;
uint8 WeakPercent;
ObjectGuid PlayerGUID;
uint32 ManaBurnTimer;
void Reset() override
{
Weak = false;
Materialize = false;
Drained = false;
WeakPercent = 25 + (rand32() % 16); // 25-40
PlayerGUID.Clear();
ManaBurnTimer = 5000 + (rand32() % 3 * 1000); // 5-8 sec cd
if (me->GetEntry() == NPC_DRAINED_PHASE_HUNTER_ENTRY)
me->UpdateEntry(NPC_PHASE_HUNTER_ENTRY);
}
void JustEngagedWith(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
PlayerGUID = who->GetGUID();
}
void UpdateAI(uint32 diff) override
{
if (!Materialize)
{
DoCast(me, SPELL_MATERIALIZE);
Materialize = true;
}
if (me->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED) || me->HasUnitState(UNIT_STATE_ROOT)) // if the mob is rooted/slowed by spells eg.: Entangling Roots, Frost Nova, Hamstring, Crippling Poison, etc. => remove it
DoCast(me, SPELL_PHASE_SLIP);
if (!UpdateVictim())
return;
// some code to cast spell Mana Burn on random target which has mana
if (ManaBurnTimer <= diff)
{
std::list UnitsWithMana;
for (auto* ref : me->GetThreatManager().GetUnsortedThreatList())
if (ref->GetVictim()->GetPower(POWER_MANA))
UnitsWithMana.push_back(ref->GetVictim());
if (!UnitsWithMana.empty())
{
DoCast(Trinity::Containers::SelectRandomContainerElement(UnitsWithMana), SPELL_MANA_BURN);
ManaBurnTimer = urand(8000, 18000); // 8-18 sec cd
}
else
ManaBurnTimer = 3500;
} else ManaBurnTimer -= diff;
if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) // start: support for quest 10190
{
if (!Weak && HealthBelowPct(WeakPercent)
&& player->GetQuestStatus(QUEST_RECHARGING_THE_BATTERIES) == QUEST_STATUS_INCOMPLETE)
{
Talk(EMOTE_WEAK);
Weak = true;
}
if (Weak && !Drained && me->HasAura(SPELL_RECHARGING_BATTERY))
{
Drained = true;
int32 uHpPct = int32(me->GetHealthPct());
me->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY);
me->SetHealth(me->CountPctFromMaxHealth(uHpPct));
me->LowerPlayerDamageReq(me->GetMaxHealth() - me->GetHealth());
me->SetInCombatWith(player);
}
} // end: support for quest 10190
}
};
};
/*######
## Quest 10857: Teleport This!
######*/
enum DetonateTeleporter
{
SPELL_TELEPORTER_KILL_CREDIT_1 = 38982, // 22348
SPELL_TELEPORTER_KILL_CREDIT_2 = 38983, // 22351
SPELL_TELEPORTER_KILL_CREDIT_3 = 38984, // 22350
NPC_WESTERN_TELEPORTER_CREDIT = 22348,
NPC_EASTERN_TELEPORTER_CREDIT = 22351,
NPC_CENTRAL_TELEPORTER_CREDIT = 22350
};
// 38920 - Detonate Teleporter
class spell_detonate_teleporter : public SpellScript
{
bool Load() override
{
return GetCaster()->GetTypeId() == TYPEID_UNIT;
}
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_TELEPORTER_KILL_CREDIT_1,
SPELL_TELEPORTER_KILL_CREDIT_2,
SPELL_TELEPORTER_KILL_CREDIT_3
});
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Creature* creature = GetHitCreature())
{
if (Unit* charmer = GetCaster()->GetCharmerOrOwner())
{
if (Player* player = charmer->ToPlayer())
{
uint32 spellId = 0;
switch (creature->GetEntry())
{
case NPC_WESTERN_TELEPORTER_CREDIT:
spellId = SPELL_TELEPORTER_KILL_CREDIT_1;
break;
case NPC_EASTERN_TELEPORTER_CREDIT:
spellId = SPELL_TELEPORTER_KILL_CREDIT_2;
break;
case NPC_CENTRAL_TELEPORTER_CREDIT:
spellId = SPELL_TELEPORTER_KILL_CREDIT_3;
break;
default:
return;
}
player->CastSpell(player, spellId);
}
}
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_detonate_teleporter::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_netherstorm()
{
new npc_commander_dawnforge();
new at_commander_dawnforge();
new npc_phase_hunter();
RegisterSpellScript(spell_detonate_teleporter);
}