Ported .Net Core commits:

hondacrx:
- Initial commit: Switch to .Net Core 2.0
- Fix build and removed not needed files
Fabi:
- Updated solution platforms.
- Changed folder structure.
- Change library target framework to netstandard2.0.
- Updated solution platforms again...
- Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
Fabian
2017-10-26 17:23:44 +02:00
parent 227702e19c
commit a3dc7b3f48
844 changed files with 26064 additions and 1824 deletions
@@ -0,0 +1,30 @@
/*
* 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 Game.Entities;
namespace Scripts.Northrend.Ulduar
{
namespace Algalon
{
class AlgalonTheObserver
{
public static Position AlgalonSummonPos = new Position(1632.531f, -304.8516f, 450.1123f, 1.530165f);
public static Position AlgalonLandPos = new Position(1632.668f, -302.7656f, 417.3211f, 1.530165f);
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,148 @@
/*
* 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/>.
*/
namespace Scripts.Northrend.Ulduar
{
namespace Razorscale
{
/*class boss_razorscale_controller : BossAI
{
public boss_razorscale_controller(Creature creature) : base(creature, InstanceData.RazorscaleControl)
{
me.SetDisplayId(me.GetCreatureTemplate().ModelId2);
}
public override void Reset()
{
_Reset();
me.SetReactState(ReactStates.Passive);
}
public override void SpellHit(Unit caster, SpellInfo spell)
{
switch (spell.Id)
{
case SPELL_FLAMED:
GameObject Harpoon = ObjectAccessor.GetGameObject(me, instance.GetGuidData(GO_RAZOR_HARPOON_1));
if (Harpoon)
Harpoon.RemoveFromWorld();
Harpoon = ObjectAccessor.GetGameObject(me, instance.GetGuidData(GO_RAZOR_HARPOON_2));
if (Harpoon)
Harpoon.RemoveFromWorld();
Harpoon = ObjectAccessor.GetGameObject(me, instance.GetGuidData(GO_RAZOR_HARPOON_3));
if (Harpoon)
Harpoon.RemoveFromWorld();
Harpoon = ObjectAccessor.GetGameObject(me, instance.GetGuidData(GO_RAZOR_HARPOON_4));
if (Harpoon)
Harpoon.RemoveFromWorld();
DoAction(ACTION_HARPOON_BUILD);
DoAction(ACTION_PLACE_BROKEN_HARPOON);
break;
case SPELL_HARPOON_SHOT_1:
case SPELL_HARPOON_SHOT_2:
case SPELL_HARPOON_SHOT_3:
case SPELL_HARPOON_SHOT_4:
DoCast(SPELL_HARPOON_TRIGGER);
break;
}
}
public override void JustDied(Unit killer)
{
_JustDied();
}
public override void DoAction(int action)
{
if (instance.GetBossState(BOSS_RAZORSCALE) != EncounterState.InProgress)
return;
switch (action)
{
case ACTION_HARPOON_BUILD:
events.ScheduleEvent(EVENT_BUILD_HARPOON_1, 50000);
if (me->GetMap()->GetSpawnMode() == DIFFICULTY_25_N)
events.ScheduleEvent(EVENT_BUILD_HARPOON_3, 90000);
break;
case ACTION_PLACE_BROKEN_HARPOON:
for (uint8 n = 0; n < RAID_MODE(2, 4); n++)
me->SummonGameObject(GO_RAZOR_BROKEN_HARPOON, PosHarpoon[n].GetPositionX(), PosHarpoon[n].GetPositionY(), PosHarpoon[n].GetPositionZ(), 2.286f, 0, 0, 0, 0, 180);
break;
}
}
public override void UpdateAI(uint Diff)
{
_events.Update(Diff);
while (uint eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_BUILD_HARPOON_1:
Talk(EMOTE_HARPOON);
if (GameObject * Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_1, PosHarpoon[0].GetPositionX(), PosHarpoon[0].GetPositionY(), PosHarpoon[0].GetPositionZ(), 4.790f, 0.0f, 0.0f, 0.0f, 0.0f, uint32(me->GetRespawnTime())))
{
if (GameObject * BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) //only nearest broken harpoon
BrokenHarpoon->RemoveFromWorld();
events.ScheduleEvent(EVENT_BUILD_HARPOON_2, 20000);
events.CancelEvent(EVENT_BUILD_HARPOON_1);
}
return;
case EVENT_BUILD_HARPOON_2:
Talk(EMOTE_HARPOON);
if (GameObject * Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_2, PosHarpoon[1].GetPositionX(), PosHarpoon[1].GetPositionY(), PosHarpoon[1].GetPositionZ(), 4.659f, 0, 0, 0, 0, uint32(me->GetRespawnTime())))
{
if (GameObject * BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f))
BrokenHarpoon->RemoveFromWorld();
events.CancelEvent(EVENT_BUILD_HARPOON_2);
}
return;
case EVENT_BUILD_HARPOON_3:
Talk(EMOTE_HARPOON);
if (GameObject * Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_3, PosHarpoon[2].GetPositionX(), PosHarpoon[2].GetPositionY(), PosHarpoon[2].GetPositionZ(), 5.382f, 0, 0, 0, 0, uint32(me->GetRespawnTime())))
{
if (GameObject * BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f))
BrokenHarpoon->RemoveFromWorld();
events.ScheduleEvent(EVENT_BUILD_HARPOON_4, 20000);
events.CancelEvent(EVENT_BUILD_HARPOON_3);
}
return;
case EVENT_BUILD_HARPOON_4:
Talk(EMOTE_HARPOON);
if (GameObject * Harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_4, PosHarpoon[3].GetPositionX(), PosHarpoon[3].GetPositionY(), PosHarpoon[3].GetPositionZ(), 4.266f, 0, 0, 0, 0, uint32(me->GetRespawnTime())))
{
if (GameObject * BrokenHarpoon = Harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f))
BrokenHarpoon->RemoveFromWorld();
events.CancelEvent(EVENT_BUILD_HARPOON_4);
}
return;
}
}
}
}
public override CreatureAI Get(Creature creature)
{
return GetInstanceAI<boss_razorscale_controllerAI>(creature);
}
}*/
}
}
@@ -0,0 +1,415 @@
/*
* 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/>.
*/
namespace Scripts.Northrend.Ulduar
{
struct BossIds
{
public const uint MaxEncounter = 17;
public const uint Leviathan = 0;
public const uint Ignis = 1;
public const uint Razorscale = 2;
public const uint Xt002 = 3;
public const uint AssemblyOfIron = 4;
public const uint Kologarn = 5;
public const uint Auriaya = 6;
public const uint Mimiron = 7;
public const uint Hodir = 8;
public const uint Thorim = 9;
public const uint Freya = 10;
public const uint Brightleaf = 11;
public const uint Ironbranch = 12;
public const uint Stonebark = 13;
public const uint Vezax = 14;
public const uint YoggSaron = 15;
public const uint Algalon = 16;
}
struct InstanceCreatureIds
{
// General
public const uint Leviathan = 33113;
public const uint SalvagedDemolisher = 33109;
public const uint SalvagedSiegeEngine = 33060;
public const uint SalvagedChopper = 33062;
public const uint Ignis = 33118;
public const uint Razorscale = 33186;
public const uint RazorscaleController = 33233;
public const uint SteelforgedDeffender = 33236;
public const uint ExpeditionCommander = 33210;
public const uint Xt002 = 33293;
public const uint XtToyPile = 33337;
public const uint Steelbreaker = 32867;
public const uint Molgeim = 32927;
public const uint Brundir = 32857;
public const uint Kologarn = 32930;
public const uint FocusedEyebeam = 33632;
public const uint FocusedEyebeamRight = 33802;
public const uint LeftArm = 32933;
public const uint RightArm = 32934;
public const uint Rubble = 33768;
public const uint Auriaya = 33515;
public const uint Mimiron = 33350;
public const uint Hodir = 32845;
public const uint Thorim = 32865;
public const uint Freya = 32906;
public const uint Vezax = 33271;
public const uint YoggSaron = 33288;
public const uint Algalon = 32871;
//XT002
public const uint XS013Scrapbot = 33343;
// Mimiron
public const uint LeviathanMkII = 33432;
public const uint Vx001 = 33651;
public const uint AerialCommandUnit = 33670;
public const uint AssaultBot = 34057;
public const uint BombBot = 33836;
public const uint JunkBot = 33855;
public const uint EmergencyFireBot = 34147;
public const uint FrostBomb = 34149;
public const uint BurstTarget = 34211;
public const uint Flame = 34363;
public const uint FlameSpread = 34121;
public const uint DBTarget = 33576;
public const uint RocketMimironVisual = 34050;
public const uint WorldTriggerMimiron = 21252;
public const uint Computer = 34143;
// Freya'S Keepers
public const uint Ironbranch = 32913;
public const uint Brightleaf = 32915;
public const uint Stonebark = 32914;
// Hodir'S Helper Npcs
public const uint TorGreycloud = 32941;
public const uint KarGreycloud = 33333;
public const uint EiviNightfeather = 33325;
public const uint EllieNightfeather = 32901;
public const uint SpiritwalkerTara = 33332;
public const uint SpiritwalkerYona = 32950;
public const uint ElementalistMahfuun = 33328;
public const uint ElementalistAvuun = 32900;
public const uint AmiraBlazeweaver = 33331;
public const uint VeeshaBlazeweaver = 32946;
public const uint MissyFlamecuffs = 32893;
public const uint SissyFlamecuffs = 33327;
public const uint BattlePriestEliza = 32948;
public const uint BattlePriestGina = 33330;
public const uint FieldMedicPenny = 32897;
public const uint FieldMedicJessi = 33326;
// Freya'S Trash Npcs
public const uint CorruptedServitor = 33354;
public const uint MisguidedNymph = 33355;
public const uint GuardianLasher = 33430;
public const uint ForestSwarmer = 33431;
public const uint MangroveEnt = 33525;
public const uint IronrootLasher = 33526;
public const uint NaturesBlade = 33527;
public const uint GuardianOfLife = 33528;
// Freya Achievement Trigger
public const uint FreyaAchieveTrigger = 33406;
// Yogg-Saron
public const uint Sara = 33134;
public const uint GuardianOfYoggSaron = 33136;
public const uint HodirObservationRing = 33213;
public const uint FreyaObservationRing = 33241;
public const uint ThorimObservationRing = 33242;
public const uint MimironObservationRing = 33244;
public const uint VoiceOfYoggSaron = 33280;
public const uint OminousCloud = 33292;
public const uint FreyaYs = 33410;
public const uint HodirYs = 33411;
public const uint MimironYs = 33412;
public const uint ThorimYs = 33413;
public const uint SuitOfArmor = 33433;
public const uint KingLlane = 33437;
public const uint TheLichKing = 33441;
public const uint ImmolatedChampion = 33442;
public const uint Ysera = 33495;
public const uint Neltharion = 33523;
public const uint Malygos = 33535;
public const uint DeathRay = 33881;
public const uint DeathOrb = 33882;
public const uint BrainOfYoggSaron = 33890;
public const uint InfluenceTentacle = 33943;
public const uint TurnedChampion = 33962;
public const uint CrusherTentacle = 33966;
public const uint ConstrictorTentacle = 33983;
public const uint CorruptorTentacle = 33985;
public const uint ImmortalGuardian = 33988;
public const uint SanityWell = 33991;
public const uint DescendIntoMadness = 34072;
public const uint MarkedImmortalGuardian = 36064;
// Algalon The Observer
public const uint BrannBronzbeardAlg = 34064;
public const uint Azeroth = 34246;
public const uint LivingConstellation = 33052;
public const uint AlgalonStalker = 33086;
public const uint CollapsingStar = 32955;
public const uint BlackHole = 32953;
public const uint WormHole = 34099;
public const uint AlgalonVoidZoneVisualStalker = 34100;
public const uint AlgalonStalkerAsteroidTarget01 = 33104;
public const uint AlgalonStalkerAsteroidTarget02 = 33105;
public const uint UnleashedDarkMatter = 34097;
}
struct InstanceGameObjectIds
{
// Leviathan
public const uint LeviathanDoor = 194905;
public const uint LeviathanGate = 194630;
// Razorscale
public const uint MoleMachine = 194316;
public const uint RazorHarpoon1 = 194542;
public const uint RazorHarpoon2 = 194541;
public const uint RazorHarpoon3 = 194543;
public const uint RazorHarpoon4 = 194519;
public const uint RazorBrokenHarpoon = 194565;
// Xt-002
public const uint Xt002Door = 194631;
// Assembly Of Iron
public const uint IronCouncilDoor = 194554;
public const uint ArchivumDoor = 194556;
// Kologarn
public const uint KologarnChestHero = 195047;
public const uint KologarnChest = 195046;
public const uint KologarnBridge = 194232;
public const uint KologarnDoor = 194553;
// Hodir
public const uint HodirEntrance = 194442;
public const uint HodirDoor = 194634;
public const uint HodirIceDoor = 194441;
public const uint HodirRareCacheOfWinter = 194200;
public const uint HodirRareCacheOfWinterHero = 194201;
public const uint HodirChestHero = 194308;
public const uint HodirChest = 194307;
// Thorim
public const uint ThorimChestHero = 194315;
public const uint ThorimChest = 194314;
// Mimiron
public const uint MimironTram = 194675;
public const uint MimironElevator = 194749;
public const uint MimironButton = 194739;
public const uint MimironDoor1 = 194774;
public const uint MimironDoor2 = 194775;
public const uint MimironDoor3 = 194776;
public const uint CacheOfInnovation = 194789;
public const uint CacheOfInnovationFirefighter = 194957;
public const uint CacheOfInnovationHero = 194956;
public const uint CacheOfInnovationFirefighterHero = 194958;
// Vezax
public const uint VezaxDoor = 194750;
// Yogg-Saron
public const uint YoggSaronDoor = 194773;
public const uint BrainRoomDoor1 = 194635;
public const uint BrainRoomDoor2 = 194636;
public const uint BrainRoomDoor3 = 194637;
// Algalon The Observer
public const uint CelestialPlanetariumAccess10 = 194628;
public const uint CelestialPlanetariumAccess25 = 194752;
public const uint DoodadUlSigildoor01 = 194767;
public const uint DoodadUlSigildoor02 = 194911;
public const uint DoodadUlSigildoor03 = 194910;
public const uint DoodadUlUniversefloor01 = 194715;
public const uint DoodadUlUniversefloor02 = 194716;
public const uint DoodadUlUniverseglobe01 = 194148;
public const uint DoodadUlUlduarTrapdoor03 = 194253;
public const uint GiftOfTheObserver10 = 194821;
public const uint GiftOfTheObserver25 = 194822;
}
struct InstanceEventIds
{
public const int TowerOfStormDestroyed = 21031;
public const int TowerOfFrostDestroyed = 21032;
public const int TowerOfFlamesDestroyed = 21033;
public const int TowerOfLifeDestroyed = 21030;
public const int ActivateSanityWell = 21432;
public const int HodirsProtectiveGazeProc = 21437;
}
struct LeviathanActions
{
public const int TowerOfStormDestroyed = 1;
public const int TowerOfFrostDestroyed = 2;
public const int TowerOfFlamesDestroyed = 3;
public const int TowerOfLifeDestroyed = 4;
public const int MoveToCenterPosition = 10;
}
struct InstanceCriteriaIds
{
public const uint ConSpeedAtory = 21597;
public const uint Lumberjacked = 21686;
public const uint Disarmed = 21687;
public const uint WaitsDreamingStormwind25 = 10321;
public const uint WaitsDreamingChamber25 = 10322;
public const uint WaitsDreamingIcecrown25 = 10323;
public const uint WaitsDreamingStormwind10 = 10324;
public const uint WaitsDreamingChamber10 = 10325;
public const uint WaitsDreamingIcecrown10 = 10326;
public const uint DriveMeCrazy10 = 10185;
public const uint DriveMeCrazy25 = 10296;
public const uint ThreeLightsInTheDarkness10 = 10410;
public const uint ThreeLightsInTheDarkness25 = 10414;
public const uint TwoLightsInTheDarkness10 = 10388;
public const uint TwoLightsInTheDarkness25 = 10415;
public const uint OneLightInTheDarkness10 = 10409;
public const uint OneLightInTheDarkness25 = 10416;
public const uint AloneInTheDarkness10 = 10412;
public const uint AloneInTheDarkness25 = 10417;
public const uint HeraldOfTitans = 10678;
// Champion Of Ulduar
public const uint ChampionLeviathan10 = 10042;
public const uint ChampionIgnis10 = 10342;
public const uint ChampionRazorscale10 = 10340;
public const uint ChampionXt002_10 = 10341;
public const uint ChampionIronCouncil10 = 10598;
public const uint ChampionKologarn10 = 10348;
public const uint ChampionAuriaya10 = 10351;
public const uint ChampionHodir10 = 10439;
public const uint ChampionThorim10 = 10403;
public const uint ChampionFreya10 = 10582;
public const uint ChampionMimiron10 = 10347;
public const uint ChampionVezax10 = 10349;
public const uint ChampionYoggSaron10 = 10350;
// Conqueror Of Ulduar
public const uint ChampionLeviathan25 = 10352;
public const uint ChampionIgnis25 = 10355;
public const uint ChampionRazorscale25 = 10353;
public const uint ChampionXt002_25 = 10354;
public const uint ChampionIronCouncil25 = 10599;
public const uint ChampionKologarn25 = 10357;
public const uint ChampionAuriaya25 = 10363;
public const uint ChampionHodir25 = 10719;
public const uint ChampionThorim25 = 10404;
public const uint ChampionFreya25 = 10583;
public const uint ChampionMimiron25 = 10361;
public const uint ChampionVezax25 = 10362;
public const uint ChampionYoggSaron25 = 10364;
}
struct InstanceData
{
// Colossus (Leviathan)
public const uint Colossus = 20;
// Razorscale
public const uint ExpeditionCommander = 21;
public const uint RazorscaleControl = 22;
// Xt-002
public const uint ToyPile0 = 23;
public const uint ToyPile1 = 24;
public const uint ToyPile2 = 25;
public const uint ToyPile3 = 26;
// Assembly Of Iron
public const uint Steelbreaker = 27;
public const uint Molgeim = 28;
public const uint Brundir = 29;
// Hodir
public const uint HodirRareCache = 30;
// Mimiron
public const uint LeviathanMKII = 31;
public const uint VX001 = 32;
public const uint AerialCommandUnit = 33;
public const uint Computer = 34;
public const uint MimironWorldTrigger = 35;
public const uint MimironElevator = 36;
public const uint MimironTram = 37;
public const uint MimironButton = 38;
// Yogg-Saron
public const uint VoiceOfYoggSaron = 39;
public const uint Sara = 40;
public const uint BrainOfYoggSaron = 41;
public const uint FreyaYs = 42;
public const uint HodirYs = 43;
public const uint ThorimYs = 44;
public const uint MimironYs = 45;
public const uint Illusion = 46;
public const uint DriveMeCrazy = 47;
public const uint KeepersCount = 48;
// Algalon The Observer
public const uint AlgalonSummonState = 49;
public const uint Sigildoor01 = 50;
public const uint Sigildoor02 = 51;
public const uint Sigildoor03 = 52;
public const uint UniverseFloor01 = 53;
public const uint UniverseFloor02 = 54;
public const uint UniverseGlobe = 55;
public const uint AlgalonTrapdoor = 56;
public const uint BrannBronzebeardAlg = 57;
// Misc
public const uint BrannBronzebeardIntro = 58;
public const uint LoreKeeperOfNorgannon = 59;
public const uint Dellorah = 60;
public const uint BronzebeardRadio = 61;
}
struct InstanceWorldStates
{
public const uint AlgalonDespawnTimer = 4131;
public const uint AlgalonTimerEnabled = 4132;
}
struct InstanceAchievementData
{
// Fl Achievement Boolean
public const uint DataUnbroken = 29052906; // 2905, 2906 Are Achievement Ids,
public const uint MaxHeraldArmorItemlevel = 226;
public const uint MaxHeraldWeaponItemlevel = 232;
}
struct InstanceEvents
{
public const uint EventDespawnAlgalon = 1;
public const uint EventUpdateAlgalonTimer = 2;
public const uint ActionInitAlgalon = 6;
}
struct YoggSaronIllusions
{
public const uint ChamberIllusion = 0;
public const uint IcecrownIllusion = 1;
public const uint StormwindIllusion = 2;
}
}
File diff suppressed because it is too large Load Diff
+884
View File
@@ -0,0 +1,884 @@
/*
* 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 Framework.Dynamic;
using Game.AI;
using Game.Entities;
using Game.Maps;
using Game.Scripting;
using Game.Spells;
using System;
using System.Collections.Generic;
namespace Scripts.Northrend.Ulduar.Xt002
{
struct SpellIds
{
public const uint TympanicTantrum = 62776;
public const uint SearingLight = 63018;
public const uint SummonLifeSpark = 64210;
public const uint SummonVoidZone = 64203;
public const uint GravityBomb = 63024;
public const uint Heartbreak = 65737;
// Cast By 33337 At Heartbreak:
public const uint RechargePummeler = 62831; // Summons 33344
public const uint RechargeScrapbot = 62828; // Summons 33343
public const uint RechargeBoombot = 62835; // Summons 33346
// Cast By 33329 On 33337 (Visual?)
public const uint EnergyOrb = 62790; // Triggers 62826 - Needs Spellscript For Periodic Tick To Cast One Of The Random Spells Above
public const uint HeartHealToFull = 17683;
public const uint HeartOverload = 62789;
public const uint HeartLightningTether = 64799; // Cast On Self?
public const uint Enrage = 26662;
public const uint Stand = 37752;
public const uint Submerge = 37751;
//------------------Void Zone--------------------
public const uint VoidZone = 64203;
public const uint Consumption = 64208;
// Life Spark
public const uint ArcanePowerState = 49411;
public const uint StaticCharged = 64227;
public const uint Shock = 64230;
//----------------Xt-002 Heart-------------------
public const uint ExposedHeart = 63849;
public const uint HeartRideVehicle = 63852;
public const uint RideVehicleExposed = 63313; //Heart Exposed
//---------------Xm-024 Pummeller----------------
public const uint ArcingSmash = 8374;
public const uint Trample = 5568;
public const uint Uppercut = 10966;
// Scrabot:
public const uint ScrapbotRideVehicle = 47020;
public const uint ScrapRepair = 62832;
public const uint Suicide = 7;
//------------------Boombot-----------------------
public const uint AuraBoombot = 65032;
public const uint Boom = 62834;
// Achievement-Related Spells
public const uint AchievementCreditNerfScrapbots = 65037;
}
struct XT002Data
{
public const uint TransferedHealth = 0;
public const uint HardMode = 1;
public const uint HealthRecovered = 2;
public const uint GravityBombCasualty = 3;
}
struct Texts
{
public const uint Aggro = 0;
public const uint HeartOpened = 1;
public const uint HeartClosed = 2;
public const uint TympanicTantrum = 3;
public const uint Slay = 4;
public const uint Berserk = 5;
public const uint Death = 6;
public const uint Summon = 7;
public const uint EmoteHeartOpened = 8;
public const uint EmoteHeartClosed = 9;
public const uint EmoteTympanicTantrum = 10;
public const uint EmoteScrapbot = 11;
}
struct Misc
{
public const uint PhaseOneGroup = 1;
public const int ActionHardMode = 1;
public const uint AchievMustDeconstructFaster = 21027;
public const sbyte SeatHeartNormal = 0;
public const sbyte SeatHeartExposed = 1;
}
[Script]
class boss_xt002 : BossAI
{
public boss_xt002(Creature creature) : base(creature, BossIds.Xt002)
{
Initialize();
_transferHealth = 0;
}
void Initialize()
{
_healthRecovered = false;
_gravityBombCasualty = false;
_hardMode = false;
_heartExposed = 0;
}
public override void Reset()
{
_Reset();
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
me.SetReactState(ReactStates.Aggressive);
DoCastSelf(SpellIds.Stand);
Initialize();
instance.DoStopCriteriaTimer(CriteriaTimedTypes.Event, Misc.AchievMustDeconstructFaster);
}
public override void EnterCombat(Unit who)
{
Talk(Texts.Aggro);
_EnterCombat();
//Enrage
_scheduler.Schedule(TimeSpan.FromMinutes(10), task =>
{
Talk(Texts.Berserk);
DoCastSelf(SpellIds.Enrage);
});
//Gavity Bomb
_scheduler.Schedule(TimeSpan.FromSeconds(20), Misc.PhaseOneGroup, task =>
{
Unit target = SelectTarget(SelectAggroTarget.Random, 0);
if (target)
DoCast(target, SpellIds.GravityBomb);
task.Repeat(TimeSpan.FromSeconds(20));
});
//Searing Light
_scheduler.Schedule(TimeSpan.FromSeconds(20), Misc.PhaseOneGroup, task =>
{
Unit target = SelectTarget(SelectAggroTarget.Random, 0);
if (target)
DoCast(target, SpellIds.SearingLight);
task.Repeat(TimeSpan.FromSeconds(20));
});
//Tympanic Tantrum
_scheduler.Schedule(TimeSpan.FromSeconds(30), Misc.PhaseOneGroup, task =>
{
Talk(Texts.TympanicTantrum);
Talk(Texts.EmoteTympanicTantrum);
DoCast(SpellIds.TympanicTantrum);
task.Repeat(TimeSpan.FromSeconds(30));
});
instance.DoStartCriteriaTimer(CriteriaTimedTypes.Event, Misc.AchievMustDeconstructFaster);
}
public override void DoAction(int action)
{
switch (action)
{
case Misc.ActionHardMode:
_scheduler.Schedule(TimeSpan.FromMilliseconds(1), task =>
{
SetPhaseOne(true);
});
break;
}
}
public override void KilledUnit(Unit who)
{
if (who.GetTypeId() == TypeId.Player)
Talk(Texts.Slay);
}
public override void JustDied(Unit killer)
{
Talk(Texts.Death);
_JustDied();
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
}
public override void DamageTaken(Unit attacker, ref uint damage)
{
if (!_hardMode && !me.HasReactState(ReactStates.Passive) && !HealthAbovePct(100 - 25 * (_heartExposed + 1)))
ExposeHeart();
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (!me.HasReactState(ReactStates.Passive))
DoMeleeAttackIfReady();
}
public override void PassengerBoarded(Unit who, sbyte seatId, bool apply)
{
if (apply && who.GetEntry() == InstanceCreatureIds.XS013Scrapbot)
{
// Need this so we can properly determine when to expose heart again in damagetaken hook
if (me.GetHealthPct() > (25 * (4 - _heartExposed)))
++_heartExposed;
Talk(Texts.EmoteScrapbot);
DoCast(who, SpellIds.ScrapRepair, true);
_healthRecovered = true;
}
if (apply && seatId == Misc.SeatHeartExposed)
who.CastSpell(who, SpellIds.ExposedHeart); // Channeled
}
public override uint GetData(uint type)
{
switch (type)
{
case XT002Data.HardMode:
return _hardMode ? 1 : 0u;
case XT002Data.HealthRecovered:
return _healthRecovered ? 1 : 0u;
case XT002Data.GravityBombCasualty:
return _gravityBombCasualty ? 1 : 0u;
}
return 0;
}
public override void SetData(uint type, uint data)
{
switch (type)
{
case XT002Data.TransferedHealth:
_transferHealth = data;
break;
case XT002Data.GravityBombCasualty:
_gravityBombCasualty = (data > 0) ? true : false;
break;
}
}
void ExposeHeart()
{
Talk(Texts.HeartOpened);
Talk(Texts.EmoteHeartOpened);
DoCastSelf(SpellIds.Submerge); // WIll make creature untargetable
me.AttackStop();
me.SetReactState(ReactStates.Passive);
Unit heart = me.GetVehicleKit() ? me.GetVehicleKit().GetPassenger(Misc.SeatHeartNormal) : null;
if (heart)
{
heart.CastSpell(heart, SpellIds.HeartOverload);
heart.CastSpell(me, SpellIds.HeartLightningTether);
heart.CastSpell(heart, SpellIds.HeartHealToFull, true);
heart.CastSpell(me, SpellIds.RideVehicleExposed, true);
heart.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
heart.SetFlag(UnitFields.Flags, UnitFlags.Unk29);
}
_scheduler.DelayGroup(Misc.PhaseOneGroup, TimeSpan.FromSeconds(30));
// Start "end of phase 2 timer"
_scheduler.Schedule(TimeSpan.FromSeconds(30), task => { SetPhaseOne(false); });
_heartExposed++;
}
void SetPhaseOne(bool isHardMode)
{
if (isHardMode)
{
me.SetFullHealth();
DoCastSelf(SpellIds.Heartbreak, true);
me.AddLootMode(LootModes.HardMode1);
_hardMode = true;
}
Talk(Texts.HeartClosed);
Talk(Texts.EmoteHeartClosed);
me.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
me.SetReactState(ReactStates.Aggressive);
DoCastSelf(SpellIds.Stand);
//_events.RescheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT / 2);
//_events.RescheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB);
//_events.RescheduleEvent(EVENT_TYMPANIC_TANTRUM, RandomHelper.URand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX));
Unit heart = me.GetVehicleKit() ? me.GetVehicleKit().GetPassenger(Misc.SeatHeartExposed) : null;
if (!heart)
return;
heart.CastSpell(me, SpellIds.HeartRideVehicle, true);
heart.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable);
heart.RemoveFlag(UnitFields.Flags, UnitFlags.Unk29);
heart.RemoveAurasDueToSpell(SpellIds.ExposedHeart);
if (!_hardMode)
{
if (_transferHealth == 0)
_transferHealth = (uint)(heart.GetMaxHealth() - heart.GetHealth());
if (_transferHealth >= me.GetHealth())
_transferHealth = (uint)me.GetHealth() - 1;
me.ModifyHealth(-(int)_transferHealth);
me.LowerPlayerDamageReq(_transferHealth);
}
}
// Achievement related
bool _healthRecovered; // Did a scrapbot recover XT-002's health during the encounter?
bool _hardMode; // Are we in hard mode? Or: was the heart killed during phase 2?
bool _gravityBombCasualty; // Did someone die because of Gravity Bomb damage?
byte _heartExposed;
uint _transferHealth;
}
[Script]
class npc_xt002_heart : ScriptedAI
{
public npc_xt002_heart(Creature creature) : base(creature)
{
_instance = creature.GetInstanceScript();
SetCombatMovement(false);
}
public override void UpdateAI(uint diff) { }
public override void JustDied(Unit killer)
{
Creature xt002 = _instance != null ? ObjectAccessor.GetCreature(me, _instance.GetGuidData(BossIds.Xt002)) : null;
if (!xt002 || xt002.GetAI() == null)
return;
xt002.GetAI().SetData(XT002Data.TransferedHealth, (uint)me.GetHealth());
xt002.GetAI().DoAction(Misc.ActionHardMode);
}
InstanceScript _instance;
}
[Script]
class npc_scrapbot : ScriptedAI
{
public npc_scrapbot(Creature creature) : base(creature)
{
_instance = me.GetInstanceScript();
}
public override void Reset()
{
me.SetReactState(ReactStates.Passive);
Creature pXT002 = ObjectAccessor.GetCreature(me, _instance.GetGuidData(BossIds.Xt002));
if (pXT002)
me.GetMotionMaster().MoveFollow(pXT002, 0.0f, 0.0f);
}
public override void MovementInform(MovementGeneratorType type, uint id)
{
ObjectGuid guid = _instance.GetGuidData(BossIds.Xt002);
if (type == MovementGeneratorType.Follow && id == guid.GetCounter())
{
Creature xt002 = ObjectAccessor.GetCreature(me, guid);
if (xt002)
{
if (me.IsWithinMeleeRange(xt002))
{
DoCast(xt002, SpellIds.ScrapbotRideVehicle);
// Unapply vehicle aura again
xt002.RemoveAurasDueToSpell(SpellIds.ScrapbotRideVehicle);
me.DespawnOrUnsummon();
}
}
}
}
InstanceScript _instance;
}
[Script]
class npc_pummeller : ScriptedAI
{
public npc_pummeller(Creature creature) : base(creature)
{
Initialize();
_instance = creature.GetInstanceScript();
}
void Initialize()
{
_scheduler.SetValidator(() => me.IsWithinMeleeRange(me.GetVictim()));
//Arcing Smash
_scheduler.Schedule(TimeSpan.FromSeconds(27), task =>
{
DoCastVictim(SpellIds.ArcingSmash);
task.Repeat(TimeSpan.FromSeconds(27));
});
//Trample
_scheduler.Schedule(TimeSpan.FromSeconds(22), task =>
{
DoCastVictim(SpellIds.Trample);
task.Repeat(TimeSpan.FromSeconds(22));
});
//Uppercut
_scheduler.Schedule(TimeSpan.FromSeconds(17), task =>
{
DoCastVictim(SpellIds.Uppercut);
task.Repeat(TimeSpan.FromSeconds(17));
});
}
public override void Reset()
{
Initialize();
Creature xt002 = ObjectAccessor.GetCreature(me, _instance.GetGuidData(BossIds.Xt002));
if (xt002)
{
Position pos = xt002.GetPosition();
me.GetMotionMaster().MovePoint(0, pos);
}
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
InstanceScript _instance;
}
class BoomEvent : BasicEvent
{
public BoomEvent(Creature me)
{
_me = me;
}
public override bool Execute(ulong time, uint diff)
{
// This hack is here because we suspect our implementation of spell effect execution on targets
// is done in the wrong order. We suspect that 0 needs to be applied on all targets,
// then 1, etc - instead of applying each effect on target1, then target2, etc.
// The above situation causes the visual for this spell to be bugged, so we remove the instakill
// effect and implement a script hack for that.
_me.CastSpell(_me, SpellIds.Boom, false);
return true;
}
Creature _me;
}
[Script]
class npc_boombot : ScriptedAI
{
public npc_boombot(Creature creature) : base(creature)
{
Initialize();
_instance = creature.GetInstanceScript();
}
void Initialize()
{
_boomed = false;
}
public override void Reset()
{
Initialize();
DoCast(SpellIds.AuraBoombot); // For achievement
// HACK/workaround:
// these values aren't confirmed - lack of data - and the values in DB are incorrect
// these values are needed for correct damage of Boom spell
me.SetFloatValue(UnitFields.MinDamage, 15000.0f);
me.SetFloatValue(UnitFields.MaxDamage, 18000.0f);
// @todo proper waypoints?
Creature pXT002 = ObjectAccessor.GetCreature(me, _instance.GetGuidData(BossIds.Xt002));
if (pXT002)
me.GetMotionMaster().MoveFollow(pXT002, 0.0f, 0.0f);
}
public override void DamageTaken(Unit who, ref uint damage)
{
if (damage >= (me.GetHealth() - me.GetMaxHealth() * 0.5f) && !_boomed)
{
_boomed = true; // Prevent recursive calls
//me.SendSpellInstakillLog(Spells.Boom, me);
//me.DealDamage(me, me.GetHealth(), null, DamageEffectType.NoDamage, SpellSchoolMask.Normal, null, false);
damage = 0;
me.CastSpell(me, SpellIds.Boom, false);
// Visual only seems to work if the instant kill event is delayed or the spell itself is delayed
// Casting done from player and caster source has the same targetinfo flags,
// so that can't be the issue
// See BoomEvent class
// Schedule 1s delayed
//me.m_Events.AddEvent(new BoomEvent(me), me.m_Events.CalculateTime(1 * Time.InMilliseconds));
}
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
// No melee attack
}
InstanceScript _instance;
bool _boomed;
}
[Script]
class npc_life_spark : ScriptedAI
{
public npc_life_spark(Creature creature) : base(creature) { }
void Initialize()
{
_scheduler.Schedule(TimeSpan.FromMilliseconds(1), task =>
{
DoCastVictim(SpellIds.Shock);
task.Repeat(TimeSpan.FromSeconds(12));
});
}
public override void Reset()
{
DoCastSelf(SpellIds.ArcanePowerState);
_scheduler.CancelAll();
}
public override void EnterCombat(Unit victim)
{
DoCastSelf(SpellIds.StaticCharged);
_scheduler.Schedule(TimeSpan.FromSeconds(12), task =>
{
DoCastVictim(SpellIds.Shock);
task.Repeat();
});
}
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
if (me.HasUnitState(UnitState.Casting))
return;
_scheduler.Update(diff, DoMeleeAttackIfReady);
}
}
[Script]
class npc_xt_void_zone : PassiveAI
{
public npc_xt_void_zone(Creature creature) : base(creature) { }
public override void Reset()
{
_scheduler.Schedule(TimeSpan.FromSeconds(1), consumption =>
{
DoCastSelf(SpellIds.Consumption);
consumption.Repeat();
});
}
public override void UpdateAI(uint diff)
{
_scheduler.Update(diff);
}
}
[Script]
class spell_xt002_searing_light_spawn_life_spark : AuraScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.SummonLifeSpark);
}
void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
{
Player player = GetOwner().ToPlayer();
if (player)
{
Unit xt002 = GetCaster();
if (xt002)
if (xt002.HasAura((uint)aurEff.GetAmount())) // Heartbreak aura indicating hard mode
xt002.CastSpell(player, SpellIds.SummonLifeSpark, true);
}
}
public override void Register()
{
AfterEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, AuraType.PeriodicTriggerSpell, AuraEffectHandleModes.Real));
}
}
[Script]
class spell_xt002_gravity_bomb_aura : AuraScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.SummonVoidZone);
}
void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode)
{
Player player = GetOwner().ToPlayer();
if (player)
{
Unit xt002 = GetCaster();
if (xt002)
if (xt002.HasAura((uint)aurEff.GetAmount())) // Heartbreak aura indicating hard mode
xt002.CastSpell(player, SpellIds.SummonVoidZone, true);
}
}
void OnPeriodic(AuraEffect aurEff)
{
Unit xt002 = GetCaster();
if (!xt002)
return;
Unit owner = GetOwner().ToUnit();
if (!owner)
return;
if ((uint)aurEff.GetAmount() >= owner.GetHealth())
if (xt002.GetAI() != null)
xt002.GetAI().SetData(XT002Data.GravityBombCasualty, 1);
}
public override void Register()
{
OnEffectPeriodic.Add(new EffectPeriodicHandler(OnPeriodic, 2, AuraType.PeriodicDamage));
AfterEffectRemove.Add(new EffectApplyHandler(OnRemove, 0, AuraType.PeriodicTriggerSpell, AuraEffectHandleModes.Real));
}
}
[Script]
class spell_xt002_gravity_bomb_damage : SpellScript
{
void HandleScript(uint eff)
{
Unit caster = GetCaster();
if (!caster)
return;
if ((uint)GetHitDamage() >= GetHitUnit().GetHealth())
if (caster.GetAI() != null)
caster.GetAI().SetData(XT002Data.GravityBombCasualty, 1);
}
public override void Register()
{
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.SchoolDamage));
}
}
[Script]
class spell_xt002_heart_overload_periodic : SpellScript
{
public override bool Validate(SpellInfo spell)
{
return ValidateSpellInfo(SpellIds.EnergyOrb, SpellIds.RechargeBoombot, SpellIds.RechargePummeler, SpellIds.RechargeScrapbot);
}
void HandleScript(uint effIndex)
{
Unit caster = GetCaster();
if (caster)
{
InstanceScript instance = caster.GetInstanceScript();
if (instance != null)
{
Unit toyPile = Global.ObjAccessor.GetUnit(caster, instance.GetGuidData(InstanceData.ToyPile0 + RandomHelper.URand(0, 3)));
if (toyPile)
{
caster.CastSpell(toyPile, SpellIds.EnergyOrb, true);
// This should probably be incorporated in a dummy effect handler, but I've had trouble getting the correct target
// Weighed randomization (approximation)
uint[] spells = { SpellIds.RechargeScrapbot, SpellIds.RechargeScrapbot, SpellIds.RechargeScrapbot, SpellIds.RechargePummeler, SpellIds.RechargeBoombot };
for (byte i = 0; i < 5; ++i)
{
uint spellId = spells[RandomHelper.IRand(0, 4)];
toyPile.CastSpell(toyPile, spellId, true, null, null, instance.GetGuidData(BossIds.Xt002));
}
}
}
Creature creatureBase = caster.GetVehicleCreatureBase();
if (creatureBase)
creatureBase.GetAI().Talk(Texts.Summon);
}
}
public override void Register()
{
OnEffectHit.Add(new EffectHandler(HandleScript, 0, SpellEffectName.Dummy));
}
}
[Script]
class spell_xt002_tympanic_tantrum : SpellScript
{
void FilterTargets(List<WorldObject> targets)
{
targets.RemoveAll(new PlayerOrPetCheck());
}
void RecalculateDamage()
{
SetHitDamage((int)GetHitUnit().CountPctFromMaxHealth(GetHitDamage()));
}
public override void Register()
{
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargets, 0, Targets.UnitSrcAreaEnemy));
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargets, 1, Targets.UnitSrcAreaEnemy));
OnHit.Add(new HitHandler(RecalculateDamage));
}
}
[Script]
class spell_xt002_submerged : SpellScript
{
void HandleScript(uint eff)
{
Creature target = GetHitCreature();
if (!target)
return;
target.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable);
target.SetStandState(UnitStandStateType.Submerged);
}
public override void Register()
{
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
}
}
[Script]
class spell_xt002_321_boombot_aura : AuraScript
{
public override bool Validate(SpellInfo spellInfo)
{
return ValidateSpellInfo(SpellIds.AchievementCreditNerfScrapbots);
}
bool CheckProc(ProcEventInfo eventInfo)
{
if (eventInfo.GetActionTarget().GetEntry() != InstanceCreatureIds.XS013Scrapbot)
return false;
return true;
}
void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo)
{
InstanceScript instance = eventInfo.GetActor().GetInstanceScript();
if (instance == null)
return;
instance.DoCastSpellOnPlayers(SpellIds.AchievementCreditNerfScrapbots);
}
public override void Register()
{
DoCheckProc.Add(new CheckProcHandler(CheckProc));
OnEffectProc.Add(new EffectProcHandler(HandleProc, 0, AuraType.Dummy));
}
}
[Script]
class achievement_nerf_engineering : AchievementCriteriaScript
{
public achievement_nerf_engineering() : base("achievement_nerf_engineering") { }
public override bool OnCheck(Player source, Unit target)
{
if (!target || target.GetAI() == null)
return false;
return target.GetAI().GetData(XT002Data.HealthRecovered) == 0;
}
}
[Script]
class achievement_heartbreaker : AchievementCriteriaScript
{
public achievement_heartbreaker() : base("achievement_heartbreaker") { }
public override bool OnCheck(Player source, Unit target)
{
if (!target || target.GetAI() == null)
return false;
return target.GetAI().GetData(XT002Data.HardMode) != 0;
}
}
[Script]
class achievement_nerf_gravity_bombs : AchievementCriteriaScript
{
public achievement_nerf_gravity_bombs() : base("achievement_nerf_gravity_bombs") { }
public override bool OnCheck(Player source, Unit target)
{
if (!target || target.GetAI() == null)
return false;
return target.GetAI().GetData(XT002Data.GravityBombCasualty) == 0;
}
}
}
@@ -0,0 +1,39 @@
/*
* 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 Game.Entities;
namespace Scripts.Northrend.Ulduar
{
class YoggSaron
{
public static Position[] ObservationRingKeepersPos =
{
new Position(1945.682f, 33.34201f, 411.4408f, 5.270895f), // Freya
new Position(1945.761f, -81.52171f, 411.4407f, 1.029744f), // Hodir
new Position(2028.822f, -65.73573f, 411.4426f, 2.460914f), // Thorim
new Position(2028.766f, 17.42014f, 411.4446f, 3.857178f), // Mimiron
};
public static Position[] YSKeepersPos =
{
new Position(2036.873f, 25.42513f, 338.4984f, 3.909538f), // Freya
new Position(1939.045f, -90.87457f, 338.5426f, 0.994837f), // Hodir
new Position(1939.148f, 42.49035f, 338.5427f, 5.235988f), // Thorim
new Position(2036.658f, -73.58822f, 338.4985f, 2.460914f), // Mimiron
};
}
}