1525 lines
61 KiB
C#
1525 lines
61 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Game.Entities;
|
|
using Game.AI;
|
|
using Game.Scripting;
|
|
using Game.Spells;
|
|
using Framework.Constants;
|
|
using Game.Maps;
|
|
using Game.DataStorage;
|
|
|
|
namespace Scripts.Northrend.IcecrownCitadel
|
|
{
|
|
using static IccConst;
|
|
using static ProfessorPutricideConst;
|
|
|
|
class ProfessorPutricideConst
|
|
{
|
|
// Festergut
|
|
public const uint EventFestergutDies = 1;
|
|
public const uint EventFestergutGoo = 2;
|
|
|
|
public const uint SayFestergutGaseousBlight = 0;
|
|
public const uint SayFestergutDeath = 1;
|
|
|
|
public const uint SpellReleaseGasVisual = 69125;
|
|
public const uint SpellGaseousBlightLarge = 69157;
|
|
public const uint SpellGaseousBlightMedium = 69162;
|
|
public const uint SpellGaseousBlightSmall = 69164;
|
|
public const uint SpellMalleableGooH = 72296;
|
|
public const uint SpellMalleableGooSummon = 72299;
|
|
|
|
|
|
// Rotface
|
|
public const uint EventRotfaceDies = 3;
|
|
public const uint EventRotfaceOozeFlood = 5;
|
|
|
|
public const uint SayRotfaceOozeFlood = 2;
|
|
public const uint SayRotfaceDeath = 3;
|
|
|
|
// Professor Putricide
|
|
public const uint EventBerserk = 6; // All Phases
|
|
public const uint EventSlimePuddle = 7; // All Phases
|
|
public const uint EventUnstableExperiment = 8; // P1 && P2
|
|
public const uint EventTearGas = 9; // Phase Transition Not Heroic
|
|
public const uint EventResumeAttack = 10;
|
|
public const uint EventMalleableGoo = 11;
|
|
public const uint EventChokingGasBomb = 12;
|
|
public const uint EventUnboundPlague = 13;
|
|
public const uint EventMutatedPlague = 14;
|
|
public const uint EventPhaseTransition = 15;
|
|
|
|
public const uint SayAggro = 4;
|
|
public const uint EmoteUnstableExperiment = 5;
|
|
public const uint SayPhaseTransitionHeroic = 6;
|
|
public const uint SayTransform1 = 7;
|
|
public const uint SayTransform2 = 8; // Always Used For Phase2 Change; Do Not Group With public const uint SayTransform1
|
|
public const uint EmoteMalleableGoo = 9;
|
|
public const uint EmoteChokingGasBomb = 10;
|
|
public const uint SayKill = 11;
|
|
public const uint SayBerserk = 12;
|
|
public const uint SayDeath = 13;
|
|
|
|
public const uint SpellSlimePuddleTrigger = 70341;
|
|
public const uint SpellMalleableGoo = 70852;
|
|
public const uint SpellUnstableExperiment = 70351;
|
|
public const uint SpellTearGas = 71617; // Phase Transition
|
|
public const uint SpellTearGasCreature = 71618;
|
|
public const uint SpellTearGasCancel = 71620;
|
|
public const uint SpellTearGasPeriodicTrigger = 73170;
|
|
public const uint SpellCreateConcoction = 71621;
|
|
public const uint SpellGuzzlePotions = 71893;
|
|
public const uint SpellOozeTankProtection = 71770; // Protects The Tank
|
|
public const uint SpellChokingGasBomb = 71255;
|
|
public const uint SpellOozeVariable = 74118;
|
|
public const uint SpellGasVariable = 74119;
|
|
public const uint SpellUnboundPlague = 70911;
|
|
public const uint SpellUnboundPlagueSearcher = 70917;
|
|
public const uint SpellPlagueSickness = 70953;
|
|
public const uint SpellUnboundPlagueProtection = 70955;
|
|
public const uint SpellMutatedPlague = 72451;
|
|
public const uint SpellMutatedPlagueClear = 72618;
|
|
|
|
// Slime Puddle
|
|
public const uint SpellGrowStacker = 70345;
|
|
public const uint SpellGrow = 70347;
|
|
public const uint SpellSlimePuddleAura = 70343;
|
|
|
|
// Gas Cloud
|
|
public const uint SpellGaseousBloatProc = 70215;
|
|
public const uint SpellGaseousBloat = 70672;
|
|
public const uint SpellGaseousBloatProtection = 70812;
|
|
public const uint SpellExpungedGas = 70701;
|
|
|
|
// Volatile Ooze
|
|
public const uint SpellOozeEruption = 70492;
|
|
public const uint SpellVolatileOozeAdhesive = 70447;
|
|
public const uint SpellOozeEruptionSearchPeriodic = 70457;
|
|
public const uint SpellVolatileOozeProtection = 70530;
|
|
|
|
// Choking Gas Bomb
|
|
public const uint SpellChokingGasBombPeriodic = 71259;
|
|
public const uint SpellChokingGasExplosionTrigger = 71280;
|
|
|
|
// Mutated Abomination Vehicle
|
|
public const uint SpellAbominationVehiclePowerDrain = 70385;
|
|
public const uint SpellMutatedTransformation = 70311;
|
|
public const uint SpellMutatedTransformationDamage = 70405;
|
|
public const uint SpellMutatedTransformationName = 72401;
|
|
|
|
// Unholy Infusion
|
|
public const uint SpellUnholyInfusionCredit = 71518;
|
|
|
|
public static Position festergutWatchPos = new Position(4324.820f, 3166.03f, 389.3831f, 3.316126f); //emote 432 (release gas)
|
|
public static Position rotfaceWatchPos = new Position(4390.371f, 3164.50f, 389.3890f, 5.497787f); //emote 432 (release ooze)
|
|
public static Position tablePos = new Position(4356.190f, 3262.90f, 389.4820f, 1.483530f);
|
|
|
|
//Points
|
|
public const uint PointFestergut = 366260;
|
|
public const uint PointRotface = 366270;
|
|
public const uint PointTable = 366780;
|
|
|
|
//Data
|
|
public const uint DataExperimentStage = 1;
|
|
public const uint DataPhase = 2;
|
|
public const uint DataAbomination = 3;
|
|
}
|
|
|
|
enum Phases
|
|
{
|
|
None = 0,
|
|
Festergut = 1,
|
|
Rotface = 2,
|
|
Combat1 = 4,
|
|
Combat2 = 5,
|
|
Combat3 = 6
|
|
}
|
|
|
|
class AbominationDespawner
|
|
{
|
|
public AbominationDespawner(Unit owner)
|
|
{
|
|
_owner = owner;
|
|
}
|
|
|
|
public bool Invoke(ObjectGuid guid)
|
|
{
|
|
Unit summon = Global.ObjAccessor.GetUnit(_owner, guid);
|
|
if (summon)
|
|
{
|
|
if (summon.GetEntry() == NPC_MUTATED_ABOMINATION_10 || summon.GetEntry() == NPC_MUTATED_ABOMINATION_25)
|
|
{
|
|
Vehicle veh = summon.GetVehicleKit();
|
|
if (veh)
|
|
veh.RemoveAllPassengers(); // also despawns the vehicle
|
|
|
|
// Found unit is Mutated Abomination, remove it
|
|
return true;
|
|
}
|
|
|
|
// Found unit is not Mutated Abomintaion, leave it
|
|
return false;
|
|
}
|
|
|
|
// No unit found, remove from SummonList
|
|
return true;
|
|
}
|
|
|
|
Unit _owner;
|
|
}
|
|
|
|
struct RotfaceHeightCheck
|
|
{
|
|
public RotfaceHeightCheck(Creature rotface)
|
|
{
|
|
_rotface = rotface;
|
|
}
|
|
|
|
public bool Invoke(Creature stalker)
|
|
{
|
|
return stalker.GetPositionZ() < _rotface.GetPositionZ() + 5.0f;
|
|
}
|
|
|
|
Creature _rotface;
|
|
}
|
|
|
|
class boss_professor_putricide : CreatureScript
|
|
{
|
|
public boss_professor_putricide() : base("boss_professor_putricide") { }
|
|
|
|
class boss_professor_putricideAI : BossAI
|
|
{
|
|
public boss_professor_putricideAI(Creature creature) : base(creature, DataTypes.ProfessorPutricide)
|
|
{
|
|
_baseSpeed = creature.GetSpeedRate(UnitMoveType.Run);
|
|
_experimentState = EXPERIMENT_STATE_OOZE;
|
|
|
|
_phase = Phases.None;
|
|
_oozeFloodStage = 0;
|
|
}
|
|
|
|
public override void Reset()
|
|
{
|
|
if (!(_events.IsInPhase((byte)Phases.Rotface) || _events.IsInPhase((byte)Phases.Festergut)))
|
|
instance.SetBossState(DataTypes.ProfessorPutricide, EncounterState.NotStarted);
|
|
instance.SetData(DataTypes.NauseaAchievement, 1);
|
|
|
|
_events.Reset();
|
|
summons.DespawnAll();
|
|
SetPhase(Phases.Combat1);
|
|
_experimentState = EXPERIMENT_STATE_OOZE;
|
|
me.SetReactState(ReactStates.Defensive);
|
|
me.SetWalk(false);
|
|
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Point)
|
|
me.GetMotionMaster().MovementExpired();
|
|
|
|
if (instance.GetBossState(DATA_ROTFACE) == EncounterState.Done && instance.GetBossState(DataTypes.Festergut) == EncounterState.Done)
|
|
me.RemoveFlag(UnitFields.Flags, UnitFlags.ImmuneToPc | UnitFlags.NotSelectable);
|
|
}
|
|
|
|
public override void EnterCombat(Unit who)
|
|
{
|
|
if (_events.IsInPhase((byte)Phases.Rotface) || _events.IsInPhase((byte)Phases.Festergut))
|
|
return;
|
|
|
|
if (!instance.CheckRequiredBosses(DataTypes.ProfessorPutricide, who.ToPlayer()))
|
|
{
|
|
EnterEvadeMode();
|
|
instance.DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT);
|
|
return;
|
|
}
|
|
|
|
me.setActive(true);
|
|
_events.Reset();
|
|
_events.ScheduleEvent(EVENT_BERSERK, 600000);
|
|
_events.ScheduleEvent(EVENT_SLIME_PUDDLE, 10000);
|
|
_events.ScheduleEvent(EVENT_UNSTABLE_EXPERIMENT, RandomHelper.URand(30000, 35000));
|
|
if (IsHeroic())
|
|
_events.ScheduleEvent(EVENT_UNBOUND_PLAGUE, 20000);
|
|
|
|
SetPhase(Phases.Combat1);
|
|
Talk(SAY_AGGRO);
|
|
DoCast(me, SPELL_OOZE_TANK_PROTECTION, true);
|
|
DoZoneInCombat(me);
|
|
|
|
instance.SetBossState(DataTypes.ProfessorPutricide, EncounterState.InProgress);
|
|
}
|
|
|
|
public override void JustReachedHome()
|
|
{
|
|
_JustReachedHome();
|
|
me.SetWalk(false);
|
|
if (_events.IsInPhase((byte)Phases.Combat1) || _events.IsInPhase((byte)Phases.Combat2) || _events.IsInPhase((byte)Phases.Combat3))
|
|
instance.SetBossState(DataTypes.ProfessorPutricide, EncounterState.Fail);
|
|
}
|
|
|
|
public override void KilledUnit(Unit victim)
|
|
{
|
|
if (victim.IsPlayer())
|
|
Talk(SAY_KILL);
|
|
}
|
|
|
|
public override void JustDied(Unit killer)
|
|
{
|
|
_JustDied();
|
|
Talk(SAY_DEATH);
|
|
|
|
if (Is25ManRaid() && me.HasAura(SPELL_SHADOWS_FATE))
|
|
DoCastAOE(SPELL_UNHOLY_INFUSION_CREDIT, true);
|
|
|
|
DoCast(SPELL_MUTATED_PLAGUE_CLEAR);
|
|
}
|
|
|
|
public override void JustSummoned(Creature summon)
|
|
{
|
|
summons.Summon(summon);
|
|
switch (summon.GetEntry())
|
|
{
|
|
case NPC_MALLEABLE_OOZE_STALKER:
|
|
DoCast(summon, SPELL_MALLEABLE_GOO_H);
|
|
return;
|
|
case NPC_GROWING_OOZE_PUDDLE:
|
|
summon.CastSpell(summon, SPELL_GROW_STACKER, true);
|
|
summon.CastSpell(summon, SPELL_SLIME_PUDDLE_AURA, true);
|
|
// blizzard casts this spell 7 times initially (confirmed in sniff)
|
|
for (byte i = 0; i < 7; ++i)
|
|
summon.CastSpell(summon, SPELL_GROW, true);
|
|
break;
|
|
case NPC_GAS_CLOUD:
|
|
// no possible aura seen in sniff adding the aurastate
|
|
summon.ModifyAuraState(AuraStateType.Unk22, true);
|
|
summon.CastSpell(summon, SPELL_GASEOUS_BLOAT_PROC, true);
|
|
summon.ApplySpellImmune(0, SpellImmunity.Effect, SpellEffectName.KnockBack, true);
|
|
summon.SetReactState(ReactStates.Passive);
|
|
break;
|
|
case NPC_VOLATILE_OOZE:
|
|
// no possible aura seen in sniff adding the aurastate
|
|
summon.ModifyAuraState(AuraStateType.Unk19, true);
|
|
summon.CastSpell(summon, SPELL_OOZE_ERUPTION_SEARCH_PERIODIC, true);
|
|
summon.ApplySpellImmune(0, SpellImmunity.Effect, SpellEffectName.KnockBack, true);
|
|
summon.SetReactState(ReactStates.Passive);
|
|
break;
|
|
case NPC_CHOKING_GAS_BOMB:
|
|
summon.CastSpell(summon, SPELL_CHOKING_GAS_BOMB_PERIODIC, true);
|
|
summon.CastSpell(summon, SPELL_CHOKING_GAS_EXPLOSION_TRIGGER, true);
|
|
return;
|
|
case NPC_MUTATED_ABOMINATION_10:
|
|
case NPC_MUTATED_ABOMINATION_25:
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (me.IsInCombat())
|
|
DoZoneInCombat(summon);
|
|
}
|
|
|
|
public override void DamageTaken(Unit attacker, ref uint damage)
|
|
{
|
|
switch (_phase)
|
|
{
|
|
case Phases.Combat1:
|
|
if (HealthAbovePct(80))
|
|
return;
|
|
me.SetReactState(ReactStates.Passive);
|
|
DoAction(SharedActions.ChangePhase);
|
|
break;
|
|
case Phases.Combat2:
|
|
if (HealthAbovePct(35))
|
|
return;
|
|
me.SetReactState(ReactStates.Passive);
|
|
DoAction(SharedActions.ChangePhase);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override void MovementInform(MovementGeneratorType type, uint id)
|
|
{
|
|
if (type != MovementGeneratorType.Point)
|
|
return;
|
|
switch (id)
|
|
{
|
|
case POINT_FESTERGUT:
|
|
instance.SetBossState(DataTypes.Festergut, EncounterState.InProgress); // needed here for delayed gate close
|
|
me.SetSpeed(UnitMoveType.Run, _baseSpeed, true);
|
|
DoAction(SharedActions.FestergutGas);
|
|
Creature festergut = ObjectAccessor.GetCreature(me, instance.GetGuidData(DataTypes.Festergut));
|
|
if (festergut)
|
|
festergut.CastSpell(festergut, SPELL_GASEOUS_BLIGHT_LARGE, false, null, null, festergut.GetGUID());
|
|
break;
|
|
case POINT_ROTFACE:
|
|
instance.SetBossState(DATA_ROTFACE, EncounterState.InProgress); // needed here for delayed gate close
|
|
me.SetSpeed(UnitMoveType.Run, _baseSpeed, true);
|
|
DoAction(SharedActions.RotfaceOoze);
|
|
_events.ScheduleEvent(EVENT_ROTFACE_OOZE_FLOOD, 25000, 0, Phases.Rotface);
|
|
break;
|
|
case POINT_TABLE:
|
|
// stop attack
|
|
me.GetMotionMaster().MoveIdle();
|
|
me.SetSpeed(UnitMoveType.Run, _baseSpeed, true);
|
|
GameObject table = ObjectAccessor.GetGameObject(me, instance.GetGuidData(DataTypes.PutricideTable));
|
|
if (table)
|
|
me.SetFacingToObject(table);
|
|
// operating on new phase already
|
|
switch (_phase)
|
|
{
|
|
case Phases.Combat2:
|
|
{
|
|
SpellInfo spell = Global.SpellMgr.GetSpellInfo(SPELL_CREATE_CONCOCTION);
|
|
DoCast(me, SPELL_CREATE_CONCOCTION);
|
|
_events.ScheduleEvent(EVENT_PHASE_TRANSITION, spell.CalcCastTime() + 100);
|
|
break;
|
|
}
|
|
case Phases.Combat3:
|
|
{
|
|
SpellInfo spell = Global.SpellMgr.GetSpellInfo(SPELL_GUZZLE_POTIONS);
|
|
DoCast(me, SPELL_GUZZLE_POTIONS);
|
|
_events.ScheduleEvent(EVENT_PHASE_TRANSITION, spell.CalcCastTime() + 100);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override void DoAction(int action)
|
|
{
|
|
switch (action)
|
|
{
|
|
case SharedActions.FestergutCombat:
|
|
SetPhase(Phases.Festergut);
|
|
me.SetSpeed(UnitMoveType.Run, _baseSpeed * 2.0f, true);
|
|
me.GetMotionMaster().MovePoint(POINT_FESTERGUT, ProfessorPutricideConst.festergutWatchPos);
|
|
me.SetReactState(ReactStates.Passive);
|
|
DoZoneInCombat(me);
|
|
if (IsHeroic())
|
|
_events.ScheduleEvent(EVENT_FESTERGUT_GOO, RandomHelper.URand(13000, 18000), 0, Phases.Festergut);
|
|
break;
|
|
case SharedActions.FestergutGas:
|
|
Talk(SAY_FESTERGUT_GASEOUS_BLIGHT);
|
|
DoCast(me, SPELL_RELEASE_GAS_VISUAL, true);
|
|
break;
|
|
case SharedActions.FestergutDeath:
|
|
_events.ScheduleEvent(EVENT_FESTERGUT_DIES, 4000, 0, Phases.Festergut);
|
|
break;
|
|
case SharedActions.RotfaceCombat:
|
|
{
|
|
SetPhase(Phases.Rotface);
|
|
me.SetSpeed(UnitMoveType.Run, _baseSpeed * 2.0f, true);
|
|
me.GetMotionMaster().MovePoint(POINT_ROTFACE, rotfaceWatchPos);
|
|
me.SetReactState(ReactStates.Passive);
|
|
_oozeFloodStage = 0;
|
|
DoZoneInCombat(me);
|
|
// init random sequence of floods
|
|
Creature rotface = ObjectAccessor.GetCreature(me, instance.GetGuidData(DATA_ROTFACE));
|
|
if (rotface)
|
|
{
|
|
List<Creature> list = new List<Creature>();
|
|
rotface.GetCreatureListWithEntryInGrid(list, NPC_PUDDLE_STALKER, 50.0f);
|
|
list.RemoveAll(new RotfaceHeightCheck(rotface).Invoke);
|
|
if (list.Count() > 4)
|
|
{
|
|
list.Sort(new ObjectDistanceOrderPred(rotface));
|
|
list.RemoveRange(4, list.Count - 1);
|
|
}
|
|
|
|
byte i = 0;
|
|
while (!list.Empty())
|
|
{
|
|
var itr = list[RandomHelper.IRand(0, list.Count - 1)];
|
|
_oozeFloodDummyGUIDs[i++] = itr.GetGUID();
|
|
list.Remove(itr);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SharedActions.RotfaceOoze:
|
|
Talk(SAY_ROTFACE_OOZE_FLOOD);
|
|
Creature dummy = ObjectAccessor.GetCreature(me, _oozeFloodDummyGUIDs[_oozeFloodStage]);
|
|
if (dummy)
|
|
dummy.CastSpell(dummy, oozeFloodSpells[_oozeFloodStage], true, null, null, me.GetGUID()); // cast from self for LoS (with prof's GUID for logs)
|
|
if (++_oozeFloodStage == 4)
|
|
_oozeFloodStage = 0;
|
|
break;
|
|
case SharedActions.RotfaceDeath:
|
|
_events.ScheduleEvent(EVENT_ROTFACE_DIES, 4500, 0, Phases.Rotface);
|
|
break;
|
|
case SharedActions.ChangePhase:
|
|
me.SetSpeed(UnitMoveType.Run, _baseSpeed * 2.0f, true);
|
|
_events.DelayEvents(30000);
|
|
me.AttackStop();
|
|
if (!IsHeroic())
|
|
{
|
|
DoCast(me, SPELL_TEAR_GAS);
|
|
_events.ScheduleEvent(EVENT_TEAR_GAS, 2500);
|
|
}
|
|
else
|
|
{
|
|
Talk(SAY_PHASE_TRANSITION_HEROIC);
|
|
DoCast(me, SPELL_UNSTABLE_EXPERIMENT, true);
|
|
DoCast(me, SPELL_UNSTABLE_EXPERIMENT, true);
|
|
// cast variables
|
|
if (Is25ManRaid())
|
|
{
|
|
List<Unit> targetList = new List<Unit>();
|
|
{
|
|
var threatlist = me.GetThreatManager().getThreatList();
|
|
foreach (var itr in threatlist)
|
|
if (itr.getTarget().IsPlayer())
|
|
targetList.Add(itr.getTarget());
|
|
}
|
|
|
|
int half = targetList.Count / 2;
|
|
// half gets ooze variable
|
|
while (half < targetList.Count)
|
|
{
|
|
var itr = targetList[RandomHelper.IRand(0, targetList.Count - 1)];
|
|
itr.CastSpell(itr, SPELL_OOZE_VARIABLE, true);
|
|
targetList.Remove(itr);
|
|
}
|
|
// and half gets gas
|
|
foreach (var itr in targetList)
|
|
itr.CastSpell(itr, SPELL_GAS_VARIABLE, true);
|
|
}
|
|
me.GetMotionMaster().MovePoint(POINT_TABLE, ProfessorPutricideConst.tablePos);
|
|
}
|
|
switch (_phase)
|
|
{
|
|
case Phases.Combat1:
|
|
SetPhase(Phases.Combat2);
|
|
_events.ScheduleEvent(EVENT_MALLEABLE_GOO, RandomHelper.URand(21000, 26000));
|
|
_events.ScheduleEvent(EVENT_CHOKING_GAS_BOMB, RandomHelper.URand(35000, 40000));
|
|
break;
|
|
case Phases.Combat2:
|
|
SetPhase(Phases.Combat3);
|
|
_events.ScheduleEvent(EVENT_MUTATED_PLAGUE, 25000);
|
|
_events.CancelEvent(EVENT_UNSTABLE_EXPERIMENT);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override uint GetData(uint type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case DataExperimentStage:
|
|
return _experimentState ? 1 : 0u;
|
|
case DataPhase:
|
|
return (uint)_phase;
|
|
case DataAbomination:
|
|
return (summons.HasEntry(NPC_MUTATED_ABOMINATION_10) || summons.HasEntry(NPC_MUTATED_ABOMINATION_25)) ? 1 : 0u;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public override void SetData(uint id, uint data)
|
|
{
|
|
if (id == DataExperimentStage)
|
|
_experimentState = data != 0;
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if ((!(_events.IsInPhase((byte)Phases.Rotface) || _events.IsInPhase((byte)Phases.Festergut)) && !UpdateVictim()) || !CheckInRoom())
|
|
return;
|
|
|
|
_events.Update(diff);
|
|
|
|
if (me.HasUnitState(UnitState.Casting))
|
|
return;
|
|
_events.ExecuteEvents(eventId =>
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_FESTERGUT_DIES:
|
|
Talk(SAY_FESTERGUT_DEATH);
|
|
EnterEvadeMode();
|
|
break;
|
|
case EVENT_FESTERGUT_GOO:
|
|
me.CastCustomSpell(SPELL_MALLEABLE_GOO_SUMMON, SpellValueMod.MaxTargets, 1, null, true);
|
|
_events.ScheduleEvent(EVENT_FESTERGUT_GOO, (Is25ManRaid() ? 10000 : 30000) + RandomHelper.URand(0, 5000), 0, Phases.Festergut);
|
|
break;
|
|
case EVENT_ROTFACE_DIES:
|
|
Talk(SAY_ROTFACE_DEATH);
|
|
EnterEvadeMode();
|
|
break;
|
|
case EVENT_ROTFACE_OOZE_FLOOD:
|
|
DoAction(SharedActions.RotfaceOoze);
|
|
_events.ScheduleEvent(EVENT_ROTFACE_OOZE_FLOOD, 25000, 0, Phases.Rotface);
|
|
break;
|
|
case EVENT_BERSERK:
|
|
Talk(SAY_BERSERK);
|
|
DoCast(me, SPELL_BERSERK2);
|
|
break;
|
|
case EVENT_SLIME_PUDDLE:
|
|
{
|
|
List<Unit> targets = SelectTargetList(2, SelectAggroTarget.Random, 0.0f, true);
|
|
if (!targets.Empty())
|
|
{
|
|
foreach (var itr in targets)
|
|
DoCast(itr, SPELL_SLIME_PUDDLE_TRIGGER);
|
|
}
|
|
_events.ScheduleEvent(EVENT_SLIME_PUDDLE, 35000);
|
|
break;
|
|
}
|
|
case EVENT_UNSTABLE_EXPERIMENT:
|
|
Talk(EMOTE_UNSTABLE_EXPERIMENT);
|
|
DoCast(me, SPELL_UNSTABLE_EXPERIMENT);
|
|
_events.ScheduleEvent(EVENT_UNSTABLE_EXPERIMENT, RandomHelper.URand(35000, 40000));
|
|
break;
|
|
case EVENT_TEAR_GAS:
|
|
me.GetMotionMaster().MovePoint(POINT_TABLE, ProfessorPutricideConst.tablePos);
|
|
DoCast(me, SPELL_TEAR_GAS_PERIODIC_TRIGGER, true);
|
|
break;
|
|
case EVENT_RESUME_ATTACK:
|
|
me.SetReactState(ReactStates.Defensive);
|
|
AttackStart(me.GetVictim());
|
|
// remove Tear Gas
|
|
me.RemoveAurasDueToSpell(SPELL_TEAR_GAS_PERIODIC_TRIGGER);
|
|
instance.DoRemoveAurasDueToSpellOnPlayers(71615);
|
|
DoCastAOE(SPELL_TEAR_GAS_CANCEL);
|
|
instance.DoRemoveAurasDueToSpellOnPlayers(SPELL_GAS_VARIABLE);
|
|
instance.DoRemoveAurasDueToSpellOnPlayers(SPELL_OOZE_VARIABLE);
|
|
break;
|
|
case EVENT_MALLEABLE_GOO:
|
|
if (Is25ManRaid())
|
|
{
|
|
List<Unit> targets = SelectTargetList(2, SelectAggroTarget.Random, -7.0f, true);
|
|
if (!targets.Empty())
|
|
{
|
|
Talk(EMOTE_MALLEABLE_GOO);
|
|
foreach (var itr in targets)
|
|
DoCast(itr, SPELL_MALLEABLE_GOO);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Unit target = SelectTarget(SelectAggroTarget.Random, 1, -7.0f, true);
|
|
if (target)
|
|
{
|
|
Talk(EMOTE_MALLEABLE_GOO);
|
|
DoCast(target, SPELL_MALLEABLE_GOO);
|
|
}
|
|
}
|
|
_events.ScheduleEvent(EVENT_MALLEABLE_GOO, RandomHelper.URand(25000, 30000));
|
|
break;
|
|
case EVENT_CHOKING_GAS_BOMB:
|
|
Talk(EMOTE_CHOKING_GAS_BOMB);
|
|
DoCast(me, SPELL_CHOKING_GAS_BOMB);
|
|
_events.ScheduleEvent(EVENT_CHOKING_GAS_BOMB, RandomHelper.URand(35000, 40000));
|
|
break;
|
|
case EVENT_UNBOUND_PLAGUE:
|
|
{
|
|
Unit target = SelectTarget(SelectAggroTarget.Random, 0, new NonTankTargetSelector(me));
|
|
if (target)
|
|
{
|
|
DoCast(target, SPELL_UNBOUND_PLAGUE);
|
|
DoCast(target, SPELL_UNBOUND_PLAGUE_SEARCHER);
|
|
}
|
|
_events.ScheduleEvent(EVENT_UNBOUND_PLAGUE, 90000);
|
|
}
|
|
break;
|
|
case EVENT_MUTATED_PLAGUE:
|
|
DoCastVictim(SPELL_MUTATED_PLAGUE);
|
|
_events.ScheduleEvent(EVENT_MUTATED_PLAGUE, 10000);
|
|
break;
|
|
case EVENT_PHASE_TRANSITION:
|
|
{
|
|
switch (_phase)
|
|
{
|
|
case Phases.Combat2:
|
|
{
|
|
Creature face = me.FindNearestCreature(NPC_TEAR_GAS_TARGET_STALKER, 50.0f);
|
|
if (face)
|
|
me.SetFacingToObject(face);
|
|
me.HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
|
|
Talk(SAY_TRANSFORM_1);
|
|
_events.ScheduleEvent(EVENT_RESUME_ATTACK, 5500, 0, Phases.Combat2);
|
|
}
|
|
break;
|
|
case Phases.Combat3:
|
|
{ Creature face = me.FindNearestCreature(NPC_TEAR_GAS_TARGET_STALKER, 50.0f);
|
|
if (face)
|
|
me.SetFacingToObject(face);
|
|
me.HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
|
|
Talk(SAY_TRANSFORM_2);
|
|
summons.DespawnIf(new AbominationDespawner(me).Invoke);
|
|
_events.ScheduleEvent(EVENT_RESUME_ATTACK, 8500, 0, Phases.Combat3);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
|
|
void SetPhase(Phases newPhase)
|
|
{
|
|
_phase = newPhase;
|
|
_events.SetPhase((byte)newPhase);
|
|
}
|
|
|
|
ObjectGuid[] _oozeFloodDummyGUIDs = new ObjectGuid[4];
|
|
Phases _phase; // external of EventMap because event phase gets reset on evade
|
|
float _baseSpeed;
|
|
byte _oozeFloodStage;
|
|
bool _experimentState;
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return GetIcecrownCitadelAI<boss_professor_putricideAI>(creature);
|
|
}
|
|
}
|
|
|
|
class npc_putricide_oozeAI : ScriptedAI
|
|
{
|
|
public npc_putricide_oozeAI(Creature creature, uint hitTargetSpellId) : base(creature)
|
|
{
|
|
_hitTargetSpellId = hitTargetSpellId;
|
|
_newTargetSelectTimer = 0;
|
|
|
|
}
|
|
|
|
public override void SpellHitTarget(Unit target, SpellInfo spell)
|
|
{
|
|
if (_newTargetSelectTimer == 0 && spell.Id == _hitTargetSpellId)
|
|
_newTargetSelectTimer = 1000;
|
|
}
|
|
|
|
public override void SpellHit(Unit caster, SpellInfo spell)
|
|
{
|
|
if (spell.Id == SPELL_TEAR_GAS_CREATURE)
|
|
_newTargetSelectTimer = 1000;
|
|
}
|
|
|
|
public override void UpdateAI(uint diff)
|
|
{
|
|
if (!UpdateVictim() && _newTargetSelectTimer == 0)
|
|
return;
|
|
|
|
if (_newTargetSelectTimer == 0 && !me.IsNonMeleeSpellCast(false, false, true, false, true))
|
|
_newTargetSelectTimer = 1000;
|
|
|
|
DoMeleeAttackIfReady();
|
|
|
|
if (_newTargetSelectTimer == 0)
|
|
return;
|
|
|
|
if (me.HasAura(SPELL_TEAR_GAS_CREATURE))
|
|
return;
|
|
|
|
if (_newTargetSelectTimer <= diff)
|
|
{
|
|
_newTargetSelectTimer = 0;
|
|
CastMainSpell();
|
|
}
|
|
else
|
|
_newTargetSelectTimer -= diff;
|
|
}
|
|
|
|
public virtual void CastMainSpell() { }
|
|
|
|
uint _hitTargetSpellId;
|
|
uint _newTargetSelectTimer;
|
|
}
|
|
|
|
class npc_volatile_ooze : CreatureScript
|
|
{
|
|
public npc_volatile_ooze() : base("npc_volatile_ooze") { }
|
|
|
|
class npc_volatile_oozeAI : npc_putricide_oozeAI
|
|
{
|
|
public npc_volatile_oozeAI(Creature creature) : base(creature, SPELL_OOZE_ERUPTION)
|
|
{
|
|
}
|
|
|
|
public override void CastMainSpell()
|
|
{
|
|
me.CastSpell(me, ProfessorPutricideConst.SpellVolatileOozeAdhesive, false);
|
|
}
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return GetIcecrownCitadelAI<npc_volatile_oozeAI>(creature);
|
|
}
|
|
}
|
|
|
|
class npc_gas_cloud : CreatureScript
|
|
{
|
|
public npc_gas_cloud() : base("npc_gas_cloud") { }
|
|
|
|
class npc_gas_cloudAI : npc_putricide_oozeAI
|
|
{
|
|
public npc_gas_cloudAI(Creature creature) : base(creature, SPELL_EXPUNGED_GAS)
|
|
{
|
|
_newTargetSelectTimer = 0;
|
|
}
|
|
|
|
public override void CastMainSpell()
|
|
{
|
|
me.CastCustomSpell(SPELL_GASEOUS_BLOAT, SpellValueMod.AuraStack, 10, me, false);
|
|
}
|
|
|
|
uint _newTargetSelectTimer;
|
|
}
|
|
|
|
public override CreatureAI GetAI(Creature creature)
|
|
{
|
|
return GetIcecrownCitadelAI<npc_gas_cloudAI>(creature);
|
|
}
|
|
}
|
|
|
|
class spell_putricide_gaseous_bloat : SpellScriptLoader
|
|
{
|
|
public spell_putricide_gaseous_bloat() : base("spell_putricide_gaseous_bloat") { }
|
|
|
|
class spell_putricide_gaseous_bloat_AuraScript : AuraScript
|
|
{
|
|
void HandleExtraEffect(AuraEffect aurEff)
|
|
{
|
|
Unit target = GetTarget();
|
|
Unit caster = GetCaster();
|
|
if (caster)
|
|
{
|
|
target.RemoveAuraFromStack(GetSpellInfo().Id, GetCasterGUID());
|
|
if (!target.HasAura(GetId()))
|
|
caster.CastCustomSpell(SPELL_GASEOUS_BLOAT, SpellValueMod.AuraStack, 10, caster, false);
|
|
}
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectPeriodic.Add(new EffectPeriodicHandler(HandleExtraEffect, 0, SPELL_AURA_PERIODIC_DAMAGE));
|
|
}
|
|
}
|
|
|
|
public override AuraScript GetAuraScript()
|
|
{
|
|
return new spell_putricide_gaseous_bloat_AuraScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_ooze_channel : SpellScriptLoader
|
|
{
|
|
public spell_putricide_ooze_channel() : base("spell_putricide_ooze_channel") { }
|
|
|
|
class spell_putricide_ooze_channel_SpellScript : SpellScript
|
|
{
|
|
public spell_putricide_ooze_channel_SpellScript()
|
|
{
|
|
_target = null;
|
|
}
|
|
|
|
public override bool Validate(SpellInfo spell)
|
|
{
|
|
if (spell.ExcludeTargetAuraSpell == 0)
|
|
return false;
|
|
if (!Global.SpellMgr.HasSpellInfo(spell.ExcludeTargetAuraSpell))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// set up initial variables and check if caster is creature
|
|
// this will let use safely use ToCreature() casts in entire script
|
|
public override bool Load()
|
|
{
|
|
return GetCaster().IsTypeId(TypeId.Unit);
|
|
}
|
|
|
|
void SelectTarget(List<WorldObject> targets)
|
|
{
|
|
if (targets.Empty())
|
|
{
|
|
FinishCast(SpellCastResult.NoValidTargets);
|
|
GetCaster().ToCreature().DespawnOrUnsummon(1); // despawn next update
|
|
return;
|
|
}
|
|
|
|
WorldObject target = targets.PickRandom();
|
|
targets.Clear();
|
|
targets.Add(target);
|
|
_target = target;
|
|
}
|
|
|
|
void SetTarget(List<WorldObject> targets)
|
|
{
|
|
targets.Clear();
|
|
if (_target)
|
|
targets.Add(_target);
|
|
}
|
|
|
|
void StartAttack()
|
|
{
|
|
GetCaster().ClearUnitState(UnitState.Casting);
|
|
GetCaster().DeleteThreatList();
|
|
GetCaster().ToCreature().GetAI().AttackStart(GetHitUnit());
|
|
GetCaster().AddThreat(GetHitUnit(), 500000000.0f); // value seen in sniff
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(SelectTarget, 0, Targets.UnitSrcAreaEnemy));
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(SetTarget, 1, Targets.UnitSrcAreaEnemy));
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(SetTarget, 2, Targets.UnitSrcAreaEnemy));
|
|
AfterHit.Add(new HitHandler(StartAttack));
|
|
}
|
|
|
|
WorldObject _target;
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_ooze_channel_SpellScript();
|
|
}
|
|
}
|
|
|
|
class ExactDistanceCheck
|
|
{
|
|
public ExactDistanceCheck(Unit source, float dist)
|
|
{
|
|
_source = source;
|
|
_dist = dist;
|
|
}
|
|
|
|
public bool Invoke(WorldObject unit)
|
|
{
|
|
return _source.GetExactDist2d(unit) > _dist;
|
|
}
|
|
|
|
Unit _source;
|
|
float _dist;
|
|
}
|
|
|
|
class spell_putricide_slime_puddle : SpellScriptLoader
|
|
{
|
|
public spell_putricide_slime_puddle() : base("spell_putricide_slime_puddle") { }
|
|
|
|
class spell_putricide_slime_puddle_SpellScript : SpellScript
|
|
{
|
|
void ScaleRange(List<WorldObject> targets)
|
|
{
|
|
targets.RemoveAll(new ExactDistanceCheck(GetCaster(), 2.5f * GetCaster().GetObjectScale()).Invoke);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(ScaleRange, 0, Targets.UnitDestAreaEntry));
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(ScaleRange, 1, Targets.UnitDestAreaEntry));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_slime_puddle_SpellScript();
|
|
}
|
|
}
|
|
|
|
// this is here only because on retail you dont actually enter HEROIC mode for ICC
|
|
class spell_putricide_slime_puddle_aura : SpellScriptLoader
|
|
{
|
|
public spell_putricide_slime_puddle_aura() : base("spell_putricide_slime_puddle_aura") { }
|
|
|
|
class spell_putricide_slime_puddle_aura_SpellScript : SpellScript
|
|
{
|
|
void ReplaceAura()
|
|
{
|
|
Unit target = GetHitUnit();
|
|
if (target)
|
|
GetCaster().AddAura(Convert.ToBoolean((int)GetCaster().GetMap().GetSpawnMode() & 1) ? 72456 : 70346u, target);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnHit.Add(new HitHandler(ReplaceAura));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_slime_puddle_aura_SpellScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_unstable_experiment : SpellScriptLoader
|
|
{
|
|
public spell_putricide_unstable_experiment() : base("spell_putricide_unstable_experiment") { }
|
|
|
|
class spell_putricide_unstable_experiment_SpellScript : SpellScript
|
|
{
|
|
void HandleScript(uint effIndex)
|
|
{
|
|
PreventHitDefaultEffect(effIndex);
|
|
if (!GetCaster().IsTypeId(TypeId.Unit))
|
|
return;
|
|
|
|
Creature creature = GetCaster().ToCreature();
|
|
|
|
uint stage = creature.GetAI().GetData(DataExperimentStage);
|
|
creature.GetAI().SetData(DataExperimentStage, stage ^ 1);
|
|
|
|
Creature target = null;
|
|
List<Creature> creList = new List<Creature>();
|
|
GetCaster().GetCreatureListWithEntryInGrid(creList, NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 200.0f);
|
|
// 2 of them are spawned at green place - weird trick blizz
|
|
foreach (var itr in creList)
|
|
{
|
|
target = itr;
|
|
List<Creature> tmp = new List<Creature>();
|
|
target.GetCreatureListWithEntryInGrid(tmp, NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 10.0f);
|
|
if ((stage == 0 && tmp.Count > 1) || (stage != 0 && tmp.Count == 1))
|
|
break;
|
|
}
|
|
|
|
GetCaster().CastSpell(target, (uint)GetSpellInfo().GetEffect(stage).CalcValue(), true, null, null, GetCaster().GetGUID());
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_unstable_experiment_SpellScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_ooze_eruption_searcher : SpellScriptLoader
|
|
{
|
|
public spell_putricide_ooze_eruption_searcher() : base("spell_putricide_ooze_eruption_searcher") { }
|
|
|
|
class spell_putricide_ooze_eruption_searcher_SpellScript : SpellScript
|
|
{
|
|
void HandleDummy(uint effIndex)
|
|
{
|
|
if (GetHitUnit().HasAura(SPELL_VOLATILE_OOZE_ADHESIVE))
|
|
{
|
|
GetHitUnit().RemoveAurasDueToSpell(SPELL_VOLATILE_OOZE_ADHESIVE, GetCaster().GetGUID(), 0, AuraRemoveMode.EnemySpell);
|
|
GetCaster().CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true);
|
|
}
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleDummy, 0, SpellEffectName.Dummy));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_ooze_eruption_searcher_SpellScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_choking_gas_bomb : SpellScriptLoader
|
|
{
|
|
public spell_putricide_choking_gas_bomb() : base("spell_putricide_choking_gas_bomb") { }
|
|
|
|
class spell_putricide_choking_gas_bomb_SpellScript : SpellScript
|
|
{
|
|
void HandleScript(uint effIndex)
|
|
{
|
|
uint skipIndex = RandomHelper.URand(0, 2);
|
|
foreach (SpellEffectInfo effect in GetSpellInfo().GetEffectsForDifficulty(GetCaster().GetMap().GetDifficultyID()))
|
|
{
|
|
if (effect == null || effect.EffectIndex == skipIndex)
|
|
continue;
|
|
|
|
uint spellId = (uint)effect.CalcValue();
|
|
GetCaster().CastSpell(GetCaster(), spellId, true, null, null, GetCaster().GetGUID());
|
|
}
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_choking_gas_bomb_SpellScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_unbound_plague : SpellScriptLoader
|
|
{
|
|
public spell_putricide_unbound_plague() : base("spell_putricide_unbound_plague") { }
|
|
|
|
class spell_putricide_unbound_plague_SpellScript : SpellScript
|
|
{
|
|
public override bool Validate(SpellInfo spell)
|
|
{
|
|
if (!Global.SpellMgr.GetSpellInfo(SPELL_UNBOUND_PLAGUE))
|
|
return false;
|
|
if (!Global.SpellMgr.GetSpellInfo(SPELL_UNBOUND_PLAGUE_SEARCHER))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void FilterTargets(List<WorldObject> targets)
|
|
{
|
|
AuraEffect eff = GetCaster().GetAuraEffect(SPELL_UNBOUND_PLAGUE_SEARCHER, 0);
|
|
if (eff != null)
|
|
{
|
|
if (eff.GetTickNumber() < 2)
|
|
{
|
|
targets.Clear();
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
targets.RemoveAll(new UnitAuraCheck<WorldObject>(true, SPELL_UNBOUND_PLAGUE));
|
|
targets.RandomResize(1);
|
|
}
|
|
|
|
void HandleScript(uint effIndex)
|
|
{
|
|
if (!GetHitUnit())
|
|
return;
|
|
|
|
InstanceScript instance = GetCaster().GetInstanceScript();
|
|
if (instance == null)
|
|
return;
|
|
|
|
if (!GetHitUnit().HasAura(SPELL_UNBOUND_PLAGUE))
|
|
{
|
|
Creature professor = ObjectAccessor.GetCreature(GetCaster(), instance.GetGuidData(DataTypes.ProfessorPutricide));
|
|
if (professor)
|
|
{
|
|
Aura oldPlague = GetCaster().GetAura(SPELL_UNBOUND_PLAGUE, professor.GetGUID());
|
|
if (oldPlague != null)
|
|
{
|
|
Aura newPlague = professor.AddAura(SPELL_UNBOUND_PLAGUE, GetHitUnit());
|
|
if (newPlague != null)
|
|
{
|
|
newPlague.SetMaxDuration(oldPlague.GetMaxDuration());
|
|
newPlague.SetDuration(oldPlague.GetDuration());
|
|
oldPlague.Remove();
|
|
GetCaster().RemoveAurasDueToSpell(SPELL_UNBOUND_PLAGUE_SEARCHER);
|
|
GetCaster().CastSpell(GetCaster(), SPELL_PLAGUE_SICKNESS, true);
|
|
GetCaster().CastSpell(GetCaster(), SPELL_UNBOUND_PLAGUE_PROTECTION, true);
|
|
professor.CastSpell(GetHitUnit(), SPELL_UNBOUND_PLAGUE_SEARCHER, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargets, 0, Targets.UnitSrcAreaAlly));
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_unbound_plague_SpellScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_eat_ooze : SpellScriptLoader
|
|
{
|
|
public spell_putricide_eat_ooze() : base("spell_putricide_eat_ooze") { }
|
|
|
|
class spell_putricide_eat_ooze_SpellScript : SpellScript
|
|
{
|
|
void SelectTarget(List<WorldObject> targets)
|
|
{
|
|
if (targets.Empty())
|
|
return;
|
|
|
|
targets.Sort(new ObjectDistanceOrderPred(GetCaster()));
|
|
WorldObject target = targets[0];
|
|
targets.Clear();
|
|
targets.Add(target);
|
|
}
|
|
|
|
void HandleScript(uint effIndex)
|
|
{
|
|
Creature target = GetHitCreature();
|
|
if (!target)
|
|
return;
|
|
|
|
Aura grow = target.GetAura((uint)GetEffectValue());
|
|
if (grow != null)
|
|
{
|
|
if (grow.GetStackAmount() < 3)
|
|
{
|
|
target.RemoveAurasDueToSpell(SPELL_GROW_STACKER);
|
|
target.RemoveAura(grow);
|
|
target.DespawnOrUnsummon(1);
|
|
}
|
|
else
|
|
grow.ModStackAmount(-3);
|
|
}
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(SelectTarget, 0, Targets.UnitDestAreaEntry));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_eat_ooze_SpellScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_mutated_plague : SpellScriptLoader
|
|
{
|
|
public spell_putricide_mutated_plague() : base("spell_putricide_mutated_plague") { }
|
|
|
|
class spell_putricide_mutated_plague_AuraScript : AuraScript
|
|
{
|
|
void HandleTriggerSpell(AuraEffect aurEff)
|
|
{
|
|
PreventDefaultAction();
|
|
Unit caster = GetCaster();
|
|
if (!caster)
|
|
return;
|
|
|
|
uint triggerSpell = GetSpellInfo().GetEffect(aurEff.GetEffIndex()).TriggerSpell;
|
|
SpellInfo spell = Global.SpellMgr.GetSpellInfo(triggerSpell);
|
|
|
|
int damage = spell.GetEffect(0).CalcValue(caster);
|
|
float multiplier = 2.0f;
|
|
if (Convert.ToBoolean((int)GetTarget().GetMap().GetSpawnMode() & 1))
|
|
multiplier = 3.0f;
|
|
|
|
damage *= (int)Math.Pow(multiplier, GetStackAmount());
|
|
damage = (int)(damage * 1.5f);
|
|
|
|
GetTarget().CastCustomSpell(triggerSpell, SpellValueMod.BasePoint0, damage, GetTarget(), true, null, aurEff, GetCasterGUID());
|
|
}
|
|
|
|
void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
|
|
{
|
|
uint healSpell = (uint)GetSpellInfo().GetEffect(0).CalcValue();
|
|
SpellInfo healSpellInfo = Global.SpellMgr.GetSpellInfo(healSpell);
|
|
|
|
if (healSpellInfo == null)
|
|
return;
|
|
|
|
int heal = healSpellInfo.GetEffect(0).CalcValue() * GetStackAmount();
|
|
GetTarget().CastCustomSpell(healSpell, SpellValueMod.BasePoint0, heal, GetTarget(), true, null, null, GetCasterGUID());
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectPeriodic.Add(new EffectPeriodicHandler(HandleTriggerSpell, 0, SPELL_AURA_PERIODIC_TRIGGER_SPELL));
|
|
AfterEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AuraEffectHandleModes.Real));
|
|
}
|
|
}
|
|
|
|
public override AuraScript GetAuraScript()
|
|
{
|
|
return new spell_putricide_mutated_plague_AuraScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_mutation_init : SpellScriptLoader
|
|
{
|
|
public spell_putricide_mutation_init() : base("spell_putricide_mutation_init") { }
|
|
|
|
class spell_putricide_mutation_init_SpellScript : SpellScript
|
|
{
|
|
SpellCastResult CheckRequirementInternal(SpellCustomErrors extendedError)
|
|
{
|
|
InstanceScript instance = GetExplTargetUnit().GetInstanceScript();
|
|
if (instance == null)
|
|
return SpellCastResult.CantDoThatRightNow;
|
|
|
|
Creature professor = ObjectAccessor.GetCreature(GetExplTargetUnit(), instance.GetGuidData(DataTypes.ProfessorPutricide));
|
|
if (!professor)
|
|
return SpellCastResult.CantDoThatRightNow;
|
|
|
|
if (professor.GetAI().GetData(DataPhase) == (uint)Phases.Combat3 || !professor.IsAlive())
|
|
{
|
|
extendedError = SpellCustomErrors.AllPotionsUsed;
|
|
return SpellCastResult.CustomError;
|
|
}
|
|
|
|
if (professor.GetAI().GetData(DataAbomination) != 0)
|
|
{
|
|
extendedError = SpellCustomErrors.TooManyAbominations;
|
|
return SpellCastResult.CustomError;
|
|
}
|
|
|
|
return SpellCastResult.SpellCastOk;
|
|
}
|
|
|
|
SpellCastResult CheckRequirement()
|
|
{
|
|
if (!GetExplTargetUnit())
|
|
return SpellCastResult.BadTargets;
|
|
|
|
if (!GetExplTargetUnit().IsPlayer())
|
|
return SpellCastResult.TargetNotPlayer;
|
|
|
|
SpellCustomErrors extension = SpellCustomErrors.None;
|
|
SpellCastResult result = CheckRequirementInternal(extension);
|
|
if (result != SpellCastResult.SpellCastOk)
|
|
{
|
|
Spell.SendCastResult(GetExplTargetUnit().ToPlayer(), GetSpellInfo(), 0, result, extension);
|
|
return result;
|
|
}
|
|
|
|
return SpellCastResult.SpellCastOk;
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnCheckCast.Add(new CheckCastHandler(CheckRequirement));
|
|
}
|
|
}
|
|
|
|
class spell_putricide_mutation_init_AuraScript : AuraScript
|
|
{
|
|
void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
|
|
{
|
|
uint spellId = 70311;
|
|
if (Convert.ToBoolean((int)GetTarget().GetMap().GetSpawnMode() & 1))
|
|
spellId = 71503;
|
|
|
|
GetTarget().CastSpell(GetTarget(), spellId, true);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
AfterEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, SPELL_AURA_DUMMY, AuraEffectHandleModes.Real));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_mutation_init_SpellScript();
|
|
}
|
|
|
|
public override AuraScript GetAuraScript()
|
|
{
|
|
return new spell_putricide_mutation_init_AuraScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_mutated_transformation_dismiss : SpellScriptLoader
|
|
{
|
|
public spell_putricide_mutated_transformation_dismiss() : base("spell_putricide_mutated_transformation_dismiss") { }
|
|
|
|
class spell_putricide_mutated_transformation_dismiss_AuraScript : AuraScript
|
|
{
|
|
void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
|
|
{
|
|
Vehicle veh = GetTarget().GetVehicleKit();
|
|
if (veh)
|
|
veh.RemoveAllPassengers();
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
AfterEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AuraEffectHandleModes.Real));
|
|
}
|
|
}
|
|
|
|
public override AuraScript GetAuraScript()
|
|
{
|
|
return new spell_putricide_mutated_transformation_dismiss_AuraScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_mutated_transformation : SpellScriptLoader
|
|
{
|
|
public spell_putricide_mutated_transformation() : base("spell_putricide_mutated_transformation") { }
|
|
|
|
class spell_putricide_mutated_transformation_SpellScript : SpellScript
|
|
{
|
|
void HandleSummon(uint effIndex)
|
|
{
|
|
PreventHitDefaultEffect(effIndex);
|
|
Unit caster = GetOriginalCaster();
|
|
if (!caster)
|
|
return;
|
|
|
|
InstanceScript instance = caster.GetInstanceScript();
|
|
if (instance == null)
|
|
return;
|
|
|
|
Creature putricide = ObjectAccessor.GetCreature(caster, instance.GetGuidData(DataTypes.ProfessorPutricide));
|
|
if (!putricide)
|
|
return;
|
|
|
|
if (putricide.GetAI().GetData(DataAbomination) != 0)
|
|
{
|
|
Player player = caster.ToPlayer();
|
|
if (player)
|
|
Spell.SendCastResult(player, GetSpellInfo(), 0, SpellCastResult.CustomError, SpellCustomErrors.TooManyAbominations);
|
|
return;
|
|
}
|
|
|
|
uint entry = (uint)GetSpellInfo().GetEffect(effIndex).MiscValue;
|
|
SummonPropertiesRecord properties = CliDB.SummonPropertiesStorage.LookupByKey(GetSpellInfo().GetEffect(effIndex).MiscValueB);
|
|
uint duration = (uint)GetSpellInfo().GetDuration();
|
|
|
|
Position pos = caster.GetPosition();
|
|
TempSummon summon = caster.GetMap().SummonCreature(entry, pos, properties, duration, caster, GetSpellInfo().Id);
|
|
if (!summon || !summon.IsVehicle())
|
|
return;
|
|
|
|
summon.CastSpell(summon, SPELL_ABOMINATION_VEHICLE_POWER_DRAIN, true);
|
|
summon.CastSpell(summon, SPELL_MUTATED_TRANSFORMATION_DAMAGE, true);
|
|
caster.CastSpell(summon, SPELL_MUTATED_TRANSFORMATION_NAME, true);
|
|
|
|
caster.EnterVehicle(summon, 0); // VEHICLE_SPELL_RIDE_HARDCODED is used according to sniff, this is ok
|
|
summon.SetCreatorGUID(caster.GetGUID());
|
|
putricide.GetAI().JustSummoned(summon);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHit.Add(new EffectHandler(HandleSummon, 0, SpellEffectName.Summon));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_mutated_transformation_SpellScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_mutated_transformation_dmg : SpellScriptLoader
|
|
{
|
|
public spell_putricide_mutated_transformation_dmg() : base("spell_putricide_mutated_transformation_dmg") { }
|
|
|
|
class spell_putricide_mutated_transformation_dmg_SpellScript : SpellScript
|
|
{
|
|
void FilterTargetsInitial(List<WorldObject> targets)
|
|
{
|
|
Unit owner = Global.ObjAccessor.GetUnit(GetCaster(), GetCaster().GetCreatorGUID());
|
|
if (owner)
|
|
targets.Remove(owner);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargetsInitial, 0, Targets.UnitSrcAreaAlly));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_mutated_transformation_dmg_SpellScript();
|
|
}
|
|
}
|
|
|
|
class spell_putricide_regurgitated_ooze : SpellScriptLoader
|
|
{
|
|
public spell_putricide_regurgitated_ooze() : base("spell_putricide_regurgitated_ooze") { }
|
|
|
|
class spell_putricide_regurgitated_ooze_SpellScript : SpellScript
|
|
{
|
|
// the only purpose of this hook is to fail the achievement
|
|
void ExtraEffect(uint effIndex)
|
|
{
|
|
InstanceScript instance = GetCaster().GetInstanceScript();
|
|
if (instance != null)
|
|
instance.SetData(DataTypes.NauseaAchievement, 0);
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(ExtraEffect, 0, SpellEffectName.ApplyAura));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_regurgitated_ooze_SpellScript();
|
|
}
|
|
}
|
|
|
|
// Removes aura with id stored in effect value
|
|
class spell_putricide_clear_aura_effect_value : SpellScriptLoader
|
|
{
|
|
public spell_putricide_clear_aura_effect_value() : base("spell_putricide_clear_aura_effect_value") { }
|
|
|
|
class spell_putricide_clear_aura_effect_value_SpellScript : SpellScript
|
|
{
|
|
void HandleScript(uint effIndex)
|
|
{
|
|
PreventHitDefaultEffect(effIndex);
|
|
GetHitUnit().RemoveAurasDueToSpell((uint)GetEffectValue());
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_putricide_clear_aura_effect_value_SpellScript();
|
|
}
|
|
}
|
|
|
|
// Stinky and Precious spell, it's here because its used for both (Festergut and Rotface "pets")
|
|
class spell_stinky_precious_decimate : SpellScriptLoader
|
|
{
|
|
public spell_stinky_precious_decimate() : base("spell_stinky_precious_decimate") { }
|
|
|
|
class spell_stinky_precious_decimate_SpellScript : SpellScript
|
|
{
|
|
void HandleScript(uint effIndex)
|
|
{
|
|
if (GetHitUnit().GetHealthPct() > GetEffectValue())
|
|
{
|
|
uint newHealth = GetHitUnit().GetMaxHealth() * (uint)GetEffectValue() / 100;
|
|
GetHitUnit().SetHealth(newHealth);
|
|
}
|
|
}
|
|
|
|
public override void Register()
|
|
{
|
|
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
|
|
}
|
|
}
|
|
|
|
public override SpellScript GetSpellScript()
|
|
{
|
|
return new spell_stinky_precious_decimate_SpellScript();
|
|
}
|
|
}
|
|
}
|