Start adding missing scripts Part 6
This commit is contained in:
@@ -355,9 +355,9 @@ namespace Scripts.EasternKingdoms.BlackrockMountain.BlackrockDepths.CorenDirebre
|
||||
}
|
||||
}
|
||||
|
||||
class go_direbrew_mole_machineAI : GameObjectAI
|
||||
class go_direbrew_mole_machine : GameObjectAI
|
||||
{
|
||||
public go_direbrew_mole_machineAI(GameObject go) : base(go) { }
|
||||
public go_direbrew_mole_machine(GameObject go) : base(go) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
|
||||
@@ -100,12 +100,12 @@ namespace Scripts.EasternKingdoms.BlackrockMountain.BlackrockDepths.Magmus
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_ironhand_guardianAI : ScriptedAI
|
||||
class npc_ironhand_guardian : ScriptedAI
|
||||
{
|
||||
InstanceScript _instance;
|
||||
bool _active;
|
||||
|
||||
public npc_ironhand_guardianAI(Creature creature) : base(creature)
|
||||
public npc_ironhand_guardian(Creature creature) : base(creature)
|
||||
{
|
||||
_instance = me.GetInstanceScript();
|
||||
_active = false;
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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.Scripting;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.Curator
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint HatefulBolt = 30383;
|
||||
public const uint Evocation = 30254;
|
||||
public const uint ArcaneInfusion = 30403;
|
||||
public const uint Berserk = 26662;
|
||||
public const uint SummonAstralFlareNe = 30236;
|
||||
public const uint SummonAstralFlareNw = 30239;
|
||||
public const uint SummonAstralFlareSe = 30240;
|
||||
public const uint SummonAstralFlareSw = 30241;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayAggro = 0;
|
||||
public const uint SaySummon = 1;
|
||||
public const uint SayEvocate = 2;
|
||||
public const uint SayEnrage = 3;
|
||||
public const uint SayKill = 4;
|
||||
public const uint SayDeath = 5;
|
||||
}
|
||||
|
||||
struct MiscConst
|
||||
{
|
||||
public const uint GroupAstralFlare = 1;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_curator : BossAI
|
||||
{
|
||||
public boss_curator(Creature creature) : base(creature, DataTypes.Curator) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_Reset();
|
||||
_infused = false;
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
if (victim.IsPlayer())
|
||||
Talk(TextIds.SayKill);
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
_JustDied();
|
||||
Talk(TextIds.SayDeath);
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
base.JustEngagedWith(who);
|
||||
Talk(TextIds.SayAggro);
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(12), task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.MaxThreat, 1);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.HatefulBolt);
|
||||
task.Repeat(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(15));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(10), MiscConst.GroupAstralFlare, task =>
|
||||
{
|
||||
if (RandomHelper.randChance(50))
|
||||
Talk(TextIds.SaySummon);
|
||||
|
||||
DoCastSelf(RandomHelper.RAND(SpellIds.SummonAstralFlareNe, SpellIds.SummonAstralFlareNw, SpellIds.SummonAstralFlareSe, SpellIds.SummonAstralFlareSw), new CastSpellExtraArgs(true));
|
||||
|
||||
int mana = (me.GetMaxPower(PowerType.Mana) / 10);
|
||||
if (mana != 0)
|
||||
{
|
||||
me.ModifyPower(PowerType.Mana, -mana);
|
||||
|
||||
if (me.GetPower(PowerType.Mana) * 100 / me.GetMaxPower(PowerType.Mana) < 10)
|
||||
{
|
||||
Talk(TextIds.SayEvocate);
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
DoCastSelf(SpellIds.Evocation);
|
||||
}
|
||||
}
|
||||
task.Repeat(TimeSpan.FromSeconds(10));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromMinutes(12), ScheduleTasks =>
|
||||
{
|
||||
Talk(TextIds.SayEnrage);
|
||||
DoCastSelf(SpellIds.Berserk, new CastSpellExtraArgs(true));
|
||||
});
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
|
||||
{
|
||||
if (!HealthAbovePct(15) && !_infused)
|
||||
{
|
||||
_infused = true;
|
||||
_scheduler.Schedule(TimeSpan.FromMilliseconds(1), task => DoCastSelf(SpellIds.ArcaneInfusion, new CastSpellExtraArgs(true)));
|
||||
_scheduler.CancelGroup(MiscConst.GroupAstralFlare);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
_scheduler.Update(diff, () => DoMeleeAttackIfReady());
|
||||
}
|
||||
|
||||
bool _infused;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_curator_astral_flare : ScriptedAI
|
||||
{
|
||||
public npc_curator_astral_flare(Creature creature) : base(creature)
|
||||
{
|
||||
me.SetReactState(ReactStates.Passive);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(2), task =>
|
||||
{
|
||||
me.SetReactState(ReactStates.Aggressive);
|
||||
me.RemoveUnitFlag(UnitFlags.Uninteractible);
|
||||
DoZoneInCombat();
|
||||
});
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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.Entities;
|
||||
using Game.Maps;
|
||||
using Game.Scripting;
|
||||
using System;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan
|
||||
{
|
||||
struct DataTypes
|
||||
{
|
||||
public const uint Attumen = 0;
|
||||
public const uint Moroes = 1;
|
||||
public const uint MaidenOfVirtue = 2;
|
||||
public const uint OptionalBoss = 3;
|
||||
public const uint OperaPerformance = 4;
|
||||
public const uint Curator = 5;
|
||||
public const uint Aran = 6;
|
||||
public const uint Terestian = 7;
|
||||
public const uint Netherspite = 8;
|
||||
public const uint Chess = 9;
|
||||
public const uint Malchezzar = 10;
|
||||
public const uint Nightbane = 11;
|
||||
|
||||
public const uint OperaOzDeathcount = 14;
|
||||
|
||||
public const uint Kilrek = 15;
|
||||
public const uint GoCurtains = 18;
|
||||
public const uint GoStagedoorleft = 19;
|
||||
public const uint GoStagedoorright = 20;
|
||||
public const uint GoLibraryDoor = 21;
|
||||
public const uint GoMassiveDoor = 22;
|
||||
public const uint GoNetherDoor = 23;
|
||||
public const uint GoGameDoor = 24;
|
||||
public const uint GoGameExitDoor = 25;
|
||||
|
||||
public const uint ImageOfMedivh = 26;
|
||||
public const uint MastersTerraceDoor1 = 27;
|
||||
public const uint MastersTerraceDoor2 = 28;
|
||||
public const uint GoSideEntranceDoor = 29;
|
||||
public const uint GoBlackenedUrn = 30;
|
||||
}
|
||||
|
||||
struct CreatureIds
|
||||
{
|
||||
public const uint HyakissTheLurker = 16179;
|
||||
public const uint RokadTheRavager = 16181;
|
||||
public const uint ShadikithTheGlider = 16180;
|
||||
public const uint TerestianIllhoof = 15688;
|
||||
public const uint Moroes = 15687;
|
||||
public const uint Nightbane = 17225;
|
||||
public const uint AttumenUnmounted = 15550;
|
||||
public const uint AttumenMounted = 16152;
|
||||
public const uint Midnight = 16151;
|
||||
|
||||
// Trash
|
||||
public const uint ColdmistWidow = 16171;
|
||||
public const uint ColdmistStalker = 16170;
|
||||
public const uint Shadowbat = 16173;
|
||||
public const uint VampiricShadowbat = 16175;
|
||||
public const uint GreaterShadowbat = 16174;
|
||||
public const uint PhaseHound = 16178;
|
||||
public const uint Dreadbeast = 16177;
|
||||
public const uint Shadowbeast = 16176;
|
||||
public const uint Kilrek = 17229;
|
||||
}
|
||||
|
||||
struct GameObjectIds
|
||||
{
|
||||
public const uint StageCurtain = 183932;
|
||||
public const uint StageDoorLeft = 184278;
|
||||
public const uint StageDoorRight = 184279;
|
||||
public const uint PrivateLibraryDoor = 184517;
|
||||
public const uint MassiveDoor = 185521;
|
||||
public const uint GamesmanHallDoor = 184276;
|
||||
public const uint GamesmanHallExitDoor = 184277;
|
||||
public const uint NetherspaceDoor = 185134;
|
||||
public const uint MastersTerraceDoor = 184274;
|
||||
public const uint MastersTerraceDoor2 = 184280;
|
||||
public const uint SideEntranceDoor = 184275;
|
||||
public const uint DustCoveredChest = 185119;
|
||||
public const uint BlackenedUrn = 194092;
|
||||
}
|
||||
|
||||
enum KZMisc
|
||||
{
|
||||
OptionalBossRequiredDeathCount = 50
|
||||
}
|
||||
|
||||
[Script]
|
||||
class instance_karazhan : InstanceMapScript
|
||||
{
|
||||
public static Position[] OptionalSpawn =
|
||||
{
|
||||
new Position(-10960.981445f, -1940.138428f, 46.178097f, 4.12f), // Hyakiss the Lurker
|
||||
new Position(-10945.769531f, -2040.153320f, 49.474438f, 0.077f), // Shadikith the Glider
|
||||
new Position(-10899.903320f, -2085.573730f, 49.474449f, 1.38f) // Rokad the Ravager
|
||||
};
|
||||
|
||||
public instance_karazhan() : base(nameof(instance_karazhan), 532) { }
|
||||
|
||||
class instance_karazhan_InstanceMapScript : InstanceScript
|
||||
{
|
||||
uint OperaEvent;
|
||||
uint OzDeathCount;
|
||||
uint OptionalBossCount;
|
||||
ObjectGuid CurtainGUID;
|
||||
ObjectGuid StageDoorLeftGUID;
|
||||
ObjectGuid StageDoorRightGUID;
|
||||
ObjectGuid KilrekGUID;
|
||||
ObjectGuid TerestianGUID;
|
||||
ObjectGuid MoroesGUID;
|
||||
ObjectGuid NightbaneGUID;
|
||||
ObjectGuid LibraryDoor; // Door at Shade of Aran
|
||||
ObjectGuid MassiveDoor; // Door at Netherspite
|
||||
ObjectGuid SideEntranceDoor; // Side Entrance
|
||||
ObjectGuid GamesmansDoor; // Door before Chess
|
||||
ObjectGuid GamesmansExitDoor; // Door after Chess
|
||||
ObjectGuid NetherspaceDoor; // Door at Malchezaar
|
||||
ObjectGuid[] MastersTerraceDoor = new ObjectGuid[2];
|
||||
ObjectGuid ImageGUID;
|
||||
ObjectGuid DustCoveredChest;
|
||||
ObjectGuid BlackenedUrnGUID;
|
||||
|
||||
public instance_karazhan_InstanceMapScript(InstanceMap map) : base(map)
|
||||
{
|
||||
SetHeaders("KZ");
|
||||
SetBossNumber(12);
|
||||
|
||||
// 1 - Oz, 2 - Hood, 3 - Raj, this never gets altered.
|
||||
OperaEvent = RandomHelper.URand(1, 3);
|
||||
OzDeathCount = 0;
|
||||
OptionalBossCount = 0;
|
||||
}
|
||||
|
||||
public override void OnCreatureCreate(Creature creature)
|
||||
{
|
||||
switch (creature.GetEntry())
|
||||
{
|
||||
case CreatureIds.Kilrek:
|
||||
KilrekGUID = creature.GetGUID();
|
||||
break;
|
||||
case CreatureIds.TerestianIllhoof:
|
||||
TerestianGUID = creature.GetGUID();
|
||||
break;
|
||||
case CreatureIds.Moroes:
|
||||
MoroesGUID = creature.GetGUID();
|
||||
break;
|
||||
case CreatureIds.Nightbane:
|
||||
NightbaneGUID = creature.GetGUID();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnUnitDeath(Unit unit)
|
||||
{
|
||||
Creature creature = unit.ToCreature();
|
||||
if (!creature)
|
||||
return;
|
||||
|
||||
switch (creature.GetEntry())
|
||||
{
|
||||
case CreatureIds.ColdmistWidow:
|
||||
case CreatureIds.ColdmistStalker:
|
||||
case CreatureIds.Shadowbat:
|
||||
case CreatureIds.VampiricShadowbat:
|
||||
case CreatureIds.GreaterShadowbat:
|
||||
case CreatureIds.PhaseHound:
|
||||
case CreatureIds.Dreadbeast:
|
||||
case CreatureIds.Shadowbeast:
|
||||
if (GetBossState(DataTypes.OptionalBoss) == EncounterState.ToBeDecided)
|
||||
{
|
||||
++OptionalBossCount;
|
||||
if (OptionalBossCount == (uint)KZMisc.OptionalBossRequiredDeathCount)
|
||||
{
|
||||
switch (RandomHelper.URand(CreatureIds.HyakissTheLurker, CreatureIds.RokadTheRavager))
|
||||
{
|
||||
case CreatureIds.HyakissTheLurker:
|
||||
instance.SummonCreature(CreatureIds.HyakissTheLurker, OptionalSpawn[0]);
|
||||
break;
|
||||
case CreatureIds.ShadikithTheGlider:
|
||||
instance.SummonCreature(CreatureIds.ShadikithTheGlider, OptionalSpawn[1]);
|
||||
break;
|
||||
case CreatureIds.RokadTheRavager:
|
||||
instance.SummonCreature(CreatureIds.RokadTheRavager, OptionalSpawn[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetData(uint type, uint data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.OperaOzDeathcount:
|
||||
if (data == (uint)EncounterState.Special)
|
||||
++OzDeathCount;
|
||||
else if (data == (uint)EncounterState.InProgress)
|
||||
OzDeathCount = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SetBossState(uint type, EncounterState state)
|
||||
{
|
||||
if (!base.SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.OperaPerformance:
|
||||
if (state == EncounterState.Done)
|
||||
{
|
||||
HandleGameObject(StageDoorLeftGUID, true);
|
||||
HandleGameObject(StageDoorRightGUID, true);
|
||||
GameObject sideEntrance = instance.GetGameObject(SideEntranceDoor);
|
||||
if (sideEntrance)
|
||||
sideEntrance.RemoveFlag(GameObjectFlags.Locked);
|
||||
UpdateEncounterStateForKilledCreature(16812, null);
|
||||
}
|
||||
break;
|
||||
case DataTypes.Chess:
|
||||
if (state == EncounterState.Done)
|
||||
DoRespawnGameObject(DustCoveredChest, TimeSpan.FromHours(24));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SetGuidData(uint type, ObjectGuid data)
|
||||
{
|
||||
if (type == DataTypes.ImageOfMedivh)
|
||||
ImageGUID = data;
|
||||
}
|
||||
|
||||
public override void OnGameObjectCreate(GameObject go)
|
||||
{
|
||||
switch (go.GetEntry())
|
||||
{
|
||||
case GameObjectIds.StageCurtain:
|
||||
CurtainGUID = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.StageDoorLeft:
|
||||
StageDoorLeftGUID = go.GetGUID();
|
||||
if (GetBossState(DataTypes.OperaPerformance) == EncounterState.Done)
|
||||
go.SetGoState(GameObjectState.Active);
|
||||
break;
|
||||
case GameObjectIds.StageDoorRight:
|
||||
StageDoorRightGUID = go.GetGUID();
|
||||
if (GetBossState(DataTypes.OperaPerformance) == EncounterState.Done)
|
||||
go.SetGoState(GameObjectState.Active);
|
||||
break;
|
||||
case GameObjectIds.PrivateLibraryDoor:
|
||||
LibraryDoor = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.MassiveDoor:
|
||||
MassiveDoor = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.GamesmanHallDoor:
|
||||
GamesmansDoor = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.GamesmanHallExitDoor:
|
||||
GamesmansExitDoor = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.NetherspaceDoor:
|
||||
NetherspaceDoor = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.MastersTerraceDoor:
|
||||
MastersTerraceDoor[0] = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.MastersTerraceDoor2:
|
||||
MastersTerraceDoor[1] = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.SideEntranceDoor:
|
||||
SideEntranceDoor = go.GetGUID();
|
||||
if (GetBossState(DataTypes.OperaPerformance) == EncounterState.Done)
|
||||
go.SetFlag(GameObjectFlags.Locked);
|
||||
else
|
||||
go.RemoveFlag(GameObjectFlags.Locked);
|
||||
break;
|
||||
case GameObjectIds.DustCoveredChest:
|
||||
DustCoveredChest = go.GetGUID();
|
||||
break;
|
||||
case GameObjectIds.BlackenedUrn:
|
||||
BlackenedUrnGUID = go.GetGUID();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (OperaEvent)
|
||||
{
|
||||
/// @todo Set Object visibilities for Opera based on performance
|
||||
case 1:
|
||||
break;
|
||||
|
||||
case 2:
|
||||
break;
|
||||
|
||||
case 3:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override uint GetData(uint type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.OperaPerformance:
|
||||
return OperaEvent;
|
||||
case DataTypes.OperaOzDeathcount:
|
||||
return OzDeathCount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override ObjectGuid GetGuidData(uint type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.Kilrek:
|
||||
return KilrekGUID;
|
||||
case DataTypes.Terestian:
|
||||
return TerestianGUID;
|
||||
case DataTypes.Moroes:
|
||||
return MoroesGUID;
|
||||
case DataTypes.Nightbane:
|
||||
return NightbaneGUID;
|
||||
case DataTypes.GoStagedoorleft:
|
||||
return StageDoorLeftGUID;
|
||||
case DataTypes.GoStagedoorright:
|
||||
return StageDoorRightGUID;
|
||||
case DataTypes.GoCurtains:
|
||||
return CurtainGUID;
|
||||
case DataTypes.GoLibraryDoor:
|
||||
return LibraryDoor;
|
||||
case DataTypes.GoMassiveDoor:
|
||||
return MassiveDoor;
|
||||
case DataTypes.GoSideEntranceDoor:
|
||||
return SideEntranceDoor;
|
||||
case DataTypes.GoGameDoor:
|
||||
return GamesmansDoor;
|
||||
case DataTypes.GoGameExitDoor:
|
||||
return GamesmansExitDoor;
|
||||
case DataTypes.GoNetherDoor:
|
||||
return NetherspaceDoor;
|
||||
case DataTypes.MastersTerraceDoor1:
|
||||
return MastersTerraceDoor[0];
|
||||
case DataTypes.MastersTerraceDoor2:
|
||||
return MastersTerraceDoor[1];
|
||||
case DataTypes.ImageOfMedivh:
|
||||
return ImageGUID;
|
||||
case DataTypes.GoBlackenedUrn:
|
||||
return BlackenedUrnGUID;
|
||||
}
|
||||
|
||||
return ObjectGuid.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public override InstanceScript GetInstanceScript(InstanceMap map)
|
||||
{
|
||||
return new instance_karazhan_InstanceMapScript(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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 Game.AI;
|
||||
using Game.Entities;
|
||||
using Game.Scripting;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.MaidenOfVirtue
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint Repentance = 29511;
|
||||
public const uint Holyfire = 29522;
|
||||
public const uint Holywrath = 32445;
|
||||
public const uint Holyground = 29523;
|
||||
public const uint Berserk = 26662;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayAggro = 0;
|
||||
public const uint SaySlay = 1;
|
||||
public const uint SayRepentance = 2;
|
||||
public const uint SayDeath = 3;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_maiden_of_virtue : BossAI
|
||||
{
|
||||
public boss_maiden_of_virtue(Creature creature) : base(creature, DataTypes.MaidenOfVirtue) { }
|
||||
|
||||
public override void KilledUnit(Unit Victim)
|
||||
{
|
||||
if (RandomHelper.randChance(50))
|
||||
Talk(TextIds.SaySlay);
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
base.JustEngagedWith(who);
|
||||
Talk(TextIds.SayAggro);
|
||||
|
||||
DoCastSelf(SpellIds.Holyground, new CastSpellExtraArgs(true));
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(33), TimeSpan.FromSeconds(45), task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Repentance);
|
||||
Talk(TextIds.SayRepentance);
|
||||
task.Repeat(TimeSpan.FromSeconds(35));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(8), task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 50, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.Holyfire);
|
||||
task.Repeat(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(19));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(25), task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 80, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.Holywrath);
|
||||
task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(25));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromMinutes(10), task =>
|
||||
{
|
||||
DoCastSelf(SpellIds.Berserk, new CastSpellExtraArgs(true));
|
||||
});
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, () => DoMeleeAttackIfReady());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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.Scripting;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.Midnight
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
// Attumen
|
||||
public const uint Shadowcleave = 29832;
|
||||
public const uint IntangiblePresence = 29833;
|
||||
public const uint SpawnSmoke = 10389;
|
||||
public const uint Charge = 29847;
|
||||
|
||||
// Midnight
|
||||
public const uint Knockdown = 29711;
|
||||
public const uint SummonAttumen = 29714;
|
||||
public const uint Mount = 29770;
|
||||
public const uint SummonAttumenMounted = 29799;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayKill = 0;
|
||||
public const uint SayRandom = 1;
|
||||
public const uint SayDisarmed = 2;
|
||||
public const uint SayMidnightKill = 3;
|
||||
public const uint SayAppear = 4;
|
||||
public const uint SayMount = 5;
|
||||
|
||||
public const uint SayDeath = 3;
|
||||
|
||||
// Midnight
|
||||
public const uint EmoteCallAttumen = 0;
|
||||
public const uint EmoteMountUp = 1;
|
||||
}
|
||||
|
||||
enum Phases
|
||||
{
|
||||
None,
|
||||
AttumenEngages,
|
||||
Mounted
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_attumen : BossAI
|
||||
{
|
||||
ObjectGuid _midnightGUID;
|
||||
Phases _phase;
|
||||
|
||||
public boss_attumen(Creature creature) : base(creature, DataTypes.Attumen)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_midnightGUID.Clear();
|
||||
_phase = Phases.None;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
Creature midnight = ObjectAccessor.GetCreature(me, _midnightGUID);
|
||||
if (midnight)
|
||||
base._DespawnAtEvade(TimeSpan.FromSeconds(10), midnight);
|
||||
|
||||
me.DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
public override void ScheduleTasks()
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(25), task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Shadowcleave);
|
||||
task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(25));
|
||||
});
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(45), task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.IntangiblePresence);
|
||||
|
||||
task.Repeat(TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(45));
|
||||
});
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(60), task =>
|
||||
{
|
||||
Talk(TextIds.SayRandom);
|
||||
task.Repeat(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(60));
|
||||
});
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
|
||||
{
|
||||
// Attumen does not die until he mounts Midnight, let health fall to 1 and prevent further damage.
|
||||
if (damage >= me.GetHealth() && _phase != Phases.Mounted)
|
||||
damage = (uint)(me.GetHealth() - 1);
|
||||
|
||||
if (_phase == Phases.AttumenEngages && me.HealthBelowPctDamaged(25, damage))
|
||||
{
|
||||
_phase = Phases.None;
|
||||
|
||||
Creature midnight = ObjectAccessor.GetCreature(me, _midnightGUID);
|
||||
if (midnight)
|
||||
midnight.GetAI().DoCastAOE(SpellIds.Mount, new CastSpellExtraArgs(true));
|
||||
}
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
Talk(TextIds.SayKill);
|
||||
}
|
||||
|
||||
public override void JustSummoned(Creature summon)
|
||||
{
|
||||
if (summon.GetEntry() == CreatureIds.AttumenMounted)
|
||||
{
|
||||
Creature midnight = ObjectAccessor.GetCreature(me, _midnightGUID);
|
||||
if (midnight)
|
||||
{
|
||||
if (midnight.GetHealth() > me.GetHealth())
|
||||
summon.SetHealth(midnight.GetHealth());
|
||||
else
|
||||
summon.SetHealth(me.GetHealth());
|
||||
|
||||
summon.GetAI().DoZoneInCombat();
|
||||
summon.GetAI().SetGUID(_midnightGUID, (int)CreatureIds.Midnight);
|
||||
}
|
||||
}
|
||||
|
||||
base.JustSummoned(summon);
|
||||
}
|
||||
|
||||
public override void IsSummonedBy(WorldObject summoner)
|
||||
{
|
||||
if (summoner.GetEntry() == CreatureIds.Midnight)
|
||||
_phase = Phases.AttumenEngages;
|
||||
|
||||
if (summoner.GetEntry() == CreatureIds.AttumenUnmounted)
|
||||
{
|
||||
_phase = Phases.Mounted;
|
||||
DoCastSelf(SpellIds.SpawnSmoke);
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(25), task =>
|
||||
{
|
||||
Unit target = null;
|
||||
List<Unit> targetList = new();
|
||||
|
||||
foreach (var refe in me.GetThreatManager().GetSortedThreatList())
|
||||
{
|
||||
target = refe.GetVictim();
|
||||
if (target && !target.IsWithinDist(me, 8.00f, false) && target.IsWithinDist(me, 25.0f, false))
|
||||
targetList.Add(target);
|
||||
|
||||
target = null;
|
||||
}
|
||||
|
||||
if (!targetList.Empty())
|
||||
target = targetList.SelectRandom();
|
||||
|
||||
DoCast(target, SpellIds.Charge);
|
||||
task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(25));
|
||||
});
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(35), task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Knockdown);
|
||||
task.Repeat(TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(35));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
Unit midnight = Global.ObjAccessor.GetUnit(me, _midnightGUID);
|
||||
if (midnight)
|
||||
midnight.KillSelf();
|
||||
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
public override void SetGUID(ObjectGuid guid, int id)
|
||||
{
|
||||
if (id == CreatureIds.Midnight)
|
||||
_midnightGUID = guid;
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim() && _phase != Phases.None)
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, () => DoMeleeAttackIfReady());
|
||||
}
|
||||
|
||||
public override void SpellHit(WorldObject caster, SpellInfo spellInfo)
|
||||
{
|
||||
if (spellInfo.Mechanic == Mechanics.Disarm)
|
||||
Talk(TextIds.SayDisarmed);
|
||||
|
||||
if (spellInfo.Id == SpellIds.Mount)
|
||||
{
|
||||
Creature midnight = ObjectAccessor.GetCreature(me, _midnightGUID);
|
||||
if (midnight)
|
||||
{
|
||||
_phase = Phases.None;
|
||||
_scheduler.CancelAll();
|
||||
|
||||
midnight.AttackStop();
|
||||
midnight.RemoveAllAttackers();
|
||||
midnight.SetReactState(ReactStates.Passive);
|
||||
midnight.GetMotionMaster().MoveFollow(me, 2.0f, 0.0f);
|
||||
midnight.GetAI().Talk(TextIds.EmoteMountUp);
|
||||
|
||||
me.AttackStop();
|
||||
me.RemoveAllAttackers();
|
||||
me.SetReactState(ReactStates.Passive);
|
||||
me.GetMotionMaster().MoveFollow(midnight, 2.0f, 0.0f);
|
||||
Talk(TextIds.SayMount);
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
|
||||
{
|
||||
Creature midnight = ObjectAccessor.GetCreature(me, _midnightGUID);
|
||||
if (midnight)
|
||||
{
|
||||
if (me.IsWithinDist2d(midnight, 5.0f))
|
||||
{
|
||||
DoCastAOE(SpellIds.SummonAttumenMounted);
|
||||
me.SetVisible(false);
|
||||
me.GetMotionMaster().Clear();
|
||||
midnight.SetVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
midnight.GetMotionMaster().MoveFollow(me, 2.0f, 0.0f);
|
||||
me.GetMotionMaster().MoveFollow(midnight, 2.0f, 0.0f);
|
||||
task.Repeat();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_midnight : BossAI
|
||||
{
|
||||
ObjectGuid _attumenGUID;
|
||||
Phases _phase;
|
||||
|
||||
public boss_midnight(Creature creature) : base(creature, DataTypes.Attumen)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_phase = Phases.None;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
base.Reset();
|
||||
me.SetVisible(true);
|
||||
me.SetReactState(ReactStates.Defensive);
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
|
||||
{
|
||||
// Midnight never dies, let health fall to 1 and prevent further damage.
|
||||
if (damage >= me.GetHealth())
|
||||
damage = (uint)(me.GetHealth() - 1);
|
||||
|
||||
if (_phase == Phases.None && me.HealthBelowPctDamaged(95, damage))
|
||||
{
|
||||
_phase = Phases.AttumenEngages;
|
||||
Talk(TextIds.EmoteCallAttumen);
|
||||
DoCastAOE(SpellIds.SummonAttumen);
|
||||
}
|
||||
else if (_phase == Phases.AttumenEngages && me.HealthBelowPctDamaged(25, damage))
|
||||
{
|
||||
_phase = Phases.Mounted;
|
||||
DoCastAOE(SpellIds.Mount, new CastSpellExtraArgs(true));
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustSummoned(Creature summon)
|
||||
{
|
||||
if (summon.GetEntry() == CreatureIds.AttumenUnmounted)
|
||||
{
|
||||
_attumenGUID = summon.GetGUID();
|
||||
summon.GetAI().SetGUID(me.GetGUID(), (int)CreatureIds.Midnight);
|
||||
summon.GetAI().AttackStart(me.GetVictim());
|
||||
summon.GetAI().Talk(TextIds.SayAppear);
|
||||
}
|
||||
|
||||
base.JustSummoned(summon);
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
base.JustEngagedWith(who);
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(25), task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Knockdown);
|
||||
task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(25));
|
||||
});
|
||||
}
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
base._DespawnAtEvade(TimeSpan.FromSeconds(10));
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
if (_phase == Phases.AttumenEngages)
|
||||
{
|
||||
Unit unit = Global.ObjAccessor.GetUnit(me, _attumenGUID);
|
||||
if (unit)
|
||||
Talk(TextIds.SayMidnightKill, unit);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim() || _phase == Phases.Mounted)
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, () => DoMeleeAttackIfReady());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,737 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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.Linq;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.Moroes
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint Vanish = 29448;
|
||||
public const uint Garrote = 37066;
|
||||
public const uint Blind = 34694;
|
||||
public const uint Gouge = 29425;
|
||||
public const uint Frenzy = 37023;
|
||||
|
||||
// Adds
|
||||
public const uint Manaburn = 29405;
|
||||
public const uint Mindfly = 29570;
|
||||
public const uint Swpain = 34441;
|
||||
public const uint Shadowform = 29406;
|
||||
|
||||
public const uint Hammerofjustice = 13005;
|
||||
public const uint Judgementofcommand = 29386;
|
||||
public const uint Sealofcommand = 29385;
|
||||
|
||||
public const uint Dispelmagic = 15090;
|
||||
public const uint Greaterheal = 29564;
|
||||
public const uint Holyfire = 29563;
|
||||
public const uint Pwshield = 29408;
|
||||
|
||||
public const uint Cleanse = 29380;
|
||||
public const uint Greaterblessofmight = 29381;
|
||||
public const uint Holylight = 29562;
|
||||
public const uint Divineshield = 41367;
|
||||
|
||||
public const uint Hamstring = 9080;
|
||||
public const uint Mortalstrike = 29572;
|
||||
public const uint Whirlwind = 29573;
|
||||
|
||||
public const uint Disarm = 8379;
|
||||
public const uint Heroicstrike = 29567;
|
||||
public const uint Shieldbash = 11972;
|
||||
public const uint Shieldwall = 29390;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayAggro = 0;
|
||||
public const uint SaySpecial = 1;
|
||||
public const uint SayKill = 2;
|
||||
public const uint SayDeath = 3;
|
||||
}
|
||||
|
||||
struct MiscConst
|
||||
{
|
||||
public const uint GroupNonEnrage = 1;
|
||||
|
||||
public static Position[] Locations =
|
||||
{
|
||||
new Position(-10991.0f, -1884.33f, 81.73f, 0.614315f),
|
||||
new Position(-10989.4f, -1885.88f, 81.73f, 0.904913f),
|
||||
new Position(-10978.1f, -1887.07f, 81.73f, 2.035550f),
|
||||
new Position(-10975.9f, -1885.81f, 81.73f, 2.253890f)
|
||||
};
|
||||
|
||||
public static uint[] Adds =
|
||||
{
|
||||
17007,
|
||||
19872,
|
||||
19873,
|
||||
19874,
|
||||
19875,
|
||||
19876,
|
||||
};
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_moroes : BossAI
|
||||
{
|
||||
public ObjectGuid[] AddGUID = new ObjectGuid[4];
|
||||
uint[] AddId = new uint[4];
|
||||
|
||||
bool InVanish;
|
||||
bool Enrage;
|
||||
|
||||
public boss_moroes(Creature creature) : base(creature, DataTypes.Moroes)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
Enrage = false;
|
||||
InVanish = false;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
if (me.IsAlive())
|
||||
SpawnAdds();
|
||||
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
base.JustEngagedWith(who);
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(5), MiscConst.GroupNonEnrage, task =>
|
||||
{
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
{
|
||||
if (!AddGUID[i].IsEmpty())
|
||||
{
|
||||
Creature temp = ObjectAccessor.GetCreature(me, AddGUID[i]);
|
||||
if (temp && temp.IsAlive())
|
||||
if (!temp.GetVictim())
|
||||
temp.GetAI().AttackStart(me.GetVictim());
|
||||
}
|
||||
}
|
||||
task.Repeat();
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(23), MiscConst.GroupNonEnrage, task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Gouge);
|
||||
task.Repeat(TimeSpan.FromSeconds(40));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(30), MiscConst.GroupNonEnrage, task =>
|
||||
{
|
||||
DoCast(me, SpellIds.Vanish);
|
||||
InVanish = true;
|
||||
|
||||
task.Schedule(TimeSpan.FromSeconds(5), garroteTask =>
|
||||
{
|
||||
Talk(TextIds.SaySpecial);
|
||||
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100, true);
|
||||
if (target)
|
||||
target.CastSpell(target, SpellIds.Garrote, true);
|
||||
|
||||
InVanish = false;
|
||||
});
|
||||
|
||||
task.Repeat();
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(35), MiscConst.GroupNonEnrage, task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.MinDistance, 0, 0.0f, true, false);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.Blind);
|
||||
task.Repeat(TimeSpan.FromSeconds(40));
|
||||
});
|
||||
|
||||
Talk(TextIds.SayAggro);
|
||||
AddsAttack();
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
Talk(TextIds.SayKill);
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
|
||||
base.JustDied(killer);
|
||||
|
||||
DeSpawnAdds();
|
||||
|
||||
//remove aura from spell Garrote when Moroes dies
|
||||
instance.DoRemoveAurasDueToSpellOnPlayers(SpellIds.Garrote);
|
||||
}
|
||||
|
||||
void SpawnAdds()
|
||||
{
|
||||
DeSpawnAdds();
|
||||
|
||||
if (isAddlistEmpty())
|
||||
{
|
||||
List<uint> AddList = MiscConst.Adds.ToList();
|
||||
AddList.RandomResize(4);
|
||||
|
||||
byte i = 0;
|
||||
foreach (var entry in AddList)
|
||||
{
|
||||
Creature creature = me.SummonCreature(entry, MiscConst.Locations[i], TempSummonType.CorpseTimedDespawn, TimeSpan.FromSeconds(10));
|
||||
if (creature)
|
||||
{
|
||||
AddGUID[i] = creature.GetGUID();
|
||||
AddId[i] = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
{
|
||||
Creature creature = me.SummonCreature(AddId[i], MiscConst.Locations[i], TempSummonType.CorpseTimedDespawn, TimeSpan.FromSeconds(10));
|
||||
if (creature)
|
||||
AddGUID[i] = creature.GetGUID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isAddlistEmpty()
|
||||
{
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
if (AddId[i] == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeSpawnAdds()
|
||||
{
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
{
|
||||
if (!AddGUID[i].IsEmpty())
|
||||
{
|
||||
Creature temp = ObjectAccessor.GetCreature(me, AddGUID[i]);
|
||||
if (temp)
|
||||
temp.DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddsAttack()
|
||||
{
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
{
|
||||
if (!AddGUID[i].IsEmpty())
|
||||
{
|
||||
Creature temp = ObjectAccessor.GetCreature((me), AddGUID[i]);
|
||||
if (temp && temp.IsAlive())
|
||||
{
|
||||
temp.GetAI().AttackStart(me.GetVictim());
|
||||
DoZoneInCombat(temp);
|
||||
}
|
||||
else
|
||||
EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!Enrage && HealthBelowPct(30))
|
||||
{
|
||||
DoCast(me, SpellIds.Frenzy);
|
||||
Enrage = true;
|
||||
_scheduler.CancelGroup(MiscConst.GroupNonEnrage);
|
||||
}
|
||||
|
||||
_scheduler.Update(diff, () =>
|
||||
{
|
||||
if (!InVanish)
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_moroes_guest : ScriptedAI
|
||||
{
|
||||
InstanceScript instance;
|
||||
|
||||
ObjectGuid[] GuestGUID = new ObjectGuid[4];
|
||||
|
||||
public boss_moroes_guest(Creature creature) : base(creature)
|
||||
{
|
||||
instance = creature.GetInstanceScript();
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
instance.SetBossState(DataTypes.Moroes, EncounterState.NotStarted);
|
||||
}
|
||||
|
||||
public void AcquireGUID()
|
||||
{
|
||||
Creature Moroes = ObjectAccessor.GetCreature(me, instance.GetGuidData(DataTypes.Moroes));
|
||||
if (Moroes)
|
||||
{
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
{
|
||||
ObjectGuid Guid = Moroes.GetAI<boss_moroes>().AddGUID[i];
|
||||
if (!Guid.IsEmpty())
|
||||
GuestGUID[i] = Guid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Unit SelectGuestTarget()
|
||||
{
|
||||
ObjectGuid TempGUID = GuestGUID[RandomHelper.Rand32() % 4];
|
||||
if (!TempGUID.IsEmpty())
|
||||
{
|
||||
Unit unit = Global.ObjAccessor.GetUnit(me, TempGUID);
|
||||
if (unit && unit.IsAlive())
|
||||
return unit;
|
||||
}
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (instance.GetBossState(DataTypes.Moroes) != EncounterState.InProgress)
|
||||
EnterEvadeMode();
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_baroness_dorothea_millstipe : boss_moroes_guest
|
||||
{
|
||||
//Shadow Priest
|
||||
public boss_baroness_dorothea_millstipe(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
ManaBurn_Timer = 7000;
|
||||
MindFlay_Timer = 1000;
|
||||
ShadowWordPain_Timer = 6000;
|
||||
}
|
||||
|
||||
uint ManaBurn_Timer;
|
||||
uint MindFlay_Timer;
|
||||
uint ShadowWordPain_Timer;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
DoCast(me, SpellIds.Shadowform, new CastSpellExtraArgs(true));
|
||||
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
base.UpdateAI(diff);
|
||||
|
||||
if (MindFlay_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Mindfly);
|
||||
MindFlay_Timer = 12000; // 3 sec channeled
|
||||
}
|
||||
else MindFlay_Timer -= diff;
|
||||
|
||||
if (ManaBurn_Timer <= diff)
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100, true);
|
||||
if (target)
|
||||
if (target.GetPowerType() == PowerType.Mana)
|
||||
DoCast(target, SpellIds.Manaburn);
|
||||
ManaBurn_Timer = 5000; // 3 sec cast
|
||||
}
|
||||
else ManaBurn_Timer -= diff;
|
||||
|
||||
if (ShadowWordPain_Timer <= diff)
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100, true);
|
||||
if (target)
|
||||
{
|
||||
DoCast(target, SpellIds.Swpain);
|
||||
ShadowWordPain_Timer = 7000;
|
||||
}
|
||||
}
|
||||
else ShadowWordPain_Timer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_baron_rafe_dreuger : boss_moroes_guest
|
||||
{
|
||||
//Retr Pally
|
||||
public boss_baron_rafe_dreuger(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
HammerOfJustice_Timer = 1000;
|
||||
SealOfCommand_Timer = 7000;
|
||||
JudgementOfCommand_Timer = SealOfCommand_Timer + 29000;
|
||||
}
|
||||
|
||||
uint HammerOfJustice_Timer;
|
||||
uint SealOfCommand_Timer;
|
||||
uint JudgementOfCommand_Timer;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
base.UpdateAI(diff);
|
||||
|
||||
if (SealOfCommand_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SpellIds.Sealofcommand);
|
||||
SealOfCommand_Timer = 32000;
|
||||
JudgementOfCommand_Timer = 29000;
|
||||
}
|
||||
else SealOfCommand_Timer -= diff;
|
||||
|
||||
if (JudgementOfCommand_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Judgementofcommand);
|
||||
JudgementOfCommand_Timer = SealOfCommand_Timer + 29000;
|
||||
}
|
||||
else JudgementOfCommand_Timer -= diff;
|
||||
|
||||
if (HammerOfJustice_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Hammerofjustice);
|
||||
HammerOfJustice_Timer = 12000;
|
||||
}
|
||||
else HammerOfJustice_Timer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_lady_catriona_von_indi : boss_moroes_guest
|
||||
{
|
||||
//Holy Priest
|
||||
public boss_lady_catriona_von_indi(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
DispelMagic_Timer = 11000;
|
||||
GreaterHeal_Timer = 1500;
|
||||
HolyFire_Timer = 5000;
|
||||
PowerWordShield_Timer = 1000;
|
||||
}
|
||||
|
||||
uint DispelMagic_Timer;
|
||||
uint GreaterHeal_Timer;
|
||||
uint HolyFire_Timer;
|
||||
uint PowerWordShield_Timer;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
AcquireGUID();
|
||||
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
base.UpdateAI(diff);
|
||||
|
||||
if (PowerWordShield_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SpellIds.Pwshield);
|
||||
PowerWordShield_Timer = 15000;
|
||||
}
|
||||
else PowerWordShield_Timer -= diff;
|
||||
|
||||
if (GreaterHeal_Timer <= diff)
|
||||
{
|
||||
Unit target = SelectGuestTarget();
|
||||
|
||||
DoCast(target, SpellIds.Greaterheal);
|
||||
GreaterHeal_Timer = 17000;
|
||||
}
|
||||
else GreaterHeal_Timer -= diff;
|
||||
|
||||
if (HolyFire_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Holyfire);
|
||||
HolyFire_Timer = 22000;
|
||||
}
|
||||
else HolyFire_Timer -= diff;
|
||||
|
||||
if (DispelMagic_Timer <= diff)
|
||||
{
|
||||
Unit target = RandomHelper.RAND(SelectGuestTarget(), SelectTarget(SelectTargetMethod.Random, 0, 100, true));
|
||||
if (target)
|
||||
DoCast(target, SpellIds.Dispelmagic);
|
||||
|
||||
DispelMagic_Timer = 25000;
|
||||
}
|
||||
else DispelMagic_Timer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_lady_keira_berrybuck : boss_moroes_guest
|
||||
{
|
||||
//Holy Pally
|
||||
public boss_lady_keira_berrybuck(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
Cleanse_Timer = 13000;
|
||||
GreaterBless_Timer = 1000;
|
||||
HolyLight_Timer = 7000;
|
||||
DivineShield_Timer = 31000;
|
||||
}
|
||||
|
||||
uint Cleanse_Timer;
|
||||
uint GreaterBless_Timer;
|
||||
uint HolyLight_Timer;
|
||||
uint DivineShield_Timer;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
AcquireGUID();
|
||||
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
base.UpdateAI(diff);
|
||||
|
||||
if (DivineShield_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SpellIds.Divineshield);
|
||||
DivineShield_Timer = 31000;
|
||||
}
|
||||
else DivineShield_Timer -= diff;
|
||||
|
||||
if (HolyLight_Timer <= diff)
|
||||
{
|
||||
Unit target = SelectGuestTarget();
|
||||
|
||||
DoCast(target, SpellIds.Holylight);
|
||||
HolyLight_Timer = 10000;
|
||||
}
|
||||
else HolyLight_Timer -= diff;
|
||||
|
||||
if (GreaterBless_Timer <= diff)
|
||||
{
|
||||
Unit target = SelectGuestTarget();
|
||||
|
||||
DoCast(target, SpellIds.Greaterblessofmight);
|
||||
|
||||
GreaterBless_Timer = 50000;
|
||||
}
|
||||
else GreaterBless_Timer -= diff;
|
||||
|
||||
if (Cleanse_Timer <= diff)
|
||||
{
|
||||
Unit target = SelectGuestTarget();
|
||||
|
||||
DoCast(target, SpellIds.Cleanse);
|
||||
|
||||
Cleanse_Timer = 10000;
|
||||
}
|
||||
else Cleanse_Timer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_lord_robin_daris : boss_moroes_guest
|
||||
{
|
||||
//Arms Warr
|
||||
public boss_lord_robin_daris(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
Hamstring_Timer = 7000;
|
||||
MortalStrike_Timer = 10000;
|
||||
WhirlWind_Timer = 21000;
|
||||
}
|
||||
|
||||
uint Hamstring_Timer;
|
||||
uint MortalStrike_Timer;
|
||||
uint WhirlWind_Timer;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
base.UpdateAI(diff);
|
||||
|
||||
if (Hamstring_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Hamstring);
|
||||
Hamstring_Timer = 12000;
|
||||
}
|
||||
else Hamstring_Timer -= diff;
|
||||
|
||||
if (MortalStrike_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Mortalstrike);
|
||||
MortalStrike_Timer = 18000;
|
||||
}
|
||||
else MortalStrike_Timer -= diff;
|
||||
|
||||
if (WhirlWind_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SpellIds.Whirlwind);
|
||||
WhirlWind_Timer = 21000;
|
||||
}
|
||||
else WhirlWind_Timer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_lord_crispin_ference : boss_moroes_guest
|
||||
{
|
||||
//Arms Warr
|
||||
public boss_lord_crispin_ference(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
Disarm_Timer = 6000;
|
||||
HeroicStrike_Timer = 10000;
|
||||
ShieldBash_Timer = 8000;
|
||||
ShieldWall_Timer = 4000;
|
||||
}
|
||||
|
||||
uint Disarm_Timer;
|
||||
uint HeroicStrike_Timer;
|
||||
uint ShieldBash_Timer;
|
||||
uint ShieldWall_Timer;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
base.UpdateAI(diff);
|
||||
|
||||
if (Disarm_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Disarm);
|
||||
Disarm_Timer = 12000;
|
||||
}
|
||||
else Disarm_Timer -= diff;
|
||||
|
||||
if (HeroicStrike_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Heroicstrike);
|
||||
HeroicStrike_Timer = 10000;
|
||||
}
|
||||
else HeroicStrike_Timer -= diff;
|
||||
|
||||
if (ShieldBash_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Shieldbash);
|
||||
ShieldBash_Timer = 13000;
|
||||
}
|
||||
else ShieldBash_Timer -= diff;
|
||||
|
||||
if (ShieldWall_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SpellIds.Shieldwall);
|
||||
ShieldWall_Timer = 21000;
|
||||
}
|
||||
else ShieldWall_Timer -= diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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.Numerics;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.Netherspite
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint NetherburnAura = 30522;
|
||||
public const uint Voidzone = 37063;
|
||||
public const uint NetherInfusion = 38688;
|
||||
public const uint Netherbreath = 38523;
|
||||
public const uint BanishVisual = 39833;
|
||||
public const uint BanishRoot = 42716;
|
||||
public const uint Empowerment = 38549;
|
||||
public const uint NetherspiteRoar = 38684;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint EmotePhasePortal = 0;
|
||||
public const uint EmotePhaseBanish = 1;
|
||||
}
|
||||
|
||||
enum Portals
|
||||
{
|
||||
Red = 0, // Perseverence
|
||||
Green = 1, // Serenity
|
||||
Blue = 2 // Dominance
|
||||
}
|
||||
|
||||
struct MiscConst
|
||||
{
|
||||
public static Vector3[] PortalCoord =
|
||||
{
|
||||
new Vector3(-11195.353516f, -1613.237183f, 278.237258f), // Left side
|
||||
new Vector3(-11137.846680f, -1685.607422f, 278.239258f), // Right side
|
||||
new Vector3(-11094.493164f, -1591.969238f, 279.949188f) // Back side
|
||||
};
|
||||
|
||||
public static uint[] PortalID = { 17369, 17367, 17368 };
|
||||
public static uint[] PortalVisual = { 30487, 30490, 30491 };
|
||||
public static uint[] PortalBeam = { 30465, 30464, 30463 };
|
||||
public static uint[] PlayerBuff = { 30421, 30422, 30423 };
|
||||
public static uint[] NetherBuff = { 30466, 30467, 30468 };
|
||||
public static uint[] PlayerDebuff = { 38637, 38638, 38639 };
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_netherspite : ScriptedAI
|
||||
{
|
||||
InstanceScript instance;
|
||||
|
||||
bool PortalPhase;
|
||||
bool Berserk;
|
||||
uint PhaseTimer; // timer for phase switching
|
||||
uint VoidZoneTimer;
|
||||
uint NetherInfusionTimer; // berserking timer
|
||||
uint NetherbreathTimer;
|
||||
uint EmpowermentTimer;
|
||||
uint PortalTimer; // timer for beam checking
|
||||
ObjectGuid[] PortalGUID = new ObjectGuid[3]; // guid's of portals
|
||||
ObjectGuid[] BeamerGUID = new ObjectGuid[3]; // guid's of auxiliary beaming portals
|
||||
ObjectGuid[] BeamTarget = new ObjectGuid[3]; // guid's of portals' current targets
|
||||
|
||||
public boss_netherspite(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
instance = creature.GetInstanceScript();
|
||||
|
||||
PortalPhase = false;
|
||||
PhaseTimer = 0;
|
||||
EmpowermentTimer = 0;
|
||||
PortalTimer = 0;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
Berserk = false;
|
||||
NetherInfusionTimer = 540000;
|
||||
VoidZoneTimer = 15000;
|
||||
NetherbreathTimer = 3000;
|
||||
}
|
||||
|
||||
bool IsBetween(WorldObject u1, WorldObject target, WorldObject u2) // the in-line checker
|
||||
{
|
||||
if (!u1 || !u2 || !target)
|
||||
return false;
|
||||
|
||||
float xn, yn, xp, yp, xh, yh;
|
||||
xn = u1.GetPositionX();
|
||||
yn = u1.GetPositionY();
|
||||
xp = u2.GetPositionX();
|
||||
yp = u2.GetPositionY();
|
||||
xh = target.GetPositionX();
|
||||
yh = target.GetPositionY();
|
||||
|
||||
// check if target is between (not checking distance from the beam yet)
|
||||
if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp))
|
||||
return false;
|
||||
// check distance from the beam
|
||||
return (Math.Abs((xn - xp) * yh + (yp - yn) * xh - xn * yp + xp * yn) / dist(xn, yn, xp, yp) < 1.5f);
|
||||
}
|
||||
|
||||
float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance
|
||||
{
|
||||
return MathF.Sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb));
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
HandleDoors(true);
|
||||
DestroyPortals();
|
||||
}
|
||||
|
||||
void SummonPortals()
|
||||
{
|
||||
uint r = RandomHelper.Rand32() % 4;
|
||||
int[] pos = new int[3];
|
||||
pos[(int)Portals.Red] = ((r % 2) != 0 ? (r > 1 ? 2 : 1) : 0);
|
||||
pos[(int)Portals.Green] = ((r % 2) != 0 ? 0 : (r > 1 ? 2 : 1));
|
||||
pos[(int)Portals.Blue] = (r > 1 ? 1 : 2); // Blue Portal not on the left side (0)
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
Creature portal = me.SummonCreature(MiscConst.PortalID[i], MiscConst.PortalCoord[pos[i]].X, MiscConst.PortalCoord[pos[i]].Y, MiscConst.PortalCoord[pos[i]].Z, 0, TempSummonType.TimedDespawn, TimeSpan.FromMinutes(1));
|
||||
if (portal)
|
||||
{
|
||||
PortalGUID[i] = portal.GetGUID();
|
||||
portal.AddAura(MiscConst.PortalVisual[i], portal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DestroyPortals()
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
Creature portal = ObjectAccessor.GetCreature(me, PortalGUID[i]);
|
||||
if (portal)
|
||||
portal.DisappearAndDie();
|
||||
|
||||
Creature portal1 = ObjectAccessor.GetCreature(me, BeamerGUID[i]);
|
||||
if (portal1)
|
||||
portal1.DisappearAndDie();
|
||||
|
||||
PortalGUID[i].Clear();
|
||||
BeamTarget[i].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePortals() // Here we handle the beams' behavior
|
||||
{
|
||||
for (int j = 0; j < 3; ++j) // j = color
|
||||
{
|
||||
Creature portal = ObjectAccessor.GetCreature(me, PortalGUID[j]);
|
||||
if (portal)
|
||||
{
|
||||
// the one who's been cast upon before
|
||||
Unit current = Global.ObjAccessor.GetUnit(portal, BeamTarget[j]);
|
||||
// temporary store for the best suitable beam reciever
|
||||
Unit target = me;
|
||||
|
||||
var players = me.GetMap().GetPlayers();
|
||||
|
||||
// get the best suitable target
|
||||
foreach (var player in players)
|
||||
{
|
||||
if (player && player.IsAlive() // alive
|
||||
&& (!target || target.GetDistance2d(portal) > player.GetDistance2d(portal)) // closer than current best
|
||||
&& !player.HasAura(MiscConst.PlayerDebuff[j]) // not exhausted
|
||||
&& !player.HasAura(MiscConst.PlayerBuff[(j + 1) % 3]) // not on another beam
|
||||
&& !player.HasAura(MiscConst.PlayerBuff[(j + 2) % 3])
|
||||
&& IsBetween(me, player, portal)) // on the beam
|
||||
target = player;
|
||||
}
|
||||
|
||||
// buff the target
|
||||
if (target.IsPlayer())
|
||||
target.AddAura(MiscConst.PlayerBuff[j], target);
|
||||
else
|
||||
target.AddAura(MiscConst.NetherBuff[j], target);
|
||||
// cast visual beam on the chosen target if switched
|
||||
// simple target switching isn't working . using BeamerGUID to cast (workaround)
|
||||
if (!current || target != current)
|
||||
{
|
||||
BeamTarget[j] = target.GetGUID();
|
||||
// remove currently beaming portal
|
||||
Creature beamer = ObjectAccessor.GetCreature(portal, BeamerGUID[j]);
|
||||
if (beamer)
|
||||
{
|
||||
beamer.CastSpell(target, MiscConst.PortalBeam[j], false);
|
||||
beamer.DisappearAndDie();
|
||||
BeamerGUID[j].Clear();
|
||||
}
|
||||
// create new one and start beaming on the target
|
||||
Creature beamer1 = portal.SummonCreature(MiscConst.PortalID[j], portal.GetPositionX(), portal.GetPositionY(), portal.GetPositionZ(), portal.GetOrientation(), TempSummonType.TimedDespawn, TimeSpan.FromMinutes(1));
|
||||
if (beamer1)
|
||||
{
|
||||
beamer1.CastSpell(target, MiscConst.PortalBeam[j], false);
|
||||
BeamerGUID[j] = beamer1.GetGUID();
|
||||
}
|
||||
}
|
||||
// aggro target if Red Beam
|
||||
if (j == (int)Portals.Red && me.GetVictim() != target && target.IsPlayer())
|
||||
AddThreat(target, 100000.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchToPortalPhase()
|
||||
{
|
||||
me.RemoveAurasDueToSpell(SpellIds.BanishRoot);
|
||||
me.RemoveAurasDueToSpell(SpellIds.BanishVisual);
|
||||
SummonPortals();
|
||||
PhaseTimer = 60000;
|
||||
PortalPhase = true;
|
||||
PortalTimer = 10000;
|
||||
EmpowermentTimer = 10000;
|
||||
Talk(TextIds.EmotePhasePortal);
|
||||
}
|
||||
|
||||
void SwitchToBanishPhase()
|
||||
{
|
||||
me.RemoveAurasDueToSpell(SpellIds.Empowerment);
|
||||
me.RemoveAurasDueToSpell(SpellIds.NetherburnAura);
|
||||
DoCast(me, SpellIds.BanishVisual, new CastSpellExtraArgs(true));
|
||||
DoCast(me, SpellIds.BanishRoot, new CastSpellExtraArgs(true));
|
||||
DestroyPortals();
|
||||
PhaseTimer = 30000;
|
||||
PortalPhase = false;
|
||||
Talk(TextIds.EmotePhaseBanish);
|
||||
|
||||
for (byte i = 0; i < 3; ++i)
|
||||
me.RemoveAurasDueToSpell(MiscConst.NetherBuff[i]);
|
||||
}
|
||||
|
||||
void HandleDoors(bool open) // Massive Door switcher
|
||||
{
|
||||
GameObject Door = ObjectAccessor.GetGameObject(me, instance.GetGuidData(DataTypes.GoMassiveDoor));
|
||||
if (Door)
|
||||
Door.SetGoState(open ? GameObjectState.Active : GameObjectState.Ready);
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
HandleDoors(false);
|
||||
SwitchToPortalPhase();
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
HandleDoors(true);
|
||||
DestroyPortals();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
// Void Zone
|
||||
if (VoidZoneTimer <= diff)
|
||||
{
|
||||
DoCast(SelectTarget(SelectTargetMethod.Random, 1, 45, true), SpellIds.Voidzone, new CastSpellExtraArgs(true));
|
||||
VoidZoneTimer = 15000;
|
||||
}
|
||||
else VoidZoneTimer -= diff;
|
||||
|
||||
// NetherInfusion Berserk
|
||||
if (!Berserk && NetherInfusionTimer <= diff)
|
||||
{
|
||||
me.AddAura(SpellIds.NetherInfusion, me);
|
||||
DoCast(me, SpellIds.NetherspiteRoar);
|
||||
Berserk = true;
|
||||
}
|
||||
else NetherInfusionTimer -= diff;
|
||||
|
||||
if (PortalPhase) // Portal Phase
|
||||
{
|
||||
// Distribute beams and buffs
|
||||
if (PortalTimer <= diff)
|
||||
{
|
||||
UpdatePortals();
|
||||
PortalTimer = 1000;
|
||||
}
|
||||
else PortalTimer -= diff;
|
||||
|
||||
// Empowerment & Nether Burn
|
||||
if (EmpowermentTimer <= diff)
|
||||
{
|
||||
DoCast(me, SpellIds.Empowerment);
|
||||
me.AddAura(SpellIds.NetherburnAura, me);
|
||||
EmpowermentTimer = 90000;
|
||||
}
|
||||
else EmpowermentTimer -= diff;
|
||||
|
||||
if (PhaseTimer <= diff)
|
||||
{
|
||||
if (!me.IsNonMeleeSpellCast(false))
|
||||
{
|
||||
SwitchToBanishPhase();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else PhaseTimer -= diff;
|
||||
}
|
||||
else // Banish Phase
|
||||
{
|
||||
// Netherbreath
|
||||
if (NetherbreathTimer <= diff)
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 40, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.Netherbreath);
|
||||
NetherbreathTimer = RandomHelper.URand(5000, 7000);
|
||||
}
|
||||
else NetherbreathTimer -= diff;
|
||||
|
||||
if (PhaseTimer <= diff)
|
||||
{
|
||||
if (!me.IsNonMeleeSpellCast(false))
|
||||
{
|
||||
SwitchToPortalPhase();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else PhaseTimer -= diff;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.Nightbane
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint BellowingRoar = 36922;
|
||||
public const uint CharredEarth = 30129;
|
||||
public const uint Cleave = 30131;
|
||||
public const uint DistractingAsh = 30130;
|
||||
public const uint RainOfBones = 37098;
|
||||
public const uint SmokingBlast = 30128;
|
||||
public const uint SmokingBlastT = 37057;
|
||||
public const uint SmolderingBreath = 30210;
|
||||
public const uint SummonSkeleton = 30170;
|
||||
public const uint TailSweep = 25653;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint EmoteSummon = 0;
|
||||
public const uint YellAggro = 1;
|
||||
public const uint YellFlyPhase = 2;
|
||||
public const uint YellLandPhase = 3;
|
||||
public const uint EmoteBreath = 4;
|
||||
}
|
||||
|
||||
struct PointIds
|
||||
{
|
||||
public const uint IntroStart = 0;
|
||||
public const uint IntroEnd = 1;
|
||||
public const uint IntroLanding = 2;
|
||||
public const uint PhaseTwoFly = 3;
|
||||
public const uint PhaseTwoPreFly = 4;
|
||||
public const uint PhaseTwoLanding = 5;
|
||||
public const uint PhaseTwoEnd = 6;
|
||||
}
|
||||
|
||||
struct SplineChainIds
|
||||
{
|
||||
public const uint IntroStart = 1;
|
||||
public const uint IntroEnd = 2;
|
||||
public const uint IntroLanding = 3;
|
||||
public const uint SecondLanding = 4;
|
||||
public const uint PhaseTwo = 5;
|
||||
}
|
||||
|
||||
enum NightbanePhases
|
||||
{
|
||||
Intro = 0,
|
||||
Ground,
|
||||
Fly
|
||||
}
|
||||
|
||||
struct MiscConst
|
||||
{
|
||||
public const int ActionSummon = 0;
|
||||
public const uint PathPhaseTwo = 13547500;
|
||||
|
||||
public const uint GroupGround = 1;
|
||||
public const uint GroupFly = 2;
|
||||
|
||||
public static Position FlyPosition = new Position(-11160.13f, -1870.683f, 97.73876f, 0.0f);
|
||||
public static Position FlyPositionLeft = new Position(-11094.42f, -1866.992f, 107.8375f, 0.0f);
|
||||
public static Position FlyPositionRight = new Position(-11193.77f, -1921.983f, 107.9845f, 0.0f);
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_nightbane : BossAI
|
||||
{
|
||||
byte _flyCount;
|
||||
NightbanePhases phase;
|
||||
|
||||
public boss_nightbane(Creature creature) : base(creature, DataTypes.Nightbane) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_Reset();
|
||||
_flyCount = 0;
|
||||
me.SetDisableGravity(true);
|
||||
HandleTerraceDoors(true);
|
||||
GameObject urn = ObjectAccessor.GetGameObject(me, instance.GetGuidData(DataTypes.GoBlackenedUrn));
|
||||
if (urn)
|
||||
urn.RemoveFlag(GameObjectFlags.InUse);
|
||||
}
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
me.SetDisableGravity(true);
|
||||
base.EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
public override void JustReachedHome()
|
||||
{
|
||||
_DespawnAtEvade();
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
_JustDied();
|
||||
HandleTerraceDoors(true);
|
||||
}
|
||||
|
||||
public override void DoAction(int action)
|
||||
{
|
||||
if (action == MiscConst.ActionSummon)
|
||||
{
|
||||
Talk(TextIds.EmoteSummon);
|
||||
phase = NightbanePhases.Intro;
|
||||
me.SetActive(true);
|
||||
me.SetFarVisible(true);
|
||||
me.RemoveUnitFlag(UnitFlags.Uninteractible);
|
||||
me.GetMotionMaster().MoveAlongSplineChain(PointIds.IntroStart, SplineChainIds.IntroStart, false);
|
||||
HandleTerraceDoors(false);
|
||||
}
|
||||
}
|
||||
|
||||
void SetupGroundPhase()
|
||||
{
|
||||
phase = NightbanePhases.Ground;
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(15), MiscConst.GroupGround, task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Cleave);
|
||||
task.Repeat(TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(15));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(23), MiscConst.GroupGround, task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true);
|
||||
if (target)
|
||||
if (!me.HasInArc(MathF.PI, target))
|
||||
DoCast(target, SpellIds.TailSweep);
|
||||
task.Repeat(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(30));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(48), MiscConst.GroupGround, task =>
|
||||
{
|
||||
DoCastAOE(SpellIds.BellowingRoar);
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(18), MiscConst.GroupGround, task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.CharredEarth);
|
||||
task.Repeat(TimeSpan.FromSeconds(18), TimeSpan.FromSeconds(21));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(26), TimeSpan.FromSeconds(30), MiscConst.GroupGround, task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.SmolderingBreath);
|
||||
task.Repeat(TimeSpan.FromSeconds(28), TimeSpan.FromSeconds(40));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(82), MiscConst.GroupGround, task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.DistractingAsh);
|
||||
});
|
||||
}
|
||||
|
||||
void HandleTerraceDoors(bool open)
|
||||
{
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.MastersTerraceDoor1), open);
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.MastersTerraceDoor2), open);
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
base.JustEngagedWith(who);
|
||||
Talk(TextIds.YellAggro);
|
||||
SetupGroundPhase();
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
|
||||
{
|
||||
if (phase == NightbanePhases.Fly)
|
||||
{
|
||||
if (damage >= me.GetHealth())
|
||||
damage = (uint)(me.GetHealth() - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((_flyCount == 0 && HealthBelowPct(75)) || (_flyCount == 1 && HealthBelowPct(50)) || (_flyCount == 2 && HealthBelowPct(25)))
|
||||
{
|
||||
phase = NightbanePhases.Fly;
|
||||
StartPhaseFly();
|
||||
}
|
||||
}
|
||||
|
||||
public override void MovementInform(MovementGeneratorType type, uint pointId)
|
||||
{
|
||||
if (type == MovementGeneratorType.SplineChain)
|
||||
{
|
||||
switch (pointId)
|
||||
{
|
||||
case PointIds.IntroStart:
|
||||
me.SetStandState(UnitStandStateType.Stand);
|
||||
_scheduler.Schedule(TimeSpan.FromMilliseconds(1), task =>
|
||||
{
|
||||
me.GetMotionMaster().MoveAlongSplineChain(PointIds.IntroEnd, SplineChainIds.IntroEnd, false);
|
||||
});
|
||||
break;
|
||||
case PointIds.IntroEnd:
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(2), task =>
|
||||
{
|
||||
me.GetMotionMaster().MoveAlongSplineChain(PointIds.IntroLanding, SplineChainIds.IntroLanding, false);
|
||||
});
|
||||
break;
|
||||
case PointIds.IntroLanding:
|
||||
me.SetDisableGravity(false);
|
||||
me.HandleEmoteCommand(Emote.OneshotLand);
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(3), task =>
|
||||
{
|
||||
me.SetImmuneToPC(false);
|
||||
DoZoneInCombat();
|
||||
});
|
||||
break;
|
||||
case PointIds.PhaseTwoLanding:
|
||||
phase = NightbanePhases.Ground;
|
||||
me.SetDisableGravity(false);
|
||||
me.HandleEmoteCommand(Emote.OneshotLand);
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(3), task =>
|
||||
{
|
||||
SetupGroundPhase();
|
||||
me.SetReactState(ReactStates.Aggressive);
|
||||
});
|
||||
break;
|
||||
case PointIds.PhaseTwoEnd:
|
||||
_scheduler.Schedule(TimeSpan.FromMilliseconds(1), task =>
|
||||
{
|
||||
me.GetMotionMaster().MoveAlongSplineChain(PointIds.PhaseTwoLanding, SplineChainIds.SecondLanding, false);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type == MovementGeneratorType.Point)
|
||||
{
|
||||
if (pointId == PointIds.PhaseTwoFly)
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(33), MiscConst.GroupFly, task =>
|
||||
{
|
||||
_scheduler.CancelGroup(MiscConst.GroupFly);
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(2), MiscConst.GroupGround, landTask =>
|
||||
{
|
||||
Talk(TextIds.YellLandPhase);
|
||||
me.SetDisableGravity(true);
|
||||
me.GetMotionMaster().MoveAlongSplineChain(PointIds.PhaseTwoEnd, SplineChainIds.PhaseTwo, false);
|
||||
});
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(2), MiscConst.GroupFly, task =>
|
||||
{
|
||||
Talk(TextIds.EmoteBreath);
|
||||
task.Schedule(TimeSpan.FromSeconds(3), MiscConst.GroupFly, somethingTask =>
|
||||
{
|
||||
ResetThreatList();
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true);
|
||||
if (target)
|
||||
{
|
||||
me.SetFacingToObject(target);
|
||||
DoCast(target, SpellIds.RainOfBones);
|
||||
}
|
||||
});
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(21), MiscConst.GroupFly, task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.SmokingBlastT);
|
||||
task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(7));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(17), MiscConst.GroupFly, task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.SmokingBlast);
|
||||
task.Repeat(TimeSpan.FromMilliseconds(1400));
|
||||
});
|
||||
}
|
||||
else if (pointId == PointIds.PhaseTwoPreFly)
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromMilliseconds(1), task =>
|
||||
{
|
||||
me.GetMotionMaster().MovePoint(PointIds.PhaseTwoFly, MiscConst.FlyPosition, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StartPhaseFly()
|
||||
{
|
||||
++_flyCount;
|
||||
Talk(TextIds.YellFlyPhase);
|
||||
_scheduler.CancelGroup(MiscConst.GroupGround);
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
me.HandleEmoteCommand(Emote.OneshotLiftoff);
|
||||
me.SetDisableGravity(true);
|
||||
me.SetReactState(ReactStates.Passive);
|
||||
me.AttackStop();
|
||||
|
||||
if (me.GetDistance(MiscConst.FlyPositionLeft) < me.GetDistance(MiscConst.FlyPosition))
|
||||
me.GetMotionMaster().MovePoint(PointIds.PhaseTwoPreFly, MiscConst.FlyPositionLeft, true);
|
||||
else if (me.GetDistance(MiscConst.FlyPositionRight) < me.GetDistance(MiscConst.FlyPosition))
|
||||
me.GetMotionMaster().MovePoint(PointIds.PhaseTwoPreFly, MiscConst.FlyPositionRight, true);
|
||||
else
|
||||
me.GetMotionMaster().MovePoint(PointIds.PhaseTwoFly, MiscConst.FlyPosition, true);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim() && phase != NightbanePhases.Intro)
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, () => DoMeleeAttackIfReady());
|
||||
}
|
||||
}
|
||||
|
||||
[Script] // 37098 - Rain of Bones
|
||||
class spell_rain_of_bones_AuraScript : AuraScript
|
||||
{
|
||||
public override bool Validate(SpellInfo spellInfo)
|
||||
{
|
||||
return ValidateSpellInfo(SpellIds.SummonSkeleton);
|
||||
}
|
||||
|
||||
void OnTrigger(AuraEffect aurEff)
|
||||
{
|
||||
if (aurEff.GetTickNumber() % 5 == 0)
|
||||
GetTarget().CastSpell(GetTarget(), SpellIds.SummonSkeleton, true);
|
||||
}
|
||||
|
||||
public override void Register()
|
||||
{
|
||||
OnEffectPeriodic.Add(new EffectPeriodicHandler(OnTrigger, 1, AuraType.PeriodicTriggerSpell));
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class go_blackened_urn : GameObjectAI
|
||||
{
|
||||
InstanceScript instance;
|
||||
|
||||
public go_blackened_urn(GameObject go) : base(go)
|
||||
{
|
||||
instance = go.GetInstanceScript();
|
||||
}
|
||||
|
||||
public override bool OnGossipHello(Player player)
|
||||
{
|
||||
if (me.HasFlag(GameObjectFlags.InUse))
|
||||
return false;
|
||||
|
||||
if (instance.GetBossState(DataTypes.Nightbane) == EncounterState.Done || instance.GetBossState(DataTypes.Nightbane) == EncounterState.InProgress)
|
||||
return false;
|
||||
|
||||
Creature nightbane = ObjectAccessor.GetCreature(me, instance.GetGuidData(DataTypes.Nightbane));
|
||||
if (nightbane)
|
||||
{
|
||||
me.SetFlag(GameObjectFlags.InUse);
|
||||
nightbane.GetAI().DoAction(MiscConst.ActionSummon);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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.Numerics;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.PrinceMalchezaar
|
||||
{
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayAggro = 0;
|
||||
public const uint SayAxeToss1 = 1;
|
||||
public const uint SayAxeToss2 = 2;
|
||||
//public const uint SaySpecial1 = 3; Not used, needs to be implemented, but I don't know where it should be used.
|
||||
//public const uint SaySpecial2 = 4; Not used, needs to be implemented, but I don't know where it should be used.
|
||||
//public const uint SaySpecial3 = 5; Not used, needs to be implemented, but I don't know where it should be used.
|
||||
public const uint SaySlay = 6;
|
||||
public const uint SaySummon = 7;
|
||||
public const uint SayDeath = 8;
|
||||
}
|
||||
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint Enfeeble = 30843; //Enfeeble during phase 1 and 2
|
||||
public const uint EnfeebleEffect = 41624;
|
||||
|
||||
public const uint Shadownova = 30852; //Shadownova used during all phases
|
||||
public const uint SwPain = 30854; //Shadow word pain during phase 1 and 3 (different targeting rules though)
|
||||
public const uint ThrashPassive = 12787; //Extra attack chance during phase 2
|
||||
public const uint SunderArmor = 30901; //Sunder armor during phase 2
|
||||
public const uint ThrashAura = 12787; //Passive proc chance for thrash
|
||||
public const uint EquipAxes = 30857; //Visual for axe equiping
|
||||
public const uint AmplifyDamage = 39095; //Amplifiy during phase 3
|
||||
public const uint Cleave = 30131; //Same as Nightbane.
|
||||
public const uint Hellfire = 30859; //Infenals' hellfire aura
|
||||
|
||||
public const uint InfernalRelay = 30834;
|
||||
}
|
||||
|
||||
struct MiscConst
|
||||
{
|
||||
public const uint TotalInfernalPoints = 18;
|
||||
public const uint NetherspiteInfernal = 17646; //The netherspite infernal creature
|
||||
public const uint MalchezarsAxe = 17650; //Malchezar's axes (creatures), summoned during phase 3
|
||||
|
||||
public const uint InfernalModelInvisible = 11686; //Infernal Effects
|
||||
public const int EquipIdAxe = 33542; //Axes info
|
||||
}
|
||||
|
||||
[Script]
|
||||
class netherspite_infernal : ScriptedAI
|
||||
{
|
||||
public ObjectGuid Malchezaar;
|
||||
public Vector2 Point;
|
||||
|
||||
public netherspite_infernal(Creature creature) : base(creature) { }
|
||||
|
||||
public override void Reset() { }
|
||||
|
||||
public override void JustEngagedWith(Unit who) { }
|
||||
|
||||
public override void MoveInLineOfSight(Unit who) { }
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit who)
|
||||
{
|
||||
Unit unit = Global.ObjAccessor.GetUnit(me, Malchezaar);
|
||||
if (unit)
|
||||
{
|
||||
Creature creature = unit.ToCreature();
|
||||
if (creature)
|
||||
creature.GetAI().KilledUnit(who);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SpellHit(WorldObject caster, SpellInfo spellInfo)
|
||||
{
|
||||
if (spellInfo.Id == SpellIds.InfernalRelay)
|
||||
{
|
||||
me.SetDisplayId(me.GetNativeDisplayId());
|
||||
me.SetUnitFlag(UnitFlags.Uninteractible);
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(4), task => DoCast(me, SpellIds.Hellfire));
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(170), task =>
|
||||
{
|
||||
Creature pMalchezaar = ObjectAccessor.GetCreature(me, Malchezaar);
|
||||
|
||||
if (pMalchezaar && pMalchezaar.IsAlive())
|
||||
pMalchezaar.GetAI<boss_malchezaar>().Cleanup(me, Point);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit done_by, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
|
||||
{
|
||||
if (!done_by || done_by.GetGUID() != Malchezaar)
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_malchezaar : ScriptedAI
|
||||
{
|
||||
static Vector2[] InfernalPoints =
|
||||
{
|
||||
new Vector2(-10922.8f, -1985.2f),
|
||||
new Vector2(-10916.2f, -1996.2f),
|
||||
new Vector2(-10932.2f, -2008.1f),
|
||||
new Vector2(-10948.8f, -2022.1f),
|
||||
new Vector2(-10958.7f, -1997.7f),
|
||||
new Vector2(-10971.5f, -1997.5f),
|
||||
new Vector2(-10990.8f, -1995.1f),
|
||||
new Vector2(-10989.8f, -1976.5f),
|
||||
new Vector2(-10971.6f, -1973.0f),
|
||||
new Vector2(-10955.5f, -1974.0f),
|
||||
new Vector2(-10939.6f, -1969.8f),
|
||||
new Vector2(-10958.0f, -1952.2f),
|
||||
new Vector2(-10941.7f, -1954.8f),
|
||||
new Vector2(-10943.1f, -1988.5f),
|
||||
new Vector2(-10948.8f, -2005.1f),
|
||||
new Vector2(-10984.0f, -2019.3f),
|
||||
new Vector2(-10932.8f, -1979.6f),
|
||||
new Vector2(-10935.7f, -1996.0f)
|
||||
};
|
||||
|
||||
InstanceScript instance;
|
||||
uint EnfeebleTimer;
|
||||
uint EnfeebleResetTimer;
|
||||
uint ShadowNovaTimer;
|
||||
uint SWPainTimer;
|
||||
uint SunderArmorTimer;
|
||||
uint AmplifyDamageTimer;
|
||||
uint Cleave_Timer;
|
||||
uint InfernalTimer;
|
||||
uint AxesTargetSwitchTimer;
|
||||
uint InfernalCleanupTimer;
|
||||
|
||||
List<ObjectGuid> infernals = new();
|
||||
List<Vector2> positions = new();
|
||||
|
||||
ObjectGuid[] axes = new ObjectGuid[2];
|
||||
ObjectGuid[] enfeeble_targets = new ObjectGuid[5];
|
||||
ulong[] enfeeble_health = new ulong[5];
|
||||
|
||||
uint phase;
|
||||
|
||||
public boss_malchezaar(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
|
||||
instance = creature.GetInstanceScript();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
EnfeebleTimer = 30000;
|
||||
EnfeebleResetTimer = 38000;
|
||||
ShadowNovaTimer = 35500;
|
||||
SWPainTimer = 20000;
|
||||
AmplifyDamageTimer = 5000;
|
||||
Cleave_Timer = 8000;
|
||||
InfernalTimer = 40000;
|
||||
InfernalCleanupTimer = 47000;
|
||||
AxesTargetSwitchTimer = RandomHelper.URand(7500, 20000);
|
||||
SunderArmorTimer = RandomHelper.URand(5000, 10000);
|
||||
phase = 1;
|
||||
|
||||
for (byte i = 0; i < 5; ++i)
|
||||
{
|
||||
enfeeble_targets[i].Clear();
|
||||
enfeeble_health[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
AxesCleanup();
|
||||
ClearWeapons();
|
||||
InfernalCleanup();
|
||||
positions.Clear();
|
||||
|
||||
Initialize();
|
||||
|
||||
for (byte i = 0; i < MiscConst.TotalInfernalPoints; ++i)
|
||||
positions.Add(InfernalPoints[i]);
|
||||
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.GoNetherDoor), true);
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
Talk(TextIds.SaySlay);
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
|
||||
AxesCleanup();
|
||||
ClearWeapons();
|
||||
InfernalCleanup();
|
||||
positions.Clear();
|
||||
|
||||
for (byte i = 0; i < MiscConst.TotalInfernalPoints; ++i)
|
||||
positions.Add(InfernalPoints[i]);
|
||||
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.GoNetherDoor), true);
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
Talk(TextIds.SayAggro);
|
||||
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.GoNetherDoor), false); // Open the door leading further in
|
||||
}
|
||||
|
||||
void InfernalCleanup()
|
||||
{
|
||||
//Infernal Cleanup
|
||||
foreach (var guid in infernals)
|
||||
{
|
||||
Unit pInfernal = Global.ObjAccessor.GetUnit(me, guid);
|
||||
if (pInfernal && pInfernal.IsAlive())
|
||||
{
|
||||
pInfernal.SetVisible(false);
|
||||
pInfernal.SetDeathState(DeathState.JustDied);
|
||||
}
|
||||
}
|
||||
|
||||
infernals.Clear();
|
||||
}
|
||||
|
||||
void AxesCleanup()
|
||||
{
|
||||
for (byte i = 0; i < 2; ++i)
|
||||
{
|
||||
Unit axe = Global.ObjAccessor.GetUnit(me, axes[i]);
|
||||
if (axe && axe.IsAlive())
|
||||
axe.KillSelf();
|
||||
axes[i].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ClearWeapons()
|
||||
{
|
||||
SetEquipmentSlots(false, 0, 0);
|
||||
me.SetCanDualWield(false);
|
||||
}
|
||||
|
||||
void EnfeebleHealthEffect()
|
||||
{
|
||||
SpellInfo info = Global.SpellMgr.GetSpellInfo(SpellIds.EnfeebleEffect, GetDifficulty());
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
Unit tank = me.GetThreatManager().GetCurrentVictim();
|
||||
List<Unit> targets = new();
|
||||
|
||||
foreach (var refe in me.GetThreatManager().GetSortedThreatList())
|
||||
{
|
||||
Unit target = refe.GetVictim();
|
||||
if (target != tank && target.IsAlive() && target.IsPlayer())
|
||||
targets.Add(target);
|
||||
}
|
||||
|
||||
if (targets.Empty())
|
||||
return;
|
||||
|
||||
//cut down to size if we have more than 5 targets
|
||||
targets.RandomResize(5);
|
||||
|
||||
uint i = 0;
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
enfeeble_targets[i] = target.GetGUID();
|
||||
enfeeble_health[i] = target.GetHealth();
|
||||
|
||||
CastSpellExtraArgs args = new(TriggerCastFlags.FullMask);
|
||||
args.OriginalCaster = me.GetGUID();
|
||||
target.CastSpell(target, SpellIds.Enfeeble, args);
|
||||
target.SetHealth(1);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void EnfeebleResetHealth()
|
||||
{
|
||||
for (byte i = 0; i < 5; ++i)
|
||||
{
|
||||
Unit target = Global.ObjAccessor.GetUnit(me, enfeeble_targets[i]);
|
||||
if (target && target.IsAlive())
|
||||
target.SetHealth(enfeeble_health[i]);
|
||||
enfeeble_targets[i].Clear();
|
||||
enfeeble_health[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SummonInfernal(uint diff)
|
||||
{
|
||||
Vector2 point = Vector2.Zero;
|
||||
Position pos = null;
|
||||
if ((me.GetMapId() != 532) || positions.Empty())
|
||||
pos = me.GetRandomNearPosition(60);
|
||||
else
|
||||
{
|
||||
point = positions.SelectRandom();
|
||||
pos.Relocate(point.X, point.Y, 275.5f, RandomHelper.FRand(0.0f, (MathF.PI * 2)));
|
||||
}
|
||||
|
||||
Creature infernal = me.SummonCreature(MiscConst.NetherspiteInfernal, pos, TempSummonType.TimedDespawn, TimeSpan.FromMinutes(3));
|
||||
|
||||
if (infernal)
|
||||
{
|
||||
infernal.SetDisplayId(MiscConst.InfernalModelInvisible);
|
||||
infernal.SetFaction(me.GetFaction());
|
||||
if (point != Vector2.Zero)
|
||||
infernal.GetAI<netherspite_infernal>().Point = point;
|
||||
infernal.GetAI<netherspite_infernal>().Malchezaar = me.GetGUID();
|
||||
|
||||
infernals.Add(infernal.GetGUID());
|
||||
DoCast(infernal, SpellIds.InfernalRelay);
|
||||
}
|
||||
|
||||
Talk(TextIds.SaySummon);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (EnfeebleResetTimer != 0 && EnfeebleResetTimer <= diff) // Let's not forget to reset that
|
||||
{
|
||||
EnfeebleResetHealth();
|
||||
EnfeebleResetTimer = 0;
|
||||
}
|
||||
else EnfeebleResetTimer -= diff;
|
||||
|
||||
if (me.HasUnitState(UnitState.Stunned)) // While shifting to phase 2 malchezaar stuns himself
|
||||
return;
|
||||
|
||||
if (me.GetVictim() && me.GetTarget() != me.GetVictim().GetGUID())
|
||||
me.SetTarget(me.GetVictim().GetGUID());
|
||||
|
||||
if (phase == 1)
|
||||
{
|
||||
if (HealthBelowPct(60))
|
||||
{
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
|
||||
phase = 2;
|
||||
|
||||
//animation
|
||||
DoCast(me, SpellIds.EquipAxes);
|
||||
|
||||
//text
|
||||
Talk(TextIds.SayAxeToss1);
|
||||
|
||||
//passive thrash aura
|
||||
DoCast(me, SpellIds.ThrashAura, new CastSpellExtraArgs(true));
|
||||
|
||||
//models
|
||||
SetEquipmentSlots(false, MiscConst.EquipIdAxe, MiscConst.EquipIdAxe);
|
||||
|
||||
me.SetBaseAttackTime(WeaponAttackType.OffAttack, (me.GetBaseAttackTime(WeaponAttackType.BaseAttack) * 150) / 100);
|
||||
me.SetCanDualWield(true);
|
||||
}
|
||||
}
|
||||
else if (phase == 2)
|
||||
{
|
||||
if (HealthBelowPct(30))
|
||||
{
|
||||
InfernalTimer = 15000;
|
||||
|
||||
phase = 3;
|
||||
|
||||
ClearWeapons();
|
||||
|
||||
//remove thrash
|
||||
me.RemoveAurasDueToSpell(SpellIds.ThrashAura);
|
||||
|
||||
Talk(TextIds.SayAxeToss2);
|
||||
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100, true);
|
||||
for (byte i = 0; i < 2; ++i)
|
||||
{
|
||||
Creature axe = me.SummonCreature(MiscConst.MalchezarsAxe, me.GetPositionX(), me.GetPositionY(), me.GetPositionZ(), 0, TempSummonType.TimedDespawnOutOfCombat, TimeSpan.FromSeconds(1));
|
||||
if (axe)
|
||||
{
|
||||
axe.SetUnitFlag(UnitFlags.Uninteractible);
|
||||
axe.SetFaction(me.GetFaction());
|
||||
axes[i] = axe.GetGUID();
|
||||
if (target)
|
||||
{
|
||||
axe.GetAI().AttackStart(target);
|
||||
AddThreat(target, 10000000.0f, axe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ShadowNovaTimer > 35000)
|
||||
ShadowNovaTimer = EnfeebleTimer + 5000;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SunderArmorTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.SunderArmor);
|
||||
SunderArmorTimer = RandomHelper.URand(10000, 18000);
|
||||
}
|
||||
else SunderArmorTimer -= diff;
|
||||
|
||||
if (Cleave_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Cleave);
|
||||
Cleave_Timer = RandomHelper.URand(6000, 12000);
|
||||
}
|
||||
else Cleave_Timer -= diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AxesTargetSwitchTimer <= diff)
|
||||
{
|
||||
AxesTargetSwitchTimer = RandomHelper.URand(7500, 20000);
|
||||
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100, true);
|
||||
if (target)
|
||||
{
|
||||
for (byte i = 0; i < 2; ++i)
|
||||
{
|
||||
Unit axe = Global.ObjAccessor.GetUnit(me, axes[i]);
|
||||
if (axe)
|
||||
{
|
||||
if (axe.GetVictim())
|
||||
ResetThreat(axe.GetVictim(), axe);
|
||||
AddThreat(target, 1000000.0f, axe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else AxesTargetSwitchTimer -= diff;
|
||||
|
||||
if (AmplifyDamageTimer <= diff)
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.AmplifyDamage);
|
||||
AmplifyDamageTimer = RandomHelper.URand(20000, 30000);
|
||||
}
|
||||
else AmplifyDamageTimer -= diff;
|
||||
}
|
||||
|
||||
//Time for global and double timers
|
||||
if (InfernalTimer <= diff)
|
||||
{
|
||||
SummonInfernal(diff);
|
||||
InfernalTimer = phase == 3 ? 14500 : 44500u; // 15 secs in phase 3, 45 otherwise
|
||||
}
|
||||
else InfernalTimer -= diff;
|
||||
|
||||
if (ShadowNovaTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.Shadownova);
|
||||
ShadowNovaTimer = phase == 3 ? 31000 : uint.MaxValue;
|
||||
}
|
||||
else ShadowNovaTimer -= diff;
|
||||
|
||||
if (phase != 2)
|
||||
{
|
||||
if (SWPainTimer <= diff)
|
||||
{
|
||||
Unit target;
|
||||
if (phase == 1)
|
||||
target = me.GetVictim(); // the tank
|
||||
else // anyone but the tank
|
||||
target = SelectTarget(SelectTargetMethod.Random, 1, 100, true);
|
||||
|
||||
if (target)
|
||||
DoCast(target, SpellIds.SwPain);
|
||||
|
||||
SWPainTimer = 20000;
|
||||
}
|
||||
else SWPainTimer -= diff;
|
||||
}
|
||||
|
||||
if (phase != 3)
|
||||
{
|
||||
if (EnfeebleTimer <= diff)
|
||||
{
|
||||
EnfeebleHealthEffect();
|
||||
EnfeebleTimer = 30000;
|
||||
ShadowNovaTimer = 5000;
|
||||
EnfeebleResetTimer = 9000;
|
||||
}
|
||||
else EnfeebleTimer -= diff;
|
||||
}
|
||||
|
||||
if (phase == 2)
|
||||
DoMeleeAttacksIfReady();
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void DoMeleeAttacksIfReady()
|
||||
{
|
||||
if (me.IsWithinMeleeRange(me.GetVictim()) && !me.IsNonMeleeSpellCast(false))
|
||||
{
|
||||
//Check for base attack
|
||||
if (me.IsAttackReady() && me.GetVictim())
|
||||
{
|
||||
me.AttackerStateUpdate(me.GetVictim());
|
||||
me.ResetAttackTimer();
|
||||
}
|
||||
//Check for offhand attack
|
||||
if (me.IsAttackReady(WeaponAttackType.OffAttack) && me.GetVictim())
|
||||
{
|
||||
me.AttackerStateUpdate(me.GetVictim(), WeaponAttackType.OffAttack);
|
||||
me.ResetAttackTimer(WeaponAttackType.OffAttack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Cleanup(Creature infernal, Vector2 point)
|
||||
{
|
||||
foreach (var guid in infernals)
|
||||
{
|
||||
if (guid == infernal.GetGUID())
|
||||
{
|
||||
infernals.Remove(guid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
positions.Add(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,568 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.ShadeOfAran
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint Frostbolt = 29954;
|
||||
public const uint Fireball = 29953;
|
||||
public const uint Arcmissle = 29955;
|
||||
public const uint Chainsofice = 29991;
|
||||
public const uint Dragonsbreath = 29964;
|
||||
public const uint Massslow = 30035;
|
||||
public const uint FlameWreath = 29946;
|
||||
public const uint AoeCs = 29961;
|
||||
public const uint Playerpull = 32265;
|
||||
public const uint Aexplosion = 29973;
|
||||
public const uint MassPoly = 29963;
|
||||
public const uint BlinkCenter = 29967;
|
||||
public const uint Elementals = 29962;
|
||||
public const uint Conjure = 29975;
|
||||
public const uint Drink = 30024;
|
||||
public const uint Potion = 32453;
|
||||
public const uint AoePyroblast = 29978;
|
||||
|
||||
public const uint CircularBlizzard = 29951;
|
||||
public const uint Waterbolt = 31012;
|
||||
public const uint ShadowPyro = 29978;
|
||||
}
|
||||
|
||||
struct CreatureIds
|
||||
{
|
||||
public const uint WaterElemental = 17167;
|
||||
public const uint ShadowOfAran = 18254;
|
||||
public const uint AranBlizzard = 17161;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayAggro = 0;
|
||||
public const uint SayFlamewreath = 1;
|
||||
public const uint SayBlizzard = 2;
|
||||
public const uint SayExplosion = 3;
|
||||
public const uint SayDrink = 4;
|
||||
public const uint SayElementals = 5;
|
||||
public const uint SayKill = 6;
|
||||
public const uint SayTimeover = 7;
|
||||
public const uint SayDeath = 8;
|
||||
public const uint SayAtiesh = 9;
|
||||
}
|
||||
|
||||
enum SuperSpell
|
||||
{
|
||||
Flame = 0,
|
||||
Blizzard,
|
||||
Ae,
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_aran : ScriptedAI
|
||||
{
|
||||
static uint[] AtieshStaves =
|
||||
{
|
||||
22589, //ItemAtieshMage,
|
||||
22630, //ItemAtieshWarlock,
|
||||
22631, //ItemAtieshPriest,
|
||||
22632 //ItemAtieshDruid,
|
||||
};
|
||||
|
||||
InstanceScript instance;
|
||||
|
||||
uint SecondarySpellTimer;
|
||||
uint NormalCastTimer;
|
||||
uint SuperCastTimer;
|
||||
uint BerserkTimer;
|
||||
uint CloseDoorTimer; // Don't close the door right on aggro in case some people are still entering.
|
||||
|
||||
SuperSpell LastSuperSpell;
|
||||
|
||||
uint FlameWreathTimer;
|
||||
uint FlameWreathCheckTime;
|
||||
ObjectGuid[] FlameWreathTarget = new ObjectGuid[3];
|
||||
float[] FWTargPosX = new float[3];
|
||||
float[] FWTargPosY = new float[3];
|
||||
|
||||
uint CurrentNormalSpell;
|
||||
uint ArcaneCooldown;
|
||||
uint FireCooldown;
|
||||
uint FrostCooldown;
|
||||
|
||||
uint DrinkInterruptTimer;
|
||||
|
||||
bool ElementalsSpawned;
|
||||
bool Drinking;
|
||||
bool DrinkInturrupted;
|
||||
bool SeenAtiesh;
|
||||
|
||||
public boss_aran(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
instance = creature.GetInstanceScript();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
SecondarySpellTimer = 5000;
|
||||
NormalCastTimer = 0;
|
||||
SuperCastTimer = 35000;
|
||||
BerserkTimer = 720000;
|
||||
CloseDoorTimer = 15000;
|
||||
|
||||
LastSuperSpell = (SuperSpell)(RandomHelper.Rand32() % 3);
|
||||
|
||||
FlameWreathTimer = 0;
|
||||
FlameWreathCheckTime = 0;
|
||||
|
||||
CurrentNormalSpell = 0;
|
||||
ArcaneCooldown = 0;
|
||||
FireCooldown = 0;
|
||||
FrostCooldown = 0;
|
||||
|
||||
DrinkInterruptTimer = 10000;
|
||||
|
||||
ElementalsSpawned = false;
|
||||
Drinking = false;
|
||||
DrinkInturrupted = false;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
// Not in progress
|
||||
instance.SetBossState(DataTypes.Aran, EncounterState.NotStarted);
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.GoLibraryDoor), true);
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
Talk(TextIds.SayKill);
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
|
||||
instance.SetBossState(DataTypes.Aran, EncounterState.Done);
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.GoLibraryDoor), true);
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
Talk(TextIds.SayAggro);
|
||||
|
||||
instance.SetBossState(DataTypes.Aran, EncounterState.InProgress);
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.GoLibraryDoor), false);
|
||||
}
|
||||
|
||||
void FlameWreathEffect()
|
||||
{
|
||||
List<Unit> targets = new();
|
||||
//store the threat list in a different container
|
||||
foreach (var refe in me.GetThreatManager().GetSortedThreatList())
|
||||
{
|
||||
Unit target = refe.GetVictim();
|
||||
if (refe.GetVictim().IsPlayer() && refe.GetVictim().IsAlive())
|
||||
targets.Add(target);
|
||||
}
|
||||
|
||||
//cut down to size if we have more than 3 targets
|
||||
targets.RandomResize(3);
|
||||
|
||||
uint i = 0;
|
||||
foreach (var unit in targets)
|
||||
{
|
||||
if (unit)
|
||||
{
|
||||
FlameWreathTarget[i] = unit.GetGUID();
|
||||
FWTargPosX[i] = unit.GetPositionX();
|
||||
FWTargPosY[i] = unit.GetPositionY();
|
||||
DoCast(unit, SpellIds.FlameWreath, new CastSpellExtraArgs(true));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (CloseDoorTimer != 0)
|
||||
{
|
||||
if (CloseDoorTimer <= diff)
|
||||
{
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.GoLibraryDoor), false);
|
||||
CloseDoorTimer = 0;
|
||||
}
|
||||
else CloseDoorTimer -= diff;
|
||||
}
|
||||
|
||||
//Cooldowns for casts
|
||||
if (ArcaneCooldown != 0)
|
||||
{
|
||||
if (ArcaneCooldown >= diff)
|
||||
ArcaneCooldown -= diff;
|
||||
else ArcaneCooldown = 0;
|
||||
}
|
||||
|
||||
if (FireCooldown != 0)
|
||||
{
|
||||
if (FireCooldown >= diff)
|
||||
FireCooldown -= diff;
|
||||
else FireCooldown = 0;
|
||||
}
|
||||
|
||||
if (FrostCooldown != 0)
|
||||
{
|
||||
if (FrostCooldown >= diff)
|
||||
FrostCooldown -= diff;
|
||||
else FrostCooldown = 0;
|
||||
}
|
||||
|
||||
if (!Drinking && me.GetMaxPower(PowerType.Mana) != 0 && me.GetPowerPct(PowerType.Mana) < 20.0f)
|
||||
{
|
||||
Drinking = true;
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
|
||||
Talk(TextIds.SayDrink);
|
||||
|
||||
if (!DrinkInturrupted)
|
||||
{
|
||||
DoCast(me, SpellIds.MassPoly, new CastSpellExtraArgs(true));
|
||||
DoCast(me, SpellIds.Conjure, new CastSpellExtraArgs(false));
|
||||
DoCast(me, SpellIds.Drink, new CastSpellExtraArgs(false));
|
||||
me.SetStandState(UnitStandStateType.Sit);
|
||||
DrinkInterruptTimer = 10000;
|
||||
}
|
||||
}
|
||||
|
||||
//Drink Interrupt
|
||||
if (Drinking && DrinkInturrupted)
|
||||
{
|
||||
Drinking = false;
|
||||
me.RemoveAurasDueToSpell(SpellIds.Drink);
|
||||
me.SetStandState(UnitStandStateType.Stand);
|
||||
me.SetPower(PowerType.Mana, me.GetMaxPower(PowerType.Mana) - 32000);
|
||||
DoCast(me, SpellIds.Potion, new CastSpellExtraArgs(false));
|
||||
}
|
||||
|
||||
//Drink Interrupt Timer
|
||||
if (Drinking && !DrinkInturrupted)
|
||||
{
|
||||
if (DrinkInterruptTimer >= diff)
|
||||
DrinkInterruptTimer -= diff;
|
||||
else
|
||||
{
|
||||
me.SetStandState(UnitStandStateType.Stand);
|
||||
DoCast(me, SpellIds.Potion, new CastSpellExtraArgs(true));
|
||||
DoCast(me, SpellIds.AoePyroblast, new CastSpellExtraArgs(false));
|
||||
DrinkInturrupted = true;
|
||||
Drinking = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Don't execute any more code if we are drinking
|
||||
if (Drinking)
|
||||
return;
|
||||
|
||||
//Normal casts
|
||||
if (NormalCastTimer <= diff)
|
||||
{
|
||||
if (!me.IsNonMeleeSpellCast(false))
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100, true);
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
uint[] Spells = new uint[3];
|
||||
byte AvailableSpells = 0;
|
||||
|
||||
//Check for what spells are not on cooldown
|
||||
if (ArcaneCooldown == 0)
|
||||
{
|
||||
Spells[AvailableSpells] = SpellIds.Arcmissle;
|
||||
++AvailableSpells;
|
||||
}
|
||||
if (FireCooldown == 0)
|
||||
{
|
||||
Spells[AvailableSpells] = SpellIds.Fireball;
|
||||
++AvailableSpells;
|
||||
}
|
||||
if (FrostCooldown == 0)
|
||||
{
|
||||
Spells[AvailableSpells] = SpellIds.Frostbolt;
|
||||
++AvailableSpells;
|
||||
}
|
||||
|
||||
//If no available spells wait 1 second and try again
|
||||
if (AvailableSpells != 0)
|
||||
{
|
||||
CurrentNormalSpell = Spells[RandomHelper.Rand32() % AvailableSpells];
|
||||
DoCast(target, CurrentNormalSpell);
|
||||
}
|
||||
}
|
||||
NormalCastTimer = 1000;
|
||||
}
|
||||
else NormalCastTimer -= diff;
|
||||
|
||||
if (SecondarySpellTimer <= diff)
|
||||
{
|
||||
switch (RandomHelper.URand(0, 1))
|
||||
{
|
||||
case 0:
|
||||
DoCast(me, SpellIds.AoeCs);
|
||||
break;
|
||||
case 1:
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100, true);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.Chainsofice);
|
||||
break;
|
||||
}
|
||||
SecondarySpellTimer = RandomHelper.URand(5000, 20000);
|
||||
}
|
||||
else SecondarySpellTimer -= diff;
|
||||
|
||||
if (SuperCastTimer <= diff)
|
||||
{
|
||||
SuperSpell[] Available = new SuperSpell[2];
|
||||
|
||||
switch (LastSuperSpell)
|
||||
{
|
||||
case SuperSpell.Ae:
|
||||
Available[0] = SuperSpell.Flame;
|
||||
Available[1] = SuperSpell.Blizzard;
|
||||
break;
|
||||
case SuperSpell.Flame:
|
||||
Available[0] = SuperSpell.Ae;
|
||||
Available[1] = SuperSpell.Blizzard;
|
||||
break;
|
||||
case SuperSpell.Blizzard:
|
||||
Available[0] = SuperSpell.Flame;
|
||||
Available[1] = SuperSpell.Ae;
|
||||
break;
|
||||
default:
|
||||
Available[0] = 0;
|
||||
Available[1] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
LastSuperSpell = Available[RandomHelper.URand(0, 1)];
|
||||
|
||||
switch (LastSuperSpell)
|
||||
{
|
||||
case SuperSpell.Ae:
|
||||
Talk(TextIds.SayExplosion);
|
||||
|
||||
DoCast(me, SpellIds.BlinkCenter, new CastSpellExtraArgs(true));
|
||||
DoCast(me, SpellIds.Playerpull, new CastSpellExtraArgs(true));
|
||||
DoCast(me, SpellIds.Massslow, new CastSpellExtraArgs(true));
|
||||
DoCast(me, SpellIds.Aexplosion, new CastSpellExtraArgs(false));
|
||||
break;
|
||||
|
||||
case SuperSpell.Flame:
|
||||
Talk(TextIds.SayFlamewreath);
|
||||
|
||||
FlameWreathTimer = 20000;
|
||||
FlameWreathCheckTime = 500;
|
||||
|
||||
FlameWreathTarget[0].Clear();
|
||||
FlameWreathTarget[1].Clear();
|
||||
FlameWreathTarget[2].Clear();
|
||||
|
||||
FlameWreathEffect();
|
||||
break;
|
||||
|
||||
case SuperSpell.Blizzard:
|
||||
Talk(TextIds.SayBlizzard);
|
||||
|
||||
Creature pSpawn = me.SummonCreature(CreatureIds.AranBlizzard, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType.TimedDespawn, TimeSpan.FromSeconds(25));
|
||||
if (pSpawn)
|
||||
{
|
||||
pSpawn.SetFaction(me.GetFaction());
|
||||
pSpawn.CastSpell(pSpawn, SpellIds.CircularBlizzard, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SuperCastTimer = RandomHelper.URand(35000, 40000);
|
||||
}
|
||||
else SuperCastTimer -= diff;
|
||||
|
||||
if (!ElementalsSpawned && HealthBelowPct(40))
|
||||
{
|
||||
ElementalsSpawned = true;
|
||||
|
||||
for (uint i = 0; i < 4; ++i)
|
||||
{
|
||||
Creature unit = me.SummonCreature(CreatureIds.WaterElemental, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType.TimedDespawn, TimeSpan.FromSeconds(90));
|
||||
if (unit)
|
||||
{
|
||||
unit.Attack(me.GetVictim(), true);
|
||||
unit.SetFaction(me.GetFaction());
|
||||
}
|
||||
}
|
||||
|
||||
Talk(TextIds.SayElementals);
|
||||
}
|
||||
|
||||
if (BerserkTimer <= diff)
|
||||
{
|
||||
for (uint i = 0; i < 5; ++i)
|
||||
{
|
||||
Creature unit = me.SummonCreature(CreatureIds.ShadowOfAran, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType.TimedDespawnOutOfCombat, TimeSpan.FromSeconds(5));
|
||||
if (unit)
|
||||
{
|
||||
unit.Attack(me.GetVictim(), true);
|
||||
unit.SetFaction(me.GetFaction());
|
||||
}
|
||||
}
|
||||
|
||||
Talk(TextIds.SayTimeover);
|
||||
|
||||
BerserkTimer = 60000;
|
||||
}
|
||||
else BerserkTimer -= diff;
|
||||
|
||||
//Flame Wreath check
|
||||
if (FlameWreathTimer != 0)
|
||||
{
|
||||
if (FlameWreathTimer >= diff)
|
||||
FlameWreathTimer -= diff;
|
||||
else FlameWreathTimer = 0;
|
||||
|
||||
if (FlameWreathCheckTime <= diff)
|
||||
{
|
||||
for (byte i = 0; i < 3; ++i)
|
||||
{
|
||||
if (FlameWreathTarget[i].IsEmpty())
|
||||
continue;
|
||||
|
||||
Unit unit = Global.ObjAccessor.GetUnit(me, FlameWreathTarget[i]);
|
||||
if (unit && !unit.IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
|
||||
{
|
||||
unit.CastSpell(unit, 20476, new CastSpellExtraArgs(TriggerCastFlags.FullMask)
|
||||
.SetOriginalCaster(me.GetGUID()));
|
||||
unit.CastSpell(unit, 11027, true);
|
||||
FlameWreathTarget[i].Clear();
|
||||
}
|
||||
}
|
||||
FlameWreathCheckTime = 500;
|
||||
}
|
||||
else FlameWreathCheckTime -= diff;
|
||||
}
|
||||
|
||||
if (ArcaneCooldown != 0 && FireCooldown != 0 && FrostCooldown != 0)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit pAttacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
|
||||
{
|
||||
if (!DrinkInturrupted && Drinking && damage != 0)
|
||||
DrinkInturrupted = true;
|
||||
}
|
||||
|
||||
public override void SpellHit(WorldObject caster, SpellInfo spellInfo)
|
||||
{
|
||||
//We only care about interrupt effects and only if they are durring a spell currently being cast
|
||||
if (!spellInfo.HasEffect(SpellEffectName.InterruptCast) || !me.IsNonMeleeSpellCast(false))
|
||||
return;
|
||||
|
||||
//Interrupt effect
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
|
||||
//Normally we would set the cooldown equal to the spell duration
|
||||
//but we do not have access to the DurationStore
|
||||
|
||||
switch (CurrentNormalSpell)
|
||||
{
|
||||
case SpellIds.Arcmissle: ArcaneCooldown = 5000; break;
|
||||
case SpellIds.Fireball: FireCooldown = 5000; break;
|
||||
case SpellIds.Frostbolt: FrostCooldown = 5000; break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void MoveInLineOfSight(Unit who)
|
||||
{
|
||||
base.MoveInLineOfSight(who);
|
||||
|
||||
if (SeenAtiesh || me.IsInCombat() || me.GetDistance2d(who) > me.GetAttackDistance(who) + 10.0f)
|
||||
return;
|
||||
|
||||
Player player = who.ToPlayer();
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
foreach (uint id in AtieshStaves)
|
||||
{
|
||||
if (!PlayerHasWeaponEquipped(player, id))
|
||||
continue;
|
||||
|
||||
SeenAtiesh = true;
|
||||
Talk(TextIds.SayAtiesh);
|
||||
me.SetFacingTo(me.GetAbsoluteAngle(player));
|
||||
me.ClearUnitState(UnitState.Moving);
|
||||
me.GetMotionMaster().MoveDistract(7 * Time.InMilliseconds, me.GetAbsoluteAngle(who));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerHasWeaponEquipped(Player player, uint itemEntry)
|
||||
{
|
||||
Item item = player.GetItemByPos(InventorySlots.Bag0, EquipmentSlot.MainHand);
|
||||
if (item && item.GetEntry() == itemEntry)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class water_elemental : ScriptedAI
|
||||
{
|
||||
public water_elemental(Creature creature) : base(creature) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromMilliseconds(2000 + (RandomHelper.Rand32() % 3000)), task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Waterbolt);
|
||||
task.Repeat(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5));
|
||||
});
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who) { }
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 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.Scripting;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
|
||||
namespace Scripts.EasternKingdoms.Karazhan.TerestianIllhoof
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint ShadowBolt = 30055;
|
||||
public const uint SummonImp = 30066;
|
||||
public const uint FiendishPortal1 = 30171;
|
||||
public const uint FiendishPortal2 = 30179;
|
||||
public const uint Berserk = 32965;
|
||||
public const uint SummonFiendishImp = 30184;
|
||||
public const uint BrokenPact = 30065;
|
||||
public const uint AmplifyFlames = 30053;
|
||||
public const uint Firebolt = 30050;
|
||||
public const uint SummonDemonchains = 30120;
|
||||
public const uint DemonChains = 30206;
|
||||
public const uint Sacrifice = 30115;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SaySlay = 0;
|
||||
public const uint SayDeath = 1;
|
||||
public const uint SayAggro = 2;
|
||||
public const uint SaySacrifice = 3;
|
||||
public const uint SaySummonPortal = 4;
|
||||
}
|
||||
|
||||
struct MiscConst
|
||||
{
|
||||
public const uint NpcFiendishPortal = 17265;
|
||||
public const int ActionDespawnImps = 1;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_terestian : BossAI
|
||||
{
|
||||
public boss_terestian(Creature creature) : base(creature, DataTypes.Terestian) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
EntryCheckPredicate pred = new(MiscConst.NpcFiendishPortal);
|
||||
summons.DoAction(MiscConst.ActionDespawnImps, pred);
|
||||
_Reset();
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.MaxThreat, 0);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.ShadowBolt);
|
||||
task.Repeat(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(10));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(3), task =>
|
||||
{
|
||||
me.RemoveAurasDueToSpell(SpellIds.BrokenPact);
|
||||
DoCastAOE(SpellIds.SummonImp, new CastSpellExtraArgs(true));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
|
||||
{
|
||||
Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100.0f, true);
|
||||
if (target)
|
||||
{
|
||||
DoCast(target, SpellIds.Sacrifice, new CastSpellExtraArgs(true));
|
||||
target.CastSpell(target, SpellIds.SummonDemonchains, true);
|
||||
Talk(TextIds.SaySacrifice);
|
||||
}
|
||||
task.Repeat(TimeSpan.FromSeconds(42));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
|
||||
{
|
||||
Talk(TextIds.SaySummonPortal);
|
||||
DoCastAOE(SpellIds.FiendishPortal1);
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(11), task =>
|
||||
{
|
||||
DoCastAOE(SpellIds.FiendishPortal2, new CastSpellExtraArgs(true));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromMinutes(10), task =>
|
||||
{
|
||||
DoCastSelf(SpellIds.Berserk, new CastSpellExtraArgs(true));
|
||||
});
|
||||
}
|
||||
|
||||
public override void JustEngagedWith(Unit who)
|
||||
{
|
||||
base.JustEngagedWith(who);
|
||||
Talk(TextIds.SayAggro);
|
||||
}
|
||||
|
||||
public override void SpellHit(WorldObject caster, SpellInfo spellInfo)
|
||||
{
|
||||
if (spellInfo.Id == SpellIds.BrokenPact)
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(32), task =>
|
||||
{
|
||||
me.RemoveAurasDueToSpell(SpellIds.BrokenPact);
|
||||
DoCastAOE(SpellIds.SummonImp, new CastSpellExtraArgs(true));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
if (victim.IsPlayer())
|
||||
Talk(TextIds.SaySlay);
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
EntryCheckPredicate pred = new(MiscConst.NpcFiendishPortal);
|
||||
summons.DoAction(MiscConst.ActionDespawnImps, pred);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
_scheduler.Update(diff, () => DoMeleeAttackIfReady());
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_kilrek : ScriptedAI
|
||||
{
|
||||
public npc_kilrek(Creature creature) : base(creature) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(8), task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.AmplifyFlames);
|
||||
task.Repeat(TimeSpan.FromSeconds(9));
|
||||
});
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
DoCastAOE(SpellIds.BrokenPact, new CastSpellExtraArgs(true));
|
||||
me.DespawnOrUnsummon(TimeSpan.FromSeconds(15));
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, () =>
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_demon_chain : PassiveAI
|
||||
{
|
||||
ObjectGuid _sacrificeGUID;
|
||||
|
||||
public npc_demon_chain(Creature creature) : base(creature) { }
|
||||
|
||||
public override void IsSummonedBy(WorldObject summoner)
|
||||
{
|
||||
_sacrificeGUID = summoner.GetGUID();
|
||||
DoCastSelf(SpellIds.DemonChains, new CastSpellExtraArgs(true));
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Unit sacrifice = Global.ObjAccessor.GetUnit(me, _sacrificeGUID);
|
||||
if (sacrifice)
|
||||
sacrifice.RemoveAurasDueToSpell(SpellIds.Sacrifice);
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_fiendish_portal : PassiveAI
|
||||
{
|
||||
SummonList _summons;
|
||||
|
||||
public npc_fiendish_portal(Creature creature) : base(creature)
|
||||
{
|
||||
_summons = new(me);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromMilliseconds(2400), TimeSpan.FromSeconds(8), task =>
|
||||
{
|
||||
DoCastAOE(SpellIds.SummonFiendishImp, new CastSpellExtraArgs(true));
|
||||
task.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
public override void DoAction(int action)
|
||||
{
|
||||
if (action == MiscConst.ActionDespawnImps)
|
||||
_summons.DespawnAll();
|
||||
}
|
||||
|
||||
public override void JustSummoned(Creature summon)
|
||||
{
|
||||
_summons.Summon(summon);
|
||||
DoZoneInCombat(summon);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_fiendish_imp : ScriptedAI
|
||||
{
|
||||
public npc_fiendish_imp(Creature creature) : base(creature) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(2), task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Firebolt);
|
||||
task.Repeat(TimeSpan.FromMilliseconds(2400));
|
||||
});
|
||||
|
||||
me.ApplySpellImmune(0, SpellImmunity.School, SpellSchoolMask.Fire, true);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, () => DoMeleeAttackIfReady());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user