Ported .Net Core commits:

hondacrx:
- Initial commit: Switch to .Net Core 2.0
- Fix build and removed not needed files
Fabi:
- Updated solution platforms.
- Changed folder structure.
- Change library target framework to netstandard2.0.
- Updated solution platforms again...
- Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
Fabian
2017-10-26 17:23:44 +02:00
parent 227702e19c
commit a3dc7b3f48
844 changed files with 26064 additions and 1824 deletions
@@ -0,0 +1,649 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using Game.AI;
using Game.Entities;
using Game.Maps;
using Game.Scripting;
using Game.Spells;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Scripts.Northrend.AzjolNerub.AzjolNerub.Anubarak
{
struct SpellIds
{
public const uint Emerge = 53500;
public const uint Submerge = 53421;
public const uint ImpaleAura = 53456;
public const uint ImpaleVisual = 53455;
public const uint ImpaleDamage = 53454;
public const uint LeechingSwarm = 53467;
public const uint Pound = 59433;
public const uint PoundDamage = 59432;
public const uint CarrionBeetles = 53520;
public const uint CarrionBeetle = 53521;
public const uint SummonDarter = 53599;
public const uint SummonAssassin = 53609;
public const uint SummonGuardian = 53614;
public const uint SummonVenomancer = 53615;
public const uint Dart = 59349;
public const uint Backstab = 52540;
public const uint AssassinVisual = 53611;
public const uint SunderArmor = 53618;
public const uint PoisonBolt = 53617;
}
struct CreatureIds
{
public const uint WorldTrigger = 22515;
}
struct TextIds
{
public const uint SayAggro = 0;
public const uint SaySlay = 1;
public const uint SayDeath = 2;
public const uint SayLocust = 3;
public const uint SaySubmerge = 4;
public const uint SayIntro = 5;
}
struct EventIds
{
public const uint Pound = 1;
public const uint Impale = 2;
public const uint LeechingSwarm = 3;
public const uint CarrionBeetles = 4;
public const uint Submerge = 5; // Use Event For This So We Don'T Submerge Mid-Cast
public const uint Darter = 6;
public const uint Assassin = 7;
public const uint Guardian = 8;
public const uint Venomancer = 9;
public const uint CloseDoor = 10;
}
struct Misc
{
public const uint AchievGottaGoStartEvent = 20381;
public const byte PhaseEmerge = 1;
public const byte PhaseSubmerge = 2;
public const int GuidTypePet = 0;
public const int GuidTypeImpale = 1;
public const byte SummonGroupWorldTriggerGuardian = 1;
public const int ActionPetDied = 1;
public const int ActionPetEvade = 2;
}
[Script]
class boss_anub_arak : BossAI
{
public boss_anub_arak(Creature creature) : base(creature, ANDataTypes.Anubarak) { }
public override void Reset()
{
base.Reset();
me.RemoveFlag(UnitFields.Flags, UnitFlags.NonAttackable | UnitFlags.NotSelectable);
instance.DoStopCriteriaTimer(CriteriaTimedTypes.Event, Misc.AchievGottaGoStartEvent);
_nextSubmerge = 75;
_petCount = 0;
}
public override bool CanAIAttack(Unit victim) { return true; } // do not check boundary here
public override void EnterCombat(Unit who)
{
base.EnterCombat(who);
GameObject door = instance.GetGameObject(ANDataTypes.AnubarakWall);
if (door)
door.SetGoState(GameObjectState.Active); // open door for now
GameObject door2 = instance.GetGameObject(ANDataTypes.AnubarakWall2);
if (door2)
door2.SetGoState(GameObjectState.Active);
Talk(TextIds.SayAggro);
instance.DoStartCriteriaTimer(CriteriaTimedTypes.Event, Misc.AchievGottaGoStartEvent);
_events.SetPhase(Misc.PhaseEmerge);
_events.ScheduleEvent(EventIds.CloseDoor, TimeSpan.FromSeconds(5));
_events.ScheduleEvent(EventIds.Pound, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(4), 0, Misc.PhaseEmerge);
_events.ScheduleEvent(EventIds.LeechingSwarm, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(7), 0, Misc.PhaseEmerge);
_events.ScheduleEvent(EventIds.CarrionBeetles, TimeSpan.FromSeconds(14), TimeSpan.FromSeconds(17), 0, Misc.PhaseEmerge);
// set up world triggers
List<TempSummon> summoned;
me.SummonCreatureGroup(Misc.SummonGroupWorldTriggerGuardian, out summoned);
if (summoned.Empty()) // something went wrong
{
EnterEvadeMode(EvadeReason.Other);
return;
}
_guardianTrigger = summoned.First().GetGUID();
Creature trigger = DoSummon(CreatureIds.WorldTrigger, me.GetPosition(), 0u, TempSummonType.ManualDespawn);
if (trigger)
_assassinTrigger = trigger.GetGUID();
else
{
EnterEvadeMode(EvadeReason.Other);
return;
}
}
public override void EnterEvadeMode(EvadeReason why)
{
summons.DespawnAll();
_DespawnAtEvade();
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_events.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
_events.ExecuteEvents(eventId =>
{
switch (eventId)
{
case EventIds.CloseDoor:
GameObject door = instance.GetGameObject(ANDataTypes.AnubarakWall);
if (door)
door.SetGoState(GameObjectState.Ready);
GameObject door2 = instance.GetGameObject(ANDataTypes.AnubarakWall2);
if (door2)
door2.SetGoState(GameObjectState.Ready);
break;
case EventIds.Pound:
DoCastVictim(SpellIds.Pound);
_events.Repeat(TimeSpan.FromSeconds(26), TimeSpan.FromSeconds(32));
break;
case EventIds.LeechingSwarm:
Talk(TextIds.SayLocust);
DoCastAOE(SpellIds.LeechingSwarm);
_events.Repeat(TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(28));
break;
case EventIds.CarrionBeetles:
DoCastAOE(SpellIds.CarrionBeetles);
_events.Repeat(TimeSpan.FromSeconds(24), TimeSpan.FromSeconds(27));
break;
case EventIds.Impale:
Creature impaleTarget = ObjectAccessor.GetCreature(me, _impaleTarget);
if (impaleTarget)
DoCast(impaleTarget, SpellIds.ImpaleDamage, true);
break;
case EventIds.Submerge:
Talk(TextIds.SaySubmerge);
DoCastSelf(SpellIds.Submerge);
break;
case EventIds.Darter:
{
List<Creature> triggers = new List<Creature>();
me.GetCreatureListWithEntryInGrid(triggers, CreatureIds.WorldTrigger);
if (!triggers.Empty())
{
var it = triggers.SelectRandom();
it.CastSpell(it, SpellIds.SummonDarter, true);
_events.Repeat(TimeSpan.FromSeconds(11));
}
else
EnterEvadeMode(EvadeReason.Other);
break;
}
case EventIds.Assassin:
{
Creature trigger = ObjectAccessor.GetCreature(me, _assassinTrigger);
if (trigger)
{
trigger.CastSpell(trigger, SpellIds.SummonAssassin, true);
trigger.CastSpell(trigger, SpellIds.SummonAssassin, true);
if (_assassinCount > 2)
{
_assassinCount -= 2;
_events.Repeat(TimeSpan.FromSeconds(20));
}
else
_assassinCount = 0;
}
else // something went wrong
EnterEvadeMode(EvadeReason.Other);
break;
}
case EventIds.Guardian:
{
Creature trigger = ObjectAccessor.GetCreature(me, _guardianTrigger);
if (trigger)
{
trigger.CastSpell(trigger, SpellIds.SummonGuardian, true);
trigger.CastSpell(trigger, SpellIds.SummonGuardian, true);
if (_guardianCount > 2)
{
_guardianCount -= 2;
_events.Repeat(TimeSpan.FromSeconds(20));
}
else
_guardianCount = 0;
}
else
EnterEvadeMode(EvadeReason.Other);
}
break;
case EventIds.Venomancer:
{
Creature trigger = ObjectAccessor.GetCreature(me, _guardianTrigger);
if (trigger)
{
trigger.CastSpell(trigger, SpellIds.SummonVenomancer, true);
trigger.CastSpell(trigger, SpellIds.SummonVenomancer, true);
if (_venomancerCount > 2)
{
_venomancerCount -= 2;
_events.Repeat(TimeSpan.FromSeconds(20));
}
else
_venomancerCount = 0;
}
else
EnterEvadeMode(EvadeReason.Other);
}
break;
default:
break;
}
if (me.HasUnitState(UnitState.Casting))
return;
});
DoMeleeAttackIfReady();
}
public override void JustDied(Unit killer)
{
_JustDied();
Talk(TextIds.SayDeath);
}
public override void KilledUnit(Unit victim)
{
if (victim.IsTypeId(TypeId.Player))
Talk(TextIds.SaySlay);
}
public override void SetGUID(ObjectGuid guid, int type)
{
switch (type)
{
case Misc.GuidTypePet:
{
Creature creature = ObjectAccessor.GetCreature(me, guid);
if (creature)
JustSummoned(creature);
else // something has gone horribly wrong
EnterEvadeMode(EvadeReason.Other);
break;
}
case Misc.GuidTypeImpale:
_impaleTarget = guid;
_events.ScheduleEvent(EventIds.Impale, TimeSpan.FromSeconds(4));
break;
}
}
public override void DoAction(int action)
{
switch (action)
{
case Misc.ActionPetDied:
if (_petCount == 0) // underflow check - something has gone horribly wrong
{
EnterEvadeMode(EvadeReason.Other);
return;
}
if (--_petCount == 0) // last pet died, emerge
{
me.RemoveAurasDueToSpell(SpellIds.Submerge);
me.RemoveAurasDueToSpell(SpellIds.ImpaleAura);
me.RemoveFlag(UnitFields.Flags, UnitFlags.NonAttackable | UnitFlags.NotSelectable);
DoCastSelf(SpellIds.Emerge);
_events.SetPhase(Misc.PhaseEmerge);
_events.ScheduleEvent(EventIds.Pound, TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(18), 0, Misc.PhaseEmerge);
_events.ScheduleEvent(EventIds.LeechingSwarm, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), 0, Misc.PhaseEmerge);
_events.ScheduleEvent(EventIds.CarrionBeetles, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15), 0, Misc.PhaseEmerge);
}
break;
case Misc.ActionPetEvade:
EnterEvadeMode(EvadeReason.Other);
break;
}
}
public override void DamageTaken(Unit source, ref uint damage)
{
if (me.HasAura(SpellIds.Submerge))
damage = 0;
else
if (_nextSubmerge != 0 && me.HealthBelowPctDamaged((int)_nextSubmerge, damage))
{
_events.CancelEvent(EventIds.Submerge);
_events.ScheduleEvent(EventIds.Submerge, 0, 0, Misc.PhaseEmerge);
_nextSubmerge = _nextSubmerge - 25;
}
}
public override void SpellHit(Unit whose, SpellInfo spell)
{
if (spell.Id == SpellIds.Submerge)
{
me.SetFlag(UnitFields.Flags, UnitFlags.NonAttackable | UnitFlags.NotSelectable);
me.RemoveAurasDueToSpell(SpellIds.LeechingSwarm);
DoCastSelf(SpellIds.ImpaleAura, true);
_events.SetPhase(Misc.PhaseSubmerge);
switch (_nextSubmerge)
{
case 50: // first submerge phase
_assassinCount = 4;
_guardianCount = 2;
_venomancerCount = 0;
break;
case 25: // second submerge phase
_assassinCount = 6;
_guardianCount = 2;
_venomancerCount = 2;
break;
case 0: // third submerge phase
_assassinCount = 6;
_guardianCount = 2;
_venomancerCount = 2;
_events.ScheduleEvent(EventIds.Darter, TimeSpan.FromSeconds(0), 0, Misc.PhaseSubmerge);
break;
}
_petCount = (uint)(_guardianCount + _venomancerCount);
if (_assassinCount != 0)
_events.ScheduleEvent(EventIds.Assassin, TimeSpan.FromSeconds(0), 0, Misc.PhaseSubmerge);
if (_guardianCount != 0)
_events.ScheduleEvent(EventIds.Guardian, TimeSpan.FromSeconds(4), 0, Misc.PhaseSubmerge);
if (_venomancerCount != 0)
_events.ScheduleEvent(EventIds.Venomancer, TimeSpan.FromSeconds(20), 0, Misc.PhaseSubmerge);
}
}
ObjectGuid _impaleTarget;
uint _nextSubmerge;
uint _petCount;
ObjectGuid _guardianTrigger;
ObjectGuid _assassinTrigger;
byte _assassinCount;
byte _guardianCount;
byte _venomancerCount;
}
class npc_anubarak_pet_template : ScriptedAI
{
public npc_anubarak_pet_template(Creature creature, bool isLarge) : base(creature)
{
_instance = creature.GetInstanceScript();
_isLarge = isLarge;
}
public override void InitializeAI()
{
base.InitializeAI();
Creature anubarak = _instance.GetCreature(ANDataTypes.Anubarak);
if (anubarak)
anubarak.GetAI().SetGUID(me.GetGUID(), Misc.GuidTypePet);
else
me.DespawnOrUnsummon();
}
public override void JustDied(Unit killer)
{
base.JustDied(killer);
if (_isLarge)
{
Creature anubarak = _instance.GetCreature(ANDataTypes.Anubarak);
if (anubarak)
anubarak.GetAI().DoAction(Misc.ActionPetDied);
}
}
public override void EnterEvadeMode(EvadeReason why)
{
Creature anubarak = _instance.GetCreature(ANDataTypes.Anubarak);
if (anubarak)
anubarak.GetAI().DoAction(Misc.ActionPetEvade);
else
me.DespawnOrUnsummon();
}
protected InstanceScript _instance;
bool _isLarge;
}
[Script]
class npc_anubarak_anub_ar_darter : npc_anubarak_pet_template
{
public npc_anubarak_anub_ar_darter(Creature creature) : base(creature, false) { }
public override void InitializeAI()
{
base.InitializeAI();
DoCastAOE(SpellIds.Dart);
}
}
[Script]
class npc_anubarak_anub_ar_assassin : npc_anubarak_pet_template
{
public npc_anubarak_anub_ar_assassin(Creature creature) : base(creature, false)
{
_backstabTimer = 6 * Time.InMilliseconds;
}
bool IsInBounds(Position jumpTo, List<AreaBoundary> boundary)
{
if (boundary == null)
return true;
foreach (var it in boundary)
if (!it.IsWithinBoundary(jumpTo))
return false;
return true;
}
Position GetRandomPositionAround(Creature anubarak)
{
float DISTANCE_MIN = 10.0f;
float DISTANCE_MAX = 30.0f;
double angle = RandomHelper.NextDouble() * 2.0 * Math.PI;
return new Position(anubarak.GetPositionX() + (float)(RandomHelper.FRand(DISTANCE_MIN, DISTANCE_MAX) * Math.Sin(angle)), anubarak.GetPositionY() + (float)(RandomHelper.FRand(DISTANCE_MIN, DISTANCE_MAX) * Math.Cos(angle)), anubarak.GetPositionZ());
}
public override void InitializeAI()
{
base.InitializeAI();
var boundary = _instance.GetBossBoundary(ANDataTypes.Anubarak);
Creature anubarak = _instance.GetCreature(ANDataTypes.Anubarak);
if (anubarak)
{
Position jumpTo;
do
jumpTo = GetRandomPositionAround(anubarak);
while (!IsInBounds(jumpTo, boundary));
me.GetMotionMaster().MoveJump(jumpTo, 40.0f, 40.0f);
DoCastSelf(SpellIds.AssassinVisual, true);
}
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
if (diff >= _backstabTimer)
{
if (me.GetVictim() && me.GetVictim().isInBack(me))
DoCastVictim(SpellIds.Backstab);
_backstabTimer = 6 * Time.InMilliseconds;
}
else
_backstabTimer -= diff;
DoMeleeAttackIfReady();
}
public override void MovementInform(MovementGeneratorType type, uint id)
{
if (id == EventId.Jump)
{
me.RemoveAurasDueToSpell(SpellIds.AssassinVisual);
DoZoneInCombat();
}
}
uint _backstabTimer;
}
[Script]
class npc_anubarak_anub_ar_guardian : npc_anubarak_pet_template
{
public npc_anubarak_anub_ar_guardian(Creature creature) : base(creature, true)
{
_sunderTimer = 6 * Time.InMilliseconds;
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
if (diff >= _sunderTimer)
{
DoCastVictim(SpellIds.SunderArmor);
_sunderTimer = 12 * Time.InMilliseconds;
}
else
_sunderTimer -= diff;
DoMeleeAttackIfReady();
}
uint _sunderTimer;
}
[Script]
class npc_anubarak_anub_ar_venomancer : npc_anubarak_pet_template
{
public npc_anubarak_anub_ar_venomancer(Creature creature) : base(creature, true)
{
_boltTimer = 5 * Time.InMilliseconds;
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
if (diff >= _boltTimer)
{
DoCastVictim(SpellIds.PoisonBolt);
_boltTimer = RandomHelper.URand(2, 3) * Time.InMilliseconds;
}
else
_boltTimer -= diff;
DoMeleeAttackIfReady();
}
uint _boltTimer;
}
[Script]
class npc_anubarak_impale_target : NullCreatureAI
{
public npc_anubarak_impale_target(Creature creature) : base(creature) { }
public override void InitializeAI()
{
Creature anubarak = me.GetInstanceScript().GetCreature(ANDataTypes.Anubarak);
if (anubarak)
{
DoCastSelf(SpellIds.ImpaleVisual);
me.DespawnOrUnsummon(TimeSpan.FromSeconds(6));
anubarak.GetAI().SetGUID(me.GetGUID(), Misc.GuidTypeImpale);
}
else
me.DespawnOrUnsummon();
}
}
[Script]
class spell_anubarak_pound : SpellScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.PoundDamage);
}
void HandleDummy(uint effIndex)
{
Unit target = GetHitUnit();
if (target)
GetCaster().CastSpell(target, SpellIds.PoundDamage, true);
}
public override void Register()
{
OnEffectHitTarget.Add(new EffectHandler(HandleDummy, 0, SpellEffectName.ApplyAura));
}
}
[Script]
class spell_anubarak_carrion_beetles : AuraScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.CarrionBeetle);
}
void HandlePeriodic(AuraEffect eff)
{
GetCaster().CastSpell(GetCaster(), SpellIds.CarrionBeetle, true);
GetCaster().CastSpell(GetCaster(), SpellIds.CarrionBeetle, true);
}
public override void Register()
{
OnEffectPeriodic.Add(new EffectPeriodicHandler(HandlePeriodic, 0, AuraType.PeriodicDummy));
}
}
}
@@ -0,0 +1,866 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using Game.AI;
using Game.Entities;
using Game.Maps;
using Game.Scripting;
using Game.Spells;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Scripts.Northrend.AzjolNerub.AzjolNerub.KrikthirTheGatewatcher
{
struct SpellIds
{
// Krik'Thir The Gatewatcher
public const uint SubbossAggroTrigger = 52343;
public const uint Swarm = 52440;
public const uint MindFlay = 52586;
public const uint CurseOfFatigue = 52592;
public const uint Frenzy = 28747;
// Watchers - Shared
public const uint WebWrap = 52086;
public const uint WebWrapWrapped = 52087;
public const uint InfectedBite = 52469;
// Watcher Gashra
public const uint Enrage = 52470;
// Watcher Narjil
public const uint BlindingWebs = 52524;
// Watcher Silthik
public const uint PoisonSpray = 52493;
// Anub'Ar Warrior
public const uint Cleave = 49806;
public const uint Strike = 52532;
// Anub'Ar Skirmisher
public const uint Charge = 52538;
public const uint Backstab = 52540;
public const uint FixtateTrigger = 52536;
public const uint FixtateTriggered = 52537;
// Anub'Ar Shadowcaster
public const uint ShadowBolt = 52534;
public const uint ShadowNova = 52535;
// Skittering Infector
public const uint AcidSplash = 52446;
}
struct Misc
{
public const uint DataPetGroup = 0;
// Krik'thir the Gatewatcher
public const uint EventSendGroup = 1;
public const uint EventSwarm = 2;
public const uint EventMindFlay = 3;
public const uint EventFrenzy = 4;
}
struct ActionIds
{
public const int GashraDied = 0;
public const int NarjilDied = 1;
public const int SilthikDied = 2;
public const int WatcherEngaged = 3;
public const int PetEngaged = 4;
public const int PetEvade = 5;
}
struct TextIds
{
public const uint SayAggro = 0;
public const uint SaySlay = 1;
public const uint SayDeath = 2;
public const uint SaySwarm = 3;
public const uint SayPrefight = 4;
public const uint SaySendGroup = 5;
}
[Script]
class boss_krik_thir : BossAI
{
public boss_krik_thir(Creature creature) : base(creature, ANDataTypes.KrikthirTheGatewatcher) { }
void SummonAdds()
{
if (instance.GetBossState(ANDataTypes.KrikthirTheGatewatcher) == EncounterState.Done)
return;
for (byte i = 1; i <= 3; ++i)
{
List<TempSummon> summons;
me.SummonCreatureGroup(i, out summons);
foreach (TempSummon summon in summons)
summon.GetAI().SetData(Misc.DataPetGroup, i);
}
}
public override void Reset()
{
base.Reset();
_hadFrenzy = false;
_petsInCombat = false;
_watchersActive = 0;
me.SetReactState(ReactStates.Passive);
}
public override void InitializeAI()
{
base.InitializeAI();
SummonAdds();
}
public override void JustRespawned()
{
base.JustRespawned();
SummonAdds();
}
public override void KilledUnit(Unit victim)
{
if (victim.IsTypeId(TypeId.Player))
Talk(TextIds.SaySlay);
}
public override void JustDied(Unit killer)
{
summons.Clear();
base.JustDied(killer);
Talk(TextIds.SayDeath);
}
public override void EnterCombat(Unit who)
{
_petsInCombat = false;
me.SetReactState(ReactStates.Aggressive);
summons.DoZoneInCombat();
_events.CancelEvent(Misc.EventSendGroup);
_events.ScheduleEvent(Misc.EventSwarm, TimeSpan.FromSeconds(5));
_events.ScheduleEvent(Misc.EventMindFlay, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3));
base.EnterCombat(who);
}
public override void MoveInLineOfSight(Unit who)
{
if (!me.HasReactState(ReactStates.Passive))
{
base.MoveInLineOfSight(who);
return;
}
if (me.CanStartAttack(who, false) && me.IsWithinDistInMap(who, me.GetAttackDistance(who) + me.m_CombatDistance))
EnterCombat(who);
}
public override void EnterEvadeMode(EvadeReason why)
{
summons.DespawnAll();
_DespawnAtEvade();
}
public override void DoAction(int action)
{
switch (action)
{
case -ANInstanceMisc.ActionGatewatcherGreet:
if (!_hadGreet && me.IsAlive() && !me.IsInCombat() && !_petsInCombat)
{
_hadGreet = true;
Talk(TextIds.SayPrefight);
}
break;
case ActionIds.GashraDied:
case ActionIds.NarjilDied:
case ActionIds.SilthikDied:
if (_watchersActive == 0) // something is wrong
{
EnterEvadeMode(EvadeReason.Other);
return;
}
if ((--_watchersActive) == 0) // if there are no watchers currently in combat...
_events.RescheduleEvent(Misc.EventSendGroup, TimeSpan.FromSeconds(5)); // ...send the next watcher after the targets sooner
break;
case ActionIds.WatcherEngaged:
++_watchersActive;
break;
case ActionIds.PetEngaged:
if (_petsInCombat || me.IsInCombat())
break;
_petsInCombat = true;
Talk(TextIds.SayAggro);
_events.ScheduleEvent(Misc.EventSendGroup, TimeSpan.FromSeconds(70));
break;
case ActionIds.PetEvade:
EnterEvadeMode(EvadeReason.Other);
break;
}
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim() && !_petsInCombat)
return;
_events.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
if (me.HealthBelowPct(10) && !_hadFrenzy)
{
_hadFrenzy = true;
_events.ScheduleEvent(Misc.EventFrenzy, TimeSpan.FromSeconds(1));
}
_events.ExecuteEvents(eventId =>
{
switch (eventId)
{
case Misc.EventSendGroup:
DoCastAOE(SpellIds.SubbossAggroTrigger, true);
_events.Repeat(TimeSpan.FromSeconds(70));
break;
case Misc.EventSwarm:
DoCastAOE(SpellIds.Swarm);
Talk(TextIds.SaySwarm);
break;
case Misc.EventMindFlay:
DoCastVictim(SpellIds.MindFlay);
_events.Repeat(TimeSpan.FromSeconds(9), TimeSpan.FromSeconds(11));
break;
case Misc.EventFrenzy:
DoCastSelf(SpellIds.Frenzy);
DoCastAOE(SpellIds.CurseOfFatigue);
_events.Repeat(TimeSpan.FromSeconds(15));
break;
}
if (me.HasUnitState(UnitState.Casting))
return;
});
DoMeleeAttackIfReady();
}
public override void SpellHit(Unit whose, SpellInfo spell)
{
if (spell.Id == SpellIds.SubbossAggroTrigger)
DoZoneInCombat();
}
public override void SpellHitTarget(Unit who, SpellInfo spell)
{
if (spell.Id == SpellIds.SubbossAggroTrigger)
Talk(TextIds.SaySendGroup);
}
bool _hadGreet;
bool _hadFrenzy;
bool _petsInCombat;
byte _watchersActive;
}
class npc_gatewatcher_petAI : ScriptedAI
{
public npc_gatewatcher_petAI(Creature creature, bool isWatcher) : base(creature)
{
_instance = creature.GetInstanceScript();
_isWatcher = isWatcher;
}
public virtual void _EnterCombat() { }
public override void EnterCombat(Unit who)
{
if (_isWatcher)
{
_isWatcher = false;
TempSummon meSummon = me.ToTempSummon();
if (meSummon)
{
Creature summoner = meSummon.GetSummonerCreatureBase();
if (summoner)
summoner.GetAI().DoAction(ActionIds.WatcherEngaged);
}
}
if (me.HasReactState(ReactStates.Passive))
{
List<Creature> others = new List<Creature>();
me.GetCreatureListWithEntryInGrid(others, 0, 40.0f);
foreach (Creature other in others)
{
if (other.GetAI().GetData(Misc.DataPetGroup) == _petGroup)
{
other.SetReactState(ReactStates.Aggressive);
other.GetAI().AttackStart(who);
}
}
TempSummon meSummon = me.ToTempSummon();
if (meSummon)
{
Creature summoner = meSummon.GetSummonerCreatureBase();
if (summoner)
summoner.GetAI().DoAction(ActionIds.PetEngaged);
}
}
_EnterCombat();
base.EnterCombat(who);
}
public override void SetData(uint data, uint value)
{
if (data == Misc.DataPetGroup)
{
_petGroup = value;
me.SetReactState(_petGroup != 0 ? ReactStates.Passive : ReactStates.Aggressive);
}
}
public override uint GetData(uint data)
{
if (data == Misc.DataPetGroup)
return _petGroup;
return 0;
}
public override void MoveInLineOfSight(Unit who)
{
if (!me.HasReactState(ReactStates.Passive))
{
base.MoveInLineOfSight(who);
return;
}
if (me.CanStartAttack(who, false) && me.IsWithinDistInMap(who, me.GetAttackDistance(who) + me.m_CombatDistance))
EnterCombat(who);
}
public override void SpellHit(Unit whose, SpellInfo spell)
{
if (spell.Id == SpellIds.SubbossAggroTrigger)
DoZoneInCombat();
}
public override void EnterEvadeMode(EvadeReason why)
{
TempSummon meSummon = me.ToTempSummon();
if (meSummon)
{
Creature summoner = meSummon.GetSummonerCreatureBase();
if (summoner)
summoner.GetAI().DoAction(ActionIds.PetEvade);
else
me.DespawnOrUnsummon();
return;
}
base.EnterEvadeMode(why);
}
protected InstanceScript _instance;
uint _petGroup;
bool _isWatcher;
}
[Script]
class npc_watcher_gashra : npc_gatewatcher_petAI
{
public npc_watcher_gashra(Creature creature) : base(creature, true)
{
me.SetReactState(ReactStates.Passive);
}
public override void Reset()
{
_scheduler.CancelAll();
}
public override void _EnterCombat()
{
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
_scheduler.Schedule(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), task =>
{
DoCastSelf(SpellIds.Enrage);
task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(20));
});
_scheduler.Schedule(TimeSpan.FromSeconds(16), TimeSpan.FromSeconds(19), task =>
{
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 100.0f);
if (target)
DoCast(target, SpellIds.WebWrap);
task.Repeat(TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(19));
});
_scheduler.Schedule(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(11), task =>
{
DoCastVictim(SpellIds.InfectedBite);
task.Repeat(TimeSpan.FromSeconds(23), TimeSpan.FromSeconds(27));
});
}
public override void JustDied(Unit killer)
{
Creature krikthir = _instance.GetCreature(ANDataTypes.KrikthirTheGatewatcher);
if (krikthir && krikthir.IsAlive())
krikthir.GetAI().DoAction(ActionIds.GashraDied);
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
DoMeleeAttackIfReady();
}
}
[Script]
class npc_watcher_narjil : npc_gatewatcher_petAI
{
public npc_watcher_narjil(Creature creature) : base(creature, true) { }
public override void Reset()
{
_scheduler.CancelAll();
}
public override void _EnterCombat()
{
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
_scheduler.Schedule(TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(18), task =>
{
DoCastVictim(SpellIds.BlindingWebs);
task.Repeat(TimeSpan.FromSeconds(23), TimeSpan.FromSeconds(27));
});
_scheduler.Schedule(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), task =>
{
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 100, true);
if (target)
DoCast(target, SpellIds.WebWrap);
task.Repeat(TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(19));
});
_scheduler.Schedule(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(11), task =>
{
DoCastVictim(SpellIds.InfectedBite);
task.Repeat(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(25));
});
}
public override void JustDied(Unit killer)
{
Creature krikthir = _instance.GetCreature(ANDataTypes.KrikthirTheGatewatcher);
if (krikthir && krikthir.IsAlive())
krikthir.GetAI().DoAction(ActionIds.NarjilDied);
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
DoMeleeAttackIfReady();
}
}
[Script]
class npc_watcher_silthik : npc_gatewatcher_petAI
{
public npc_watcher_silthik(Creature creature) : base(creature, true) { }
public override void Reset()
{
_scheduler.CancelAll();
}
public override void _EnterCombat()
{
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
_scheduler.Schedule(TimeSpan.FromSeconds(16), TimeSpan.FromSeconds(19), task =>
{
DoCastVictim(SpellIds.PoisonSpray);
task.Repeat(TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(19));
});
_scheduler.Schedule(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(11), task =>
{
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 100, true);
if (target)
DoCast(target, SpellIds.WebWrap);
task.Repeat(TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(17));
});
_scheduler.Schedule(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), task =>
{
DoCastVictim(SpellIds.InfectedBite);
task.Repeat(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(24));
});
}
public override void JustDied(Unit killer)
{
Creature krikthir = _instance.GetCreature(ANDataTypes.KrikthirTheGatewatcher);
if (krikthir && krikthir.IsAlive())
krikthir.GetAI().DoAction(ActionIds.SilthikDied);
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
DoMeleeAttackIfReady();
}
}
[Script]
class npc_anub_ar_warrior : npc_gatewatcher_petAI
{
public npc_anub_ar_warrior(Creature creature) : base(creature, false) { }
public override void Reset()
{
_scheduler.CancelAll();
}
public override void _EnterCombat()
{
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
_scheduler.Schedule(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(9), task =>
{
DoCastVictim(SpellIds.Cleave);
task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(16));
});
_scheduler.Schedule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10), task =>
{
DoCastVictim(SpellIds.Strike);
task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(19));
});
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
DoMeleeAttackIfReady();
}
}
[Script]
class npc_anub_ar_skirmisher : npc_gatewatcher_petAI
{
public npc_anub_ar_skirmisher(Creature creature) : base(creature, false) { }
public override void Reset()
{
_scheduler.CancelAll();
}
public override void _EnterCombat()
{
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
_scheduler.Schedule(TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(8), task =>
{
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 100.0f, true);
if (target)
DoCast(target, SpellIds.Charge);
task.Repeat(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(25));
});
_scheduler.Schedule(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(9), task =>
{
if (me.GetVictim() && me.GetVictim().isInBack(me))
DoCastVictim(SpellIds.Backstab);
task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(13));
});
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
DoMeleeAttackIfReady();
}
public override void SpellHitTarget(Unit target, SpellInfo spell)
{
if (spell.Id == SpellIds.Charge && target)
DoCast(target, SpellIds.FixtateTrigger);
}
}
[Script]
class npc_anub_ar_shadowcaster : npc_gatewatcher_petAI
{
public npc_anub_ar_shadowcaster(Creature creature) : base(creature, false) { }
public override void Reset()
{
_scheduler.CancelAll();
}
public override void _EnterCombat()
{
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
_scheduler.Schedule(TimeSpan.FromSeconds(4), task =>
{
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 100.0f, true);
if (target)
DoCast(target, SpellIds.ShadowBolt);
task.Repeat(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(4));
});
_scheduler.Schedule(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(14), task =>
{
DoCastVictim(SpellIds.ShadowNova);
task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(16));
});
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
DoMeleeAttackIfReady();
}
}
[Script]
class npc_skittering_swarmer : ScriptedAI
{
public npc_skittering_swarmer(Creature creature) : base(creature) { }
public override void InitializeAI()
{
base.InitializeAI();
Creature gatewatcher = me.GetInstanceScript().GetCreature(ANDataTypes.KrikthirTheGatewatcher);
if (gatewatcher)
{
Unit target = gatewatcher.getAttackerForHelper();
if (target)
AttackStart(target);
gatewatcher.GetAI().JustSummoned(me);
}
}
}
[Script]
class npc_skittering_infector : ScriptedAI
{
public npc_skittering_infector(Creature creature) : base(creature) { }
public override void InitializeAI()
{
base.InitializeAI();
Creature gatewatcher = me.GetInstanceScript().GetCreature(ANDataTypes.KrikthirTheGatewatcher);
if (gatewatcher)
{
Unit target = gatewatcher.getAttackerForHelper();
if (target)
AttackStart(target);
gatewatcher.GetAI().JustSummoned(me);
}
}
public override void JustDied(Unit killer)
{
DoCastAOE(SpellIds.AcidSplash);
base.JustDied(killer);
}
}
[Script]
class npc_gatewatcher_web_wrap : NullCreatureAI
{
public npc_gatewatcher_web_wrap(Creature creature) : base(creature) { }
public override void JustDied(Unit killer)
{
TempSummon meSummon = me.ToTempSummon();
if (meSummon)
{
Unit summoner = meSummon.GetSummoner();
if (summoner)
summoner.RemoveAurasDueToSpell(SpellIds.WebWrapWrapped);
}
}
}
[Script]
class spell_gatewatcher_subboss_trigger : SpellScript
{
void HandleTargets(List<WorldObject> targetList)
{
// Remove any Watchers that are already in combat
foreach (var obj in targetList.ToList())
{
Creature creature = obj.ToCreature();
if (creature)
if (creature.IsAlive() && !creature.IsInCombat())
continue;
targetList.Remove(obj);
}
// Default to Krik'thir himself if he isn't engaged
WorldObject target = null;
if (GetCaster() && !GetCaster().IsInCombat())
target = GetCaster();
// Unless there are Watchers that aren't engaged yet
if (!targetList.Empty())
{
// If there are, pick one of them at random
target = targetList.SelectRandom();
}
// And hit only that one
targetList.Clear();
if (target)
targetList.Add(target);
}
public override void Register()
{
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(HandleTargets, 0, Targets.UnitSrcAreaEntry));
}
}
[Script]
class spell_anub_ar_skirmisher_fixtate : SpellScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.FixtateTriggered);
}
void HandleScript(uint effIndex)
{
Unit target = GetHitUnit();
if (target)
target.CastSpell(GetCaster(), SpellIds.FixtateTriggered, true);
}
public override void Register()
{
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
}
}
[Script]
class spell_gatewatcher_web_wrap : AuraScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.WebWrapWrapped);
}
void HandleEffectRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
{
if (GetTargetApplication().GetRemoveMode() != AuraRemoveMode.Expire)
return;
Unit target = GetTarget();
if (target)
target.CastSpell(target, SpellIds.WebWrapWrapped, true);
}
public override void Register()
{
OnEffectRemove.Add(new EffectApplyHandler(HandleEffectRemove, 0, AuraType.ModRoot, AuraEffectHandleModes.Real));
}
}
[Script]
class achievement_watch_him_die : AchievementCriteriaScript
{
public achievement_watch_him_die() : base("achievement_watch_him_die") { }
public override bool OnCheck(Player player, Unit target)
{
if (!target)
return false;
InstanceScript instance = target.GetInstanceScript();
if (instance == null)
return false;
foreach (uint watcherData in new[] { ANDataTypes.WatcherGashra, ANDataTypes.WatcherNarjil, ANDataTypes.WatcherSilthik })
{
Creature watcher = instance.GetCreature(watcherData);
if (watcher)
if (watcher.IsAlive())
continue;
return false;
}
return true;
}
}
}
@@ -0,0 +1,943 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using Game.AI;
using Game.Combat;
using Game.Entities;
using Game.Maps;
using Game.Scripting;
using Game.Spells;
using System;
using System.Collections.Generic;
namespace Scripts.Northrend.AzjolNerub.AzjolNerub.Nadronox
{
struct SpellIds
{
// Hadronox
public const uint WebFrontDoors = 53177;
public const uint WebSideDoors = 53185;
public const uint LeechPoison = 53030;
public const uint LeechPoisonHeal = 53800;
public const uint AcidCloud = 53400;
public const uint WebGrab = 57731;
public const uint PierceArmor = 53418;
// Anub'Ar Opponent Summoning Spells
public const uint SummonChampionPeriodic = 53035;
public const uint SummonCryptFiendPeriodic = 53037;
public const uint SummonNecromancerPeriodic = 53036;
public const uint SummonChampionTop = 53064;
public const uint SummonCryptFiendTop = 53065;
public const uint SummonNecromancerTop = 53066;
public const uint SummonChampionBottom = 53090;
public const uint SummonCryptFiendBottom = 53091;
public const uint SummonNecromancerBottom = 53092;
// Anub'Ar Crusher
public const uint Smash = 53318;
public const uint Frenzy = 53801;
// Anub'Ar Foes - Shared
public const uint Taunt = 53798;
// Anub'Ar Champion
public const uint Rend = 59343;
public const uint Pummel = 59344;
// Anub'Ar Crypt Guard
public const uint CrushingWebs = 59347;
public const uint InfectedWound = 59348;
// Anub'Ar Necromancer
public const uint ShadowBolt = 53333;
public const uint AnimateBones1 = 53334;
public const uint AnimateBones2 = 53336;
}
enum SummonGroups
{
Crusher1 = 1,
Crusher2 = 2,
Crusher3 = 3
}
struct ActionIds
{
public const int HadronoxMove = 1;
public const int CrusherEngaged = 2;
public const int PackWalk = 3;
}
struct Data
{
public const uint CrusherPackId = 1;
public const uint HadronoxEnteredCombat = 2;
public const uint HadronoxWebbedDoors = 3;
}
struct CreatureIds
{
public const uint Crusher = 28922;
public const uint WorldtriggerLarge = 23472;
}
struct TextIds
{
public const uint SayCrusherAggro = 1;
public const uint EmoteCrusherFrenzy = 2;
public const uint EmoteHadronoxMove = 1;
}
// Movement IDs used by the permanently spawning Anub'ar opponents - they are done in sequence, as one finishes, the next one starts
enum MovementIds
{
None = 0,
Outside,
Downstairs,
Downstairs2,
Hadronox, // this one might have us take a detour to avoid pathfinding "through" the floor...
HadronoxReal // while this one will always make us movechase
}
struct Misc
{
public static Position[] hadronoxStep =
{
new Position(515.5848f, 544.2007f, 673.6272f),
new Position(562.191f , 514.068f , 696.4448f),
new Position(610.3828f, 518.6407f, 695.9385f),
new Position(530.42f , 560.003f, 733.0308f)
};
public static Position[] crusherWaypoints =
{
new Position(529.6913f, 547.1257f, 731.9155f, 4.799650f),
new Position(517.51f , 561.439f , 734.0306f, 4.520403f),
new Position(543.414f , 551.728f , 732.0522f, 3.996804f)
};
public static Position[] championWaypoints =
{
new Position(539.2076f, 549.7539f, 732.8668f, 4.55531f),
new Position(527.3098f, 559.5197f, 732.9407f, 4.742493f),
new Position()
};
public static Position[] cryptFiendWaypoints =
{
new Position(520.3911f, 548.7895f, 732.0118f, 5.0091f),
new Position(),
new Position(550.9611f, 545.1674f, 731.9031f, 3.996804f)
};
public static Position[] necromancerWaypoints =
{
new Position(),
new Position(507.6937f, 563.3471f, 734.8986f, 4.520403f),
new Position(535.1049f, 552.8961f, 732.8441f, 3.996804f),
};
public static Position[] initialMoves =
{
new Position(485.314606f, 611.418640f, 771.428406f),
new Position(575.760437f, 611.516418f, 771.427368f),
new Position(588.930725f, 598.233276f, 739.142151f)
};
public static Position[] downstairsMoves =
{
new Position(513.574341f, 587.022156f, 736.229065f),
new Position(537.920410f, 580.436157f, 732.796692f),
new Position(601.289246f, 583.259644f, 725.443054f),
};
public static Position[] downstairsMoves2 =
{
new Position(571.498718f, 576.978333f, 727.582947f),
new Position(571.498718f, 576.978333f, 727.582947f),
new Position()
};
}
[Script]
class boss_hadronox : BossAI
{
public boss_hadronox(Creature creature) : base(creature, ANDataTypes.Hadronox) { }
bool IsInCombatWithPlayer()
{
List<HostileReference> refs = me.GetThreatManager().getThreatList();
foreach (HostileReference hostileRef in refs)
{
Unit target = hostileRef.getTarget();
if (target)
if (target.IsControlledByPlayer())
return true;
}
return false;
}
void SetStep(byte step)
{
if (_lastPlayerCombatState)
return;
_step = step;
me.SetHomePosition(Misc.hadronoxStep[step]);
me.GetMotionMaster().Clear();
me.AttackStop();
SetCombatMovement(false);
me.GetMotionMaster().MovePoint(0, Misc.hadronoxStep[step]);
}
void SummonCrusherPack(SummonGroups group)
{
List<TempSummon> summoned;
me.SummonCreatureGroup((byte)group, out summoned);
foreach (TempSummon summon in summoned)
{
summon.GetAI().SetData(Data.CrusherPackId, (uint)group);
summon.GetAI().DoAction(ActionIds.PackWalk);
}
}
public override void MovementInform(MovementGeneratorType type, uint id)
{
if (type != MovementGeneratorType.Point)
return;
SetCombatMovement(true);
AttackStart(me.GetVictim());
if (_step < Misc.hadronoxStep.Length - 1)
return;
DoCastAOE(SpellIds.WebFrontDoors);
DoCastAOE(SpellIds.WebSideDoors);
_doorsWebbed = true;
DoZoneInCombat();
}
public override uint GetData(uint data)
{
if (data == Data.HadronoxEnteredCombat)
return _enteredCombat ? 1 : 0u;
if (data == Data.HadronoxWebbedDoors)
return _doorsWebbed ? 1 : 0u;
return 0;
}
public override bool CanAIAttack(Unit target)
{
// Prevent Hadronox from going too far from her current home position
if (!target.IsControlledByPlayer() && target.GetDistance(me.GetHomePosition()) > 20.0f)
return false;
return base.CanAIAttack(target);
}
public override void EnterCombat(Unit who)
{
_scheduler.CancelAll();
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
_scheduler.Schedule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(7), task =>
{
DoCastAOE(SpellIds.LeechPoison);
task.Repeat(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(9));
});
_scheduler.Schedule(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(13), task =>
{
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 100.0f);
if (target)
DoCast(target, SpellIds.AcidCloud);
task.Repeat(TimeSpan.FromSeconds(16), TimeSpan.FromSeconds(23));
});
_scheduler.Schedule(TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(19), task =>
{
DoCastAOE(SpellIds.WebGrab);
task.Repeat(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(25));
});
_scheduler.Schedule(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(7), task =>
{
DoCastVictim(SpellIds.PierceArmor);
task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15));
});
_scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
{
if (IsInCombatWithPlayer() != _lastPlayerCombatState)
{
_lastPlayerCombatState = !_lastPlayerCombatState;
if (_lastPlayerCombatState) // we are now in combat with players
{
if (!instance.CheckRequiredBosses(ANDataTypes.Hadronox))
{
EnterEvadeMode(EvadeReason.SequenceBreak);
return;
}
// cancel current point movement if engaged by players
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Point)
{
me.GetMotionMaster().Clear();
SetCombatMovement(true);
AttackStart(me.GetVictim());
}
}
else // we are no longer in combat with players - reset the encounter
EnterEvadeMode(EvadeReason.NoHostiles);
}
task.Repeat(TimeSpan.FromSeconds(1));
});
me.setActive(true);
}
public override void DoAction(int action)
{
switch (action)
{
case ActionIds.CrusherEngaged:
if (_enteredCombat)
break;
instance.SetBossState(ANDataTypes.Hadronox, EncounterState.InProgress);
_enteredCombat = true;
SummonCrusherPack(SummonGroups.Crusher2);
SummonCrusherPack(SummonGroups.Crusher3);
break;
case ActionIds.HadronoxMove:
if (_step < Misc.hadronoxStep.Length - 1)
{
SetStep((byte)(_step + 1));
Talk(TextIds.EmoteHadronoxMove);
}
break;
}
}
public override void EnterEvadeMode(EvadeReason why)
{
List<Creature> triggers = new List<Creature>();
me.GetCreatureListWithEntryInGrid(triggers, CreatureIds.WorldtriggerLarge);
foreach (Creature trigger in triggers)
{
if (trigger.HasAura(SpellIds.SummonChampionPeriodic) || trigger.HasAura(SpellIds.WebFrontDoors) || trigger.HasAura(SpellIds.WebSideDoors))
_DespawnAtEvade(25, trigger);
}
_DespawnAtEvade(25);
summons.DespawnAll();
foreach (ObjectGuid gNerubian in _anubar)
{
Creature nerubian = ObjectAccessor.GetCreature(me, gNerubian);
if (nerubian)
nerubian.DespawnOrUnsummon();
}
}
public override void SetGUID(ObjectGuid guid, int what)
{
_anubar.Add(guid);
}
public void Initialize()
{
me.SetFloatValue(UnitFields.BoundingRadius, 9.0f);
me.SetFloatValue(UnitFields.CombatReach, 9.0f);
_enteredCombat = false;
_doorsWebbed = false;
_lastPlayerCombatState = false;
SetStep(0);
SetCombatMovement(true);
SummonCrusherPack(SummonGroups.Crusher1);
}
public override void InitializeAI()
{
base.InitializeAI();
if (me.IsAlive())
Initialize();
}
public override void JustRespawned()
{
base.JustRespawned();
Initialize();
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
DoMeleeAttackIfReady();
}
// Safeguard to prevent Hadronox dying to NPCs
public override void DamageTaken(Unit who, ref uint damage)
{
if (!who.IsControlledByPlayer() && me.HealthBelowPct(70))
{
if (me.HealthBelowPctDamaged(5, damage))
damage = 0;
else
damage *= (uint)((me.GetHealthPct() - 5.0f) / 65.0f);
}
}
public override void JustSummoned(Creature summon)
{
summons.Summon(summon);
// Do not enter combat with zone
}
bool _enteredCombat; // has a player entered combat with the first crusher pack? (talk and spawn two more packs)
bool _doorsWebbed; // obvious - have we reached the top and webbed the doors shut? (trigger for hadronox denied achievement)
bool _lastPlayerCombatState; // was there a player in our threat list the last time we checked (we check every second)
byte _step;
List<ObjectGuid> _anubar = new List<ObjectGuid>();
}
class npc_hadronox_crusherPackAI : ScriptedAI
{
public npc_hadronox_crusherPackAI(Creature creature, Position[] positions) : base(creature)
{
_instance = creature.GetInstanceScript();
_positions = positions;
_myPack = 0;
_doFacing = false;
}
public override void DoAction(int action)
{
if (action == ActionIds.PackWalk)
{
switch (_myPack)
{
case SummonGroups.Crusher1:
case SummonGroups.Crusher2:
case SummonGroups.Crusher3:
me.GetMotionMaster().MovePoint(ActionIds.PackWalk, _positions[_myPack - SummonGroups.Crusher1]);
break;
default:
break;
}
}
}
public override void MovementInform(MovementGeneratorType type, uint id)
{
if (type == MovementGeneratorType.Point && id == ActionIds.PackWalk)
_doFacing = true;
}
public override void EnterEvadeMode(EvadeReason why)
{
Creature hadronox = _instance.GetCreature(ANDataTypes.Hadronox);
if (hadronox)
hadronox.GetAI().EnterEvadeMode(EvadeReason.Other);
}
public override uint GetData(uint data)
{
if (data == Data.CrusherPackId)
return (uint)_myPack;
return 0;
}
public override void SetData(uint data, uint value)
{
if (data == Data.CrusherPackId)
{
_myPack = (SummonGroups)value;
me.SetReactState(_myPack != 0 ? ReactStates.Passive : ReactStates.Aggressive);
}
}
public override void EnterCombat(Unit who)
{
if (me.HasReactState(ReactStates.Passive))
{
List<Creature> others = new List<Creature>();
me.GetCreatureListWithEntryInGrid(others, 0, 40.0f);
foreach (Creature other in others)
{
if (other.GetAI().GetData(Data.CrusherPackId) == (uint)_myPack)
{
other.SetReactState(ReactStates.Aggressive);
other.GetAI().AttackStart(who);
}
}
}
_EnterCombat();
base.EnterCombat(who);
}
public virtual void _EnterCombat() { }
public override void MoveInLineOfSight(Unit who)
{
if (!me.HasReactState(ReactStates.Passive))
{
base.MoveInLineOfSight(who);
return;
}
if (me.CanStartAttack(who, false) && me.IsWithinDistInMap(who, me.GetAttackDistance(who) + me.m_CombatDistance))
EnterCombat(who);
}
public override void UpdateAI(uint diff)
{
if (_doFacing)
{
_doFacing = false;
me.SetFacingTo(_positions[_myPack - SummonGroups.Crusher1].GetOrientation());
}
if (!UpdateVictim())
return;
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
protected InstanceScript _instance;
Position[] _positions;
protected SummonGroups _myPack;
bool _doFacing;
}
[Script]
class npc_anub_ar_crusher : npc_hadronox_crusherPackAI
{
public npc_anub_ar_crusher(Creature creature) : base(creature, Misc.crusherWaypoints) { }
public override void _EnterCombat()
{
_scheduler.Schedule(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(12), task =>
{
DoCastVictim(SpellIds.Smash);
task.Repeat(TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(21));
});
if (_myPack != SummonGroups.Crusher1)
return;
Creature hadronox = _instance.GetCreature(ANDataTypes.Hadronox);
if (hadronox)
{
if (hadronox.GetAI().GetData(Data.HadronoxEnteredCombat) != 0)
return;
hadronox.GetAI().DoAction(ActionIds.CrusherEngaged);
}
Talk(TextIds.SayCrusherAggro);
}
public override void DamageTaken(Unit source, ref uint damage)
{
if (_hadFrenzy || !me.HealthBelowPctDamaged(25, damage))
return;
_hadFrenzy = true;
Talk(TextIds.EmoteCrusherFrenzy);
DoCastSelf(SpellIds.Frenzy);
}
public override void JustDied(Unit killer)
{
Creature hadronox = _instance.GetCreature(ANDataTypes.Hadronox);
if (hadronox)
hadronox.GetAI().DoAction(ActionIds.HadronoxMove);
base.JustDied(killer);
}
bool _hadFrenzy;
}
[Script]
class npc_anub_ar_crusher_champion : npc_hadronox_crusherPackAI
{
public npc_anub_ar_crusher_champion(Creature creature) : base(creature, Misc.championWaypoints) { }
public override void _EnterCombat()
{
_scheduler.Schedule(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(8), task =>
{
DoCastVictim(SpellIds.Rend);
task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(16));
});
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(19), task =>
{
DoCastVictim(SpellIds.Pummel);
task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(17));
});
}
}
[Script]
class npc_anub_ar_crusher_crypt_fiend : npc_hadronox_crusherPackAI
{
public npc_anub_ar_crusher_crypt_fiend(Creature creature) : base(creature, Misc.cryptFiendWaypoints) { }
public override void _EnterCombat()
{
_scheduler.Schedule(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(8), task =>
{
DoCastVictim(SpellIds.CrushingWebs);
task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(16));
});
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(19), task =>
{
DoCastVictim(SpellIds.InfectedWound);
task.Repeat(TimeSpan.FromSeconds(16), TimeSpan.FromSeconds(25));
});
}
}
[Script]
class npc_anub_ar_crusher_necromancer : npc_hadronox_crusherPackAI
{
public npc_anub_ar_crusher_necromancer(Creature creature) : base(creature, Misc.necromancerWaypoints) { }
public override void _EnterCombat()
{
_scheduler.Schedule(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(4), task =>
{
DoCastVictim(SpellIds.ShadowBolt);
task.Repeat(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5));
});
_scheduler.Schedule(TimeSpan.FromSeconds(37), TimeSpan.FromSeconds(45), task =>
{
DoCastVictim(RandomHelper.URand(0, 1) != 0 ? SpellIds.AnimateBones2 : SpellIds.AnimateBones1);
task.Repeat(TimeSpan.FromSeconds(35), TimeSpan.FromSeconds(50));
});
}
}
class npc_hadronox_foeAI : ScriptedAI
{
public npc_hadronox_foeAI(Creature creature) : base(creature)
{
_instance = creature.GetInstanceScript();
_nextMovement = MovementIds.Outside;
_mySpawn = 0;
}
public override void InitializeAI()
{
base.InitializeAI();
Creature hadronox = _instance.GetCreature(ANDataTypes.Hadronox);
if (hadronox)
hadronox.GetAI().SetGUID(me.GetGUID());
}
public override void MovementInform(MovementGeneratorType type, uint id)
{
if (type == MovementGeneratorType.Point)
_nextMovement = (MovementIds)(id + 1);
}
public override void EnterEvadeMode(EvadeReason why)
{
me.DespawnOrUnsummon();
}
public override void UpdateAI(uint diff)
{
if (_nextMovement != 0)
{
switch (_nextMovement)
{
case MovementIds.Outside:
{
float dist = float.PositiveInfinity;
for (byte spawn = 0; spawn < Misc.initialMoves.Length; ++spawn)
{
float thisDist = Misc.initialMoves[spawn].GetExactDistSq(me);
if (thisDist < dist)
{
_mySpawn = spawn;
dist = thisDist;
}
}
me.GetMotionMaster().MovePoint((uint)MovementIds.Outside, Misc.initialMoves[_mySpawn], false); // do not pathfind here, we have to pass through a "wall" of webbing
break;
}
case MovementIds.Downstairs:
me.GetMotionMaster().MovePoint((uint)MovementIds.Downstairs, Misc.downstairsMoves[_mySpawn]);
break;
case MovementIds.Downstairs2:
if (Misc.downstairsMoves2[_mySpawn].GetPositionX() > 0.0f) // might be unset for this spawn - if yes, skip
{
me.GetMotionMaster().MovePoint((uint)MovementIds.Downstairs2, Misc.downstairsMoves2[_mySpawn]);
break;
}
goto case MovementIds.Hadronox;
// intentional missing break
case MovementIds.Hadronox:
case MovementIds.HadronoxReal:
{
float zCutoff = 702.0f;
Creature hadronox = _instance.GetCreature(ANDataTypes.Hadronox);
if (hadronox && hadronox.IsAlive())
{
if (_nextMovement != MovementIds.HadronoxReal)
{
if (hadronox.GetPositionZ() < zCutoff)
{
me.GetMotionMaster().MovePoint((uint)MovementIds.Hadronox, Misc.hadronoxStep[2]);
break;
}
}
AttackStart(hadronox);
}
break;
}
default:
break;
}
_nextMovement = MovementIds.None;
}
if (!UpdateVictim())
return;
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
InstanceScript _instance;
MovementIds _nextMovement;
byte _mySpawn;
}
[Script]
class npc_anub_ar_champion : npc_hadronox_foeAI
{
public npc_anub_ar_champion(Creature creature) : base(creature) { }
public override void EnterCombat(Unit who)
{
_scheduler.Schedule(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(8), task =>
{
DoCastVictim(SpellIds.Rend);
task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(16));
});
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(19), task =>
{
DoCastVictim(SpellIds.Pummel);
task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(17));
});
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(50), task =>
{
DoCastVictim(SpellIds.Taunt);
task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(50));
});
}
}
[Script]
class npc_anub_ar_crypt_fiend : npc_hadronox_foeAI
{
public npc_anub_ar_crypt_fiend(Creature creature) : base(creature) { }
public override void EnterCombat(Unit who)
{
_scheduler.Schedule(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(8), task =>
{
DoCastVictim(SpellIds.CrushingWebs);
task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(16));
});
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(19), task =>
{
DoCastVictim(SpellIds.InfectedWound);
task.Repeat(TimeSpan.FromSeconds(16), TimeSpan.FromSeconds(25));
});
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(50), task =>
{
DoCastVictim(SpellIds.Taunt);
task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(50));
});
}
}
[Script]
class npc_anub_ar_necromancer : npc_hadronox_foeAI
{
public npc_anub_ar_necromancer(Creature creature) : base(creature) { }
public override void EnterCombat(Unit who)
{
_scheduler.Schedule(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(4), task =>
{
DoCastVictim(SpellIds.ShadowBolt);
task.Repeat(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5));
});
_scheduler.Schedule(TimeSpan.FromSeconds(37), TimeSpan.FromSeconds(45), task =>
{
DoCastVictim(RandomHelper.URand(0, 1) != 0 ? SpellIds.AnimateBones2 : SpellIds.AnimateBones1);
task.Repeat(TimeSpan.FromSeconds(35), TimeSpan.FromSeconds(50));
});
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(50), task =>
{
DoCastVictim(SpellIds.Taunt);
task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(50));
});
}
}
[Script("spell_hadronox_periodic_summon_champion", SpellIds.SummonChampionTop, SpellIds.SummonChampionBottom)]
[Script("spell_hadronox_periodic_summon_crypt_fiend", SpellIds.SummonCryptFiendTop, SpellIds.SummonCryptFiendBottom)]
[Script("spell_hadronox_periodic_summon_necromancer", SpellIds.SummonNecromancerTop, SpellIds.SummonNecromancerBottom)]
class spell_hadronox_periodic_summon_template : AuraScript
{
public spell_hadronox_periodic_summon_template(uint topSpellId, uint bottomSpellId) : base()
{
_topSpellId = topSpellId;
_bottomSpellId = bottomSpellId;
}
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(_topSpellId, _bottomSpellId);
}
void HandleApply(AuraEffect eff, AuraEffectHandleModes mode)
{
AuraEffect effect = GetAura().GetEffect(0);
if (effect != null)
effect.SetPeriodicTimer(RandomHelper.IRand(2, 17) * Time.InMilliseconds);
}
void HandlePeriodic(AuraEffect eff)
{
Unit caster = GetCaster();
if (!caster)
return;
InstanceScript instance = caster.GetInstanceScript();
if (instance == null)
return;
if (instance.GetBossState(ANDataTypes.Hadronox) == EncounterState.Done)
GetAura().Remove();
else
{
if (caster.GetPositionZ() >= 750.0f)
caster.CastSpell(caster, _topSpellId, true);
else
caster.CastSpell(caster, _bottomSpellId, true);
}
}
public override void Register()
{
AfterEffectApply.Add(new EffectApplyHandler(HandleApply, 0, AuraType.PeriodicDummy, AuraEffectHandleModes.Real));
OnEffectPeriodic.Add(new EffectPeriodicHandler(HandlePeriodic, 0, AuraType.PeriodicDummy));
}
uint _topSpellId;
uint _bottomSpellId;
}
[Script]
class spell_hadronox_leeching_poison : AuraScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.LeechPoisonHeal);
}
void HandleEffectRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
{
if (GetTargetApplication().GetRemoveMode() != AuraRemoveMode.ByDeath)
return;
if (GetTarget().IsGuardian())
return;
Unit caster = GetCaster();
if (caster)
caster.CastSpell(caster, SpellIds.LeechPoisonHeal, true);
}
public override void Register()
{
OnEffectRemove.Add(new EffectApplyHandler(HandleEffectRemove, 0, AuraType.PeriodicLeech, AuraEffectHandleModes.Real));
}
}
[Script]
class spell_hadronox_web_doors : SpellScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.SummonChampionPeriodic, SpellIds.SummonCryptFiendPeriodic, SpellIds.SummonNecromancerPeriodic);
}
void HandleDummy(uint effIndex)
{
Unit target = GetHitUnit();
if (target)
{
target.RemoveAurasDueToSpell(SpellIds.SummonChampionPeriodic);
target.RemoveAurasDueToSpell(SpellIds.SummonCryptFiendPeriodic);
target.RemoveAurasDueToSpell(SpellIds.SummonNecromancerPeriodic);
}
}
public override void Register()
{
OnEffectHitTarget.Add(new EffectHandler(HandleDummy, 0, SpellEffectName.ApplyAura));
}
}
[Script]
class achievement_hadronox_denied : AchievementCriteriaScript
{
public achievement_hadronox_denied() : base("achievement_hadronox_denied") { }
public override bool OnCheck(Player player, Unit target)
{
if (!target)
return false;
Creature cTarget = target.ToCreature();
if (cTarget)
if (cTarget.GetAI().GetData(Data.HadronoxWebbedDoors) == 0)
return true;
return false;
}
}
}
@@ -0,0 +1,144 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Maps;
using Game.Scripting;
namespace Scripts.Northrend.AzjolNerub.AzjolNerub
{
struct ANDataTypes
{
// Encounter States/Boss Guids
public const uint KrikthirTheGatewatcher = 0;
public const uint Hadronox = 1;
public const uint Anubarak = 2;
// Additional Data
public const uint WatcherNarjil = 3;
public const uint WatcherGashra = 4;
public const uint WatcherSilthik = 5;
public const uint AnubarakWall = 6;
public const uint AnubarakWall2 = 7;
}
struct ANCreatureIds
{
public const uint Krikthir = 28684;
public const uint Hadronox = 28921;
public const uint Anubarak = 29120;
public const uint WatcherNarjil = 28729;
public const uint WatcherGashra = 28730;
public const uint WatcherSilthik = 28731;
}
struct ANGameObjectIds
{
public const uint KrikthirDoor = 192395;
public const uint AnubarakDoor1 = 192396;
public const uint AnubarakDoor2 = 192397;
public const uint AnubarakDoor3 = 192398;
}
// These are passed as -action to AI's DoAction to differentiate between them and boss scripts' own actions
struct ANInstanceMisc
{
public const string DataHeader = "AN";
public const uint EncounterCount = 3;
public const int ActionGatewatcherGreet = 1;
public static DoorData[] doorData =
{
new DoorData(ANGameObjectIds.KrikthirDoor, ANDataTypes.KrikthirTheGatewatcher, DoorType.Passage),
new DoorData(ANGameObjectIds.AnubarakDoor1, ANDataTypes.Anubarak, DoorType.Room ),
new DoorData(ANGameObjectIds.AnubarakDoor2, ANDataTypes.Anubarak, DoorType.Room ),
new DoorData(ANGameObjectIds.AnubarakDoor3, ANDataTypes.Anubarak, DoorType.Room )
};
public static ObjectData[] creatureData =
{
new ObjectData(ANCreatureIds.Krikthir, ANDataTypes.KrikthirTheGatewatcher ),
new ObjectData(ANCreatureIds.Hadronox, ANDataTypes.Hadronox ),
new ObjectData(ANCreatureIds.Anubarak, ANDataTypes.Anubarak ),
new ObjectData(ANCreatureIds.WatcherNarjil, ANDataTypes.WatcherGashra ),
new ObjectData(ANCreatureIds.WatcherGashra, ANDataTypes.WatcherSilthik ),
new ObjectData(ANCreatureIds.WatcherSilthik, ANDataTypes.WatcherNarjil )
};
public static ObjectData[] gameobjectData =
{
new ObjectData(ANGameObjectIds.AnubarakDoor1, ANDataTypes.AnubarakWall),
new ObjectData(ANGameObjectIds.AnubarakDoor3, ANDataTypes.AnubarakWall2)
};
public static BossBoundaryEntry[] boundaries =
{
new BossBoundaryEntry(ANDataTypes.KrikthirTheGatewatcher, new RectangleBoundary(400.0f, 580.0f, 623.5f, 810.0f)),
new BossBoundaryEntry(ANDataTypes.Hadronox, new ZRangeBoundary(666.0f, 776.0f)),
new BossBoundaryEntry(ANDataTypes.Anubarak, new CircleBoundary(new Position(550.6178f, 253.5917f), 26.0f))
};
}
[Script]
class instance_azjol_nerub : InstanceMapScript
{
public instance_azjol_nerub() : base(nameof(instance_azjol_nerub), 601) { }
class instance_azjol_nerub_InstanceScript : InstanceScript
{
public instance_azjol_nerub_InstanceScript(Map map) : base(map)
{
SetHeaders(ANInstanceMisc.DataHeader);
SetBossNumber(ANInstanceMisc.EncounterCount);
LoadBossBoundaries(ANInstanceMisc.boundaries);
LoadDoorData(ANInstanceMisc.doorData);
LoadObjectData(ANInstanceMisc.creatureData, ANInstanceMisc.gameobjectData);
}
public override void OnUnitDeath(Unit who)
{
base.OnUnitDeath(who);
Creature creature = who.ToCreature();
if (!creature || creature.IsCritter() || creature.IsControlledByPlayer())
return;
Creature gatewatcher = GetCreature(ANDataTypes.KrikthirTheGatewatcher);
if (gatewatcher)
gatewatcher.GetAI().DoAction(-ANInstanceMisc.ActionGatewatcherGreet);
}
public override bool CheckRequiredBosses(uint bossId, Player player)
{
if (_SkipCheckRequiredBosses(player))
return true;
if (bossId > ANDataTypes.KrikthirTheGatewatcher && GetBossState(ANDataTypes.KrikthirTheGatewatcher) != EncounterState.Done)
return false;
return true;
}
}
public override InstanceScript GetInstanceScript(InstanceMap map)
{
return new instance_azjol_nerub_InstanceScript(map);
}
}
}