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:
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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.Scripting;
|
||||
using System;
|
||||
|
||||
namespace Scripts.Northrend.AzjolNerub.Ahnkahet.Amanitar
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint Bash = 57094; // Victim
|
||||
public const uint EntanglingRoots = 57095; // Random Victim 100y
|
||||
public const uint Mini = 57055; // Self
|
||||
public const uint VenomBoltVolley = 57088; // Random Victim 100y
|
||||
public const uint HealthyMushroomPotentFungus = 56648; // Killer 3y
|
||||
public const uint PoisonousMushroomPoisonCloud = 57061; // Self - Duration 8 Sec
|
||||
public const uint PoisonousMushroomVisualArea = 61566; // Self
|
||||
public const uint PoisonousMushroomVisualAura = 56741; // Self
|
||||
public const uint PutridMushroom = 31690; // To Make The Mushrooms Visible
|
||||
public const uint PowerMushroomVisualAura = 56740;
|
||||
}
|
||||
|
||||
struct CreatureIds
|
||||
{
|
||||
public const uint Trigger = 19656;
|
||||
public const uint HealthyMushroom = 30391;
|
||||
public const uint PoisonousMushroom = 30435;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_amanitar : BossAI
|
||||
{
|
||||
public boss_amanitar(Creature creature) : base(creature, DataTypes.Amanitar) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_Reset();
|
||||
me.SetMeleeDamageSchool(SpellSchools.Nature);
|
||||
me.ApplySpellImmune(0, SpellImmunity.School, SpellSchoolMask.Nature, true);
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit who)
|
||||
{
|
||||
_EnterCombat();
|
||||
|
||||
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(5), task =>
|
||||
{
|
||||
SpawnAdds();
|
||||
task.Repeat(TimeSpan.FromSeconds(20));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(9), task =>
|
||||
{
|
||||
DoCast(SelectTarget(SelectAggroTarget.Random, 0, 100, true), SpellIds.EntanglingRoots, true);
|
||||
task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(14), task =>
|
||||
{
|
||||
DoCastVictim(SpellIds.Bash);
|
||||
task.Repeat(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(12));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(18), task =>
|
||||
{
|
||||
DoCast(SpellIds.Mini);
|
||||
task.Repeat(TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(30));
|
||||
});
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), task =>
|
||||
{
|
||||
DoCast(SelectTarget(SelectAggroTarget.Random, 0, 100, true), SpellIds.VenomBoltVolley, true);
|
||||
task.Repeat(TimeSpan.FromSeconds(18), TimeSpan.FromSeconds(22));
|
||||
});
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
_JustDied();
|
||||
instance.DoRemoveAurasDueToSpellOnPlayers(SpellIds.Mini);
|
||||
}
|
||||
|
||||
void SpawnAdds()
|
||||
{
|
||||
int u = 0;
|
||||
|
||||
for (byte i = 0; i < 30; ++i)
|
||||
{
|
||||
Position pos = me.GetRandomNearPosition(30.0f);
|
||||
pos.posZ = me.GetMap().GetHeight(pos.GetPositionX(), pos.GetPositionY(), MapConst.MaxHeight) + 2.0f;
|
||||
|
||||
Creature trigger = me.SummonCreature(CreatureIds.Trigger, pos);
|
||||
if (trigger)
|
||||
{
|
||||
Creature temp1 = trigger.FindNearestCreature(CreatureIds.HealthyMushroom, 4.0f, true);
|
||||
Creature temp2 = trigger.FindNearestCreature(CreatureIds.PoisonousMushroom, 4.0f, true);
|
||||
if (temp1 || temp2)
|
||||
{
|
||||
trigger.DisappearAndDie();
|
||||
}
|
||||
else
|
||||
{
|
||||
u = 1 - u;
|
||||
trigger.DisappearAndDie();
|
||||
me.SummonCreature(u > 0 ? CreatureIds.PoisonousMushroom : CreatureIds.HealthyMushroom, pos, TempSummonType.TimedOrCorpseDespawn, 60 * Time.InMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_amanitar_mushrooms : ScriptedAI
|
||||
{
|
||||
public npc_amanitar_mushrooms(Creature creature) : base(creature) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
_scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting));
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
|
||||
{
|
||||
if (me.GetEntry() == CreatureIds.PoisonousMushroom)
|
||||
{
|
||||
DoCast(me, SpellIds.PoisonousMushroomVisualArea, true);
|
||||
DoCast(me, SpellIds.PoisonousMushroomPoisonCloud);
|
||||
}
|
||||
task.Repeat(TimeSpan.FromSeconds(7));
|
||||
});
|
||||
|
||||
me.SetDisplayId(me.GetCreatureTemplate().ModelId2);
|
||||
DoCast(SpellIds.PutridMushroom);
|
||||
|
||||
if (me.GetEntry() == CreatureIds.PoisonousMushroom)
|
||||
DoCast(SpellIds.PoisonousMushroomVisualAura);
|
||||
else
|
||||
DoCast(SpellIds.PowerMushroomVisualAura);
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit attacker, ref uint damage)
|
||||
{
|
||||
if (damage >= me.GetHealth() && me.GetEntry() == CreatureIds.HealthyMushroom)
|
||||
DoCast(me, SpellIds.HealthyMushroomPotentFungus, true);
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit who) { }
|
||||
public override void AttackStart(Unit victim) { }
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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.Scripting;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Scripts.Northrend.AzjolNerub.Ahnkahet.ElderNadox
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint BroodPlague = 56130;
|
||||
public const uint HBroodRage = 59465;
|
||||
public const uint Enrage = 26662; // Enraged If Too Far Away From Home
|
||||
public const uint SummonSwarmers = 56119; // 2x 30178 -- 2x Every 10secs
|
||||
public const uint SummonSwarmGuard = 56120; // 1x 30176
|
||||
|
||||
// Adds
|
||||
public const uint SwarmBuff = 56281;
|
||||
public const uint Sprint = 56354;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayAggro = 0;
|
||||
public const uint SaySlay = 1;
|
||||
public const uint SayDeath = 2;
|
||||
public const uint SayEggSac = 3;
|
||||
public const uint EmoteHatches = 4;
|
||||
}
|
||||
|
||||
struct Misc
|
||||
{
|
||||
public const uint DataRespectYourElders = 6;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_elder_nadox : BossAI
|
||||
{
|
||||
public boss_elder_nadox(Creature creature) : base(creature, DataTypes.ElderNadox)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
GuardianSummoned = false;
|
||||
GuardianDied = false;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit who)
|
||||
{
|
||||
_EnterCombat();
|
||||
Talk(TextIds.SayAggro);
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(13), task =>
|
||||
{
|
||||
DoCast(SelectTarget(SelectAggroTarget.Random, 0, 100, true), SpellIds.BroodPlague, true);
|
||||
task.Repeat(TimeSpan.FromSeconds(15));
|
||||
});
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
|
||||
{
|
||||
/// @todo: summoned by egg
|
||||
DoCast(me, SpellIds.SummonSwarmers);
|
||||
if (RandomHelper.URand(1, 3) == 3) // 33% chance of dialog
|
||||
Talk(TextIds.SayEggSac);
|
||||
task.Repeat();
|
||||
});
|
||||
|
||||
if (IsHeroic())
|
||||
{
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(12), task =>
|
||||
{
|
||||
DoCast(SpellIds.HBroodRage);
|
||||
task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(50));
|
||||
});
|
||||
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(5), task =>
|
||||
{
|
||||
if (me.HasAura(SpellIds.Enrage))
|
||||
return;
|
||||
if (me.GetPositionZ() < 24.0f)
|
||||
DoCast(me, SpellIds.Enrage, true);
|
||||
task.Repeat();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void SummonedCreatureDies(Creature summon, Unit killer)
|
||||
{
|
||||
if (summon.GetEntry() == AKCreatureIds.AhnkaharGuardian)
|
||||
GuardianDied = true;
|
||||
}
|
||||
|
||||
public override uint GetData(uint type)
|
||||
{
|
||||
if (type == Misc.DataRespectYourElders)
|
||||
return !GuardianDied ? 1 : 0u;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit who)
|
||||
{
|
||||
if (who.IsTypeId(TypeId.Player))
|
||||
Talk(TextIds.SaySlay);
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
_JustDied();
|
||||
Talk(TextIds.SayDeath);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
|
||||
if (!GuardianSummoned && me.HealthBelowPct(50))
|
||||
{
|
||||
/// @todo: summoned by egg
|
||||
Talk(TextIds.EmoteHatches, me);
|
||||
DoCast(me, SpellIds.SummonSwarmGuard);
|
||||
GuardianSummoned = true;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
bool GuardianSummoned;
|
||||
bool GuardianDied;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_ahnkahar_nerubian : ScriptedAI
|
||||
{
|
||||
public npc_ahnkahar_nerubian(Creature creature) : base(creature) { }
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
_scheduler.Schedule(TimeSpan.FromSeconds(13), task =>
|
||||
{
|
||||
DoCast(me, SpellIds.Sprint);
|
||||
task.Repeat(TimeSpan.FromSeconds(20));
|
||||
});
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
// 56159 - Swarm
|
||||
[Script]
|
||||
class spell_ahn_kahet_swarm : SpellScript
|
||||
{
|
||||
public spell_ahn_kahet_swarm()
|
||||
{
|
||||
_targetCount = 0;
|
||||
}
|
||||
|
||||
public override bool Validate(SpellInfo spellInfo)
|
||||
{
|
||||
return ValidateSpellInfo(SpellIds.SwarmBuff);
|
||||
}
|
||||
|
||||
void CountTargets(List<WorldObject> targets)
|
||||
{
|
||||
_targetCount = targets.Count;
|
||||
}
|
||||
|
||||
void HandleDummy(uint effIndex)
|
||||
{
|
||||
if (_targetCount != 0)
|
||||
{
|
||||
Aura aura = GetCaster().GetAura(SpellIds.SwarmBuff);
|
||||
if (aura != null)
|
||||
{
|
||||
aura.SetStackAmount((byte)_targetCount);
|
||||
aura.RefreshDuration();
|
||||
}
|
||||
else
|
||||
GetCaster().CastCustomSpell(SpellIds.SwarmBuff, SpellValueMod.AuraStack, _targetCount, GetCaster(), TriggerCastFlags.FullMask);
|
||||
}
|
||||
else
|
||||
GetCaster().RemoveAurasDueToSpell(SpellIds.SwarmBuff);
|
||||
}
|
||||
|
||||
public override void Register()
|
||||
{
|
||||
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(CountTargets, 0, Targets.UnitSrcAreaAlly));
|
||||
OnEffectHit.Add(new EffectHandler(HandleDummy, 0, SpellEffectName.Dummy));
|
||||
}
|
||||
|
||||
int _targetCount;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class achievement_respect_your_elders : AchievementCriteriaScript
|
||||
{
|
||||
public achievement_respect_your_elders() : base("achievement_respect_your_elders") { }
|
||||
|
||||
public override bool OnCheck(Player player, Unit target)
|
||||
{
|
||||
return target && target.GetAI().GetData(Misc.DataRespectYourElders) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Scripts.Northrend.AzjolNerub.Ahnkahet.HeraldVolazj
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint Insanity = 57496; //Dummy
|
||||
public const uint InsanityVisual = 57561;
|
||||
public const uint InsanityTarget = 57508;
|
||||
public const uint MindFlay = 57941;
|
||||
public const uint ShadowBoltVolley = 57942;
|
||||
public const uint Shiver = 57949;
|
||||
public const uint ClonePlayer = 57507; //Cast On Player During Insanity
|
||||
public const uint InsanityPhasing1 = 57508;
|
||||
public const uint InsanityPhasing2 = 57509;
|
||||
public const uint InsanityPhasing3 = 57510;
|
||||
public const uint InsanityPhasing4 = 57511;
|
||||
public const uint InsanityPhasing5 = 57512;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayAggro = 0;
|
||||
public const uint SaySlay = 1;
|
||||
public const uint SayDeath = 2;
|
||||
public const uint SayPhase = 3;
|
||||
}
|
||||
|
||||
struct Misc
|
||||
{
|
||||
public const uint AchievQuickDemiseStartEvent = 20382;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class boss_volazj : ScriptedAI
|
||||
{
|
||||
public boss_volazj(Creature creature) : base(creature)
|
||||
{
|
||||
Summons = new SummonList(me);
|
||||
|
||||
Initialize();
|
||||
instance = creature.GetInstanceScript();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
uiMindFlayTimer = 8 * Time.InMilliseconds;
|
||||
uiShadowBoltVolleyTimer = 5 * Time.InMilliseconds;
|
||||
uiShiverTimer = 15 * Time.InMilliseconds;
|
||||
// Used for Insanity handling
|
||||
insanityHandled = 0;
|
||||
}
|
||||
|
||||
// returns the percentage of health after taking the given damage.
|
||||
uint GetHealthPct(uint damage)
|
||||
{
|
||||
if (damage > me.GetHealth())
|
||||
return 0;
|
||||
return (uint)(100 * (me.GetHealth() - damage) / me.GetMaxHealth());
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit pAttacker, ref uint damage)
|
||||
{
|
||||
if (me.HasFlag(UnitFields.Flags, UnitFlags.NotSelectable))
|
||||
damage = 0;
|
||||
|
||||
if ((GetHealthPct(0) >= 66 && GetHealthPct(damage) < 66) ||
|
||||
(GetHealthPct(0) >= 33 && GetHealthPct(damage) < 33))
|
||||
{
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
DoCast(me, SpellIds.Insanity, false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SpellHitTarget(Unit target, SpellInfo spell)
|
||||
{
|
||||
if (spell.Id == SpellIds.Insanity)
|
||||
{
|
||||
// Not good target or too many players
|
||||
if (target.GetTypeId() != TypeId.Player || insanityHandled > 4)
|
||||
return;
|
||||
// First target - start channel visual and set self as unnattackable
|
||||
if (insanityHandled == 0)
|
||||
{
|
||||
// Channel visual
|
||||
DoCast(me, SpellIds.InsanityVisual, true);
|
||||
// Unattackable
|
||||
me.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
||||
me.SetControlled(true, UnitState.Stunned);
|
||||
}
|
||||
|
||||
// phase the player
|
||||
target.CastSpell(target, SpellIds.InsanityTarget + insanityHandled, true);
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.InsanityTarget + insanityHandled);
|
||||
if (spellInfo == null)
|
||||
return;
|
||||
|
||||
// summon twisted party members for this target
|
||||
var players = me.GetMap().GetPlayers();
|
||||
foreach (var player in players)
|
||||
{
|
||||
if (!player || !player.IsAlive())
|
||||
continue;
|
||||
// Summon clone
|
||||
Unit summon = me.SummonCreature(AKCreatureIds.TwistedVisage, me.GetPositionX(), me.GetPositionY(), me.GetPositionZ(), me.GetOrientation(), TempSummonType.CorpseDespawn, 0);
|
||||
if (summon)
|
||||
{
|
||||
// clone
|
||||
player.CastSpell(summon, SpellIds.ClonePlayer, true);
|
||||
// phase the summon
|
||||
summon.SetInPhase((uint)spellInfo.GetEffect(0).MiscValueB, true, true);
|
||||
}
|
||||
}
|
||||
++insanityHandled;
|
||||
}
|
||||
}
|
||||
|
||||
void ResetPlayersPhase()
|
||||
{
|
||||
var players = me.GetMap().GetPlayers();
|
||||
foreach (var player in players)
|
||||
{
|
||||
for (uint index = 0; index <= 4; ++index)
|
||||
player.RemoveAurasDueToSpell(SpellIds.InsanityTarget + index);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
instance.SetBossState(DataTypes.HeraldVolazj, EncounterState.NotStarted);
|
||||
instance.DoStopCriteriaTimer(CriteriaTimedTypes.Event, Misc.AchievQuickDemiseStartEvent);
|
||||
|
||||
// Visible for all players in insanity
|
||||
me.SetInPhase(169, true, true);
|
||||
for (uint i = 173; i <= 177; ++i)
|
||||
me.SetInPhase(i, true, true);
|
||||
|
||||
ResetPlayersPhase();
|
||||
|
||||
// Cleanup
|
||||
Summons.DespawnAll();
|
||||
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
||||
me.SetControlled(false, UnitState.Stunned);
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit who)
|
||||
{
|
||||
Talk(TextIds.SayAggro);
|
||||
|
||||
instance.SetBossState(DataTypes.HeraldVolazj, EncounterState.InProgress);
|
||||
instance.DoStartCriteriaTimer(CriteriaTimedTypes.Event, Misc.AchievQuickDemiseStartEvent);
|
||||
}
|
||||
|
||||
public override void JustSummoned(Creature summon)
|
||||
{
|
||||
Summons.Summon(summon);
|
||||
}
|
||||
|
||||
public override void SummonedCreatureDespawn(Creature summon)
|
||||
{
|
||||
uint nextPhase = 0;
|
||||
Summons.Despawn(summon);
|
||||
|
||||
// Check if all summons in this phase killed
|
||||
foreach (var guid in Summons)
|
||||
{
|
||||
Creature visage = ObjectAccessor.GetCreature(me, guid);
|
||||
if (visage)
|
||||
{
|
||||
// Not all are dead
|
||||
if (visage.IsInPhase(summon))
|
||||
return;
|
||||
else
|
||||
{
|
||||
nextPhase = visage.GetPhases().First();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Roll Insanity
|
||||
var players = me.GetMap().GetPlayers();
|
||||
foreach (var player in players)
|
||||
{
|
||||
if (player)
|
||||
{
|
||||
for (uint index = 0; index <= 4; ++index)
|
||||
player.RemoveAurasDueToSpell(SpellIds.InsanityTarget + index);
|
||||
player.CastSpell(player, SpellIds.InsanityTarget + nextPhase - 173, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (insanityHandled != 0)
|
||||
{
|
||||
if (!Summons.Empty())
|
||||
return;
|
||||
|
||||
insanityHandled = 0;
|
||||
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
||||
me.SetControlled(false, UnitState.Stunned);
|
||||
me.RemoveAurasDueToSpell(SpellIds.InsanityVisual);
|
||||
}
|
||||
|
||||
if (uiMindFlayTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.MindFlay);
|
||||
uiMindFlayTimer = 20 * Time.InMilliseconds;
|
||||
}
|
||||
else uiMindFlayTimer -= diff;
|
||||
|
||||
if (uiShadowBoltVolleyTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SpellIds.ShadowBoltVolley);
|
||||
uiShadowBoltVolleyTimer = 5 * Time.InMilliseconds;
|
||||
}
|
||||
else uiShadowBoltVolleyTimer -= diff;
|
||||
|
||||
if (uiShiverTimer <= diff)
|
||||
{
|
||||
Unit target = SelectTarget(SelectAggroTarget.Random, 0);
|
||||
if (target)
|
||||
DoCast(target, SpellIds.Shiver);
|
||||
uiShiverTimer = 15 * Time.InMilliseconds;
|
||||
}
|
||||
else uiShiverTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
|
||||
instance.SetBossState(DataTypes.HeraldVolazj, EncounterState.Done);
|
||||
|
||||
Summons.DespawnAll();
|
||||
ResetPlayersPhase();
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit who)
|
||||
{
|
||||
if (who.IsTypeId(TypeId.Player))
|
||||
Talk(TextIds.SaySlay);
|
||||
}
|
||||
|
||||
InstanceScript instance;
|
||||
|
||||
uint uiMindFlayTimer;
|
||||
uint uiShadowBoltVolleyTimer;
|
||||
uint uiShiverTimer;
|
||||
uint insanityHandled;
|
||||
SummonList Summons;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace Scripts.Northrend.AzjolNerub.Ahnkahet.JedogaShadowseeker
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint SphereVisual = 56075;
|
||||
public const uint GiftOfTheHerald = 56219;
|
||||
public const uint CycloneStrike = 56855; // Self
|
||||
public const uint LightningBolt = 56891; // 40y
|
||||
public const uint Thundershock = 56926; // 30y
|
||||
|
||||
public const uint BeamVisualJedogasAufseher1 = 60342;
|
||||
public const uint BeamVisualJedogasAufseher2 = 56312;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint SayAggro = 0;
|
||||
public const uint SaySacrifice1 = 1;
|
||||
public const uint SaySacrifice2 = 2;
|
||||
public const uint SaySlay = 3;
|
||||
public const uint SayDeath = 4;
|
||||
public const uint SayPreaching = 5;
|
||||
}
|
||||
struct Misc
|
||||
{
|
||||
public const int ActionInitiateKilled = 1;
|
||||
public const uint DataVolunteerWork = 2;
|
||||
|
||||
public static Position[] JedogaPosition =
|
||||
{
|
||||
new Position(372.330994f, -705.278015f, -0.624178f, 5.427970f),
|
||||
new Position(372.330994f, -705.278015f, -16.179716f, 5.427970f)
|
||||
};
|
||||
}
|
||||
|
||||
[Script]
|
||||
public class boss_jedoga_shadowseeker : ScriptedAI
|
||||
{
|
||||
public boss_jedoga_shadowseeker(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
instance = creature.GetInstanceScript();
|
||||
bFirstTime = true;
|
||||
bPreDone = false;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
uiOpFerTimer = RandomHelper.URand(15 * Time.InMilliseconds, 20 * Time.InMilliseconds);
|
||||
|
||||
uiCycloneTimer = 3 * Time.InMilliseconds;
|
||||
uiBoltTimer = 7 * Time.InMilliseconds;
|
||||
uiThunderTimer = 12 * Time.InMilliseconds;
|
||||
|
||||
bOpFerok = false;
|
||||
bOpFerokFail = false;
|
||||
bOnGround = false;
|
||||
bCanDown = false;
|
||||
volunteerWork = true;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
if (!bFirstTime)
|
||||
instance.SetBossState(DataTypes.JedogaShadowseeker, EncounterState.Fail);
|
||||
|
||||
instance.SetGuidData(DataTypes.PlJedogaTarget, ObjectGuid.Empty);
|
||||
instance.SetGuidData(DataTypes.AddJedogaVictim, ObjectGuid.Empty);
|
||||
instance.SetData(DataTypes.JedogaResetInitiands, 0);
|
||||
MoveUp();
|
||||
|
||||
bFirstTime = false;
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit who)
|
||||
{
|
||||
if (instance == null || (who.GetTypeId() == TypeId.Unit && who.GetEntry() == AKCreatureIds.JedogaController))
|
||||
return;
|
||||
|
||||
Talk(TextIds.SayAggro);
|
||||
me.SetInCombatWithZone();
|
||||
instance.SetBossState(DataTypes.JedogaShadowseeker, EncounterState.InProgress);
|
||||
}
|
||||
|
||||
public override void AttackStart(Unit who)
|
||||
{
|
||||
if (!who || (who.GetTypeId() == TypeId.Unit && who.GetEntry() == AKCreatureIds.JedogaController))
|
||||
return;
|
||||
|
||||
base.AttackStart(who);
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit Victim)
|
||||
{
|
||||
if (!Victim || !Victim.IsTypeId(TypeId.Player))
|
||||
return;
|
||||
|
||||
Talk(TextIds.SaySlay);
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
instance.SetBossState(DataTypes.JedogaShadowseeker, EncounterState.Done);
|
||||
}
|
||||
|
||||
public override void DoAction(int action)
|
||||
{
|
||||
if (action == Misc.ActionInitiateKilled)
|
||||
volunteerWork = false;
|
||||
}
|
||||
|
||||
public override uint GetData(uint type)
|
||||
{
|
||||
if (type == Misc.DataVolunteerWork)
|
||||
return volunteerWork ? 1 : 0u;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void MoveInLineOfSight(Unit who)
|
||||
{
|
||||
if (instance == null || !who || (who.IsTypeId(TypeId.Unit) && who.GetEntry() == AKCreatureIds.JedogaController))
|
||||
return;
|
||||
|
||||
if (!bPreDone && who.IsTypeId(TypeId.Player) && me.GetDistance(who) < 100.0f)
|
||||
{
|
||||
Talk(TextIds.SayPreaching);
|
||||
bPreDone = true;
|
||||
}
|
||||
|
||||
if (instance.GetBossState(DataTypes.JedogaShadowseeker) != EncounterState.InProgress || !bOnGround)
|
||||
return;
|
||||
|
||||
if (!me.GetVictim() && me.CanCreatureAttack(who))
|
||||
{
|
||||
float attackRadius = me.GetAttackDistance(who);
|
||||
if (me.IsWithinDistInMap(who, attackRadius) && me.IsWithinLOSInMap(who))
|
||||
{
|
||||
if (!me.GetVictim())
|
||||
{
|
||||
who.RemoveAurasByType(AuraType.ModStealth);
|
||||
AttackStart(who);
|
||||
}
|
||||
else
|
||||
{
|
||||
who.SetInCombatWith(me);
|
||||
me.AddThreat(who, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveDown()
|
||||
{
|
||||
bOpFerokFail = false;
|
||||
|
||||
instance.SetData(DataTypes.JedogaTriggerSwitch, 0);
|
||||
me.GetMotionMaster().MovePoint(1, Misc.JedogaPosition[1]);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Normal, false);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, false);
|
||||
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable | UnitFlags.NonAttackable);
|
||||
|
||||
me.RemoveAurasDueToSpell(SpellIds.SphereVisual);
|
||||
|
||||
bOnGround = true;
|
||||
|
||||
if (UpdateVictim())
|
||||
{
|
||||
AttackStart(me.GetVictim());
|
||||
me.GetMotionMaster().MoveChase(me.GetVictim());
|
||||
}
|
||||
else
|
||||
{
|
||||
Unit target = Global.ObjAccessor.GetUnit(me, instance.GetGuidData(DataTypes.PlJedogaTarget));
|
||||
if (target)
|
||||
{
|
||||
AttackStart(target);
|
||||
instance.SetData(DataTypes.JedogaResetInitiands, 0);
|
||||
if (instance.GetBossState(DataTypes.JedogaShadowseeker) != EncounterState.InProgress)
|
||||
EnterCombat(target);
|
||||
}
|
||||
else if (!me.IsInCombat())
|
||||
EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
|
||||
void MoveUp()
|
||||
{
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Normal, true);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, true);
|
||||
me.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable | UnitFlags.NonAttackable);
|
||||
|
||||
me.AttackStop();
|
||||
me.RemoveAllAuras();
|
||||
me.LoadCreaturesAddon();
|
||||
me.GetMotionMaster().MovePoint(0, Misc.JedogaPosition[0]);
|
||||
|
||||
instance.SetData(DataTypes.JedogaTriggerSwitch, 1);
|
||||
if (instance.GetBossState(DataTypes.JedogaShadowseeker) == EncounterState.InProgress)
|
||||
GetVictimForSacrifice();
|
||||
|
||||
bOnGround = false;
|
||||
uiOpFerTimer = RandomHelper.URand(15 * Time.InMilliseconds, 30 * Time.InMilliseconds);
|
||||
}
|
||||
|
||||
void GetVictimForSacrifice()
|
||||
{
|
||||
ObjectGuid victim = instance.GetGuidData(DataTypes.AddJedogaInitiand);
|
||||
if (!victim.IsEmpty())
|
||||
{
|
||||
Talk(TextIds.SaySacrifice1);
|
||||
instance.SetGuidData(DataTypes.AddJedogaVictim, victim);
|
||||
}
|
||||
else
|
||||
bCanDown = true;
|
||||
}
|
||||
|
||||
void Sacrifice()
|
||||
{
|
||||
Talk(TextIds.SaySacrifice2);
|
||||
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
DoCast(me, SpellIds.GiftOfTheHerald, false);
|
||||
|
||||
bOpFerok = false;
|
||||
bCanDown = true;
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (instance.GetBossState(DataTypes.JedogaShadowseeker) != EncounterState.InProgress && instance.GetData(DataTypes.AllInitiandDead) != 0)
|
||||
MoveDown();
|
||||
|
||||
if (bOpFerok && !bOnGround && !bCanDown)
|
||||
Sacrifice();
|
||||
|
||||
if (bOpFerokFail && !bOnGround && !bCanDown)
|
||||
bCanDown = true;
|
||||
|
||||
if (bCanDown)
|
||||
{
|
||||
MoveDown();
|
||||
bCanDown = false;
|
||||
}
|
||||
|
||||
if (bOnGround)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (uiCycloneTimer <= diff)
|
||||
{
|
||||
DoCast(me, SpellIds.CycloneStrike, false);
|
||||
uiCycloneTimer = RandomHelper.URand(15 * Time.InMilliseconds, 30 * Time.InMilliseconds);
|
||||
}
|
||||
else uiCycloneTimer -= diff;
|
||||
|
||||
if (uiBoltTimer <= diff)
|
||||
{
|
||||
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 100, true);
|
||||
if (target)
|
||||
me.CastSpell(target, SpellIds.LightningBolt, false);
|
||||
|
||||
uiBoltTimer = RandomHelper.URand(15 * Time.InMilliseconds, 30 * Time.InMilliseconds);
|
||||
}
|
||||
else uiBoltTimer -= diff;
|
||||
|
||||
if (uiThunderTimer <= diff)
|
||||
{
|
||||
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 100, true);
|
||||
if (target)
|
||||
me.CastSpell(target, SpellIds.Thundershock, false);
|
||||
|
||||
uiThunderTimer = RandomHelper.URand(15 * Time.InMilliseconds, 30 * Time.InMilliseconds);
|
||||
}
|
||||
else uiThunderTimer -= diff;
|
||||
|
||||
if (uiOpFerTimer <= diff)
|
||||
MoveUp();
|
||||
else
|
||||
uiOpFerTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
InstanceScript instance;
|
||||
|
||||
uint uiOpFerTimer;
|
||||
uint uiCycloneTimer;
|
||||
uint uiBoltTimer;
|
||||
uint uiThunderTimer;
|
||||
|
||||
bool bPreDone;
|
||||
public bool bOpFerok;
|
||||
bool bOnGround;
|
||||
public bool bOpFerokFail;
|
||||
bool bCanDown;
|
||||
bool volunteerWork;
|
||||
bool bFirstTime;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class npc_jedoga_initiand : ScriptedAI
|
||||
{
|
||||
public npc_jedoga_initiand(Creature creature) : base(creature)
|
||||
{
|
||||
Initialize();
|
||||
instance = creature.GetInstanceScript();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
bWalking = false;
|
||||
bCheckTimer = 2 * Time.InMilliseconds;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
Initialize();
|
||||
|
||||
if (instance.GetBossState(DataTypes.JedogaShadowseeker) != EncounterState.InProgress)
|
||||
{
|
||||
me.RemoveAurasDueToSpell(SpellIds.SphereVisual);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Normal, false);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, false);
|
||||
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable | UnitFlags.NonAttackable);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoCast(me, SpellIds.SphereVisual, false);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Normal, true);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, true);
|
||||
me.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable | UnitFlags.NonAttackable);
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
if (!killer || instance == null)
|
||||
return;
|
||||
|
||||
if (bWalking)
|
||||
{
|
||||
Creature boss = ObjectAccessor.GetCreature(me, instance.GetGuidData(DataTypes.JedogaShadowseeker));
|
||||
if (boss)
|
||||
{
|
||||
if (!boss.GetAI<boss_jedoga_shadowseeker>().bOpFerok)
|
||||
boss.GetAI<boss_jedoga_shadowseeker>().bOpFerokFail = true;
|
||||
|
||||
if (killer.IsTypeId(TypeId.Player))
|
||||
boss.GetAI().DoAction(Misc.ActionInitiateKilled);
|
||||
}
|
||||
|
||||
instance.SetGuidData(DataTypes.AddJedogaVictim, ObjectGuid.Empty);
|
||||
|
||||
bWalking = false;
|
||||
}
|
||||
if (killer.IsTypeId(TypeId.Player))
|
||||
instance.SetGuidData(DataTypes.PlJedogaTarget, killer.GetGUID());
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit who) { }
|
||||
|
||||
public override void AttackStart(Unit victim)
|
||||
{
|
||||
if ((instance.GetBossState(DataTypes.JedogaShadowseeker) == EncounterState.InProgress) || !victim)
|
||||
return;
|
||||
|
||||
base.AttackStart(victim);
|
||||
}
|
||||
|
||||
public override void MoveInLineOfSight(Unit who)
|
||||
{
|
||||
if ((instance.GetBossState(DataTypes.JedogaShadowseeker) == EncounterState.InProgress) || !who)
|
||||
return;
|
||||
|
||||
base.MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
public override void MovementInform(MovementGeneratorType uiType, uint uiPointId)
|
||||
{
|
||||
if (uiType != MovementGeneratorType.Point || instance == null)
|
||||
return;
|
||||
|
||||
switch (uiPointId)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
Creature boss = me.GetMap().GetCreature(instance.GetGuidData(DataTypes.JedogaShadowseeker));
|
||||
if (boss)
|
||||
{
|
||||
boss.GetAI<boss_jedoga_shadowseeker>().bOpFerok = true;
|
||||
boss.GetAI<boss_jedoga_shadowseeker>().bOpFerokFail = false;
|
||||
me.KillSelf();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (bCheckTimer <= diff)
|
||||
{
|
||||
if (me.GetGUID() == instance.GetGuidData(DataTypes.AddJedogaVictim) && !bWalking)
|
||||
{
|
||||
me.RemoveAurasDueToSpell(SpellIds.SphereVisual);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Normal, false);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, false);
|
||||
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable | UnitFlags.NonAttackable);
|
||||
|
||||
float distance = me.GetDistance(Misc.JedogaPosition[1]);
|
||||
|
||||
if (distance < 9.0f)
|
||||
me.SetSpeedRate(UnitMoveType.Walk, 0.5f);
|
||||
else if (distance < 15.0f)
|
||||
me.SetSpeedRate(UnitMoveType.Walk, 0.75f);
|
||||
else if (distance < 20.0f)
|
||||
me.SetSpeedRate(UnitMoveType.Walk, 1.0f);
|
||||
|
||||
me.GetMotionMaster().Clear(false);
|
||||
me.GetMotionMaster().MovePoint(1, Misc.JedogaPosition[1]);
|
||||
bWalking = true;
|
||||
}
|
||||
if (!bWalking)
|
||||
{
|
||||
if (instance.GetBossState(DataTypes.JedogaShadowseeker) != EncounterState.InProgress && me.HasAura(SpellIds.SphereVisual))
|
||||
{
|
||||
me.RemoveAurasDueToSpell(SpellIds.SphereVisual);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Normal, false);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, false);
|
||||
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable | UnitFlags.NonAttackable);
|
||||
}
|
||||
if (instance.GetBossState(DataTypes.JedogaShadowseeker) == EncounterState.InProgress && !me.HasAura(SpellIds.SphereVisual))
|
||||
{
|
||||
DoCast(me, SpellIds.SphereVisual, false);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Normal, true);
|
||||
me.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, true);
|
||||
me.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable | UnitFlags.NonAttackable);
|
||||
}
|
||||
}
|
||||
bCheckTimer = 2 * Time.InMilliseconds;
|
||||
}
|
||||
else bCheckTimer -= diff;
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
InstanceScript instance;
|
||||
|
||||
uint bCheckTimer;
|
||||
bool bWalking;
|
||||
}
|
||||
|
||||
|
||||
[Script]
|
||||
class npc_jedogas_aufseher_trigger : ScriptedAI
|
||||
{
|
||||
public npc_jedogas_aufseher_trigger(Creature creature) : base(creature)
|
||||
{
|
||||
instance = creature.GetInstanceScript();
|
||||
bRemoved = false;
|
||||
bRemoved2 = false;
|
||||
bCast = false;
|
||||
bCast2 = false;
|
||||
|
||||
SetCombatMovement(false);
|
||||
}
|
||||
|
||||
public override void Reset() { }
|
||||
public override void EnterCombat(Unit who) { }
|
||||
public override void AttackStart(Unit victim) { }
|
||||
public override void MoveInLineOfSight(Unit who) { }
|
||||
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!bRemoved && me.GetPositionX() > 440.0f)
|
||||
{
|
||||
if (instance.GetBossState(DataTypes.PrinceTaldaram) == EncounterState.Done)
|
||||
{
|
||||
me.InterruptNonMeleeSpells(true);
|
||||
bRemoved = true;
|
||||
return;
|
||||
}
|
||||
if (!bCast)
|
||||
{
|
||||
DoCast(me, SpellIds.BeamVisualJedogasAufseher1, false);
|
||||
bCast = true;
|
||||
}
|
||||
}
|
||||
if (!bRemoved2 && me.GetPositionX() < 440.0f)
|
||||
{
|
||||
if (!bCast2 && instance.GetData(DataTypes.JedogaTriggerSwitch) != 0)
|
||||
{
|
||||
DoCast(me, SpellIds.BeamVisualJedogasAufseher2, false);
|
||||
bCast2 = true;
|
||||
}
|
||||
if (bCast2 && instance.GetData(DataTypes.JedogaTriggerSwitch) == 0)
|
||||
{
|
||||
me.InterruptNonMeleeSpells(true);
|
||||
bCast2 = false;
|
||||
}
|
||||
if (!bRemoved2 && instance.GetBossState(DataTypes.JedogaShadowseeker) == EncounterState.Done)
|
||||
{
|
||||
me.InterruptNonMeleeSpells(true);
|
||||
bRemoved2 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstanceScript instance;
|
||||
|
||||
bool bRemoved;
|
||||
bool bRemoved2;
|
||||
bool bCast;
|
||||
bool bCast2;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class achievement_volunteer_work : AchievementCriteriaScript
|
||||
{
|
||||
public achievement_volunteer_work() : base("achievement_volunteer_work") { }
|
||||
|
||||
public override bool OnCheck(Player player, Unit target)
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
Creature Jedoga = target.ToCreature();
|
||||
if (Jedoga)
|
||||
if (Jedoga.GetAI().GetData(Misc.DataVolunteerWork) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace Scripts.Northrend.AzjolNerub.Ahnkahet.PrinceTaldaram
|
||||
{
|
||||
struct SpellIds
|
||||
{
|
||||
public const uint Bloodthirst = 55968; // Trigger Spell + Add Aura
|
||||
public const uint ConjureFlameSphere = 55931;
|
||||
public const uint FlameSphereSummon1 = 55895; // 1x 30106
|
||||
public const uint FlameSphereSummon2 = 59511; // 1x 31686
|
||||
public const uint FlameSphereSummon3 = 59512; // 1x 31687
|
||||
public const uint FlameSphereSpawnEffect = 55891;
|
||||
public const uint FlameSphereVisual = 55928;
|
||||
public const uint FlameSpherePeriodic = 55926;
|
||||
public const uint FlameSphereDeathEffect = 55947;
|
||||
public const uint EmbraceOfTheVampyr = 55959;
|
||||
public const uint Vanish = 55964;
|
||||
|
||||
public const uint BeamVisual = 60342;
|
||||
public const uint HoverFall = 60425;
|
||||
}
|
||||
|
||||
struct CreatureIds
|
||||
{
|
||||
public const uint FlameSphere1 = 30106;
|
||||
public const uint FlameSphere2 = 31686;
|
||||
public const uint FlameSphere3 = 31687;
|
||||
}
|
||||
|
||||
struct TextIds
|
||||
{
|
||||
public const uint Say1 = 0;
|
||||
public const uint SayWarning = 1;
|
||||
public const uint SayAggro = 2;
|
||||
public const uint SaySlay = 3;
|
||||
public const uint SayDeath = 4;
|
||||
public const uint SayFeed = 5;
|
||||
public const uint SayVanish = 6;
|
||||
}
|
||||
|
||||
struct Misc
|
||||
{
|
||||
public const uint EventConjureFlameSpheres = 1;
|
||||
public const uint EventBloodthirst = 2;
|
||||
public const uint EventVanish = 3;
|
||||
public const uint EventJustVanished = 4;
|
||||
public const uint EventVanished = 5;
|
||||
public const uint EventFeeding = 6;
|
||||
|
||||
// Flame Sphere
|
||||
public const uint EventStartMove = 7;
|
||||
public const uint EventDespawn = 8;
|
||||
|
||||
public const uint DataEmbraceDmg = 20000;
|
||||
public const uint DataEmbraceDmgH = 40000;
|
||||
public const float DataSphereDistance = 25.0f;
|
||||
public const float DataSphereAngleOffset = MathFunctions.PI / 2;
|
||||
public const float DataGroundPositionZ = 11.30809f;
|
||||
}
|
||||
|
||||
[Script]
|
||||
public class boss_prince_taldaram : BossAI
|
||||
{
|
||||
public boss_prince_taldaram(Creature creature) : base(creature, DataTypes.PrinceTaldaram)
|
||||
{
|
||||
me.SetDisableGravity(true);
|
||||
_embraceTakenDamage = 0;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_Reset();
|
||||
_flameSphereTargetGUID.Clear();
|
||||
_embraceTargetGUID.Clear();
|
||||
_embraceTakenDamage = 0;
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit who)
|
||||
{
|
||||
_EnterCombat();
|
||||
Talk(TextIds.SayAggro);
|
||||
_events.ScheduleEvent(Misc.EventBloodthirst, 10000);
|
||||
_events.ScheduleEvent(Misc.EventVanish, RandomHelper.URand(25000, 35000));
|
||||
_events.ScheduleEvent(Misc.EventConjureFlameSpheres, 5000);
|
||||
}
|
||||
|
||||
public override void JustSummoned(Creature summon)
|
||||
{
|
||||
base.JustSummoned(summon);
|
||||
|
||||
switch (summon.GetEntry())
|
||||
{
|
||||
case CreatureIds.FlameSphere1:
|
||||
case CreatureIds.FlameSphere2:
|
||||
case CreatureIds.FlameSphere3:
|
||||
summon.GetAI().SetGUID(_flameSphereTargetGUID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
_events.ExecuteEvents(eventId =>
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case Misc.EventBloodthirst:
|
||||
DoCast(me, SpellIds.Bloodthirst);
|
||||
_events.ScheduleEvent(Misc.EventBloodthirst, 10000);
|
||||
break;
|
||||
case Misc.EventConjureFlameSpheres:
|
||||
// random target?
|
||||
Unit victim = me.GetVictim();
|
||||
if (victim)
|
||||
{
|
||||
_flameSphereTargetGUID = victim.GetGUID();
|
||||
DoCast(victim, SpellIds.ConjureFlameSphere);
|
||||
}
|
||||
_events.ScheduleEvent(Misc.EventConjureFlameSpheres, 15000);
|
||||
break;
|
||||
case Misc.EventVanish:
|
||||
{
|
||||
var players = me.GetMap().GetPlayers();
|
||||
uint targets = 0;
|
||||
foreach (var player in players)
|
||||
{
|
||||
if (player && player.IsAlive())
|
||||
++targets;
|
||||
}
|
||||
|
||||
if (targets > 2)
|
||||
{
|
||||
Talk(TextIds.SayVanish);
|
||||
DoCast(me, SpellIds.Vanish);
|
||||
me.SetInCombatState(true); // Prevents the boss from resetting
|
||||
_events.DelayEvents(500);
|
||||
_events.ScheduleEvent(Misc.EventJustVanished, 500);
|
||||
Unit embraceTarget = SelectTarget(SelectAggroTarget.Random, 0, 100.0f, true);
|
||||
if (embraceTarget)
|
||||
_embraceTargetGUID = embraceTarget.GetGUID();
|
||||
}
|
||||
_events.ScheduleEvent(Misc.EventVanish, RandomHelper.URand(25000, 35000));
|
||||
break;
|
||||
}
|
||||
case Misc.EventJustVanished:
|
||||
{
|
||||
Unit embraceTarget = GetEmbraceTarget();
|
||||
if (embraceTarget)
|
||||
{
|
||||
me.GetMotionMaster().Clear();
|
||||
me.SetSpeedRate(UnitMoveType.Walk, 2.0f);
|
||||
me.GetMotionMaster().MoveChase(embraceTarget);
|
||||
}
|
||||
_events.ScheduleEvent(Misc.EventVanished, 1300);
|
||||
}
|
||||
break;
|
||||
case Misc.EventVanished:
|
||||
{
|
||||
Unit embraceTarget = GetEmbraceTarget();
|
||||
if (embraceTarget)
|
||||
DoCast(embraceTarget, SpellIds.EmbraceOfTheVampyr);
|
||||
Talk(TextIds.SayFeed);
|
||||
me.GetMotionMaster().Clear();
|
||||
me.SetSpeedRate(UnitMoveType.Walk, 1.0f);
|
||||
me.GetMotionMaster().MoveChase(me.GetVictim());
|
||||
_events.ScheduleEvent(Misc.EventFeeding, 20000);
|
||||
}
|
||||
break;
|
||||
case Misc.EventFeeding:
|
||||
_embraceTargetGUID.Clear();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit doneBy, ref uint damage)
|
||||
{
|
||||
Unit embraceTarget = GetEmbraceTarget();
|
||||
|
||||
if (embraceTarget && embraceTarget.IsAlive())
|
||||
{
|
||||
_embraceTakenDamage += damage;
|
||||
if (_embraceTakenDamage > DungeonMode<uint>(Misc.DataEmbraceDmg, Misc.DataEmbraceDmgH))
|
||||
{
|
||||
_embraceTargetGUID.Clear();
|
||||
me.CastStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Talk(TextIds.SayDeath);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
if (!victim.IsTypeId(TypeId.Player))
|
||||
return;
|
||||
|
||||
if (victim.GetGUID() == _embraceTargetGUID)
|
||||
_embraceTargetGUID.Clear();
|
||||
|
||||
Talk(TextIds.SaySlay);
|
||||
}
|
||||
|
||||
public bool CheckSpheres()
|
||||
{
|
||||
for (byte i = 0; i < 2; ++i)
|
||||
{
|
||||
if (instance.GetData(DataTypes.Sphere1 + i) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
RemovePrison();
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit GetEmbraceTarget()
|
||||
{
|
||||
if (!_embraceTargetGUID.IsEmpty())
|
||||
return Global.ObjAccessor.GetUnit(me, _embraceTargetGUID);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void RemovePrison()
|
||||
{
|
||||
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
||||
me.RemoveAurasDueToSpell(SpellIds.BeamVisual);
|
||||
me.SetHomePosition(me.GetPositionX(), me.GetPositionY(), Misc.DataGroundPositionZ, me.GetOrientation());
|
||||
DoCast(SpellIds.HoverFall);
|
||||
me.SetDisableGravity(false);
|
||||
me.GetMotionMaster().MoveLand(0, me.GetHomePosition());
|
||||
Talk(TextIds.SayWarning);
|
||||
instance.HandleGameObject(instance.GetGuidData(DataTypes.PrinceTaldaramPlatform), true);
|
||||
}
|
||||
|
||||
ObjectGuid _flameSphereTargetGUID;
|
||||
ObjectGuid _embraceTargetGUID;
|
||||
uint _embraceTakenDamage;
|
||||
}
|
||||
|
||||
[Script] // 30106, 31686, 31687 - Flame Sphere
|
||||
class npc_prince_taldaram_flame_sphere : ScriptedAI
|
||||
{
|
||||
public npc_prince_taldaram_flame_sphere(Creature creature) : base(creature)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
DoCast(me, SpellIds.FlameSphereSpawnEffect, true);
|
||||
DoCast(me, SpellIds.FlameSphereVisual, true);
|
||||
|
||||
_flameSphereTargetGUID.Clear();
|
||||
_events.Reset();
|
||||
_events.ScheduleEvent(Misc.EventStartMove, 3 * Time.InMilliseconds);
|
||||
_events.ScheduleEvent(Misc.EventDespawn, 13 * Time.InMilliseconds);
|
||||
}
|
||||
|
||||
public override void SetGUID(ObjectGuid guid, int id = 0)
|
||||
{
|
||||
_flameSphereTargetGUID = guid;
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit who) { }
|
||||
|
||||
public override void MoveInLineOfSight(Unit who) { }
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
_events.Update(diff);
|
||||
|
||||
_events.ExecuteEvents(eventId =>
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case Misc.EventStartMove:
|
||||
{
|
||||
DoCast(me, SpellIds.FlameSpherePeriodic, true);
|
||||
|
||||
/// @todo: find correct values
|
||||
float angleOffset = 0.0f;
|
||||
float distOffset = Misc.DataSphereDistance;
|
||||
|
||||
switch (me.GetEntry())
|
||||
{
|
||||
case CreatureIds.FlameSphere1:
|
||||
break;
|
||||
case CreatureIds.FlameSphere2:
|
||||
angleOffset = Misc.DataSphereAngleOffset;
|
||||
break;
|
||||
case CreatureIds.FlameSphere3:
|
||||
angleOffset = -Misc.DataSphereAngleOffset;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Unit sphereTarget = Global.ObjAccessor.GetUnit(me, _flameSphereTargetGUID);
|
||||
if (!sphereTarget)
|
||||
return;
|
||||
|
||||
float angle = me.GetAngle(sphereTarget) + angleOffset;
|
||||
float x = me.GetPositionX() + distOffset * (float)Math.Cos(angle);
|
||||
float y = me.GetPositionY() + distOffset * (float)Math.Sin(angle);
|
||||
|
||||
/// @todo: correct speed
|
||||
me.GetMotionMaster().MovePoint(0, x, y, me.GetPositionZ());
|
||||
break;
|
||||
}
|
||||
case Misc.EventDespawn:
|
||||
DoCast(me, SpellIds.FlameSphereDeathEffect, true);
|
||||
me.DespawnOrUnsummon(1000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ObjectGuid _flameSphereTargetGUID;
|
||||
}
|
||||
|
||||
[Script] // 193093, 193094 - Ancient Nerubian Device
|
||||
class go_prince_taldaram_sphere : GameObjectScript
|
||||
{
|
||||
public go_prince_taldaram_sphere() : base("go_prince_taldaram_sphere") { }
|
||||
|
||||
public override bool OnGossipHello(Player player, GameObject go)
|
||||
{
|
||||
InstanceScript instance = go.GetInstanceScript();
|
||||
if (instance == null)
|
||||
return false;
|
||||
|
||||
Creature PrinceTaldaram = ObjectAccessor.GetCreature(go, instance.GetGuidData(DataTypes.PrinceTaldaram));
|
||||
if (PrinceTaldaram && PrinceTaldaram.IsAlive())
|
||||
{
|
||||
go.SetFlag(GameObjectFields.Flags, GameObjectFlags.NotSelectable);
|
||||
go.SetGoState(GameObjectState.Active);
|
||||
|
||||
switch (go.GetEntry())
|
||||
{
|
||||
case GameObjectIds.Sphere1:
|
||||
instance.SetData(DataTypes.Sphere1, (uint)EncounterState.InProgress);
|
||||
PrinceTaldaram.GetAI().Talk(TextIds.Say1);
|
||||
break;
|
||||
case GameObjectIds.Sphere2:
|
||||
instance.SetData(DataTypes.Sphere2, (uint)EncounterState.InProgress);
|
||||
PrinceTaldaram.GetAI().Talk(TextIds.Say1);
|
||||
break;
|
||||
}
|
||||
|
||||
PrinceTaldaram.GetAI<boss_prince_taldaram>().CheckSpheres();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Script] // 55931 - Conjure Flame Sphere
|
||||
class spell_prince_taldaram_conjure_flame_sphere : SpellScript
|
||||
{
|
||||
public override bool Validate(SpellInfo spellInfo)
|
||||
{
|
||||
return ValidateSpellInfo(SpellIds.FlameSphereSummon1, SpellIds.FlameSphereSummon2, SpellIds.FlameSphereSummon3);
|
||||
}
|
||||
|
||||
void HandleScript(uint effIndex)
|
||||
{
|
||||
Unit caster = GetCaster();
|
||||
caster.CastSpell(caster, SpellIds.FlameSphereSummon1, true);
|
||||
|
||||
if (caster.GetMap().IsHeroic())
|
||||
{
|
||||
caster.CastSpell(caster, SpellIds.FlameSphereSummon2, true);
|
||||
caster.CastSpell(caster, SpellIds.FlameSphereSummon3, true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Register()
|
||||
{
|
||||
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.Dummy));
|
||||
}
|
||||
}
|
||||
|
||||
[Script] // 55895, 59511, 59512 - Flame Sphere Summon
|
||||
class spell_prince_taldaram_flame_sphere_summon : SpellScript
|
||||
{
|
||||
void SetDest(ref SpellDestination dest)
|
||||
{
|
||||
dest.RelocateOffset(new Position(0.0f, 0.0f, 5.5f, 0.0f));
|
||||
}
|
||||
|
||||
public override void Register()
|
||||
{
|
||||
OnDestinationTargetSelect.Add(new DestinationTargetSelectHandler(SetDest, 0, Targets.DestCaster));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* 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;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Scripts.Northrend.AzjolNerub.Ahnkahet
|
||||
{
|
||||
struct DataTypes
|
||||
{
|
||||
// Encounter States/Boss GUIDs
|
||||
public const uint ElderNadox = 0;
|
||||
public const uint PrinceTaldaram = 1;
|
||||
public const uint JedogaShadowseeker = 2;
|
||||
public const uint Amanitar = 3;
|
||||
public const uint HeraldVolazj = 4;
|
||||
|
||||
// Additional Data
|
||||
public const uint Sphere1 = 5;
|
||||
public const uint Sphere2 = 6;
|
||||
public const uint PrinceTaldaramPlatform = 7;
|
||||
public const uint PlJedogaTarget = 8;
|
||||
public const uint AddJedogaVictim = 9;
|
||||
public const uint AddJedogaInitiand = 10;
|
||||
public const uint JedogaTriggerSwitch = 11;
|
||||
public const uint JedogaResetInitiands = 12;
|
||||
public const uint AllInitiandDead = 13;
|
||||
}
|
||||
|
||||
struct AKCreatureIds
|
||||
{
|
||||
public const uint ElderNadox = 29309;
|
||||
public const uint PrinceTaldaram = 29308;
|
||||
public const uint JedogaShadowseeker = 29310;
|
||||
public const uint Amanitar = 30258;
|
||||
public const uint HeraldVolazj = 29311;
|
||||
|
||||
// Elder Nadox
|
||||
public const uint AhnkaharGuardian = 30176;
|
||||
public const uint AhnkaharSwarmer = 30178;
|
||||
|
||||
// Jedoga Shadowseeker
|
||||
public const uint Initiand = 30114;
|
||||
public const uint JedogaController = 30181;
|
||||
|
||||
// Herald Volazj
|
||||
//public const uint TwistedVisage1 = 30621,
|
||||
//public const uint TwistedVisage2 = 30622,
|
||||
//public const uint TwistedVisage3 = 30623,
|
||||
//public const uint TwistedVisage4 = 30624,
|
||||
public const uint TwistedVisage = 30625;
|
||||
}
|
||||
|
||||
struct GameObjectIds
|
||||
{
|
||||
public const uint PrinceTaldaramGate = 192236;
|
||||
public const uint PrinceTaldaramPlatform = 193564;
|
||||
public const uint Sphere1 = 193093;
|
||||
public const uint Sphere2 = 193094;
|
||||
}
|
||||
|
||||
[Script]
|
||||
class instance_ahnkahet : InstanceMapScript
|
||||
{
|
||||
public instance_ahnkahet() : base("instance_ahnkahet", 619) { }
|
||||
|
||||
class instance_ahnkahet_InstanceScript : InstanceScript
|
||||
{
|
||||
public instance_ahnkahet_InstanceScript(Map map) : base(map)
|
||||
{
|
||||
SetHeaders("AK");
|
||||
SetBossNumber(DataTypes.HeraldVolazj + 1);
|
||||
LoadDoorData(new DoorData(GameObjectIds.PrinceTaldaramGate, DataTypes.PrinceTaldaram, DoorType.Passage));
|
||||
|
||||
SwitchTrigger = 0;
|
||||
|
||||
SpheresState[0] = 0;
|
||||
SpheresState[1] = 0;
|
||||
}
|
||||
|
||||
public override void OnCreatureCreate(Creature creature)
|
||||
{
|
||||
switch (creature.GetEntry())
|
||||
{
|
||||
case AKCreatureIds.ElderNadox:
|
||||
ElderNadoxGUID = creature.GetGUID();
|
||||
break;
|
||||
case AKCreatureIds.PrinceTaldaram:
|
||||
PrinceTaldaramGUID = creature.GetGUID();
|
||||
break;
|
||||
case AKCreatureIds.JedogaShadowseeker:
|
||||
JedogaShadowseekerGUID = creature.GetGUID();
|
||||
break;
|
||||
case AKCreatureIds.Amanitar:
|
||||
AmanitarGUID = creature.GetGUID();
|
||||
break;
|
||||
case AKCreatureIds.HeraldVolazj:
|
||||
HeraldVolazjGUID = creature.GetGUID();
|
||||
break;
|
||||
case AKCreatureIds.Initiand:
|
||||
InitiandGUIDs.Add(creature.GetGUID());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGameObjectCreate(GameObject go)
|
||||
{
|
||||
switch (go.GetEntry())
|
||||
{
|
||||
case GameObjectIds.PrinceTaldaramPlatform:
|
||||
PrinceTaldaramPlatformGUID = go.GetGUID();
|
||||
if (GetBossState(DataTypes.PrinceTaldaram) == EncounterState.Done)
|
||||
HandleGameObject(ObjectGuid.Empty, true, go);
|
||||
break;
|
||||
case GameObjectIds.Sphere1:
|
||||
if (SpheresState[0] != 0)
|
||||
{
|
||||
go.SetGoState(GameObjectState.Active);
|
||||
go.SetFlag(GameObjectFields.Flags, GameObjectFlags.NotSelectable);
|
||||
}
|
||||
else
|
||||
go.RemoveFlag(GameObjectFields.Flags, GameObjectFlags.NotSelectable);
|
||||
break;
|
||||
case GameObjectIds.Sphere2:
|
||||
if (SpheresState[1] != 0)
|
||||
{
|
||||
go.SetGoState(GameObjectState.Active);
|
||||
go.SetFlag(GameObjectFields.Flags, GameObjectFlags.NotSelectable);
|
||||
}
|
||||
else
|
||||
go.RemoveFlag(GameObjectFields.Flags, GameObjectFlags.NotSelectable);
|
||||
break;
|
||||
case GameObjectIds.PrinceTaldaramGate:
|
||||
AddDoor(go, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGameObjectRemove(GameObject go)
|
||||
{
|
||||
switch (go.GetEntry())
|
||||
{
|
||||
case GameObjectIds.PrinceTaldaramGate:
|
||||
AddDoor(go, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetData(uint type, uint data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.Sphere1:
|
||||
case DataTypes.Sphere2:
|
||||
SpheresState[type - DataTypes.Sphere1] = data;
|
||||
break;
|
||||
case DataTypes.JedogaTriggerSwitch:
|
||||
SwitchTrigger = (byte)data;
|
||||
break;
|
||||
case DataTypes.JedogaResetInitiands:
|
||||
foreach (ObjectGuid guid in InitiandGUIDs)
|
||||
{
|
||||
Creature creature = instance.GetCreature(guid);
|
||||
if (creature)
|
||||
{
|
||||
creature.Respawn();
|
||||
if (!creature.IsInEvadeMode())
|
||||
creature.GetAI().EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override uint GetData(uint type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.Sphere1:
|
||||
case DataTypes.Sphere2:
|
||||
return SpheresState[type - DataTypes.Sphere1];
|
||||
case DataTypes.AllInitiandDead:
|
||||
foreach (ObjectGuid guid in InitiandGUIDs)
|
||||
{
|
||||
Creature cr = instance.GetCreature(guid);
|
||||
if (!cr || cr.IsAlive())
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
case DataTypes.JedogaTriggerSwitch:
|
||||
return SwitchTrigger;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void SetGuidData(uint type, ObjectGuid data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.AddJedogaVictim:
|
||||
JedogaSacrifices = data;
|
||||
break;
|
||||
case DataTypes.PlJedogaTarget:
|
||||
JedogaTarget = data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override ObjectGuid GetGuidData(uint type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.ElderNadox:
|
||||
return ElderNadoxGUID;
|
||||
case DataTypes.PrinceTaldaram:
|
||||
return PrinceTaldaramGUID;
|
||||
case DataTypes.JedogaShadowseeker:
|
||||
return JedogaShadowseekerGUID;
|
||||
case DataTypes.Amanitar:
|
||||
return AmanitarGUID;
|
||||
case DataTypes.HeraldVolazj:
|
||||
return HeraldVolazjGUID;
|
||||
case DataTypes.PrinceTaldaramPlatform:
|
||||
return PrinceTaldaramPlatformGUID;
|
||||
case DataTypes.AddJedogaInitiand:
|
||||
{
|
||||
List<ObjectGuid> vInitiands = new List<ObjectGuid>();
|
||||
foreach (ObjectGuid guid in InitiandGUIDs)
|
||||
{
|
||||
Creature cr = instance.GetCreature(guid);
|
||||
if (cr && cr.IsAlive())
|
||||
vInitiands.Add(guid);
|
||||
}
|
||||
if (vInitiands.Empty())
|
||||
return ObjectGuid.Empty;
|
||||
|
||||
return vInitiands.SelectRandom();
|
||||
}
|
||||
case DataTypes.AddJedogaVictim:
|
||||
return JedogaSacrifices;
|
||||
case DataTypes.PlJedogaTarget:
|
||||
return JedogaTarget;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ObjectGuid.Empty;
|
||||
}
|
||||
|
||||
public override bool SetBossState(uint type, EncounterState state)
|
||||
{
|
||||
if (!base.SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.JedogaShadowseeker:
|
||||
if (state == EncounterState.Done)
|
||||
{
|
||||
foreach (ObjectGuid guid in InitiandGUIDs)
|
||||
{
|
||||
Creature cr = instance.GetCreature(guid);
|
||||
if (cr)
|
||||
cr.DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteSaveDataMore(string data)
|
||||
{
|
||||
data += SpheresState[0] + ' ' + SpheresState[1];
|
||||
}
|
||||
|
||||
void ReadSaveDataMore(string data)
|
||||
{
|
||||
data += SpheresState[0];
|
||||
data += SpheresState[1];
|
||||
}
|
||||
|
||||
ObjectGuid ElderNadoxGUID;
|
||||
ObjectGuid PrinceTaldaramGUID;
|
||||
ObjectGuid JedogaShadowseekerGUID;
|
||||
ObjectGuid AmanitarGUID;
|
||||
ObjectGuid HeraldVolazjGUID;
|
||||
|
||||
ObjectGuid PrinceTaldaramPlatformGUID;
|
||||
ObjectGuid JedogaSacrifices;
|
||||
ObjectGuid JedogaTarget;
|
||||
|
||||
List<ObjectGuid> InitiandGUIDs = new List<ObjectGuid>();
|
||||
|
||||
uint[] SpheresState = new uint[2];
|
||||
byte SwitchTrigger;
|
||||
}
|
||||
|
||||
public override InstanceScript GetInstanceScript(InstanceMap map)
|
||||
{
|
||||
return new instance_ahnkahet_InstanceScript(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user