EverWrath/src/server/scripts/Northrend/zone_storm_peaks.cpp

1186 lines
37 KiB
C++

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "AreaDefines.h"
#include "CombatAI.h"
#include "CreatureScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptedEscortAI.h"
#include "ScriptedGossip.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "Vehicle.h"
#include "WaypointMgr.h"
enum qSniffingOutThePerpetrator
{
NPC_FROSTHOUND = 29677,
NPC_FROSTBITE = 29903,
SPELL_SUMMON_PURSUERS_PERIODIC = 54993,
SPELL_SNIFFING_CREDIT = 55477,
TALK_EMOTE_FROSTHOUND_SNIFF = 0,
TALK_SEEN = 1,
TALK_CONFRONT = 2,
TALK_EMOTE_TRACKED_COMPLETE = 3,
};
struct npc_frosthound : public npc_escortAI
{
explicit npc_frosthound(Creature* creature) : npc_escortAI(creature), _summons(creature), _completionWaypoint((creature->GetEntry() == NPC_FROSTBITE) ? 19 : 34) { }
void AttackStart(Unit* /*who*/) override {}
void JustEngagedWith(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason /* why */) override {}
void JustDied(Unit* /*killer*/) override { }
void OnCharmed(bool /*apply*/) override { }
void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
{
if (who->IsPlayer())
{
if (apply)
{
me->SetFaction(who->GetFaction());
me->CastSpell(me, SPELL_SUMMON_PURSUERS_PERIODIC, true);
Start(false, who->GetGUID());
Talk(TALK_EMOTE_FROSTHOUND_SNIFF, me);
}
}
}
void UpdateAI(uint32 diff) override
{
npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
}
void WaypointReached(uint32 waypointId) override
{
Player* player = GetPlayerForEscort();
if (!player)
return;
if (waypointId == 0)
Talk(TALK_SEEN, player);
else if (waypointId == _completionWaypoint)
{
Talk(TALK_EMOTE_TRACKED_COMPLETE, me);
Talk(TALK_CONFRONT, player);
if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit())
summoner->ToPlayer()->KilledMonsterCredit(NPC_FROSTHOUND); // same credit for Alliance and Horde
_summons.DespawnAll();
}
}
void JustSummoned(Creature* cr) override
{
_summons.Summon(cr);
cr->ToTempSummon()->SetTempSummonType(TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT);
cr->ToTempSummon()->InitStats(20000);
if (urand(0, 1))
cr->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f);
else if (cr->AI())
cr->AI()->AttackStart(me);
}
void Reset() override
{
_summons.DespawnAll();
}
private:
SummonList _summons;
uint32 _completionWaypoint;
};
enum eIronWatcher
{
SPELL_THUNDERING_STOMP = 60925,
SPELL_STORM_HAMMER = 56448,
SPELL_SHATTERED_EYES = 57290,
SPELL_STORM_HAMMER_DUMMY = 60930,
};
class npc_iron_watcher : public CreatureScript
{
public:
npc_iron_watcher() : CreatureScript("npc_iron_watcher") { }
struct npc_iron_watcherAI : public ScriptedAI
{
npc_iron_watcherAI(Creature* creature) : ScriptedAI(creature) {}
uint32 spellTimer;
uint32 hpTimer;
bool charging;
void Reset() override
{
spellTimer = 0;
hpTimer = 0;
charging = false;
me->SetControlled(false, UNIT_STATE_STUNNED);
}
void MovementInform(uint32 type, uint32 /*pointId*/) override
{
if (type == POINT_MOTION_TYPE)
me->SetControlled(true, UNIT_STATE_STUNNED);
}
void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
{
if (spellInfo->Id == SPELL_STORM_HAMMER)
{
me->CastSpell(caster, SPELL_STORM_HAMMER_DUMMY, true);
if (charging)
{
me->RemoveAllAurasExceptType(SPELL_AURA_MECHANIC_IMMUNITY);
Talk(1);
caster->ToPlayer()->KilledMonsterCredit(me->GetEntry());
me->DespawnOrUnsummon(8s);
me->GetMotionMaster()->MoveJump(8721.94f, -1955, 963, 70.0f, 30.0f);
}
}
}
void UpdateAI(uint32 diff) override
{
if (charging)
return;
if (!UpdateVictim())
return;
spellTimer += diff;
hpTimer += diff;
if (spellTimer >= 10000)
{
me->CastSpell(me, SPELL_THUNDERING_STOMP, false);
spellTimer = 0;
}
if (hpTimer >= 1000)
{
if (me->HealthBelowPct(40))
{
Talk(0);
me->RemoveAllAuras();
me->CastSpell(me, SPELL_SHATTERED_EYES, true);
me->ApplySpellImmune(SPELL_SHATTERED_EYES, IMMUNITY_MECHANIC, MECHANIC_STUN, false);
me->GetMotionMaster()->MoveCharge(8548, -1956, 1467.8f);
charging = true;
}
hpTimer = 0;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_iron_watcherAI(creature);
}
};
enum eTimeLost
{
NPC_TIME_LOST_PROTO_DRAKE = 32491,
NPC_VYRAGOSA = 32630,
SPELL_TIME_SHIFT = 61084,
SPELL_TIME_LAPSE = 51020,
SPELL_FROST_BREATH = 47425,
SPELL_FROST_CLEAVE = 51857,
};
class npc_time_lost_proto_drake : public CreatureScript
{
public:
npc_time_lost_proto_drake() : CreatureScript("npc_time_lost_proto_drake") { }
struct npc_time_lost_proto_drakeAI : public npc_escortAI
{
npc_time_lost_proto_drakeAI(Creature* creature) : npc_escortAI(creature)
{
rollPath = false;
setVisible = false;
me->setActive(true);
me->SetVisible(false);
}
EventMap events;
bool rollPath;
bool setVisible;
void Reset() override
{
npc_escortAI::Reset();
if (me->HasUnitState(UNIT_STATE_EVADE))
return;
me->SetVisible(false); // pussywizard: zeby nie dostawali info o npc w miejscu spawna (kampienie z addonem npc scan)
rollPath = true;
}
void RollPath()
{
me->SetEntry(NPC_TIME_LOST_PROTO_DRAKE);
Start(true, ObjectGuid::Empty, 0, false, true, true);
SetNextWaypoint(urand(0, 250), true);
me->UpdateEntry(roll_chance_i(25) ? NPC_TIME_LOST_PROTO_DRAKE : NPC_VYRAGOSA, 0, false);
}
void WaypointReached(uint32 /*pointId*/) override { }
void JustEngagedWith(Unit*) override
{
events.Reset();
if (me->GetEntry() == NPC_TIME_LOST_PROTO_DRAKE)
{
events.ScheduleEvent(SPELL_TIME_SHIFT, 10s);
events.ScheduleEvent(SPELL_TIME_LAPSE, 5s);
}
else
{
events.ScheduleEvent(SPELL_FROST_BREATH, 8s);
events.ScheduleEvent(SPELL_FROST_CLEAVE, 5s);
}
}
void UpdateEscortAI(uint32 diff) override
{
if (rollPath)
{
RollPath();
rollPath = false;
setVisible = true;
return;
}
if (setVisible)
{
me->SetVisible(true);
setVisible = false;
}
if (!UpdateVictim())
return;
events.Update(diff);
switch (events.ExecuteEvent())
{
case SPELL_TIME_SHIFT:
me->CastSpell(me, SPELL_TIME_SHIFT, false);
events.Repeat(18s);
break;
case SPELL_TIME_LAPSE:
me->CastSpell(me->GetVictim(), SPELL_TIME_LAPSE, false);
events.Repeat(12s);
break;
case SPELL_FROST_BREATH:
me->CastSpell(me->GetVictim(), SPELL_FROST_BREATH, false);
events.Repeat(12s);
break;
case SPELL_FROST_CLEAVE:
me->CastSpell(me->GetVictim(), SPELL_FROST_CLEAVE, false);
events.Repeat(8s);
break;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_time_lost_proto_drakeAI(creature);
}
};
enum eWildWyrm
{
SPELL_FIGHT_WYRM_BASE = 56673,
SPELL_FIGHT_WYRM_NEXT = 60863,
SPELL_SPEAR_OF_HODIR = 56671,
SPELL_DODGE_CLAWS = 56704,
SPELL_WYRM_GRIP = 56689,
SPELL_GRAB_ON = 60533,
SPELL_THRUST_SPEAR = 56690,
SPELL_MIGHTY_SPEAR_THRUST = 60586,
SPELL_FATAL_STRIKE = 60587,
SPELL_PRY_JAWS_OPEN = 56706,
SPELL_JAWS_OF_DEATH = 56692,
};
class npc_wild_wyrm : public CreatureScript
{
public:
npc_wild_wyrm() : CreatureScript("npc_wild_wyrm") { }
struct npc_wild_wyrmAI : public ScriptedAI
{
npc_wild_wyrmAI(Creature* creature) : ScriptedAI(creature) {}
ObjectGuid playerGUID;
uint32 checkTimer;
uint32 announceAttackTimer;
uint32 attackTimer;
bool setCharm;
bool switching;
bool startPath;
void EnterEvadeMode(EvadeReason why) override
{
if (switching || me->HasControlVehicleAura())
return;
ScriptedAI::EnterEvadeMode(why);
}
void Reset() override
{
me->SetRegeneratingHealth(true);
me->SetSpeed(MOVE_RUN, 1.14f, true); // ZOMG!
setCharm = false;
switching = false;
startPath = false;
checkTimer = 0;
playerGUID.Clear();
attackTimer = 0;
announceAttackTimer = 0;
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
}
void PassengerBoarded(Unit*, int8, bool apply) override
{
if (!apply && me->IsAlive() && me->HasAura(SPELL_WYRM_GRIP))
me->RemoveAurasDueToSpell(SPELL_WYRM_GRIP);
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type == POINT_MOTION_TYPE && pointId == 1 && !me->GetCharmerGUID())
{
if (Player* player = GetValidPlayer())
{
checkTimer = 1;
me->SetFullHealth();
player->CastSpell(me, SPELL_FIGHT_WYRM_BASE, true);
me->CastSpell(me, SPELL_WYRM_GRIP, true);
me->SetRegeneratingHealth(false);
}
}
else if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized())
startPath = true;
else if (type == EFFECT_MOTION_TYPE && pointId == me->GetEntry())
me->KillSelf();
}
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (who != me)
{
damage = 0;
if (!GetValidPlayer())
setCharm = true; // will enter evade on next update
}
}
void AttackStart(Unit*) override { }
void MoveInLineOfSight(Unit* /*who*/) override { }
void OnCharmed(bool apply) override
{
if (apply)
setCharm = true;
}
void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
{
if (!playerGUID && spellInfo->Id == SPELL_SPEAR_OF_HODIR)
{
me->GetMotionMaster()->MovePoint(1, caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ() + 12.0f);
playerGUID = caster->GetGUID();
}
else if (spellInfo->Id == SPELL_GRAB_ON)
{
if (Aura* aura = me->GetAura(SPELL_WYRM_GRIP))
aura->ModStackAmount(10);
}
else if (spellInfo->Id == SPELL_THRUST_SPEAR)
{
if (Aura* aura = me->GetAura(SPELL_WYRM_GRIP))
aura->ModStackAmount(-5);
}
else if (spellInfo->Id == SPELL_MIGHTY_SPEAR_THRUST)
{
if (Aura* aura = me->GetAura(SPELL_WYRM_GRIP))
aura->ModStackAmount(-15);
}
else if (spellInfo->Id == SPELL_FATAL_STRIKE)
{
if (roll_chance_i(me->GetAuraCount(SPELL_PRY_JAWS_OPEN) * 10))
{
if (Player* player = GetValidPlayer())
{
player->KilledMonsterCredit(30415);
player->RemoveAurasDueToSpell(SPELL_JAWS_OF_DEATH);
}
me->SetStandState(UNIT_STAND_STATE_DEAD);
me->GetMotionMaster()->MoveFall(me->GetEntry());
}
else
Talk(2);
}
}
Player* GetValidPlayer()
{
Player* charmer = ObjectAccessor::GetPlayer(*me, playerGUID);
if (charmer && charmer->IsAlive() && me->GetDistance(charmer) < 20.0f)
return charmer;
return nullptr;
}
void UpdateAI(uint32 diff) override
{
if (startPath)
{
startPath = false;
me->GetMotionMaster()->MovePath(me->GetWaypointPath(), FORCED_MOVEMENT_NONE, PathSource::WAYPOINT_MGR);
}
if (setCharm)
{
setCharm = false;
if (Player* charmer = GetValidPlayer())
{
me->SetFaction(FACTION_MONSTER_2);
charmer->SetClientControl(me, 0, true);
me->SetSpeed(MOVE_RUN, 2.0f, true);
startPath = true;
}
else
{
me->RemoveAllAuras();
EnterEvadeMode(EVADE_REASON_OTHER);
}
return;
}
if (!checkTimer)
return;
if (checkTimer < 10000)
{
checkTimer += diff;
if (checkTimer >= 2000)
{
checkTimer = 1;
if (me->HealthBelowPct(25))
{
if (Player* player = GetValidPlayer())
{
Talk(3);
switching = true;
me->RemoveAllAuras();
me->CastSpell(me, SPELL_JAWS_OF_DEATH, true);
player->CastSpell(me, SPELL_FIGHT_WYRM_NEXT, true);
checkTimer = 10000;
return;
}
else
{
me->RemoveAllAuras();
EnterEvadeMode(EVADE_REASON_OTHER);
return;
}
}
}
}
else if (checkTimer < 20000)
{
checkTimer += diff;
if (checkTimer >= 13000)
{
switching = false;
checkTimer = 20000;
}
}
else if (checkTimer < 30000)
{
checkTimer += diff;
if (checkTimer >= 22000)
{
checkTimer = 20000;
Player* player = GetValidPlayer();
if (!player)
{
me->RemoveAllAuras();
EnterEvadeMode(EVADE_REASON_OTHER);
}
}
return;
}
announceAttackTimer += diff;
if (announceAttackTimer >= 7000)
{
announceAttackTimer = urand(0, 3000);
Talk(0);
attackTimer = 1;
}
if (attackTimer)
{
attackTimer += diff;
if (attackTimer > 2000)
{
attackTimer = 0;
Player* player = ObjectAccessor::GetPlayer(*me, playerGUID);
if (player && player->HasAura(SPELL_DODGE_CLAWS))
Talk(1);
else if (player)
me->AttackerStateUpdate(player);
else
{
me->RemoveAllAuras();
EnterEvadeMode(EVADE_REASON_OTHER);
}
}
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_wild_wyrmAI(creature);
}
};
class spell_q13003_thursting_hodirs_spear_aura : public AuraScript
{
PrepareAuraScript(spell_q13003_thursting_hodirs_spear_aura);
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
ModStackAmount(60);
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Creature* creature = GetUnitOwner()->ToCreature())
{
if (!creature->IsInEvadeMode())
{
creature->RemoveAllAuras();
creature->AI()->EnterEvadeMode();
}
}
}
void HandlePeriodic(AuraEffect const* /* aurEff */)
{
ModStackAmount(-1);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_q13003_thursting_hodirs_spear_aura::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
OnEffectApply += AuraEffectApplyFn(spell_q13003_thursting_hodirs_spear_aura::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
AfterEffectRemove += AuraEffectRemoveFn(spell_q13003_thursting_hodirs_spear_aura::AfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
enum q13007IronColossus
{
SPELL_JORMUNGAR_SUBMERGE = 56504,
SPELL_JORMUNGAR_EMERGE = 56508,
SPELL_JORMUNGAR_SUBMERGE_VISUAL = 56512,
SPELL_COLOSSUS_GROUND_SLAM = 61673
};
class spell_q13007_iron_colossus : public SpellScript
{
PrepareSpellScript(spell_q13007_iron_colossus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_JORMUNGAR_SUBMERGE_VISUAL, SPELL_COLOSSUS_GROUND_SLAM });
}
void HandleDummy(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
Creature* caster = GetCaster()->ToCreature();
if (!caster)
return;
if (GetSpellInfo()->Id == SPELL_JORMUNGAR_SUBMERGE)
{
caster->CastSpell(caster, SPELL_JORMUNGAR_SUBMERGE_VISUAL, true);
caster->ApplySpellImmune(SPELL_COLOSSUS_GROUND_SLAM, IMMUNITY_ID, SPELL_COLOSSUS_GROUND_SLAM, true);
caster->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
caster->SetControlled(false, UNIT_STATE_ROOT);
for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
caster->m_spells[i] = 0;
caster->m_spells[0] = SPELL_JORMUNGAR_EMERGE;
}
else
{
caster->RemoveAurasDueToSpell(SPELL_JORMUNGAR_SUBMERGE_VISUAL);
caster->ApplySpellImmune(SPELL_COLOSSUS_GROUND_SLAM, IMMUNITY_ID, SPELL_COLOSSUS_GROUND_SLAM, false);
caster->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
caster->SetControlled(true, UNIT_STATE_ROOT);
if (CreatureTemplate const* ct = sObjectMgr->GetCreatureTemplate(caster->GetEntry()))
for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
caster->m_spells[i] = ct->spells[i];
}
if (Player* player = caster->GetCharmerOrOwnerPlayerOrPlayerItself())
player->VehicleSpellInitialize();
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_q13007_iron_colossus::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
/*######
## npc_roxi_ramrocket
######*/
enum RoxiRamrocket
{
SPELL_MECHANO_HOG = 60866,
SPELL_MEKGINEERS_CHOPPER = 60867
};
class npc_roxi_ramrocket : public CreatureScript
{
public:
npc_roxi_ramrocket() : CreatureScript("npc_roxi_ramrocket") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
//Quest Menu
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
//Trainer Menu
if (creature->IsTrainer())
AddGossipItemFor(player, GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN);
//Vendor Menu
if (creature->IsVendor())
if (player->HasSpell(SPELL_MECHANO_HOG) || player->HasSpell(SPELL_MEKGINEERS_CHOPPER))
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
{
case GOSSIP_ACTION_TRAIN:
player->GetSession()->SendTrainerList(creature->GetGUID());
break;
case GOSSIP_ACTION_TRADE:
player->GetSession()->SendListInventory(creature->GetGUID());
break;
}
return true;
}
};
/*######
## npc_brunnhildar_prisoner
######*/
enum BrunnhildarPrisoner
{
SPELL_ICE_PRISON = 54894,
SPELL_ICE_LANCE = 55046,
SPELL_FREE_PRISONER = 55048,
SPELL_RIDE_DRAKE = 55074,
SPELL_SHARD_IMPACT = 55047
};
class npc_brunnhildar_prisoner : public CreatureScript
{
public:
npc_brunnhildar_prisoner() : CreatureScript("npc_brunnhildar_prisoner") { }
struct npc_brunnhildar_prisonerAI : public ScriptedAI
{
npc_brunnhildar_prisonerAI(Creature* creature) : ScriptedAI(creature) { }
bool freed;
void Reset() override
{
freed = false;
me->CastSpell(me, SPELL_ICE_PRISON, true);
}
void JustRespawned() override
{
Reset();
}
void UpdateAI(uint32 /*diff*/) override
{
if (!freed)
return;
if (!me->GetVehicle())
me->DespawnOrUnsummon();
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
if (spell->Id != SPELL_ICE_LANCE)
return;
if (caster->GetVehicleKit()->GetAvailableSeatCount() != 0)
{
me->CastSpell(me, SPELL_FREE_PRISONER, true);
me->CastSpell(caster, SPELL_RIDE_DRAKE, true);
me->CastSpell(me, SPELL_SHARD_IMPACT, true);
freed = true;
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_brunnhildar_prisonerAI(creature);
}
};
/*######
## npc_freed_protodrake
######*/
enum FreedProtoDrake
{
NPC_DRAKE = 29709,
TEXT_EMOTE = 0,
SPELL_KILL_CREDIT_PRISONER = 55144,
SPELL_SUMMON_LIBERATED = 55073,
SPELL_KILL_CREDIT_DRAKE = 55143,
EVENT_CHECK_AREA = 1,
EVENT_REACHED_HOME = 2,
};
class npc_freed_protodrake : public CreatureScript
{
public:
npc_freed_protodrake() : CreatureScript("npc_freed_protodrake") { }
struct npc_freed_protodrakeAI : public VehicleAI
{
npc_freed_protodrakeAI(Creature* creature) : VehicleAI(creature) { }
EventMap events;
void Reset() override
{
events.ScheduleEvent(EVENT_CHECK_AREA, 5s);
me->SetSpeed(MOVE_RUN, 2.0f);
}
void MovementInform(uint32 type, uint32 /*id*/) override
{
if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized())
events.ScheduleEvent(EVENT_REACHED_HOME, 2s);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_CHECK_AREA:
if (me->GetAreaId() == AREA_VALLEY_OF_ANCIENT_WINTERS)
{
if (Vehicle* vehicle = me->GetVehicleKit())
if (Unit* passenger = vehicle->GetPassenger(0))
{
Talk(TEXT_EMOTE, passenger);
me->GetMotionMaster()->MovePath(NPC_DRAKE, FORCED_MOVEMENT_NONE, PathSource::WAYPOINT_MGR);
}
}
else
events.ScheduleEvent(EVENT_CHECK_AREA, 5s);
break;
case EVENT_REACHED_HOME:
if (Vehicle* vehicle = me->GetVehicleKit())
if (Unit* player = vehicle->GetPassenger(0))
if (player->IsPlayer())
{
// for each prisoner on drake, give credit
for (uint8 i = 1; i < 4; ++i)
if (Unit* prisoner = me->GetVehicleKit()->GetPassenger(i))
{
if (!prisoner->IsCreature())
return;
prisoner->CastSpell(player, SPELL_KILL_CREDIT_PRISONER, true);
prisoner->CastSpell(prisoner, SPELL_SUMMON_LIBERATED, true);
prisoner->ExitVehicle();
}
me->CastSpell(me, SPELL_KILL_CREDIT_DRAKE, true);
player->ExitVehicle();
}
break;
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_freed_protodrakeAI(creature);
}
};
class npc_icefang : public CreatureScript
{
public:
npc_icefang() : CreatureScript("npc_icefang") { }
struct npc_icefangAI : public npc_escortAI
{
npc_icefangAI(Creature* creature) : npc_escortAI(creature) { }
void AttackStart(Unit* /*who*/) override { }
void JustEngagedWith(Unit* /*who*/) override { }
void EnterEvadeMode(EvadeReason /*why*/) override { }
void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
{
if (who->IsPlayer())
{
if (apply)
{
me->SetWalk(false);
Start(false, who->GetGUID());
}
}
}
void WaypointReached(uint32 /*waypointId*/) override { }
void JustDied(Unit* /*killer*/) override { }
void OnCharmed(bool /*apply*/) override { }
void UpdateAI(uint32 diff) override
{
npc_escortAI::UpdateAI(diff);
if (!UpdateVictim())
return;
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_icefangAI(creature);
}
};
class npc_hyldsmeet_protodrake : public CreatureScript
{
enum NPCs
{
NPC_HYLDSMEET_DRAKERIDER = 29694
};
public:
npc_hyldsmeet_protodrake() : CreatureScript("npc_hyldsmeet_protodrake") { }
class npc_hyldsmeet_protodrakeAI : public CreatureAI
{
public:
npc_hyldsmeet_protodrakeAI(Creature* creature) : CreatureAI(creature), _accessoryRespawnTimer(0), _vehicleKit(creature->GetVehicleKit()) { }
void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override
{
if (apply)
{
class DelayedTransportPositionOffsets : public BasicEvent
{
public:
DelayedTransportPositionOffsets(Unit* owner) : _owner(owner) { }
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
{
_owner->m_movementInfo.transport.pos.Relocate(-3.5f, 0.f, -0.2f, 0.f);
return true;
}
private:
Unit* _owner;
};
if (who->IsPlayer())
who->m_Events.AddEventAtOffset(new DelayedTransportPositionOffsets(who), 500ms);
return;
}
if (who->GetEntry() == NPC_HYLDSMEET_DRAKERIDER)
_accessoryRespawnTimer = 5 * MINUTE * IN_MILLISECONDS;
}
void UpdateAI(uint32 diff) override
{
//! We need to manually reinstall accessories because the vehicle itself is friendly to players,
//! so EnterEvadeMode is never triggered. The accessory on the other hand is hostile and killable.
if (_accessoryRespawnTimer && _accessoryRespawnTimer <= diff && _vehicleKit)
{
_vehicleKit->InstallAllAccessories(true);
_accessoryRespawnTimer = 0;
}
else
_accessoryRespawnTimer -= diff;
}
private:
uint32 _accessoryRespawnTimer;
Vehicle* _vehicleKit;
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_hyldsmeet_protodrakeAI(creature);
}
};
enum CloseRift
{
SPELL_DESPAWN_RIFT = 61665
};
class spell_close_rift_aura : public AuraScript
{
PrepareAuraScript(spell_close_rift_aura);
bool Load() override
{
_counter = 0;
return true;
}
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_DESPAWN_RIFT });
}
void HandlePeriodic(AuraEffect const* /* aurEff */)
{
if (++_counter == 5)
GetTarget()->CastSpell((Unit*)nullptr, SPELL_DESPAWN_RIFT, true);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_close_rift_aura::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
private:
uint8 _counter;
};
enum CollapsingCave
{
SPELL_COLLAPSING_CAVE = 55486
};
// 55693 - Remove Collapsing Cave Aura
class spell_q12823_remove_collapsing_cave_aura : public SpellScript
{
PrepareSpellScript(spell_q12823_remove_collapsing_cave_aura);
void HandleScriptEffect(SpellEffIndex /* effIndex */)
{
GetHitUnit()->RemoveAurasDueToSpell(SPELL_COLLAPSING_CAVE);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_q12823_remove_collapsing_cave_aura::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
//Generic Fix for Quest WhenAllElseFails ID: 12862
enum WhenAllElseFailsAlliance
{
// Creature
NPC_PROPELLED_DEVICE_1 = 30477,
NPC_PROPELLED_DEVICE_2 = 30487,
// Spell
SPELL_EJECT_PLAYER = 68576,
SPELL_KNOCKBACK_PLAYER = 42895
};
class npc_vehicle_d16_propelled_delivery : public CreatureScript
{
public:
npc_vehicle_d16_propelled_delivery() : CreatureScript("npc_vehicle_d16_propelled_delivery") { }
struct npc_vehicle_d16_propelled_deliveryAI : public VehicleAI
{
npc_vehicle_d16_propelled_deliveryAI(Creature* creature) : VehicleAI(creature) { }
void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override
{
if (apply)
{
me->GetMotionMaster()->MovePath(me->GetEntry() * 100, FORCED_MOVEMENT_NONE, PathSource::WAYPOINT_MGR);
me->SetCanFly(true);
me->SetDisableGravity(true);
me->SetSpeed(MOVE_RUN, 6.0f);
me->SetSpeedRate(MOVE_FLIGHT, 8.0f);
me->setActive(true);
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != ESCORT_MOTION_TYPE)
return;
switch (id)
{
case 12:
if (me->GetEntry() == NPC_PROPELLED_DEVICE_2)
{
if (Vehicle* vehicle = me->GetVehicleKit())
{
if (Unit* player = vehicle->GetPassenger(0))
{
if (player->IsPlayer())
{
player->m_Events.AddEventAtOffset([player]()
{
player->CastSpell(player, SPELL_KNOCKBACK_PLAYER, true);
}, 1s);
}
}
}
DoCastSelf(SPELL_EJECT_PLAYER);
}
break;
case 17:
if (me->GetEntry() == NPC_PROPELLED_DEVICE_1)
{
if (Vehicle* vehicle = me->GetVehicleKit())
{
if (Unit* player = vehicle->GetPassenger(0))
{
if (player->IsPlayer())
{
player->m_Events.AddEventAtOffset([player]()
{
player->CastSpell(player, SPELL_KNOCKBACK_PLAYER, true);
}, 1s);
}
}
}
DoCastSelf(SPELL_EJECT_PLAYER);
}
else
{
me->DespawnOrUnsummon(100ms);
}
break;
case 24:
if (me->GetEntry() == NPC_PROPELLED_DEVICE_1)
{
me->DespawnOrUnsummon(100ms);
}
break;
default:
break;
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_vehicle_d16_propelled_deliveryAI(creature);
}
};
enum StormcrestEagle
{
NPC_STORMCREST_EAGLE = 29854
};
// 56393 - Feed Stormcrest Eagle
class spell_feed_stormcrest_eagle : public SpellScript
{
PrepareSpellScript(spell_feed_stormcrest_eagle);
SpellCastResult CheckCast()
{
if (GetCaster()->FindNearestCreature(NPC_STORMCREST_EAGLE, 15.0f, true))
return SPELL_CAST_OK;
return SPELL_FAILED_BAD_TARGETS;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_feed_stormcrest_eagle::CheckCast);
}
};
void AddSC_storm_peaks()
{
RegisterCreatureAI(npc_frosthound);
new npc_iron_watcher();
new npc_time_lost_proto_drake();
new npc_wild_wyrm();
RegisterSpellScript(spell_q13003_thursting_hodirs_spear_aura);
RegisterSpellScript(spell_q13007_iron_colossus);
new npc_roxi_ramrocket();
new npc_brunnhildar_prisoner();
new npc_freed_protodrake();
new npc_icefang();
new npc_hyldsmeet_protodrake();
RegisterSpellScript(spell_close_rift_aura);
new npc_vehicle_d16_propelled_delivery();
RegisterSpellScript(spell_q12823_remove_collapsing_cave_aura);
RegisterSpellScript(spell_feed_stormcrest_eagle);
}