1769 lines
70 KiB
C#
1769 lines
70 KiB
C#
/*
|
|
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
|
*
|
|
* 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 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 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/>.
|
|
*/
|
|
|
|
using Framework.Constants;
|
|
using Game.AI;
|
|
using Game.Entities;
|
|
using Game.Maps;
|
|
using Game.Scripting;
|
|
using Game.Spells;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.Contracts;
|
|
|
|
namespace Scripts.Northrend.Ulduar
|
|
{
|
|
namespace FlameLeviathan
|
|
{
|
|
struct Spells
|
|
{
|
|
public const uint Pursued = 62374;
|
|
public const uint GatheringSpeed = 62375;
|
|
public const uint BatteringRam = 62376;
|
|
public const uint FlameVents = 62396;
|
|
public const uint MissileBarrage = 62400;
|
|
public const uint SystemsShutdown = 62475;
|
|
public const uint OverloadCircuit = 62399;
|
|
public const uint StartTheEngine = 62472;
|
|
public const uint SearingFlame = 62402;
|
|
public const uint Blaze = 62292;
|
|
public const uint TarPassive = 62288;
|
|
public const uint SmokeTrail = 63575;
|
|
public const uint Electroshock = 62522;
|
|
public const uint Napalm = 63666;
|
|
public const uint InvisAndStealthDetect = 18950; // Passive
|
|
//Tower Additional Spells
|
|
public const uint ThorimSHammer = 62911; // Tower Of Storms
|
|
public const uint MimironSInferno = 62909; // Tower Of Flames
|
|
public const uint HodirSFury = 62533; // Tower Of Frost
|
|
public const uint FreyaSWard = 62906; // Tower Of Nature
|
|
public const uint FreyaSummons = 62947; // Tower Of Nature
|
|
//Tower Ap & Health Spells
|
|
public const uint BuffTowerOfStorms = 65076;
|
|
public const uint BuffTowerOfFlames = 65075;
|
|
public const uint BuffTowerOfFrost = 65077;
|
|
public const uint BuffTowerOfLife = 64482;
|
|
//Additional Spells
|
|
public const uint Lash = 65062;
|
|
public const uint FreyaSWardEffect1 = 62947;
|
|
public const uint FreyaSWardEffect2 = 62907;
|
|
public const uint AutoRepair = 62705;
|
|
public const uint DummyBlue = 63294;
|
|
public const uint DummyGreen = 63295;
|
|
public const uint DummyYellow = 63292;
|
|
public const uint LiquidPyrite = 62494;
|
|
public const uint DustyExplosion = 63360;
|
|
public const uint DustCloudImpact = 54740;
|
|
public const uint StealthDetection = 18950;
|
|
public const uint RideVehicle = 46598;
|
|
}
|
|
|
|
struct CreatureIds
|
|
{
|
|
public const uint Seat = 33114;
|
|
public const uint Mechanolift = 33214;
|
|
public const uint Liquid = 33189;
|
|
public const uint Container = 33218;
|
|
public const uint ThorimBeacon = 33365;
|
|
public const uint MimironBeacon = 33370;
|
|
public const uint HodirBeacon = 33212;
|
|
public const uint FreyaBeacon = 33367;
|
|
public const uint ThorimTargetBeacon = 33364;
|
|
public const uint MimironTargetBeacon = 33369;
|
|
public const uint HodirTargetBeacon = 33108;
|
|
public const uint FreyaTargetBeacon = 33366;
|
|
public const uint Lorekeeper = 33686; // Hard Mode Starter
|
|
public const uint BranzBronzbeard = 33579;
|
|
public const uint Delorah = 33701;
|
|
public const uint UlduarGauntletGenerator = 33571; // Trigger Tied To Towers
|
|
}
|
|
|
|
struct Towers
|
|
{
|
|
public const uint ofStorms = 194377;
|
|
public const uint ofFlames = 194371;
|
|
public const uint ofFrost = 194370;
|
|
public const uint ofLife = 194375;
|
|
}
|
|
|
|
struct Events
|
|
{
|
|
public const int Pursue = 1;
|
|
public const int Missile = 2;
|
|
public const int Vent = 3;
|
|
public const int Speed = 4;
|
|
public const int Summon = 5;
|
|
public const int Shutdown = 6;
|
|
public const int Repair = 7;
|
|
public const int ThorimSHammer = 8; // Tower Of Storms
|
|
public const int MimironSInferno = 9; // Tower Of Flames
|
|
public const int HodirSFury = 10; // Tower Of Frost
|
|
public const int FreyaSWard = 11; // Tower Of Nature
|
|
}
|
|
|
|
struct Seats
|
|
{
|
|
public const int Player = 0;
|
|
public const int Turret = 1;
|
|
public const int Device = 2;
|
|
public const int Cannon = 7;
|
|
}
|
|
|
|
struct Vehicles
|
|
{
|
|
public const uint Siege = 33060;
|
|
public const uint Chopper = 33062;
|
|
public const uint Demolisher = 33109;
|
|
}
|
|
|
|
struct Leviathan
|
|
{
|
|
public const int DataShutout = 29112912; // 2911, 2912 are achievement IDs
|
|
public const int DataOrbitAchievements = 1;
|
|
public const int VehicleSpawns = 5;
|
|
public const int FreyaSpawns = 4;
|
|
|
|
public const int ActionStartHardMode = 5;
|
|
public const int ActionSpawnVehicles = 6;
|
|
// Amount of seats depending on Raid mode
|
|
public const int TwoSeats = 2;
|
|
public const int FourSeats = 4;
|
|
|
|
//Postions
|
|
public static Position Center = new Position(354.8771f, -12.90240f, 409.803650f);
|
|
public static Position InfernoStart = new Position(390.93f, -13.91f, 409.81f);
|
|
|
|
public static Position[] PosSiege =
|
|
{
|
|
new Position(-814.59f, -64.54f, 429.92f, 5.969f),
|
|
new Position(-784.37f, -33.31f, 429.92f, 5.096f),
|
|
new Position(-808.99f, -52.10f, 429.92f, 5.668f),
|
|
new Position(-798.59f, -44.00f, 429.92f, 5.663f),
|
|
new Position(-812.83f, -77.71f, 429.92f, 0.046f),
|
|
};
|
|
|
|
public static Position[] PosChopper =
|
|
{
|
|
new Position(-717.83f, -106.56f, 430.02f, 0.122f),
|
|
new Position(-717.83f, -114.23f, 430.44f, 0.122f),
|
|
new Position(-717.83f, -109.70f, 430.22f, 0.122f),
|
|
new Position(-718.45f, -118.24f, 430.26f, 0.052f),
|
|
new Position(-718.45f, -123.58f, 430.41f, 0.085f),
|
|
};
|
|
|
|
public static Position[] PosDemolisher =
|
|
{
|
|
new Position(-724.12f, -176.64f, 430.03f, 2.543f),
|
|
new Position(-766.70f, -225.03f, 430.50f, 1.710f),
|
|
new Position(-729.54f, -186.26f, 430.12f, 1.902f),
|
|
new Position(-756.01f, -219.23f, 430.50f, 2.369f),
|
|
new Position(-798.01f, -227.24f, 429.84f, 1.446f),
|
|
};
|
|
|
|
public static Position[] FreyaBeacons =
|
|
{
|
|
new Position(377.02f, -119.10f, 409.81f),
|
|
new Position(185.62f, -119.10f, 409.81f),
|
|
new Position(377.02f, 54.78f, 409.81f),
|
|
new Position(185.62f, 54.78f, 409.81f),
|
|
};
|
|
}
|
|
|
|
struct Says
|
|
{
|
|
public const uint Aggro = 0;
|
|
public const uint Slay = 1;
|
|
public const uint Death = 2;
|
|
public const uint Target = 3;
|
|
public const uint Hardmode = 4;
|
|
public const uint TowerNone = 5;
|
|
public const uint TowerFrost = 6;
|
|
public const uint TowerFlame = 7;
|
|
public const uint TowerNature = 8;
|
|
public const uint TowerStorm = 9;
|
|
public const uint PlayerRiding = 10;
|
|
public const uint Overload = 11;
|
|
public const uint EmotePursue = 12;
|
|
public const uint EmoteOverload = 13;
|
|
public const int EmoteRepair = 14;
|
|
}
|
|
|
|
[Script]
|
|
class boss_flame_leviathan : CreatureScript
|
|
{
|
|
public boss_flame_leviathan() : base("boss_flame_leviathan") { }
|
|
|
|
class boss_flame_leviathanAI : BossAI
|
|
{
|
|
public boss_flame_leviathanAI(Creature creature) : base(creature, BossIds.Leviathan)
|
|
{
|
|
vehicle = creature.GetVehicleKit();
|
|
}
|
|
|
|
public override void InitializeAI()
|
|
{
|
|
Contract.Assert(vehicle);
|
|
if (!me.IsDead())
|
|
Reset();
|
|
|
|
ActiveTowersCount = 4;
|
|
Shutdown = 0;
|
|
ActiveTowers = false;
|
|
towerOfStorms = false;
|
|
towerOfLife = false;
|
|
towerOfFlames = false;
|
|
towerOfFrost = false;
|
|
Shutout = true;
|
|
Unbroken = true;
|
|
|
|
DoCast(Spells.InvisAndStealthDetect);
|
|
|
|
me.SetFlag(UnitFields.Flags, UnitFlags.NonAttackable | UnitFlags.NotSelectable | UnitFlags.Stunned);
|
|
me.SetReactState(ReactStates.Passive);
|
|
}
|
|
|
|
public override void Reset()
|
|
{
|
|
_Reset();
|
|
//resets shutdown counter to 0. 2 or 4 depending on raid mode
|
|
Shutdown = 0;
|
|
_pursueTarget.Clear();
|
|
|
|
me.SetReactState(ReactStates.Defensive);
|
|
}
|
|
|
|
public override void EnterCombat(Unit who)
|
|
{
|
|
_EnterCombat();
|
|
me.SetReactState(ReactStates.Passive);
|
|
_events.ScheduleEvent(Events.Pursue, 1);
|
|
_events.ScheduleEvent(Events.Missile, RandomHelper.URand(1500, 4 * Time.InMilliseconds));
|
|
_events.ScheduleEvent(Events.Vent, 20 * Time.InMilliseconds);
|
|
_events.ScheduleEvent(Events.Shutdown, 150 * Time.InMilliseconds);
|
|
_events.ScheduleEvent(Events.Speed, 15 * Time.InMilliseconds);
|
|
_events.ScheduleEvent(Events.Summon, 1 * Time.InMilliseconds);
|
|
ActiveTower(); //void ActiveTower
|
|
}
|
|
|
|
void ActiveTower()
|
|
{
|
|
if (ActiveTowers)
|
|
{
|
|
if (towerOfStorms)
|
|
{
|
|
me.AddAura(Spells.BuffTowerOfStorms, me);
|
|
_events.ScheduleEvent(Events.ThorimSHammer, 35 * Time.InMilliseconds);
|
|
}
|
|
|
|
if (towerOfFlames)
|
|
{
|
|
me.AddAura(Spells.BuffTowerOfFlames, me);
|
|
_events.ScheduleEvent(Events.MimironSInferno, 70 * Time.InMilliseconds);
|
|
}
|
|
|
|
if (towerOfFrost)
|
|
{
|
|
me.AddAura(Spells.BuffTowerOfFrost, me);
|
|
_events.ScheduleEvent(Events.HodirSFury, 105 * Time.InMilliseconds);
|
|
}
|
|
|
|
if (towerOfLife)
|
|
{
|
|
me.AddAura(Spells.BuffTowerOfLife, me);
|
|
_events.ScheduleEvent(Events.FreyaSWard, 140 * Time.InMilliseconds);
|
|
}
|
|
|
|
if (!towerOfLife && !towerOfFrost && !towerOfFlames && !towerOfStorms)
|
|
Talk(Says.TowerNone);
|
|
else
|
|
Talk(Says.Hardmode);
|
|
}
|
|
else
|
|
Talk(Says.Aggro);
|
|
}
|
|
|
|
public override void JustDied(Unit killer)
|
|
{
|
|
_JustDied();
|
|
// Set Field Flags 67108928 = 64 | 67108864 = UNIT_FLAG_UNK_6 | UNIT_FLAG_SKINNABLE
|
|
// Set DynFlags 12
|
|
// Set NPCFlags 0
|
|
Talk(Says.Death);
|
|
}
|
|
|
|
public override void SpellHit(Unit caster, SpellInfo spell)
|
|
{
|
|
if (spell.Id == Spells.StartTheEngine)
|
|
vehicle.InstallAllAccessories(false);
|
|
|
|
if (spell.Id == Spells.Electroshock)
|
|
me.InterruptSpell(CurrentSpellTypes.Channeled);
|
|
|
|
if (spell.Id == Spells.OverloadCircuit)
|
|
++Shutdown;
|
|
}
|
|
|
|
public override uint GetData(uint type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case Leviathan.DataShutout:
|
|
return (uint)(Shutout ? 1 : 0);
|
|
case InstanceAchievementData.DataUnbroken:
|
|
return (uint)(Unbroken ? 1 : 0);
|
|
case Leviathan.DataOrbitAchievements:
|
|
if (ActiveTowers) // Only on HardMode
|
|
return ActiveTowersCount;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public override void SetData(uint id, uint data)
|
|
{
|
|
if (id == InstanceAchievementData.DataUnbroken)
|
|
Unbroken = data != 0 ? true : false;
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
_events.Update(diff);
|
|
|
|
if (Shutdown == RaidMode(Leviathan.TwoSeats, Leviathan.FourSeats))
|
|
{
|
|
Shutdown = 0;
|
|
_events.ScheduleEvent(Events.Shutdown, 4000);
|
|
me.RemoveAurasDueToSpell(Spells.OverloadCircuit);
|
|
me.InterruptNonMeleeSpells(true);
|
|
return;
|
|
}
|
|
|
|
if (me.HasUnitState(UnitState.Casting))
|
|
return;
|
|
_events.ExecuteEvents(eventId =>
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case Events.Pursue:
|
|
Talk(Says.Target);
|
|
DoCast(Spells.Pursued); // Will select target in spellscript
|
|
_events.ScheduleEvent(Events.Pursue, 35 * Time.InMilliseconds);
|
|
break;
|
|
case Events.Missile:
|
|
DoCast(me, Spells.MissileBarrage, true);
|
|
_events.ScheduleEvent(Events.Missile, 2 * Time.InMilliseconds);
|
|
break;
|
|
case Events.Vent:
|
|
DoCastAOE(Spells.FlameVents);
|
|
_events.ScheduleEvent(Events.Vent, 20 * Time.InMilliseconds);
|
|
break;
|
|
case Events.Speed:
|
|
DoCastAOE(Spells.GatheringSpeed);
|
|
_events.ScheduleEvent(Events.Speed, 15 * Time.InMilliseconds);
|
|
break;
|
|
case Events.Summon:
|
|
if (summons.Count < 15)
|
|
{
|
|
Creature lift = DoSummonFlyer(CreatureIds.Mechanolift, me, 30.0f, 50.0f, 0);
|
|
if (lift)
|
|
lift.GetMotionMaster().MoveRandom(100);
|
|
}
|
|
_events.ScheduleEvent(Events.Summon, 2 * Time.InMilliseconds);
|
|
break;
|
|
case Events.Shutdown:
|
|
Talk(Says.Overload);
|
|
Talk(Says.EmoteOverload);
|
|
me.CastSpell(me, Spells.SystemsShutdown, true);
|
|
if (Shutout)
|
|
Shutout = false;
|
|
_events.ScheduleEvent(Events.Repair, 4000);
|
|
_events.DelayEvents(20 * Time.InMilliseconds, 0);
|
|
break;
|
|
case Events.Repair:
|
|
Talk(Says.EmoteRepair);
|
|
me.ClearUnitState(UnitState.Stunned | UnitState.Root);
|
|
_events.ScheduleEvent(Events.Shutdown, 150 * Time.InMilliseconds);
|
|
_events.CancelEvent(Events.Repair);
|
|
break;
|
|
case Events.ThorimSHammer: // Tower of Storms
|
|
for (byte i = 0; i < 7; ++i)
|
|
{
|
|
Creature thorim = DoSummon(CreatureIds.ThorimBeacon, me, RandomHelper.URand(20, 60), 20000, TempSummonType.TimedDespawn);
|
|
if (thorim)
|
|
thorim.GetMotionMaster().MoveRandom(100);
|
|
}
|
|
Talk(Says.TowerStorm);
|
|
_events.CancelEvent(Events.ThorimSHammer);
|
|
break;
|
|
case Events.MimironSInferno: // Tower of Flames
|
|
me.SummonCreature(CreatureIds.MimironBeacon, Leviathan.InfernoStart);
|
|
Talk(Says.TowerFlame);
|
|
_events.CancelEvent(Events.MimironSInferno);
|
|
break;
|
|
case Events.HodirSFury: // Tower of Frost
|
|
for (byte i = 0; i < 7; ++i)
|
|
{
|
|
Creature hodir = DoSummon(CreatureIds.HodirBeacon, me, 50f, 0);
|
|
if (hodir)
|
|
hodir.GetMotionMaster().MoveRandom(100);
|
|
}
|
|
Talk(Says.TowerFrost);
|
|
_events.CancelEvent(Events.HodirSFury);
|
|
break;
|
|
case Events.FreyaSWard: // Tower of Nature
|
|
Talk(Says.TowerNature);
|
|
for (int i = 0; i < 4; ++i)
|
|
me.SummonCreature(CreatureIds.FreyaBeacon, Leviathan.FreyaBeacons[i]);
|
|
|
|
Unit target = SelectTarget(SelectAggroTarget.Random);
|
|
if (target)
|
|
DoCast(target, Spells.FreyaSWard);
|
|
_events.CancelEvent(Events.FreyaSWard);
|
|
break;
|
|
}
|
|
});
|
|
|
|
DoBatteringRamIfReady();
|
|
}
|
|
|
|
public override void SpellHitTarget(Unit target, SpellInfo spell)
|
|
{
|
|
if (spell.Id == Spells.Pursued)
|
|
_pursueTarget = target.GetGUID();
|
|
}
|
|
|
|
public override void DoAction(int action)
|
|
{
|
|
if (action != 0 && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count
|
|
{
|
|
if (me.HasLootMode(LootModes.Default | LootModes.HardMode1 | LootModes.HardMode2 | LootModes.HardMode3 | LootModes.HardMode4) && ActiveTowersCount == 4)
|
|
me.RemoveLootMode(LootModes.HardMode4);
|
|
|
|
if (me.HasLootMode(LootModes.Default | LootModes.HardMode1 | LootModes.HardMode2 | LootModes.HardMode3) && ActiveTowersCount == 3)
|
|
me.RemoveLootMode(LootModes.HardMode3);
|
|
|
|
if (me.HasLootMode(LootModes.Default | LootModes.HardMode1 | LootModes.HardMode2) && ActiveTowersCount == 2)
|
|
me.RemoveLootMode(LootModes.HardMode2);
|
|
|
|
if (me.HasLootMode(LootModes.Default | LootModes.HardMode1) && ActiveTowersCount == 1)
|
|
me.RemoveLootMode(LootModes.HardMode1);
|
|
}
|
|
|
|
switch (action)
|
|
{
|
|
case LeviathanActions.TowerOfStormDestroyed:
|
|
if (towerOfStorms)
|
|
{
|
|
towerOfStorms = false;
|
|
--ActiveTowersCount;
|
|
}
|
|
break;
|
|
case LeviathanActions.TowerOfFrostDestroyed:
|
|
if (towerOfFrost)
|
|
{
|
|
towerOfFrost = false;
|
|
--ActiveTowersCount;
|
|
}
|
|
break;
|
|
case LeviathanActions.TowerOfFlamesDestroyed:
|
|
if (towerOfFlames)
|
|
{
|
|
towerOfFlames = false;
|
|
--ActiveTowersCount;
|
|
}
|
|
break;
|
|
case LeviathanActions.TowerOfLifeDestroyed:
|
|
if (towerOfLife)
|
|
{
|
|
towerOfLife = false;
|
|
--ActiveTowersCount;
|
|
}
|
|
break;
|
|
case Leviathan.ActionStartHardMode: // Activate hard-mode enable all towers, apply buffs on leviathan
|
|
ActiveTowers = true;
|
|
towerOfStorms = true;
|
|
towerOfLife = true;
|
|
towerOfFlames = true;
|
|
towerOfFrost = true;
|
|
me.SetLootMode(LootModes.Default | LootModes.HardMode1 | LootModes.HardMode2 | LootModes.HardMode3 | LootModes.HardMode4);
|
|
break;
|
|
case LeviathanActions.MoveToCenterPosition: // Triggered by 2 Collossus near door
|
|
if (!me.IsDead())
|
|
{
|
|
me.SetHomePosition(Leviathan.Center);
|
|
me.GetMotionMaster().MoveCharge(Leviathan.Center.GetPositionX(), Leviathan.Center.GetPositionY(), Leviathan.Center.GetPositionZ()); // position center
|
|
me.SetReactState(ReactStates.Aggressive);
|
|
me.RemoveFlag(UnitFields.Flags, UnitFlags.NonAttackable | UnitFlags.NotSelectable | UnitFlags.Stunned);
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//! Copypasta from DoSpellAttackIfReady, only difference is the target - it cannot be selected trough GetVictim this way -
|
|
//! I also removed the spellInfo check
|
|
void DoBatteringRamIfReady()
|
|
{
|
|
if (me.isAttackReady())
|
|
{
|
|
Unit target = Global.ObjAccessor.GetUnit(me, _pursueTarget);
|
|
if (me.IsWithinCombatRange(target, 30.0f))
|
|
{
|
|
DoCast(target, Spells.BatteringRam);
|
|
me.resetAttackTimer();
|
|
}
|
|
}
|
|
}
|
|
|
|
Vehicle vehicle;
|
|
byte ActiveTowersCount;
|
|
byte Shutdown;
|
|
bool ActiveTowers;
|
|
bool towerOfStorms;
|
|
bool towerOfLife;
|
|
bool towerOfFlames;
|
|
bool towerOfFrost;
|
|
bool Shutout;
|
|
bool Unbroken;
|
|
ObjectGuid _pursueTarget;
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return instance_ulduar.GetUlduarInstanceAI<boss_flame_leviathanAI>(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class boss_flame_leviathan_seat : CreatureScript
|
|
{
|
|
public boss_flame_leviathan_seat() : base("boss_flame_leviathan_seat") { }
|
|
|
|
class boss_flame_leviathan_seatAI : ScriptedAI
|
|
{
|
|
public boss_flame_leviathan_seatAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
vehicle = creature.GetVehicleKit();
|
|
Contract.Assert(vehicle);
|
|
me.SetReactState(ReactStates.Passive);
|
|
me.SetDisplayId(me.GetCreatureTemplate().ModelId2);
|
|
instance = creature.GetInstanceScript();
|
|
}
|
|
|
|
InstanceScript instance;
|
|
Vehicle vehicle;
|
|
|
|
public override void PassengerBoarded(Unit who, sbyte seatId, bool apply)
|
|
{
|
|
if (!me.GetVehicle())
|
|
return;
|
|
|
|
if (seatId == Seats.Player)
|
|
{
|
|
Creature leviathan = me.GetVehicleCreatureBase();
|
|
if (!apply)
|
|
return;
|
|
else if (leviathan)
|
|
leviathan.GetAI().Talk(Says.PlayerRiding);
|
|
|
|
Unit turretPassenger = me.GetVehicleKit().GetPassenger(Seats.Turret);
|
|
if (turretPassenger)
|
|
{
|
|
Creature turret = turretPassenger.ToCreature();
|
|
if (turret)
|
|
{
|
|
turret.SetFaction(me.GetVehicleBase().getFaction());
|
|
turret.SetUInt32Value(UnitFields.Flags, 0); // unselectable
|
|
turret.GetAI().AttackStart(who);
|
|
}
|
|
}
|
|
Unit devicePassenger = me.GetVehicleKit().GetPassenger(Seats.Device);
|
|
if (devicePassenger)
|
|
{
|
|
Creature device = devicePassenger.ToCreature();
|
|
if (device)
|
|
{
|
|
device.SetFlag64(UnitFields.NpcFlags, NPCFlags.SpellClick);
|
|
device.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
|
}
|
|
}
|
|
|
|
me.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
|
}
|
|
else if (seatId == Seats.Turret)
|
|
{
|
|
if (apply)
|
|
return;
|
|
|
|
Unit device = vehicle.GetPassenger(Seats.Device);
|
|
if (device)
|
|
{
|
|
device.SetFlag64(UnitFields.NpcFlags, NPCFlags.SpellClick);
|
|
device.SetUInt32Value(UnitFields.Flags, 0); // unselectable
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return instance_ulduar.GetUlduarInstanceAI<boss_flame_leviathan_seatAI>(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class boss_flame_leviathan_defense_cannon : CreatureScript
|
|
{
|
|
public boss_flame_leviathan_defense_cannon() : base("boss_flame_leviathan_defense_cannon") { }
|
|
|
|
class boss_flame_leviathan_defense_cannonAI : ScriptedAI
|
|
{
|
|
public boss_flame_leviathan_defense_cannonAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
}
|
|
|
|
uint NapalmTimer;
|
|
|
|
public override void Reset()
|
|
{
|
|
NapalmTimer = 5 * Time.InMilliseconds;
|
|
DoCast(me, Spells.StealthDetection);
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (NapalmTimer <= diff)
|
|
{
|
|
Unit target = SelectTarget(SelectAggroTarget.Random, 0);
|
|
if (target)
|
|
if (CanAIAttack(target))
|
|
DoCast(target, Spells.Napalm, true);
|
|
|
|
NapalmTimer = 5000;
|
|
}
|
|
else
|
|
NapalmTimer -= diff;
|
|
}
|
|
|
|
public override bool CanAIAttack(Unit who)
|
|
{
|
|
if (!who.IsTypeId(TypeId.Player) || !who.GetVehicle() || who.GetVehicleBase().GetEntry() == CreatureIds.Seat)
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new boss_flame_leviathan_defense_cannonAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class boss_flame_leviathan_defense_turret : CreatureScript
|
|
{
|
|
public boss_flame_leviathan_defense_turret() : base("boss_flame_leviathan_defense_turret") { }
|
|
|
|
class boss_flame_leviathan_defense_turretAI : TurretAI
|
|
{
|
|
public boss_flame_leviathan_defense_turretAI(Creature creature) : base(creature) { }
|
|
|
|
public override void DamageTaken(Unit who, ref uint damage)
|
|
{
|
|
if (!CanAIAttack(who))
|
|
damage = 0;
|
|
}
|
|
|
|
public override bool CanAIAttack(Unit who)
|
|
{
|
|
if (!who.IsTypeId(TypeId.Player) || !who.GetVehicle() || who.GetVehicleBase().GetEntry() != CreatureIds.Seat)
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new boss_flame_leviathan_defense_turretAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class boss_flame_leviathan_overload_device : CreatureScript
|
|
{
|
|
public boss_flame_leviathan_overload_device() : base("boss_flame_leviathan_overload_device") { }
|
|
|
|
class boss_flame_leviathan_overload_deviceAI : PassiveAI
|
|
{
|
|
public boss_flame_leviathan_overload_deviceAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
}
|
|
|
|
public override void OnSpellClick(Unit clicker, ref bool result)
|
|
{
|
|
if (!result)
|
|
return;
|
|
|
|
if (me.GetVehicle())
|
|
{
|
|
me.RemoveFlag64(UnitFields.NpcFlags, NPCFlags.SpellClick);
|
|
me.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
|
|
|
Unit player = me.GetVehicle().GetPassenger(Seats.Player);
|
|
if (player)
|
|
{
|
|
me.GetVehicleBase().CastSpell(player, Spells.SmokeTrail, true);
|
|
player.GetMotionMaster().MoveKnockbackFrom(me.GetVehicleBase().GetPositionX(), me.GetVehicleBase().GetPositionY(), 30, 30);
|
|
player.ExitVehicle();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new boss_flame_leviathan_overload_deviceAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class boss_flame_leviathan_safety_container : CreatureScript
|
|
{
|
|
public boss_flame_leviathan_safety_container() : base("boss_flame_leviathan_safety_container") { }
|
|
|
|
class boss_flame_leviathan_safety_containerAI : PassiveAI
|
|
{
|
|
public boss_flame_leviathan_safety_containerAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
}
|
|
|
|
public override void JustDied(Unit killer)
|
|
{
|
|
float x, y, z;
|
|
me.GetPosition(out x, out y, out z);
|
|
z = me.GetMap().GetHeight(me.GetPhases(), x, y, z);
|
|
me.GetMotionMaster().MovePoint(0, x, y, z);
|
|
me.SetPosition(x, y, z, 0);
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new boss_flame_leviathan_safety_containerAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_mechanolift : CreatureScript
|
|
{
|
|
public npc_mechanolift() : base("npc_mechanolift") { }
|
|
|
|
class npc_mechanoliftAI : PassiveAI
|
|
{
|
|
public npc_mechanoliftAI(Creature creature) : base(creature)
|
|
{
|
|
Contract.Assert(me.GetVehicleKit());
|
|
}
|
|
|
|
uint MoveTimer;
|
|
|
|
public override void Reset()
|
|
{
|
|
MoveTimer = 0;
|
|
me.GetMotionMaster().MoveRandom(50);
|
|
}
|
|
|
|
public override void JustDied(Unit killer)
|
|
{
|
|
me.GetMotionMaster().MoveTargetedHome();
|
|
DoCast(Spells.DustyExplosion);
|
|
Creature liquid = DoSummon(CreatureIds.Liquid, me, 0f);
|
|
if (liquid)
|
|
{
|
|
liquid.CastSpell(liquid, Spells.LiquidPyrite, true);
|
|
liquid.CastSpell(liquid, Spells.DustCloudImpact, true);
|
|
}
|
|
}
|
|
|
|
public override void MovementInform(MovementGeneratorType type, uint id)
|
|
{
|
|
if (type == MovementGeneratorType.Point && id == 1)
|
|
{
|
|
Creature container = me.FindNearestCreature(CreatureIds.Container, 5, true);
|
|
if (container)
|
|
container.EnterVehicle(me);
|
|
}
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (MoveTimer <= diff)
|
|
{
|
|
if (me.GetVehicleKit().HasEmptySeat(-1))
|
|
{
|
|
Creature container = me.FindNearestCreature(CreatureIds.Container, 50, true);
|
|
if (container && !container.GetVehicle())
|
|
me.GetMotionMaster().MovePoint(1, container.GetPositionX(), container.GetPositionY(), container.GetPositionZ());
|
|
}
|
|
|
|
MoveTimer = 30000; //check next 30 seconds
|
|
}
|
|
else
|
|
MoveTimer -= diff;
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new npc_mechanoliftAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_pool_of_tar : CreatureScript
|
|
{
|
|
public npc_pool_of_tar() : base("npc_pool_of_tar") { }
|
|
|
|
class npc_pool_of_tarAI : ScriptedAI
|
|
{
|
|
public npc_pool_of_tarAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
|
me.SetReactState(ReactStates.Passive);
|
|
me.CastSpell(me, Spells.TarPassive, true);
|
|
}
|
|
|
|
public override void DamageTaken(Unit who, ref uint damage)
|
|
{
|
|
damage = 0;
|
|
}
|
|
|
|
public override void SpellHit(Unit caster, SpellInfo spell)
|
|
{
|
|
if (spell.SchoolMask.HasAnyFlag(SpellSchoolMask.Fire) && !me.HasAura(Spells.Blaze))
|
|
me.CastSpell(me, Spells.Blaze, true);
|
|
}
|
|
|
|
public override void UpdateAI(uint diff) { }
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new npc_pool_of_tarAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_colossus : CreatureScript
|
|
{
|
|
public npc_colossus() : base("npc_colossus") { }
|
|
|
|
class npc_colossusAI : ScriptedAI
|
|
{
|
|
public npc_colossusAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
instance = creature.GetInstanceScript();
|
|
}
|
|
|
|
InstanceScript instance;
|
|
|
|
public override void JustDied(Unit killer)
|
|
{
|
|
if (me.GetHomePosition().IsInDist(Leviathan.Center, 50.0f))
|
|
instance.SetData(InstanceData.Colossus, instance.GetData(InstanceData.Colossus) + 1);
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return GetInstanceAI<npc_colossusAI>(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_thorims_hammer : CreatureScript
|
|
{
|
|
public npc_thorims_hammer() : base("npc_thorims_hammer") { }
|
|
|
|
class npc_thorims_hammerAI : ScriptedAI
|
|
{
|
|
public npc_thorims_hammerAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
me.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
|
me.CastSpell(me, Spells.DummyBlue, true);
|
|
}
|
|
|
|
public override void MoveInLineOfSight(Unit who)
|
|
{
|
|
if (who.IsTypeId(TypeId.Player) && who.IsVehicle() && me.IsInRange(who, 0, 10, false))
|
|
{
|
|
Creature trigger = DoSummonFlyer(CreatureIds.ThorimTargetBeacon, me, 20, 0, 1000, TempSummonType.TimedDespawn);
|
|
if (trigger)
|
|
trigger.CastSpell(who, Spells.ThorimSHammer, true);
|
|
}
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (!me.HasAura(Spells.DummyBlue))
|
|
me.CastSpell(me, Spells.DummyBlue, true);
|
|
|
|
UpdateVictim();
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new npc_thorims_hammerAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_mimirons_inferno : CreatureScript
|
|
{
|
|
public npc_mimirons_inferno() : base("npc_mimirons_inferno") { }
|
|
|
|
class npc_mimirons_infernoAI : npc_escortAI
|
|
{
|
|
public npc_mimirons_infernoAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
me.SetFlag(UnitFields.Flags, UnitFlags.NonAttackable | UnitFlags.NotSelectable);
|
|
me.CastSpell(me, Spells.DummyYellow, true);
|
|
me.SetReactState(ReactStates.Passive);
|
|
}
|
|
|
|
public override void WaypointReached(uint waypointId)
|
|
{
|
|
|
|
}
|
|
|
|
public override void Reset()
|
|
{
|
|
infernoTimer = 2000;
|
|
}
|
|
|
|
uint infernoTimer;
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
base.UpdateAI(diff);
|
|
|
|
if (!HasEscortState(eEscortState.Escorting))
|
|
Start(false, true, ObjectGuid.Empty, null, false, true);
|
|
else
|
|
{
|
|
if (infernoTimer <= diff)
|
|
{
|
|
Creature trigger = DoSummonFlyer(CreatureIds.MimironTargetBeacon, me, 20, 0, 1000, TempSummonType.TimedDespawn);
|
|
if (trigger)
|
|
{
|
|
trigger.CastSpell(me.GetPositionX(), me.GetPositionY(), me.GetPositionZ(), Spells.MimironSInferno, true);
|
|
infernoTimer = 2000;
|
|
}
|
|
}
|
|
else
|
|
infernoTimer -= diff;
|
|
|
|
if (!me.HasAura(Spells.DummyYellow))
|
|
me.CastSpell(me, Spells.DummyYellow, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new npc_mimirons_infernoAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_hodirs_fury : CreatureScript
|
|
{
|
|
public npc_hodirs_fury() : base("npc_hodirs_fury") { }
|
|
|
|
class npc_hodirs_furyAI : ScriptedAI
|
|
{
|
|
public npc_hodirs_furyAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
me.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
|
me.CastSpell(me, Spells.DummyGreen, true);
|
|
}
|
|
|
|
public override void MoveInLineOfSight(Unit who)
|
|
{
|
|
if (who.IsTypeId(TypeId.Player) && who.IsVehicle() && me.IsInRange(who, 0, 5, false))
|
|
{
|
|
Creature trigger = DoSummonFlyer(CreatureIds.HodirTargetBeacon, me, 20, 0, 1000, TempSummonType.TimedDespawn);
|
|
if (trigger)
|
|
trigger.CastSpell(who, Spells.HodirSFury, true);
|
|
}
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (!me.HasAura(Spells.DummyGreen))
|
|
me.CastSpell(me, Spells.DummyGreen, true);
|
|
|
|
UpdateVictim();
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new npc_hodirs_furyAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_freyas_ward : CreatureScript
|
|
{
|
|
public npc_freyas_ward() : base("npc_freyas_ward") { }
|
|
|
|
class npc_freyas_wardAI : ScriptedAI
|
|
{
|
|
public npc_freyas_wardAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
me.CastSpell(me, Spells.DummyGreen, true);
|
|
}
|
|
|
|
uint summonTimer;
|
|
|
|
public override void Reset()
|
|
{
|
|
summonTimer = 5000;
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (summonTimer <= diff)
|
|
{
|
|
DoCast(Spells.FreyaSWardEffect1);
|
|
DoCast(Spells.FreyaSWardEffect2);
|
|
summonTimer = 20000;
|
|
}
|
|
else
|
|
summonTimer -= diff;
|
|
|
|
if (!me.HasAura(Spells.DummyGreen))
|
|
me.CastSpell(me, Spells.DummyGreen, true);
|
|
|
|
UpdateVictim();
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new npc_freyas_wardAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_freya_ward_summon : CreatureScript
|
|
{
|
|
public npc_freya_ward_summon() : base("npc_freya_ward_summon") { }
|
|
|
|
class npc_freya_ward_summonAI : ScriptedAI
|
|
{
|
|
public npc_freya_ward_summonAI(Creature creature)
|
|
: base(creature)
|
|
{
|
|
creature.GetMotionMaster().MoveRandom(100);
|
|
}
|
|
|
|
uint lashTimer;
|
|
|
|
public override void Reset()
|
|
{
|
|
lashTimer = 5000;
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (lashTimer <= diff)
|
|
{
|
|
DoCast(Spells.Lash);
|
|
lashTimer = 20000;
|
|
}
|
|
else
|
|
lashTimer -= diff;
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new npc_freya_ward_summonAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class npc_lorekeeper : CreatureScript
|
|
{
|
|
string GOSSIP_ITEM_1 = "Activate secondary defensive systems";
|
|
string GOSSIP_ITEM_2 = "Confirmed";
|
|
|
|
public npc_lorekeeper() : base("npc_lorekeeper") { }
|
|
|
|
class npc_lorekeeperAI : ScriptedAI
|
|
{
|
|
public npc_lorekeeperAI(Creature creature)
|
|
: base(creature) { }
|
|
|
|
public override void DoAction(int action)
|
|
{
|
|
// Start encounter
|
|
if (action == Leviathan.ActionSpawnVehicles)
|
|
{
|
|
for (int i = 0; i < RaidMode(2, 5); ++i)
|
|
DoSummon(Vehicles.Siege, Leviathan.PosSiege[i], 3000, TempSummonType.CorpseTimedDespawn);
|
|
for (int i = 0; i < RaidMode(2, 5); ++i)
|
|
DoSummon(Vehicles.Chopper, Leviathan.PosChopper[i], 3000, TempSummonType.CorpseTimedDespawn);
|
|
for (int i = 0; i < RaidMode(2, 5); ++i)
|
|
DoSummon(Vehicles.Demolisher, Leviathan.PosDemolisher[i], 3000, TempSummonType.CorpseTimedDespawn);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override bool OnGossipSelect(Player player, Creature creature, uint sender, uint action)
|
|
{
|
|
player.CLOSE_GOSSIP_MENU();
|
|
InstanceScript instance = creature.GetInstanceScript();
|
|
if (instance == null)
|
|
return true;
|
|
|
|
switch (action)
|
|
{
|
|
case eTradeskill.GossipActionInfoDef + 1:
|
|
player.PrepareGossipMenu(creature);
|
|
instance.instance.LoadGrid(364, -16); //make sure leviathan is loaded
|
|
|
|
player.ADD_GOSSIP_ITEM(GossipOptionIcon.Chat, GOSSIP_ITEM_2, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 2);
|
|
player.SEND_GOSSIP_MENU(player.GetGossipTextId(creature), creature.GetGUID());
|
|
break;
|
|
case eTradeskill.GossipActionInfoDef + 2:
|
|
Creature leviathan = instance.instance.GetCreature(instance.GetGuidData(BossIds.Leviathan));
|
|
if (leviathan)
|
|
{
|
|
leviathan.GetAI().DoAction(Leviathan.ActionStartHardMode);
|
|
creature.SetVisible(false);
|
|
creature.GetAI().DoAction(Leviathan.ActionSpawnVehicles); // spawn the vehicles
|
|
Creature Delorah = creature.FindNearestCreature(CreatureIds.Delorah, 1000, true);
|
|
if (Delorah)
|
|
{
|
|
Creature Branz = creature.FindNearestCreature(CreatureIds.BranzBronzbeard, 1000, true);
|
|
if (Branz)
|
|
{
|
|
Delorah.GetMotionMaster().MovePoint(0, Branz.GetPositionX() - 4, Branz.GetPositionY(), Branz.GetPositionZ());
|
|
// @todo Delorah.AI().Talk(xxxx, Branz); when reached at branz
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override bool OnGossipHello(Player player, Creature creature)
|
|
{
|
|
InstanceScript instance = creature.GetInstanceScript();
|
|
if (instance != null && instance.GetData(BossIds.Leviathan) != (uint)EncounterState.Done && player)
|
|
{
|
|
player.PrepareGossipMenu(creature);
|
|
|
|
player.ADD_GOSSIP_ITEM(GossipOptionIcon.Chat, GOSSIP_ITEM_1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1);
|
|
player.SEND_GOSSIP_MENU(player.GetGossipTextId(creature), creature.GetGUID());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return new npc_lorekeeperAI(creature);
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class go_ulduar_tower : GameObjectScript
|
|
{
|
|
public go_ulduar_tower() : base("go_ulduar_tower") { }
|
|
|
|
public override void OnDestroyed(GameObject go, Player player)
|
|
{
|
|
InstanceScript instance = go.GetInstanceScript();
|
|
if (instance == null)
|
|
return;
|
|
|
|
switch (go.GetEntry())
|
|
{
|
|
case Towers.ofStorms:
|
|
instance.ProcessEvent(go, InstanceEventIds.TowerOfStormDestroyed);
|
|
break;
|
|
case Towers.ofFlames:
|
|
instance.ProcessEvent(go, InstanceEventIds.TowerOfFlamesDestroyed);
|
|
break;
|
|
case Towers.ofFrost:
|
|
instance.ProcessEvent(go, InstanceEventIds.TowerOfFrostDestroyed);
|
|
break;
|
|
case Towers.ofLife:
|
|
instance.ProcessEvent(go, InstanceEventIds.TowerOfLifeDestroyed);
|
|
break;
|
|
}
|
|
|
|
Creature trigger = go.FindNearestCreature(CreatureIds.UlduarGauntletGenerator, 15.0f, true);
|
|
if (trigger)
|
|
trigger.DisappearAndDie();
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_three_car_garage_demolisher : AchievementCriteriaScript
|
|
{
|
|
public achievement_three_car_garage_demolisher() : base("achievement_three_car_garage_demolisher") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
Creature vehicle = source.GetVehicleCreatureBase();
|
|
if (vehicle)
|
|
{
|
|
if (vehicle.GetEntry() == Vehicles.Demolisher)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_three_car_garage_chopper : AchievementCriteriaScript
|
|
{
|
|
public achievement_three_car_garage_chopper() : base("achievement_three_car_garage_chopper") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
Creature vehicle = source.GetVehicleCreatureBase();
|
|
if (vehicle)
|
|
{
|
|
if (vehicle.GetEntry() == Vehicles.Chopper)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_three_car_garage_siege : AchievementCriteriaScript
|
|
{
|
|
public achievement_three_car_garage_siege() : base("achievement_three_car_garage_siege") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
Creature vehicle = source.GetVehicleCreatureBase();
|
|
if (vehicle)
|
|
{
|
|
if (vehicle.GetEntry() == Vehicles.Siege)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_shutout : AchievementCriteriaScript
|
|
{
|
|
public achievement_shutout() : base("achievement_shutout") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
if (target)
|
|
{
|
|
Creature leviathan = target.ToCreature();
|
|
if (leviathan)
|
|
if (leviathan.GetAI().GetData(Leviathan.DataShutout) != 0)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_unbroken : AchievementCriteriaScript
|
|
{
|
|
public achievement_unbroken() : base("achievement_unbroken") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
if (target)
|
|
{
|
|
InstanceScript instance = target.GetInstanceScript();
|
|
if (instance != null)
|
|
return instance.GetData(InstanceAchievementData.DataUnbroken) != 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_orbital_bombardment : AchievementCriteriaScript
|
|
{
|
|
public achievement_orbital_bombardment() : base("achievement_orbital_bombardment") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
if (!target)
|
|
return false;
|
|
|
|
Creature leviathan = target.ToCreature();
|
|
if (leviathan)
|
|
if (leviathan.GetAI().GetData(Leviathan.DataOrbitAchievements) >= 1)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_orbital_devastation : AchievementCriteriaScript
|
|
{
|
|
public achievement_orbital_devastation() : base("achievement_orbital_devastation") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
if (!target)
|
|
return false;
|
|
Creature leviathan = target.ToCreature();
|
|
if (leviathan)
|
|
if (leviathan.GetAI().GetData(Leviathan.DataOrbitAchievements) >= 2)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_nuked_from_orbit : AchievementCriteriaScript
|
|
{
|
|
public achievement_nuked_from_orbit() : base("achievement_nuked_from_orbit") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
if (!target)
|
|
return false;
|
|
|
|
Creature leviathan = target.ToCreature();
|
|
if (leviathan)
|
|
if (leviathan.GetAI().GetData(Leviathan.DataOrbitAchievements) >= 3)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class achievement_orbit_uary : AchievementCriteriaScript
|
|
{
|
|
public achievement_orbit_uary() : base("achievement_orbit_uary") { }
|
|
|
|
public override bool OnCheck(Player source, Unit target)
|
|
{
|
|
if (!target)
|
|
return false;
|
|
|
|
Creature leviathan = target.ToCreature();
|
|
if (leviathan)
|
|
if (leviathan.GetAI().GetData(Leviathan.DataOrbitAchievements) == 4)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class spell_load_into_catapult : SpellScriptLoader
|
|
{
|
|
enum Spells
|
|
{
|
|
SPELL_PASSENGER_LOADED = 62340,
|
|
}
|
|
|
|
public spell_load_into_catapult() : base("spell_load_into_catapult") { }
|
|
|
|
class spell_load_into_catapult_AuraScript : AuraScript
|
|
{
|
|
void OnApply(AuraEffect aurEff, AuraEffectHandleModes mode)
|
|
{
|
|
Unit owner = GetOwner().ToUnit();
|
|
if (!owner)
|
|
return;
|
|
|
|
owner.CastSpell(owner, 62340, true);
|
|
}
|
|
|
|
void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
|
|
{
|
|
Unit owner = GetOwner().ToUnit();
|
|
if (!owner)
|
|
return;
|
|
|
|
owner.RemoveAurasDueToSpell(62340);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectApply.Add(new EffectApplyHandler(OnApply, 0, AuraType.ControlVehicle, AuraEffectHandleModes.Real));
|
|
OnEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, AuraType.ControlVehicle, AuraEffectHandleModes.RealOrReapplyMask));
|
|
}
|
|
}
|
|
|
|
public override AuraScript GetAuraScript()
|
|
{
|
|
return new spell_load_into_catapult_AuraScript();
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class spell_auto_repair : SpellScriptLoader
|
|
{
|
|
public spell_auto_repair() : base("spell_auto_repair") { }
|
|
|
|
class spell_auto_repair_SpellScript : SpellScript
|
|
{
|
|
void CheckCooldownForTarget(SpellMissInfo missInfo)
|
|
{
|
|
if (missInfo != SpellMissInfo.None)
|
|
return;
|
|
|
|
if (GetHitUnit().HasAuraEffect(62705, 2)) // Check presence of dummy aura indicating cooldown
|
|
{
|
|
PreventHitEffect(0);
|
|
PreventHitDefaultEffect(1);
|
|
PreventHitDefaultEffect(2);
|
|
//! Currently this doesn't work: if we call PreventHitAura(), the existing aura will be removed
|
|
//! because of recent aura refreshing changes. Since removing the existing aura negates the idea
|
|
//! of a cooldown marker, we just let the dummy aura refresh itself without executing the other SpellEffectName.
|
|
//! The spelleffects can be executed by letting the dummy aura expire naturally.
|
|
//! This is a temporary solution only.
|
|
}
|
|
}
|
|
|
|
void HandleScript(uint eff)
|
|
{
|
|
Vehicle vehicle = GetHitUnit().GetVehicleKit();
|
|
if (!vehicle)
|
|
return;
|
|
|
|
Player driver = vehicle.GetPassenger(0) ? vehicle.GetPassenger(0).ToPlayer() : null;
|
|
if (!driver)
|
|
return;
|
|
|
|
driver.TextEmote(Says.EmoteRepair, driver, true);
|
|
|
|
InstanceScript instance = driver.GetInstanceScript();
|
|
if (instance == null)
|
|
return;
|
|
|
|
// Actually should/could use basepoints (100) for this spell effect as percentage of health, but oh well.
|
|
vehicle.GetBase().SetFullHealth();
|
|
|
|
// For achievement
|
|
instance.SetData(InstanceAchievementData.DataUnbroken, 0);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
|
|
BeforeHit.Add(new BeforeHitHandler(CheckCooldownForTarget));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_auto_repair_SpellScript();
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class spell_systems_shutdown : SpellScriptLoader
|
|
{
|
|
public spell_systems_shutdown() : base("spell_systems_shutdown") { }
|
|
|
|
class spell_systems_shutdown_AuraScript : AuraScript
|
|
{
|
|
void OnApply(AuraEffect aurEff, AuraEffectHandleModes mode)
|
|
{
|
|
Creature owner = GetOwner().ToCreature();
|
|
if (!owner)
|
|
return;
|
|
|
|
//! This could probably in the SPELL_EFFECT_SEND_EVENT handler too:
|
|
owner.AddUnitState(UnitState.Stunned | UnitState.Root);
|
|
owner.SetFlag(UnitFields.Flags, UnitFlags.Stunned);
|
|
owner.RemoveAurasDueToSpell(Spells.GatheringSpeed);
|
|
}
|
|
|
|
void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
|
|
{
|
|
Creature owner = GetOwner().ToCreature();
|
|
if (!owner)
|
|
return;
|
|
|
|
owner.RemoveFlag(UnitFields.Flags, UnitFlags.Stunned);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectApply.Add(new EffectApplyHandler(OnApply, 0, AuraType.ModDamagePercentTaken, AuraEffectHandleModes.Real));
|
|
OnEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, AuraType.ModDamagePercentTaken, AuraEffectHandleModes.Real));
|
|
}
|
|
}
|
|
|
|
public override AuraScript GetAuraScript()
|
|
{
|
|
return new spell_systems_shutdown_AuraScript();
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class spell_pursue : SpellScriptLoader
|
|
{
|
|
public spell_pursue() : base("spell_pursue") { }
|
|
|
|
const uint AREA_FORMATION_GROUNDS = 4652;
|
|
|
|
class spell_pursue_SpellScript : SpellScript
|
|
{
|
|
public override bool Load()
|
|
{
|
|
_target = null;
|
|
return true;
|
|
}
|
|
|
|
void FilterTargets(List<WorldObject> targets)
|
|
{
|
|
targets.RemoveAll(new Predicate<WorldObject>(target =>
|
|
{
|
|
//! No players, only vehicles (@todo check if blizzlike)
|
|
Creature creatureTarget = target.ToCreature();
|
|
if (!creatureTarget)
|
|
return true;
|
|
|
|
//! NPC entries must match
|
|
if (creatureTarget.GetEntry() != Vehicles.Demolisher && creatureTarget.GetEntry() != Vehicles.Siege)
|
|
return true;
|
|
|
|
//! NPC must be a valid vehicle installation
|
|
Vehicle vehicle = creatureTarget.GetVehicleKit();
|
|
if (!vehicle)
|
|
return true;
|
|
|
|
//! Entity needs to be in appropriate area
|
|
if (target.GetAreaId() != AREA_FORMATION_GROUNDS)
|
|
return true;
|
|
|
|
//! Vehicle must be in use by player
|
|
bool playerFound = false;
|
|
foreach (var seat in vehicle.Seats.Values)
|
|
{
|
|
if (seat.Passenger.Guid.IsPlayer())
|
|
{
|
|
playerFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return !playerFound;
|
|
}));
|
|
|
|
if (targets.Empty())
|
|
{
|
|
Creature caster = GetCaster().ToCreature();
|
|
if (caster)
|
|
caster.GetAI().EnterEvadeMode();
|
|
}
|
|
else
|
|
{
|
|
//! In the end, only one target should be selected
|
|
_target = targets.SelectRandom();
|
|
FilterTargetsSubsequently(targets);
|
|
}
|
|
}
|
|
|
|
void FilterTargetsSubsequently(List<WorldObject> targets)
|
|
{
|
|
targets.Clear();
|
|
if (_target)
|
|
targets.Add(_target);
|
|
}
|
|
|
|
void HandleScript(uint eff)
|
|
{
|
|
Creature caster = GetCaster().ToCreature();
|
|
if (!caster)
|
|
return;
|
|
|
|
caster.GetAI().AttackStart(GetHitUnit()); // Chase target
|
|
|
|
foreach (var seat in caster.GetVehicleKit().Seats.Values)
|
|
{
|
|
Player passenger = Global.ObjAccessor.GetPlayer(caster, seat.Passenger.Guid);
|
|
if (passenger)
|
|
{
|
|
caster.GetAI().Talk(Says.EmotePursue, passenger);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargets, 0, Targets.UnitSrcAreaEnemy));
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargetsSubsequently, 1, Targets.UnitSrcAreaEnemy));
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ApplyAura));
|
|
}
|
|
|
|
WorldObject _target;
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_pursue_SpellScript();
|
|
}
|
|
}
|
|
|
|
[Script]
|
|
class spell_vehicle_throw_passenger : SpellScriptLoader
|
|
{
|
|
public spell_vehicle_throw_passenger() : base("spell_vehicle_throw_passenger") { }
|
|
|
|
class spell_vehicle_throw_passenger_SpellScript : SpellScript
|
|
{
|
|
void HandleScript(uint effIndex)
|
|
{
|
|
Spell baseSpell = GetSpell();
|
|
SpellCastTargets targets = baseSpell.m_targets;
|
|
int damage = GetEffectValue();
|
|
if (targets.HasTraj())
|
|
{
|
|
Vehicle vehicle = GetCaster().GetVehicleKit();
|
|
if (vehicle)
|
|
{
|
|
Unit passenger = vehicle.GetPassenger((sbyte)(damage - 1));
|
|
if (passenger)
|
|
{
|
|
// use 99 because it is 3d search
|
|
List<WorldObject> targetList = new List<WorldObject>();
|
|
var check = new WorldObjectSpellAreaTargetCheck(99, GetExplTargetDest(), GetCaster(), GetCaster(), GetSpellInfo(), SpellTargetCheckTypes.Default, null);
|
|
var searcher = new WorldObjectListSearcher(GetCaster(), targetList, check);
|
|
Cell.VisitAllObjects(GetCaster(), searcher, 99.0f);
|
|
float minDist = 99 * 99;
|
|
Unit target = null;
|
|
foreach (var obj in targetList)
|
|
{
|
|
Unit unit = obj.ToUnit();
|
|
if (unit)
|
|
{
|
|
if (unit.GetEntry() == CreatureIds.Seat)
|
|
{
|
|
Vehicle seat = unit.GetVehicleKit();
|
|
if (seat)
|
|
{
|
|
if (!seat.GetPassenger(0))
|
|
{
|
|
Unit device = seat.GetPassenger(2);
|
|
if (device)
|
|
if (!device.GetCurrentSpell(CurrentSpellTypes.Channeled))
|
|
{
|
|
float dist = unit.GetExactDistSq(targets.GetDstPos());
|
|
if (dist < minDist)
|
|
{
|
|
minDist = dist;
|
|
target = unit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (target && target.IsWithinDist2d(targets.GetDstPos(), GetSpellInfo().GetEffect(effIndex).CalcRadius() * 2)) // now we use *2 because the location of the seat is not correct
|
|
passenger.EnterVehicle(target, 0);
|
|
else
|
|
{
|
|
passenger.ExitVehicle();
|
|
passenger.GetMotionMaster().MoveJump(targets.GetDstPos(), targets.GetSpeedXY(), targets.GetSpeedZ());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.Dummy));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_vehicle_throw_passenger_SpellScript();
|
|
}
|
|
}
|
|
}
|
|
}
|