/* * Copyright (C) 2012-2017 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 . */ using Framework.Constants; using Framework.Dynamic; using Game.AI; using Game.Entities; using Game.Maps; using Game.Scripting; using System; using System.Collections.Generic; namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheChampion { struct TrialOfChampionSpells { //Vehicle public const uint CHARGE = 63010; public const uint SHIELD_BREAKER = 68504; public const uint SHIELD = 66482; // Marshal Jacob Alerius && Mokra the Skullcrusher || Warrior public const uint MORTAL_STRIKE = 68783; public const uint MORTAL_STRIKE_H = 68784; public const uint BLADESTORM = 63784; public const uint INTERCEPT = 67540; public const uint ROLLING_THROW = 47115; //not implemented in the AI yet... // Ambrose Boltspark && Eressea Dawnsinger || Mage public const uint FIREBALL = 66042; public const uint FIREBALL_H = 68310; public const uint BLAST_WAVE = 66044; public const uint BLAST_WAVE_H = 68312; public const uint HASTE = 66045; public const uint POLYMORPH = 66043; public const uint POLYMORPH_H = 68311; // Colosos && Runok Wildmane || Shaman public const uint CHAIN_LIGHTNING = 67529; public const uint CHAIN_LIGHTNING_H = 68319; public const uint EARTH_SHIELD = 67530; public const uint HEALING_WAVE = 67528; public const uint HEALING_WAVE_H = 68318; public const uint HEX_OF_MENDING = 67534; // Jaelyne Evensong && Zul'tore || Hunter public const uint DISENGAGE = 68340; //not implemented in the AI yet... public const uint LIGHTNING_ARROWS = 66083; public const uint MULTI_SHOT = 66081; public const uint SHOOT = 65868; public const uint SHOOT_H = 67988; // Lana Stouthammer Evensong && Deathstalker Visceri || Rouge public const uint EVISCERATE = 67709; public const uint EVISCERATE_H = 68317; public const uint FAN_OF_KNIVES = 67706; public const uint POISON_BOTTLE = 67701; } /* struct Point { float x, y, z; } const Point MovementPoint[] = { {746.84f, 623.15f, 411.41f}, {747.96f, 620.29f, 411.09f}, {750.23f, 618.35f, 411.09f} } */ /* * Generic AI for vehicles used by npcs in ToC, it needs more improvements. * * Script Complete: 25%. * */ [Script] class generic_vehicleAI_toc5 : CreatureScript { public generic_vehicleAI_toc5() : base("generic_vehicleAI_toc5") { } class generic_vehicleAI_toc5AI : npc_escortAI { public generic_vehicleAI_toc5AI(Creature creature) : base(creature) { Initialize(); SetDespawnAtEnd(false); uiWaypointPath = 0; instance = creature.GetInstanceScript(); } void Initialize() { uiChargeTimer = 5000; uiShieldBreakerTimer = 8000; uiBuffTimer = RandomHelper.URand(30000, 60000); } public override void Reset() { Initialize(); } public override void SetData(uint uiType, uint uiData) { switch (uiType) { case 1: AddWaypoint(0, 747.36f, 634.07f, 411.572f); AddWaypoint(1, 780.43f, 607.15f, 411.82f); AddWaypoint(2, 785.99f, 599.41f, 411.92f); AddWaypoint(3, 778.44f, 601.64f, 411.79f); uiWaypointPath = 1; break; case 2: AddWaypoint(0, 747.35f, 634.07f, 411.57f); AddWaypoint(1, 768.72f, 581.01f, 411.92f); AddWaypoint(2, 763.55f, 590.52f, 411.71f); uiWaypointPath = 2; break; case 3: AddWaypoint(0, 747.35f, 634.07f, 411.57f); AddWaypoint(1, 784.02f, 645.33f, 412.39f); AddWaypoint(2, 775.67f, 641.91f, 411.91f); uiWaypointPath = 3; break; } if (uiType <= 3) Start(false, true); } public override void WaypointReached(uint waypointId) { switch (waypointId) { case 2: if (uiWaypointPath == 3 || uiWaypointPath == 2) instance.SetData((uint)Data.DATA_MOVEMENT_DONE, instance.GetData((uint)Data.DATA_MOVEMENT_DONE) + 1); break; case 3: instance.SetData((uint)Data.DATA_MOVEMENT_DONE, instance.GetData((uint)Data.DATA_MOVEMENT_DONE) + 1); break; } } public override void EnterCombat(Unit who) { DoCastSpellShield(); } void DoCastSpellShield() { for (byte i = 0; i < 3; ++i) DoCast(me, TrialOfChampionSpells.SHIELD, true); } public override void UpdateAI(uint uiDiff) { base.UpdateAI(uiDiff); if (!UpdateVictim()) return; if (uiBuffTimer <= uiDiff) { if (!me.HasAura(TrialOfChampionSpells.SHIELD)) DoCastSpellShield(); uiBuffTimer = RandomHelper.URand(30000, 45000); } else uiBuffTimer -= uiDiff; if (uiChargeTimer <= uiDiff) { var players = me.GetMap().GetPlayers(); if (!players.Empty()) { foreach (var player in players) { if (player && !player.IsGameMaster() && me.IsInRange(player, 8.0f, 25.0f, false)) { DoResetThreat(); me.AddThreat(player, 1.0f); DoCast(player, TrialOfChampionSpells.CHARGE); break; } } } uiChargeTimer = 5000; } else uiChargeTimer -= uiDiff; //dosen't work at all if (uiShieldBreakerTimer <= uiDiff) { Vehicle pVehicle = me.GetVehicleKit(); if (!pVehicle) return; Unit pPassenger = pVehicle.GetPassenger(0); if (pPassenger) { var players = me.GetMap().GetPlayers(); if (!players.Empty()) { foreach (var player in players) { if (player && !player.IsGameMaster() && me.IsInRange(player, 10.0f, 30.0f, false)) { pPassenger.CastSpell(player, TrialOfChampionSpells.SHIELD_BREAKER, true); break; } } } } uiShieldBreakerTimer = 7000; } else uiShieldBreakerTimer -= uiDiff; DoMeleeAttackIfReady(); } InstanceScript instance; uint uiChargeTimer; uint uiShieldBreakerTimer; uint uiBuffTimer; uint uiWaypointPath; } public override CreatureAI GetAI(Creature creature) { return GetInstanceAI(creature); } public static void AggroAllPlayers(Creature temp) { var PlList = temp.GetMap().GetPlayers(); if (PlList.Empty()) return; foreach (var player in PlList) { if (player) { if (player.IsGameMaster()) continue; if (player.IsAlive()) { temp.RemoveFlag(UnitFields.Flags, UnitFlags.NonAttackable | UnitFlags.ImmuneToPc); temp.SetReactState(ReactStates.Aggressive); temp.SetInCombatWith(player); player.SetInCombatWith(temp); temp.AddThreat(player, 0.0f); } } } } public static bool GrandChampionsOutVehicle(Creature me) { InstanceScript instance = me.GetInstanceScript(); if (instance == null) return false; Creature pGrandChampion1 = ObjectAccessor.GetCreature(me, instance.GetGuidData((uint)Data64.DATA_GRAND_CHAMPION_1)); Creature pGrandChampion2 = ObjectAccessor.GetCreature(me, instance.GetGuidData((uint)Data64.DATA_GRAND_CHAMPION_2)); Creature pGrandChampion3 = ObjectAccessor.GetCreature(me, instance.GetGuidData((uint)Data64.DATA_GRAND_CHAMPION_3)); if (pGrandChampion1 && pGrandChampion2 && pGrandChampion3) { if (pGrandChampion1.m_movementInfo.transport.guid.IsEmpty() && pGrandChampion2.m_movementInfo.transport.guid.IsEmpty() && pGrandChampion3.m_movementInfo.transport.guid.IsEmpty()) return true; } return false; } } abstract class boss_basic_toc5AI : ScriptedAI { public boss_basic_toc5AI(Creature creature) : base(creature) { Initialize(); instance = creature.GetInstanceScript(); bDone = false; bHome = false; uiPhase = 0; uiPhaseTimer = 0; me.SetReactState(ReactStates.Passive); // THIS IS A HACK, SHOULD BE REMOVED WHEN THE EVENT IS FULL SCRIPTED me.SetFlag(UnitFields.Flags, UnitFlags.NonAttackable | UnitFlags.ImmuneToPc); } public abstract void Initialize(); public override void Reset() { Initialize(); } public override void JustReachedHome() { base.JustReachedHome(); if (!bHome) return; uiPhaseTimer = 15000; uiPhase = 1; bHome = false; } public override void JustDied(Unit killer) { instance.SetData((uint)Data.BOSS_GRAND_CHAMPIONS, (uint)EncounterState.Done); } public override void UpdateAI(uint diff) { if (!bDone && generic_vehicleAI_toc5.GrandChampionsOutVehicle(me)) { bDone = true; if (me.GetGUID() == instance.GetGuidData((uint)Data64.DATA_GRAND_CHAMPION_1)) me.SetHomePosition(739.678f, 662.541f, 412.393f, 4.49f); else if (me.GetGUID() == instance.GetGuidData((uint)Data64.DATA_GRAND_CHAMPION_2)) me.SetHomePosition(746.71f, 661.02f, 411.69f, 4.6f); else if (me.GetGUID() == instance.GetGuidData((uint)Data64.DATA_GRAND_CHAMPION_3)) me.SetHomePosition(754.34f, 660.70f, 412.39f, 4.79f); EnterEvadeMode(); bHome = true; } if (uiPhaseTimer <= diff) { if (uiPhase == 1) { generic_vehicleAI_toc5.AggroAllPlayers(me); uiPhase = 0; } } else uiPhaseTimer -= diff; } public bool InVehicle() { return !me.m_movementInfo.transport.guid.IsEmpty(); } public TaskScheduler NonCombatEvents = new TaskScheduler(); public InstanceScript instance; public byte uiPhase; public uint uiPhaseTimer; bool bDone; public bool bHome; } [Script] class boss_warrior_toc5 : CreatureScript { public boss_warrior_toc5() : base("boss_warrior_toc5") { } // Marshal Jacob Alerius && Mokra the Skullcrusher || Warrior class boss_warrior_toc5AI : boss_basic_toc5AI { public boss_warrior_toc5AI(Creature creature) : base(creature) { } public override void Initialize() { _scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), task => { DoCastVictim(TrialOfChampionSpells.BLADESTORM); task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20)); }); _scheduler.Schedule(TimeSpan.FromSeconds(7), task => { var players = me.GetMap().GetPlayers(); if (!players.Empty()) { foreach (var player in players) { if (player && !player.IsGameMaster() && me.IsInRange(player, 8.0f, 25.0f, false)) { DoResetThreat(); me.AddThreat(player, 5.0f); DoCast(player, TrialOfChampionSpells.INTERCEPT); break; } } } task.Repeat(TimeSpan.FromSeconds(7)); }); _scheduler.Schedule(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(12), task => { DoCastVictim(TrialOfChampionSpells.MORTAL_STRIKE); task.Repeat(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(12)); }); } public override void UpdateAI(uint diff) { base.UpdateAI(diff); if (!UpdateVictim() || InVehicle()) return; _scheduler.Update(diff); DoMeleeAttackIfReady(); } } public override CreatureAI GetAI(Creature creature) { return GetInstanceAI(creature); } } [Script] class boss_mage_toc5 : CreatureScript { public boss_mage_toc5() : base("boss_mage_toc5") { } // Ambrose Boltspark && Eressea Dawnsinger || Mage class boss_mage_toc5AI : boss_basic_toc5AI { public boss_mage_toc5AI(Creature creature) : base(creature) { } public override void Initialize() { _scheduler.Schedule(TimeSpan.FromSeconds(5), task => { DoCastVictim(TrialOfChampionSpells.FIREBALL); task.Repeat(TimeSpan.FromSeconds(5)); }); _scheduler.Schedule(TimeSpan.FromSeconds(8), task => { Unit target = SelectTarget(SelectAggroTarget.Random, 0); if (target) DoCast(target, TrialOfChampionSpells.POLYMORPH); task.Repeat(TimeSpan.FromSeconds(8)); }); _scheduler.Schedule(TimeSpan.FromSeconds(12), task => { DoCastAOE(TrialOfChampionSpells.BLAST_WAVE, false); task.Repeat(TimeSpan.FromSeconds(13)); }); _scheduler.Schedule(TimeSpan.FromSeconds(22), task => { me.InterruptNonMeleeSpells(true); DoCast(me, TrialOfChampionSpells.HASTE); task.Repeat(TimeSpan.FromSeconds(22)); }); } public override void UpdateAI(uint diff) { base.UpdateAI(diff); if (!UpdateVictim() || InVehicle()) return; _scheduler.Update(diff); DoMeleeAttackIfReady(); } } public override CreatureAI GetAI(Creature creature) { return GetInstanceAI(creature); } } [Script] class boss_shaman_toc5 : CreatureScript { public boss_shaman_toc5() : base("boss_shaman_toc5") { } // Colosos && Runok Wildmane || Shaman class boss_shaman_toc5AI : boss_basic_toc5AI { public boss_shaman_toc5AI(Creature creature) : base(creature) { } public override void Initialize() { _scheduler.Schedule(TimeSpan.FromSeconds(16), task => { Unit target = SelectTarget(SelectAggroTarget.Random, 0); if (target) DoCast(target, TrialOfChampionSpells.CHAIN_LIGHTNING); task.Repeat(TimeSpan.FromSeconds(16)); }); _scheduler.Schedule(TimeSpan.FromSeconds(12), task => { bool bChance = RandomHelper.randChance(50); if (!bChance) { Unit pFriend = DoSelectLowestHpFriendly(40); if (pFriend) DoCast(pFriend, TrialOfChampionSpells.HEALING_WAVE); } else DoCast(me, TrialOfChampionSpells.HEALING_WAVE); task.Repeat(TimeSpan.FromSeconds(12)); }); _scheduler.Schedule(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(35), task => { DoCast(me, TrialOfChampionSpells.EARTH_SHIELD); task.Repeat(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(35)); }); _scheduler.Schedule(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(25), task => { DoCastVictim(TrialOfChampionSpells.HEX_OF_MENDING, true); task.Repeat(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(25)); }); } public override void EnterCombat(Unit who) { DoCast(me, TrialOfChampionSpells.EARTH_SHIELD); DoCast(who, TrialOfChampionSpells.HEX_OF_MENDING); } public override void UpdateAI(uint diff) { base.UpdateAI(diff); if (!UpdateVictim() || InVehicle()) return; _scheduler.Update(diff); DoMeleeAttackIfReady(); } } public override CreatureAI GetAI(Creature creature) { return GetInstanceAI(creature); } } [Script] class boss_hunter_toc5 : CreatureScript { public boss_hunter_toc5() : base("boss_hunter_toc5") { } // Jaelyne Evensong && Zul'tore || Hunter class boss_hunter_toc5AI : boss_basic_toc5AI { public boss_hunter_toc5AI(Creature creature) : base(creature) { } public override void Initialize() { _scheduler.Schedule(TimeSpan.FromSeconds(7), task => { DoCastAOE(TrialOfChampionSpells.LIGHTNING_ARROWS, false); task.Repeat(TimeSpan.FromSeconds(7)); }); _scheduler.Schedule(TimeSpan.FromSeconds(12), task => { ObjectGuid uiTargetGUID = ObjectGuid.Empty; Unit target = SelectTarget(SelectAggroTarget.Farthest, 0, 30.0f); if (target) { uiTargetGUID = target.GetGUID(); DoCast(target, TrialOfChampionSpells.SHOOT); } bool bShoot = true; task.Repeat(TimeSpan.FromSeconds(12)); task.Schedule(TimeSpan.FromSeconds(3), task1 => { if (bShoot) { me.InterruptNonMeleeSpells(true); Unit target1 = Global.ObjAccessor.GetUnit(me, uiTargetGUID); if (target1 && me.IsInRange(target1, 5.0f, 30.0f, false)) { DoCast(target1, TrialOfChampionSpells.MULTI_SHOT); } else { var players = me.GetMap().GetPlayers(); if (!players.Empty()) { foreach (var player in players) { if (player && !player.IsGameMaster() && me.IsInRange(player, 5.0f, 30.0f, false)) { DoCast(player, TrialOfChampionSpells.MULTI_SHOT); break; } } } } bShoot = false; } }); }); } public override void UpdateAI(uint diff) { base.UpdateAI(diff); if (!UpdateVictim() || InVehicle()) return; _scheduler.Update(diff); DoMeleeAttackIfReady(); } } public override CreatureAI GetAI(Creature creature) { return GetInstanceAI(creature); } } [Script] class boss_rouge_toc5 : CreatureScript { public boss_rouge_toc5() : base("boss_rouge_toc5") { } // Lana Stouthammer Evensong && Deathstalker Visceri || Rouge class boss_rouge_toc5AI : boss_basic_toc5AI { public boss_rouge_toc5AI(Creature creature) : base(creature) { } public override void Initialize() { _scheduler.Schedule(TimeSpan.FromSeconds(8), task => { DoCastVictim(TrialOfChampionSpells.EVISCERATE); task.Repeat(TimeSpan.FromSeconds(8)); }); _scheduler.Schedule(TimeSpan.FromSeconds(14), task => { DoCastAOE(TrialOfChampionSpells.FAN_OF_KNIVES, false); task.Repeat(TimeSpan.FromSeconds(14)); }); _scheduler.Schedule(TimeSpan.FromSeconds(19), task => { Unit target = SelectTarget(SelectAggroTarget.Random, 0); if (target) DoCast(target, TrialOfChampionSpells.POISON_BOTTLE); task.Repeat(TimeSpan.FromSeconds(19)); }); } public override void UpdateAI(uint diff) { base.UpdateAI(diff); if (!UpdateVictim() || !me.m_movementInfo.transport.guid.IsEmpty()) return; _scheduler.Update(diff); DoMeleeAttackIfReady(); } } public override CreatureAI GetAI(Creature creature) { return GetInstanceAI(creature); } } }