1067 lines
33 KiB
C++
1067 lines
33 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 Affero General Public License as published by the
|
|
* Free Software Foundation; either version 3 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 Affero 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 "CombatAI.h"
|
|
#include "Player.h"
|
|
#include "ScriptedCreature.h"
|
|
#include "ScriptedEscortAI.h"
|
|
#include "ScriptedGossip.h"
|
|
#include "ScriptMgr.h"
|
|
#include "SpellAuraEffects.h"
|
|
#include "SpellScript.h"
|
|
#include "Vehicle.h"
|
|
#include "WaypointMgr.h"
|
|
#include "WorldSession.h"
|
|
|
|
// Ours
|
|
enum qSniffing
|
|
{
|
|
SPELL_SUMMON_PURSUERS_PERIODIC = 54993,
|
|
SPELL_SNIFFING_CREDIT = 55477,
|
|
};
|
|
|
|
class npc_frosthound : public CreatureScript
|
|
{
|
|
public:
|
|
npc_frosthound() : CreatureScript("npc_frosthound") { }
|
|
|
|
struct npc_frosthoundAI : public npc_escortAI
|
|
{
|
|
npc_frosthoundAI(Creature* creature) : npc_escortAI(creature) {}
|
|
|
|
void AttackStart(Unit* /*who*/) override {}
|
|
void EnterCombat(Unit* /*who*/) override {}
|
|
void EnterEvadeMode() override {}
|
|
|
|
void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
|
|
{
|
|
if (who->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
if (apply)
|
|
{
|
|
me->setFaction(who->getFaction());
|
|
me->CastSpell(me, SPELL_SUMMON_PURSUERS_PERIODIC, true);
|
|
Start(false, true, who->GetGUID());
|
|
}
|
|
}
|
|
}
|
|
|
|
void JustDied(Unit* /*killer*/) override
|
|
{
|
|
}
|
|
|
|
void OnCharmed(bool /*apply*/) override
|
|
{
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
npc_escortAI::UpdateAI(diff);
|
|
|
|
if (!UpdateVictim())
|
|
return;
|
|
}
|
|
|
|
void WaypointReached(uint32 waypointId) override
|
|
{
|
|
Player* player = GetPlayerForEscort();
|
|
if (!player)
|
|
return;
|
|
|
|
switch (waypointId)
|
|
{
|
|
case 0:
|
|
me->TextEmote("You've been seen! Use the net and Freezing elixir to keep the dwarves away!", nullptr, true);
|
|
break;
|
|
case 19:
|
|
me->TextEmote("The frosthound has located the thief's hiding place. Confront him!", 0, true);
|
|
if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit())
|
|
summoner->ToPlayer()->KilledMonsterCredit(29677);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JustSummoned(Creature* cr) override
|
|
{
|
|
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);
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return new npc_frosthoundAI(creature);
|
|
}
|
|
};
|
|
|
|
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, const SpellInfo* 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(8000);
|
|
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, 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 EnterCombat(Unit*) override
|
|
{
|
|
events.Reset();
|
|
if (me->GetEntry() == NPC_TIME_LOST_PROTO_DRAKE)
|
|
{
|
|
events.ScheduleEvent(SPELL_TIME_SHIFT, 10000);
|
|
events.ScheduleEvent(SPELL_TIME_LAPSE, 5000);
|
|
}
|
|
else
|
|
{
|
|
events.ScheduleEvent(SPELL_FROST_BREATH, 8000);
|
|
events.ScheduleEvent(SPELL_FROST_CLEAVE, 5000);
|
|
}
|
|
}
|
|
|
|
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.RepeatEvent(18000);
|
|
break;
|
|
case SPELL_TIME_LAPSE:
|
|
me->CastSpell(me->GetVictim(), SPELL_TIME_LAPSE, false);
|
|
events.RepeatEvent(12000);
|
|
break;
|
|
case SPELL_FROST_BREATH:
|
|
me->CastSpell(me->GetVictim(), SPELL_FROST_BREATH, false);
|
|
events.RepeatEvent(12000);
|
|
break;
|
|
case SPELL_FROST_CLEAVE:
|
|
me->CastSpell(me->GetVictim(), SPELL_FROST_CLEAVE, false);
|
|
events.RepeatEvent(8000);
|
|
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() override
|
|
{
|
|
if (switching || me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE))
|
|
return;
|
|
ScriptedAI::EnterEvadeMode();
|
|
}
|
|
|
|
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())
|
|
Unit::Kill(me, me);
|
|
}
|
|
|
|
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, const SpellInfo* 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;
|
|
Movement::PointsArray pathPoints;
|
|
pathPoints.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
|
|
|
WaypointPath const* i_path = sWaypointMgr->GetPath(me->GetWaypointPath());
|
|
for (uint8 i = 0; i < i_path->size(); ++i)
|
|
{
|
|
WaypointData const* node = i_path->at(i);
|
|
pathPoints.push_back(G3D::Vector3(node->x, node->y, node->z));
|
|
}
|
|
|
|
me->GetMotionMaster()->MoveSplinePath(&pathPoints);
|
|
}
|
|
if (setCharm)
|
|
{
|
|
setCharm = false;
|
|
|
|
if (Player* charmer = GetValidPlayer())
|
|
{
|
|
me->setFaction(16);
|
|
charmer->SetClientControl(me, 0, true);
|
|
|
|
me->SetSpeed(MOVE_RUN, 2.0f, true);
|
|
startPath = true;
|
|
}
|
|
else
|
|
{
|
|
me->RemoveAllAuras();
|
|
EnterEvadeMode();
|
|
}
|
|
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();
|
|
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();
|
|
}
|
|
}
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return new npc_wild_wyrmAI(creature);
|
|
}
|
|
};
|
|
|
|
class spell_q13003_thursting_hodirs_spear : public SpellScriptLoader
|
|
{
|
|
public:
|
|
spell_q13003_thursting_hodirs_spear() : SpellScriptLoader("spell_q13003_thursting_hodirs_spear") { }
|
|
|
|
class spell_q13003_thursting_hodirs_spear_AuraScript : public AuraScript
|
|
{
|
|
PrepareAuraScript(spell_q13003_thursting_hodirs_spear_AuraScript);
|
|
|
|
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_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
|
|
OnEffectApply += AuraEffectApplyFn(spell_q13003_thursting_hodirs_spear_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
|
AfterEffectRemove += AuraEffectRemoveFn(spell_q13003_thursting_hodirs_spear_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
|
}
|
|
};
|
|
|
|
AuraScript* GetAuraScript() const override
|
|
{
|
|
return new spell_q13003_thursting_hodirs_spear_AuraScript();
|
|
}
|
|
};
|
|
|
|
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 SpellScriptLoader
|
|
{
|
|
public:
|
|
spell_q13007_iron_colossus() : SpellScriptLoader("spell_q13007_iron_colossus") { }
|
|
|
|
class spell_q13007_iron_colossus_SpellScript : public SpellScript
|
|
{
|
|
PrepareSpellScript(spell_q13007_iron_colossus_SpellScript);
|
|
|
|
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->RemoveFlag(UNIT_FIELD_FLAGS, 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->SetFlag(UNIT_FIELD_FLAGS, 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_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
|
}
|
|
};
|
|
|
|
SpellScript* GetSpellScript() const override
|
|
{
|
|
return new spell_q13007_iron_colossus_SpellScript();
|
|
};
|
|
};
|
|
|
|
// Theirs
|
|
/*######
|
|
## 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, const SpellInfo* 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,
|
|
|
|
AREA_VALLEY_OF_ANCIENT_WINTERS = 4437,
|
|
|
|
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, 5000);
|
|
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, 2000);
|
|
}
|
|
|
|
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);
|
|
|
|
Movement::PointsArray pathPoints;
|
|
pathPoints.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
|
|
|
WaypointPath const* i_path = sWaypointMgr->GetPath(NPC_DRAKE);
|
|
for (uint8 i = 0; i < i_path->size(); ++i)
|
|
{
|
|
WaypointData const* node = i_path->at(i);
|
|
pathPoints.push_back(G3D::Vector3(node->x, node->y, node->z));
|
|
}
|
|
|
|
me->GetMotionMaster()->MoveSplinePath(&pathPoints);
|
|
}
|
|
}
|
|
else
|
|
events.ScheduleEvent(EVENT_CHECK_AREA, 5000);
|
|
break;
|
|
case EVENT_REACHED_HOME:
|
|
if (Vehicle* vehicle = me->GetVehicleKit())
|
|
if (Unit* player = vehicle->GetPassenger(0))
|
|
if (player->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
// for each prisoner on drake, give credit
|
|
for (uint8 i = 1; i < 4; ++i)
|
|
if (Unit* prisoner = me->GetVehicleKit()->GetPassenger(i))
|
|
{
|
|
if (prisoner->GetTypeId() != TYPEID_UNIT)
|
|
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 EnterCombat(Unit* /*who*/) override { }
|
|
void EnterEvadeMode() override { }
|
|
|
|
void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
|
|
{
|
|
if (who->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
if (apply)
|
|
Start(false, true, 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)
|
|
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 : public SpellScriptLoader
|
|
{
|
|
public:
|
|
spell_close_rift() : SpellScriptLoader("spell_close_rift") { }
|
|
|
|
class spell_close_rift_AuraScript : public AuraScript
|
|
{
|
|
PrepareAuraScript(spell_close_rift_AuraScript);
|
|
|
|
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_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
|
|
}
|
|
|
|
private:
|
|
uint8 _counter;
|
|
};
|
|
|
|
AuraScript* GetAuraScript() const override
|
|
{
|
|
return new spell_close_rift_AuraScript();
|
|
}
|
|
};
|
|
|
|
void AddSC_storm_peaks()
|
|
{
|
|
// Ours
|
|
new npc_frosthound();
|
|
new npc_iron_watcher();
|
|
new npc_time_lost_proto_drake();
|
|
new npc_wild_wyrm();
|
|
new spell_q13003_thursting_hodirs_spear();
|
|
new spell_q13007_iron_colossus();
|
|
|
|
// Theirs
|
|
new npc_roxi_ramrocket();
|
|
new npc_brunnhildar_prisoner();
|
|
new npc_freed_protodrake();
|
|
new npc_icefang();
|
|
new npc_hyldsmeet_protodrake();
|
|
new spell_close_rift();
|
|
}
|