From 7e1ecfe22f21011b86d897185738228563c44832 Mon Sep 17 00:00:00 2001 From: CarnifexOptimus <156172553+CarnifexOptimus@users.noreply.github.com> Date: Wed, 29 Jan 2025 09:15:49 +0100 Subject: [PATCH] merge fixes --- BossMod/Autorotation/PlanPresetConverter.cs | 4 +- BossMod/Autorotation/RotationModuleManager.cs | 2 +- BossMod/BossModule/AOEShapes.cs | 23 +- BossMod/BossModule/ArenaBounds.cs | 87 +++-- BossMod/BossModule/BossModule.cs | 3 +- BossMod/BossModule/MiniArena.cs | 24 +- BossMod/BossModule/Shapes.cs | 174 +++++---- BossMod/Components/Cleave.cs | 4 +- BossMod/Components/Tethers.cs | 122 ++++++- BossMod/Config/ColorConfig.cs | 2 +- BossMod/Config/ConfigConverter.cs | 2 +- BossMod/Config/ConfigRoot.cs | 3 +- BossMod/Config/ModuleViewer.cs | 1 - BossMod/Data/Actor.cs | 6 +- BossMod/Data/DeepDungeonState.cs | 28 +- BossMod/Data/WorldState.cs | 7 +- BossMod/Framework/Plugin.cs | 4 +- BossMod/Framework/WorldStateGameSync.cs | 60 ++-- .../Pictomancer/MindOverManor.cs | 2 +- .../FlightOfTheGriffin.cs | 2 +- .../JanquetilaquesPortrait.cs | 2 +- .../SomewhereOnlySheKnows/TheWingedSteed.cs | 2 +- .../Viper/FangsOfTheViper.cs | 2 +- .../Viper/VengeanceOfTheViper.cs | 2 +- .../Quest/{RoleQuests => Role}/AHunterTrue.cs | 2 +- .../AnAntidoteForAnarchy.cs | 2 +- .../{RoleQuests => Role}/DreamsOfANewDay.cs | 2 +- .../HeroesAndPretenders.cs | 4 +- .../TheMightiestShield.cs | 2 +- .../Raid/M01NBIackCat/PredaceousPounce.cs | 6 +- .../Dawntrail/Unreal/Un1Byakko/Un1Byakko.cs | 2 +- .../Alliance/A13Azeyma/WildfireWard.cs | 12 +- .../Alliance/A31Thaliak/Tetraktys.cs | 9 +- .../Quest/Job/Reaper/TheKillingArt.cs | 109 ++++++ .../AncelAndMahaud.cs | 95 +++++ .../LifeEphemeralPathEternal/Guildivain.cs | 125 +++++++ .../Endwalker/Quest/Job/Sage/SagesFocus.cs | 83 +++++ .../LifeEphemeralPathEternal/AncelRockfist.cs | 59 --- .../Quest/LifeEphemeralPathEternal/Enums.cs | 74 ---- .../LifeEphemeralPathEternal/Guildivain.cs | 91 ----- .../AsTheHeavensBurn/P1TerminusIdolizer.cs | 2 +- .../AsTheHeavensBurn/P2TerminusLacerator.cs | 2 +- .../AsTheHeavensBurn/P3TerminusVanquisher.cs | 4 +- BossMod/Modules/Endwalker/Quest/SagesFocus.cs | 65 ---- .../Modules/Endwalker/Quest/TheKillingArt.cs | 87 ----- .../Modules/Endwalker/Ultimate/DSW2/DSW2.cs | 14 +- .../Endwalker/Unreal/Un4Zurvan/Un4Zurvan.cs | 8 +- .../Dungeon/D04TheVault/D042SerGrinnaux.cs | 2 +- .../D053TheEverlivingBibliotaph.cs | 2 +- .../D060Trash1.cs | 8 +- .../Dungeon/D13SohrKhai/D0130CloudGardener.cs | 2 +- .../Extreme/Ext3Thordan/Ex3Thordan.cs | 2 +- .../Heavensward/Quest/DivineIntervention.cs | 63 ---- .../Quest/{ => Job/Dragoon}/DragoonsFate.cs | 36 +- .../Quest/{ => MSQ}/ASpectacleForTheAges.cs | 6 +- .../{ => MSQ}/CloseEncountersOfTheVIthKind.cs | 13 +- .../Quest/MSQ/DivineIntervention.cs | 70 ++++ .../Quest/{ => MSQ}/FlyFreeMyPretty.cs | 53 +-- .../Heavensward/Quest/MSQ/Heliodrome.cs | 125 ------- .../Heavensward/Quest/MSQ/OneLifeOneWorld.cs | 6 +- .../Heavensward/Quest/TheFateOfStars.cs | 50 --- .../Quest/TheWarringTriad/ABloodyReunion.cs | 59 +++ .../Extreme/Ex2Garuda/Ex2Garuda.cs | 6 +- .../Quest/{ => MSQ}/OperationArchon.cs | 31 +- .../RealmReborn/Quest/MSQ/TheStepsOfFaith.cs | 340 ++++++++++++++++++ .../Quest/{ => MSQ}/TheUltimateWeapon.cs | 77 ++-- .../RealmReborn/Quest/TheStepsOfFaith.cs | 263 -------------- .../Raid/T01Caduceus/T01Caduceus.cs | 2 +- .../Raid/T04Gauntlet/T04Gauntlet.cs | 2 +- .../D08AkadaemiaAnyder/D082MorbolMarquis.cs | 19 +- .../Quest/{ => Job/Dancer}/GambolingForGil.cs | 21 +- .../{ => Job/Dancer}/SaveTheLastDanceForMe.cs | 34 +- .../Quest/Job/Gunbreaker/SteelAgainstSteel.cs | 99 +++++ .../Quest/{ => MSQ}/AFeastOfLies.cs | 61 ++-- .../{FullSteamAhead.cs => MSQ/ComingClean.cs} | 51 +-- .../{ => MSQ}/DeathUntoDawn/P1TelotekGamma.cs | 6 +- .../{ => MSQ}/DeathUntoDawn/P2LunarOdin.cs | 45 +-- .../{ => MSQ}/DeathUntoDawn/P3LunarRavana.cs | 17 +- .../{ => MSQ}/DeathUntoDawn/P4LunarIfrit.cs | 16 +- .../Quest/{ => MSQ}/FadedMemories/Ardbert.cs | 53 ++- .../{ => MSQ}/FadedMemories/FadedMemories.cs | 4 +- .../FadedMemories/FlameGeneralAldynn.cs | 9 +- .../{ => MSQ}/FadedMemories/KingThordan.cs | 12 +- .../Quest/{ => MSQ}/FadedMemories/Nidhogg.cs | 10 +- .../Quest/{ => MSQ}/FadedMemories/Zenos.cs | 9 +- .../Quest/MSQ/TheGreatShipVylbrand.cs | 207 +++++++++++ .../Quest/{ => MSQ}/TheOracleOfLight.cs | 14 +- .../Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs | 39 +- .../Quest/{ => Role}/ATearfulReunion.cs | 21 +- .../Quest/{ => Role}/CourageBornOfFear.cs | 27 +- .../Quest/{ => Role}/NyelbertsLament.cs | 21 +- .../Quest/{ => Role}/TheHardenedHeart.cs | 14 +- .../Quest/{ => Role}/TheHuntersLegacy.cs | 23 +- .../TheLostAndTheFound/Sophrosyne.cs | 4 +- .../TheLostAndTheFound/Yxtlilton.cs | 24 +- .../Quest/{ => Role}/TheSoulOfTemperance.cs | 16 +- .../Quest/{ => Role}/ToHaveLovedAndLost.cs | 34 +- .../SleepNowInSapphire/P2SapphireWeapon.cs | 86 ----- .../Shadowbringers/Quest/SteelAgainstSteel.cs | 128 ------- .../Quest/TheGreatShipVylbrand.cs | 116 ------ .../SleepNowInSapphire/P1GuidanceSystem.cs | 6 +- .../SleepNowInSapphire/P2SapphireWeapon.cs | 70 ++++ .../Quest/VowsOfVirtueDeedsOfCruelty.cs | 149 -------- .../SecretKeeper.cs | 2 +- .../Shadowbringers/Ultimate/TEA/TEA.cs | 4 +- .../BaldesionsArsenal/BA1Owain/IvoryPalm.cs | 2 +- .../TheOrphansAndTheBrokenBlade.cs | 12 +- .../Quest/{ => Job/Dragoon}/DragonSound.cs | 6 +- .../Quest/{ => Job/Monk}/ThePowerToProtect.cs | 14 +- .../{ => Job/Paladin}/RaisingTheSword.cs | 14 +- .../Quest/{ => Job/Samurai}/BloodOnTheDeck.cs | 23 +- .../{ => Job/Samurai}/TheBattleOnBekko.cs | 45 +-- .../{ => Job/Samurai}/TheFaceOfTrueEvil.cs | 36 +- .../{ => Job/Scholar}/OurUnsungHeroes.cs | 21 +- .../{ => Job/Summoner}/AnArtForTheLiving.cs | 38 +- .../{ => MSQ}/ARequiemForHeroes/Enums.cs | 13 +- .../Quest/{ => MSQ}/ARequiemForHeroes/P1.cs | 2 +- .../Quest/{ => MSQ}/ARequiemForHeroes/P2.cs | 37 +- .../{ => MSQ}/BestServedWithColdSteel.cs | 29 +- .../Quest/{ => MSQ}/EmissaryOfTheDawn.cs | 10 +- .../Quest/{ => MSQ}/HisForgottenHome.cs | 24 +- .../Quest/{ => MSQ}/HopeOnTheWaves.cs | 23 +- .../Stormblood/Quest/{ => MSQ}/Naadam.cs | 36 +- .../Quest/{ => MSQ}/ReturnOfTheBull.cs | 18 +- .../Quest/{ => MSQ}/RhalgrsBeacon.cs | 10 +- .../Quest/{ => MSQ}/TheMeasureOfHisReach.cs | 20 +- .../Stormblood/Quest/{ => MSQ}/TheResonant.cs | 13 +- .../{ => MSQ}/TheTimeBetweenTheSeconds.cs | 20 +- .../Quest/{ => MSQ}/TheWillOfTheMoon.cs | 46 +-- .../{ => TheFourLords}/TortoiseInTime.cs | 22 +- .../TheHiddenCanalsOfUznair/Airavata.cs | 2 +- .../TheLostCanalsOfUznair/CanalIcebeast.cs | 2 +- .../AltarAiravata.cs | 2 +- .../TheShiftingAltarsOfUznair/AltarArachne.cs | 2 +- .../TheShiftingAltarsOfUznair/AltarBeast.cs | 2 +- .../TheShiftingAltarsOfUznair/AltarChimera.cs | 2 +- .../AltarDiresaur.cs | 2 +- .../AltarDullahan.cs | 2 +- .../TheShiftingAltarsOfUznair/AltarKelpie.cs | 2 +- .../TheShiftingAltarsOfUznair/AltarSkatene.cs | 2 +- .../TheShiftingAltarsOfUznair/AltarTotem.cs | 2 +- .../TheShiftingAltarsOfUznair/TheOlderOne.cs | 2 +- .../TheShiftingAltarsOfUznair/TheWinged.cs | 2 +- .../Modules/Stormblood/Ultimate/UCOB/UCOB.cs | 4 +- .../Ultimate/UWU/P4ViscousAetheroplasm.cs | 2 +- .../Modules/Stormblood/Ultimate/UWU/UWU.cs | 8 +- BossMod/Util/Color.cs | 1 + BossMod/Util/CurveApprox.cs | 12 - 148 files changed, 2402 insertions(+), 2301 deletions(-) rename BossMod/Modules/Dawntrail/Quest/{JobQuests => Job}/Pictomancer/MindOverManor.cs (98%) rename BossMod/Modules/Dawntrail/Quest/{JobQuests => Job}/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs (98%) rename BossMod/Modules/Dawntrail/Quest/{JobQuests => Job}/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs (98%) rename BossMod/Modules/Dawntrail/Quest/{JobQuests => Job}/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs (97%) rename BossMod/Modules/Dawntrail/Quest/{JobQuests => Job}/Viper/FangsOfTheViper.cs (98%) rename BossMod/Modules/Dawntrail/Quest/{JobQuests => Job}/Viper/VengeanceOfTheViper.cs (99%) rename BossMod/Modules/Dawntrail/Quest/{RoleQuests => Role}/AHunterTrue.cs (99%) rename BossMod/Modules/Dawntrail/Quest/{RoleQuests => Role}/AnAntidoteForAnarchy.cs (99%) rename BossMod/Modules/Dawntrail/Quest/{RoleQuests => Role}/DreamsOfANewDay.cs (99%) rename BossMod/Modules/Dawntrail/Quest/{RoleQuests => Role}/HeroesAndPretenders.cs (97%) rename BossMod/Modules/Dawntrail/Quest/{RoleQuests => Role}/TheMightiestShield.cs (99%) create mode 100644 BossMod/Modules/Endwalker/Quest/Job/Reaper/TheKillingArt.cs create mode 100644 BossMod/Modules/Endwalker/Quest/Job/Sage/LifeEphemeralPathEternal/AncelAndMahaud.cs create mode 100644 BossMod/Modules/Endwalker/Quest/Job/Sage/LifeEphemeralPathEternal/Guildivain.cs create mode 100644 BossMod/Modules/Endwalker/Quest/Job/Sage/SagesFocus.cs delete mode 100644 BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/AncelRockfist.cs delete mode 100644 BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/Enums.cs delete mode 100644 BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/Guildivain.cs delete mode 100644 BossMod/Modules/Endwalker/Quest/SagesFocus.cs delete mode 100644 BossMod/Modules/Endwalker/Quest/TheKillingArt.cs delete mode 100644 BossMod/Modules/Heavensward/Quest/DivineIntervention.cs rename BossMod/Modules/Heavensward/Quest/{ => Job/Dragoon}/DragoonsFate.cs (61%) rename BossMod/Modules/Heavensward/Quest/{ => MSQ}/ASpectacleForTheAges.cs (75%) rename BossMod/Modules/Heavensward/Quest/{ => MSQ}/CloseEncountersOfTheVIthKind.cs (79%) create mode 100644 BossMod/Modules/Heavensward/Quest/MSQ/DivineIntervention.cs rename BossMod/Modules/Heavensward/Quest/{ => MSQ}/FlyFreeMyPretty.cs (67%) delete mode 100644 BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs delete mode 100644 BossMod/Modules/Heavensward/Quest/TheFateOfStars.cs create mode 100644 BossMod/Modules/Heavensward/Quest/TheWarringTriad/ABloodyReunion.cs rename BossMod/Modules/RealmReborn/Quest/{ => MSQ}/OperationArchon.cs (54%) create mode 100644 BossMod/Modules/RealmReborn/Quest/MSQ/TheStepsOfFaith.cs rename BossMod/Modules/RealmReborn/Quest/{ => MSQ}/TheUltimateWeapon.cs (58%) delete mode 100644 BossMod/Modules/RealmReborn/Quest/TheStepsOfFaith.cs rename BossMod/Modules/Shadowbringers/Quest/{ => Job/Dancer}/GambolingForGil.cs (75%) rename BossMod/Modules/Shadowbringers/Quest/{ => Job/Dancer}/SaveTheLastDanceForMe.cs (65%) create mode 100644 BossMod/Modules/Shadowbringers/Quest/Job/Gunbreaker/SteelAgainstSteel.cs rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/AFeastOfLies.cs (56%) rename BossMod/Modules/Shadowbringers/Quest/{FullSteamAhead.cs => MSQ/ComingClean.cs} (63%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/DeathUntoDawn/P1TelotekGamma.cs (80%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/DeathUntoDawn/P2LunarOdin.cs (63%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/DeathUntoDawn/P3LunarRavana.cs (85%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/DeathUntoDawn/P4LunarIfrit.cs (64%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/FadedMemories/Ardbert.cs (50%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/FadedMemories/FadedMemories.cs (96%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/FadedMemories/FlameGeneralAldynn.cs (62%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/FadedMemories/KingThordan.cs (72%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/FadedMemories/Nidhogg.cs (50%) rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/FadedMemories/Zenos.cs (61%) create mode 100644 BossMod/Modules/Shadowbringers/Quest/MSQ/TheGreatShipVylbrand.cs rename BossMod/Modules/Shadowbringers/Quest/{ => MSQ}/TheOracleOfLight.cs (67%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/ATearfulReunion.cs (76%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/CourageBornOfFear.cs (73%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/NyelbertsLament.cs (83%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/TheHardenedHeart.cs (90%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/TheHuntersLegacy.cs (71%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/TheLostAndTheFound/Sophrosyne.cs (83%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/TheLostAndTheFound/Yxtlilton.cs (79%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/TheSoulOfTemperance.cs (75%) rename BossMod/Modules/Shadowbringers/Quest/{ => Role}/ToHaveLovedAndLost.cs (65%) delete mode 100644 BossMod/Modules/Shadowbringers/Quest/SleepNowInSapphire/P2SapphireWeapon.cs delete mode 100644 BossMod/Modules/Shadowbringers/Quest/SteelAgainstSteel.cs delete mode 100644 BossMod/Modules/Shadowbringers/Quest/TheGreatShipVylbrand.cs rename BossMod/Modules/Shadowbringers/Quest/{ => TheSorrowOfWerlyt}/SleepNowInSapphire/P1GuidanceSystem.cs (79%) create mode 100644 BossMod/Modules/Shadowbringers/Quest/TheSorrowOfWerlyt/SleepNowInSapphire/P2SapphireWeapon.cs delete mode 100644 BossMod/Modules/Shadowbringers/Quest/VowsOfVirtueDeedsOfCruelty.cs rename BossMod/Modules/Stormblood/Quest/{ => Job/DarkKnight}/TheOrphansAndTheBrokenBlade.cs (77%) rename BossMod/Modules/Stormblood/Quest/{ => Job/Dragoon}/DragonSound.cs (86%) rename BossMod/Modules/Stormblood/Quest/{ => Job/Monk}/ThePowerToProtect.cs (79%) rename BossMod/Modules/Stormblood/Quest/{ => Job/Paladin}/RaisingTheSword.cs (80%) rename BossMod/Modules/Stormblood/Quest/{ => Job/Samurai}/BloodOnTheDeck.cs (52%) rename BossMod/Modules/Stormblood/Quest/{ => Job/Samurai}/TheBattleOnBekko.cs (53%) rename BossMod/Modules/Stormblood/Quest/{ => Job/Samurai}/TheFaceOfTrueEvil.cs (59%) rename BossMod/Modules/Stormblood/Quest/{ => Job/Scholar}/OurUnsungHeroes.cs (68%) rename BossMod/Modules/Stormblood/Quest/{ => Job/Summoner}/AnArtForTheLiving.cs (69%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/ARequiemForHeroes/Enums.cs (77%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/ARequiemForHeroes/P1.cs (96%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/ARequiemForHeroes/P2.cs (58%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/BestServedWithColdSteel.cs (80%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/EmissaryOfTheDawn.cs (80%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/HisForgottenHome.cs (75%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/HopeOnTheWaves.cs (66%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/Naadam.cs (73%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/ReturnOfTheBull.cs (84%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/RhalgrsBeacon.cs (90%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/TheMeasureOfHisReach.cs (58%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/TheResonant.cs (83%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/TheTimeBetweenTheSeconds.cs (76%) rename BossMod/Modules/Stormblood/Quest/{ => MSQ}/TheWillOfTheMoon.cs (72%) rename BossMod/Modules/Stormblood/Quest/{ => TheFourLords}/TortoiseInTime.cs (78%) diff --git a/BossMod/Autorotation/PlanPresetConverter.cs b/BossMod/Autorotation/PlanPresetConverter.cs index 729e120b02..121ba710ed 100644 --- a/BossMod/Autorotation/PlanPresetConverter.cs +++ b/BossMod/Autorotation/PlanPresetConverter.cs @@ -10,8 +10,8 @@ private record class TrackChanges(Dictionary OptionRenames); private record class ModuleChanges(Dictionary TrackChanges, Dictionary TrackRenames); private record class ModuleConverter(Dictionary ModuleChanges, Dictionary ModuleRenames); - public static VersionedJSONSchema PlanSchema = BuildSchema(true); - public static VersionedJSONSchema PresetSchema = BuildSchema(false); + public static readonly VersionedJSONSchema PlanSchema = BuildSchema(true); + public static readonly VersionedJSONSchema PresetSchema = BuildSchema(false); private static VersionedJSONSchema BuildSchema(bool plan) { diff --git a/BossMod/Autorotation/RotationModuleManager.cs b/BossMod/Autorotation/RotationModuleManager.cs index 190ec3867e..db404af416 100644 --- a/BossMod/Autorotation/RotationModuleManager.cs +++ b/BossMod/Autorotation/RotationModuleManager.cs @@ -132,7 +132,7 @@ public void Update(float estimatedAnimLockDelay, bool isMoving) _ => (ResolveTargetOverride(strategy, param)?.Position + off1 * off2.Degrees().ToDirection()) ?? Player?.Position ?? default, }; - public override string ToString() => string.Join(", ", _activeModules?.Select(m => m.Module.GetType().Name) ?? []); + public override string ToString() => string.Join(", ", ActiveModules?.Select(m => m.Module.GetType().Name) ?? []); private IEnumerable FilteredPartyMembers(StrategyPartyFiltering filter) { diff --git a/BossMod/BossModule/AOEShapes.cs b/BossMod/BossModule/AOEShapes.cs index 6a8ee345d9..0a9b7235ba 100644 --- a/BossMod/BossModule/AOEShapes.cs +++ b/BossMod/BossModule/AOEShapes.cs @@ -247,7 +247,8 @@ public RelSimplifiedComplexPolygon GetCombinedPolygon(WPos origin) if (Shapes2 != null) { Polygon = clipper.Simplify(shapes1); - for (var i = 0; i < Shapes2.Count; ++i) + var count = Shapes2.Count; + for (var i = 0; i < count; ++i) { var shape = Shapes2[i]; var singleShapeOperand = CreateOperandFromShape(shape, origin); @@ -312,27 +313,31 @@ public override void Draw(MiniArena arena, WPos origin, Angle rotation, uint col public override void Outline(MiniArena arena, WPos origin, Angle rotation, uint color = 0) { var combinedPolygon = Polygon ?? GetCombinedPolygon(origin); - for (var i = 0; i < combinedPolygon.Parts.Count; ++i) + var count = combinedPolygon.Parts.Count; + for (var i = 0; i < count; ++i) { var part = combinedPolygon.Parts[i]; - var exteriorEdges = part.ExteriorEdges.ToList(); - for (var j = 0; j < exteriorEdges.Count; ++j) + var exteriorEdges = part.ExteriorEdges; + var exteriorCount = exteriorEdges.Count; + for (var j = 0; j < exteriorCount; ++j) { var (start, end) = exteriorEdges[j]; arena.PathLineTo(origin + start); - if (j != exteriorEdges.Count - 1) + if (j != exteriorCount - 1) arena.PathLineTo(origin + end); } MiniArena.PathStroke(true, color); - foreach (var holeIndex in part.Holes) + var lenHoles = part.Holes.Length; + for (var k = 0; k < lenHoles; ++k) { - var interiorEdges = part.InteriorEdges(holeIndex).ToList(); - for (var j = 0; j < interiorEdges.Count; ++j) + var interiorEdges = part.InteriorEdges(part.Holes[k]); + var interiorCount = interiorEdges.Count; + for (var j = 0; j < interiorCount; ++j) { var (start, end) = interiorEdges[j]; arena.PathLineTo(origin + start); - if (j != interiorEdges.Count - 1) + if (j != interiorCount - 1) arena.PathLineTo(origin + end); } MiniArena.PathStroke(true, color); diff --git a/BossMod/BossModule/ArenaBounds.cs b/BossMod/BossModule/ArenaBounds.cs index de0be6bb3a..a155f50340 100644 --- a/BossMod/BossModule/ArenaBounds.cs +++ b/BossMod/BossModule/ArenaBounds.cs @@ -58,9 +58,11 @@ public List ClipAndTriangulateCone(WDir centerOffset, float innerRa (true, false) => CurveApprox.DonutSector(innerRadius, outerRadius, centerDirection - halfAngle, centerDirection + halfAngle, MaxApproxError), (true, true) => CurveApprox.Donut(innerRadius, outerRadius, MaxApproxError), }; - for (var i = 0; i < points.Length; ++i) + var len = points.Length; + var offset = centerOffset; + for (var i = 0; i < len; ++i) { - points[i] += centerOffset; + points[i] += offset; } return ClipAndTriangulate(points); } @@ -68,9 +70,11 @@ public List ClipAndTriangulateCone(WDir centerOffset, float innerRa public List ClipAndTriangulateCircle(WDir centerOffset, float radius) { var points = CurveApprox.Circle(radius, MaxApproxError); - for (var i = 0; i < points.Length; ++i) + var len = points.Length; + var offset = centerOffset; + for (var i = 0; i < len; ++i) { - points[i] += centerOffset; + points[i] += offset; } return ClipAndTriangulate(points); } @@ -78,9 +82,11 @@ public List ClipAndTriangulateCircle(WDir centerOffset, float radiu public List ClipAndTriangulateCapsule(WDir centerOffset, WDir direction, float radius, float length) { var points = CurveApprox.Capsule(direction, length, radius, MaxApproxError); - for (var i = 0; i < points.Length; ++i) + var len = points.Length; + var offset = centerOffset; + for (var i = 0; i < len; ++i) { - points[i] += centerOffset; + points[i] += offset; } return ClipAndTriangulate(points); } @@ -90,9 +96,11 @@ public List ClipAndTriangulateDonut(WDir centerOffset, float innerR if (innerRadius < outerRadius && innerRadius >= 0) { var points = CurveApprox.Donut(innerRadius, outerRadius, MaxApproxError); - for (var i = 0; i < points.Length; ++i) + var len = points.Length; + var offset = centerOffset; + for (var i = 0; i < len; ++i) { - points[i] += centerOffset; + points[i] += offset; } return ClipAndTriangulate(points); } @@ -144,13 +152,18 @@ public sealed record class ArenaBoundsCircle(float Radius, float MapResolution = protected override PolygonClipper.Operand BuildClipPoly() => new((ReadOnlySpan)CurveApprox.Circle(Radius, MaxApproxError)); public override void PathfindMap(Pathfinding.Map map, WPos center) => map.Init(_cachedMap ??= BuildMap(), center); - public override bool Contains(WDir offset) => offset.LengthSq() <= Radius * Radius; + public override bool Contains(WDir offset) + { + var radius = Radius; + return offset.LengthSq() <= radius * radius; + } public override float IntersectRay(WDir originOffset, WDir dir) => Intersect.RayCircle(originOffset, dir, Radius); public override WDir ClampToBounds(WDir offset) { - if (offset.LengthSq() > Radius * Radius) - offset *= Radius / offset.Length(); + var radius = Radius; + if (offset.LengthSq() > radius * radius) + offset *= radius / offset.Length(); return offset; } @@ -177,8 +190,11 @@ private static float CalculateScaleFactor(Angle Rotation) public override void PathfindMap(Pathfinding.Map map, WPos center) => map.Init(_cachedMap ??= BuildMap(), center); private Pathfinding.Map BuildMap() { - var map = new Pathfinding.Map(MapResolution, default, HalfWidth, HalfHeight, Rotation); - map.BlockPixelsInside2(ShapeDistance.InvertedRect(default, Rotation, HalfHeight, HalfHeight, HalfWidth), -1); + var halfWidth = HalfWidth; + var halfHeight = HalfHeight; + var rotation = Rotation; + var map = new Pathfinding.Map(MapResolution, default, halfWidth, halfHeight, rotation); + map.BlockPixelsInside2(ShapeDistance.InvertedRect(default, rotation, halfHeight, halfHeight, halfWidth), -1); return map; } @@ -187,13 +203,16 @@ private Pathfinding.Map BuildMap() public override WDir ClampToBounds(WDir offset) { - var offsetX = offset.Dot(Orientation.OrthoL()); - var offsetY = offset.Dot(Orientation); - if (Math.Abs(offsetX) > HalfWidth) - offsetX = Math.Sign(offsetX) * HalfWidth; - if (Math.Abs(offsetY) > HalfHeight) - offsetY = Math.Sign(offsetY) * HalfHeight; - return Orientation.OrthoL() * offsetX + Orientation * offsetY; + var orientation = Orientation; + var halfWidth = HalfWidth; + var halfHeight = HalfHeight; + var offsetX = offset.Dot(orientation.OrthoL()); + var offsetY = offset.Dot(orientation); + if (Math.Abs(offsetX) > halfWidth) + offsetX = Math.Sign(offsetX) * halfWidth; + if (Math.Abs(offsetY) > halfHeight) + offsetY = Math.Sign(offsetY) * halfHeight; + return orientation.OrthoL() * offsetX + orientation * offsetY; } } @@ -214,11 +233,15 @@ public ArenaBoundsCustom(float Radius, RelSimplifiedComplexPolygon Poly, float M poly = Poly; var edgeList = new List<(WDir, WDir)>(); - for (var i = 0; i < Poly.Parts.Count; ++i) + var count = Poly.Parts.Count; + for (var i = 0; i < count; ++i) { var part = Poly.Parts[i]; edgeList.AddRange(part.ExteriorEdges); - for (var j = 0; j < part.Holes.Length; ++j) + var len = part.Holes.Length; + if (len == 0) + continue; + for (var j = 0; j < len; ++j) { edgeList.AddRange(part.InteriorEdges(j)); } @@ -253,7 +276,8 @@ public override WDir ClampToBounds(WDir offset) } var minDistance = float.MaxValue; var nearestPoint = offset; - for (var i = 0; i < edges.Length; ++i) + var len = edges.Length; + for (var i = 0; i < len; ++i) { ref var edge = ref edges[i]; var edge1 = edge.Item1; @@ -279,21 +303,24 @@ private Pathfinding.Map BuildMap() if (HalfHeight == default) // calculate bounding box if not already done by ArenaBoundsComplex to reduce amount of point in polygon tests { float minX = float.MaxValue, maxX = float.MinValue, minZ = float.MaxValue, maxZ = float.MinValue; - - for (var i = 0; i < polygon.Parts.Count; ++i) + var count = polygon.Parts.Count; + for (var i = 0; i < count; ++i) { var part = polygon.Parts[i]; - for (var j = 0; j < part.Exterior.Length; ++j) + var len = part.Exterior.Length; + for (var j = 0; j < len; ++j) { var vertex = part.Exterior[j]; + var vertexX = vertex.X; + var vertexZ = vertex.Z; if (vertex.X < minX) - minX = vertex.X; + minX = vertexX; if (vertex.X > maxX) - maxX = vertex.X; + maxX = vertexX; if (vertex.Z < minZ) - minZ = vertex.Z; + minZ = vertexZ; if (vertex.Z > maxZ) - maxZ = vertex.Z; + maxZ = vertexZ; } } HalfWidth = (maxX - minX) * Half; diff --git a/BossMod/BossModule/BossModule.cs b/BossMod/BossModule/BossModule.cs index 2dad51035d..198c3e2753 100644 --- a/BossMod/BossModule/BossModule.cs +++ b/BossMod/BossModule/BossModule.cs @@ -36,7 +36,8 @@ public List Enemies(uint oid) public List Enemies(ReadOnlySpan enemies) { List relevantenemies = []; - for (var i = 0; i < enemies.Length; ++i) + var len = enemies.Length; + for (var i = 0; i < len; ++i) { var enemy = enemies[i]; var entry = RelevantEnemies.GetValueOrDefault(enemy); diff --git a/BossMod/BossModule/MiniArena.cs b/BossMod/BossModule/MiniArena.cs index 23358889ae..b9dcfa155d 100644 --- a/BossMod/BossModule/MiniArena.cs +++ b/BossMod/BossModule/MiniArena.cs @@ -281,7 +281,8 @@ public void Zone(List triangulation, uint color = 0) var drawlist = ImGui.GetWindowDrawList(); var restoreFlags = drawlist.Flags; drawlist.Flags &= ~ImDrawListFlags.AntiAliasedFill; - for (var i = 0; i < triangulation.Count; ++i) + var count = triangulation.Count; + for (var i = 0; i < count; ++i) { var tri = triangulation[i]; drawlist.AddTriangleFilled(ScreenCenter + WorldOffsetToScreenOffset(tri.A), ScreenCenter + WorldOffsetToScreenOffset(tri.B), ScreenCenter + WorldOffsetToScreenOffset(tri.C), color != 0 ? color : Colors.AOE); @@ -349,13 +350,13 @@ public void TextWorld(WPos center, string text, uint color, float fontSize = 17) public void Border(uint color) { var dl = ImGui.GetWindowDrawList(); - - for (var i = 0; i < _bounds.ShapeSimplified.Parts.Count; ++i) + var count = _bounds.ShapeSimplified.Parts.Count; + for (var i = 0; i < count; ++i) { var part = _bounds.ShapeSimplified.Parts[i]; Vector2? lastPoint = null; - - for (var j = 0; j < part.Exterior.Length; ++j) + var exteriorLen = part.Exterior.Length; + for (var j = 0; j < exteriorLen; ++j) { var offset = part.Exterior[j]; var currentPoint = ScreenCenter + WorldOffsetToScreenOffset(offset); @@ -366,12 +367,14 @@ public void Border(uint color) dl.PathStroke(color, ImDrawFlags.Closed, 2); - foreach (var holeIndex in part.Holes) + var lenHoles = part.Holes.Length; + for (var l = 0; l < lenHoles; ++l) { lastPoint = null; - var holeInteriorPoints = part.Interior(holeIndex); - for (var k = 0; k < holeInteriorPoints.Length; ++k) + var holeInteriorPoints = part.Interior(part.Holes[l]); + var interiorLen = holeInteriorPoints.Length; + for (var k = 0; k < interiorLen; ++k) { var offset = holeInteriorPoints[k]; var currentPoint = ScreenCenter + WorldOffsetToScreenOffset(offset); @@ -467,7 +470,10 @@ public void Actors(IEnumerable actors, uint color = 0, bool allowDeadAndU public void Actors(List actors, uint color = 0, bool allowDeadAndUntargetable = false) { - for (var i = 0; i < actors.Count; ++i) + var count = actors.Count; + if (count == 0) + return; + for (var i = 0; i < count; ++i) { Actor(actors[i], color == 0 ? Colors.Enemy : color, allowDeadAndUntargetable); } diff --git a/BossMod/BossModule/Shapes.cs b/BossMod/BossModule/Shapes.cs index d8192cd673..ebd40cf634 100644 --- a/BossMod/BossModule/Shapes.cs +++ b/BossMod/BossModule/Shapes.cs @@ -194,39 +194,6 @@ public override List Contour(WPos center) public override string ToString() => $"Cross:{Center.X},{Center.Z},{Length},{HalfWidth},{Rotation}"; } -// Equilateral triangle defined by center, sidelength and rotation -public sealed record class TriangleE(WPos Center, float SideLength, Angle Rotation = default) : Shape -{ - private static readonly float heightFactor = MathF.Sqrt(3) * Half; - - public override List Contour(WPos center) - { - if (Points == null) - { - var height = SideLength * heightFactor; - var halfSideLength = SideLength * Half; - var halfHeight = height * Half; - var (sin, cos) = ((float, float))Math.SinCos(Rotation.Rad); - var halfSideCos = halfSideLength * cos; - var halfSideSin = halfSideLength * sin; - var halfHeightSin = halfHeight * sin; - var halfHeightCos = halfHeight * cos; - Points = - [ - new WDir(halfSideCos - halfHeightSin, halfSideSin + halfHeightCos), - new WDir(-halfSideCos - halfHeightSin, -halfSideSin + halfHeightCos), - new WDir(halfHeightSin, -halfHeight * cos) - ]; - } - var offset = Center - center; - var result = new List(3); - for (var i = 0; i < 3; ++i) - result.Add(Points[i] + offset); - return result; - } - public override string ToString() => $"TriangleE:{Center.X},{Center.Z},{SideLength},{Rotation}"; -} - // for polygons with edge count number of lines of symmetry, eg. pentagons, hexagons and octagons public sealed record class Polygon(WPos Center, float Radius, int Edges, Angle Rotation = default) : Shape { @@ -236,13 +203,13 @@ public override List Contour(WPos center) { var angleIncrement = Angle.DoublePI / Edges; var initialRotation = Rotation.Rad; - var vertices = new List(Edges); + var vertices = new WDir[Edges]; for (var i = 0; i < Edges; ++i) { var (sin, cos) = ((float, float))Math.SinCos(i * angleIncrement + initialRotation); - vertices.Add(new(Center.X + Radius * sin, Center.Z + Radius * cos)); + vertices[i] = new(Center.X + Radius * sin, Center.Z + Radius * cos); } - Points = [.. vertices]; + Points = vertices; } var len = Points.Length; var result = new List(len); @@ -262,10 +229,10 @@ public override List Contour(WPos center) { var points = CurveApprox.CircleSector(Center, Radius, StartAngle, EndAngle, MaxApproxError); var length = points.Length; - var vertices = new List(length); + var vertices = new WDir[length]; for (var i = 0; i < length; ++i) - vertices.Add(points[i] - new WPos()); - Points = [.. vertices]; + vertices[i] = points[i] - new WPos(); + Points = vertices; } var len = Points.Length; var result = new List(len); @@ -310,14 +277,17 @@ public override List Contour(WPos center) { var angleIncrement = 2 * HalfAngle.Rad / Edges; var startAngle = CenterDir.Rad - HalfAngle.Rad; - var vertices = new List(Edges + 1); + var vertices = new WDir[Edges + 2]; + var centerX = Center.X; + var CenterZ = Center.Z; + var radius = Radius; for (var i = 0; i < Edges + 1; ++i) { var (sin, cos) = ((float, float))Math.SinCos(startAngle + i * angleIncrement); - vertices.Add(new(Center.X + Radius * sin, Center.Z + Radius * cos)); + vertices[i] = new(centerX + radius * sin, CenterZ + radius * cos); } - vertices.Add(Center - new WPos()); - Points = [.. vertices]; + vertices[Edges + 1] = Center - new WPos(); + Points = vertices; } var len = Points.Length; var result = new List(len); @@ -338,18 +308,20 @@ public override List Contour(WPos center) { var angleIncrement = 2 * HalfAngle.Rad / Edges; var startAngle = CenterDir.Rad - HalfAngle.Rad; - var vertices = new List(2 * (Edges + 1)); - for (var i = 0; i < Edges + 1; ++i) + var n = Edges + 1; + var vertices = new WDir[2 * n]; + var centerX = Center.X; + var CenterZ = Center.Z; + var innerRadius = InnerRadius; + var outerRadius = OuterRadius; + for (var i = 0; i < n; ++i) { var (sin, cos) = ((float, float))Math.SinCos(startAngle + i * angleIncrement); - vertices.Add(new(Center.X + OuterRadius * sin, Center.Z + OuterRadius * cos)); + vertices[i] = new(centerX + outerRadius * sin, CenterZ + outerRadius * cos); + vertices[2 * n - 1 - i] = new WDir(centerX + innerRadius * sin, CenterZ + innerRadius * cos); } - for (var i = Edges; i >= 0; --i) - { - var (sin, cos) = ((float, float))Math.SinCos(startAngle + i * angleIncrement); - vertices.Add(new(Center.X + InnerRadius * sin, Center.Z + InnerRadius * cos)); - } - Points = [.. vertices]; + + Points = vertices; } var len = Points.Length; var result = new List(len); @@ -369,27 +341,105 @@ public override List Contour(WPos center) if (Points == null) { var angleIncrement = Angle.DoublePI / Edges; - var vertices = new List(2 * (Edges + 1)); - - for (var i = 0; i <= Edges; ++i) + var n = Edges + 1; + var vertices = new WDir[2 * n]; + var centerX = Center.X; + var CenterZ = Center.Z; + var innerRadius = InnerRadius; + var outerRadius = OuterRadius; + for (var i = 0; i < n; ++i) { var (sin, cos) = ((float, float))Math.SinCos(i * angleIncrement); - vertices.Add(new(Center.X + OuterRadius * sin, Center.Z + OuterRadius * cos)); + vertices[i] = new(centerX + outerRadius * sin, CenterZ + outerRadius * cos); + vertices[2 * n - 1 - i] = new(centerX + innerRadius * sin, CenterZ + innerRadius * cos); } + Points = vertices; + } + + var len = Points.Length; + var result = new List(len); + for (var i = 0; i < len; ++i) + result.Add(Points[i] - center); + return result; + } + + public override string ToString() => $"DonutV:{Center.X},{Center.Z},{InnerRadius},{OuterRadius},{Edges}"; +} - for (var i = Edges; i >= 0; --i) +// Approximates an ellipse with a customizable number of edges +public sealed record class Ellipse(WPos Center, float HalfWidth, float HalfHeight, int Edges, Angle Rotation = default) : Shape +{ + public override List Contour(WPos center) + { + if (Points == null) + { + var angleIncrement = Angle.DoublePI / Edges; + var (sinRotation, cosRotation) = ((float, float))Math.SinCos(Rotation.Rad); + var vertices = new WDir[Edges]; + var halfWidth = HalfWidth; + var halfHeight = HalfHeight; + for (var i = 0; i < Edges; ++i) { - var (sin, cos) = ((float, float))Math.SinCos(i * angleIncrement); - vertices.Add(new(Center.X + InnerRadius * sin, Center.Z + InnerRadius * cos)); + var currentAngle = i * angleIncrement; + var (sin, cos) = ((float, float))Math.SinCos(currentAngle); + var x = halfWidth * cos; + var y = halfHeight * sin; + var rotatedX = x * cosRotation - y * sinRotation; + var rotatedY = x * sinRotation + y * cosRotation; + + vertices[i] = new(rotatedX, rotatedY); } - Points = [.. vertices]; + Points = vertices; } + var len = Points.Length; + var offset = Center - center; var result = new List(len); + for (var i = 0; i < len; ++i) - result.Add(Points[i] - center); + result.Add(Points[i] + offset); + return result; } - public override string ToString() => $"DonutV:{Center.X},{Center.Z},{InnerRadius},{OuterRadius},{Edges}"; + public override string ToString() => $"Ellipse:{Center.X},{Center.Z},{HalfWidth},{HalfHeight},{Edges},{Rotation}"; +} + +// Capsule shape defined by center, halfheight, halfwidth (radius), rotation, and number of edges. in this case the halfheight is the distance from capsule center to semicircle centers, +// the edges are per semicircle +public sealed record class Capsule(WPos Center, float HalfHeight, float HalfWidth, int Edges, Angle Rotation = default) : Shape +{ + public override List Contour(WPos center) + { + if (Points == null) + { + var vertices = new WDir[2 * Edges]; + var angleIncrement = MathF.PI / Edges; + var (sinRot, cosRot) = ((float, float))Math.SinCos(Rotation.Rad); + var halfWidth = HalfWidth; + var halfHeight = HalfHeight; + for (var i = 0; i < Edges; ++i) + { + var (sin, cos) = ((float, float))Math.SinCos(i * angleIncrement); + var halfWidthCos = halfWidth * cos; + var halfWidthSin = halfWidth * sin + halfHeight; + var rxTop = halfWidthCos * cosRot - halfWidthSin * sinRot; + var ryTop = halfWidthCos * sinRot + halfWidthSin * cosRot; + vertices[i] = new(rxTop, ryTop); + var rxBot = -rxTop; + var ryBot = -ryTop; + vertices[Edges + i] = new(rxBot, ryBot); + } + Points = vertices; + } + + var offset = Center - center; + var result = new List(Points.Length); + for (var i = 0; i < Points.Length; ++i) + result.Add(Points[i] + offset); + + return result; + } + + public override string ToString() => $"Capsule:{Center.X},{Center.Z},{HalfHeight},{HalfWidth},{Rotation},{Edges}"; } diff --git a/BossMod/Components/Cleave.cs b/BossMod/Components/Cleave.cs index ca2a0b4847..ff163dbd6c 100644 --- a/BossMod/Components/Cleave.cs +++ b/BossMod/Components/Cleave.cs @@ -2,14 +2,14 @@ // generic component for cleaving autoattacks; shows shape outline and warns when anyone other than main target is inside // enemy OID == 0 means 'primary actor' -public class Cleave(BossModule module, ActionID aid, AOEShape shape, uint enemyOID = 0, bool activeForUntargetable = false, bool originAtTarget = false, bool activeWhileCasting = true) : CastCounter(module, aid) +public class Cleave(BossModule module, ActionID aid, AOEShape shape, uint[]? enemyOID = null, bool activeForUntargetable = false, bool originAtTarget = false, bool activeWhileCasting = true) : CastCounter(module, aid) { public readonly AOEShape Shape = shape; public readonly bool ActiveForUntargetable = activeForUntargetable; public readonly bool ActiveWhileCasting = activeWhileCasting; public readonly bool OriginAtTarget = originAtTarget; public DateTime NextExpected; - public readonly List Enemies = module.Enemies(enemyOID != 0 ? enemyOID : module.PrimaryActor.OID); + public readonly List Enemies = module.Enemies(enemyOID ?? [module.PrimaryActor.OID]); public override void AddHints(int slot, Actor actor, TextHints hints) { diff --git a/BossMod/Components/Tethers.cs b/BossMod/Components/Tethers.cs index 533040657d..d1b7576ea2 100644 --- a/BossMod/Components/Tethers.cs +++ b/BossMod/Components/Tethers.cs @@ -105,20 +105,126 @@ public override void OnUntethered(Actor source, ActorTetherInfo tether) if (target == null) return null; - var (player, enemy) = source.Type is ActorType.Player or ActorType.Buddy ? (source, target) : (target, source); - if (player.Type is not ActorType.Player and not ActorType.Buddy || enemy.Type is ActorType.Player or ActorType.Buddy) + var (player, enemy) = Raid.WithoutSlot().Contains(source) ? (source, target) : (target, source); + var playerSlot = Raid.FindSlot(player.InstanceID); + return (playerSlot, player, enemy); + } +} + +// generic component for AOE at tethered targets; players are supposed to intercept tethers and gtfo from the raid +public class InterceptTetherAOE(BossModule module, ActionID aid, uint tetherID, float radius) : CastCounter(module, aid) +{ + // TODO: add forbidden players/NPCs logic + public readonly uint TID = tetherID; + public readonly float Radius = radius; + public readonly List<(Actor Player, Actor Enemy)> Tethers = []; + private BitMask _tetheredPlayers; + private BitMask _inAnyAOE; // players hit by aoe, excluding selves + public DateTime Activation; + + public bool Active => _tetheredPlayers.Any(); + + public override void Update() + { + _inAnyAOE = new(); + foreach (var slot in _tetheredPlayers.SetBits()) { - ReportError($"Unexpected tether pair: {source.InstanceID:X} -> {target.InstanceID:X}"); - return null; + var target = Raid[slot]; + if (target != null) + _inAnyAOE |= Raid.WithSlot().InRadiusExcluding(target, Radius).Mask(); } + } - var playerSlot = Raid.FindSlot(player.InstanceID); - if (playerSlot < 0) + public override void AddHints(int slot, Actor actor, TextHints hints) + { + if (!Active) + return; + if (!_tetheredPlayers[slot]) { - ReportError($"Non-party-member player is tethered: {source.InstanceID:X} -> {target.InstanceID:X}"); - return null; + hints.Add("Grab the tether!"); + } + else if (Raid.WithoutSlot().InRadiusExcluding(actor, Radius).Any()) + { + hints.Add("GTFO from raid!"); + } + else + { + if (_tetheredPlayers[slot]) + { + hints.Add("Hit by baited AOE"); + } + if (_inAnyAOE[slot]) + { + hints.Add("GTFO from baited AOE!"); + } + } + } + + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + var count = Tethers.Count; + if (count == 0) + return; + var raid = Raid.WithoutSlot(); + for (var i = 0; i < count; ++i) + { + var tether = Tethers[i]; + if (tether.Player != actor) + hints.AddForbiddenZone(ShapeDistance.Circle(tether.Player.Position, Radius), Activation); + else + for (var j = 0; j < raid.Length; ++j) + { + ref var member = ref raid[i]; + if (member != actor) + hints.AddForbiddenZone(ShapeDistance.Circle(member.Position, Radius), Activation); + } + } + } + + public override void DrawArenaForeground(int pcSlot, Actor pc) + { + // show tethered targets with circles + var count = Tethers.Count; + if (count == 0) + return; + for (var i = 0; i < count; ++i) + { + var side = Tethers[i]; + Arena.AddLine(side.Enemy.Position, side.Player.Position, side.Player.OID == 0 ? Colors.Safe : 0); + Arena.AddCircle(side.Player.Position, Radius); } + } + public override void OnTethered(Actor source, ActorTetherInfo tether) + { + var sides = DetermineTetherSides(source, tether); + if (sides != null) + { + Tethers.Add((sides.Value.Player, sides.Value.Enemy)); + _tetheredPlayers.Set(sides.Value.PlayerSlot); + } + } + + public override void OnUntethered(Actor source, ActorTetherInfo tether) + { + var sides = DetermineTetherSides(source, tether); + if (sides != null) + { + Tethers.Remove((sides.Value.Player, sides.Value.Enemy)); + _tetheredPlayers.Clear(sides.Value.PlayerSlot); + } + } + + // we support both player->enemy and enemy->player tethers + private (int PlayerSlot, Actor Player, Actor Enemy)? DetermineTetherSides(Actor source, ActorTetherInfo tether) + { + if (tether.ID != TID) + return null; + var target = WorldState.Actors.Find(tether.Target); + if (target == null) + return null; + var (player, enemy) = Raid.WithoutSlot().Contains(source) ? (source, target) : (target, source); + var playerSlot = Raid.FindSlot(player.InstanceID); return (playerSlot, player, enemy); } } diff --git a/BossMod/Config/ColorConfig.cs b/BossMod/Config/ColorConfig.cs index 9df791062a..72f4b2a827 100644 --- a/BossMod/Config/ColorConfig.cs +++ b/BossMod/Config/ColorConfig.cs @@ -44,7 +44,7 @@ public sealed class ColorConfig : ConfigNode public Color ArenaMeleeRangeIndicator = new(0xffff0000); [PropertyDisplay("Arena: other")] - public Color[] ArenaOther = [new(0xffff0080), new(0xff8080ff), new(0xff80ff80), new(0xffff8040), new(0xff40c0c0), new(0x40008080), new(0xffffff00), new(0xffff8000)]; + public Color[] ArenaOther = [new(0xffff0080), new(0xff8080ff), new(0xff80ff80), new(0xffff8040), new(0xff40c0c0), new(0x40008080), new(0xffffff00), new(0xffff8000), new(0xffffa080)]; [PropertyDisplay("Arena: interesting player, important for a mechanic")] public Color ArenaPlayerInteresting = new(0xffc0c0c0); diff --git a/BossMod/Config/ConfigConverter.cs b/BossMod/Config/ConfigConverter.cs index 9503ea4516..f38b124a0a 100644 --- a/BossMod/Config/ConfigConverter.cs +++ b/BossMod/Config/ConfigConverter.cs @@ -6,7 +6,7 @@ namespace BossMod; public static class ConfigConverter { - public static VersionedJSONSchema Schema = BuildSchema(); + public static readonly VersionedJSONSchema Schema = BuildSchema(); private static VersionedJSONSchema BuildSchema() { diff --git a/BossMod/Config/ConfigRoot.cs b/BossMod/Config/ConfigRoot.cs index cd3f25b989..3a7b1f6fd0 100644 --- a/BossMod/Config/ConfigRoot.cs +++ b/BossMod/Config/ConfigRoot.cs @@ -1,12 +1,13 @@ using System.IO; using System.Reflection; +using System.Text.Json; namespace BossMod; public class ConfigRoot { public Event Modified = new(); - + private const int _version = 10; public readonly Dictionary _nodes = []; public List Nodes => [.. _nodes.Values]; diff --git a/BossMod/Config/ModuleViewer.cs b/BossMod/Config/ModuleViewer.cs index a92791f2b4..0531c5f506 100644 --- a/BossMod/Config/ModuleViewer.cs +++ b/BossMod/Config/ModuleViewer.cs @@ -59,7 +59,6 @@ public ModuleViewer(PlanDatabase? planDB, WorldState ws) Customize(BossModuleInfo.Category.DeepDungeon, contentType.GetRow(21)); Customize(BossModuleInfo.Category.Ultimate, contentType.GetRow(28)); Customize(BossModuleInfo.Category.VariantCriterion, contentType.GetRow(30)); - Customize(BossModuleInfo.Category.Chaotic, contentType.GetRow(37)); var playStyle = Service.LuminaSheet()!; Customize(BossModuleInfo.Category.Foray, playStyle.GetRow(6)); diff --git a/BossMod/Data/Actor.cs b/BossMod/Data/Actor.cs index 12ec801f4d..6bfcde68b3 100644 --- a/BossMod/Data/Actor.cs +++ b/BossMod/Data/Actor.cs @@ -133,7 +133,8 @@ public int PendingHPDiffence get { var sum = 0; - for (var i = 0; i < PendingHPDifferences.Count; ++i) + var count = PendingHPDifferences.Count; + for (var i = 0; i < count; ++i) { sum += PendingHPDifferences[i].Value; } @@ -146,7 +147,8 @@ public int PendingMPDiffence get { var sum = 0; - for (var i = 0; i < PendingMPDifferences.Count; ++i) + var count = PendingMPDifferences.Count; + for (var i = 0; i < count; ++i) { sum += PendingMPDifferences[i].Value; } diff --git a/BossMod/Data/DeepDungeonState.cs b/BossMod/Data/DeepDungeonState.cs index 622c3ee9f2..e0979358fc 100644 --- a/BossMod/Data/DeepDungeonState.cs +++ b/BossMod/Data/DeepDungeonState.cs @@ -45,23 +45,25 @@ public readonly record struct PomanderState(byte Count, byte Flags) public PomanderState GetPomanderState(PomanderID pid) => GetPomanderSlot(pid) is var s && s >= 0 ? Pomanders[s] : default; public PomanderID GetPomanderID(int slot) => GetDungeonDefinition().PomanderSlot is var slots && slot >= 0 && slot < slots.Count ? (PomanderID)slots[slot].RowId : PomanderID.None; - public IEnumerable CompareToInitial() + public List CompareToInitial() { + var ops = new List(6); if (DungeonId != DungeonType.None) { - yield return new OpProgressChange(DungeonId, Progress); - yield return new OpMapDataChange(Rooms); - yield return new OpPartyStateChange(Party); - yield return new OpPomandersChange(Pomanders); - yield return new OpChestsChange(Chests); - yield return new OpMagiciteChange(Magicite); + ops.Add(new OpProgressChange(DungeonId, Progress)); + ops.Add(new OpMapDataChange(Rooms)); + ops.Add(new OpPartyStateChange(Party)); + ops.Add(new OpPomandersChange(Pomanders)); + ops.Add(new OpChestsChange(Chests)); + ops.Add(new OpMagiciteChange(Magicite)); } + return ops; } public Event ProgressChanged = new(); public sealed record class OpProgressChange(DungeonType DungeonId, DungeonProgress Value) : WorldState.Operation { - protected override void Exec(WorldState ws) + protected override void Exec(ref WorldState ws) { ws.DeepDungeon.DungeonId = DungeonId; ws.DeepDungeon.Progress = Value; @@ -87,7 +89,7 @@ public sealed record class OpMapDataChange(RoomFlags[] Rooms) : WorldState.Opera { public readonly RoomFlags[] Rooms = Rooms; - protected override void Exec(WorldState ws) + protected override void Exec(ref WorldState ws) { Array.Copy(Rooms, ws.DeepDungeon.Rooms, NumRooms); ws.DeepDungeon.MapDataChanged.Fire(this); @@ -105,7 +107,7 @@ public sealed record class OpPartyStateChange(PartyMember[] Value) : WorldState. { public readonly PartyMember[] Value = Value; - protected override void Exec(WorldState ws) + protected override void Exec(ref WorldState ws) { Array.Copy(Value, ws.DeepDungeon.Party, NumPartyMembers); ws.DeepDungeon.PartyStateChanged.Fire(this); @@ -123,7 +125,7 @@ public sealed record class OpPomandersChange(PomanderState[] Value) : WorldState { public readonly PomanderState[] Value = Value; - protected override void Exec(WorldState ws) + protected override void Exec(ref WorldState ws) { Array.Copy(Value, ws.DeepDungeon.Pomanders, NumPomanderSlots); ws.DeepDungeon.PomandersChanged.Fire(this); @@ -141,7 +143,7 @@ public sealed record class OpChestsChange(Chest[] Value) : WorldState.Operation { public readonly Chest[] Value = Value; - protected override void Exec(WorldState ws) + protected override void Exec(ref WorldState ws) { Array.Copy(Value, ws.DeepDungeon.Chests, NumChests); ws.DeepDungeon.ChestsChanged.Fire(this); @@ -159,7 +161,7 @@ public sealed record class OpMagiciteChange(byte[] Value) : WorldState.Operation { public readonly byte[] Value = Value; - protected override void Exec(WorldState ws) + protected override void Exec(ref WorldState ws) { Array.Copy(Value, ws.DeepDungeon.Magicite, NumMagicites); ws.DeepDungeon.MagiciteChanged.Fire(this); diff --git a/BossMod/Data/WorldState.cs b/BossMod/Data/WorldState.cs index 7271ee6870..01dc1d1cfa 100644 --- a/BossMod/Data/WorldState.cs +++ b/BossMod/Data/WorldState.cs @@ -59,8 +59,8 @@ public List CompareToInitial() var party = Party.CompareToInitial(); var client = Client.CompareToInitial(); var network = Network.CompareToInitial(); - - List ops = new(RSVEntries.Count + waymarks.Count + actors.Count + party.Count + client.Count + network.Count + 2); + var deepdungeon = DeepDungeon.CompareToInitial(); + List ops = new(RSVEntries.Count + waymarks.Count + actors.Count + party.Count + client.Count + network.Count + deepdungeon.Count + 2); if (CurrentTime != default) ops.Add(new OpFrameStart(Frame, default, Client.GaugePayload, Client.CameraAzimuth)); @@ -73,9 +73,8 @@ public List CompareToInitial() ops.AddRange(party); ops.AddRange(client); ops.AddRange(network); + ops.AddRange(deepdungeon); return ops; - foreach (var o in DeepDungeon.CompareToInitial()) - yield return o; } // implementation of operations public Event FrameStarted = new(); diff --git a/BossMod/Framework/Plugin.cs b/BossMod/Framework/Plugin.cs index 00f4d5cf1c..f4b0d073dc 100644 --- a/BossMod/Framework/Plugin.cs +++ b/BossMod/Framework/Plugin.cs @@ -202,7 +202,7 @@ private static void ResetColors() for (var i = 0; i < fields.Length; ++i) { - var field = fields[i]; + ref var field = ref fields[i]; var value = field.GetValue(defaultConfig); if (value is Color or Color[]) field.SetValue(currentConfig, value); @@ -245,7 +245,7 @@ private void DrawUI() _dtr.Update(); Camera.Instance?.Update(); - _wsSync.Update(_prevUpdateTime); + _wsSync.Update(ref _prevUpdateTime); _bossmod.Update(); _zonemod.ActiveModule?.Update(); _hintsBuilder.Update(_hints, PartyState.PlayerSlot, maxCastTime); diff --git a/BossMod/Framework/WorldStateGameSync.cs b/BossMod/Framework/WorldStateGameSync.cs index 970c34d1ba..9eea81f29a 100644 --- a/BossMod/Framework/WorldStateGameSync.cs +++ b/BossMod/Framework/WorldStateGameSync.cs @@ -143,7 +143,7 @@ public void Dispose() _interceptor.Dispose(); } - public unsafe void Update(TimeSpan prevFramePerf) + public unsafe void Update(ref TimeSpan prevFramePerf) { var fwk = Framework.Instance(); _ws.Execute(new WorldState.OpFrameStart @@ -202,9 +202,10 @@ private unsafe void UpdateWaymarks() private unsafe void UpdateActors() { var mgr = GameObjectManager.Instance(); - for (var i = 0; i < _actorsByIndex.Length; ++i) + var len = _actorsByIndex.Length; + for (var i = 0; i < len; ++i) { - var actor = _actorsByIndex[i]; + ref var actor = ref _actorsByIndex[i]; var obj = mgr->Objects.IndexSorted[i].Value; if (obj != null && obj->EntityId == InvalidEntityId) @@ -218,8 +219,7 @@ private unsafe void UpdateActors() if (actor != null && (obj == null || actor.InstanceID != obj->EntityId)) { - _actorsByIndex[i] = null; - RemoveActor(actor); + RemoveActor(ref actor); actor = null; } @@ -229,7 +229,7 @@ private unsafe void UpdateActors() { Service.Log($"[WorldState] Actor position mismatch for #{i} {actor}"); } - UpdateActor(obj, i, actor); + UpdateActor(ref obj, i, ref actor); } } @@ -238,13 +238,14 @@ private unsafe void UpdateActors() _actorOps.Clear(); } - private void RemoveActor(Actor actor) + private void RemoveActor(ref Actor actor) { - DispatchActorEvents(actor.InstanceID); - _ws.Execute(new ActorState.OpDestroy(actor.InstanceID)); + var id = actor.InstanceID; + DispatchActorEvents(id); + _ws.Execute(new ActorState.OpDestroy(id)); } - private unsafe void UpdateActor(GameObject* obj, int index, Actor? act) + private unsafe void UpdateActor(ref GameObject* obj, int index, ref Actor? act) { var chr = obj->IsCharacter() ? (Character*)obj : null; var name = obj->NameString; @@ -332,7 +333,7 @@ private unsafe void UpdateActor(GameObject* obj, int index, Actor? act) TotalTime = castInfo->BaseCastTime, Interruptible = castInfo->Interruptible != 0, } : null; - UpdateActorCastInfo(act, curCast); + UpdateActorCastInfo(ref act, ref curCast); } var sm = chr != null ? chr->GetStatusManager() : null; @@ -352,21 +353,22 @@ private unsafe void UpdateActor(GameObject* obj, int index, Actor? act) curStatus.Extra = s.Param; curStatus.ExpireAt = _ws.CurrentTime.AddSeconds(dur); } - UpdateActorStatus(act, i, curStatus); + UpdateActorStatus(ref act, i, ref curStatus); } } var aeh = chr != null ? chr->GetActionEffectHandler() : null; if (aeh != null) { - for (int i = 0; i < aeh->IncomingEffects.Length; ++i) + var len = aeh->IncomingEffects.Length; + for (var i = 0; i < len; ++i) { ref var eff = ref aeh->IncomingEffects[i]; ref var prev = ref act.IncomingEffects[i]; if ((prev.GlobalSequence, prev.TargetIndex) != (eff.GlobalSequence != 0 ? (eff.GlobalSequence, eff.TargetIndex) : (0, 0))) { var effects = new ActionEffects(); - for (int j = 0; j < ActionEffects.MaxCount; ++j) + for (var j = 0; j < ActionEffects.MaxCount; ++j) effects[j] = *(ulong*)eff.Effects.Effects.GetPointer(j); _ws.Execute(new ActorState.OpIncomingEffect(act.InstanceID, i, new(eff.GlobalSequence, eff.TargetIndex, eff.Source, new((ActionType)eff.ActionType, eff.ActionId), effects))); } @@ -374,16 +376,17 @@ private unsafe void UpdateActor(GameObject* obj, int index, Actor? act) } } - private void UpdateActorCastInfo(Actor act, ActorCastInfo? cast) + private void UpdateActorCastInfo(ref Actor act, ref ActorCastInfo? cast) { - if (cast == null && act.CastInfo == null) + ref var castInfo = ref act.CastInfo; + if (cast == null && castInfo == null) return; // was not casting and is not casting - if (cast != null && act.CastInfo != null && cast.Action == act.CastInfo.Action && cast.TargetID == act.CastInfo.TargetID && cast.TotalTime == act.CastInfo.TotalTime && Math.Abs(cast.ElapsedTime - act.CastInfo.ElapsedTime) < 0.2) + if (cast != null && castInfo != null && cast.Action == castInfo.Action && cast.TargetID == castInfo.TargetID && cast.TotalTime == castInfo.TotalTime && Math.Abs(cast.ElapsedTime - castInfo.ElapsedTime) < 0.2) { // continuing casting same spell // TODO: consider *not* ignoring elapsed differences, these probably mean we're doing something wrong... - act.CastInfo.ElapsedTime = cast.ElapsedTime; + castInfo.ElapsedTime = cast.ElapsedTime; return; } @@ -391,7 +394,7 @@ private void UpdateActorCastInfo(Actor act, ActorCastInfo? cast) _ws.Execute(new ActorState.OpCastInfo(act.InstanceID, cast)); } - private void UpdateActorStatus(Actor act, int index, ActorStatus value) + private void UpdateActorStatus(ref Actor act, int index, ref ActorStatus value) { // note: some statuses have non-zero remaining time but never tick down (e.g. FC buffs); currently we ignore that fact, to avoid log spam... // note: RemainingTime is not monotonously decreasing (I assume because it is really calculated by game and frametime fluctuates...), we ignore 'slight' duration increases (<1 sec) @@ -509,9 +512,10 @@ private unsafe void UpdatePartyNormal(GroupManager.Group* group, PartyMember* pl } // consider buddies as party members too var ui = UIState.Instance(); - for (var i = 0; i < ui->Buddy.DutyHelperInfo.ENpcIds.Length; ++i) + var len = ui->Buddy.DutyHelperInfo.ENpcIds.Length; + for (var i = 0; i < len; ++i) { - var instanceID = ui->Buddy.DutyHelperInfo.DutyHelpers[i].EntityId; + ref var instanceID = ref ui->Buddy.DutyHelperInfo.DutyHelpers[i].EntityId; if (instanceID != InvalidEntityId && _ws.Party.FindSlot(instanceID) < 0) { var obj = GameObjectManager.Instance()->Objects.GetObjectByEntityId(instanceID); @@ -566,7 +570,8 @@ private unsafe void UpdatePartyNPCs() private unsafe bool HasBuddy(ulong instanceID) { var ui = UIState.Instance(); - for (var i = 0; i < ui->Buddy.DutyHelperInfo.ENpcIds.Length; ++i) + var len = ui->Buddy.DutyHelperInfo.ENpcIds.Length; + for (var i = 0; i < len; ++i) if (ui->Buddy.DutyHelperInfo.DutyHelpers[i].EntityId == instanceID) return true; return false; @@ -725,9 +730,12 @@ private void DispatchActorEvents(ulong instanceID) var ops = _actorOps.GetValueOrDefault(instanceID); if (ops == null) return; - - foreach (var op in ops) + var count = ops.Count; + for (var i = 0; i < count; ++i) + { + var op = ops[i]; _ws.Execute(op); + } _actorOps.Remove(instanceID); } @@ -737,7 +745,7 @@ private void DispatchActorEvents(ulong instanceID) var res = new List<(int, Cooldown)>(max); for (int i = 0, cnt = max; i < cnt; ++i) { - var value = values[i]; + ref var value = ref values[i]; if (value != reference[i]) res.Add((i, value)); } @@ -750,7 +758,7 @@ private void DispatchActorEvents(ulong instanceID) var res = new List<(BozjaHolsterID, byte)>(len); for (var i = 0; i < len; ++i) { - var content = contents[i]; + ref var content = ref contents[i]; if (content != 0) res.Add(((BozjaHolsterID)i, content)); } diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/MindOverManor.cs b/BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/MindOverManor.cs similarity index 98% rename from BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/MindOverManor.cs rename to BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/MindOverManor.cs index 9b39e3ff5e..73f9189c4f 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/MindOverManor.cs +++ b/BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/MindOverManor.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.JobQuests.Pictomancer.MindOverManor; +namespace BossMod.Dawntrail.Quest.Job.Pictomancer.MindOverManor; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs b/BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs similarity index 98% rename from BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs rename to BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs index ea79876c31..caf2978263 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs +++ b/BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/FlightOfTheGriffin.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.JobQuests.Pictomancer.SomewhereOnlySheKnows.FlightOfTheGriffin; +namespace BossMod.Dawntrail.Quest.Job.Pictomancer.SomewhereOnlySheKnows.FlightOfTheGriffin; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs b/BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs similarity index 98% rename from BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs rename to BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs index f8e32487f5..c856c3202c 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs +++ b/BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/JanquetilaquesPortrait.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.JobQuests.Pictomancer.SomewhereOnlySheKnows.JanquetilaquesPortrait; +namespace BossMod.Dawntrail.Quest.Job.Pictomancer.SomewhereOnlySheKnows.JanquetilaquesPortrait; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs b/BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs similarity index 97% rename from BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs rename to BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs index 2410fa024d..3f865585ba 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs +++ b/BossMod/Modules/Dawntrail/Quest/Job/Pictomancer/SomewhereOnlySheKnows/TheWingedSteed.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.JobQuests.Pictomancer.SomewhereOnlySheKnows.TheWingedSteed; +namespace BossMod.Dawntrail.Quest.Job.Pictomancer.SomewhereOnlySheKnows.TheWingedSteed; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/FangsOfTheViper.cs b/BossMod/Modules/Dawntrail/Quest/Job/Viper/FangsOfTheViper.cs similarity index 98% rename from BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/FangsOfTheViper.cs rename to BossMod/Modules/Dawntrail/Quest/Job/Viper/FangsOfTheViper.cs index 2f3b3e2bef..9d77380d7f 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/FangsOfTheViper.cs +++ b/BossMod/Modules/Dawntrail/Quest/Job/Viper/FangsOfTheViper.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.JobQuests.Viper.FangsOfTheViper; +namespace BossMod.Dawntrail.Quest.Job.Viper.FangsOfTheViper; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/VengeanceOfTheViper.cs b/BossMod/Modules/Dawntrail/Quest/Job/Viper/VengeanceOfTheViper.cs similarity index 99% rename from BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/VengeanceOfTheViper.cs rename to BossMod/Modules/Dawntrail/Quest/Job/Viper/VengeanceOfTheViper.cs index 99a2e039ac..01890d1951 100644 --- a/BossMod/Modules/Dawntrail/Quest/JobQuests/Viper/VengeanceOfTheViper.cs +++ b/BossMod/Modules/Dawntrail/Quest/Job/Viper/VengeanceOfTheViper.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.JobQuests.Viper.VengeanceOfTheViper; +namespace BossMod.Dawntrail.Quest.Job.Viper.VengeanceOfTheViper; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/RoleQuests/AHunterTrue.cs b/BossMod/Modules/Dawntrail/Quest/Role/AHunterTrue.cs similarity index 99% rename from BossMod/Modules/Dawntrail/Quest/RoleQuests/AHunterTrue.cs rename to BossMod/Modules/Dawntrail/Quest/Role/AHunterTrue.cs index fa143323d5..9a78325314 100644 --- a/BossMod/Modules/Dawntrail/Quest/RoleQuests/AHunterTrue.cs +++ b/BossMod/Modules/Dawntrail/Quest/Role/AHunterTrue.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.RoleQuests.AHunterTrue; +namespace BossMod.Dawntrail.Quest.Role.AHunterTrue; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/RoleQuests/AnAntidoteForAnarchy.cs b/BossMod/Modules/Dawntrail/Quest/Role/AnAntidoteForAnarchy.cs similarity index 99% rename from BossMod/Modules/Dawntrail/Quest/RoleQuests/AnAntidoteForAnarchy.cs rename to BossMod/Modules/Dawntrail/Quest/Role/AnAntidoteForAnarchy.cs index 0945693de7..c3fea46824 100644 --- a/BossMod/Modules/Dawntrail/Quest/RoleQuests/AnAntidoteForAnarchy.cs +++ b/BossMod/Modules/Dawntrail/Quest/Role/AnAntidoteForAnarchy.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.RoleQuests.AnAntidoteForAnarchy; +namespace BossMod.Dawntrail.Quest.Role.AnAntidoteForAnarchy; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/RoleQuests/DreamsOfANewDay.cs b/BossMod/Modules/Dawntrail/Quest/Role/DreamsOfANewDay.cs similarity index 99% rename from BossMod/Modules/Dawntrail/Quest/RoleQuests/DreamsOfANewDay.cs rename to BossMod/Modules/Dawntrail/Quest/Role/DreamsOfANewDay.cs index 07be8f87b2..793dd5c1b0 100644 --- a/BossMod/Modules/Dawntrail/Quest/RoleQuests/DreamsOfANewDay.cs +++ b/BossMod/Modules/Dawntrail/Quest/Role/DreamsOfANewDay.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.RoleQuests.DreamsOfANewDay; +namespace BossMod.Dawntrail.Quest.Role.DreamsOfANewDay; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Quest/RoleQuests/HeroesAndPretenders.cs b/BossMod/Modules/Dawntrail/Quest/Role/HeroesAndPretenders.cs similarity index 97% rename from BossMod/Modules/Dawntrail/Quest/RoleQuests/HeroesAndPretenders.cs rename to BossMod/Modules/Dawntrail/Quest/Role/HeroesAndPretenders.cs index a43667b886..6b234883bf 100644 --- a/BossMod/Modules/Dawntrail/Quest/RoleQuests/HeroesAndPretenders.cs +++ b/BossMod/Modules/Dawntrail/Quest/Role/HeroesAndPretenders.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.RoleQuests.HeroesAndPretenders; +namespace BossMod.Dawntrail.Quest.Role.HeroesAndPretenders; public enum OID : uint { @@ -63,6 +63,8 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) if ((AID)spell.Action.ID is AID.ForeseenFlurryFirst or AID.ForeseenFlurryRest) { var index = Lines.FindIndex(item => item.Next.AlmostEqual(caster.Position, 1)); + if (index < 0) + return; AdvanceLine(Lines[index], caster.Position); if (Lines[index].ExplosionsLeft == 0) Lines.RemoveAt(index); diff --git a/BossMod/Modules/Dawntrail/Quest/RoleQuests/TheMightiestShield.cs b/BossMod/Modules/Dawntrail/Quest/Role/TheMightiestShield.cs similarity index 99% rename from BossMod/Modules/Dawntrail/Quest/RoleQuests/TheMightiestShield.cs rename to BossMod/Modules/Dawntrail/Quest/Role/TheMightiestShield.cs index 14f2ab7d6e..2474cd15a8 100644 --- a/BossMod/Modules/Dawntrail/Quest/RoleQuests/TheMightiestShield.cs +++ b/BossMod/Modules/Dawntrail/Quest/Role/TheMightiestShield.cs @@ -1,4 +1,4 @@ -namespace BossMod.Dawntrail.Quest.RoleQuests.TheMightiestShield; +namespace BossMod.Dawntrail.Quest.Role.TheMightiestShield; public enum OID : uint { diff --git a/BossMod/Modules/Dawntrail/Raid/M01NBIackCat/PredaceousPounce.cs b/BossMod/Modules/Dawntrail/Raid/M01NBIackCat/PredaceousPounce.cs index 51fc7e091e..41c5a1ffb1 100644 --- a/BossMod/Modules/Dawntrail/Raid/M01NBIackCat/PredaceousPounce.cs +++ b/BossMod/Modules/Dawntrail/Raid/M01NBIackCat/PredaceousPounce.cs @@ -18,14 +18,14 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) var count = _aoes.Count; if (count == 0) return []; - List aoes = new(count); + var aoes = new AOEInstance[count]; for (var i = 0; i < count; ++i) { var aoe = _aoes[i]; if (i < 2) - aoes.Add(count > 2 ? aoe with { Color = Colors.Danger } : aoe); + aoes[i] = count > 2 ? aoe with { Color = Colors.Danger } : aoe; else - aoes.Add(aoe); + aoes[i] = aoe; } return aoes; } diff --git a/BossMod/Modules/Dawntrail/Unreal/Un1Byakko/Un1Byakko.cs b/BossMod/Modules/Dawntrail/Unreal/Un1Byakko/Un1Byakko.cs index a3ede32c94..7e9af9c8c8 100644 --- a/BossMod/Modules/Dawntrail/Unreal/Un1Byakko/Un1Byakko.cs +++ b/BossMod/Modules/Dawntrail/Unreal/Un1Byakko/Un1Byakko.cs @@ -4,7 +4,7 @@ class StormPulseRepeat(BossModule module) : Components.CastCounter(module, Actio class HeavenlyStrike(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.HeavenlyStrike), new AOEShapeCircle(3), true); class FireAndLightningBoss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FireAndLightningBoss), new AOEShapeRect(54.3f, 10)); class FireAndLightningAdd(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FireAndLightningAdd), new AOEShapeRect(54.75f, 10)); -class SteelClaw(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.SteelClaw), new AOEShapeCone(17.75f, 30.Degrees()), (uint)OID.Hakutei); // TODO: verify angle +class SteelClaw(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.SteelClaw), new AOEShapeCone(17.75f, 60.Degrees()), [(uint)OID.Hakutei]); class WhiteHerald(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.WhiteHerald, ActionID.MakeSpell(AID.WhiteHerald), 15, 5.1f); // TODO: verify falloff class DistantClap(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DistantClap), new AOEShapeDonut(4, 25)); class SweepTheLegBoss(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SweepTheLegBoss), new AOEShapeCone(28.3f, 135.Degrees())); diff --git a/BossMod/Modules/Endwalker/Alliance/A13Azeyma/WildfireWard.cs b/BossMod/Modules/Endwalker/Alliance/A13Azeyma/WildfireWard.cs index cfef957f32..39a61cc311 100644 --- a/BossMod/Modules/Endwalker/Alliance/A13Azeyma/WildfireWard.cs +++ b/BossMod/Modules/Endwalker/Alliance/A13Azeyma/WildfireWard.cs @@ -3,10 +3,9 @@ class WildfireWard(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.IlluminatingGlimpse), 15, false, 1, kind: Kind.DirLeft); class ArenaBounds(BossModule module) : Components.GenericAOEs(module) { - private static readonly WPos triangleCenter = new(-750, -753.325f); - private static readonly TriangleE triangle = new(triangleCenter, 24); - private static readonly AOEShapeCustom triangleCutOut = new([new Circle(A13Azeyma.NormalCenter, 29.5f)], [triangle]); - private static readonly ArenaBoundsComplex triangleBounds = new([triangle]); + private static readonly Polygon[] triangle = [new(A13Azeyma.NormalCenter, 13.279f, 3, 180.Degrees())]; + private static readonly AOEShapeCustom triangleCutOut = new([new Square(A13Azeyma.NormalCenter, 29.5f)], triangle); + private static readonly ArenaBoundsComplex triangleBounds = new(triangle); private AOEInstance? _aoe; @@ -22,10 +21,13 @@ public override void OnEventEnvControl(byte index, uint state) { _aoe = null; Arena.Bounds = triangleBounds; - Arena.Center = triangleCenter; + Arena.Center = triangleBounds.Center; } else if (state == 0x00080004) + { Arena.Bounds = A13Azeyma.NormalBounds; + Arena.Center = A13Azeyma.NormalCenter; + } } } } diff --git a/BossMod/Modules/Endwalker/Alliance/A31Thaliak/Tetraktys.cs b/BossMod/Modules/Endwalker/Alliance/A31Thaliak/Tetraktys.cs index 38de1bac0a..313cac2ea3 100644 --- a/BossMod/Modules/Endwalker/Alliance/A31Thaliak/Tetraktys.cs +++ b/BossMod/Modules/Endwalker/Alliance/A31Thaliak/Tetraktys.cs @@ -4,10 +4,9 @@ class TetraktysBorder(BossModule module) : Components.GenericAOEs(module) { public static readonly WPos NormalCenter = new(-945, 945); public static readonly ArenaBoundsSquare NormalBounds = new(24); - private static readonly WPos TriangleCenter = new(-945, 941.5f); - private static readonly TriangleE triangle = new(TriangleCenter, 48); - private static readonly ArenaBoundsComplex TriangleBounds = new([triangle]); - private static readonly AOEShapeCustom transition = new([new Square(NormalCenter, 24)], [triangle]); + private static readonly Polygon[] triangle = [new(new(-945, 948.71267f), 27.71281f, 3, 180.Degrees())]; + private static readonly ArenaBoundsComplex TriangleBounds = new(triangle); + private static readonly AOEShapeCustom transition = new([new Square(NormalCenter, 24)], triangle); private AOEInstance? _aoe; public bool Active; @@ -25,7 +24,7 @@ public override void OnEventEnvControl(byte index, uint state) case 0x00020001: _aoe = null; Arena.Bounds = TriangleBounds; - Arena.Center = TriangleCenter; + Arena.Center = TriangleBounds.Center; Active = true; break; case 0x00080004: diff --git a/BossMod/Modules/Endwalker/Quest/Job/Reaper/TheKillingArt.cs b/BossMod/Modules/Endwalker/Quest/Job/Reaper/TheKillingArt.cs new file mode 100644 index 0000000000..d07ca0bf89 --- /dev/null +++ b/BossMod/Modules/Endwalker/Quest/Job/Reaper/TheKillingArt.cs @@ -0,0 +1,109 @@ +namespace BossMod.Endwalker.Quest.Job.Reaper.TheKillingArt; + +public enum OID : uint +{ + Boss = 0x3664, // R1.5 + VoidHecteyes = 0x3666, // R1.2 + VoidPersona = 0x3667, // R1.2 + Voidzone = 0x1E963D, + Helper = 0x233C +} + +public enum AID : uint +{ + AutoAttack1 = 870, // Boss/VoidPersona->player/Drusilla, no cast, single-target + AutoAttack2 = 872, // VoidHecteyes->player/Drusilla, no cast, single-target + + VoidCall = 27589, // Boss->self, 4.0s cast, single-target + MeatySliceVisual = 27590, // Boss->self, 3.4+0.6s cast, single-target + MeatySlice = 27591, // Helper->self, 4.0s cast, range 50 width 12 rect + CleaverVisual = 27594, // Boss->self, 3.5+0.5s cast, single-target + Cleaver = 27595, // Helper->self, 4.0s cast, range 40 120-degree cone + FlankCleaverVisual = 27596, // Boss->self, 3.5+0.5s cast, single-target + FlankCleaver = 27597, // Helper->self, 4.0s cast, range 40 120-degree cone + Explosion1 = 27606, // VoidHecteyes->self, 20.0s cast, range 60 circle + Explosion2 = 27607, // VoidPersona->self, 20.0s cast, range 50 circle + FocusInferiVisual = 27592, // Boss->self, 2.9+0.6s cast, single-target + FocusInferi = 27593, // Helper->location, 3.5s cast, range 6 circle + CarnemLevareVisual = 27598, // Boss->self, 4.0s cast, single-target + CarnemLevare1 = 27599, // Helper->self, 4.0s cast, range 40 width 8 cross + CarnemLevare2 = 27602, // Helper->self, 3.5s cast, range 12-17 180-degree donut sector + CarnemLevare3 = 27600, // Helper->self, 3.5s cast, range 2-7 180-degree donut sector + CarnemLevare4 = 27603, // Helper->self, 3.5s cast, range 17-22 180-degree donut sector + CarnemLevare5 = 27601, // Helper->self, 3.5s cast, range 7-12 180-degree donut sector + VoidMortar = 27604, // Boss->self, 4.0+1.0s cast, single-target + VoidMortar1 = 27605 // Helper->self, 5.0s cast, range 13 circle +} + +class VoidMortar(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.VoidMortar1), 13); +class FocusInferi(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6, ActionID.MakeSpell(AID.FocusInferi), m => m.Enemies(OID.Voidzone).Where(x => x.EventState != 7), 0); +class CarnemLevareCross(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CarnemLevare1), new AOEShapeCross(40, 4)); + +class CarnemLevareDonut(BossModule module) : Components.GenericAOEs(module) +{ + private readonly List _aoes = new(4); + private static readonly Angle a90 = 90.Degrees(); + private static readonly AOEShapeDonutSector[] sectors = [new(12, 17, a90), new(2, 7, a90), new(17, 22, a90), new(7, 12, a90)]; + + public override IEnumerable ActiveAOEs(int slot, Actor actor) + { + var count = _aoes.Count; + if (count == 0) + return []; + var max = count > 4 ? 4 : count; + var aoes = new AOEInstance[max]; + for (var i = 0; i < max; ++i) + aoes[i] = _aoes[i]; + return aoes; + } + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + var shape = (AID)spell.Action.ID switch + { + AID.CarnemLevare2 => sectors[0], + AID.CarnemLevare3 => sectors[1], + AID.CarnemLevare4 => sectors[2], + AID.CarnemLevare5 => sectors[3], + _ => null + }; + + if (shape != null) + _aoes.Add(new(shape, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell))); + } + + public override void OnCastFinished(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID is AID.CarnemLevare2 or AID.CarnemLevare3 or AID.CarnemLevare4 or AID.CarnemLevare5) + _aoes.RemoveAt(0); + } +} +class MeatySlice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MeatySlice), new AOEShapeRect(50, 6)); + +abstract class Cleave(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(40, 60.Degrees())); +class Cleaver(BossModule module) : Cleave(module, AID.Cleaver); +class FlankCleaver(BossModule module) : Cleave(module, AID.FlankCleaver); + +class Adds(BossModule module) : Components.AddsMulti(module, [(uint)OID.VoidHecteyes, (uint)OID.VoidPersona], 1); + +class OrcusStates : StateMachineBuilder +{ + public OrcusStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69614, NameID = 10581)] +public class Orcus(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) +{ + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-69.569f, -388), 19.5f, 64)], [new Rectangle(new(-69, -368), 20, 0.94f)]); +} diff --git a/BossMod/Modules/Endwalker/Quest/Job/Sage/LifeEphemeralPathEternal/AncelAndMahaud.cs b/BossMod/Modules/Endwalker/Quest/Job/Sage/LifeEphemeralPathEternal/AncelAndMahaud.cs new file mode 100644 index 0000000000..fb02e799c1 --- /dev/null +++ b/BossMod/Modules/Endwalker/Quest/Job/Sage/LifeEphemeralPathEternal/AncelAndMahaud.cs @@ -0,0 +1,95 @@ +namespace BossMod.Endwalker.Quest.Job.Sage.LifeEphemeralPathEternal.AncelAndMahaud; + +public enum OID : uint +{ + Boss = 0x35C5, // R0.5 + MahaudFlamehand = 0x35C4, // R0.5 + ChiBomb = 0x35C7, // R1.0 + Helper = 0x233C, // R0.5 +} + +public enum AID : uint +{ + AutoAttack = 872, // Boss->Lalah, no cast, single-target + Teleport1 = 26868, // Boss->location, no cast, single-target + Teleport2 = 26869, // MahaudFlamehand->location, no cast, single-target + + ChiBlastVisual = 26838, // Boss->self, 5.0s cast, single-target + ChiBlast = 26839, // Helper->self, 5.0s cast, range 100 circle + ChiBomb = 26835, // Boss->self, 5.0s cast, single-target + + Explosion = 26837, // ChiBomb->self, 5.0s cast, range 6 circle + ArmOfTheScholar = 26836, // Boss->self, 5.0s cast, range 5 circle + RawRockbreaker = 26832, // Boss->self, 5.0s cast, single-target + RawRockbreaker1 = 26833, // Helper->self, 4.0s cast, range 10 circle + RawRockbreaker2 = 26834, // Helper->self, 4.0s cast, range 10-20 donut + DemifireII = 26842, // MahaudFlamehand->Lalah, 8.0s cast, single-target + Demiburst = 26843, // MahaudFlamehand->self, 7.0s cast, single-target + ElectrogeneticForce = 26844, // Helper->self, 8.0s cast, range 6 circle + DemifireIII = 26841, // MahaudFlamehand->Lalah, 3.0s cast, single-target + FourElements = 26846, // MahaudFlamehand->self, 8.0s cast, single-target + ClassicalFire = 26847, // Helper->Lalah, 8.0s cast, range 6 circle + ClassicalThunder = 26848, // Helper->player/Loifa/Lalah, 5.0s cast, range 6 circle + ClassicalBlizzard = 26849, // Helper->location, 5.0s cast, range 6 circle + ClassicalStone = 26850, // Helper->self, 9.0s cast, range 50 circle +} + +class DemifireII(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.DemifireII)); +class ElectrogeneticForce(BossModule module) : Components.CastTowers(module, ActionID.MakeSpell(AID.ElectrogeneticForce), 6); +class RawRockbreaker(BossModule module) : Components.ConcentricAOEs(module, [new AOEShapeCircle(10), new AOEShapeDonut(10, 20)]) +{ + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if (spell.Action.ID == (uint)AID.RawRockbreaker) + AddSequence(spell.LocXZ, Module.CastFinishAt(spell)); + } + + public override void OnCastFinished(Actor caster, ActorCastInfo spell) + { + var order = (AID)spell.Action.ID switch + { + AID.RawRockbreaker1 => 0, + AID.RawRockbreaker2 => 1, + _ => -1 + }; + AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2)); + } +} + +class ChiBlast(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.ChiBlast)); +class Explosion(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Explosion), 6); +class ArmOfTheScholar(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ArmOfTheScholar), 5); + +class ClassicalFire(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.ClassicalFire), 6); +class ClassicalThunder(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.ClassicalThunder), 6); +class ClassicalBlizzard(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ClassicalBlizzard), 6); +class ClassicalStone(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ClassicalStone), 15); + +class AncelAndMahaudStates : StateMachineBuilder +{ + public AncelAndMahaudStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69608, NameID = 10732)] +public class AncelAndMahaud(WorldState ws, Actor primary) : BossModule(ws, primary, ArenaBounds.Center, ArenaBounds) +{ + public static readonly ArenaBoundsComplex ArenaBounds = new([new Polygon(new(224.8f, -855.8f), 19.5f, 20)]); + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies([(uint)OID.Boss, (uint)OID.MahaudFlamehand])); + } +} diff --git a/BossMod/Modules/Endwalker/Quest/Job/Sage/LifeEphemeralPathEternal/Guildivain.cs b/BossMod/Modules/Endwalker/Quest/Job/Sage/LifeEphemeralPathEternal/Guildivain.cs new file mode 100644 index 0000000000..dfc4f71164 --- /dev/null +++ b/BossMod/Modules/Endwalker/Quest/Job/Sage/LifeEphemeralPathEternal/Guildivain.cs @@ -0,0 +1,125 @@ +namespace BossMod.Endwalker.Quest.Job.Sage.LifeEphemeralPathEternal.Guildivain; + +public enum OID : uint +{ + Boss = 0x35C6, // R4.998, x1 + StrengthenedNoulith = 0x35C8, // R1.0 + EnhancedNoulith = 0x3859, // R1.0 + Helper = 0x233C +} + +public enum AID : uint +{ + Nouliths = 26851, // BossP2->self, 5.0s cast, single-target + AetherstreamTank = 26852, // StrengthenedNoulith->Lalah, no cast, range 50 width 4 rect + AetherstreamPlayer = 26853, // StrengthenedNoulith->players/Loifa, no cast, range 50 width 4 rect + Tracheostomy = 26854, // BossP2->self, 5.0s cast, range 10-20 donut + + RightScalpel = 26855, // BossP2->self, 5.0s cast, range 15 210-degree cone + LeftScalpel = 26856, // BossP2->self, 5.0s cast, range 15 210-degree cone + LeftRightScalpel1 = 26864, // BossP2->self, 7.0s cast, range 15 210-degree cone + LeftRightScalpel2 = 26865, // BossP2->self, 3.0s cast, range 15 210-degree cone + RightLeftScalpel1 = 26862, // BossP2->self, 7.0s cast, range 15 210-degree cone + RightLeftScalpel2 = 26863, // BossP2->self, 3.0s cast, range 15 210-degree cone + + Laparotomy = 26857, // BossP2->self, 5.0s cast, range 15 120-degree cone + Amputation = 26858, // BossP2->self, 7.0s cast, range 20 120-degree cone + Hypothermia = 26861, // BossP2->self, 5.0s cast, range 50 circle + CryonicsVisual = 26859, // BossP2->self, 8.0s cast, single-target + Cryonics = 26860, // Helper->players, 8.0s cast, range 6 circle + + Craniotomy = 28386, // BossP2->self, 8.0s cast, range 40 circle + + FrigotherapyVisual = 26866, // BossP2->self, 5.0s cast, single-target + Frigotherapy = 26867 // Helper->players/Mahaud/Loifa, 7.0s cast, range 5 circle +} + +public enum TetherID : uint +{ + Noulith = 17, // StrengthenedNoulith->Lalah/player/Loifa + Craniotomy = 174 // EnhancedNoulith->Lalah/Loifa/player/Mahaud/Ancel +} + +public enum SID : uint +{ + Craniotomy = 2968 // none->player/Lalah/Mahaud/Ancel/Loifa, extra=0x0 +} + +class AetherstreamTether(BossModule module) : Components.BaitAwayTethers(module, new AOEShapeRect(50, 2), (uint)TetherID.Noulith) +{ + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + if ((AID)spell.Action.ID is AID.AetherstreamPlayer or AID.AetherstreamTank) + CurrentBaits.RemoveAll(x => x.Target.InstanceID == spell.MainTargetID); + } +} + +class Tracheostomy : Components.SimpleAOEs +{ + public Tracheostomy(BossModule module) : base(module, ActionID.MakeSpell(AID.Tracheostomy), new AOEShapeDonut(10, 20)) + { + WorldState.Actors.EventStateChanged.Subscribe((act) => + { + if (act.OID == 0x1EA1A1 && act.EventState == 7) + Arena.Bounds = AncelAndMahaud.AncelAndMahaud.ArenaBounds; + }); + } + + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + base.OnEventCast(caster, spell); + if (spell.Action == WatchedAction) + Arena.Bounds = Guildivain.SmallBounds; + } +} + +abstract class Scalpel(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(15, 105.Degrees())); +class RightScalpel(BossModule module) : Scalpel(module, AID.RightScalpel); +class LeftScalpel(BossModule module) : Scalpel(module, AID.LeftScalpel); +class RightLeftScalpel1(BossModule module) : Scalpel(module, AID.RightLeftScalpel1); +class RightLeftScalpel2(BossModule module) : Scalpel(module, AID.RightLeftScalpel2); +class LeftRightScalpel1(BossModule module) : Scalpel(module, AID.LeftRightScalpel1); +class LeftRightScalpel2(BossModule module) : Scalpel(module, AID.LeftRightScalpel2); + +class Laparotomy(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Laparotomy), new AOEShapeCone(15, 60.Degrees())); +class Amputation(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Amputation), new AOEShapeCone(20, 60.Degrees())); + +class Hypothermia(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Hypothermia)); +class Cryonics(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Cryonics), 6); +class Craniotomy(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Craniotomy)); + +class Frigotherapy(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Frigotherapy), 5); + +class GuildivainStates : StateMachineBuilder +{ + public GuildivainStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69608, NameID = 10733)] +public class Guildivain(WorldState ws, Actor primary) : BossModule(ws, primary, SmallBounds.Center, AncelAndMahaud.AncelAndMahaud.ArenaBounds) +{ + public static readonly ArenaBoundsComplex SmallBounds = new([new Polygon(new(224.8f, -855.8f), 10, 20)]); + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(OID.EnhancedNoulith)); + Arena.Actor(PrimaryActor); + } +} diff --git a/BossMod/Modules/Endwalker/Quest/Job/Sage/SagesFocus.cs b/BossMod/Modules/Endwalker/Quest/Job/Sage/SagesFocus.cs new file mode 100644 index 0000000000..438ebdde0c --- /dev/null +++ b/BossMod/Modules/Endwalker/Quest/Job/Sage/SagesFocus.cs @@ -0,0 +1,83 @@ +namespace BossMod.Endwalker.Quest.Job.Sage.SagesFocus; + +public enum OID : uint +{ + Boss = 0x3587, // R0.5 + Loifa = 0x3588, // R0.5 + Mahaud = 0x3586, // R0.5 + StrengthenedNoulith = 0x358E, // R1.0 + ChiBomb = 0x358D, // R1.0 + Helper = 0x233C +} + +public enum AID : uint +{ + AutoAttack1 = 872, // Boss/Loifa->Lalah, no cast, single-target + Teleport1 = 26544, // Boss->location, no cast, single-target + Teleport2 = 26556, // Loifa->location, no cast, single-target + Teleport3 = 26557, // Mahaud->location, no cast, single-target + Teleport4 = 26540, // StrengthenedNoulith->location, no cast, single-target + + Demifire = 26558, // Mahaud->Lalah, no cast, single-target + TripleThreat = 26535, // Boss->Lalah, 8.0s cast, single-target + ChiBomb = 26536, // Boss->self, 5.0s cast, single-target + Explosion = 26537, // ChiBomb->self, 5.0s cast, range 6 circle + ArmOfTheScholar = 26543, // Boss->self, 5.0s cast, range 5 circle + Nouliths = 26538, // 3588->self, 5.0s cast, single-target + Noubelea = 26541, // 3588->self, 5.0s cast, single-target + Noubelea1 = 26542, // 358E->self, 5.0s cast, range 50 width 4 rect + DemiblizzardIII = 26545, // Mahaud->self, 5.0s cast, single-target + DemiblizzardIII1 = 26546, // Helper->self, 5.0s cast, range 10-40 donut + Demigravity1 = 26539, // Mahaud->location, 5.0s cast, range 6 circle + Demigravity2 = 26550, // Helper->location, 5.0s cast, range 6 circle + DemifireIII = 26547, // Mahaud->self, 5.0s cast, single-target + DemifireIII1 = 26548, // Helper->self, 5.6s cast, range 40 circle + DemifireIIVisual = 26552, // Mahaud->self, 7.0s cast, single-target + DemifireIISpread = 26553, // Helper->player/Lalah, 5.0s cast, range 5 circle + DemifireIIAOE = 26554, // Helper->location, 5.0s cast, range 14 circle + Diagnosis = 26555, // Loifa->Mahaud, 3.0s cast, single-target + DosisIII = 26551, // Loifa->Lalah, 8.0s cast, single-target +} + +class DosisIII(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.DosisIII)); +class DemifireSpread(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.DemifireIISpread), 5); +class DemifireIIAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DemifireIIAOE), 14); +class DemifireIII(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.DemifireIII1)); +class Noubelea(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Noubelea1), new AOEShapeRect(50, 2)); +class Demigravity1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Demigravity1), 6); +class Demigravity2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Demigravity2), 6); +class Demiblizzard(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DemiblizzardIII1), new AOEShapeDonut(10, 40)); +class TripleThreat(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.TripleThreat)); +class Explosion(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Explosion), 6); +class ArmOfTheScholar(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ArmOfTheScholar), 5); + +class AncelRockfistStates : StateMachineBuilder +{ + public AncelRockfistStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69604, NameID = 10732)] +public class AncelRockfist(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) +{ + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(0, -82.146f), 18.5f, 20)]); + private static readonly uint[] bosses = [(uint)OID.Boss, (uint)OID.Mahaud, (uint)OID.Loifa]; + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(bosses)); + } +} + diff --git a/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/AncelRockfist.cs b/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/AncelRockfist.cs deleted file mode 100644 index 51163d5057..0000000000 --- a/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/AncelRockfist.cs +++ /dev/null @@ -1,59 +0,0 @@ -namespace BossMod.Endwalker.Quest.LifeEphemeralPathEternal; - -class ElectrogeneticForce(BossModule module) : Components.CastTowers(module, ActionID.MakeSpell(AID.ElectrogeneticForce), 6); -class RawRockbreaker(BossModule module) : Components.ConcentricAOEs(module, [new AOEShapeCircle(10), new AOEShapeDonut(10, 20)]) -{ - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if (spell.Action.ID == (uint)AID.RawRockbreaker) - AddSequence(caster.Position, Module.CastFinishAt(spell)); - } - - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - var idx = (AID)spell.Action.ID switch - { - AID.RawRockbreaker1 => 0, - AID.RawRockbreaker2 => 1, - _ => -1 - }; - AdvanceSequence(idx, caster.Position, WorldState.FutureTime(2)); - } - - public override void Update() - { - if (!Module.PrimaryActor.IsTargetable) - Sequences.Clear(); - } -} -class ChiBlast(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.ChiBlast1)); -class Explosion(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeCircle(6)); -class ArmOfTheScholar(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ArmOfTheScholar), new AOEShapeCircle(5)); - -class ClassicalFire(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.ClassicalFire), 6); -class ClassicalThunder(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.ClassicalThunder), 6); -class ClassicalBlizzard(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.ClassicalBlizzard), 6); -class ClassicalStone(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ClassicalStone), new AOEShapeCircle(15)); - -class AncelRockfistStates : StateMachineBuilder -{ - public AncelRockfistStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69608, NameID = 10732)] -public class AncelRockfist(WorldState ws, Actor primary) : BossModule(ws, primary, new(224.8f, -855.8f), new ArenaBoundsCircle(20)) -{ - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); -} diff --git a/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/Enums.cs b/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/Enums.cs deleted file mode 100644 index d9879ffa03..0000000000 --- a/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/Enums.cs +++ /dev/null @@ -1,74 +0,0 @@ -namespace BossMod.Endwalker.Quest.LifeEphemeralPathEternal; - -public enum OID : uint -{ - Boss = 0x35C5, - BossP2 = 0x35C6, - Helper = 0x233C, - MahaudFlamehand = 0x35C4, // R0.500, x1 - Lalah = 0x35C2, - Loifa = 0x35C3, - Mahaud = 0x361C, - Ancel = 0x361D, - EnhancedNoulith = 0x3859, // R1.000, x0 (spawn during fight) -} - -public enum AID : uint -{ - ChiBlast = 26838, // Boss->self, 5.0s cast, single-target - ChiBlast1 = 26839, // Helper->self, 5.0s cast, range 100 circle - ChiBomb = 26835, // Boss->self, 5.0s cast, single-target - Explosion = 26837, // 35C7->self, 5.0s cast, range 6 circle - ArmOfTheScholar = 26836, // Boss->self, 5.0s cast, range 5 circle - RawRockbreaker = 26832, // Boss->self, 5.0s cast, single-target - RawRockbreaker1 = 26833, // Helper->self, 4.0s cast, range 10 circle - RawRockbreaker2 = 26834, // Helper->self, 4.0s cast, range 10-20 donut - DemifireII = 26842, // MahaudFlamehand->Lalah, 8.0s cast, single-target - Demiburst = 26843, // MahaudFlamehand->self, 7.0s cast, single-target - ElectrogeneticForce = 26844, // Helper->self, 8.0s cast, range 6 circle - ElectrogeneticBlast = 26845, // Helper->self, 1.0s cast, range 80 circle - DemifireIII = 26841, // MahaudFlamehand->Lalah, 3.0s cast, single-target - FourElements = 26846, // MahaudFlamehand->self, 8.0s cast, single-target - ClassicalFire = 26847, // Helper->Lalah, 8.0s cast, range 6 circle - ClassicalThunder = 26848, // Helper->player/Loifa/Lalah, 5.0s cast, range 6 circle - ClassicalBlizzard = 26849, // Helper->location, 5.0s cast, range 6 circle - ClassicalStone = 26850, // Helper->self, 9.0s cast, range 50 circle - - Nouliths = 26851, // BossP2->self, 5.0s cast, single-target - AetherstreamTank = 26852, // 35C8->Lalah, no cast, range 50 width 4 rect - AetherstreamPlayer = 26853, // 35C8->players/Loifa, no cast, range 50 width 4 rect - Tracheostomy = 26854, // BossP2->self, 5.0s cast, range 10-20 donut - RightScalpel = 26855, // BossP2->self, 5.0s cast, range 15 210-degree cone - LeftScalpel = 26856, // BossP2->self, 5.0s cast, range 15 210-degree cone - Laparotomy = 26857, // BossP2->self, 5.0s cast, range 15 120-degree cone - Amputation = 26858, // BossP2->self, 7.0s cast, range 20 120-degree cone - Hypothermia = 26861, // BossP2->self, 5.0s cast, range 50 circle - Cryonics = 26860, // Helper->player, 8.0s cast, range 6 circle - Cryonics1 = 26859, // BossP2->self, 8.0s cast, single-target - Craniotomy = 28386, // BossP2->self, 8.0s cast, range 40 circle - RightLeftScalpel = 26862, // BossP2->self, 7.0s cast, range 15 210-degree cone - RightLeftScalpel1 = 26863, // BossP2->self, 3.0s cast, range 15 210-degree cone - LeftRightScalpel = 26864, // BossP2->self, 7.0s cast, range 15 210-degree cone - LeftRightScalpel1 = 26865, // BossP2->self, 3.0s cast, range 15 210-degree cone - Frigotherapy = 26866, // BossP2->self, 5.0s cast, single-target - Frigotherapy1 = 26867, // Helper->players/Mahaud/Loifa, 7.0s cast, range 5 circle -} - -public enum IconID : uint -{ - Tankbuster = 230, // Lalah - Noulith = 244, // player/Loifa -} - -public enum TetherID : uint -{ - Noulith = 17, // StrengthenedNoulith->Lalah/player/Loifa - Craniotomy = 174, // EnhancedNoulith->Lalah/Loifa/player/Mahaud/Ancel -} - -public enum SID : uint -{ - Craniotomy = 2968, // none->player/Lalah/Mahaud/Ancel/Loifa, extra=0x0 - DownForTheCount = 1953, // none->player/Lalah/Mahaud/Ancel/Loifa, extra=0xEC7 - -} diff --git a/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/Guildivain.cs b/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/Guildivain.cs deleted file mode 100644 index 5e12572506..0000000000 --- a/BossMod/Modules/Endwalker/Quest/LifeEphemeralPathEternal/Guildivain.cs +++ /dev/null @@ -1,91 +0,0 @@ -namespace BossMod.Endwalker.Quest.LifeEphemeralPathEternal; - -class AetherstreamTether(BossModule module) : Components.BaitAwayTethers(module, new AOEShapeRect(50, 2), (uint)TetherID.Noulith) -{ - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - if ((AID)spell.Action.ID is AID.AetherstreamPlayer or AID.AetherstreamTank) - CurrentBaits.RemoveAll(x => x.Target.InstanceID == spell.MainTargetID); - } -} - -class Tracheostomy : Components.SelfTargetedAOEs -{ - public Tracheostomy(BossModule module) : base(module, ActionID.MakeSpell(AID.Tracheostomy), new AOEShapeDonut(10, 20)) - { - WorldState.Actors.EventStateChanged.Subscribe((act) => - { - if (act.OID == 0x1EA1A1 && act.EventState == 7) - Arena.Bounds = new ArenaBoundsCircle(20); - }); - } - - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - base.OnEventCast(caster, spell); - if (spell.Action == WatchedAction) - Arena.Bounds = new ArenaBoundsCircle(10); - } -} - -class RightScalpel(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RightScalpel), new AOEShapeCone(15, 105.Degrees())); -class LeftScalpel(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.LeftScalpel), new AOEShapeCone(15, 105.Degrees())); -class Laparotomy(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Laparotomy), new AOEShapeCone(15, 60.Degrees())); -class Amputation(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Amputation), new AOEShapeCone(20, 60.Degrees())); - -class Hypothermia(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Hypothermia)); -class Cryonics(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Cryonics), 6); -class Craniotomy(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Craniotomy)); -class RightLeftScalpel1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RightLeftScalpel), new AOEShapeCone(15, 105.Degrees())); -class RightLeftScalpel2(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RightLeftScalpel1), new AOEShapeCone(15, 105.Degrees())); -class LeftRightScalpel1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.LeftRightScalpel), new AOEShapeCone(15, 105.Degrees())); -class LeftRightScalpel2(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.LeftRightScalpel1), new AOEShapeCone(15, 105.Degrees())); - -class EnhancedNoulith(BossModule module) : Components.Adds(module, (uint)OID.EnhancedNoulith) -{ - private readonly List<(Actor, Actor)> Tethers = []; - public override void OnTethered(Actor source, ActorTetherInfo tether) - { - if (tether.ID == (uint)TetherID.Craniotomy && WorldState.Actors.Find(tether.Target) is Actor target) - Tethers.Add((source, target)); - } - - public override void OnStatusLose(Actor actor, ActorStatus status) - { - if (status.ID == (uint)SID.Craniotomy) - Tethers.RemoveAll(t => t.Item2 == actor); - } - - public override void DrawArenaBackground(int pcSlot, Actor pc) - { - foreach (var t in Tethers) - Arena.AddLine(t.Item1.Position, t.Item2.Position, ArenaColor.Danger); - } -} -class Frigotherapy(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Frigotherapy1), 5); - -class GuildivainOfTheTaintedEdgeStates : StateMachineBuilder -{ - public GuildivainOfTheTaintedEdgeStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69608, NameID = 10733, PrimaryActorOID = (uint)OID.BossP2)] -public class GuildivainOfTheTaintedEdge(WorldState ws, Actor primary) : BossModule(ws, primary, new(224.8f, -855.8f), new ArenaBoundsCircle(20)); diff --git a/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P1TerminusIdolizer.cs b/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P1TerminusIdolizer.cs index 448b391208..87b0106b20 100644 --- a/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P1TerminusIdolizer.cs +++ b/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P1TerminusIdolizer.cs @@ -11,8 +11,8 @@ public enum OID : uint public enum AID : uint { - AutoAttack = 26994, // Boss->Estinien, no cast, single-target + DeadlyTentacles = 26998, // Boss->Estinien, no cast, single-target TentacleWhip = 27005, // Boss->self, no cast, single-target Shout = 27000, // Boss->self, no cast, single-target diff --git a/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P2TerminusLacerator.cs b/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P2TerminusLacerator.cs index 20122d43e1..807163d29d 100644 --- a/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P2TerminusLacerator.cs +++ b/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P2TerminusLacerator.cs @@ -30,7 +30,7 @@ public enum AID : uint Explosion = 27026 // Meteorite->self, 3.0s cast, range 6 circle } -class TheBlackDeath(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.TheBlackDeath), new AOEShapeCone(25, 60.Degrees()), (uint)OID.Boss, activeWhileCasting: false); +class TheBlackDeath(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.TheBlackDeath), new AOEShapeCone(25, 60.Degrees()), [(uint)OID.Boss], activeWhileCasting: false); class Burst(BossModule module) : Components.CastTowers(module, ActionID.MakeSpell(AID.Burst), 5); class DeadlyImpact(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DeadlyImpact), 10, 6); class BlackStar(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.BlackStar)); diff --git a/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P3TerminusVanquisher.cs b/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P3TerminusVanquisher.cs index 1bf537d1c5..2137360540 100644 --- a/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P3TerminusVanquisher.cs +++ b/BossMod/Modules/Endwalker/Quest/MSQ/AsTheHeavensBurn/P3TerminusVanquisher.cs @@ -40,8 +40,8 @@ public enum AID : uint ForceOfLoathing = 27031 // TerminusVanquisher->self, no cast, range 10 120-degree cone } -class TheBlackDeath(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.TheBlackDeath), new AOEShapeCone(25, 60.Degrees()), (uint)OID.Boss, activeWhileCasting: false); -class ForceOfLoathing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.ForceOfLoathing), new AOEShapeCone(10, 60.Degrees()), (uint)OID.TerminusVanquisher, activeWhileCasting: false); +class TheBlackDeath(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.TheBlackDeath), new AOEShapeCone(25, 60.Degrees()), [(uint)OID.Boss], activeWhileCasting: false); +class ForceOfLoathing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.ForceOfLoathing), new AOEShapeCone(10, 60.Degrees()), [(uint)OID.TerminusVanquisher], activeWhileCasting: false); class DeadlyImpact(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DeadlyImpact), 10, 6); class BlackStar(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.BlackStar)); diff --git a/BossMod/Modules/Endwalker/Quest/SagesFocus.cs b/BossMod/Modules/Endwalker/Quest/SagesFocus.cs deleted file mode 100644 index 72a5e90d80..0000000000 --- a/BossMod/Modules/Endwalker/Quest/SagesFocus.cs +++ /dev/null @@ -1,65 +0,0 @@ -namespace BossMod.Endwalker.Quest.SagesFocus; - -public enum OID : uint -{ - Boss = 0x3587, - Helper = 0x233C, - Mahaud = 0x3586, - Loifa = 0x3588, -} - -public enum AID : uint -{ - TripleThreat = 26535, // Boss->3589, 8.0s cast, single-target - ChiBomb = 26536, // Boss->self, 5.0s cast, single-target - Explosion = 26537, // 358D->self, 5.0s cast, range 6 circle - ArmOfTheScholar = 26543, // Boss->self, 5.0s cast, range 5 circle - Nouliths = 26538, // 3588->self, 5.0s cast, single-target - Noubelea = 26541, // 3588->self, 5.0s cast, single-target - Noubelea1 = 26542, // 358E->self, 5.0s cast, range 50 width 4 rect - DemiblizzardIII = 26545, // 3586->self, 5.0s cast, single-target - DemiblizzardIII1 = 26546, // Helper->self, 5.0s cast, range -40 donut - Demigravity = 26539, // 3586->location, 5.0s cast, range 6 circle - Demigravity1 = 26550, // Helper->location, 5.0s cast, range 6 circle - DemifireIII = 26547, // 3586->self, 5.0s cast, single-target - DemifireIII1 = 26548, // Helper->self, 5.6s cast, range 40 circle - DemifireII = 26552, // Mahaud->self, 7.0s cast, single-target - DemifireII1 = 26553, // Helper->player/3589, 5.0s cast, range 5 circle - DemifireII2 = 26554, // Helper->location, 5.0s cast, range 14 circle -} - -class DemifireSpread(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.DemifireII1), 5); -class DemifireII(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.DemifireII2), 14); -class DemifireIII(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.DemifireIII1)); -class Noubelea(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Noubelea1), new AOEShapeRect(50, 2)); -class Demigravity(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Demigravity), 6); -class Demigravity1(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Demigravity1), 6); -class Demiblizzard(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DemiblizzardIII1), new AOEShapeDonut(10, 40)); -class TripleThreat(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.TripleThreat)); -class Explosion(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeCircle(6)); -class ArmOfTheScholar(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ArmOfTheScholar), new AOEShapeCircle(5)); - -class AncelRockfistStates : StateMachineBuilder -{ - public AncelRockfistStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69604, NameID = 10732)] -public class AncelRockfist(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, -82.17f), new ArenaBoundsCircle(18.5f)) -{ - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); -} - diff --git a/BossMod/Modules/Endwalker/Quest/TheKillingArt.cs b/BossMod/Modules/Endwalker/Quest/TheKillingArt.cs deleted file mode 100644 index 7c93da35e1..0000000000 --- a/BossMod/Modules/Endwalker/Quest/TheKillingArt.cs +++ /dev/null @@ -1,87 +0,0 @@ -namespace BossMod.Endwalker.Quest.TheKillingArt; - -public enum OID : uint -{ - Boss = 0x3664, // R1.500, x1 - Helper = 0x233C, // R0.500, x10, Helper type - VoidHecteyes = 0x3666, // R1.200, x0 (spawn during fight) - VoidPersona = 0x3667, // R1.200, x0 (spawn during fight) - Voidzone = 0x1E963D -} - -public enum AID : uint -{ - MeatySlice = 27590, // Boss->self, 3.4+0.6s cast, single-target - MeatySlice1 = 27591, // Helper->self, 4.0s cast, range 50 width 12 rect - Cleaver = 27594, // Boss->self, 3.5+0.5s cast, single-target - Cleaver1 = 27595, // Helper->self, 4.0s cast, range 40 120-degree cone - FlankCleaver = 27596, // Boss->self, 3.5+0.5s cast, single-target - FlankCleaver1 = 27597, // Helper->self, 4.0s cast, range 40 120-degree cone - Explosion = 27606, // VoidHecteyes->self, 20.0s cast, range 60 circle - Explosion1 = 27607, // VoidPersona->self, 20.0s cast, range 50 circle - FocusInferi = 27592, // Boss->self, 2.9+0.6s cast, single-target - FocusInferi1 = 27593, // Helper->location, 3.5s cast, range 6 circle - CarnemLevare = 27598, // Boss->self, 4.0s cast, single-target - CarnemLevare1 = 27599, // Helper->self, 4.0s cast, range 40 width 8 cross - CarnemLevare2 = 27602, // Helper->self, 3.5s cast, range -17 donut - CarnemLevare3 = 27600, // Helper->self, 3.5s cast, range -7 donut - CarnemLevare4 = 27603, // Helper->self, 3.5s cast, range -22 donut - CarnemLevare5 = 27601, // Helper->self, 3.5s cast, range -12 donut - VoidMortar = 27604, // Boss->self, 4.0+1.0s cast, single-target - VoidMortar1 = 27605, // Helper->self, 5.0s cast, range 13 circle -} - -class VoidMortar(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.VoidMortar1), new AOEShapeCircle(13)); -class FocusInferi(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6, ActionID.MakeSpell(AID.FocusInferi1), m => m.Enemies(OID.Voidzone).Where(x => x.EventState != 7), 0); -class CarnemLevareCross(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CarnemLevare1), new AOEShapeCross(40, 4)); -class CarnemLevareDonut(BossModule module) : Components.GenericAOEs(module) -{ - private readonly List<(Actor, AOEShape)> Casters = []; - - public override IEnumerable ActiveAOEs(int slot, Actor actor) => Casters.Take(4).Select(c => new AOEInstance(c.Item2, c.Item1.Position, c.Item1.CastInfo!.Rotation, Module.CastFinishAt(c.Item1.CastInfo))); - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - AOEShape? sh = (AID)spell.Action.ID switch - { - AID.CarnemLevare2 => new AOEShapeDonutSector(12, 17, 90.Degrees()), - AID.CarnemLevare3 => new AOEShapeDonutSector(2, 7, 90.Degrees()), - AID.CarnemLevare4 => new AOEShapeDonutSector(17, 22, 90.Degrees()), - AID.CarnemLevare5 => new AOEShapeDonutSector(7, 12, 90.Degrees()), - _ => null - }; - - if (sh != null) - Casters.Add((caster, sh)); - } - - public override void OnCastFinished(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID is AID.CarnemLevare2 or AID.CarnemLevare3 or AID.CarnemLevare4 or AID.CarnemLevare5) - Casters.RemoveAll(x => x.Item1 == caster); - } -} -class MeatySlice(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MeatySlice1), new AOEShapeRect(50, 6)); -class Cleaver(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Cleaver1), new AOEShapeCone(40, 60.Degrees())); -class FlankCleaver(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.FlankCleaver1), new AOEShapeCone(40, 60.Degrees())); -class Adds(BossModule module) : Components.AddsMulti(module, [(uint)OID.VoidHecteyes, (uint)OID.VoidPersona], 1); - -class OrcusStates : StateMachineBuilder -{ - public OrcusStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69614, NameID = 10581)] -public class Orcus(WorldState ws, Actor primary) : BossModule(ws, primary, new(-69.7f, -388.5f), new ArenaBoundsCircle(20)); - diff --git a/BossMod/Modules/Endwalker/Ultimate/DSW2/DSW2.cs b/BossMod/Modules/Endwalker/Ultimate/DSW2/DSW2.cs index 36687de614..ddaa97b68b 100644 --- a/BossMod/Modules/Endwalker/Ultimate/DSW2/DSW2.cs +++ b/BossMod/Modules/Endwalker/Ultimate/DSW2/DSW2.cs @@ -1,16 +1,22 @@ namespace BossMod.Endwalker.Ultimate.DSW2; class P2AscalonsMercyConcealed(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AscalonsMercyConcealedAOE), new AOEShapeCone(50, 15.Degrees())); -class P2AscalonMight(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.AscalonsMight), new AOEShapeCone(50, 30.Degrees()), (uint)OID.BossP2); + +abstract class AscalonMight(BossModule module, OID oid) : Components.Cleave(module, ActionID.MakeSpell(AID.AscalonsMight), new AOEShapeCone(50, 30.Degrees()), [(uint)oid]); +class P2AscalonMight(BossModule module) : AscalonMight(module, OID.BossP2); + class P2UltimateEnd(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.UltimateEndAOE)); class P3Drachenlance(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DrachenlanceAOE), new AOEShapeCone(13, 45.Degrees())); class P3SoulTether(BossModule module) : Components.TankbusterTether(module, ActionID.MakeSpell(AID.SoulTether), (uint)TetherID.HolyShieldBash, 5); class P4Resentment(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.Resentment)); class P5TwistingDive(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TwistingDive), new AOEShapeRect(60, 5)); -class P5Cauterize1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Cauterize1), new AOEShapeRect(48, 10)); -class P5Cauterize2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Cauterize2), new AOEShapeRect(48, 10)); + +abstract class Cauterize(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(48, 10)); +class P5Cauterize1(BossModule module) : Cauterize(module, AID.Cauterize1); +class P5Cauterize2(BossModule module) : Cauterize(module, AID.Cauterize2); + class P5SpearOfTheFury(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpearOfTheFuryP5), new AOEShapeRect(50, 5)); -class P5AscalonMight(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.AscalonsMight), new AOEShapeCone(50, 30.Degrees()), (uint)OID.BossP5); +class P5AscalonMight(BossModule module) : AscalonMight(module, OID.BossP5); class P5Surrender(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.Surrender)); class P6SwirlingBlizzard(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SwirlingBlizzard), new AOEShapeDonut(20, 35)); class P7Shockwave(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.ShockwaveP7)); diff --git a/BossMod/Modules/Endwalker/Unreal/Un4Zurvan/Un4Zurvan.cs b/BossMod/Modules/Endwalker/Unreal/Un4Zurvan/Un4Zurvan.cs index 31e5085bb9..5efe79813e 100644 --- a/BossMod/Modules/Endwalker/Unreal/Un4Zurvan/Un4Zurvan.cs +++ b/BossMod/Modules/Endwalker/Unreal/Un4Zurvan/Un4Zurvan.cs @@ -1,9 +1,11 @@ namespace BossMod.Endwalker.Unreal.Un4Zurvan; -class P1MetalCutter(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.MetalCutterP1), new AOEShapeCone(37.44f, 45.Degrees()), (uint)OID.BossP1); +abstract class MetalCutter(BossModule module, AID aid, OID oid) : Components.Cleave(module, ActionID.MakeSpell(aid), new AOEShapeCone(37.44f, 45.Degrees()), [(uint)oid]); +class P1MetalCutter(BossModule module) : MetalCutter(module, AID.MetalCutterP1, OID.BossP1); + class P1FlareStar(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlareStarAOE), 6); class P1Purge(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.Purge)); -class P2MetalCutter(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.MetalCutterP2), new AOEShapeCone(37.44f, 45.Degrees()), (uint)OID.BossP2); +class P2MetalCutter(BossModule module) : MetalCutter(module, AID.MetalCutterP2, OID.BossP2); class P2IcyVoidzone(BossModule module) : Components.PersistentVoidzone(module, 5, m => m.Enemies(OID.IcyVoidzone).Where(z => z.EventState != 7)); class P2BitingHalberd(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BitingHalberd), new AOEShapeCone(55.27f, 135.Degrees())); class P2TailEnd(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailEnd), 15); @@ -11,7 +13,7 @@ class P2TailEnd(BossModule module) : Components.SimpleAOEs(module, ActionID.Make class P2SouthernCross(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SouthernCrossAOE), 6); class P2SouthernCrossVoidzone(BossModule module) : Components.PersistentVoidzone(module, 6, m => m.Enemies(OID.SouthernCrossVoidzone).Where(z => z.EventState != 7)); class P2WaveCannon(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.WaveCannonSolo), new AOEShapeRect(55.27f, 5)); -class P2TyrfingFire(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.TyrfingFire), new AOEShapeCircle(5), (uint)OID.BossP2, originAtTarget: true); +class P2TyrfingFire(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.TyrfingFire), new AOEShapeCircle(5), [(uint)OID.BossP2], originAtTarget: true); [ModuleInfo(BossModuleInfo.Maturity.Verified, PrimaryActorOID = (uint)OID.BossP1, GroupType = BossModuleInfo.GroupType.RemovedUnreal, GroupID = 951, NameID = 5567, PlanLevel = 90)] public class Un4Zurvan(WorldState ws, Actor primary) : BossModule(ws, primary, default, new ArenaBoundsCircle(20)) diff --git a/BossMod/Modules/Heavensward/Dungeon/D04TheVault/D042SerGrinnaux.cs b/BossMod/Modules/Heavensward/Dungeon/D04TheVault/D042SerGrinnaux.cs index d6d2e677db..fa58e57039 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D04TheVault/D042SerGrinnaux.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D04TheVault/D042SerGrinnaux.cs @@ -38,7 +38,7 @@ public enum AID : uint BossPhase2Vanish = 4256 // SerGrinnauxTheBull->self, no cast, single-target } -class HeavySwing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.HeavySwing), new AOEShapeCone(6.5f, 45.Degrees()), (uint)OID.SerGrinnauxTheBull); +class HeavySwing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.HeavySwing), new AOEShapeCone(6.5f, 45.Degrees()), [(uint)OID.SerGrinnauxTheBull]); class Overpower(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(10.2f, 45.Degrees())); class DimensionalRip(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 5, ActionID.MakeSpell(AID.DimensionalRip), m => m.Enemies(OID.StellarImplodeArea).Where(e => e.EventState != 7), 1.1f); diff --git a/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D053TheEverlivingBibliotaph.cs b/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D053TheEverlivingBibliotaph.cs index 08693c3d50..ca7ab684d2 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D053TheEverlivingBibliotaph.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D05GreatGubalLibrary/D053TheEverlivingBibliotaph.cs @@ -92,7 +92,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) class DeepDarkness(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DeepDarkness), new AOEShapeDonut(12, 25)); class MagicBurst(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagicBurst), 15); class VoidBlizzardIIIAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.VoidBlizzardIIIAOE), 5); -class AbyssalSwing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.AbyssalSwing), new AOEShapeCone(7.5f, 45.Degrees()), (uint)OID.Biblioklept); +class AbyssalSwing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.AbyssalSwing), new AOEShapeCone(7.5f, 45.Degrees()), [(uint)OID.Biblioklept]); class AbyssalCharge(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AbyssalCharge), new AOEShapeRect(41, 2)); class VoidCall(BossModule module) : Components.GenericTowers(module, prioritizeInsufficient: true) diff --git a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs index fca4934aa0..a4ec0566d8 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D06AetherochemicalResearchFacility/D060Trash1.cs @@ -27,9 +27,9 @@ public enum AID : uint DefensiveManeuvers = 607 // ScrambledIronClaw->self, 3.0s cast, single-target, apply stoneskin } -class PassiveInfraredGuidanceSystem(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.PassiveInfraredGuidanceSystem), new AOEShapeCircle(6), (uint)OID.Boss, originAtTarget: true); +class PassiveInfraredGuidanceSystem(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.PassiveInfraredGuidanceSystem), new AOEShapeCircle(6), [(uint)OID.Boss], originAtTarget: true); -abstract class HeadSpin(BossModule module, AID aid, uint enemy) : Components.Cleave(module, ActionID.MakeSpell(aid), new AOEShapeCircle(5.225f), enemy) +abstract class HeadSpin(BossModule module, AID aid, OID oid) : Components.Cleave(module, ActionID.MakeSpell(aid), new AOEShapeCircle(5.225f), [(uint)oid]) { public override void AddHints(int slot, Actor actor, TextHints hints) { @@ -49,8 +49,8 @@ public override void DrawArenaForeground(int pcSlot, Actor pc) base.DrawArenaForeground(pcSlot, pc); } } -class Headspin1(BossModule module) : HeadSpin(module, AID.Headspin1, (uint)OID.ScrambledPaladin); -class Headspin2(BossModule module) : HeadSpin(module, AID.Headspin2, (uint)OID.ScrambledEngineer); +class Headspin1(BossModule module) : HeadSpin(module, AID.Headspin1, OID.ScrambledPaladin); +class Headspin2(BossModule module) : HeadSpin(module, AID.Headspin2, OID.ScrambledEngineer); class GrandSword(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GrandSword), new AOEShapeCone(16, 60.Degrees())); class TheHand(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheHand), new AOEShapeCone(7.5f, 60.Degrees())); diff --git a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs index da72f1e168..92df9ddaf9 100644 --- a/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs +++ b/BossMod/Modules/Heavensward/Dungeon/D13SohrKhai/D0130CloudGardener.cs @@ -25,7 +25,7 @@ public enum AID : uint class RiseAndFall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RiseAndFall), new AOEShapeCone(9, 135.Degrees())); class TightTornado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TightTornado), new AOEShapeRect(18, 2)); -class Venom(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Venom), new AOEShapeCone(10.9f, 60.Degrees()), (uint)OID.SanctuarySkipper); +class Venom(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Venom), new AOEShapeCone(10.9f, 60.Degrees()), [(uint)OID.SanctuarySkipper]); class DarkBlizzardIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DarkBlizzardIII), 5); class D130CloudGardenerStates : StateMachineBuilder diff --git a/BossMod/Modules/Heavensward/Extreme/Ext3Thordan/Ex3Thordan.cs b/BossMod/Modules/Heavensward/Extreme/Ext3Thordan/Ex3Thordan.cs index b0fb07f3c4..a451de6705 100644 --- a/BossMod/Modules/Heavensward/Extreme/Ext3Thordan/Ex3Thordan.cs +++ b/BossMod/Modules/Heavensward/Extreme/Ext3Thordan/Ex3Thordan.cs @@ -2,7 +2,7 @@ namespace BossMod.Heavensward.Extreme.Ex3Thordan; class AscalonsMight(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.AscalonsMight), new AOEShapeCone(11.8f, 45.Degrees())); -abstract class HeavenlySlash(BossModule module, OID oid) : Components.Cleave(module, ActionID.MakeSpell(AID.HeavenlySlash), new AOEShapeCone(10.2f, 45.Degrees()), (uint)oid); +abstract class HeavenlySlash(BossModule module, OID oid) : Components.Cleave(module, ActionID.MakeSpell(AID.HeavenlySlash), new AOEShapeCone(10.2f, 45.Degrees()), [(uint)oid]); class HeavenlySlashAdelphel(BossModule module) : HeavenlySlash(module, OID.SerAdelphel); class HeavenlySlashJanlenoux(BossModule module) : HeavenlySlash(module, OID.SerJanlenoux); diff --git a/BossMod/Modules/Heavensward/Quest/DivineIntervention.cs b/BossMod/Modules/Heavensward/Quest/DivineIntervention.cs deleted file mode 100644 index c81f39bf27..0000000000 --- a/BossMod/Modules/Heavensward/Quest/DivineIntervention.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace BossMod.Heavensward.Quest.DivineIntervention; - -public enum OID : uint -{ - Boss = 0x1010, - Helper = 0x233C, - IshgardianSteelChain = 0x102C, // R1.000, x1 - SerPaulecrainColdfire = 0x1011, // R0.500, x1 - ThunderPicket = 0xEC4, // R1.000, x0 (spawn during fight) -} - -public enum AID : uint -{ - LightningBolt = 3993, // EC4->E0F, 2.0s cast, width 4 rect charge - IronTempest = 1003, // Boss->self, 3.5s cast, range 5+R circle - Overpower = 720, // Boss->self, 2.5s cast, range 6+R 90-degree cone - RingOfFrost = 1316, // 1011->self, 3.0s cast, range 6+R circle - Rive = 1135, // Boss->self, 2.5s cast, range 30+R width 2 rect - Heartstopper = 866, // 1011->self, 2.5s cast, range 3+R width 3 rect -} - -class LightningBolt(BossModule module) : Components.ChargeAOEs(module, ActionID.MakeSpell(AID.LightningBolt), 2); -class IronTempest(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.IronTempest), new AOEShapeCircle(5.5f)); -class Overpower(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(6.5f, 45.Degrees())); -class RingOfFrost(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RingOfFrost), new AOEShapeCircle(6.5f)); -class Rive(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Rive), new AOEShapeRect(30.5f, 1)); -class Heartstopper(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Heartstopper), new AOEShapeRect(3.5f, 1.5f)); -class Chain(BossModule module) : Components.Adds(module, (uint)OID.IshgardianSteelChain, 1); - -class SerGrinnauxTheBullStates : StateMachineBuilder -{ - public SerGrinnauxTheBullStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .Raw.Update = () => module.PrimaryActor.IsDeadOrDestroyed && module.Enemies(OID.SerPaulecrainColdfire).All(x => x.IsDeadOrDestroyed); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 67133, NameID = 3850)] -public class SerGrinnauxTheBull(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, 2), FunnyBounds) -{ - public static ArenaBoundsCustom NewBounds() - { - var arc = CurveApprox.CircleArc(new(3.6f, 0), 11.5f, 0.Degrees(), 180.Degrees(), 0.01f); - var arc2 = CurveApprox.CircleArc(new(-3.6f, 0), 11.5f, 180.Degrees(), 360.Degrees(), 0.01f); - - return new(16, new(arc.Concat(arc2).Select(a => a.ToWDir()))); - } - - public static readonly ArenaBoundsCustom FunnyBounds = NewBounds(); - - protected override void DrawEnemies(int pcSlot, Actor pc) - { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); - } -} diff --git a/BossMod/Modules/Heavensward/Quest/DragoonsFate.cs b/BossMod/Modules/Heavensward/Quest/Job/Dragoon/DragoonsFate.cs similarity index 61% rename from BossMod/Modules/Heavensward/Quest/DragoonsFate.cs rename to BossMod/Modules/Heavensward/Quest/Job/Dragoon/DragoonsFate.cs index 6ffdd0b21f..623bbe27e3 100644 --- a/BossMod/Modules/Heavensward/Quest/DragoonsFate.cs +++ b/BossMod/Modules/Heavensward/Quest/Job/Dragoon/DragoonsFate.cs @@ -1,32 +1,30 @@ -namespace BossMod.Heavensward.Quest.DragoonsFate; +namespace BossMod.Heavensward.Quest.Job.DragoonsFate; public enum OID : uint { - Boss = 0x10B9, // R7.000, x1 - Icicle = 0x10BC, // R2.500, x0 (spawn during fight) - Graoully = 0x10BA, // R7.000, x0 (spawn during fight) + Boss = 0x10B9, // R7.0 + Icicle = 0x10BC, // R2.5 + Graoully = 0x10BA, // R7.0 } public enum AID : uint { - PillarImpact = 3095, // 10BC->self, 3.0s cast, range 4+R circle - PillarPierce = 4259, // 10BC->self, 2.0s cast, range 80+R width 4 rect - Cauterize = 4260, // 10BA->self, 3.0s cast, range 48+R width 20 rect - SheetOfIce = 4261, // Boss->location, 2.5s cast, range 5 circle + PillarImpact = 3095, // Icicle->self, 3.0s cast, range 4+R circle + PillarPierce = 4259, // Icicle->self, 2.0s cast, range 80+R width 4 rect + Cauterize = 4260, // Graoully->self, 3.0s cast, range 48+R width 20 rect + SheetOfIce = 4261 // Boss->location, 2.5s cast, range 5 circle } public enum SID : uint { Prey = 904, // none->player/10BB, extra=0x0 - SlipperyPrey = 475, // none->player/10BB, extra=0x0 - ThinIce = 905, // Boss->player/10BB, extra=0x1/0x2/0x3 - DeepFreeze = 3479, // Boss->10BB/player, extra=0x1 + ThinIce = 905 // Boss->player/10BB, extra=0x1/0x2/0x3 } -class SheetOfIce(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.SheetOfIce), 5); -class PillarImpact(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.PillarImpact), new AOEShapeCircle(6.5f)); -class PillarPierce(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.PillarPierce), new AOEShapeRect(82.5f, 2)); -class Cauterize(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Cauterize), new AOEShapeRect(55, 10)); +class SheetOfIce(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SheetOfIce), 5); +class PillarImpact(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PillarImpact), 6.5f); +class PillarPierce(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PillarPierce), new AOEShapeRect(82.5f, 2)); +class Cauterize(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Cauterize), new AOEShapeRect(55, 10)); class Prey(BossModule module) : BossComponent(module) { @@ -71,7 +69,7 @@ public override void OnStatusLose(Actor actor, ActorStatus status) public override void DrawArenaBackground(int pcSlot, Actor pc) { if (PreyCur is Actor p && Module.PrimaryActor is var primary && primary.IsTargetable) - Cleave.Outline(Arena, primary.Position, primary.AngleTo(p), ArenaColor.Danger); + Cleave.Outline(Arena, primary.Position, primary.AngleTo(p), Colors.Danger); } } @@ -89,9 +87,7 @@ public GraoullyStates(BossModule module) : base(module) } [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 67231, NameID = 4190)] -public class Graoully(WorldState ws, Actor primary) : BossModule(ws, primary, BCenter, BBounds) +public class Graoully(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - public static readonly WPos BCenter = new(-515.285f, -304.69f); - private static readonly WPos[] Corners = [new(-483.91f, -299.22f), new(-519.70f, -272.85f), new(-546.66f, -309.50f), new(-510.38f, -336.53f)]; - public static readonly ArenaBoundsCustom BBounds = new(32, new(Corners.Select(c => c - BCenter))); + private static readonly ArenaBoundsComplex arena = new([new PolygonCustom([new(-483.91f, -299.22f), new(-519.70f, -272.85f), new(-546.66f, -309.50f), new(-510.38f, -336.53f)])]); } diff --git a/BossMod/Modules/Heavensward/Quest/ASpectacleForTheAges.cs b/BossMod/Modules/Heavensward/Quest/MSQ/ASpectacleForTheAges.cs similarity index 75% rename from BossMod/Modules/Heavensward/Quest/ASpectacleForTheAges.cs rename to BossMod/Modules/Heavensward/Quest/MSQ/ASpectacleForTheAges.cs index 3d1a98e541..1835e06965 100644 --- a/BossMod/Modules/Heavensward/Quest/ASpectacleForTheAges.cs +++ b/BossMod/Modules/Heavensward/Quest/MSQ/ASpectacleForTheAges.cs @@ -1,4 +1,4 @@ -namespace BossMod.Heavensward.Quest.ASpectacleForTheAges; +namespace BossMod.Heavensward.Quest.MSQ.ASpectacleForTheAges; public enum OID : uint { @@ -12,8 +12,8 @@ public enum AID : uint TheCurse = 5765, // D25->self, 3.0s cast, range 7+R ?-degree cone } -class FlamingTizona(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.FlamingTizona), 6); -class TheCurse(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TheCurse), new AOEShapeDonutSector(2, 7, 90.Degrees())); +class FlamingTizona(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlamingTizona), 6); +class TheCurse(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheCurse), new AOEShapeDonutSector(2, 7, 90.Degrees())); class Demoralize(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(0x1E9FA8).Where(e => e.EventState != 7)); class Tizona(BossModule module) : Components.Adds(module, (uint)OID.Tizona, 5); diff --git a/BossMod/Modules/Heavensward/Quest/CloseEncountersOfTheVIthKind.cs b/BossMod/Modules/Heavensward/Quest/MSQ/CloseEncountersOfTheVIthKind.cs similarity index 79% rename from BossMod/Modules/Heavensward/Quest/CloseEncountersOfTheVIthKind.cs rename to BossMod/Modules/Heavensward/Quest/MSQ/CloseEncountersOfTheVIthKind.cs index b8941f2050..000030cef2 100644 --- a/BossMod/Modules/Heavensward/Quest/CloseEncountersOfTheVIthKind.cs +++ b/BossMod/Modules/Heavensward/Quest/MSQ/CloseEncountersOfTheVIthKind.cs @@ -1,4 +1,4 @@ -namespace BossMod.Heavensward.Quest.CloseEncountersOfTheVIthKind; +namespace BossMod.Heavensward.Quest.MSQ.CloseEncountersOfTheVIthKind; public enum OID : uint { @@ -21,28 +21,27 @@ public RegulaVanHydrusStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } -class HandOfTheEmpire(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.HandOfTheEmpire), 2); - +class HandOfTheEmpire(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HandOfTheEmpire), 2); class Voidzone(BossModule module) : Components.PersistentVoidzone(module, 8, m => m.Enemies(OID.Puddle)); class TerminusEst(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.TerminusEstAOE)) { private bool _active; + private static readonly AOEShapeRect rect = new(40, 2); private IEnumerable Adds => Module.Enemies(OID.TerminusEst).Where(x => !x.IsDead); public override void DrawArenaForeground(int pcSlot, Actor pc) { - Arena.Actors(Adds, ArenaColor.Danger, true); + Arena.Actors(Adds, Colors.Danger, true); } public override IEnumerable ActiveAOEs(int slot, Actor actor) - => _active ? Adds.Select(x => new AOEInstance(new AOEShapeRect(40, 2), x.Position, x.Rotation)) : []; + => _active ? Adds.Select(x => new AOEInstance(rect, x.Position, x.Rotation)) : []; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { diff --git a/BossMod/Modules/Heavensward/Quest/MSQ/DivineIntervention.cs b/BossMod/Modules/Heavensward/Quest/MSQ/DivineIntervention.cs new file mode 100644 index 0000000000..171951eda5 --- /dev/null +++ b/BossMod/Modules/Heavensward/Quest/MSQ/DivineIntervention.cs @@ -0,0 +1,70 @@ +namespace BossMod.Heavensward.Quest.MSQ.DivineIntervention; + +public enum OID : uint +{ + Boss = 0x1010, + IshgardianSteelChain = 0x102C, // R1.0 + SerPaulecrainColdfire = 0x1011, // R0.5 + ThunderPicket = 0xEC4, // R1.0 + Helper = 0x233C +} + +public enum AID : uint +{ + LightningBolt = 3993, // ThunderPicket->E0F, 2.0s cast, width 4 rect charge + IronTempest = 1003, // Boss->self, 3.5s cast, range 5+R circle + Overpower = 720, // Boss->self, 2.5s cast, range 6+R 90-degree cone + RingOfFrost = 1316, // SerPaulecrainColdfire->self, 3.0s cast, range 6+R circle + Rive = 1135, // Boss->self, 2.5s cast, range 30+R width 2 rect + Heartstopper = 866, // SerPaulecrainColdfire->self, 2.5s cast, range 3+R width 3 rect +} + +class LightningBolt(BossModule module) : Components.ChargeAOEs(module, ActionID.MakeSpell(AID.LightningBolt), 2); +class IronTempest(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IronTempest), 5.5f); +class Overpower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(6.5f, 45.Degrees())); +class RingOfFrost(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RingOfFrost), 6.5f); +class Rive(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Rive), new AOEShapeRect(30.5f, 1)); +class Heartstopper(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Heartstopper), new AOEShapeRect(3.5f, 1.5f)); +class Chain(BossModule module) : Components.Adds(module, (uint)OID.IshgardianSteelChain, 1); + +class SerGrinnauxStates : StateMachineBuilder +{ + public SerGrinnauxStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(SerGrinnaux.Bosses).All(x => x.IsDeadOrDestroyed); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 67133, NameID = 3850)] +public class SerGrinnaux(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) +{ + private static readonly ArenaBoundsComplex arena = new([new Capsule(new(0, 1.979f), 3.66f, 11.45f, 50, 90.Degrees())], [new Rectangle(new(0, -9.995f), 4, 0.7f)]); + public static readonly uint[] Bosses = [(uint)OID.Boss, (uint)OID.SerPaulecrainColdfire]; + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(Bosses)); + Arena.Actors(Enemies(OID.IshgardianSteelChain), Colors.Object); + } + + protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var e = hints.PotentialTargets[i]; + e.Priority = (OID)e.Actor.OID switch + { + OID.IshgardianSteelChain => 1, + _ => 0 + }; + } + } +} diff --git a/BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs b/BossMod/Modules/Heavensward/Quest/MSQ/FlyFreeMyPretty.cs similarity index 67% rename from BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs rename to BossMod/Modules/Heavensward/Quest/MSQ/FlyFreeMyPretty.cs index 965839ee10..4b7812c68f 100644 --- a/BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs +++ b/BossMod/Modules/Heavensward/Quest/MSQ/FlyFreeMyPretty.cs @@ -1,15 +1,11 @@ -<<<<<<<< HEAD:BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs -namespace BossMod.Heavensward.Quest.MSQ.Heliodrome; -======== -namespace BossMod.Heavensward.Quest.FlyFreeMyPretty; ->>>>>>>> merge:BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs +namespace BossMod.Heavensward.Quest.MSQ.FlyFreeMyPretty; public enum OID : uint { Boss = 0x195E, - Helper = 0x233C, - GrynewahtP2 = 0x195F, // R0.500, x0 (spawn during fight) - ImperialColossus = 0x1966, // R3.000, x0 (spawn during fight) + GrynewahtP2 = 0x195F, // R0.5 + ImperialColossus = 0x1966, // R3.0 + Helper = 0x233C } public enum AID : uint @@ -30,8 +26,8 @@ class MagitekMissiles(BossModule module) : Components.SimpleAOEs(module, ActionI class ShrapnelShell(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ShrapnelShell), 6); class Firebomb(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(0x1E86DF).Where(e => e.EventState != 7)); -class Uprising(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedUprising), new AOEShapeCone(8.5f, 60.Degrees())); -class Suffering(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedSuffering), 6.5f); +class AugmentedUprising(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedUprising), new AOEShapeCone(8.5f, 60.Degrees())); +class AugmentedSuffering(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedSuffering), 6.5f); class Heartstopper(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Heartstopper), new AOEShapeRect(3.5f, 1.5f)); class Overpower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(6, 45.Degrees())); class GrandSword(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GrandSword), new AOEShapeCone(21, 60.Degrees())); @@ -42,8 +38,11 @@ class Adds(BossModule module) : Components.AddsMulti(module, [0x1960, 0x1961, 0x { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var e = hints.PotentialTargets[i]; e.Priority = (OID)e.Actor.OID == OID.ImperialColossus ? 5 : e.Actor.TargetID == actor.InstanceID ? 1 : 0; + } } } @@ -52,7 +51,7 @@ class Bounds(BossModule module) : BossComponent(module) public override void OnEventDirectorUpdate(uint updateID, uint param1, uint param2, uint param3, uint param4) { if (updateID == 0x10000002) - Arena.Bounds = new ArenaBoundsCircle(20); + Arena.Bounds = Grynewaht.CircleBounds; } } @@ -77,8 +76,8 @@ public GrynewahtStates(BossModule module) : base(module) { State build(uint id) => SimpleState(id, 10000, "Enrage") .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() @@ -89,37 +88,17 @@ State build(uint id) => SimpleState(id, 10000, "Enrage") .ActivateOnEnter(); SimplePhase(1, id => build(id).ActivateOnEnter(), "P1") - .Raw.Update = () => module.Enemies(OID.GrynewahtP2).Count != 0; + .Raw.Update = () => Module.Enemies(OID.GrynewahtP2).Count != 0; DeathPhase(0x100, id => build(id).ActivateOnEnter().OnEnter(() => { - module.Arena.Bounds = Grynewaht.CircleBounds; + Module.Arena.Bounds = Grynewaht.CircleBounds; })); } } -<<<<<<<< HEAD:BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 222, NameID = 5576)] -public class Grynewaht(WorldState ws, Actor primary) : BossModule(ws, primary, default, hexBounds) -======== [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 67894, NameID = 5576)] -public class Grynewaht(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, 0), HexBounds) ->>>>>>>> merge:BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs +public class Grynewaht(WorldState ws, Actor primary) : BossModule(ws, primary, default, hexBounds) { private static readonly ArenaBoundsComplex hexBounds = new([new Polygon(default, 10.675f, 6, 30.Degrees())]); public static readonly ArenaBoundsComplex CircleBounds = new([new Polygon(default, 20, 20)]); - -<<<<<<<< HEAD:BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs - protected override bool CheckPull() => Raid.Player()!.InCombat; -======== - private static ArenaBoundsCustom BuildHexBounds() - { - var hexSideLen = 20 / MathF.Sqrt(3); - - // slight adjustment to account for player hitbox radius, otherwise dodges can get very sketchy - hexSideLen -= 1.5f; - - List verts = [new(hexSideLen, 0), hexSideLen * 30.Degrees().ToDirection(), -hexSideLen * 150.Degrees().ToDirection(), new(-hexSideLen, 0), hexSideLen * -30.Degrees().ToDirection(), hexSideLen * 150.Degrees().ToDirection()]; - return new(hexSideLen, new(verts)); - } ->>>>>>>> merge:BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs } diff --git a/BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs b/BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs deleted file mode 100644 index 965839ee10..0000000000 --- a/BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs +++ /dev/null @@ -1,125 +0,0 @@ -<<<<<<<< HEAD:BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs -namespace BossMod.Heavensward.Quest.MSQ.Heliodrome; -======== -namespace BossMod.Heavensward.Quest.FlyFreeMyPretty; ->>>>>>>> merge:BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs - -public enum OID : uint -{ - Boss = 0x195E, - Helper = 0x233C, - GrynewahtP2 = 0x195F, // R0.500, x0 (spawn during fight) - ImperialColossus = 0x1966, // R3.000, x0 (spawn during fight) -} - -public enum AID : uint -{ - AugmentedUprising = 7608, // Boss->self, 3.0s cast, range 8+R 120-degree cone - AugmentedSuffering = 7607, // Boss->self, 3.5s cast, range 6+R circle - Heartstopper = 866, // ImperialEques->self, 2.5s cast, range 3+R width 3 rect - Overpower = 720, // ImperialLaquearius->self, 2.1s cast, range 6+R 90-degree cone - GrandSword = 7615, // ImperialColossus->self, 3.0s cast, range 18+R 120-degree cone - MagitekRay = 7617, // ImperialColossus->location, 3.0s cast, range 6 circle - GrandStrike = 7616, // ImperialColossus->self, 2.5s cast, range 45+R width 4 rect - ShrapnelShell = 7614, // GrynewahtP2->location, 2.5s cast, range 6 circle - MagitekMissiles = 7612, // GrynewahtP2->location, 5.0s cast, range 15 circle - -} - -class MagitekMissiles(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekMissiles), 15); -class ShrapnelShell(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ShrapnelShell), 6); -class Firebomb(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(0x1E86DF).Where(e => e.EventState != 7)); - -class Uprising(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedUprising), new AOEShapeCone(8.5f, 60.Degrees())); -class Suffering(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedSuffering), 6.5f); -class Heartstopper(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Heartstopper), new AOEShapeRect(3.5f, 1.5f)); -class Overpower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(6, 45.Degrees())); -class GrandSword(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GrandSword), new AOEShapeCone(21, 60.Degrees())); -class MagitekRay(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekRay), 6); -class GrandStrike(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GrandStrike), new AOEShapeRect(48, 2)); - -class Adds(BossModule module) : Components.AddsMulti(module, [0x1960, 0x1961, 0x1962, 0x1963, 0x1964, 0x1965, 0x1966]) -{ - public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - foreach (var e in hints.PotentialTargets) - e.Priority = (OID)e.Actor.OID == OID.ImperialColossus ? 5 : e.Actor.TargetID == actor.InstanceID ? 1 : 0; - } -} - -class Bounds(BossModule module) : BossComponent(module) -{ - public override void OnEventDirectorUpdate(uint updateID, uint param1, uint param2, uint param3, uint param4) - { - if (updateID == 0x10000002) - Arena.Bounds = new ArenaBoundsCircle(20); - } -} - -class ReaperAI(BossModule module) : BossComponent(module) -{ - public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - if (actor.MountId == 103 && WorldState.Actors.Find(actor.TargetID) is var target && target != null) - { - if ((OID)target.OID == OID.ImperialColossus) - hints.ActionsToExecute.Push(ActionID.MakeSpell(Roleplay.AID.DiffractiveMagitekCannon), target, ActionQueue.Priority.High, targetPos: target.PosRot.XYZ()); - hints.ActionsToExecute.Push(ActionID.MakeSpell(Roleplay.AID.MagitekCannon), target, ActionQueue.Priority.High, targetPos: target.PosRot.XYZ()); - - hints.GoalZones.Add(hints.GoalSingleTarget(target, 25)); - } - } -} - -class GrynewahtStates : StateMachineBuilder -{ - public GrynewahtStates(BossModule module) : base(module) - { - State build(uint id) => SimpleState(id, 10000, "Enrage") - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - - SimplePhase(1, id => build(id).ActivateOnEnter(), "P1") - .Raw.Update = () => module.Enemies(OID.GrynewahtP2).Count != 0; - DeathPhase(0x100, id => build(id).ActivateOnEnter().OnEnter(() => - { - module.Arena.Bounds = Grynewaht.CircleBounds; - })); - } -} - -<<<<<<<< HEAD:BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 222, NameID = 5576)] -public class Grynewaht(WorldState ws, Actor primary) : BossModule(ws, primary, default, hexBounds) -======== -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 67894, NameID = 5576)] -public class Grynewaht(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, 0), HexBounds) ->>>>>>>> merge:BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs -{ - private static readonly ArenaBoundsComplex hexBounds = new([new Polygon(default, 10.675f, 6, 30.Degrees())]); - public static readonly ArenaBoundsComplex CircleBounds = new([new Polygon(default, 20, 20)]); - -<<<<<<<< HEAD:BossMod/Modules/Heavensward/Quest/MSQ/Heliodrome.cs - protected override bool CheckPull() => Raid.Player()!.InCombat; -======== - private static ArenaBoundsCustom BuildHexBounds() - { - var hexSideLen = 20 / MathF.Sqrt(3); - - // slight adjustment to account for player hitbox radius, otherwise dodges can get very sketchy - hexSideLen -= 1.5f; - - List verts = [new(hexSideLen, 0), hexSideLen * 30.Degrees().ToDirection(), -hexSideLen * 150.Degrees().ToDirection(), new(-hexSideLen, 0), hexSideLen * -30.Degrees().ToDirection(), hexSideLen * 150.Degrees().ToDirection()]; - return new(hexSideLen, new(verts)); - } ->>>>>>>> merge:BossMod/Modules/Heavensward/Quest/FlyFreeMyPretty.cs -} diff --git a/BossMod/Modules/Heavensward/Quest/MSQ/OneLifeOneWorld.cs b/BossMod/Modules/Heavensward/Quest/MSQ/OneLifeOneWorld.cs index 344ee0a806..10af1ca419 100644 --- a/BossMod/Modules/Heavensward/Quest/MSQ/OneLifeOneWorld.cs +++ b/BossMod/Modules/Heavensward/Quest/MSQ/OneLifeOneWorld.cs @@ -62,8 +62,9 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme { var playerIsAttacked = false; - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; if (e.Actor.TargetID == actor.InstanceID) { playerIsAttacked = true; @@ -85,8 +86,9 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme } else { - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; if (e.Actor == Knight) e.Priority = 2; else if (e.Actor == Covered) diff --git a/BossMod/Modules/Heavensward/Quest/TheFateOfStars.cs b/BossMod/Modules/Heavensward/Quest/TheFateOfStars.cs deleted file mode 100644 index e9f3b69463..0000000000 --- a/BossMod/Modules/Heavensward/Quest/TheFateOfStars.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace BossMod.Heavensward.Quest.TheFateOfStars; - -public enum OID : uint -{ - Boss = 0x161E, - Helper = 0x233C, - MagitekTurretI = 0x161F, // R0.600, x0 (spawn during fight) - MagitekTurretII = 0x1620, // R0.600, x0 (spawn during fight) - TerminusEst = 0x1621, // R1.000, x0 (spawn during fight) -} - -public enum AID : uint -{ - MagitekSlug = 6026, // Boss->self, 2.5s cast, range 60+R width 4 rect - AetherochemicalGrenado = 6031, // 1620->location, 3.0s cast, range 8 circle - SelfDetonate = 6032, // 161F/1620->self, 5.0s cast, range 40+R circle - MagitekSpread = 6027, // Boss->self, 3.0s cast, range 20+R 240-degree cone -} - -class MagitekSlug(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MagitekSlug), new AOEShapeRect(60, 2)); -class AetherochemicalGrenado(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.AetherochemicalGrenado), 8); -class SelfDetonate(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.SelfDetonate), "Kill turret before detonation!", true) -{ - public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - foreach (var h in hints.PriorityTargets) - if (h.Actor.CastInfo?.Action == WatchedAction) - h.Priority = 5; - } -} -class MagitekSpread(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MagitekSpread), new AOEShapeCone(20.55f, 120.Degrees())); - -class RegulaVanHydrusStates : StateMachineBuilder -{ - public RegulaVanHydrusStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 67824, NameID = 3818)] -public class RegulaVanHydrus(WorldState ws, Actor primary) : BossModule(ws, primary, new(230, 79), new ArenaBoundsCircle(20)) -{ - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); -} - diff --git a/BossMod/Modules/Heavensward/Quest/TheWarringTriad/ABloodyReunion.cs b/BossMod/Modules/Heavensward/Quest/TheWarringTriad/ABloodyReunion.cs new file mode 100644 index 0000000000..c3b51241dd --- /dev/null +++ b/BossMod/Modules/Heavensward/Quest/TheWarringTriad/ABloodyReunion.cs @@ -0,0 +1,59 @@ +namespace BossMod.Heavensward.Quest.WarringTriad.ABloodyReunion; + +public enum OID : uint +{ + Boss = 0x161E, + MagitekTurretI = 0x161F, // R0.6 + MagitekTurretII = 0x1620, // R0.6 + TerminusEst = 0x1621, // R1.0 + Helper = 0x233C +} + +public enum AID : uint +{ + MagitekSlug = 6026, // Boss->self, 2.5s cast, range 60+R width 4 rect + AetherochemicalGrenado = 6031, // MagitekTurretII->location, 3.0s cast, range 8 circle + SelfDetonate = 6032, // MagitekTurretI/MagitekTurretII->self, 5.0s cast, range 40+R circle + MagitekSpread = 6027, // Boss->self, 3.0s cast, range 20+R 240-degree cone +} + +class MagitekSlug(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekSlug), new AOEShapeRect(60, 2)); +class AetherochemicalGrenado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherochemicalGrenado), 8); +class SelfDetonate(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.SelfDetonate), "Kill turret before detonation!", true) +{ + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + var count = hints.PotentialTargets.Count; + for (var i = 0; i < count; ++i) + { + var h = hints.PotentialTargets[i]; + if (h.Actor.CastInfo?.Action == WatchedAction) + h.Priority = 5; + } + } +} +class MagitekSpread(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekSpread), new AOEShapeCone(20.55f, 120.Degrees())); + +class RegulaVanHydrusStates : StateMachineBuilder +{ + public RegulaVanHydrusStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 173, NameID = 3818)] +public class RegulaVanHydrus(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) +{ + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(230, 79), 20.256f, 24)]); + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies([(uint)OID.MagitekTurretI, (uint)OID.MagitekTurretII])); + Arena.Actor(PrimaryActor); + } +} diff --git a/BossMod/Modules/RealmReborn/Extreme/Ex2Garuda/Ex2Garuda.cs b/BossMod/Modules/RealmReborn/Extreme/Ex2Garuda/Ex2Garuda.cs index 36b27c56e9..d919291c37 100644 --- a/BossMod/Modules/RealmReborn/Extreme/Ex2Garuda/Ex2Garuda.cs +++ b/BossMod/Modules/RealmReborn/Extreme/Ex2Garuda/Ex2Garuda.cs @@ -2,9 +2,9 @@ class DownburstBoss(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Downburst1), new AOEShapeCone(11.7f, 60.Degrees())); // TODO: verify angle -abstract class Downburst(BossModule module, AID aid, uint oid) : Components.Cleave(module, ActionID.MakeSpell(aid), new AOEShapeCone(11.36f, 60.Degrees()), oid); // TODO: verify angle -class DownburstSuparna(BossModule module) : Downburst(module, AID.Downburst1, (uint)OID.Suparna); // TODO: verify angle -class DownburstChirada(BossModule module) : Downburst(module, AID.Downburst2, (uint)OID.Chirada); // TODO: verify angle +abstract class Downburst(BossModule module, AID aid, OID oid) : Components.Cleave(module, ActionID.MakeSpell(aid), new AOEShapeCone(11.36f, 60.Degrees()), [(uint)oid]); // TODO: verify angle +class DownburstSuparna(BossModule module) : Downburst(module, AID.Downburst1, OID.Suparna); // TODO: verify angle +class DownburstChirada(BossModule module) : Downburst(module, AID.Downburst2, OID.Chirada); // TODO: verify angle class Slipstream(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Slipstream), new AOEShapeCone(11.7f, 45.Degrees())); class FrictionAdds(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FrictionAdds), 5); diff --git a/BossMod/Modules/RealmReborn/Quest/OperationArchon.cs b/BossMod/Modules/RealmReborn/Quest/MSQ/OperationArchon.cs similarity index 54% rename from BossMod/Modules/RealmReborn/Quest/OperationArchon.cs rename to BossMod/Modules/RealmReborn/Quest/MSQ/OperationArchon.cs index 2b69db0e91..aacea470b6 100644 --- a/BossMod/Modules/RealmReborn/Quest/OperationArchon.cs +++ b/BossMod/Modules/RealmReborn/Quest/MSQ/OperationArchon.cs @@ -1,11 +1,11 @@ -namespace BossMod.RealmReborn.Quest.OperationArchon; +namespace BossMod.RealmReborn.Quest.MSQ.OperationArchon; public enum OID : uint { Boss = 0x38F5, // R1.500, x? - Helper = 0x233C, // R0.500, x?, Helper type ImperialPilusPrior = 0x38F7, // R1.500, x0 (spawn during fight) ImperialCenturion = 0x38F6, // R1.500, x0 (spawn during fight) + Helper = 0x233C } public enum SID : uint @@ -24,24 +24,25 @@ public enum AID : uint GalesOfTartarus1 = 28876, // Boss->self, 6.0s cast, range 30 width 30 rect } -class Adds(BossModule module) : Components.Adds(module, (uint)OID.ImperialCenturion); -class Adds1(BossModule module) : Components.Adds(module, (uint)OID.ImperialPilusPrior); +class Adds(BossModule module) : Components.AddsMulti(module, [(uint)OID.ImperialPilusPrior, (uint)OID.ImperialCenturion]); -class MagitekMissiles(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.MagitekMissiles), 7); -class DrillShot(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DrillShot), new AOEShapeRect(30, 2.5f)); -class TartareanShockwave(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TartareanShockwave), new AOEShapeCircle(7)); -class BigTartareanShockwave(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TartareanShockwave1), new AOEShapeCircle(14)); -class GalesOfTartarus(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.GalesOfTartarus), new AOEShapeRect(30, 2.5f)); -class BigGalesOfTartarus(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.GalesOfTartarus1), new AOEShapeRect(30, 15)); -class DirectionalParry(BossModule module) : Components.DirectionalParry(module, (uint)OID.Boss) +class MagitekMissiles(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekMissiles), 7); +class DrillShot(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DrillShot), new AOEShapeRect(30, 2.5f)); +class TartareanShockwave(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TartareanShockwave), 7); +class BigTartareanShockwave(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TartareanShockwave1), 14); +class GalesOfTartarus(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GalesOfTartarus), new AOEShapeRect(30, 2.5f)); +class BigGalesOfTartarus(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GalesOfTartarus1), new AOEShapeRect(30, 15)); +class DirectionalParry(BossModule module) : Components.DirectionalParry(module, [(uint)OID.Boss]) { + private static readonly Angle a45 = 45.Degrees(); + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { if (Module.PrimaryActor.FindStatus(SID.DirectionalParry) != null) - hints.AddForbiddenZone(new AOEShapeCone(100, 45.Degrees()), Module.PrimaryActor.Position, Module.PrimaryActor.Rotation, WorldState.FutureTime(10)); + hints.AddForbiddenZone(ShapeDistance.Cone(Module.PrimaryActor.Position, 100, Module.PrimaryActor.Rotation, a45), WorldState.FutureTime(10)); } } -class TartareanTomb(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TartareanTomb), new AOEShapeCircle(11)); +class TartareanTomb(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TartareanTomb), 11); class RhitahtynSasArvinaStates : StateMachineBuilder { @@ -54,11 +55,9 @@ public RhitahtynSasArvinaStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } diff --git a/BossMod/Modules/RealmReborn/Quest/MSQ/TheStepsOfFaith.cs b/BossMod/Modules/RealmReborn/Quest/MSQ/TheStepsOfFaith.cs new file mode 100644 index 0000000000..eb89d11dbe --- /dev/null +++ b/BossMod/Modules/RealmReborn/Quest/MSQ/TheStepsOfFaith.cs @@ -0,0 +1,340 @@ +namespace BossMod.RealmReborn.Quest.MSQ.TheStepsOfFaith; + +public enum OID : uint +{ + Boss = 0x3A5F, // R30.0 + HordeWyvern1 = 0x3CD5, // R3.6 + HordeWyvern2 = 0x3AA2, // R3.6 + HordeWyvern3 = 0x3AA4, // R3.6 + HordeWyvern4 = 0x3AA5, // R3.6 + HordeWyvern5 = 0x3AAC, // R3.6 + HordeWyvern6 = 0x3AA7, // R3.6 + HordeWyvern7 = 0x3AAF, // R3.6 + HordeWyvern8 = 0x3ABF, // R3.6 + HordeWyvern9 = 0x3AA8, // R3.6 + HordeWyvern10 = 0x3AA9, // R3.6 + HordeDragonfly1 = 0x3A94, // R0.8 + HordeDragonfly2 = 0x3A93, // R0.8 + HordeDragonfly3 = 0x3A95, // R0.8 + HordeDragonfly4 = 0x3A96, // R0.8 + HordeDragonfly5 = 0x3A97, // R0.8 + HordeDragonfly6 = 0x3ABB, // R0.8 + HordeDragonfly7 = 0x3ABC, // R0.8 + HordeDragonfly8 = 0x3AB0, // R0.8 + HordeAevis1 = 0x3A9A, // R2.2 + HordeAevis2 = 0x3A9B, // R2.2 + HordeAevis3 = 0x3A9C, // R2.2 + HordeAevis4 = 0x3A9D, // R2.2 + HordeAevis5 = 0x3AA0, // R2.2 + HordeAevis6 = 0x3A9E, // R2.2 + HordeAevis7 = 0x3A9F, // R2.2 + HordeAevis8 = 0x3AC0, // R2.2 + HordeAevis9 = 0x3AB1, // R2.2 + HordeBiast1 = 0x3AB2, // R2.7 + HordeBiast2 = 0x3AB3, // R2.7 + HordeBiast3 = 0x3AB4, // R2.7 + HordeBiast4 = 0x3AAB, // R2.7 + HordeBiast5 = 0x3AB6, // R2.7 + HordeBiast6 = 0x3AC2, // R2.7 + HordeBiast7 = 0x3AB8, // R2.7 + HordeBiast8 = 0x3AB9, // R2.7 + HordeBiast9 = 0x3AB7, // R2.7 + HordeArmoredDragon = 0x3ABA, // R6.25 + HordeTranscendent = 0x3ABD, // R3.4 + HordeShieldDragon = 0x3AC1, // R5.3 + Helper = 0x233C +} + +public enum AID : uint +{ + AutoAttack1 = 6499, // horde dragons->allies, no cast, single-target + + BlazingShriekVisual = 30882, // Boss->self, no cast, single-target + BlazingShriek = 26407, // Helper->self, 0.8s cast, range 100 width 44 rect + FlameBreathVisual = 30877, // Boss->self, 3.3+1,7s cast, single-target + FlameBreath = 26812, // Helper->self, 35.0s cast, range 1 width 2 rect + FlameBreath1 = 30185, // Helper->self, 5.0s cast, range 1 width 2 rect + FlameBreath2 = 26411, // Boss->self, 3.8+1.2s cast, range 60 width 20 rect + FlameBreath3 = 30186, // Helper->self, 5.0s cast, range 60 width 20 rect + FlameBreathChannel = 30884, // Helper->self, no cast, range 40 width 20 rect + CauterizeVisual = 30878, // Boss->self, 30.5+4.5s cast, single-target + Cauterize = 30885, // Helper->self, no cast, range 40 width 44 rect + Touchdown = 26408, // Helper->self, 6.0s cast, range 80 circle + FireballVisual1 = 30874, // Boss->self, 3.0+3,0s cast, single-target + FireballVisual2 = 30876, // Boss->self, 3.0s cast, single-target + FireballVisual3 = 28975, // Boss->self, 3.0s cast, single-target + FireballSpread = 30875, // Helper->allies, 6.0s cast, range 6 circle + FireballAOE = 30894, // HordeTranscendent->location, 3.5s cast, range 6 circle + BlazingFire = 30211, // Boss->location, no cast, range 10 circle + + BodySlamVisual = 26400, // Boss->self, 4.7+1,3s cast, single-target + BodySlam = 26401, // Helper->self, 6.0s cast, range 80 width 44 rect + Flamisphere = 30883, // Helper->location, 8.0s cast, range 10 circle + + RipperClaw = 31262, // HordeTranscendent->self, 3.7s cast, range 9 90-degree cone + EarthshakerAOE = 30880, // Boss->self, 4.5s cast, range 31 circle + Earthshaker = 30887, // Helper->self, 6.5s cast, range 80 30-degree cone + EarthrisingAOE = 26410, // Boss->self, 4.5s cast, range 31 circle + EarthrisingCast = 30888, // Helper->self, 7.0s cast, range 8 circle + EarthrisingRepeat = 26412, // Helper->self, no cast, range 8 circle + SidewiseSlice = 30879, // Boss->self, 8.0s cast, range 50 120-degree cone + ScorchingBreathVisual = 29785, // Boss->self, 15.0+5.0s cast, single-target + ScorchingBreath = 29789, // Helper->self, no cast, range 40 width 20 rect + SeismicShriekVisual = 30881, // Boss->self, no cast, single-target + SeismicShriek1 = 26405, // Boss->self, no cast, range 100 circle + SeismicShriek2 = 26406, // Boss->self, no cast, range 80 circle + Twingaze = 28971, // Boss->self, no cast, single-target + Levinshower = 30892, // HordeBiast2/HordeBiast4/HordeBiast5/HordeBiast6/HordeBiast7->self, no cast, range 6 120-degree cone + DragonStomp = 30893, // HordeArmoredDragon->self, 2.0s cast, range 40 circle + BoneShaker = 31258, // HordeTranscendent->self, no cast, range 50 circle + MagmaticSpell = 28974, // Boss->self, no cast, single-target + Rake = 30898, // HordeShieldDragon->player, no cast, single-target + FallOfMan = 30187, // Helper->self, 20.0s cast, range 90 width 20 rect +} + +class RipperClaw(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RipperClaw), new AOEShapeCone(9, 45.Degrees())); +class Levinshower(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Levinshower), new AOEShapeCone(6, 60.Degrees()), +[(uint)OID.HordeBiast2, (uint)OID.HordeBiast4, (uint)OID.HordeBiast5, (uint)OID.HordeBiast6, (uint)OID.HordeBiast7]); +class EarthShakerAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EarthshakerAOE), 31); +class Earthshaker(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Earthshaker), new AOEShapeCone(80, 15.Degrees()), 2); + +class EarthrisingAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EarthrisingAOE), 31); +class Earthrising(BossModule module) : Components.Exaflare(module, 8) +{ + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.EarthrisingCast) + { + Lines.Add(new() { Next = spell.LocXZ, Advance = new(0, -7.5f), NextExplosion = Module.CastFinishAt(spell), TimeToMove = 1, ExplosionsLeft = 5, MaxShownExplosions = 2 }); + } + } + + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + if ((AID)spell.Action.ID is AID.EarthrisingRepeat or AID.EarthrisingCast) + { + var index = Lines.FindIndex(item => item.Next.AlmostEqual(caster.Position, 1)); + if (index < 0) + return; + AdvanceLine(Lines[index], caster.Position); + if (Lines[index].ExplosionsLeft == 0) + Lines.RemoveAt(index); + } + } +} + +class SidewiseSlice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SidewiseSlice), new AOEShapeCone(50, 60.Degrees())); + +class FireballSpread(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.FireballSpread), 6); +class FireballAOE(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FireballAOE), 6); +class Flamisphere(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Flamisphere), 10); + +class BodySlam(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.BodySlam), 20, kind: Kind.DirForward, stopAtWall: true); + +class FlameBreath(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.FlameBreathChannel)) +{ + private AOEInstance? _aoe; + private static readonly AOEShapeRect rect = new(500, 10); + + public override IEnumerable ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.FlameBreath1) + _aoe = new(rect, Module.PrimaryActor.Position, Module.PrimaryActor.Rotation, Module.CastFinishAt(spell).AddSeconds(1)); + } + + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + base.OnEventCast(caster, spell); + if (NumCasts >= 35) + { + _aoe = null; + NumCasts = 0; + } + } +} + +class FlameBreath2(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.FlameBreathChannel)) +{ + private AOEInstance? _aoe; + private static readonly AOEShapeRect rect = new(60, 10); + + public override IEnumerable ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.FlameBreath2) + { + NumCasts = 0; + _aoe = new(rect, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell)); + } + } + + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + base.OnEventCast(caster, spell); + if (NumCasts >= 14) + { + _aoe = null; + } + } +} + +class Cauterize(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.Cauterize)) +{ + private Actor? Source; + private static readonly AOEShapeRect rect = new(160, 22); + private static readonly AOEShapeRect MoveIt = new(40, 22, 38); + + public override IEnumerable ActiveAOEs(int slot, Actor actor) + { + if (Source == null) + yield break; + + if (Arena.Center.Z > 218) + yield return new(MoveIt, Arena.Center); + else + yield return new(rect, Source.Position, 180.Degrees(), Module.CastFinishAt(Source.CastInfo)); + } + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if (spell.Action == WatchedAction) + Source = Module.PrimaryActor; + } + + public override void OnCastFinished(Actor caster, ActorCastInfo spell) + { + if (spell.Action == WatchedAction) + Source = null; + } +} + +class Touchdown(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.Touchdown), 10, stopAtWall: true); + +class ScorchingBreath(BossModule module) : Components.GenericAOEs(module) +{ + private static readonly AOEShapeRect rect = new(100, 10, 100); + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.ScorchingBreath) + NumCasts++; + } + + public override IEnumerable ActiveAOEs(int slot, Actor actor) + { + if (NumCasts > 0) + yield return new(rect, Module.PrimaryActor.Position, Module.PrimaryActor.Rotation, Module.CastFinishAt(Module.PrimaryActor.CastInfo)); + } +} + +class ScrollingBounds(BossModule module) : BossComponent(module) +{ + public const float HalfHeight = 40; + public const float HalfWidth = 22; + + public static readonly ArenaBoundsRect Bounds = new(HalfWidth, HalfHeight); + + private int Phase = 1; + private (float Min, float Max) ZBounds = (120, 300); + + public override void OnEventEnvControl(byte index, uint state) + { + if (state == 0x00020001) + { + if (index == 0x03) + { + ZBounds = (120, 200); + Phase = 2; + } + else if (index == 0x04) + { + ZBounds = (-40, 40); + Phase = 4; + } + else if (index == 0x06) + { + ZBounds = (-200, -120); + Phase = 6; + } + } + else if (state == 0x00800040) + { + if (index == 0x00) + { + ZBounds = (-40, 200); + Phase = 3; + } + else if (index == 0x01) + { + ZBounds = (-200, 40); + Phase = 5; + } + } + } + + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + // force player to walk south to aggro vishap (status 1268 = In Event, not actionable) + if (Phase == 1 && !actor.InCombat && actor.FindStatus(1268) == null) + hints.AddForbiddenZone(ShapeDistance.Rect(Arena.Center, new WDir(0, 1), 38, 22, 40)); + // subsequent state transitions don't trigger until player moves into the area + else if (Phase == 3 && actor.Position.Z > 25 || Phase == 5 && actor.Position.Z > -135) + hints.AddForbiddenZone(ShapeDistance.Rect(Arena.Center, new WDir(0, 1), 40, 22, 38)); + } + + public override void Update() + { + if (WorldState.Party.Player() is not Actor p) + return; + Arena.Center = new(0, Math.Clamp(p.Position.Z, ZBounds.Min + HalfHeight, ZBounds.Max - HalfHeight)); + } +} + +class VishapStates : StateMachineBuilder +{ + public VishapStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 70127, NameID = 3330)] +public class Vishap(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, 245), ScrollingBounds.Bounds) +{ + // vishap doesn't start targetable + private static readonly uint[] opponents = [(uint)OID.HordeWyvern1, (uint)OID.HordeWyvern2, (uint)OID.HordeWyvern3, (uint)OID.HordeWyvern4, (uint)OID.HordeWyvern5, + (uint)OID.HordeWyvern6, (uint)OID.HordeWyvern7, (uint)OID.HordeWyvern8, (uint)OID.HordeWyvern8, (uint)OID.HordeWyvern9, (uint)OID.HordeWyvern10, (uint)OID.HordeDragonfly1, + (uint)OID.HordeDragonfly2, (uint)OID.HordeDragonfly3, (uint)OID.HordeDragonfly4, (uint)OID.HordeDragonfly5, (uint)OID.HordeDragonfly6, (uint)OID.HordeDragonfly7, + (uint)OID.HordeDragonfly8, (uint)OID.HordeAevis1, (uint)OID.HordeAevis2, (uint)OID.HordeAevis3, (uint)OID.HordeAevis4, (uint)OID.HordeAevis5, (uint)OID.HordeAevis6, + (uint)OID.HordeAevis7, (uint)OID.HordeAevis8, (uint)OID.HordeAevis9, (uint)OID.HordeBiast1, (uint)OID.HordeBiast2, (uint)OID.HordeBiast3, (uint)OID.HordeBiast4, + (uint)OID.HordeBiast5, (uint)OID.HordeBiast6, (uint)OID.HordeBiast7, (uint)OID.HordeBiast8, (uint)OID.HordeBiast9, (uint)OID.HordeArmoredDragon, (uint)OID.HordeShieldDragon, + (uint)OID.HordeTranscendent]; + + protected override bool CheckPull() => PrimaryActor.InCombat; + + protected override void DrawEnemies(int pcSlot, Actor pc) + { + Arena.Actors(Enemies(opponents)); + Arena.Actor(PrimaryActor, allowDeadAndUntargetable: true); + } +} + diff --git a/BossMod/Modules/RealmReborn/Quest/TheUltimateWeapon.cs b/BossMod/Modules/RealmReborn/Quest/MSQ/TheUltimateWeapon.cs similarity index 58% rename from BossMod/Modules/RealmReborn/Quest/TheUltimateWeapon.cs rename to BossMod/Modules/RealmReborn/Quest/MSQ/TheUltimateWeapon.cs index ef6bf5515e..706436b8be 100644 --- a/BossMod/Modules/RealmReborn/Quest/TheUltimateWeapon.cs +++ b/BossMod/Modules/RealmReborn/Quest/MSQ/TheUltimateWeapon.cs @@ -1,10 +1,10 @@ -namespace BossMod.RealmReborn.Quest.TheUltimateWeapon; +namespace BossMod.RealmReborn.Quest.MSQ.TheUltimateWeapon; public enum OID : uint { - Boss = 0x3933, // R1.750, x? - SeaOfPitch = 0x1EB738, // R0.500, x?, EventObj type - Firesphere = 0x3934, // R1.000, x0 (spawn during fight) + Boss = 0x3933, // R1.75 + SeaOfPitch = 0x1EB738, // R0.5 + Firesphere = 0x3934, // R1.0 } public enum AID : uint @@ -27,28 +27,24 @@ class BurstFlare(BossModule module) : Components.KnockbackFromCastTarget(module, { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - base.AddAIHints(slot, actor, assignment, hints); - // don't add any hints if Burst hasn't gone off yet, it tends to spook AI mode into running into deathwall if (Module.Enemies(OID.Firesphere).Any(x => x.CastInfo?.RemainingTime > 0)) return; - - foreach (var c in Casters) - hints.AddForbiddenZone(new AOEShapeDonut(5, 100), Arena.Center, default, Module.CastFinishAt(c.CastInfo)); + if (Casters.Count != 0) + hints.AddForbiddenZone(ShapeDistance.InvertedCircle(Arena.Center, 5), Module.CastFinishAt(Casters[0].CastInfo)); } } -class GripOfNight(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.GripOfNight), new AOEShapeCone(40, 75.Degrees())); - -class AncientCross(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AncientCross), new AOEShapeCircle(6), maxCasts: 8); - -class AncientEruption(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AncientEruption), new AOEShapeCircle(6)); - -class FluidFlare(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.FluidFlare), new AOEShapeCone(40, 30.Degrees())); +class GripOfNight(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GripOfNight), new AOEShapeCone(40, 75.Degrees())); +class AncientCross(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AncientCross), 6, 8); +class AncientEruption(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AncientEruption), 6); +class FluidFlare(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FluidFlare), new AOEShapeCone(40, 30.Degrees())); class FireSphere(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.Burst)) { private DateTime? _predictedCast; + private static readonly AOEShapeCircle circle = new(8); + public override void OnCastFinished(Actor caster, ActorCastInfo spell) { if ((AID)spell.Action.ID == AID.FiresphereSummon) @@ -65,60 +61,50 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) { if (_predictedCast is DateTime dt && dt > WorldState.CurrentTime) foreach (var enemy in Module.Enemies(OID.Firesphere)) - yield return new AOEInstance(new AOEShapeCircle(8), enemy.Position, default, dt); + yield return new(circle, enemy.Position, default, dt); } } -class Nightburn(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Nightburn), "WoLbuster"); +class Nightburn(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.Nightburn)); +class AncientFire(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.AncientFireIII)); -class AncientFire(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.AncientFireIII), hint: "Raidwide + spawn deathwall"); - -class DeathWall(BossModule module) : BossComponent(module) +class ArenaChange(BossModule module) : Components.GenericAOEs(module) { - private bool _active; - private bool _completed; + private bool completed; + private static readonly AOEShapeDonut donut = new(15, 20); + private AOEInstance? _aoe; - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID == AID.AncientFireIII && !_completed) - _active = true; - } - public override void DrawArenaBackground(int pcSlot, Actor pc) - { - if (_active) - new AOEShapeDonut(15, 100).Draw(Arena, Arena.Center, default, ArenaColor.AOE); - } + public override IEnumerable ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); - public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if (_active) - hints.AddForbiddenZone(new AOEShapeDonut(15, 100), Arena.Center); + if ((AID)spell.Action.ID == AID.AncientFireIII && !completed) + _aoe = new(donut, Arena.Center, default, Module.CastFinishAt(spell, 0.7f)); } public override void OnEventEnvControl(byte index, uint state) { if (index == 0 && state == 0x20001) { - Module.Arena.Bounds = new ArenaBoundsCircle(15); - _completed = true; - _active = false; + Arena.Bounds = new ArenaBoundsCircle(15); + completed = true; } } } -class DarkThunder(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DarkThunder), new AOEShapeCircle(1)); - +class DarkThunder(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DarkThunder), 1); class SeaOfPitch(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(OID.SeaOfPitch).Where(x => x.EventState != 7)); -class EndOfDays(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.EndOfDays), new AOEShapeRect(60, 4)); -class EndOfDaysAdds(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.EndOfDaysAdds), new AOEShapeRect(60, 4)); +abstract class EoD(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(60, 4)); +class EndOfDays(BossModule module) : EoD(module, AID.EndOfDays); +class EndOfDaysAdds(BossModule module) : EoD(module, AID.EndOfDaysAdds); class LahabreaStates : StateMachineBuilder { public LahabreaStates(BossModule module) : base(module) { TrivialPhase() - .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() @@ -130,8 +116,7 @@ public LahabreaStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } diff --git a/BossMod/Modules/RealmReborn/Quest/TheStepsOfFaith.cs b/BossMod/Modules/RealmReborn/Quest/TheStepsOfFaith.cs deleted file mode 100644 index ec19d7d21a..0000000000 --- a/BossMod/Modules/RealmReborn/Quest/TheStepsOfFaith.cs +++ /dev/null @@ -1,263 +0,0 @@ -namespace BossMod.RealmReborn.Quest.TheStepsOfFaith; - -public enum OID : uint -{ - Boss = 0x3A5F, // R30.000, x1 -} - -public enum AID : uint -{ - FlameBreathCast = 30185, // Vishap->self, 5.0s cast, range 1 width 2 rect - FlameBreathChannel = 30884, // Vishap->self, no cast, range 40 width 20 rect - Cauterize = 30878, // Boss->self, 30.5+4.5s cast, single-target - Touchdown = 26408, // Vishap->self, 6.0s cast, range 80 circle - Fireball = 30875, // Vishap->players/3A71/3A6F/3A6C/3A69/3A68/3A62/3A61/3A60/3A72/3A70/3A6B/3A6A/3A64/3A63, 6.0s cast, range 6 circle - BodySlam = 26401, // Vishap->self, 6.0s cast, range 80 width 44 rect - Flamisphere = 30883, // Vishap->location, 8.0s cast, range 10 circle - FlameBreath2Cast = 26411, // Boss->self, 3.8+1.2s cast, range 60 width 20 rect - RipperClaw = 31262, // 3ABD->self, 3.7s cast, range 9 ?-degree cone - EarthshakerAOE = 30880, // Boss->self, 4.5s cast, range 31 circle - Earthshaker = 30887, // Vishap->self, 6.5s cast, range 80 30-degree cone - EarthrisingAOE = 26410, // Boss->self, 4.5s cast, range 31 circle - EarthrisingCast = 30888, // Vishap->self, 7.0s cast, range 8 circle - EarthrisingRepeat = 26412, // Vishap->self, no cast, range 8 circle - SidewiseSlice = 30879, // Boss->self, 8.0s cast, range 50 120-degree cone - ScorchingBreath = 29785, // Boss->self, 15.0+5.0s cast, single-target - -} - -class RipperClaw(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RipperClaw), new AOEShapeCone(9, 45.Degrees())); - -class EarthShakerAOE(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.EarthshakerAOE), new AOEShapeCircle(31)); -class Earthshaker(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Earthshaker), new AOEShapeCone(80, 15.Degrees()), maxCasts: 2); - -class EarthrisingAOE(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.EarthrisingAOE), new AOEShapeCircle(31)); -class Earthrising(BossModule module) : Components.Exaflare(module, 8) -{ - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID == AID.EarthrisingCast) - { - Lines.Add(new() { Next = caster.Position, Advance = new(0, -7.5f), NextExplosion = Module.CastFinishAt(spell), TimeToMove = 1, ExplosionsLeft = 5, MaxShownExplosions = 2 }); - } - } - - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - if ((AID)spell.Action.ID is AID.EarthrisingRepeat or AID.EarthrisingCast) - { - foreach (var l in Lines.Where(l => l.Next.AlmostEqual(caster.Position, 1))) - AdvanceLine(l, caster.Position); - ++NumCasts; - } - } -} - -class SidewiseSlice(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SidewiseSlice), new AOEShapeCone(50, 60.Degrees())); - -class FireballSpread(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Fireball), 6); - -class Flamisphere(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Flamisphere), new AOEShapeCircle(10)); - -class BodySlam(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.BodySlam), 20, kind: Kind.DirForward, stopAtWall: true); - -class FlameBreath(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.FlameBreathChannel)) -{ - private AOEInstance? _aoe; - - public override IEnumerable ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID == AID.FlameBreathCast) - _aoe = new(new AOEShapeRect(500, 10), Module.PrimaryActor.Position, 180.Degrees(), Module.CastFinishAt(spell).AddSeconds(1)); - } - - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - base.OnEventCast(caster, spell); - if (NumCasts >= 35) - { - _aoe = null; - NumCasts = 0; - } - } -} - -class FlameBreath2(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.FlameBreathChannel)) -{ - private AOEInstance? _aoe; - - public override IEnumerable ActiveAOEs(int slot, Actor actor) => Utils.ZeroOrOne(_aoe); - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID == AID.FlameBreath2Cast) - { - NumCasts = 0; - - _aoe = new(new AOEShapeRect(60, 10), caster.Position, spell.Rotation, Module.CastFinishAt(spell)); - } - } - - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - base.OnEventCast(caster, spell); - if (NumCasts >= 14) - { - _aoe = null; - } - } -} - -class Cauterize(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.Cauterize)) -{ - private Actor? Source; - - private static readonly AOEShapeRect MoveIt = new(40, 22, 38); - - public override IEnumerable ActiveAOEs(int slot, Actor actor) - { - if (Source == null) - yield break; - - if (Arena.Center.Z > 218) - yield return new AOEInstance(MoveIt, Arena.Center); - else - yield return new AOEInstance(new AOEShapeRect(160, 22), Source.Position, 180.Degrees(), Module.CastFinishAt(Source.CastInfo)); - } - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if (spell.Action == WatchedAction) - Source = Module.PrimaryActor; - } - - public override void OnCastFinished(Actor caster, ActorCastInfo spell) - { - if (spell.Action == WatchedAction) - Source = null; - } -} - -class Touchdown(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.Touchdown), 10, stopAtWall: true); - -class ScorchingBreath(BossModule module) : Components.GenericAOEs(module) -{ - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID == AID.ScorchingBreath) - NumCasts++; - } - - public override IEnumerable ActiveAOEs(int slot, Actor actor) - { - if (NumCasts > 0) - yield return new AOEInstance(new AOEShapeRect(100, 10, 100), Module.PrimaryActor.Position, Module.PrimaryActor.Rotation, Module.CastFinishAt(Module.PrimaryActor.CastInfo)); - } -} - -class ScrollingBounds(BossModule module) : BossComponent(module) -{ - public const float HalfHeight = 40; - public const float HalfWidth = 22; - - public static readonly ArenaBoundsRect Bounds = new(HalfWidth, HalfHeight); - - private int Phase = 1; - private (float Min, float Max) ZBounds = (120, 300); - - public override void OnEventEnvControl(byte index, uint state) - { - if (index == 3 && state == 0x20001) - { - ZBounds = (120, 200); - Phase = 2; - } - - if (index == 0 && state == 0x800040) - { - ZBounds = (-40, 200); - Phase = 3; - } - - if (index == 4 && state == 0x20001) - { - ZBounds = (-40, 40); - Phase = 4; - } - - if (index == 1 && state == 0x800040) - { - ZBounds = (-200, 40); - Phase = 5; - } - - if (index == 6 && state == 0x20001) - { - ZBounds = (-200, -120); - Phase = 6; - } - } - - public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - // force player to walk south to aggro vishap (status 1268 = In Event, not actionable) - if (Phase == 1 && !actor.InCombat && actor.FindStatus(1268) == null) - hints.AddForbiddenZone(new AOEShapeRect(38, 22, 40), Arena.Center); - - // subsequent state transitions don't trigger until player moves into the area - if (Phase == 3 && actor.Position.Z > 25) - hints.AddForbiddenZone(new AOEShapeRect(40, 22, 38), Arena.Center); - - if (Phase == 5 && actor.Position.Z > -135) - hints.AddForbiddenZone(new AOEShapeRect(40, 22, 38), Arena.Center); - } - - public override void Update() - { - base.Update(); - if (WorldState.Party.Player() is not Actor p) - return; - - Arena.Center = new(0, Math.Clamp(p.Position.Z, ZBounds.Min + HalfHeight, ZBounds.Max - HalfHeight)); - } -} - -class VishapStates : StateMachineBuilder -{ - public VishapStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - ; - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 70127, NameID = 3330)] -public class Vishap(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, 245), ScrollingBounds.Bounds) -{ - // vishap doesn't start targetable - protected override bool CheckPull() => PrimaryActor.InCombat; - - protected override void DrawEnemies(int pcSlot, Actor pc) - { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); - Arena.Actor(PrimaryActor, ArenaColor.Enemy, true); - } -} - diff --git a/BossMod/Modules/RealmReborn/Raid/T01Caduceus/T01Caduceus.cs b/BossMod/Modules/RealmReborn/Raid/T01Caduceus/T01Caduceus.cs index 05301f071d..756e869c60 100644 --- a/BossMod/Modules/RealmReborn/Raid/T01Caduceus/T01Caduceus.cs +++ b/BossMod/Modules/RealmReborn/Raid/T01Caduceus/T01Caduceus.cs @@ -30,7 +30,7 @@ public enum SID : uint SteelScales = 349, // Boss->Boss, extra=1-8 (num stacks) } -class HoodSwing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.HoodSwing), new AOEShapeCone(11, 60.Degrees()), (uint)OID.Boss) // TODO: verify angle +class HoodSwing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.HoodSwing), new AOEShapeCone(11, 60.Degrees())) // TODO: verify angle { private DateTime _lastBossCast; // assume boss/add cleaves are synchronized?.. public float SecondsUntilNextCast() => Math.Max(0, 18 - (float)(WorldState.CurrentTime - _lastBossCast).TotalSeconds); diff --git a/BossMod/Modules/RealmReborn/Raid/T04Gauntlet/T04Gauntlet.cs b/BossMod/Modules/RealmReborn/Raid/T04Gauntlet/T04Gauntlet.cs index 1feeccd45b..86195b4c86 100644 --- a/BossMod/Modules/RealmReborn/Raid/T04Gauntlet/T04Gauntlet.cs +++ b/BossMod/Modules/RealmReborn/Raid/T04Gauntlet/T04Gauntlet.cs @@ -28,7 +28,7 @@ public enum AID : uint EmergencyOverride = 1258 // DriveCylinder->self, no cast, soft enrage raidwide } -class Rotoswipe(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Rotoswipe), new AOEShapeCone(11, 60.Degrees()), (uint)OID.ClockworkDreadnaught); // TODO: verify angle +class Rotoswipe(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Rotoswipe), new AOEShapeCone(11, 60.Degrees()), [(uint)OID.ClockworkDreadnaught]); // TODO: verify angle class GravityThrustPox(BossModule module) : Components.GenericAOEs(module, default, "Move behind rook!") { diff --git a/BossMod/Modules/Shadowbringers/Dungeon/D08AkadaemiaAnyder/D082MorbolMarquis.cs b/BossMod/Modules/Shadowbringers/Dungeon/D08AkadaemiaAnyder/D082MorbolMarquis.cs index 6af05cb58b..a3eeb93ba5 100644 --- a/BossMod/Modules/Shadowbringers/Dungeon/D08AkadaemiaAnyder/D082MorbolMarquis.cs +++ b/BossMod/Modules/Shadowbringers/Dungeon/D08AkadaemiaAnyder/D082MorbolMarquis.cs @@ -44,7 +44,8 @@ class SapShower(BossModule module) : Components.SpreadFromCastTargets(module, Ac class ExtensibleTendrilsPutridBreath(BossModule module) : Components.GenericAOEs(module) { private static readonly AOEShapeCross cross = new(25, 3); - private static readonly AOEShapeCone cone = new(25, D082MorbolMarquis.A45); + private static readonly Angle a45 = 45.Degrees(); + private static readonly AOEShapeCone cone = new(25, a45); private AOEInstance? _aoe; private DateTime activation; private int remainingCasts; @@ -60,7 +61,7 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) { var delay1 = activation.AddSeconds((5 - remainingCasts) * 6.1f); if ((delay1 - WorldState.CurrentTime).TotalSeconds <= 2.5f) - yield return new(cross, Module.PrimaryActor.Position, Module.PrimaryActor.Rotation + D082MorbolMarquis.A45, delay1); + yield return new(cross, Module.PrimaryActor.Position, Module.PrimaryActor.Rotation + a45, delay1); } var delay2 = activation.AddSeconds(27.1f); if (activation != default && (delay2 - WorldState.CurrentTime).TotalSeconds <= 4.9f) @@ -128,14 +129,14 @@ public D082MorbolMarquisStates(BossModule module) : base(module) public class D082MorbolMarquis(WorldState ws, Actor primary) : BossModule(ws, primary, DefaultBounds.Center, DefaultBounds) { private const int X = -224, InnerRadius = 10, OuterRadius = 15, Radius = 25, Edges = 12; - private static readonly WPos ArenaCenter = new(X, -38); - public static readonly Angle A45 = 45.Degrees(), a135 = 135.Degrees(); - private static readonly Polygon[] defaultCircle = [new(ArenaCenter, 24.5f * CosPI.Pi48th, 48)]; + private static readonly WPos arenaCenter = new(X, -38); + private static readonly Angle a45 = 45.Degrees(), a135 = 135.Degrees(); + private static readonly Polygon[] defaultCircle = [new(arenaCenter, 24.5f * CosPI.Pi48th, 48)]; private static readonly Rectangle[] defaultDifference = [new(new(X, -13), Radius, 1.1f), new(new(X, -63), Radius, 1.1f)]; - private static readonly Shape[] blueBlossom = [new ConeV(ArenaCenter, InnerRadius, A45, A45, Edges), new ConeV(ArenaCenter, InnerRadius, -a135, A45, Edges), - new DonutSegmentV(ArenaCenter, OuterRadius, Radius, A45, A45, Edges), new DonutSegmentV(ArenaCenter, OuterRadius, Radius, -a135, A45, Edges)]; - private static readonly Shape[] yellowBlossom = [new ConeV(ArenaCenter, InnerRadius, -A45, A45, Edges), new ConeV(ArenaCenter, InnerRadius, a135, A45, Edges), - new DonutSegmentV(ArenaCenter, OuterRadius, Radius, -A45, A45, Edges), new DonutSegmentV(ArenaCenter, OuterRadius, Radius, a135, A45, Edges)]; + private static readonly Shape[] blueBlossom = [new ConeV(arenaCenter, InnerRadius, a45, a45, Edges), new ConeV(arenaCenter, InnerRadius, -a135, a45, Edges), + new DonutSegmentV(arenaCenter, OuterRadius, Radius, a45, a45, Edges), new DonutSegmentV(arenaCenter, OuterRadius, Radius, -a135, a45, Edges)]; + private static readonly Shape[] yellowBlossom = [new ConeV(arenaCenter, InnerRadius, -a45, a45, Edges), new ConeV(arenaCenter, InnerRadius, a135, a45, Edges), + new DonutSegmentV(arenaCenter, OuterRadius, Radius, -a45, a45, Edges), new DonutSegmentV(arenaCenter, OuterRadius, Radius, a135, a45, Edges)]; public static readonly ArenaBoundsComplex DefaultBounds = new(defaultCircle, defaultDifference); public static readonly ArenaBoundsComplex BlueBlossomBounds = new(defaultCircle, [.. defaultDifference, .. blueBlossom]); public static readonly ArenaBoundsComplex YellowBlossomBounds = new(defaultCircle, [.. defaultDifference, .. yellowBlossom]); diff --git a/BossMod/Modules/Shadowbringers/Quest/GambolingForGil.cs b/BossMod/Modules/Shadowbringers/Quest/Job/Dancer/GambolingForGil.cs similarity index 75% rename from BossMod/Modules/Shadowbringers/Quest/GambolingForGil.cs rename to BossMod/Modules/Shadowbringers/Quest/Job/Dancer/GambolingForGil.cs index 29fcdbbe6e..424252596e 100644 --- a/BossMod/Modules/Shadowbringers/Quest/GambolingForGil.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Job/Dancer/GambolingForGil.cs @@ -1,9 +1,9 @@ -namespace BossMod.Shadowbringers.Quest.GambolingForGil; +namespace BossMod.Shadowbringers.Quest.Job.Dancer.GambolingForGil; public enum OID : uint { - Boss = 0x29D2, // R0.500, x1 - Whirlwind = 0x29D5, // R1.000, x0 (spawn during fight) + Boss = 0x29D2, // R0.5 + Whirlwind = 0x29D5, // R1.0 } public enum AID : uint @@ -58,11 +58,11 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) } } class Whirlwind(BossModule module) : Components.PersistentVoidzone(module, 6, m => m.Enemies(OID.Whirlwind).Where(x => !x.IsDead)); -class WarDance(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.WarDance), new AOEShapeCircle(5)); +class WarDance(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WarDance), 5); class CharmingChasse(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.CharmingChasse)); -class HannishFire(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.HannishFire1), 6); -class HannishWaters(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HannishWaters), new AOEShapeCone(40, 15.Degrees())); -class RanaasFinish(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RanaasFinish), new AOEShapeCircle(15)); +class HannishFire(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HannishFire1), 6); +class HannishWaters(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HannishWaters), new AOEShapeCone(40, 15.Degrees())); +class RanaasFinish(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RanaasFinish), 15); class RanaaMihgoStates : StateMachineBuilder { @@ -80,9 +80,8 @@ public RanaaMihgoStates(BossModule module) : base(module) } } -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 670, NameID = 8489)] -public class RanaaMihgo(WorldState ws, Actor primary) : BossModule(ws, primary, new(520.47f, 124.99f), WeirdBounds) +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68786, NameID = 8489)] +public class RanaaMihgo(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - public static readonly ArenaBoundsCustom WeirdBounds = new(17.5f, new(CurveApprox.Ellipse(17.5f, 16f, 0.01f))); + public static readonly ArenaBoundsComplex arena = new([new Ellipse(new(520.47f, 124.99f), 17.5f, 16, 50)]); } - diff --git a/BossMod/Modules/Shadowbringers/Quest/SaveTheLastDanceForMe.cs b/BossMod/Modules/Shadowbringers/Quest/Job/Dancer/SaveTheLastDanceForMe.cs similarity index 65% rename from BossMod/Modules/Shadowbringers/Quest/SaveTheLastDanceForMe.cs rename to BossMod/Modules/Shadowbringers/Quest/Job/Dancer/SaveTheLastDanceForMe.cs index b69b7bc9cd..7f81b119ae 100644 --- a/BossMod/Modules/Shadowbringers/Quest/SaveTheLastDanceForMe.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Job/Dancer/SaveTheLastDanceForMe.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.SaveTheLastDanceForMe; +namespace BossMod.Shadowbringers.Quest.Job.Dancer.SaveTheLastDanceForMe; public enum OID : uint { @@ -16,45 +16,33 @@ public enum AID : uint BitterLove = 15650, // 2AC9->self, 3.0s cast, range 12 120-degree cone } -class Dread(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Dread), 5); -class BitterLove(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BitterLove), new AOEShapeCone(12, 60.Degrees())); +class Dread(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Dread), 5); +class BitterLove(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BitterLove), new AOEShapeCone(12, 60.Degrees())); class WhelmingLoss(BossModule module) : Components.Exaflare(module, new AOEShapeCircle(5)) { public override void OnCastStarted(Actor caster, ActorCastInfo spell) { if (spell.Action.ID == (uint)AID.WhelmingLossFirst) - Lines.Add(new Line - { - Next = caster.Position, - Advance = caster.Rotation.ToDirection() * 5, - NextExplosion = Module.CastFinishAt(spell), - TimeToMove = 1, - ExplosionsLeft = 7, - MaxShownExplosions = 3 - }); + Lines.Add(new() { Next = spell.LocXZ, Advance = spell.Rotation.ToDirection() * 5, NextExplosion = Module.CastFinishAt(spell), TimeToMove = 1, ExplosionsLeft = 7, MaxShownExplosions = 3 }); } public override void OnEventCast(Actor caster, ActorCastEvent spell) { if (spell.Action.ID is (uint)AID.WhelmingLossFirst or (uint)AID.WhelmingLossRest) { - var index = Lines.FindIndex(l => l.Next.AlmostEqual(caster.Position, 1)); - if (index == -1) - { - ReportError($"Failed to find entry for {caster.InstanceID:X}"); + var index = Lines.FindIndex(item => item.Next.AlmostEqual(caster.Position, 1)); + if (index < 0) return; - } - AdvanceLine(Lines[index], caster.Position); + if (Lines[index].ExplosionsLeft == 0) + Lines.RemoveAt(index); } } } class Adds(BossModule module) : Components.Adds(module, (uint)OID.ShadowySpume); class Anguish(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.Anguish), 6); -class ForebodingAura(BossModule module) : Components.GenericAOEs(module) -{ - public override IEnumerable ActiveAOEs(int slot, Actor actor) => Module.Enemies(OID.ForebodingAura).Where(e => !e.IsDead).Select(e => new AOEInstance(new AOEShapeCircle(8), e.Position)); -} + +class ForebodingAura(BossModule module) : Components.PersistentVoidzone(module, 8, m => m.Enemies(OID.ForebodingAura).Where(e => !e.IsDead)); class AethericShadowStates : StateMachineBuilder { @@ -75,7 +63,7 @@ public AethericShadowStates(BossModule module) : base(module) { protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (actor.FindStatus(DNC.SID.ClosedPosition) == null && Raid.WithoutSlot().Exclude(actor).FirstOrDefault() is Actor partner) + if (actor.FindStatus(DNC.SID.ClosedPosition) == null && Raid.WithoutSlot(false, false).Exclude(actor).FirstOrDefault() is Actor partner) { hints.ActionsToExecute.Push(ActionID.MakeSpell(DNC.AID.ClosedPosition), partner, ActionQueue.Priority.VeryHigh); } diff --git a/BossMod/Modules/Shadowbringers/Quest/Job/Gunbreaker/SteelAgainstSteel.cs b/BossMod/Modules/Shadowbringers/Quest/Job/Gunbreaker/SteelAgainstSteel.cs new file mode 100644 index 0000000000..ad615b07b9 --- /dev/null +++ b/BossMod/Modules/Shadowbringers/Quest/Job/Gunbreaker/SteelAgainstSteel.cs @@ -0,0 +1,99 @@ +namespace BossMod.Shadowbringers.Quest.Job.Gunbreaker.SteelAgainstSteel; + +public enum OID : uint +{ + Boss = 0x2A45, + Fustuarium = 0x2AD8, // R0.5 + CullingBlade = 0x2AD3, // R0.5 + IndustrialForce = 0x2BCE, // R0.5 + TerminusEst = 0x2A46, // R1.0 + CaptiveBolt = 0x2AD7, // R0.5 + Helper = 0x233C +} + +public enum AID : uint +{ + CullingBlade1 = 17553, // CullingBlade->self, 3.5s cast, range 60 30-degree cone + TheOrder = 17568, // Boss->self, 4.0s cast, single-target + TerminusEst1 = 17567, // TerminusEst->self, no cast, range 40+R width 4 rect + CaptiveBolt = 17561, // CaptiveBolt->self, 7.0s cast, range 50+R width 10 rect + AetherochemicalGrenado = 17575, // 2A47->location, 4.0s cast, range 8 circle + Exsanguination1 = 17563, // 2AD4->self, 5.0s cast, range 2-7 180-degree donut segment + Exsanguination2 = 17564, // 2AD5->self, 5.0s cast, range 7-12 180-degree donut segment + Exsanguination3 = 17565, // 2AD6->self, 5.0s cast, range 12-17 180-degree donut segment + DiffractiveLaser = 17574, // 2A48->self, 3.0s cast, range 45+R width 4 rect + SnakeShot = 17569, // Boss->self, 4.0s cast, range 20 240-degree cone + ScaldingTank1 = 17558, // Fustuarium->2A4A, 6.0s cast, range 6 circle + ToTheSlaughter = 17559, // Boss->self, 4.0s cast, range 40 180-degree cone +} + +class ScaldingTank(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.ScaldingTank1), 6); +class ToTheSlaughter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ToTheSlaughter), new AOEShapeCone(40, 90.Degrees())); +class Exsanguination1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Exsanguination1), new AOEShapeDonutSector(2, 7, 90.Degrees())); +class Exsanguination2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Exsanguination2), new AOEShapeDonutSector(7, 12, 90.Degrees())); +class Exsanguination3(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Exsanguination3), new AOEShapeDonutSector(12, 17, 90.Degrees())); +class CaptiveBolt(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CaptiveBolt), new AOEShapeRect(50, 5), 4); +class AetherochemicalGrenado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AetherochemicalGrenado), 8); +class DiffractiveLaser(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DiffractiveLaser), new AOEShapeRect(45, 2)); +class SnakeShot(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SnakeShot), new AOEShapeCone(20, 120.Degrees())); +class CullingBlade(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CullingBlade1), new AOEShapeCone(60, 15.Degrees())); + +class TerminusEst(BossModule module) : Components.GenericAOEs(module) +{ + private Actor? Caster; + private readonly List Actors = []; + private static readonly AOEShapeRect rect = new(40, 2); + + public override void OnActorCreated(Actor actor) + { + if (actor.OID == (uint)OID.TerminusEst) + Actors.Add(actor); + } + + public override IEnumerable ActiveAOEs(int slot, Actor actor) + { + if (Caster is Actor c) + foreach (var t in Actors) + yield return new(rect, t.Position, t.Rotation, Module.CastFinishAt(c.CastInfo)); + } + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + // check if we already have terminuses out, because he can use this spell for a diff mechanic + if ((AID)spell.Action.ID == AID.TheOrder && Actors.Count > 0) + Caster = caster; + } + + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + if ((AID)spell.Action.ID == AID.TerminusEst1) + { + Actors.Remove(caster); + // reset for next iteration + if (Actors.Count == 0) + Caster = null; + } + } +} + +class VitusQuoMessallaStates : StateMachineBuilder +{ + public VitusQuoMessallaStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68802, NameID = 8872)] +public class VitusQuoMessalla(WorldState ws, Actor primary) : BossModule(ws, primary, new(-266, -507), new ArenaBoundsCircle(19.5f)); diff --git a/BossMod/Modules/Shadowbringers/Quest/AFeastOfLies.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/AFeastOfLies.cs similarity index 56% rename from BossMod/Modules/Shadowbringers/Quest/AFeastOfLies.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/AFeastOfLies.cs index f605961e83..1ad83452db 100644 --- a/BossMod/Modules/Shadowbringers/Quest/AFeastOfLies.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/AFeastOfLies.cs @@ -1,58 +1,70 @@ -namespace BossMod.Shadowbringers.Quest.AFeastOfLies; +namespace BossMod.Shadowbringers.Quest.MSQ.AFeastOfLies; public enum OID : uint { Boss = 0x295A, - Helper = 0x233C, + Helper = 0x233C } public enum AID : uint { UnceremoniousBeheading = 16274, // Boss->self, 4.0s cast, range 10 circle KatunCycle = 16275, // Boss->self, 4.0s cast, range 5-40 donut - MercilessRight = 16278, // Boss->self, 4.0s cast, single-target - MercilessRight1 = 16283, // 29FB->self, 3.8s cast, range 40 120-degree cone - MercilessRight2 = 16284, // 29FE->self, 4.2s cast, range 40 120-degree cone + Evisceration = 16277, // Boss->self, 4.5s cast, range 40 120-degree cone HotPursuit = 16291, // Boss->self, 2.5s cast, single-target HotPursuit1 = 16285, // 29E6->location, 3.0s cast, range 5 circle + NexusOfThunder = 16280, // Boss->self, 2.5s cast, single-target NexusOfThunder1 = 16276, // 29E6->self, 4.3s cast, range 45 width 5 rect + NexusOfThunder2 = 16296, // 29E6->self, 6.3s cast, range 45 width 5 rect + LivingFlame = 16294, // Boss->self, 3.0s cast, single-target Spiritcall = 16292, // Boss->self, 3.0s cast, range 40 circle Burn = 16290, // 29C2->self, 4.5s cast, range 8 circle RisingThunder = 16293, // Boss->self, 3.0s cast, single-target Electrocution = 16286, // 295B->self, 10.0s cast, range 6 circle - ShatteredSky = 17191, // Boss->self, 4.0s cast, single-target - ShatteredSky1 = 16282, // 29E6->self, 0.5s cast, range 40 circle - NexusOfThunder2 = 16296, // 29E6->self, 6.3s cast, range 45 width 5 rect - MercilessLeft = 16279, // Boss->self, 4.0s cast, single-target + ShatteredSkyVisual = 17191, // Boss->self, 4.0s cast, single-target + ShatteredSky = 16282, // 29E6->self, 0.5s cast, range 40 circle + MercilessLeftVisual = 16279, // Boss->self, 4.0s cast, single-target MercilessLeft1 = 16298, // 29FC->self, 3.8s cast, range 40 120-degree cone MercilessLeft2 = 16297, // 29FD->self, 4.2s cast, range 40 120-degree cone + MercilessRightVisual = 16278, // Boss->self, 4.0s cast, single-target + MercilessRight1 = 16283, // 29FB->self, 3.8s cast, range 40 120-degree cone + MercilessRight2 = 16284, // 29FE->self, 4.2s cast, range 40 120-degree cone } -class UnceremoniousBeheading(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.UnceremoniousBeheading), new AOEShapeCircle(10)); -class KatunCycle(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.KatunCycle), new AOEShapeDonut(5, 40)); -class MercilessRight(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MercilessRight1), new AOEShapeCone(40, 60.Degrees())); -class MercilessRight1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MercilessRight2), new AOEShapeCone(40, 60.Degrees())); -class MercilessLeft(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MercilessLeft1), new AOEShapeCone(40, 60.Degrees())); -class MercilessLeft1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MercilessLeft2), new AOEShapeCone(40, 60.Degrees())); -class Evisceration(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Evisceration), new AOEShapeCone(40, 60.Degrees())); -class HotPursuit(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.HotPursuit1), 5); -class NexusOfThunder(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NexusOfThunder1), new AOEShapeRect(45, 2.5f)); -class NexusOfThunder1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NexusOfThunder2), new AOEShapeRect(45, 2.5f)); -class Burn(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Burn), new AOEShapeCircle(8), maxCasts: 5); +class UnceremoniousBeheading(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.UnceremoniousBeheading), 10); +class KatunCycle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.KatunCycle), new AOEShapeDonut(5, 40)); + +abstract class Cleaves(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(40, 60.Degrees())); +class MercilessRight(BossModule module) : Cleaves(module, AID.MercilessRight1); +class MercilessRight1(BossModule module) : Cleaves(module, AID.MercilessRight2); +class MercilessLeft(BossModule module) : Cleaves(module, AID.MercilessLeft1); +class MercilessLeft1(BossModule module) : Cleaves(module, AID.MercilessLeft2); +class Evisceration(BossModule module) : Cleaves(module, AID.Evisceration); + +class HotPursuit(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HotPursuit1), 5); + +abstract class NoT(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(45, 2.5f)); +class NexusOfThunder1(BossModule module) : NoT(module, AID.NexusOfThunder1); +class NexusOfThunder2(BossModule module) : NoT(module, AID.NexusOfThunder2); + +class Burn(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Burn), 8, 5); class Spiritcall(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.Spiritcall), 20, stopAtWall: true); -class Electrocution(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Electrocution), new AOEShapeCircle(6)) +class Electrocution(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Electrocution), 6) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { if (Casters.Count == 12) { var enemy = hints.PotentialTargets.Where(x => x.Actor.OID == 0x295B).MinBy(e => actor.DistanceToHitbox(e.Actor)); - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var e = hints.PotentialTargets[i]; e.Priority = e == enemy ? 1 : 0; + } } else { @@ -76,13 +88,12 @@ public RanjitStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } diff --git a/BossMod/Modules/Shadowbringers/Quest/FullSteamAhead.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/ComingClean.cs similarity index 63% rename from BossMod/Modules/Shadowbringers/Quest/FullSteamAhead.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/ComingClean.cs index 6e464d9242..4c5fcd0d3c 100644 --- a/BossMod/Modules/Shadowbringers/Quest/FullSteamAhead.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/ComingClean.cs @@ -1,11 +1,14 @@ using BossMod.QuestBattle; -namespace BossMod.Shadowbringers.Quest.FullSteamAhead; +namespace BossMod.Shadowbringers.Quest.MSQ.ComingClean; // quest name: Full Steam Ahead public enum OID : uint { - Boss = 0x295D, - LightningVoidzone = 0x1E9685 + Boss = 0x295C, // R1.0 + Ranjit = 0x295D, // R1.0 + SerpentHead = 0x295F, // R1.0 + LightningVoidzone = 0x1E9685, // R0.5 + Helper = 0x233C, // R0.5 } public enum AID : uint @@ -14,20 +17,20 @@ public enum AID : uint ShatteredSky1 = 16429, // 233C->self, 6.0s cast, range 45 circle HotPursuit = 16406, // Boss->self, 3.0s cast, single-target HotPursuit1 = 16430, // 233C->location, 3.0s cast, range 5 circle - NexusOfThunder = 16404, // Boss->self, 3.0s cast, single-target - NexusOfThunder1 = 16427, // 233C->self, 7.0s cast, range 60+R width 5 rect + NexusOfThunderVisual = 16404, // Boss->self, 3.0s cast, single-target + NexusOfThunder = 16427, // 233C->self, 7.0s cast, range 60+R width 5 rect Wrath = 16425, // 295E->self, no cast, range 100 circle CoiledLevin = 16424, // 295E->self, 3.0s cast, single-target CoiledLevin1 = 16428, // 233C->self, 7.0s cast, range 6 circle UnbridledWrath = 16426, // 295E->self, no cast, range 100 circle HiddenCurrent = 16403, // Boss->location, no cast, ??? - VeilOfGukumatz = 16423, // 2998->self, no cast, single-target - VeilOfGukumatz1 = 16422, // 295D->self, no cast, single-target - VeilOfGukumatz2 = 16402, // Boss->self, no cast, single-target + VeilOfGukumatz1 = 16423, // 2998->self, no cast, single-target + VeilOfGukumatz2 = 16422, // 295D->self, no cast, single-target + VeilOfGukumatz3 = 16402, // Boss->self, no cast, single-target UnceremoniousBeheading = 16412, // 295D->self, 3.5s cast, range 10 circle HiddenCurrent1 = 16411, // 295D->location, no cast, ??? - MercilessLeft = 16415, // 295D->self, 4.0s cast, single-target - MercilessLeft1 = 33202, // 233C->self, 4.0s cast, range 40 120-degree cone + MercilessLeftVisual = 16415, // 295D->self, 4.0s cast, single-target + MercilessLeft = 33202, // 233C->self, 4.0s cast, range 40 120-degree cone MercilessRight = 16431, // 233C->self, 4.0s cast, range 40 120-degree cone KatunCycle = 16413, // 295D->self, 5.5s cast, range 5-40 donut HotPursuit2 = 16410, // 295D->self, 3.0s cast, single-target @@ -41,17 +44,20 @@ public enum AID : uint public enum SID : uint { Smackdown = 2068, + DownForTheCount = 783 // 295E->player, extra=0xEC7 } -class KatunCycle(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.KatunCycle), new AOEShapeDonut(5, 40)); -class MercilessLeft(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MercilessLeft1), new AOEShapeCone(40, 60.Degrees())); -class MercilessRight(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MercilessRight), new AOEShapeCone(40, 60.Degrees())); -class UnceremoniousBeheading(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.UnceremoniousBeheading), new AOEShapeCircle(10)); -class Evisceration(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Evisceration), new AOEShapeCone(40, 60.Degrees())); +class KatunCycle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.KatunCycle), new AOEShapeDonut(5, 40)); -class HotPursuit(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.HotPursuit1), 5); -class NexusOfThunder(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NexusOfThunder1), new AOEShapeRect(60, 2.5f)); -class CoiledLevin(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CoiledLevin1), new AOEShapeCircle(6)); +abstract class Cleaves(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(40, 60.Degrees())); +class MercilessLeft(BossModule module) : Cleaves(module, AID.MercilessLeft); +class MercilessRight(BossModule module) : Cleaves(module, AID.MercilessRight); +class Evisceration(BossModule module) : Cleaves(module, AID.Evisceration); + +class UnceremoniousBeheading(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.UnceremoniousBeheading), 10); +class HotPursuit(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HotPursuit1), 5); +class NexusOfThunder(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.NexusOfThunder), new AOEShapeRect(60, 2.5f)); +class CoiledLevin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CoiledLevin1), 6); class LightningVoidzone(BossModule module) : Components.PersistentVoidzone(module, 6, m => m.Enemies(OID.LightningVoidzone).Where(x => x.EventState != 7)); class ThancredAI(BossModule module) : RotationModule(module); @@ -112,15 +118,18 @@ public RanjitStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - ; + .Raw.Update = () => module.Enemies(OID.Ranjit) is var boss && boss.Count != 0 && boss[0].FindStatus(SID.DownForTheCount) != null || module.WorldState.CurrentCFCID != 680; } } [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69155, NameID = 8374)] -public class Ranjit(WorldState ws, Actor primary) : BossModule(ws, primary, new(-203, 395), new ArenaBoundsCircle(19.5f)) +public class Ranjit(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { + private static readonly ArenaBoundsComplex arena = new([new Polygon(new(-203, 395), 19.5f, 20)]); + protected override void DrawArenaForeground(int pcSlot, Actor pc) { - Arena.Actors(Enemies(0x295C), ArenaColor.Enemy); + Arena.Actors(Enemies(OID.Ranjit)); + Arena.Actor(PrimaryActor); } } diff --git a/BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P1TelotekGamma.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P1TelotekGamma.cs similarity index 80% rename from BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P1TelotekGamma.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P1TelotekGamma.cs index b36a861858..8f560c56ef 100644 --- a/BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P1TelotekGamma.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P1TelotekGamma.cs @@ -1,6 +1,6 @@ using BossMod.QuestBattle.Shadowbringers.MSQ; -namespace BossMod.Shadowbringers.Quest.DeathUntoDawn.P1; +namespace BossMod.Shadowbringers.Quest.MSQ.DeathUntoDawn.P1; public enum AID : uint { @@ -15,7 +15,7 @@ enum OID : uint class AlisaieAI(BossModule module) : QuestBattle.RotationModule(module); class AntiPersonnelMissile(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.AntiPersonnelMissile), 6); -class MRVMissile(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.MRVMissile), 12, maxCasts: 6); +class MRVMissile(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MRVMissile), 12, 6); public class TelotekGammaStates : StateMachineBuilder { @@ -31,5 +31,5 @@ public TelotekGammaStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69602, NameID = 10189)] public class TelotekGamma(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, -180), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P2LunarOdin.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P2LunarOdin.cs similarity index 63% rename from BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P2LunarOdin.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P2LunarOdin.cs index ebc0e28f31..223d7290c4 100644 --- a/BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P2LunarOdin.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P2LunarOdin.cs @@ -1,7 +1,7 @@ using BossMod.QuestBattle; using RID = BossMod.Roleplay.AID; -namespace BossMod.Shadowbringers.Quest.DeathUntoDawn.P2; +namespace BossMod.Shadowbringers.Quest.MSQ.DeathUntoDawn.P2; public enum OID : uint { @@ -28,14 +28,14 @@ class UriangerAI(WorldState ws) : UnmanagedRotation(ws, 25) protected override void Exec(Actor? primaryTarget) { - var partyPositions = World.Party.WithoutSlot().Select(p => p.Position).ToList(); + var partyPositions = World.Party.WithoutSlot(false, false).Select(p => p.Position).ToList(); Hints.GoalZones.Add(pos => partyPositions.Count(p => p.InCircle(pos, 16))); - if (World.Party.WithoutSlot().All(p => HeliosLeft(p) < 1 && p.Position.InCircle(Player.Position, 15.5f + p.HitboxRadius))) + if (World.Party.WithoutSlot(false, false).All(p => HeliosLeft(p) < 1 && p.Position.InCircle(Player.Position, 15.5f + p.HitboxRadius))) UseAction(RID.AspectedHelios, Player); - if (World.Party.WithoutSlot().FirstOrDefault(p => p.HPMP.CurHP < p.HPMP.MaxHP * 0.4f) is Actor low) + if (World.Party.WithoutSlot(false, false).FirstOrDefault(p => p.HPMP.CurHP < p.HPMP.MaxHP * 0.4f) is Actor low) UseAction(RID.Benefic, low); UseAction(RID.MaleficIII, primaryTarget); @@ -58,51 +58,38 @@ protected override void Exec(Actor? primaryTarget) } } +class AutoUrianger(BossModule module) : RotationModule(module); class Fetters(BossModule module) : Components.Adds(module, (uint)OID.Fetters); -class AutoUri(BossModule module) : RotationModule(module); + class GunmetalSoul(BossModule module) : Components.GenericAOEs(module) { public override IEnumerable ActiveAOEs(int slot, Actor actor) => Module.Enemies(0x1EB1D5).Where(e => e.EventState != 7).Select(e => new AOEInstance(new AOEShapeDonut(4, 100), e.Position)); } -class LunarGungnir(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.LunarGungnir), 6); +class LunarGungnir1(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.LunarGungnir), 6); class LunarGungnir2(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.LunarGungnir1), 6); -class Gungnir(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.GungnirAOE), new AOEShapeCircle(10)); -class Gagnrath(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Gagnrath), new AOEShapeRect(50, 2)); +class Gungnir(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GungnirAOE), 10); +class Gagnrath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Gagnrath), new AOEShapeRect(50, 2)); class GungnirSpread(BossModule module) : Components.BaitAwayIcon(module, new AOEShapeCircle(10), 189, ActionID.MakeSpell(AID.GungnirSpread), 5.3f, centerAtTarget: true); -class Zantetsuken(BossModule module) : Components.GenericAOEs(module) -{ - private readonly List Casters = []; - - public override IEnumerable ActiveAOEs(int slot, Actor actor) => Casters.Select(c => new AOEInstance(new AOEShapeRect(70, 19.5f), actor.CastInfo!.LocXZ, actor.CastInfo!.Rotation, Module.CastFinishAt(actor.CastInfo))); - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID is AID.RightZantetsuken or AID.LeftZantetsuken) - Casters.Add(caster); - } - - public override void OnCastFinished(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID is AID.RightZantetsuken or AID.LeftZantetsuken) - Casters.Remove(caster); - } -} +abstract class Zantetsuken(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(70, 19.5f)); +class RightZantetsuken(BossModule module) : Zantetsuken(module, AID.RightZantetsuken); +class LeftZantetsuken(BossModule module) : Zantetsuken(module, AID.LeftZantetsuken); public class LunarOdinStates : StateMachineBuilder { public LunarOdinStates(BossModule module) : base(module) { TrivialPhase() - .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter(); + .ActivateOnEnter() + .ActivateOnEnter(); } } diff --git a/BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P3LunarRavana.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P3LunarRavana.cs similarity index 85% rename from BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P3LunarRavana.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P3LunarRavana.cs index f6bdd8e466..eb22c22965 100644 --- a/BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P3LunarRavana.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P3LunarRavana.cs @@ -1,7 +1,7 @@ using BossMod.QuestBattle; using RID = BossMod.Roleplay.AID; -namespace BossMod.Shadowbringers.Quest.DeathUntoDawn.P3; +namespace BossMod.Shadowbringers.Quest.MSQ.DeathUntoDawn.P3; public enum OID : uint { @@ -14,12 +14,12 @@ public enum OID : uint public enum AID : uint { - Explosion = 24046, // 3204->self, 5.0s cast, range 80 width 10 cross + Explosion = 24046 // 3204->self, 5.0s cast, range 80 width 10 cross } public enum SID : uint { - Invincibility = 325, + Invincibility = 325 } class GrahaAI(WorldState ws) : UnmanagedRotation(ws, 25) @@ -72,17 +72,16 @@ protected override void Exec(Actor? primaryTarget) } class AutoGraha(BossModule module) : RotationModule(module); -class DirectionalParry(BossModule module) : Components.DirectionalParry(module, 0x3201) +class DirectionalParry(BossModule module) : Components.DirectionalParry(module, [0x3201]) { + private static readonly Angle a45 = 45.Degrees(); public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { if (Module.PrimaryActor.FindStatus(680) != null) - { - hints.AddForbiddenZone(new AOEShapeCone(100, 45.Degrees()), Module.PrimaryActor.Position, Module.PrimaryActor.Rotation, WorldState.FutureTime(10)); - } + hints.AddForbiddenZone(ShapeDistance.Cone(Module.PrimaryActor.Position, 100, Module.PrimaryActor.Rotation, a45), WorldState.FutureTime(10)); } } -class Explosion(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeCross(80, 5), maxCasts: 2); +class Explosion(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeCross(80, 5), 2); class LunarRavanaStates : StateMachineBuilder { @@ -98,7 +97,7 @@ public LunarRavanaStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69602, NameID = 10037)] public class LunarRavana(WorldState ws, Actor primary) : BossModule(ws, primary, new(-144, 83), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { diff --git a/BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P4LunarIfrit.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P4LunarIfrit.cs similarity index 64% rename from BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P4LunarIfrit.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P4LunarIfrit.cs index 6201f5dbce..ae2405f1bb 100644 --- a/BossMod/Modules/Shadowbringers/Quest/DeathUntoDawn/P4LunarIfrit.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/DeathUntoDawn/P4LunarIfrit.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.DeathUntoDawn.P4; +namespace BossMod.Shadowbringers.Quest.MSQ.DeathUntoDawn.P4; public enum OID : uint { @@ -10,20 +10,20 @@ public enum OID : uint public enum AID : uint { RadiantPlume1 = 24057, // Helper->self, 7.0s cast, range 8 circle - Hellfire = 24058, // Boss->self, 36.0s cast, range 40 circle - Hellfire1 = 24059, // Boss->self, 28.0s cast, range 40 circle + Hellfire1 = 24058, // Boss->self, 36.0s cast, range 40 circle + Hellfire2 = 24059, // Boss->self, 28.0s cast, range 40 circle CrimsonCyclone = 24054, // 3203->self, 4.5s cast, range 49 width 18 rect Explosion = 24046, // 3204->self, 5.0s cast, range 80 width 10 cross AgonyOfTheDamned1 = 24062, // Helper->self, 0.7s cast, range 40 circle } -class Hellfire(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Hellfire)); class Hellfire1(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Hellfire1)); +class Hellfire2(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Hellfire2)); class AgonyOfTheDamned(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.AgonyOfTheDamned1)); -class RadiantPlume(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RadiantPlume1), new AOEShapeCircle(8)); -class CrimsonCyclone(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CrimsonCyclone), new AOEShapeRect(49, 9), maxCasts: 3); +class RadiantPlume(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RadiantPlume1), 8); +class CrimsonCyclone(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CrimsonCyclone), new AOEShapeRect(49, 9), 3); class InfernalNail(BossModule module) : Components.Adds(module, (uint)OID.InfernalNail, 5); -class Explosion(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeCross(80, 5), maxCasts: 2); +class Explosion(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Explosion), new AOEShapeCross(80, 5), 2); class LunarIfritStates : StateMachineBuilder { @@ -32,8 +32,8 @@ public LunarIfritStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter(); diff --git a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/Ardbert.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Ardbert.cs similarity index 50% rename from BossMod/Modules/Shadowbringers/Quest/FadedMemories/Ardbert.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Ardbert.cs index d70c8c34b0..c32559efa3 100644 --- a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/Ardbert.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Ardbert.cs @@ -1,11 +1,12 @@ -namespace BossMod.Shadowbringers.Quest.FadedMemories; +namespace BossMod.Shadowbringers.Quest.MSQ.FadedMemories; -class Overcome(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Overcome), new AOEShapeCone(8, 60.Degrees()), 2); -class Skydrive(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Skydrive), new AOEShapeCircle(5)); +class Overcome(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Overcome), new AOEShapeCone(8, 60.Degrees()), 2); +class Skydrive(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Skydrive), 5); class SkyHighDrive(BossModule module) : Components.GenericRotatingAOE(module) { Angle angle; + private static readonly AOEShapeRect rect = new(40, 4); public override void OnCastStarted(Actor caster, ActorCastInfo spell) { @@ -20,7 +21,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) case AID.SkyHighDriveFirst: if (angle != default) { - Sequences.Add(new(new AOEShapeRect(40, 4), caster.Position, spell.Rotation, angle, Module.CastFinishAt(spell, 0.5f), 0.6f, 10, 4)); + Sequences.Add(new(rect, spell.LocXZ, spell.Rotation, angle, Module.CastFinishAt(spell, 0.5f), 0.6f, 10, 4)); } break; } @@ -37,10 +38,10 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) } } -class AvalancheAxe(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AvalanceAxe1), new AOEShapeCircle(10)); -class AvalancheAxe2(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AvalanceAxe2), new AOEShapeCircle(10)); -class AvalancheAxe3(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AvalanceAxe3), new AOEShapeCircle(10)); -class OvercomeAllOdds(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.OvercomeAllOdds), new AOEShapeCone(60, 15.Degrees()), 1) +class AvalancheAxe1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AvalanceAxe1), 10); +class AvalancheAxe2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AvalanceAxe2), 10); +class AvalancheAxe3(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AvalanceAxe3), 10); +class OvercomeAllOdds(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OvercomeAllOdds), new AOEShapeCone(60, 15.Degrees()), 1) { public override void OnCastFinished(Actor caster, ActorCastInfo spell) { @@ -49,43 +50,37 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) MaxCasts = 2; } } -class Soulflash(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Soulflash1), new AOEShapeCircle(4)); +class Soulflash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Soulflash1), 4); class EtesianAxe(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.EtesianAxe), 15, kind: Kind.DirForward); -class Soulflash2(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Soulflash2), new AOEShapeCircle(8)); +class Soulflash2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Soulflash2), 8); class GroundbreakerExaflares(BossModule module) : Components.Exaflare(module, new AOEShapeCircle(6)) { public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if (spell.Action.ID == (uint)AID.GroundbreakerExaFirst) + if ((AID)spell.Action.ID == AID.GroundbreakerExaFirst) { - Lines.Add(new Line - { - Next = caster.Position, - Advance = caster.Rotation.ToDirection() * 6, - Rotation = default, - NextExplosion = Module.CastFinishAt(spell), - TimeToMove = 1, - ExplosionsLeft = 8, - MaxShownExplosions = 3 - }); + Lines.Add(new() { Next = spell.LocXZ, Advance = spell.Rotation.ToDirection() * 6, NextExplosion = Module.CastFinishAt(spell), TimeToMove = 1, ExplosionsLeft = 8, MaxShownExplosions = 3 }); } } public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if (spell.Action.ID is (uint)AID.GroundbreakerExaFirst or (uint)AID.GroundbreakerExaRest) + if ((AID)spell.Action.ID is AID.GroundbreakerExaFirst or AID.GroundbreakerExaRest) { - var line = Lines.FirstOrDefault(x => x.Next.AlmostEqual(caster.Position, 1)); - if (line != null) - AdvanceLine(line, caster.Position); + var index = Lines.FindIndex(item => item.Next.AlmostEqual(caster.Position, 1)); + if (index < 0) + return; + AdvanceLine(Lines[index], caster.Position); + if (Lines[index].ExplosionsLeft == 0) + Lines.RemoveAt(index); } } } -class GroundbreakerCone(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.GroundbreakerCone), new AOEShapeCone(40, 45.Degrees())); -class GroundbreakerDonut(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.GroundbreakerDonut), new AOEShapeDonut(5, 20)); -class GroundbreakerCircle(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.GroundbreakerCircle), new AOEShapeCircle(15)); +class GroundbreakerCone(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GroundbreakerCone), new AOEShapeCone(40, 45.Degrees())); +class GroundbreakerDonut(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GroundbreakerDonut), new AOEShapeDonut(5, 20)); +class GroundbreakerCircle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GroundbreakerCircle), new AOEShapeCircle(15)); class ArdbertStates : StateMachineBuilder { @@ -95,7 +90,7 @@ public ArdbertStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() diff --git a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/FadedMemories.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/FadedMemories.cs similarity index 96% rename from BossMod/Modules/Shadowbringers/Quest/FadedMemories/FadedMemories.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/FadedMemories.cs index f7e49aae1f..8944c958e7 100644 --- a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/FadedMemories.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/FadedMemories.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.FadedMemories; +namespace BossMod.Shadowbringers.Quest.MSQ.FadedMemories; public enum OID : uint { @@ -7,7 +7,7 @@ public enum OID : uint Nidhogg = 0x2F21, Zenos = 0x2F28, Ardbert = 0x2F2E, - Helper = 0x233C, + Helper = 0x233C } public enum AID : uint diff --git a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/FlameGeneralAldynn.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/FlameGeneralAldynn.cs similarity index 62% rename from BossMod/Modules/Shadowbringers/Quest/FadedMemories/FlameGeneralAldynn.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/FlameGeneralAldynn.cs index 54d236eee2..16c9ff7bfe 100644 --- a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/FlameGeneralAldynn.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/FlameGeneralAldynn.cs @@ -1,18 +1,19 @@ -namespace BossMod.Shadowbringers.Quest.FadedMemories; +namespace BossMod.Shadowbringers.Quest.MSQ.FadedMemories; -class FlamingTizona(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.FlamingTizona), 6); +class FlamingTizona(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlamingTizona), 6); class FlameGeneralAldynnStates : StateMachineBuilder { public FlameGeneralAldynnStates(BossModule module) : base(module) { - TrivialPhase().ActivateOnEnter(); + TrivialPhase() + .ActivateOnEnter(); } } [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69311, NameID = 4739, PrimaryActorOID = (uint)OID.FlameGeneralAldynn)] public class FlameGeneralAldynn(WorldState ws, Actor primary) : BossModule(ws, primary, new(-143, 357), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/KingThordan.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/KingThordan.cs similarity index 72% rename from BossMod/Modules/Shadowbringers/Quest/FadedMemories/KingThordan.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/KingThordan.cs index 4eb731e55c..45b8e8a317 100644 --- a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/KingThordan.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/KingThordan.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.FadedMemories; +namespace BossMod.Shadowbringers.Quest.MSQ.FadedMemories; class DragonsGaze(BossModule module) : Components.CastGaze(module, ActionID.MakeSpell(AID.TheDragonsGaze)); @@ -6,18 +6,22 @@ class KingThordanStates : StateMachineBuilder { public KingThordanStates(BossModule module) : base(module) { - TrivialPhase().ActivateOnEnter(); + TrivialPhase() + .ActivateOnEnter(); } } [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69311, NameID = 3632, PrimaryActorOID = (uint)OID.KingThordan)] public class KingThordan(WorldState ws, Actor primary) : BossModule(ws, primary, new(-247, 321), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var h in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var h = hints.PotentialTargets[i]; h.Priority = h.Actor.FindStatus(SID.Invincibility) == null ? 1 : 0; + } } } diff --git a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/Nidhogg.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Nidhogg.cs similarity index 50% rename from BossMod/Modules/Shadowbringers/Quest/FadedMemories/Nidhogg.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Nidhogg.cs index a7cc3c74c6..9a40b095ad 100644 --- a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/Nidhogg.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Nidhogg.cs @@ -1,13 +1,15 @@ -namespace BossMod.Shadowbringers.Quest.FadedMemories; +namespace BossMod.Shadowbringers.Quest.MSQ.FadedMemories; -class HighJump(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HighJump), new AOEShapeCircle(8)); -class Geirskogul(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Geirskogul), new AOEShapeRect(62, 4)); +class HighJump(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HighJump), 8); +class Geirskogul(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Geirskogul), 62, 4); class NidhoggStates : StateMachineBuilder { public NidhoggStates(BossModule module) : base(module) { - TrivialPhase().ActivateOnEnter().ActivateOnEnter(); + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter(); } } diff --git a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/Zenos.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Zenos.cs similarity index 61% rename from BossMod/Modules/Shadowbringers/Quest/FadedMemories/Zenos.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Zenos.cs index 848cdcc2a3..1d8f589817 100644 --- a/BossMod/Modules/Shadowbringers/Quest/FadedMemories/Zenos.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/FadedMemories/Zenos.cs @@ -1,9 +1,9 @@ -namespace BossMod.Shadowbringers.Quest.FadedMemories; +namespace BossMod.Shadowbringers.Quest.MSQ.FadedMemories; class Swords(BossModule module) : Components.AddsMulti(module, [0x2F2A, 0x2F2B, 0x2F2C]); -class EntropicFlame(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.EntropicFlame), new AOEShapeRect(50, 4)); -class VeinSplitter(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.VeinSplitter), new AOEShapeCircle(10)); +class EntropicFlame(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EntropicFlame), new AOEShapeRect(50, 4)); +class VeinSplitter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.VeinSplitter), 10); class ZenosYaeGalvusStates : StateMachineBuilder { @@ -12,8 +12,7 @@ public ZenosYaeGalvusStates(BossModule module) : base(module) TrivialPhase() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } diff --git a/BossMod/Modules/Shadowbringers/Quest/MSQ/TheGreatShipVylbrand.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/TheGreatShipVylbrand.cs new file mode 100644 index 0000000000..5661b74600 --- /dev/null +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/TheGreatShipVylbrand.cs @@ -0,0 +1,207 @@ +namespace BossMod.Shadowbringers.Quest.MSQ.TheGreatShipVylbrand; + +public enum OID : uint +{ + Boss = 0x3187, // R0.5 + SecondOrderRocksplitter = 0x3107, // R1.08 + SecondOrderRoundsman = 0x3102, // R0.9 + SecondOrderPickman = 0x3100, // R0.9 + SecondOrderAlchemist = 0x3101, // R0.9 + OghomoroGolem = 0x3103, // R1.1 + Construct2 = 0x3104, // R3.2 + Bomb = 0x3105, // R0.9 + Grenade1 = 0x318C, // R1.8-3.6 + Grenade2 = 0x3106, // R1.8 + ChannelAether = 0x1EB0F7, // R0.5 + Alphinaud = 0x30FE, // R0.500, x1 + Helper = 0x233C // R0.5 +} + +public enum AID : uint +{ + AutoAttack1 = 6499, // SecondOrderRocksplitter->player, no cast, single-target + AutoAttack2 = 6497, // SecondOrderRoundsman/SecondOrderPickman/Construct2->allies, no cast, single-target + Teleport = 22947, // Construct2->location, no cast, single-target + + KoboldDrill = 22967, // SecondOrderRocksplitter->player, 4.0s cast, single-target + BulldozeTelegraph1 = 22955, // SecondOrderRocksplitter->location, 8.0s cast, width 6 rect charge + BulldozeTelegraph2 = 22957, // Helper->location, 8.0s cast, width 6 rect charge + Bulldoze = 22956, // SecondOrderRocksplitter->location, no cast, width 6 rect charge + TunnelShakerVisual = 22958, // SecondOrderRocksplitter->self, 5.0s cast, single-target + TunnelShaker1 = 22959, // Helper->self, 5.0s cast, range 60 30-degree cone + StrataSmasher = 22960, // SecondOrderRocksplitter->location, no cast, range 60 circle + Uplift1 = 22961, // Helper->self, 6.0s cast, range 10 circle + Uplift2 = 22962, // Helper->self, 8.0s cast, range 10-20 donut + Uplift3 = 22963, // Helper->self, 10.0s cast, range 20-30 donut + + Stone = 21588, // SecondOrderAlchemist->allies, 1.0s cast, single-target + + Breakthrough = 22948, // Construct2->ally, 11.0s cast, width 8 rect charge, wild charges + + TenTrolleyWallop = 22950, // Construct2->self, 6.0s cast, range 40 60-degree cone + TenTrolleyTorque = 22949, // Construct2->self, 6.0s cast, range 16 circle + TenTrolleyTap = 23362, // Construct2->self, 3.5s cast, range 8 120-degree cone + ExplosiveChemistry = 23497, // Grenade1/Grenade2->self, 12.0s cast, single-target + SelfDestructVisual = 23500, // Grenade2->self, no cast, single-target + SelfDestruct1 = 22952, // Grenade1/Grenade2->self, no cast, range 6 circle + SelfDestruct2 = 23501, // Boss->self, 3.5s cast, range 10 circle + + Quakedown = 22953, // SecondOrderRocksplitter->location, no cast, range 60 circle, phase transition, excavate happens while player is stunned and thus useles to draw + ExcavateVisual = 23132, // SecondOrderRocksplitter->self, 17.0s cast, single-target + Excavate = 22954 // SecondOrderRocksplitter->ally, no cast, width 6 rect charge +} + +public enum TetherID : uint +{ + BombTether = 97 // Grenade2->Alphinaud +} + +class TenTrolleyTorque(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TenTrolleyTorque), 16); +class TenTrolleyTap(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TenTrolleyTap), new AOEShapeCone(8, 60.Degrees())); +class TenTrolleyWallop(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TenTrolleyWallop), new AOEShapeCone(40, 30.Degrees())); +class SelfDestruct2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SelfDestruct2), 10); + +class Bulldoze(BossModule module) : Components.GenericAOEs(module) +{ + private readonly List _aoes = new(4); + + public override IEnumerable ActiveAOEs(int slot, Actor actor) + { + var count = _aoes.Count; + if (count == 0) + return []; + var aoes = new AOEInstance[count]; + for (var i = 0; i < count; ++i) + { + var aoe = _aoes[i]; + if (i == 0) + aoes[i] = count > 1 ? aoe with { Color = Colors.Danger } : aoe; + else + aoes[i] = aoe; + } + return aoes; + } + + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.BulldozeTelegraph2) + { + var dir = spell.LocXZ - caster.Position; + _aoes.Add(new(new AOEShapeRect(dir.Length(), 3), caster.Position, Angle.FromDirection(dir), Module.CastFinishAt(spell))); + } + } + + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + if (_aoes.Count != 0 && (AID)spell.Action.ID is AID.BulldozeTelegraph1 or AID.Bulldoze) + _aoes.RemoveAt(0); + } +} + +class TunnelShaker(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TunnelShaker1), new AOEShapeCone(60, 15.Degrees())); +class Uplift(BossModule module) : Components.ConcentricAOEs(module, [new AOEShapeCircle(10), new AOEShapeDonut(10, 20), new AOEShapeDonut(20, 30)]) +{ + public override void OnCastStarted(Actor caster, ActorCastInfo spell) + { + if ((AID)spell.Action.ID == AID.Uplift1) + AddSequence(spell.LocXZ, Module.CastFinishAt(spell)); + } + + public override void OnCastFinished(Actor caster, ActorCastInfo spell) + { + if (Sequences.Count != 0) + { + var order = (AID)spell.Action.ID switch + { + AID.Uplift1 => 0, + AID.Uplift2 => 1, + AID.Uplift3 => 2, + _ => -1 + }; + AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2)); + } + } +} + +class BombTether(BossModule module) : Components.InterceptTetherAOE(module, ActionID.MakeSpell(AID.SelfDestruct1), (uint)TetherID.BombTether, 6) +{ + public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + if (Tethers.Count != 0) + { + base.AddAIHints(slot, actor, assignment, hints); + var tether = Tethers[0]; + if (tether.Player != Module.Raid.Player()) + { + var source = tether.Enemy; + var target = Module.Enemies(OID.Alphinaud)[0]; + hints.AddForbiddenZone(ShapeDistance.InvertedRect(target.Position + (target.HitboxRadius + 0.1f) * target.DirectionTo(source), source.Position, 0.6f), Activation); + } + } + } + + public override void OnTethered(Actor source, ActorTetherInfo tether) + { + base.OnTethered(source, tether); + if (Activation != default && tether.ID == TID) + Activation = WorldState.FutureTime(15); + } + + public override void OnEventCast(Actor caster, ActorCastEvent spell) + { + if (spell.Action == WatchedAction) + Activation = default; + } +} + +public class SecondOrderRocksplitterStates : StateMachineBuilder +{ + public SecondOrderRocksplitterStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .Raw.Update = () => module.Enemies(OID.SecondOrderRocksplitter) is var boss && boss.Count != 0 && boss[0].HPMP.CurHP == 1 || module.WorldState.CurrentCFCID != 764; + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69551)] +public class SecondOrderRocksplitter(WorldState ws, Actor primary) : BossModule(ws, primary, default, arena) +{ + private static readonly ArenaBoundsComplex arena = new([new Polygon(default, 26.5f, 24)]); + private static readonly uint[] opponents = [(uint)OID.Grenade1, (uint)OID.Grenade2, (uint)OID.SecondOrderRoundsman, (uint)OID.SecondOrderRocksplitter, (uint)OID.SecondOrderPickman, + (uint)OID.SecondOrderAlchemist, (uint)OID.Bomb, (uint)OID.Construct2, (uint)OID.OghomoroGolem]; + + protected override bool CheckPull() => Raid.Player()!.InCombat; + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(Enemies(opponents)); + + protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + var aether = Enemies(OID.ChannelAether); + var aethercount = aether.Count; + if (aethercount != 0) + for (var i = 0; i < aethercount; ++i) + { + var interact = aether[i]; + if (interact.IsTargetable) + { + hints.InteractWithTarget = interact; + break; + } + } + + if (Enemies(OID.Grenade2).Count != 0) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var e = hints.PotentialTargets[i]; + if ((OID)e.Actor.OID == OID.Grenade2) + e.Priority = AIHints.Enemy.PriorityPointless; + } + } +} diff --git a/BossMod/Modules/Shadowbringers/Quest/TheOracleOfLight.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/TheOracleOfLight.cs similarity index 67% rename from BossMod/Modules/Shadowbringers/Quest/TheOracleOfLight.cs rename to BossMod/Modules/Shadowbringers/Quest/MSQ/TheOracleOfLight.cs index af4008c356..9dd39210c6 100644 --- a/BossMod/Modules/Shadowbringers/Quest/TheOracleOfLight.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/TheOracleOfLight.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.TheOracleOfLight; +namespace BossMod.Shadowbringers.Quest.MSQ.TheOracleOfLight; public enum OID : uint { @@ -15,10 +15,13 @@ public enum AID : uint UnbridledWrath = 18036, // 299E->self, 5.5s cast, range 90 width 90 rect } -class HotPursuit(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.HotPursuit1), 5); -class NexusOfThunder1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NexusOfThunder1), new AOEShapeRect(60, 2.5f)); -class NexusOfThunder2(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NexusOfThunder2), new AOEShapeRect(60, 2.5f)); -class Burn(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Burn), new AOEShapeCircle(8), maxCasts: 8); +class HotPursuit(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HotPursuit1), 5); + +abstract class NoT(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(60.5f, 2.5f)); +class NexusOfThunder1(BossModule module) : NoT(module, AID.NexusOfThunder1); +class NexusOfThunder2(BossModule module) : NoT(module, AID.NexusOfThunder2); + +class Burn(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Burn), 8, 8); class UnbridledWrath(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.UnbridledWrath), 20, kind: Kind.DirForward, stopAtWall: true); class RanjitStates : StateMachineBuilder @@ -37,4 +40,3 @@ public RanjitStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68841, NameID = 8374)] public class Ranjit(WorldState ws, Actor primary) : BossModule(ws, primary, new(126.75f, -311.25f), new ArenaBoundsCircle(20)); - diff --git a/BossMod/Modules/Shadowbringers/Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs b/BossMod/Modules/Shadowbringers/Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs index 180476c5a6..e991d9b645 100644 --- a/BossMod/Modules/Shadowbringers/Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs +++ b/BossMod/Modules/Shadowbringers/Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs @@ -1,19 +1,15 @@ -<<<<<<<< HEAD:BossMod/Modules/Shadowbringers/Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs -namespace BossMod.Shadowbringers.Quest.MSQ.VowsOfVitrueDeedsOfCruelty; -======== -using BossMod.QuestBattle; +using BossMod.QuestBattle; -namespace BossMod.Shadowbringers.Quest.VowsOfVirtueDeedsOfCruelty; ->>>>>>>> merge:BossMod/Modules/Shadowbringers/Quest/VowsOfVirtueDeedsOfCruelty.cs +namespace BossMod.Shadowbringers.Quest.MSQ.VowsOfVirtueDeedsOfCruelty; public enum OID : uint { - Boss = 0x2C85, // R6.000, x1 - TerminusEstVisual = 0x2C98, // R1.000, x3 - SigniferPraetorianus = 0x2C9A, // R0.500, x0 (spawn during fight), the adds on the catwalk that just rain down Fire II - LembusPraetorianus = 0x2C99, // R2.400, x0 (spawn during fight), two large magitek ships - MagitekBit = 0x2C9C, // R0.600, x0 (spawn during fight) - BossHelper = 0x233C + Boss = 0x2C85, // R6.0 + TerminusEstVisual = 0x2C98, // R1.0 + SigniferPraetorianus = 0x2C9A, // R0.5 + LembusPraetorianus = 0x2C99, // R2.4 + MagitekBit = 0x2C9C, // R0.6 + Helper = 0x233C } public enum AID : uint @@ -26,15 +22,15 @@ public enum AID : uint AngrySalamander = 18787, // Boss->self, 3.0s cast, range 40+R width 6 rect FireII = 18959, // SigniferPraetorianus->location, 3.0s cast, range 5 circle TerminusEstBossCast = 18788, // Boss->self, 3.0s cast, single-target - TerminusEstLocationHelper = 18889, // BossHelper->self, 4.0s cast, range 3 circle + TerminusEstLocationHelper = 18889, // Helper->self, 4.0s cast, range 3 circle TerminusEstVisual = 18789, // TerminusEstVisual->self, 1.0s cast, range 40+R width 4 rect HorridRoar = 18779, // 2CC5->location, 2.0s cast, range 6 circle, this is your own attack. It spawns an aoe at the location of any enemy it initally hits GarleanFire = 4007, // LembusPraetorianus->location, 3.0s cast, range 5 circle MagitekBit = 18790, // Boss->self, no cast, single-target MetalCutterCast = 18793, // Boss->self, 6.0s cast, single-target - MetalCutter = 18794, // BossHelper->self, 6.0s cast, range 30+R 20-degree cone + MetalCutter = 18794, // Helper->self, 6.0s cast, range 30+R 20-degree cone AtomicRayCast = 18795, // Boss->self, 6.0s cast, single-target - AtomicRay = 18796, // BossHelper->location, 6.0s cast, range 10 circle + AtomicRay = 18796, // Helper->location, 6.0s cast, range 10 circle MagitekRayBit = 18791, // MagitekBit->self, 6.0s cast, range 50+R width 2 rect SelfDetonate = 18792, // MagitekBit->self, 7.0s cast, range 40+R circle, enrage if bits are not killed before cast } @@ -128,22 +124,21 @@ public ArchUltimaStates(BossModule module) : base(module) } [ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "croizat", GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69218, NameID = 9189)] -<<<<<<<< HEAD:BossMod/Modules/Shadowbringers/Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs -public class VowsOfVirtueDeedsOfCruelty(WorldState ws, Actor primary) : BossModule(ws, primary, new(240, 230), new ArenaBoundsSquare(19.5f)); -======== -public class ArchUltima(WorldState ws, Actor primary) : BossModule(ws, primary, new(240, 230), new ArenaBoundsSquare(20)) +public class ArchUltima(WorldState ws, Actor primary) : BossModule(ws, primary, new(240, 230), new ArenaBoundsSquare(19.5f)) { protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var h in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var h = hints.PotentialTargets[i]; h.Priority = (OID)h.Actor.OID switch { OID.MagitekBit => 2, OID.LembusPraetorianus => 1, _ => 0 }; + } } - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } ->>>>>>>> merge:BossMod/Modules/Shadowbringers/Quest/VowsOfVirtueDeedsOfCruelty.cs diff --git a/BossMod/Modules/Shadowbringers/Quest/ATearfulReunion.cs b/BossMod/Modules/Shadowbringers/Quest/Role/ATearfulReunion.cs similarity index 76% rename from BossMod/Modules/Shadowbringers/Quest/ATearfulReunion.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/ATearfulReunion.cs index 41bf920c9b..b6a5ac7e29 100644 --- a/BossMod/Modules/Shadowbringers/Quest/ATearfulReunion.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/ATearfulReunion.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.ATearfulReunion; +namespace BossMod.Shadowbringers.Quest.Role.ATearfulReunion; public enum OID : uint { @@ -18,10 +18,10 @@ public enum AID : uint SanctifiedBlizzardIV = 17047, // _Gen_Phronesis->self, 5.0s cast, range 5-20 donut } -class SanctifiedBlizzardIV(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedBlizzardIV), new AOEShapeDonut(5, 20)); -class SanctifiedBlizzardII(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedBlizzardII), new AOEShapeCircle(5)); -class SanctifiedFireIII(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedFireIII), 6); -class SanctifiedBlizzardIII(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedBlizzardIII), new AOEShapeCone(40.5f, 22.5f.Degrees())); +class SanctifiedBlizzardIV(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedBlizzardIV), new AOEShapeDonut(5, 20)); +class SanctifiedBlizzardII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedBlizzardII), 5); +class SanctifiedFireIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedFireIII), 6); +class SanctifiedBlizzardIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedBlizzardIII), new AOEShapeCone(40.5f, 22.5f.Degrees())); class Hollow(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(OID.Hollow)); class HollowTether(BossModule module) : Components.Chains(module, 1, chainLength: 5); class SanctifiedFireIV(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.SanctifiedFireIV1), 10); @@ -30,9 +30,9 @@ class SanctifiedFlare(BossModule module) : Components.StackWithCastTargets(modul public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - if (ActiveStacks.Any() && WorldState.Actors.First(x => x.OID == 0x29C3) is Actor cerigg) + if (ActiveStacks.Count != 0 && WorldState.Actors.First(x => x.OID == 0x29C3) is Actor cerigg) { - hints.AddForbiddenZone(new AOEShapeDonut(6, 100), cerigg.Position, default, ActiveStacks.First().Activation); + hints.AddForbiddenZone(ShapeDistance.InvertedCircle(cerigg.Position, 6), ActiveStacks.First().Activation); } } } @@ -51,7 +51,7 @@ public override void OnTethered(Actor source, ActorTetherInfo tether) public override void DrawArenaForeground(int pcSlot, Actor pc) { foreach (var b in Balls) - Arena.AddLine(pc.Position, b.Position, ArenaColor.Danger); + Arena.AddLine(pc.Position, b.Position, Colors.Danger); } public override void Update() @@ -64,6 +64,8 @@ public override void Update() var closestBall = Balls.OrderBy(player.DistanceToHitbox).FirstOrDefault(); Modify(closestBall?.Position, Hollows); + Safezones.Clear(); + AddSafezone(NextExplosion, default); } public override void AddHints(int slot, Actor actor, TextHints hints) @@ -90,8 +92,7 @@ public PhronesisStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } diff --git a/BossMod/Modules/Shadowbringers/Quest/CourageBornOfFear.cs b/BossMod/Modules/Shadowbringers/Quest/Role/CourageBornOfFear.cs similarity index 73% rename from BossMod/Modules/Shadowbringers/Quest/CourageBornOfFear.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/CourageBornOfFear.cs index e6976f2ef1..83421c72f8 100644 --- a/BossMod/Modules/Shadowbringers/Quest/CourageBornOfFear.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/CourageBornOfFear.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.CourageBornOfFear; +namespace BossMod.Shadowbringers.Quest.Role.CourageBornOfFear; public enum OID : uint { @@ -20,19 +20,19 @@ public enum AID : uint InquisitorsBlade = 17095, // 29E4->self, 5.0s cast, range 40 180-degree cone RainOfLight = 17082, // 29DD->location, 3.0s cast, range 4 circle ArrowOfFortitude = 17211, // Andreia->self, 4.0s cast, range 30 width 8 rect - BodkinVolley1 = 17189, // Andreia->29DF, 6.0s cast, range 5 circle + BodkinVolley = 17189, // Andreia->29DF, 6.0s cast, range 5 circle } -class ArrowOfFortitude(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ArrowOfFortitude), new AOEShapeRect(30, 4)); -class BodkinVolley(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.BodkinVolley1), 5, minStackSize: 1); -class RainOfLight(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.RainOfLight), 4); -class ThePathOfLight(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ThePathOfLight), new AOEShapeCircle(15)); -class InquisitorsBlade(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.InquisitorsBlade), new AOEShapeCone(40, 90.Degrees())); +class ArrowOfFortitude(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ArrowOfFortitude), new AOEShapeRect(30, 4)); +class BodkinVolley(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.BodkinVolley), 5, minStackSize: 1); +class RainOfLight(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RainOfLight), 4); +class ThePathOfLight(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ThePathOfLight), 15); +class InquisitorsBlade(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.InquisitorsBlade), new AOEShapeCone(40, 90.Degrees())); class MythrilCycloneKB(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.MythrilCyclone1), 18, stopAtWall: true); -class MythrilCycloneDonut(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MythrilCyclone2), new AOEShapeDonut(8, 20)); +class MythrilCycloneDonut(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MythrilCyclone2), new AOEShapeDonut(8, 20)); class SanctifiedMeltdown(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.SanctifiedMeltdown), 6); -class UncloudedAscension(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.UncloudedAscension1), new AOEShapeCircle(10)); -class Overcome(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Overcome), new AOEShapeCone(8.5f, 60.Degrees())); +class UncloudedAscension(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.UncloudedAscension1), 10); +class Overcome(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Overcome), new AOEShapeCone(8.5f, 60.Degrees())); class SanctifiedFireII(BossModule module) : Components.BaitAwayIcon(module, new AOEShapeCircle(5), 23, centerAtTarget: true) { @@ -92,11 +92,14 @@ public ImmaculateWarriorStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68814, NameID = 8782)] public class ImmaculateWarrior(WorldState ws, Actor primary) : BossModule(ws, primary, new(-247, 688.5f), new ArenaBoundsCircle(19.5f)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var h in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var h = hints.PotentialTargets[i]; h.Priority = h.Actor.TargetID == actor.InstanceID ? 1 : 0; + } } } diff --git a/BossMod/Modules/Shadowbringers/Quest/NyelbertsLament.cs b/BossMod/Modules/Shadowbringers/Quest/Role/NyelbertsLament.cs similarity index 83% rename from BossMod/Modules/Shadowbringers/Quest/NyelbertsLament.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/NyelbertsLament.cs index f8bbffa5d0..0e85afc0d8 100644 --- a/BossMod/Modules/Shadowbringers/Quest/NyelbertsLament.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/NyelbertsLament.cs @@ -1,13 +1,14 @@ using BossMod.QuestBattle.Shadowbringers.RoleQuests; -namespace BossMod.Shadowbringers.Quest.NyelbertsLament; +namespace BossMod.Shadowbringers.Quest.Role.NyelbertsLament; public enum OID : uint { Boss = 0x2977, - Helper = 0x233C, + BovianBull = 0x2976, - LooseBoulder = 0x2978, // R2.400, x0 (spawn during fight) + LooseBoulder = 0x2978, // R2.4 + Helper = 0x233C } public enum AID : uint @@ -57,16 +58,18 @@ private void Refresh() var blockers = Module.Enemies(OID.LooseBoulder); Modify(ActiveCaster?.CastInfo?.LocXZ, blockers.Select(b => (b.Position, b.HitboxRadius)), Module.CastFinishAt(ActiveCaster?.CastInfo)); + Safezones.Clear(); + AddSafezone(NextExplosion, default); } } -class FallingRock(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.FallingRock), 4); -class ZoomIn(BossModule module) : Components.SimpleLineStack(module, 4, 42, ActionID.MakeSpell(AID.ZoomTargetSelect), ActionID.MakeSpell(AID.ZoomIn), 5.1f) +class FallingRock(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FallingRock), 4); +class ZoomIn(BossModule module) : Components.LineStack(module, ActionID.MakeSpell(AID.ZoomTargetSelect), ActionID.MakeSpell(AID.ZoomIn), 5.1f, 42) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (Source != null) - hints.AddForbiddenZone(new AOEShapeDonut(3, 100), Arena.Center, default, Activation); + if (ActiveBaits.Any()) + hints.AddForbiddenZone(ShapeDistance.InvertedCircle(Arena.Center, 3), ActiveBaits.FirstOrDefault().Activation); } } @@ -84,7 +87,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme public override void DrawArenaBackground(int pcSlot, Actor pc) { if (EnrageCast != null && Paladin != null) - Arena.ZoneCone(Paladin.Position, 0, 8, Paladin.Rotation + 180.Degrees(), 60.Degrees(), ArenaColor.SafeFromAOE); + Arena.ZoneCone(Paladin.Position, 0, 8, Paladin.Rotation + 180.Degrees(), 60.Degrees(), Colors.SafeFromAOE); } public override void AddHints(int slot, Actor actor, TextHints hints) @@ -112,5 +115,5 @@ public BovianStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69162, NameID = 8363)] public class Bovian(WorldState ws, Actor primary) : BossModule(ws, primary, new(-440, -691), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Shadowbringers/Quest/TheHardenedHeart.cs b/BossMod/Modules/Shadowbringers/Quest/Role/TheHardenedHeart.cs similarity index 90% rename from BossMod/Modules/Shadowbringers/Quest/TheHardenedHeart.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/TheHardenedHeart.cs index 9c23a90128..586a95e049 100644 --- a/BossMod/Modules/Shadowbringers/Quest/TheHardenedHeart.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/TheHardenedHeart.cs @@ -1,6 +1,6 @@ using BossMod.QuestBattle; -namespace BossMod.Shadowbringers.Quest.TheHardenedHeart; +namespace BossMod.Shadowbringers.Quest.Role.TheHardenedHeart; public enum OID : uint { @@ -27,7 +27,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) } class TwistedTalent(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.TwistedTalent1), 5); -class AbyssalCharge(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AbyssalCharge1), new AOEShapeRect(40, 2)); +class AbyssalCharge(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AbyssalCharge1), new AOEShapeRect(40, 2)); class AutoBranden(WorldState ws) : UnmanagedRotation(ws, 3) { @@ -93,7 +93,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) public override void DrawArenaBackground(int pcSlot, Actor pc) { if (DwarfTether is Tether t) - Arena.AddLine(t.Source.Position, t.Target.Position, ArenaColor.Danger); + Arena.AddLine(t.Source.Position, t.Target.Position, Colors.Danger); } public override void OnEventCast(Actor caster, ActorCastEvent spell) @@ -105,7 +105,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) class BrandenAI(BossModule module) : RotationModule(module); -class RustingClaw(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RustingClaw), new AOEShapeCone(10.3f, 45.Degrees())); +class RustingClaw(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RustingClaw), new AOEShapeCone(10.3f, 45.Degrees())); class TadricTheVaingloriousStates : StateMachineBuilder { @@ -124,12 +124,13 @@ public TadricTheVaingloriousStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68783, NameID = 8339)] public class TadricTheVainglorious(WorldState ws, Actor primary) : BossModule(ws, primary, new(100, 100), new ArenaBoundsSquare(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var h in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var h = hints.PotentialTargets[i]; h.Priority = h.Actor.FindStatus(775) == null ? (h.Actor.TargetID == actor.InstanceID ? 2 : 1) : 0; if (h.Actor.OID is not (0x291D or 0x2919) && h.Actor.CastInfo == null) { @@ -140,4 +141,3 @@ protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRoles } } } - diff --git a/BossMod/Modules/Shadowbringers/Quest/TheHuntersLegacy.cs b/BossMod/Modules/Shadowbringers/Quest/Role/TheHuntersLegacy.cs similarity index 71% rename from BossMod/Modules/Shadowbringers/Quest/TheHuntersLegacy.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/TheHuntersLegacy.cs index 4aa94e49a9..b4d97cf589 100644 --- a/BossMod/Modules/Shadowbringers/Quest/TheHuntersLegacy.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/TheHuntersLegacy.cs @@ -1,6 +1,6 @@ using BossMod.QuestBattle; -namespace BossMod.Shadowbringers.Quest.TheHuntersLegacy; +namespace BossMod.Shadowbringers.Quest.Role.TheHuntersLegacy; public enum OID : uint { @@ -22,13 +22,16 @@ public enum AID : uint } class Thunderbolt(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.Thunderbolt1), 5); -class BalamBlaster(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BalamBlaster), new AOEShapeCone(38.05f, 135.Degrees())); -class BalamBlasterRear(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BalamBlasterRear), new AOEShapeCone(38.05f, 135.Degrees())); -class ElectricWhisker(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ElectricWhisker), new AOEShapeCone(16.05f, 45.Degrees())); -class RoaringThunder(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.RoaringThunder), new AOEShapeDonut(8, 30)); -class StreakLightning(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.StreakLightning), 3); -class StreakLightning1(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.StreakLightning1), 3); -class AlternatingCurrent(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AlternatingCurrent1), new AOEShapeRect(60, 2.5f)); + +abstract class BB(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(38.05f, 135.Degrees())); +class BalamBlaster(BossModule module) : BB(module, AID.BalamBlaster); +class BalamBlasterRear(BossModule module) : BB(module, AID.BalamBlasterRear); + +class ElectricWhisker(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ElectricWhisker), new AOEShapeCone(16.05f, 45.Degrees())); +class RoaringThunder(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RoaringThunder), new AOEShapeDonut(8, 30)); +class StreakLightning(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.StreakLightning), 3); +class StreakLightning1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.StreakLightning1), 3); +class AlternatingCurrent(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AlternatingCurrent1), new AOEShapeRect(60, 2.5f)); class RumblingThunder(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.RumblingThunderStack), 5, 1); class RendaRae(WorldState ws) : UnmanagedRotation(ws, 20) @@ -59,13 +62,13 @@ class RonkanAura(BossModule module) : BossComponent(module) public override void DrawArenaBackground(int pcSlot, Actor pc) { if (AuraCenter is Actor a) - Arena.ZoneCircle(a.Position, 10, ArenaColor.SafeFromAOE); + Arena.ZoneCircle(a.Position, 10, Colors.SafeFromAOE); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { if (AuraCenter is Actor a) - hints.AddForbiddenZone(new AOEShapeDonut(10, 100), a.Position, activation: WorldState.FutureTime(5)); + hints.AddForbiddenZone(ShapeDistance.InvertedCircle(a.Position, 10), activation: WorldState.FutureTime(5)); } } diff --git a/BossMod/Modules/Shadowbringers/Quest/TheLostAndTheFound/Sophrosyne.cs b/BossMod/Modules/Shadowbringers/Quest/Role/TheLostAndTheFound/Sophrosyne.cs similarity index 83% rename from BossMod/Modules/Shadowbringers/Quest/TheLostAndTheFound/Sophrosyne.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/TheLostAndTheFound/Sophrosyne.cs index f6a259691a..4e3664b59b 100644 --- a/BossMod/Modules/Shadowbringers/Quest/TheLostAndTheFound/Sophrosyne.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/TheLostAndTheFound/Sophrosyne.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.TheLostAndTheFound.Sophrosyne; +namespace BossMod.Shadowbringers.Quest.Role.TheLostAndTheFound.Sophrosyne; public enum OID : uint { @@ -25,5 +25,5 @@ public SophrosyneStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68806, NameID = 8395)] public class Sophrosyne(WorldState ws, Actor primary) : BossModule(ws, primary, new(632, 64.15f), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Shadowbringers/Quest/TheLostAndTheFound/Yxtlilton.cs b/BossMod/Modules/Shadowbringers/Quest/Role/TheLostAndTheFound/Yxtlilton.cs similarity index 79% rename from BossMod/Modules/Shadowbringers/Quest/TheLostAndTheFound/Yxtlilton.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/TheLostAndTheFound/Yxtlilton.cs index d6806f5362..a43e1f15b9 100644 --- a/BossMod/Modules/Shadowbringers/Quest/TheLostAndTheFound/Yxtlilton.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/TheLostAndTheFound/Yxtlilton.cs @@ -1,11 +1,11 @@ using BossMod.QuestBattle; -namespace BossMod.Shadowbringers.Quest.TheLostAndTheFound.Yxtlilton; +namespace BossMod.Shadowbringers.Quest.Role.TheLostAndTheFound.Yxtlilton; public enum OID : uint { Boss = 0x29B0, - Helper = 0x233C, + Helper = 0x233C } public enum AID : uint @@ -20,8 +20,8 @@ class CodexOfGravity(BossModule module) : Components.StackWithCastTargets(module public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); - if (Stacks.Count > 0) - hints.AddForbiddenZone(new AOEShapeDonut(1.5f, 100), Arena.Center, default, Stacks[0].Activation); + if (Stacks.Count != 0) + hints.AddForbiddenZone(ShapeDistance.InvertedCircle(Arena.Center, 1.5f), Stacks[0].Activation); } } @@ -32,9 +32,19 @@ protected override void Exec(Actor? primaryTarget) if (primaryTarget == null) return; - var party = World.Party.WithoutSlot().ToList(); + var party = World.Party.WithoutSlot(false, false); - Hints.GoalZones.Add(p => party.Count(act => act.Position.InCircle(p, 15 + Player.HitboxRadius + act.HitboxRadius))); + Hints.GoalZones.Add(p => + { + var count = 0; + for (var i = 0; i < party.Length; ++i) + { + var act = party[i]; + if (act.Position.InCircle(p, 15 + Player.HitboxRadius + act.HitboxRadius)) + count++; + } + return count; + }); var lowest = party.MinBy(p => p.PredictedHPRatio)!; var esunable = party.FirstOrDefault(x => x.FindStatus(482) != null); @@ -83,5 +93,5 @@ public YxtliltonStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68806, NameID = 8393)] public class Yxtlilton(WorldState ws, Actor primary) : BossModule(ws, primary, new(-120, -770), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Shadowbringers/Quest/TheSoulOfTemperance.cs b/BossMod/Modules/Shadowbringers/Quest/Role/TheSoulOfTemperance.cs similarity index 75% rename from BossMod/Modules/Shadowbringers/Quest/TheSoulOfTemperance.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/TheSoulOfTemperance.cs index 6de41c42a6..cf67e50ab8 100644 --- a/BossMod/Modules/Shadowbringers/Quest/TheSoulOfTemperance.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/TheSoulOfTemperance.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.TheSoulOfTemperance; +namespace BossMod.Shadowbringers.Quest.Role.TheSoulOfTemperance; public enum OID : uint { @@ -20,16 +20,16 @@ public enum AID : uint SanctifiedHoly2 = 17604, // 2A0C->location, 4.0s cast, range 6 circle } -class SanctifiedHoly1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedHoly1), new AOEShapeCircle(8)); -class SanctifiedHoly2(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedHoly2), 6); -class ForceOfRestraint(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ForceOfRestraint), new AOEShapeRect(60, 2)); +class SanctifiedHoly1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedHoly1), 8); +class SanctifiedHoly2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedHoly2), 6); +class ForceOfRestraint(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ForceOfRestraint), new AOEShapeRect(60, 2)); class HolyBlur(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.HolyBlur)); class Focus(BossModule module) : Components.BaitAwayChargeCast(module, ActionID.MakeSpell(AID.Focus), 2); -class TemperedVirtue(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TemperedVirtue), new AOEShapeCircle(15)); -class WaterAndWine(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.WaterAndWine), new AOEShapeDonut(6, 12)); +class TemperedVirtue(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TemperedVirtue), 15); +class WaterAndWine(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WaterAndWine), new AOEShapeDonut(6, 12)); class SanctifiedStone(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.SanctifiedStone), 5, 1); -class SanctifiedAero(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedAero1), new AOEShapeRect(40.5f, 3)); +class SanctifiedAero(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedAero1), new AOEShapeRect(40.5f, 3)); class Repose(BossModule module) : BossComponent(module) { @@ -72,5 +72,5 @@ public SophrosyneStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68808, NameID = 8777)] public class Sophrosyne(WorldState ws, Actor primary) : BossModule(ws, primary, new(-651.8f, -127.25f), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Shadowbringers/Quest/ToHaveLovedAndLost.cs b/BossMod/Modules/Shadowbringers/Quest/Role/ToHaveLovedAndLost.cs similarity index 65% rename from BossMod/Modules/Shadowbringers/Quest/ToHaveLovedAndLost.cs rename to BossMod/Modules/Shadowbringers/Quest/Role/ToHaveLovedAndLost.cs index d332164bac..1c47c0cd78 100644 --- a/BossMod/Modules/Shadowbringers/Quest/ToHaveLovedAndLost.cs +++ b/BossMod/Modules/Shadowbringers/Quest/Role/ToHaveLovedAndLost.cs @@ -1,4 +1,4 @@ -namespace BossMod.Shadowbringers.Quest.ToHaveLovedAndLost; +namespace BossMod.Shadowbringers.Quest.Role.ToHaveLovedAndLost; public enum OID : uint { @@ -26,35 +26,41 @@ public enum AID : uint SanctifiedHoly1 = 17431, // 2AB3/2AB2->players/2928, 5.0s cast, range 6 circle } -class HereticsFork(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HereticsFork), new AOEShapeCross(40, 3)); -class SpiritsWithout(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SpiritsWithout), new AOEShapeRect(3.5f, 1.5f)); -class SeraphBlade(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SeraphBlade), new AOEShapeCone(40, 90.Degrees())); -class HereticsQuoit(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HereticsQuoit), new AOEShapeDonut(5, 15)); +class HereticsFork(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HereticsFork), new AOEShapeCross(40, 3)); +class SpiritsWithout(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpiritsWithout), new AOEShapeRect(3.5f, 1.5f)); +class SeraphBlade(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SeraphBlade), new AOEShapeCone(40, 90.Degrees())); +class HereticsQuoit(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HereticsQuoit), new AOEShapeDonut(5, 15)); class SanctifiedHoly(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.SanctifiedHoly1), 6); class Fracture(BossModule module) : Components.GenericTowers(module) { - private readonly AID[] TowerCasts = [AID.Fracture, AID.Fracture1, AID.Fracture2, AID.Fracture3, AID.Fracture4, AID.Fracture5]; - - private bool IsTower(ActionID act) => TowerCasts.Contains((AID)act.ID); + private readonly HashSet casts = [AID.Fracture, AID.Fracture1, AID.Fracture2, AID.Fracture3, AID.Fracture4, AID.Fracture5]; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if (IsTower(spell.Action)) + if (casts.Contains((AID)spell.Action.ID)) Towers.Add(new(spell.LocXZ, 3, activation: Module.CastFinishAt(spell))); } public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - if (IsTower(spell.Action)) - Towers.RemoveAll(t => t.Position.AlmostEqual(spell.LocXZ, 1)); + if (casts.Contains((AID)spell.Action.ID)) + for (var i = 0; i < Towers.Count; ++i) + { + var tower = Towers[i]; + if (tower.Position == spell.LocXZ) + { + Towers.Remove(tower); + break; + } + } } } -class Bloodstain(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Bloodstain), new AOEShapeCircle(5)); +class Bloodstain(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Bloodstain), 5); class BrandOfSin(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.BrandOfSin), 10); class BladeOfJustice(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.BladeOfJustice), 6, minStackSize: 1); -class SanctifiedHolyII(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedHolyII), new AOEShapeCircle(5)); -class SanctifiedHolyIII(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.SanctifiedHolyIII), 6); +class SanctifiedHolyII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedHolyII), 5); +class SanctifiedHolyIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SanctifiedHolyIII), 6); class DikaiosyneStates : StateMachineBuilder { diff --git a/BossMod/Modules/Shadowbringers/Quest/SleepNowInSapphire/P2SapphireWeapon.cs b/BossMod/Modules/Shadowbringers/Quest/SleepNowInSapphire/P2SapphireWeapon.cs deleted file mode 100644 index a0ec6bca18..0000000000 --- a/BossMod/Modules/Shadowbringers/Quest/SleepNowInSapphire/P2SapphireWeapon.cs +++ /dev/null @@ -1,86 +0,0 @@ -using BossMod.Shadowbringers.Quest.SleepNowInSapphire.P1GuidanceSystem; - -namespace BossMod.Shadowbringers.Quest.SleepNowInSapphire.P2SapphireWeapon; - -public enum OID : uint -{ - Boss = 0x2DFA, - Helper = 0x233C, -} - -public enum AID : uint -{ - TailSwing = 20326, // Boss->self, 4.0s cast, range 46 circle - OptimizedJudgment = 20325, // Boss->self, 4.0s cast, range -60 donut - MagitekSpread = 20336, // RegulasImage->self, 5.0s cast, range 43 ?-degree cone - SideraysRight = 20329, // Helper->self, 8.0s cast, range 128 ?-degree cone - SideraysLeft = 21021, // Helper->self, 8.0s cast, range 128 ?-degree cone - SapphireRay = 20327, // Boss->self, 8.0s cast, range 120 width 40 rect - MagitekRay = 20332, // 2DFC->self, 3.0s cast, range 100 width 6 rect - ServantRoar = 20339, // 2DFD->self, 2.5s cast, range 100 width 8 rect -} - -public enum SID : uint -{ - Invincibility = 775, // none->Boss, extra=0x0 -} - -class MagitekRay(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MagitekRay), new AOEShapeRect(100, 3)); -class ServantRoar(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ServantRoar), new AOEShapeRect(100, 4)); -class TailSwing(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TailSwing), new AOEShapeCircle(46)); -class OptimizedJudgment(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.OptimizedJudgment), new AOEShapeDonut(21, 60)); -class MagitekSpread(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MagitekSpread), new AOEShapeCone(43, 120.Degrees())); -class SapphireRay(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SapphireRay), new AOEShapeRect(120, 20)); -class Siderays(BossModule module) : Components.GenericAOEs(module) -{ - private readonly List<(Actor, WPos)> Casters = []; - - public override IEnumerable ActiveAOEs(int slot, Actor actor) => Casters.Select(c => new AOEInstance(new AOEShapeCone(128, 45.Degrees()), c.Item2, c.Item1.CastInfo!.Rotation, Module.CastFinishAt(c.Item1.CastInfo))); - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - switch ((AID)spell.Action.ID) - { - case AID.SideraysLeft: - Casters.Add((caster, caster.Position + caster.Rotation.ToDirection().OrthoL() * 15)); - break; - case AID.SideraysRight: - Casters.Add((caster, caster.Position + caster.Rotation.ToDirection().OrthoR() * 15)); - break; - } - } - - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - Casters.RemoveAll(c => c.Item1 == caster); - } -} - -class TheSapphireWeaponStates : StateMachineBuilder -{ - public TheSapphireWeaponStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69431, NameID = 9458)] -public class TheSapphireWeapon(WorldState ws, Actor primary) : BossModule(ws, primary, new(-15, 610), new ArenaBoundsSquare(60, 1)) -{ - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); - - protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - foreach (var h in hints.PotentialTargets) - h.Priority = h.Actor.FindStatus(SID.Invincibility) == null ? 1 : 0; - } -} - diff --git a/BossMod/Modules/Shadowbringers/Quest/SteelAgainstSteel.cs b/BossMod/Modules/Shadowbringers/Quest/SteelAgainstSteel.cs deleted file mode 100644 index dfd2b3530e..0000000000 --- a/BossMod/Modules/Shadowbringers/Quest/SteelAgainstSteel.cs +++ /dev/null @@ -1,128 +0,0 @@ -namespace BossMod.Shadowbringers.Quest.SteelAgainstSteel; - -public enum OID : uint -{ - Boss = 0x2A45, - Helper = 0x233C, - Fustuarium = 0x2AD8, // R0.500, x1 (spawn during fight) - CullingBlade = 0x2AD3, // R0.500, x0 (spawn during fight) - IndustrialForce = 0x2BCE, // R0.500, x0 (spawn during fight) - TerminusEst = 0x2A46, // R1.000, x0 (spawn during fight) - CaptiveBolt = 0x2AD7, // R0.500, x0 (spawn during fight) -} - -public enum AID : uint -{ - CullingBlade1 = 17553, // CullingBlade->self, 3.5s cast, range 60 30-degree cone - TheOrder = 17568, // Boss->self, 4.0s cast, single-target - TerminusEst1 = 17567, // TerminusEst->self, no cast, range 40+R width 4 rect - CaptiveBolt = 17561, // CaptiveBolt->self, 7.0s cast, range 50+R width 10 rect - AetherochemicalGrenado = 17575, // 2A47->location, 4.0s cast, range 8 circle - Exsanguination = 17565, // 2AD6->self, 5.0s cast, range -17 donut - Exsanguination1 = 17564, // 2AD5->self, 5.0s cast, range -12 donut - Exsanguination2 = 17563, // 2AD4->self, 5.0s cast, range -7 donut - DiffractiveLaser = 17574, // 2A48->self, 3.0s cast, range 45+R width 4 rect - SnakeShot = 17569, // Boss->self, 4.0s cast, range 20 240-degree cone - ScaldingTank1 = 17558, // Fustuarium->2A4A, 6.0s cast, range 6 circle - ToTheSlaughter = 17559, // Boss->self, 4.0s cast, range 40 180-degree cone -} - -class ScaldingTank(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.ScaldingTank1), 6); -class ToTheSlaughter(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ToTheSlaughter), new AOEShapeCone(40, 90.Degrees())); -class Exsanguination(BossModule module) : Components.GenericAOEs(module) -{ - private readonly List<(Actor Actor, float Inner)> Casters = []; - - public override IEnumerable ActiveAOEs(int slot, Actor actor) => Casters.Select(c => new AOEInstance(new AOEShapeDonutSector(c.Inner, c.Inner + 5, 90.Degrees()), c.Actor.CastInfo!.LocXZ, c.Actor.Rotation, Module.CastFinishAt(c.Actor.CastInfo))); - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - var radius = (AID)spell.Action.ID switch - { - AID.Exsanguination => 12, - AID.Exsanguination1 => 7, - AID.Exsanguination2 => 2, - _ => 0 - }; - - if (radius > 0) - Casters.Add((caster, radius)); - } - - public override void OnCastFinished(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID is AID.Exsanguination or AID.Exsanguination1 or AID.Exsanguination2) - Casters.RemoveAll(c => c.Actor == caster); - } -} -class CaptiveBolt(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CaptiveBolt), new AOEShapeRect(50, 5), maxCasts: 4); -class AetherochemicalGrenado(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.AetherochemicalGrenado), 8); -class DiffractiveLaser(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DiffractiveLaser), new AOEShapeRect(45, 2)); -class SnakeShot(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SnakeShot), new AOEShapeCone(20, 120.Degrees())); -class CullingBlade(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CullingBlade1), new AOEShapeCone(60, 15.Degrees())) -{ - public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - base.AddAIHints(slot, actor, assignment, hints); - - // zone rasterization can end up missing the arena center since it only contains the tips of a bunch of very pointy triangles - if (Casters.FirstOrDefault() is Actor c) - hints.AddForbiddenZone(ShapeDistance.Circle(c.Position, 0.5f), Module.CastFinishAt(c.CastInfo)); - } -} -class TerminusEst(BossModule module) : Components.GenericAOEs(module) -{ - private Actor? Caster; - private readonly List Actors = []; - - public override void OnActorCreated(Actor actor) - { - if (actor.OID == (uint)OID.TerminusEst) - Actors.Add(actor); - } - - public override IEnumerable ActiveAOEs(int slot, Actor actor) - { - if (Caster is Actor c) - foreach (var t in Actors) - yield return new AOEInstance(new AOEShapeRect(40, 2), t.Position, t.Rotation, Module.CastFinishAt(c.CastInfo)); - } - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - // check if we already have terminuses out, because he can use this spell for a diff mechanic - if (spell.Action.ID == (uint)AID.TheOrder && Actors.Count > 0) - Caster = caster; - } - - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - if (spell.Action.ID == (uint)AID.TerminusEst1) - { - Actors.Remove(caster); - // reset for next iteration - if (Actors.Count == 0) - Caster = null; - } - } -} - -class VitusQuoMessallaStates : StateMachineBuilder -{ - public VitusQuoMessallaStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68802, NameID = 8872)] -public class VitusQuoMessalla(WorldState ws, Actor primary) : BossModule(ws, primary, new(-266, -507), new ArenaBoundsCircle(19.5f)); diff --git a/BossMod/Modules/Shadowbringers/Quest/TheGreatShipVylbrand.cs b/BossMod/Modules/Shadowbringers/Quest/TheGreatShipVylbrand.cs deleted file mode 100644 index 44d334849b..0000000000 --- a/BossMod/Modules/Shadowbringers/Quest/TheGreatShipVylbrand.cs +++ /dev/null @@ -1,116 +0,0 @@ -namespace BossMod.Shadowbringers.Quest.TheGreatShipVylbrand; - -public enum OID : uint -{ - Boss = 0x3107 -} - -public enum AID : uint -{ - W10TrolleyWallop = 22950, // 3104->self, 6.0s cast, range 40 60-degree cone - W10TrolleyTap = 23362, // 3104->self, 3.5s cast, range 8 120-degree cone - W10TrolleyTorque = 22949, // 3104->self, 6.0s cast, range 16 circle - Bulldoze = 22955, // 3107->location, 8.0s cast, width 6 rect charge - Bulldoze1 = 22957, // 233C->location, 8.0s cast, width 6 rect charge - TunnelShaker1 = 22959, // 233C->self, 5.0s cast, range 60 30-degree cone - Uplift = 22961, // 233C->self, 6.0s cast, range 10 circle - Uplift1 = 22962, // 233C->self, 8.0s cast, range 10-20 donut - Uplift2 = 22963, // 233C->self, 10.0s cast, range 20-30 donut -} - -class Torque(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.W10TrolleyTorque), new AOEShapeCircle(16)); -class Tap(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.W10TrolleyTap), new AOEShapeCone(8, 60.Degrees())); -class Wallop(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.W10TrolleyWallop), new AOEShapeCone(40, 30.Degrees())); -class Bulldoze(BossModule module) : Components.ChargeAOEs(module, ActionID.MakeSpell(AID.Bulldoze), 3); -class Bulldoze2(BossModule module) : Components.ChargeAOEs(module, ActionID.MakeSpell(AID.Bulldoze1), 3); -class TunnelShaker(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TunnelShaker1), new AOEShapeCone(60, 15.Degrees())); -class Uplift(BossModule module) : Components.ConcentricAOEs(module, [new AOEShapeCircle(10), new AOEShapeDonut(10, 20), new AOEShapeDonut(20, 30)]) -{ - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if (spell.Action.ID == (uint)AID.Uplift) - { - AddSequence(caster.Position, Module.CastFinishAt(spell)); - } - } - - public override void OnCastFinished(Actor caster, ActorCastInfo spell) - { - var order = (AID)spell.Action.ID switch - { - AID.Uplift => 0, - AID.Uplift1 => 1, - AID.Uplift2 => 2, - _ => -1 - }; - if (!AdvanceSequence(order, caster.Position, WorldState.FutureTime(2))) - ReportError($"unexpected order {order}"); - } -} - -class BombTether : Components.BaitAwayTethers -{ - private DateTime? Activation; - - public BombTether(BossModule module) : base(module, new AOEShapeCircle(6), 97) - { - CenterAtTarget = true; - } - - public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - if (Activation != null) - hints.AddForbiddenZone(new AOEShapeDonut(1.5f, 100), new(9.15f, -8.44f), activation: Activation.Value); - } - - public override void AddHints(int slot, Actor actor, TextHints hints) - { - if (CurrentBaits.Count > 0) - hints.Add("Intercept tether!", CurrentBaits.Any(b => b.Target != actor)); - } - - public override void OnTethered(Actor source, ActorTetherInfo tether) - { - base.OnTethered(source, tether); - if (tether.ID == TID) - Activation = WorldState.FutureTime(15); - } - - public override void OnUntethered(Actor source, ActorTetherInfo tether) - { - base.OnUntethered(source, tether); - if (tether.ID == TID) - Activation = null; - } -} - -public class SecondOrderRocksplitterStates : StateMachineBuilder -{ - public SecondOrderRocksplitterStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .Raw.Update = () => Module.WorldState.CurrentCFCID != 764; - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69551)] -public class SecondOrderRocksplitter(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, 0), new ArenaBoundsCircle(27)) -{ - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); - - protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - hints.InteractWithTarget = Enemies(0x1EB0F7).FirstOrDefault(x => x.IsTargetable); - - foreach (var e in hints.PotentialTargets) - if (e.Actor.OID == 0x3106) - e.Priority = AIHints.Enemy.PriorityPointless; - } -} diff --git a/BossMod/Modules/Shadowbringers/Quest/SleepNowInSapphire/P1GuidanceSystem.cs b/BossMod/Modules/Shadowbringers/Quest/TheSorrowOfWerlyt/SleepNowInSapphire/P1GuidanceSystem.cs similarity index 79% rename from BossMod/Modules/Shadowbringers/Quest/SleepNowInSapphire/P1GuidanceSystem.cs rename to BossMod/Modules/Shadowbringers/Quest/TheSorrowOfWerlyt/SleepNowInSapphire/P1GuidanceSystem.cs index 9395f1677e..abec4011ef 100644 --- a/BossMod/Modules/Shadowbringers/Quest/SleepNowInSapphire/P1GuidanceSystem.cs +++ b/BossMod/Modules/Shadowbringers/Quest/TheSorrowOfWerlyt/SleepNowInSapphire/P1GuidanceSystem.cs @@ -1,6 +1,6 @@ using BossMod.QuestBattle.Shadowbringers.SideQuests; -namespace BossMod.Shadowbringers.Quest.SleepNowInSapphire.P1GuidanceSystem; +namespace BossMod.Shadowbringers.Quest.SorrowOfWerlyt.SleepNowInSapphire.P1GuidanceSystem; public enum OID : uint { @@ -13,7 +13,7 @@ public enum AID : uint AerialBombardment = 21492, // 233C->location, 2.5s cast, range 12 circle } -class AerialBombardment(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.AerialBombardment), 12); +class AerialBombardment(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AerialBombardment), 12); class GWarrior(BossModule module) : QuestBattle.RotationModule(module); @@ -28,7 +28,7 @@ public GuidanceSystemStates(BossModule module) : base(module) } [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69431, NameID = 9461)] -public class GuidanceSystem(WorldState ws, Actor primary) : BossModule(ws, primary, new(-15, 610), new ArenaBoundsSquare(60, 1)) +public class GuidanceSystem(WorldState ws, Actor primary) : BossModule(ws, primary, new(-15, 610), new ArenaBoundsSquare(60)) { protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { diff --git a/BossMod/Modules/Shadowbringers/Quest/TheSorrowOfWerlyt/SleepNowInSapphire/P2SapphireWeapon.cs b/BossMod/Modules/Shadowbringers/Quest/TheSorrowOfWerlyt/SleepNowInSapphire/P2SapphireWeapon.cs new file mode 100644 index 0000000000..2f710aa131 --- /dev/null +++ b/BossMod/Modules/Shadowbringers/Quest/TheSorrowOfWerlyt/SleepNowInSapphire/P2SapphireWeapon.cs @@ -0,0 +1,70 @@ +using BossMod.Shadowbringers.Quest.SorrowOfWerlyt.SleepNowInSapphire.P1GuidanceSystem; + +namespace BossMod.Shadowbringers.Quest.SorrowOfWerlyt.SleepNowInSapphire.P2SapphireWeapon; + +public enum OID : uint +{ + Boss = 0x2DFA, + Helper = 0x233C, +} + +public enum AID : uint +{ + TailSwing = 20326, // Boss->self, 4.0s cast, range 46 circle + OptimizedJudgment = 20325, // Boss->self, 4.0s cast, range 21-60 donut + MagitekSpread = 20336, // RegulasImage->self, 5.0s cast, range 43 240-degree cone + SideraysRight = 20329, // Helper->self, 8.0s cast, range 128 90-degree cone + SideraysLeft = 21021, // Helper->self, 8.0s cast, range 128 90-degree cone + SapphireRay = 20327, // Boss->self, 8.0s cast, range 120 width 40 rect + MagitekRay = 20332, // 2DFC->self, 3.0s cast, range 100 width 6 rect + ServantRoar = 20339, // 2DFD->self, 2.5s cast, range 100 width 8 rect +} + +public enum SID : uint +{ + Invincibility = 775, // none->Boss, extra=0x0 +} + +class MagitekRay(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekRay), new AOEShapeRect(100, 3)); +class ServantRoar(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ServantRoar), new AOEShapeRect(100, 4)); +class TailSwing(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TailSwing), new AOEShapeCircle(46)); +class OptimizedJudgment(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OptimizedJudgment), new AOEShapeDonut(21, 60)); +class MagitekSpread(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekSpread), new AOEShapeCone(43, 120.Degrees())); +class SapphireRay(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SapphireRay), new AOEShapeRect(120, 20)); + +abstract class Siderays(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(128, 45.Degrees())); +class SideraysLeft(BossModule module) : Siderays(module, AID.SideraysLeft); +class SideraysRight(BossModule module) : Siderays(module, AID.SideraysRight); + +class TheSapphireWeaponStates : StateMachineBuilder +{ + public TheSapphireWeaponStates(BossModule module) : base(module) + { + TrivialPhase() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter(); + } +} + +[ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69431, NameID = 9458)] +public class TheSapphireWeapon(WorldState ws, Actor primary) : BossModule(ws, primary, new(-15, 610), new ArenaBoundsSquare(60)) +{ + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); + + protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) + { + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var h = hints.PotentialTargets[i]; + h.Priority = h.Actor.FindStatus(SID.Invincibility) == null ? 1 : 0; + } + } +} + diff --git a/BossMod/Modules/Shadowbringers/Quest/VowsOfVirtueDeedsOfCruelty.cs b/BossMod/Modules/Shadowbringers/Quest/VowsOfVirtueDeedsOfCruelty.cs deleted file mode 100644 index 180476c5a6..0000000000 --- a/BossMod/Modules/Shadowbringers/Quest/VowsOfVirtueDeedsOfCruelty.cs +++ /dev/null @@ -1,149 +0,0 @@ -<<<<<<<< HEAD:BossMod/Modules/Shadowbringers/Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs -namespace BossMod.Shadowbringers.Quest.MSQ.VowsOfVitrueDeedsOfCruelty; -======== -using BossMod.QuestBattle; - -namespace BossMod.Shadowbringers.Quest.VowsOfVirtueDeedsOfCruelty; ->>>>>>>> merge:BossMod/Modules/Shadowbringers/Quest/VowsOfVirtueDeedsOfCruelty.cs - -public enum OID : uint -{ - Boss = 0x2C85, // R6.000, x1 - TerminusEstVisual = 0x2C98, // R1.000, x3 - SigniferPraetorianus = 0x2C9A, // R0.500, x0 (spawn during fight), the adds on the catwalk that just rain down Fire II - LembusPraetorianus = 0x2C99, // R2.400, x0 (spawn during fight), two large magitek ships - MagitekBit = 0x2C9C, // R0.600, x0 (spawn during fight) - BossHelper = 0x233C -} - -public enum AID : uint -{ - LoadData = 18786, // Boss->self, 3.0s cast, single-target - AutoAttack = 870, // Boss/LembusPraetorianus->player, no cast, single-target - MagitekRayRightArm = 18783, // Boss->self, 3.2s cast, range 45+R width 8 rect - MagitekRayLeftArm = 18784, // Boss->self, 3.2s cast, range 45+R width 8 rect - SystemError = 18785, // Boss->self, 1.0s cast, single-target - AngrySalamander = 18787, // Boss->self, 3.0s cast, range 40+R width 6 rect - FireII = 18959, // SigniferPraetorianus->location, 3.0s cast, range 5 circle - TerminusEstBossCast = 18788, // Boss->self, 3.0s cast, single-target - TerminusEstLocationHelper = 18889, // BossHelper->self, 4.0s cast, range 3 circle - TerminusEstVisual = 18789, // TerminusEstVisual->self, 1.0s cast, range 40+R width 4 rect - HorridRoar = 18779, // 2CC5->location, 2.0s cast, range 6 circle, this is your own attack. It spawns an aoe at the location of any enemy it initally hits - GarleanFire = 4007, // LembusPraetorianus->location, 3.0s cast, range 5 circle - MagitekBit = 18790, // Boss->self, no cast, single-target - MetalCutterCast = 18793, // Boss->self, 6.0s cast, single-target - MetalCutter = 18794, // BossHelper->self, 6.0s cast, range 30+R 20-degree cone - AtomicRayCast = 18795, // Boss->self, 6.0s cast, single-target - AtomicRay = 18796, // BossHelper->location, 6.0s cast, range 10 circle - MagitekRayBit = 18791, // MagitekBit->self, 6.0s cast, range 50+R width 2 rect - SelfDetonate = 18792, // MagitekBit->self, 7.0s cast, range 40+R circle, enrage if bits are not killed before cast -} - -abstract class MagitekRay(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(45, 4)); -class MagitekRayRightArm(BossModule module) : MagitekRay(module, AID.MagitekRayRightArm); -class MagitekRayLeftArm(BossModule module) : MagitekRay(module, AID.MagitekRayLeftArm); - -class AngrySalamander(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AngrySalamander), new AOEShapeRect(40, 3)); -class TerminusEstRects(BossModule module) : Components.GenericAOEs(module) -{ - private readonly List _aoes = []; - private static readonly AOEShapeRect _shape = new(40, 2); - public override IEnumerable ActiveAOEs(int slot, Actor actor) => _aoes; - - public override void OnCastStarted(Actor caster, ActorCastInfo spell) - { - if ((AID)spell.Action.ID == AID.TerminusEstLocationHelper) - { - _aoes.AddRange( - [ - new(_shape, spell.LocXZ, spell.Rotation, Module.CastFinishAt(spell)), - new(_shape, spell.LocXZ, spell.Rotation - 90.Degrees(), Module.CastFinishAt(spell)), - new(_shape, spell.LocXZ, spell.Rotation + 90.Degrees(), Module.CastFinishAt(spell)) - ]); - } - } - - public override void OnEventCast(Actor caster, ActorCastEvent spell) - { - if ((AID)spell.Action.ID == AID.TerminusEstVisual) - { - _aoes.Clear(); - ++NumCasts; - } - } -} -class TerminusEstCircle(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TerminusEstLocationHelper), 3); -class FireII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FireII), 5); -class GarleanFire(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.GarleanFire), 5); -class MetalCutter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MetalCutter), new AOEShapeCone(30, 10.Degrees())); -class MagitekRayBits(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekRayBit), new AOEShapeRect(50, 1)); -class AtomicRay(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AtomicRay), 10); -class SelfDetonate(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.SelfDetonate), "Enrage if bits are not killed before cast"); - -class EstinienAI(WorldState ws) : UnmanagedRotation(ws, 3) -{ - protected override void Exec(Actor? primaryTarget) - { - if (primaryTarget == null) - return; - - if (Hints.PotentialTargets.Any(x => (OID)x.Actor.OID is OID.SigniferPraetorianus or OID.MagitekBit)) - UseAction(Roleplay.AID.HorridRoar, Player); - - if (World.Party.LimitBreakCur == 10000) - UseAction(Roleplay.AID.DragonshadowDive, primaryTarget, 100); - - if (primaryTarget.OID == (uint)OID.Boss) - { - var dotRemaining = StatusDetails(primaryTarget, Roleplay.SID.StabWound, Player.InstanceID).Left; - if (dotRemaining < 2.3f) - UseAction(Roleplay.AID.Drachenlance, primaryTarget); - } - - UseAction(Roleplay.AID.AlaMorn, primaryTarget); - UseAction(Roleplay.AID.Stardiver, primaryTarget, -10); - } -} - -class AutoEstinien(BossModule module) : RotationModule(module); - -class ArchUltimaStates : StateMachineBuilder -{ - public ArchUltimaStates(BossModule module) : base(module) - { - TrivialPhase() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter(); - } -} - -[ModuleInfo(BossModuleInfo.Maturity.Contributed, Contributors = "croizat", GroupType = BossModuleInfo.GroupType.Quest, GroupID = 69218, NameID = 9189)] -<<<<<<<< HEAD:BossMod/Modules/Shadowbringers/Quest/MSQ/VowsOfVitrueDeedsOfCruelty.cs -public class VowsOfVirtueDeedsOfCruelty(WorldState ws, Actor primary) : BossModule(ws, primary, new(240, 230), new ArenaBoundsSquare(19.5f)); -======== -public class ArchUltima(WorldState ws, Actor primary) : BossModule(ws, primary, new(240, 230), new ArenaBoundsSquare(20)) -{ - protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) - { - foreach (var h in hints.PotentialTargets) - h.Priority = (OID)h.Actor.OID switch - { - OID.MagitekBit => 2, - OID.LembusPraetorianus => 1, - _ => 0 - }; - } - - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); -} ->>>>>>>> merge:BossMod/Modules/Shadowbringers/Quest/VowsOfVirtueDeedsOfCruelty.cs diff --git a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKeeper.cs b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKeeper.cs index 41099a1090..aedd4cb489 100644 --- a/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKeeper.cs +++ b/BossMod/Modules/Shadowbringers/TreasureHunt/TheShiftingOubliettesOfLyheGhiah/SecretKeeper.cs @@ -31,7 +31,7 @@ public enum AID : uint class InhalePull(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.InhaleBoss), 20, false, 1, new AOEShapeCone(20, 60.Degrees()), Kind.TowardsOrigin, default, true); class HeavyScrapline(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HeavyScrapline), 11); class MoldyPhlegm(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 6, ActionID.MakeSpell(AID.MoldyPhlegm), m => m.Enemies(OID.ResinVoidzone).Where(z => z.EventState != 7), 1.4f); -class MoldySneeze(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.MoldySneeze), new AOEShapeCone(12, 60.Degrees()), (uint)OID.Boss); +class MoldySneeze(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.MoldySneeze), new AOEShapeCone(12, 60.Degrees())); class Spin(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Spin), 11); class Mash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Mash), new AOEShapeRect(13, 2)); diff --git a/BossMod/Modules/Shadowbringers/Ultimate/TEA/TEA.cs b/BossMod/Modules/Shadowbringers/Ultimate/TEA/TEA.cs index 180f29f353..295bae529a 100644 --- a/BossMod/Modules/Shadowbringers/Ultimate/TEA/TEA.cs +++ b/BossMod/Modules/Shadowbringers/Ultimate/TEA/TEA.cs @@ -1,7 +1,7 @@ namespace BossMod.Shadowbringers.Ultimate.TEA; class P1FluidSwing(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.FluidSwing), new AOEShapeCone(11.5f, 45.Degrees())); -class P1FluidStrike(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.FluidStrike), new AOEShapeCone(11.6f, 45.Degrees()), (uint)OID.LiquidHand); +class P1FluidStrike(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.FluidStrike), new AOEShapeCone(11.6f, 45.Degrees()), [(uint)OID.LiquidHand]); class P1Sluice(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Sluice), 5); class P1Splash(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.Splash)); class P1Drainage(BossModule module) : Components.TankbusterTether(module, ActionID.MakeSpell(AID.DrainageP1), (uint)TetherID.Drainage, 6); @@ -19,7 +19,7 @@ class P2PropellerWind(BossModule module) : Components.CastLineOfSightAOE(module, class P2DoubleRocketPunch(BossModule module) : Components.CastSharedTankbuster(module, ActionID.MakeSpell(AID.DoubleRocketPunch), 3); class P3ChasteningHeat(BossModule module) : Components.BaitAwayCast(module, ActionID.MakeSpell(AID.ChasteningHeat), new AOEShapeCircle(5), true); -class P3DivineSpear(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.DivineSpear), new AOEShapeCone(24.2f, 45.Degrees()), (uint)OID.AlexanderPrime); // TODO: verify angle +class P3DivineSpear(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.DivineSpear), new AOEShapeCone(24.2f, 45.Degrees()), [(uint)OID.AlexanderPrime]); // TODO: verify angle class P3DivineJudgmentRaidwide(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.DivineJudgmentRaidwide)); [ModuleInfo(BossModuleInfo.Maturity.Verified, PrimaryActorOID = (uint)OID.BossP1, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 694, PlanLevel = 80)] diff --git a/BossMod/Modules/Stormblood/Foray/BaldesionsArsenal/BA1Owain/IvoryPalm.cs b/BossMod/Modules/Stormblood/Foray/BaldesionsArsenal/BA1Owain/IvoryPalm.cs index 3b128df505..93ff16ea4d 100644 --- a/BossMod/Modules/Stormblood/Foray/BaldesionsArsenal/BA1Owain/IvoryPalm.cs +++ b/BossMod/Modules/Stormblood/Foray/BaldesionsArsenal/BA1Owain/IvoryPalm.cs @@ -46,7 +46,7 @@ public override void OnUntethered(Actor source, ActorTetherInfo tether) class IvoryPalmExplosion(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.Explosion), "Ivory Palm is enraging!", true); -class EurekanAero(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.EurekanAero), new AOEShapeCone(6, 60.Degrees()), (uint)OID.IvoryPalm) +class EurekanAero(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.EurekanAero), new AOEShapeCone(6, 60.Degrees()), [(uint)OID.IvoryPalm]) { public override List<(Actor origin, Actor target, Angle angle)> OriginsAndTargets() { diff --git a/BossMod/Modules/Stormblood/Quest/TheOrphansAndTheBrokenBlade.cs b/BossMod/Modules/Stormblood/Quest/Job/DarkKnight/TheOrphansAndTheBrokenBlade.cs similarity index 77% rename from BossMod/Modules/Stormblood/Quest/TheOrphansAndTheBrokenBlade.cs rename to BossMod/Modules/Stormblood/Quest/Job/DarkKnight/TheOrphansAndTheBrokenBlade.cs index 0bc2115ab8..96a5b4ec54 100644 --- a/BossMod/Modules/Stormblood/Quest/TheOrphansAndTheBrokenBlade.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/DarkKnight/TheOrphansAndTheBrokenBlade.cs @@ -1,9 +1,9 @@ -namespace BossMod.Stormblood.Quest.TheOrphansAndTheBrokenBlade; +namespace BossMod.Stormblood.Quest.Job.DarkKnight.TheOrphansAndTheBrokenBlade; public enum OID : uint { Boss = 0x1C5E, - Helper = 0x233C, + Helper = 0x233C } public enum AID : uint @@ -11,10 +11,10 @@ public enum AID : uint ShadowOfDeath1 = 8459, // 1C5F->location, 3.0s cast, range 5 circle HeadsmansDelight = 8457, // Boss->1C5C, 5.0s cast, range 5 circle SpiralHell = 8453, // 1C5F->self, 3.0s cast, range 40+R width 4 rect - HeadmansDelight = 9298, // 1C5F->player/1C5C, no cast, single-target + HeadmansDelight = 9298 // 1C5F->player/1C5C, no cast, single-target } -class SpiralHell(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SpiralHell), new AOEShapeRect(40, 2)); +class SpiralHell(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpiralHell), new AOEShapeRect(40, 2)); class HeadsmansDelight(BossModule module) : Components.GenericStackSpread(module) { public override void OnCastStarted(Actor caster, ActorCastInfo spell) @@ -29,7 +29,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) Stacks.Clear(); } } -class ShadowOfDeath(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.ShadowOfDeath1), 5); +class ShadowOfDeath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ShadowOfDeath1), 5); class DarkChain(BossModule module) : Components.Adds(module, 0x1C60) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) @@ -53,5 +53,5 @@ public OmpagneDeepblackStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68453, NameID = 6300)] public class OmpagneDeepblack(WorldState ws, Actor primary) : BossModule(ws, primary, new(-166.8f, 290), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Stormblood/Quest/DragonSound.cs b/BossMod/Modules/Stormblood/Quest/Job/Dragoon/DragonSound.cs similarity index 86% rename from BossMod/Modules/Stormblood/Quest/DragonSound.cs rename to BossMod/Modules/Stormblood/Quest/Job/Dragoon/DragonSound.cs index 80b77ec816..e26f12d59c 100644 --- a/BossMod/Modules/Stormblood/Quest/DragonSound.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/Dragoon/DragonSound.cs @@ -1,4 +1,4 @@ -namespace BossMod.Stormblood.Quest.DragonSound; +namespace BossMod.Stormblood.Quest.Job.Dragoon.DragonSound; public enum OID : uint { @@ -18,8 +18,8 @@ public enum SID : uint Enervation = 1401, // Boss->1CDE/player, extra=0x0 } -class AbyssicBuster(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AbyssicBuster), new AOEShapeCone(31.84f, 45.Degrees())); -class Heavensfall(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Heavensfall1), 5); +class AbyssicBuster(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AbyssicBuster), new AOEShapeCone(31.84f, 45.Degrees())); +class Heavensfall(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Heavensfall1), 5); class DarkStar(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.DarkStar)); // scripted interaction, no idea if it's required to complete the duty but might as well do it diff --git a/BossMod/Modules/Stormblood/Quest/ThePowerToProtect.cs b/BossMod/Modules/Stormblood/Quest/Job/Monk/ThePowerToProtect.cs similarity index 79% rename from BossMod/Modules/Stormblood/Quest/ThePowerToProtect.cs rename to BossMod/Modules/Stormblood/Quest/Job/Monk/ThePowerToProtect.cs index ce71d1b239..4045d102e9 100644 --- a/BossMod/Modules/Stormblood/Quest/ThePowerToProtect.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/Monk/ThePowerToProtect.cs @@ -1,4 +1,4 @@ -namespace BossMod.Stormblood.Quest.ThePowerToProtect; +namespace BossMod.Stormblood.Quest.Job.Monk.ThePowerToProtect; public enum OID : uint { @@ -26,7 +26,7 @@ public enum AID : uint public enum SID : uint { - ExtremeCaution = 1269, // Boss->player, extra=0x0 + ExtremeCaution = 1269 // Boss->player, extra=0x0 } @@ -44,11 +44,11 @@ public override void OnStatusLose(Actor actor, ActorStatus status) PlayerStates[slot] = default; } } -class IronTempest(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.IronTempest), new AOEShapeCircle(5.5f)); +class IronTempest(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.IronTempest), 5.5f); class FireII(BossModule module) : Components.PersistentVoidzoneAtCastTarget(module, 5, ActionID.MakeSpell(AID.FireII), m => m.Enemies(OID.FireII).Where(x => x.EventState != 7), 0); -class Overpower(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(6.5f, 45.Degrees())); -class Rive(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Rive), new AOEShapeRect(30.5f, 1)); -class DiffractiveLaser(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.DiffractiveLaser), 5); +class Overpower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Overpower), new AOEShapeCone(6.5f, 45.Degrees())); +class Rive(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Rive), new AOEShapeRect(30.5f, 1)); +class DiffractiveLaser(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DiffractiveLaser), 5); class IoStates : StateMachineBuilder { @@ -72,6 +72,6 @@ public class Io(WorldState ws, Actor primary) : BossModule(ws, primary, ArenaCen public static readonly ArenaBoundsCustom B = new(25, new(Corners.Select(c => c - ArenaCenter))); - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Stormblood/Quest/RaisingTheSword.cs b/BossMod/Modules/Stormblood/Quest/Job/Paladin/RaisingTheSword.cs similarity index 80% rename from BossMod/Modules/Stormblood/Quest/RaisingTheSword.cs rename to BossMod/Modules/Stormblood/Quest/Job/Paladin/RaisingTheSword.cs index 06db3c281d..74ff8dcf10 100644 --- a/BossMod/Modules/Stormblood/Quest/RaisingTheSword.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/Paladin/RaisingTheSword.cs @@ -1,11 +1,11 @@ -namespace BossMod.Stormblood.Quest.RaisingTheSword; +namespace BossMod.Stormblood.Quest.Job.Paladin.RaisingTheSword; public enum OID : uint { Boss = 0x1B51, - Helper = 0x233C, - AldisSwordOfNald = 0x18D6, // R0.500, x10 - TaintedWindSprite = 0x1B52, // R1.000, x0 (spawn during fight) + AldisSwordOfNald = 0x18D6, // R0.5 + TaintedWindSprite = 0x1B52, // R1.0 + Helper = 0x233C } public enum AID : uint @@ -16,8 +16,8 @@ public enum AID : uint VictorySlash = 8134, // Boss->self, 3.0s cast, range 6+R 120-degree cone } -class VictorySlash(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.VictorySlash), new AOEShapeCone(6.5f, 60.Degrees())); -class ShudderingSwipeCone(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ShudderingSwipeAOE), new AOEShapeCone(60, 15.Degrees())); +class VictorySlash(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.VictorySlash), new AOEShapeCone(6.5f, 60.Degrees())); +class ShudderingSwipeCone(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ShudderingSwipeAOE), new AOEShapeCone(60, 15.Degrees())); class ShudderingSwipeKB(BossModule module) : Components.Knockback(module, ActionID.MakeSpell(AID.ShudderingSwipeCast), stopAtWall: true) { private TheFourWinds? winds; @@ -55,7 +55,7 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme }, Module.CastFinishAt(c.CastInfo)); } } -class NaldsWhisper(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NaldsWhisper), new AOEShapeCircle(20)); +class NaldsWhisper(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.NaldsWhisper), 20); class TheFourWinds(BossModule module) : Components.PersistentVoidzone(module, 6, m => m.Enemies(OID.TaintedWindSprite).Where(x => x.EventState != 7)); class AldisSwordOfNaldStates : StateMachineBuilder diff --git a/BossMod/Modules/Stormblood/Quest/BloodOnTheDeck.cs b/BossMod/Modules/Stormblood/Quest/Job/Samurai/BloodOnTheDeck.cs similarity index 52% rename from BossMod/Modules/Stormblood/Quest/BloodOnTheDeck.cs rename to BossMod/Modules/Stormblood/Quest/Job/Samurai/BloodOnTheDeck.cs index e78d012603..2be0e90c0b 100644 --- a/BossMod/Modules/Stormblood/Quest/BloodOnTheDeck.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/Samurai/BloodOnTheDeck.cs @@ -1,12 +1,13 @@ -namespace BossMod.Stormblood.Quest; +namespace BossMod.Stormblood.Quest.Job.BloodOnTheDeck; + public enum OID : uint { Boss = 0x1BED, - Helper = 0x233C, - ShamShinobi = 0x1BE8, // R0.500, x4 (spawn during fight) - AdjunctOstyrgreinHelper = 0x1BEB, // R0.500, x0 (spawn during fight), Helper type - AdjunctOstyrgrein = 0x1BEA, // R0.500, x0 (spawn during fight) - Vanara = 0x1BE9, // R3.000, x0 (spawn during fight) + ShamShinobi = 0x1BE8, // R0.5 + AdjunctOstyrgreinHelper = 0x1BEB, // R0.5 + AdjunctOstyrgrein = 0x1BEA, // R0.5 + Vanara = 0x1BE9, // R3.0 + Helper = 0x233C } public enum AID : uint @@ -17,10 +18,10 @@ public enum AID : uint Bombslinger1 = 8411, // AdjunctOstyrgreinHelper->location, 3.0s cast, range 6 circle } -class ScytheTail(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ScytheTail), new AOEShapeCircle(7)); -class Butcher(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Butcher), new AOEShapeCone(9, 45.Degrees())); -class TenkaGoken(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TenkaGoken), new AOEShapeCone(8.5f, 60.Degrees())); -class Bombslinger(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Bombslinger1), 6); +class ScytheTail(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ScytheTail), 7); +class Butcher(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Butcher), new AOEShapeCone(9, 45.Degrees())); +class TenkaGoken(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TenkaGoken), new AOEShapeCone(8.5f, 60.Degrees())); +class Bombslinger(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Bombslinger1), 6); class GurumiBorlumiStates : StateMachineBuilder { @@ -37,6 +38,6 @@ public GurumiBorlumiStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68098, NameID = 6289)] public class GurumiBorlumi(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, 15.8f), new ArenaBoundsRect(8, 7.5f)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Stormblood/Quest/TheBattleOnBekko.cs b/BossMod/Modules/Stormblood/Quest/Job/Samurai/TheBattleOnBekko.cs similarity index 53% rename from BossMod/Modules/Stormblood/Quest/TheBattleOnBekko.cs rename to BossMod/Modules/Stormblood/Quest/Job/Samurai/TheBattleOnBekko.cs index a25f292749..d202409d0d 100644 --- a/BossMod/Modules/Stormblood/Quest/TheBattleOnBekko.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/Samurai/TheBattleOnBekko.cs @@ -1,11 +1,11 @@ -namespace BossMod.Stormblood.Quest.TheBattleOnBekko; +namespace BossMod.Stormblood.Quest.Job.Samurai.TheBattleOnBekko; public enum OID : uint { Boss = 0x1BF8, - Helper = 0x233C, - UgetsuSlayerOfAThousandSouls = 0x1BF9, // R0.500, x20, Helper type - Voidzone = 0x1E8EA9, // R1.000, x0 (spawn during fight) + UgetsuSlayerOfAThousandSouls = 0x1BF9, // R0.5 + Voidzone = 0x1E8EA9, // R1.0 + Helper = 0x233C } public enum AID : uint @@ -14,42 +14,45 @@ public enum AID : uint TenkaGoken = 9145, // Boss->self, 3.0s cast, range 8+R 120-degree cone ShinGetsubaku = 8437, // 1BF9->location, 3.0s cast, range 6 circle MijinGiri = 8435, // 1BF9->self, 2.5s cast, range 80+R width 10 rect - Ugetsuzan = 8439, // 1BF9->self, 2.5s cast, range -7 donut - Ugetsuzan2 = 8440, // 1BF9->self, 2.5s cast, range -12 donut - Ugetsuzan3 = 8441, // 1BF9->self, 2.5s cast, range -17 donut + Ugetsuzan1 = 8439, // 1BF9->self, 2.5s cast, range 2-7 180-degree donut sector + Ugetsuzan2 = 8440, // 1BF9->self, 2.5s cast, range 7-12 180-degree donut sector + Ugetsuzan3 = 8441, // 1BF9->self, 2.5s cast, range 12-17 180-degree donut sector + Ugetsuzan4 = 8442, // UgetsuSlayerOfAThousandSouls->self, 2.5s cast, range 17-22 180-degree donut sector KuruiYukikaze = 8446, // UgetsuSlayerOfAThousandSouls->self, 2.5s cast, range 44+R width 4 rect KuruiGekko1 = 8447, // UgetsuSlayerOfAThousandSouls->self, 2.0s cast, range 30 circle KuruiKasha1 = 8448, // UgetsuSlayerOfAThousandSouls->self, 2.5s cast, range 8+R ?-degree cone - Ugetsuzan4 = 8442, // UgetsuSlayerOfAThousandSouls->self, 2.5s cast, range -22 donut } class KuruiGekko(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.KuruiGekko1)); -class KuruiKasha(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.KuruiKasha1), new AOEShapeDonutSector(4.5f, 8.5f, 45.Degrees())); -class KuruiYukikaze(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.KuruiYukikaze), new AOEShapeRect(44, 2), 8); -class HissatsuKyuten(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HissatsuKyuten), new AOEShapeCircle(5.5f)); -class TenkaGoken(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TenkaGoken), new AOEShapeCone(8.5f, 60.Degrees())); -class ShinGetsubaku(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.ShinGetsubaku), 6); +class KuruiKasha(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.KuruiKasha1), new AOEShapeDonutSector(4.5f, 8.5f, 45.Degrees())); +class KuruiYukikaze(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.KuruiYukikaze), new AOEShapeRect(44, 2), 8); +class HissatsuKyuten(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HissatsuKyuten), 5.5f); +class TenkaGoken(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TenkaGoken), new AOEShapeCone(8.5f, 60.Degrees())); +class ShinGetsubaku(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ShinGetsubaku), 6); class ShinGetsubakuVoidzone(BossModule module) : Components.PersistentVoidzone(module, 4, m => m.Enemies(OID.Voidzone).Where(e => e.EventState != 7)); -class MijinGiri(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MijinGiri), new AOEShapeRect(80, 5, 2)); -class Ugetsuzan(BossModule module) : Components.ConcentricAOEs(module, [new AOEShapeDonutSector(2, 7, 90.Degrees()), new AOEShapeDonutSector(7, 12, 90.Degrees()), new AOEShapeDonutSector(12, 17, 90.Degrees())]) +class MijinGiri(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MijinGiri), new AOEShapeRect(80.5f, 5)); + +class Ugetsuzan(BossModule module) : Components.ConcentricAOEs(module, sectors) { + private static readonly Angle a90 = 90.Degrees(); + private static readonly AOEShapeDonutSector[] sectors = [new(2, 7, a90), new(7, 12, a90), new(12, 17, a90), new(17, 22, a90)]; public override void OnCastStarted(Actor caster, ActorCastInfo spell) { - if (spell.Action.ID == (uint)AID.Ugetsuzan) - AddSequence(caster.Position - caster.Rotation.ToDirection() * 4, Module.CastFinishAt(spell), caster.Rotation); + if ((AID)spell.Action.ID == AID.Ugetsuzan1) + AddSequence(spell.LocXZ, Module.CastFinishAt(spell), spell.Rotation); } - public override void OnEventCast(Actor caster, ActorCastEvent spell) + public override void OnCastFinished(Actor caster, ActorCastInfo spell) { - var idx = (AID)spell.Action.ID switch + var order = (AID)spell.Action.ID switch { - AID.Ugetsuzan => 0, + AID.Ugetsuzan1 => 0, AID.Ugetsuzan2 => 1, AID.Ugetsuzan3 => 2, AID.Ugetsuzan4 => 3, _ => -1 }; - AdvanceSequence(idx, caster.Position - caster.Rotation.ToDirection() * 4, WorldState.FutureTime(2.5f), caster.Rotation); + AdvanceSequence(order, spell.LocXZ, WorldState.FutureTime(2.5f), spell.Rotation); } } diff --git a/BossMod/Modules/Stormblood/Quest/TheFaceOfTrueEvil.cs b/BossMod/Modules/Stormblood/Quest/Job/Samurai/TheFaceOfTrueEvil.cs similarity index 59% rename from BossMod/Modules/Stormblood/Quest/TheFaceOfTrueEvil.cs rename to BossMod/Modules/Stormblood/Quest/Job/Samurai/TheFaceOfTrueEvil.cs index 49774827d1..13abdf0986 100644 --- a/BossMod/Modules/Stormblood/Quest/TheFaceOfTrueEvil.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/Samurai/TheFaceOfTrueEvil.cs @@ -1,32 +1,35 @@ -namespace BossMod.Stormblood.Quest.TheFaceOfTrueEvil; +namespace BossMod.Stormblood.Quest.Job.Samurai.TheFaceOfTrueEvil; public enum OID : uint { Boss = 0x1BEE, - Helper = 0x233C, - Musosai = 0x1BEF, // R0.500, x12, Helper type - Musosai1 = 0x1BF0, // R1.000, x0 (spawn during fight) - ViolentWind = 0x1BF1, // R1.000, x0 (spawn during fight) + Musosai = 0x1BF0, // R1.0 + ViolentWind = 0x1BF1, // R1.0 + Helper2 = 0x1BEF, + Helper = 0x233C } public enum AID : uint { - HissatsuTo1 = 8415, // 1BEF->self, 3.0s cast, range 44+R width 4 rect + HissatsuTo = 8415, // 1BEF->self, 3.0s cast, range 44+R width 4 rect HissatsuKyuten = 8412, // Boss->self, 3.0s cast, range 5+R circle - Arashi = 8418, // Boss->self, 4.0s cast, single-target - Arashi1 = 8419, // 1BF0->self, no cast, range 4 circle + ArashiVisual = 8418, // Boss->self, 4.0s cast, single-target + Arashi = 8419, // 1BF0->self, no cast, range 4 circle HissatsuKiku1 = 8417, // Musosai->self, 4.0s cast, range 44+R width 4 rect - Maiogi1 = 8421, // Musosai->self, 4.0s cast, range 80+R ?-degree cone + Maiogi = 8421, // Musosai->self, 4.0s cast, range 80+R ?-degree cone Musojin = 8422, // Boss->self, 25.0s cast, single-target ArashiNoKiku = 8643, // Boss->self, 3.0s cast, single-target ArashiNoMaiogi = 8642, // Boss->self, 3.0s cast, single-target } class Musojin(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Musojin)); -class HissatsuKiku(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HissatsuKiku1), new AOEShapeRect(44.5f, 2)); -class Maiogi(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Maiogi1), new AOEShapeCone(80, 25.Degrees())); -class HissatsuTo(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HissatsuTo1), new AOEShapeRect(44.5f, 2)); -class HissatsuKyuten(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HissatsuKyuten), new AOEShapeCircle(5.5f)); + +abstract class Hissatsu(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(44.5f, 2)); +class HissatsuKiku(BossModule module) : Hissatsu(module, AID.HissatsuKiku1); +class HissatsuTo(BossModule module) : Hissatsu(module, AID.HissatsuTo); + +class Maiogi(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Maiogi), new AOEShapeCone(80, 25.Degrees())); +class HissatsuKyuten(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HissatsuKyuten), 5.5f); class Arashi(BossModule module) : Components.GenericAOEs(module) { private DateTime? Activation; @@ -36,8 +39,8 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) if (Activation == null) yield break; - foreach (var e in Module.Enemies(OID.Musosai1)) - yield return new AOEInstance(new AOEShapeCircle(4), e.Position, default, Activation.Value); + foreach (var e in Module.Enemies(OID.Musosai)) + yield return new(new AOEShapeCircle(4), e.Position, default, Activation.Value); } public override void OnCastStarted(Actor caster, ActorCastInfo spell) @@ -48,7 +51,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void OnEventCast(Actor caster, ActorCastEvent spell) { - if (spell.Action.ID == (uint)AID.Arashi1) + if ((AID)spell.Action.ID == AID.Arashi) Activation = null; } } @@ -71,4 +74,3 @@ public MusosaiStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68101, NameID = 6111)] public class Musosai(WorldState ws, Actor primary) : BossModule(ws, primary, new(-217.27f, -158.31f), new ArenaBoundsSquare(15)); - diff --git a/BossMod/Modules/Stormblood/Quest/OurUnsungHeroes.cs b/BossMod/Modules/Stormblood/Quest/Job/Scholar/OurUnsungHeroes.cs similarity index 68% rename from BossMod/Modules/Stormblood/Quest/OurUnsungHeroes.cs rename to BossMod/Modules/Stormblood/Quest/Job/Scholar/OurUnsungHeroes.cs index 23fff69301..044d7750a3 100644 --- a/BossMod/Modules/Stormblood/Quest/OurUnsungHeroes.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/Scholar/OurUnsungHeroes.cs @@ -1,4 +1,4 @@ -namespace BossMod.Stormblood.Quest.OurUnsungHeroes; +namespace BossMod.Stormblood.Quest.Jobs.Scholar.OurUnsungHeroes; public enum OID : uint { @@ -13,25 +13,25 @@ public enum AID : uint CureIV = 8635, // Boss->self, 5.0s cast, range 40 circle CureIII1 = 8636, // FallenKuribu->players/1CAD/1CAE, no cast, range 10 circle CureV1 = 8637, // FallenKuribu->players, no cast, range 6 circle - DarkII = 4366, // ShadowSprite->self, 2.5s cast, range 50+R 60-degree cone + DarkII = 4366 // ShadowSprite->self, 2.5s cast, range 50+R 60-degree cone } public enum IconID : uint { CureIII = 71, // player/1CAD/1CAE - Stack = 62, // player + Stack = 62 // player } public enum SID : uint { - Invincibility = 325, // Boss->Boss, extra=0x0 + Invincibility = 325 // Boss->Boss, extra=0x0 } -class CureIV(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CureIV), new AOEShapeCircle(12)); -class Glory(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Glory), new AOEShapeCone(42.7f, 45.Degrees())); +class CureIV(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CureIV), 12); +class Glory(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Glory), new AOEShapeCone(42.7f, 45.Degrees())); class CureIII(BossModule module) : Components.SpreadFromIcon(module, (uint)IconID.CureIII, ActionID.MakeSpell(AID.CureIII1), 10, 5.15f); class CureV(BossModule module) : Components.StackWithIcon(module, (uint)IconID.Stack, ActionID.MakeSpell(AID.CureV1), 6, 5.15f); -class DarkII(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DarkII), new AOEShapeCone(50.8f, 30.Degrees())); +class DarkII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DarkII), new AOEShapeCone(50.8f, 30.Degrees())); class FallenKuribuStates : StateMachineBuilder { @@ -51,7 +51,10 @@ public FallenKuribuStates(BossModule module) : base(module) { protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var h in hints.PotentialTargets) - h.Priority = h.Actor.FindStatus(SID.Invincibility) == null ? 1 : 0; + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var h = hints.PotentialTargets[i]; + h.Priority = h.Actor.FindStatus(SID.Invincibility) == null ? 1 : AIHints.Enemy.PriorityInvincible; + } } } diff --git a/BossMod/Modules/Stormblood/Quest/AnArtForTheLiving.cs b/BossMod/Modules/Stormblood/Quest/Job/Summoner/AnArtForTheLiving.cs similarity index 69% rename from BossMod/Modules/Stormblood/Quest/AnArtForTheLiving.cs rename to BossMod/Modules/Stormblood/Quest/Job/Summoner/AnArtForTheLiving.cs index a050938ed8..4a8821290f 100644 --- a/BossMod/Modules/Stormblood/Quest/AnArtForTheLiving.cs +++ b/BossMod/Modules/Stormblood/Quest/Job/Summoner/AnArtForTheLiving.cs @@ -1,11 +1,11 @@ -namespace BossMod.Stormblood.Quest.AnArtForTheLiving; +namespace BossMod.Stormblood.Quest.Job.Summoner.AnArtForTheLiving; public enum OID : uint { Boss = 0x1CBA, - Helper = 0x233C, - ExplosiveIndicator = 0x1CD7, // R0.500, x0 (spawn during fight) - AetherochemicalExplosive = 0x1CD5, // R1.000, x1 (spawn during fight) + ExplosiveIndicator = 0x1CD7, // R0.5 + AetherochemicalExplosive = 0x1CD5, // R1.0 + Helper = 0x233C } public enum AID : uint @@ -15,7 +15,7 @@ public enum AID : uint NerveGasLeft = 8708, // FX1979->self, 3.0s cast, range 30+R 180-degree cone NerveGasRight = 8709, // 1CD8->self, 3.0s cast, range 30+R 180-degree cone W111TonzeSwing = 8697, // 1CD1->self, 4.0s cast, range 8+R circle - W11TonzeSwipe = 8699, // 1CD1->self, 3.0s cast, range 5+R ?-degree cone + W11TonzeSwipe = 8699, // 1CD1->self, 3.0s cast, range 5+R 120-degree cone } public enum SID : uint @@ -23,14 +23,16 @@ public enum SID : uint Invincibility = 325 } -class OneOneOneTonzeSwing(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.W111TonzeSwing), new AOEShapeCircle(12)); -class OneOneTonzeSwipe(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.W11TonzeSwipe), new AOEShapeCone(9, 45.Degrees())); // may be the wrong angle +class OneOneOneTonzeSwing(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.W111TonzeSwing), 12); +class OneOneTonzeSwipe(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.W11TonzeSwipe), new AOEShapeCone(9, 60.Degrees())); -class NerveGas1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NerveGas), new AOEShapeCone(35, 60.Degrees())); -class NerveGas2(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NerveGasRight), new AOEShapeCone(35, 90.Degrees())); -class NerveGas3(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.NerveGasLeft), new AOEShapeCone(35, 90.Degrees())); +class NerveGas1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.NerveGas), new AOEShapeCone(35, 60.Degrees())); -class PiercingLaser(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.PiercingLaser), new AOEShapeRect(33.68f, 3)); +abstract class NerveGasLR(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeCone(35, 90.Degrees())); +class NerveGasRight(BossModule module) : NerveGasLR(module, AID.NerveGasRight); +class NerveGasLeft(BossModule module) : NerveGasLR(module, AID.NerveGasLeft); + +class PiercingLaser(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PiercingLaser), new AOEShapeRect(33.68f, 3)); class AetherochemicalExplosive(BossModule module) : Components.GenericAOEs(module) { @@ -66,8 +68,11 @@ class Adds(BossModule module) : Components.AddsMulti(module, [0x1CB6, 0x1CD1, 0x { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) - e.Priority = e.Actor.FindStatus(SID.Invincibility) == null ? 1 : 0; + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var e = hints.PotentialTargets[i]; + e.Priority = e.Actor.FindStatus(SID.Invincibility) == null ? 1 : AIHints.Enemy.PriorityInvincible; + } } } @@ -79,12 +84,11 @@ public SummoningNodeStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - .ActivateOnEnter() + .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } diff --git a/BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/Enums.cs b/BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/Enums.cs similarity index 77% rename from BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/Enums.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/Enums.cs index 3b69ab9773..234c77dc13 100644 --- a/BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/Enums.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/Enums.cs @@ -1,14 +1,15 @@ -namespace BossMod.Stormblood.Quest.ARequiemForHeroes; +namespace BossMod.Stormblood.Quest.MSQ.ARequiemForHeroes; public enum OID : uint { BossP1 = 0x268A, BossP2 = 0x268C, - Helper = 0x233C, - AmeNoHabakiri = 0x2692, // R3.000, x0 (spawn during fight) - TheStorm = 0x2760, // R3.000, x0 (spawn during fight) - TheSwell = 0x275F, // R3.000, x0 (spawn during fight) - DarkAether = 0x2694, // R1.200, x0 (spawn during fight) + + AmeNoHabakiri = 0x2692, // R3.0 + TheStorm = 0x2760, // R3.0 + TheSwell = 0x275F, // R3.0 + DarkAether = 0x2694, // R1.2 + Helper = 0x233C } public enum AID : uint diff --git a/BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/P1.cs b/BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/P1.cs similarity index 96% rename from BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/P1.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/P1.cs index 52ef8c972b..49d6ec1de6 100644 --- a/BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/P1.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/P1.cs @@ -1,6 +1,6 @@ using BossMod.QuestBattle; -namespace BossMod.Stormblood.Quest.ARequiemForHeroes; +namespace BossMod.Stormblood.Quest.MSQ.ARequiemForHeroes; class AutoHien(WorldState ws) : UnmanagedRotation(ws, 3) { diff --git a/BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/P2.cs b/BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/P2.cs similarity index 58% rename from BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/P2.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/P2.cs index c42f8422a5..1637b906d4 100644 --- a/BossMod/Modules/Stormblood/Quest/ARequiemForHeroes/P2.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/ARequiemForHeroes/P2.cs @@ -1,21 +1,11 @@ -namespace BossMod.Stormblood.Quest.ARequiemForHeroes; +namespace BossMod.Stormblood.Quest.MSQ.ARequiemForHeroes; class StormUnbound(BossModule module) : Components.Exaflare(module, 5) { public override void OnCastStarted(Actor caster, ActorCastInfo spell) { if ((AID)spell.Action.ID == AID.TheStormUnboundCast) - { - Lines.Add(new() - { - Next = caster.Position, - Advance = caster.Rotation.ToDirection() * 5, - NextExplosion = Module.CastFinishAt(spell), - TimeToMove = 1, - ExplosionsLeft = 4, - MaxShownExplosions = 2 - }); - } + Lines.Add(new() { Next = spell.LocXZ, Advance = caster.Rotation.ToDirection() * 5, NextExplosion = Module.CastFinishAt(spell), TimeToMove = 1, ExplosionsLeft = 4, MaxShownExplosions = 2 }); } public override void OnEventCast(Actor caster, ActorCastEvent spell) @@ -24,20 +14,19 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) { foreach (var l in Lines.Where(l => l.Next.AlmostEqual(caster.Position, 1))) AdvanceLine(l, caster.Position); - ++NumCasts; } } } -class LightlessSpark2(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.LightlessSparkAdds), new AOEShapeCone(40, 45.Degrees())); +class LightlessSpark2(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LightlessSparkAdds), new AOEShapeCone(40, 45.Degrees())); -class ArtOfTheStorm(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ArtOfTheStorm), new AOEShapeCircle(8)); -class EntropicFlame(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.EntropicFlame), new AOEShapeRect(50, 4)); +class ArtOfTheStorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ArtOfTheStorm), 8); +class EntropicFlame(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EntropicFlame), new AOEShapeRect(50, 4)); -class FloodOfDarkness(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.FloodOfDarkness), new AOEShapeCircle(6), maxCasts: 6); -class VeinSplitter(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.VeinSplitter), new AOEShapeCircle(10)); -class LightlessSpark(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.LightlessSpark), new AOEShapeCone(40, 45.Degrees())); -class SwellUnbound(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.TheSwellUnbound), new AOEShapeDonut(8, 20)); +class FloodOfDarkness(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FloodOfDarkness), 6); +class VeinSplitter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.VeinSplitter), 10); +class LightlessSpark(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LightlessSpark), new AOEShapeCone(40, 45.Degrees())); +class SwellUnbound(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.TheSwellUnbound), new AOEShapeDonut(8, 20)); class Swell(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.ArtOfTheSwell), 8) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) @@ -46,9 +35,11 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme hints.AddForbiddenZone(new AOEShapeDonut(8, 50), Arena.Center); } } -class ArtOfTheSword1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ArtOfTheSword1), new AOEShapeRect(40, 3)); -class ArtOfTheSword2(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ArtOfTheSword2), new AOEShapeRect(40, 3)); -class ArtOfTheSword3(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ArtOfTheSword3), new AOEShapeRect(40, 3)); + +abstract class ArtOfTheSword(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(40, 3)); +class ArtOfTheSword1(BossModule module) : ArtOfTheSword(module, AID.ArtOfTheSword1); +class ArtOfTheSword2(BossModule module) : ArtOfTheSword(module, AID.ArtOfTheSword2); +class ArtOfTheSword3(BossModule module) : ArtOfTheSword(module, AID.ArtOfTheSword3); class DarkAether(BossModule module) : Components.GenericAOEs(module) { diff --git a/BossMod/Modules/Stormblood/Quest/BestServedWithColdSteel.cs b/BossMod/Modules/Stormblood/Quest/MSQ/BestServedWithColdSteel.cs similarity index 80% rename from BossMod/Modules/Stormblood/Quest/BestServedWithColdSteel.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/BestServedWithColdSteel.cs index 8faa744c35..38cceb0b45 100644 --- a/BossMod/Modules/Stormblood/Quest/BestServedWithColdSteel.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/BestServedWithColdSteel.cs @@ -1,10 +1,10 @@ -namespace BossMod.Stormblood.Quest.BestServedWithColdSteel; +namespace BossMod.Stormblood.Quest.MSQ.BestServedWithColdSteel; public enum OID : uint { - Boss = 0x1A52, // R2.100f, x1 + Boss = 0x1A52, // R2.1 Grynewaht = 0x1A53, - Helper = 0x233C, + Helper = 0x233C } public enum AID : uint @@ -15,20 +15,20 @@ public enum AID : uint AugmentedSuffering = 8492, // Boss->self, 3.5fs cast, range $1fR circle AugmentedUprising = 8493, // Boss->self, 3.0fs cast, range $1fR 120-degree cone SelfDetonate = 8122, // 1A56->self, no cast, range 6 circle - SelfDetonate1 = 9169, // Boss->self, 60.0s cast, range 100 circle + SelfDetonate1 = 9169 // Boss->self, 60.0s cast, range 100 circle } public enum TetherID : uint { - Mine = 54, // 1A56->player + Mine = 54 // 1A56->player } -class AugmentedUprising(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AugmentedUprising), new AOEShapeCone(8.5f, 60.Degrees())); -class AugmentedSuffering(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AugmentedSuffering), new AOEShapeCircle(6.5f)); -class OpenFire(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.OpenFire1), 6); +class AugmentedUprising(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedUprising), new AOEShapeCone(8.5f, 60.Degrees())); +class AugmentedSuffering(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedSuffering), 6.5f); +class OpenFire(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.OpenFire1), 6); -class CermetPile(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CermetPile), new AOEShapeRect(42.1f, 3f)); -class Firebomb(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Firebomb), 4); +class CermetPile(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CermetPile), new AOEShapeRect(42.1f, 3f)); +class Firebomb(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Firebomb), 4); class MagitekTurret(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.SelfDetonate)) { @@ -59,7 +59,7 @@ public override IEnumerable ActiveAOEs(int slot, Actor actor) // offset danger zone slightly toward mine so that AI can dodge // if centered on player it doesn't know which direction to go : mineToPlayer * 0.9f; - yield return new AOEInstance(new AOEShapeCircle(6), m.source.Position + projectedExplosion, default, Activation: m.tethered.AddSeconds(12)); + yield return new(new AOEShapeCircle(6), m.source.Position + projectedExplosion, default, Activation: m.tethered.AddSeconds(12)); } } @@ -83,7 +83,7 @@ public override void OnActorDestroyed(Actor actor) public override void DrawArenaForeground(int pcSlot, Actor pc) { foreach (var m in Mines.Where(m => m.target == pc)) - Arena.AddLine(m.source.Position, pc.Position, ArenaColor.Danger); + Arena.AddLine(m.source.Position, pc.Position, Colors.Danger); } } @@ -138,13 +138,14 @@ public class MagitekVanguardIPrototype(WorldState ws, Actor primary) : BossModul protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var h in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var h = hints.PotentialTargets[i]; if (h.Actor.OID == 0x1A52) h.Priority = 1; else if (h.Actor.TargetID == actor.InstanceID) diff --git a/BossMod/Modules/Stormblood/Quest/EmissaryOfTheDawn.cs b/BossMod/Modules/Stormblood/Quest/MSQ/EmissaryOfTheDawn.cs similarity index 80% rename from BossMod/Modules/Stormblood/Quest/EmissaryOfTheDawn.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/EmissaryOfTheDawn.cs index 9936b94e45..eb328c91cb 100644 --- a/BossMod/Modules/Stormblood/Quest/EmissaryOfTheDawn.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/EmissaryOfTheDawn.cs @@ -1,14 +1,14 @@ using BossMod.QuestBattle.Stormblood.MSQ; -namespace BossMod.Stormblood.Quest.EmissaryOfTheDawn; +namespace BossMod.Stormblood.Quest.MSQ.EmissaryOfTheDawn; public enum OID : uint { Boss = 0x234B, - Helper = 0x233C, + Helper = 0x233C } -class AlphiAI(BossModule module) : QuestBattle.RotationModule(module); +class AlphinaudAI(BossModule module) : QuestBattle.RotationModule(module); class LB(BossModule module) : BossComponent(module) { @@ -24,7 +24,7 @@ class HostileSkyArmorStates : StateMachineBuilder public HostileSkyArmorStates(BossModule module) : base(module) { TrivialPhase() - .ActivateOnEnter() + .ActivateOnEnter() .ActivateOnEnter() .Raw.Update = () => module.WorldState.CurrentCFCID != 582; } @@ -33,6 +33,6 @@ public HostileSkyArmorStates(BossModule module) : base(module) [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68612, NameID = 7257)] public class HostileSkyArmor(WorldState ws, Actor primary) : BossModule(ws, primary, new(0, 0), new ArenaBoundsCircle(20)) { - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Stormblood/Quest/HisForgottenHome.cs b/BossMod/Modules/Stormblood/Quest/MSQ/HisForgottenHome.cs similarity index 75% rename from BossMod/Modules/Stormblood/Quest/HisForgottenHome.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/HisForgottenHome.cs index 67963a398a..662a89a309 100644 --- a/BossMod/Modules/Stormblood/Quest/HisForgottenHome.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/HisForgottenHome.cs @@ -1,22 +1,23 @@ -namespace BossMod.Stormblood.Quest.HisForgottenHome; +namespace BossMod.Stormblood.Quest.MSQ.HisForgottenHome; + public enum OID : uint { Boss = 0x213A, - Helper = 0x233C, - SoftshellOfTheRed = 0x213B, // R1.600, x4 (spawn during fight) - SoftshellOfTheRed1 = 0x213C, // R1.600, x0 (spawn during fight) - SoftshellOfTheRed2 = 0x213D, // R1.600, x0 (spawn during fight) + SoftshellOfTheRed = 0x213B, // R1.6 + SoftshellOfTheRed1 = 0x213C, // R1.6 + SoftshellOfTheRed2 = 0x213D, // R1.6 + Helper = 0x233C } public enum AID : uint { Kasaya = 8585, // SoftshellOfTheRed->self, 2.5s cast, range 6+R 120-degree cone WaterIII = 5831, // Boss->location, 3.0s cast, range 8 circle - BlizzardIII = 10874, // Boss->location, 3.0s cast, range 5 circle + BlizzardIII = 1087, // Boss->location, 3.0s cast, range 5 circle } -class Kasaya(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Kasaya), new AOEShapeCone(7.6f, 60.Degrees())); -class WaterIII(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.WaterIII), 8); +class Kasaya(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Kasaya), new AOEShapeCone(7.6f, 60.Degrees())); +class WaterIII(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WaterIII), 8); class BlizzardIIIIcon(BossModule module) : Components.BaitAwayIcon(module, new AOEShapeCircle(5), 26, centerAtTarget: true) { @@ -58,13 +59,16 @@ public class SlickshellCaptain(WorldState ws, Actor primary) : BossModule(ws, pr public static readonly ArenaBoundsCustom CustomBounds = new(30, new(vertices.Select(v => v - BoundsCenter))); - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { // attack anyone targeting isse - foreach (var h in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var h = hints.PotentialTargets[i]; h.Priority = WorldState.Actors.Find(h.Actor.TargetID)?.OID == 0x2138 ? 1 : 0; + } } } diff --git a/BossMod/Modules/Stormblood/Quest/HopeOnTheWaves.cs b/BossMod/Modules/Stormblood/Quest/MSQ/HopeOnTheWaves.cs similarity index 66% rename from BossMod/Modules/Stormblood/Quest/HopeOnTheWaves.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/HopeOnTheWaves.cs index 036208cf37..abc1ced2b3 100644 --- a/BossMod/Modules/Stormblood/Quest/HopeOnTheWaves.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/HopeOnTheWaves.cs @@ -1,4 +1,4 @@ -namespace BossMod.Stormblood.Quest.HopeOnTheWaves; +namespace BossMod.Stormblood.Quest.MSQ.HopeOnTheWaves; public enum OID : uint { @@ -17,13 +17,13 @@ public enum AID : uint AssaultCannon = 10823, // 21B5->self, 2.5s cast, range 75+R width 2 rect } -class AssaultCannon(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AssaultCannon), new AOEShapeRect(75, 1)); -class CircleOfDeath(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CircleOfDeath), new AOEShapeCircle(10.24f)); -class TwoTonzeMagitekMissile(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.W2TonzeMagitekMissile), 6); -class MagitekMissileProximity(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.MagitekMissile1), 11.75f); -class CermetPile(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.CermetPile), new AOEShapeRect(42, 3)); +class AssaultCannon(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AssaultCannon), new AOEShapeRect(75, 1)); +class CircleOfDeath(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CircleOfDeath), 10.24f); +class TwoTonzeMagitekMissile(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.W2TonzeMagitekMissile), 6); +class MagitekMissileProximity(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekMissile1), 11.75f); +class CermetPile(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.CermetPile), new AOEShapeRect(42, 3)); class SelfDetonate(BossModule module) : Components.CastHint(module, ActionID.MakeSpell(AID.SelfDetonate), "Kill before detonation!", true); -class MineSelfDetonate(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SelfDetonate1), new AOEShapeCircle(6)); +class MineSelfDetonate(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SelfDetonate1), 6); class Adds(BossModule module) : BossComponent(module) { @@ -35,8 +35,9 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme ? castInfo.LocXZ : null; - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; if (lbCenter != null && e.Actor.OID == 0x2114) { e.ShouldBeTanked = true; @@ -69,12 +70,12 @@ public ImperialCenturionStates(BossModule module) : base(module) } [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68560, NameID = 4148)] -public class ImperialCenturion(WorldState ws, Actor primary) : BossModule(ws, primary, new(473.25f, 751.75f), BoundsP2) +public class ImperialCenturion(WorldState ws, Actor primary) : BossModule(ws, primary, arena.Center, arena) { - public static readonly ArenaBoundsCustom BoundsP2 = new(30, new(CurveApprox.Ellipse(34, 21, 0.05f).Select(p => p.Rotate(140.Degrees())))); + public static readonly ArenaBoundsComplex arena = new([new Ellipse(new(473.25f, 751.75f), 34, 21, 50, 140.Degrees())]); protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } } diff --git a/BossMod/Modules/Stormblood/Quest/Naadam.cs b/BossMod/Modules/Stormblood/Quest/MSQ/Naadam.cs similarity index 73% rename from BossMod/Modules/Stormblood/Quest/Naadam.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/Naadam.cs index 0f2be8492c..d1343640a8 100644 --- a/BossMod/Modules/Stormblood/Quest/Naadam.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/Naadam.cs @@ -1,14 +1,14 @@ -namespace BossMod.Stormblood.Quest.Naadam; +namespace BossMod.Stormblood.Quest.MSQ.Naadam; public enum OID : uint { Boss = 0x1B31, + MagnaiTheOlder = 0x1B38, // R0.5 + StellarChuluu = 0x1B3F, // R1.8 + StellarChuluu1 = 0x1B40, // R1.8 + Grynewaht = 0x1B3A, // R0.5 + Ovoo = 0x1EA4E1, Helper = 0x233C, - MagnaiTheOlder = 0x1B38, // R0.500, x0 (spawn during fight) - StellarChuluu = 0x1B3F, // R1.800, x0 (spawn during fight) - StellarChuluu1 = 0x1B40, // R1.800, x0 (spawn during fight) - Grynewaht = 0x1B3A, // R0.500, x0 (spawn during fight) - Ovoo = 0x1EA4E1 } public enum AID : uint @@ -18,7 +18,7 @@ public enum AID : uint Epigraph = 8339, // 1A58->self, 3.0s cast, range 45+R width 8 rect DiffractiveLaser = 9122, // ArmoredWeapon->location, 3.0s cast, range 5 circle AugmentedSuffering = 8492, // Grynewaht->self, 3.5s cast, range 6+R circle - AugmentedUprising = 8493, // Grynewaht->self, 3.0s cast, range 8+R 120-degree cone + AugmentedUprising = 8493 // Grynewaht->self, 3.0s cast, range 8+R 120-degree cone } public enum SID : uint @@ -26,13 +26,13 @@ public enum SID : uint EarthenAccord = 778 } -class DiffractiveLaser(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.DiffractiveLaser), 5); -class AugmentedSuffering(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AugmentedSuffering), new AOEShapeCircle(6.5f)); -class AugmentedUprising(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AugmentedUprising), new AOEShapeCone(8.5f, 60.Degrees())); +class DiffractiveLaser(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DiffractiveLaser), 5); +class AugmentedSuffering(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedSuffering), 6.5f); +class AugmentedUprising(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AugmentedUprising), new AOEShapeCone(8.5f, 60.Degrees())); -class ViolentEarth(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.ViolentEarth), 6); -class DispellingWind(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DispellingWind), new AOEShapeRect(40.5f, 4)); -class Epigraph(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Epigraph), new AOEShapeRect(45, 4)); +class ViolentEarth(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ViolentEarth), 6); +class DispellingWind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DispellingWind), new AOEShapeRect(40.5f, 4)); +class Epigraph(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Epigraph), new AOEShapeRect(45, 4)); class DrawOvoo : BossComponent { @@ -45,7 +45,7 @@ public DrawOvoo(BossModule module) : base(module) public override void DrawArenaForeground(int pcSlot, Actor pc) { - Arena.Actor(Ovoo, ArenaColor.Object, true); + Arena.Actor(Ovoo, Colors.Object, true); } } @@ -76,8 +76,9 @@ class ProtectOvoo(BossModule module) : BossComponent(module) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; if (e.Actor.FindStatus(SID.EarthenAccord) != null) e.Priority = 5; else if (e.Actor.OID == (uint)OID.StellarChuluu) @@ -94,8 +95,9 @@ public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignme { var chuluu = WorldState.Actors.Where(x => (OID)x.OID == OID.StellarChuluu1).Select(x => x.InstanceID).ToList(); - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; if (chuluu.Contains(e.Actor.TargetID)) e.Priority = 5; else if ((OID)e.Actor.OID == OID.Grynewaht) @@ -137,6 +139,6 @@ public OvooStates(BossModule module) : base(module) { protected override bool CheckPull() => Raid.Player()?.Position.InCircle(PrimaryActor.Position, 15) ?? false; - protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + protected override void DrawEnemies(int pcSlot, Actor pc) => Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } diff --git a/BossMod/Modules/Stormblood/Quest/ReturnOfTheBull.cs b/BossMod/Modules/Stormblood/Quest/MSQ/ReturnOfTheBull.cs similarity index 84% rename from BossMod/Modules/Stormblood/Quest/ReturnOfTheBull.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/ReturnOfTheBull.cs index 92d76ac875..942b10b5c4 100644 --- a/BossMod/Modules/Stormblood/Quest/ReturnOfTheBull.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/ReturnOfTheBull.cs @@ -1,4 +1,4 @@ -namespace BossMod.Stormblood.Quest.ReturnOfTheBull; +namespace BossMod.Stormblood.Quest.MSQ.ReturnOfTheBull; public enum OID : uint { Boss = 0x1FD2, @@ -18,8 +18,8 @@ public enum AID : uint ThePathOfLight = 9875, // Boss->self, 5.0s cast, range 40+R 120-degree cone } -class PathOfLight(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ThePathOfLight), new AOEShapeCone(43.5f, 60.Degrees())); -class BlissfulSpear(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.BlissfulSpear), new AOEShapeCross(40, 4)); +class PathOfLight(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ThePathOfLight), new AOEShapeCone(43.5f, 60.Degrees())); +class BlissfulSpear(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.BlissfulSpear), new AOEShapeCross(40, 4)); class ThePallOfLight(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.ThePallOfLight), 6, 1); class BlissfulHammer(BossModule module) : Components.BaitAwayIcon(module, new AOEShapeCircle(7), 109, ActionID.MakeSpell(AID.BlissfulHammer), 12.15f, true); class FordolaShield(BossModule module) : BossComponent(module) @@ -29,7 +29,7 @@ class FordolaShield(BossModule module) : BossComponent(module) public override void DrawArenaBackground(int pcSlot, Actor pc) { if (Shield != null) - Arena.AddCircleFilled(Shield.Position, 4, ArenaColor.SafeFromAOE); + Arena.AddCircleFilled(Shield.Position, 4, Colors.SafeFromAOE); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) @@ -51,7 +51,7 @@ class Deflect(BossModule module) : BossComponent(module) public override void DrawArenaForeground(int pcSlot, Actor pc) { - Arena.Actors(Spheres, 0xFFFFA080); + Arena.Actors(Spheres, Colors.Other9); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) @@ -82,8 +82,7 @@ public LakshmiStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } @@ -92,13 +91,16 @@ public LakshmiStates(BossModule module) : base(module) { protected override void CalculateModuleAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) + { + var e = hints.PotentialTargets[i]; e.Priority = (OID)e.Actor.OID switch { OID.Boss => 1, OID.Aether => -1, _ => 0 }; + } } } diff --git a/BossMod/Modules/Stormblood/Quest/RhalgrsBeacon.cs b/BossMod/Modules/Stormblood/Quest/MSQ/RhalgrsBeacon.cs similarity index 90% rename from BossMod/Modules/Stormblood/Quest/RhalgrsBeacon.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/RhalgrsBeacon.cs index 8410fa5c46..76d933b75f 100644 --- a/BossMod/Modules/Stormblood/Quest/RhalgrsBeacon.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/RhalgrsBeacon.cs @@ -1,15 +1,15 @@ -namespace BossMod.Stormblood.Quest.RhalgrsBeacon; +namespace BossMod.Stormblood.Quest.MSQ.RhalgrsBeacon; public enum OID : uint { Boss = 0x1A88, - Helper = 0x233C, TerminusEst = 0x1BCA, MarkXLIIIArtilleryCannon = 0x1B4A, // R2.000, x3 SkullsSpear = 0x1A8C, // R0.500, x3 SkullsBlade = 0x1A8B, // R0.500, x3 MagitekTurretII = 0x1BC7, // R0.600, x0 (spawn during fight) ChoppingBlock = 0x1EA4D9, // R0.500, x0 (spawn during fight), voidzone event object + Helper = 0x233C } public enum AID : uint @@ -21,7 +21,7 @@ public enum AID : uint ChoppingBlock1 = 8346, // 1A57->location, 3.0s cast, range 5 circle } -class DiffractiveLaser(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DiffractiveLaser), new AOEShapeCone(18.6f, 30.Degrees())); +class DiffractiveLaser(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DiffractiveLaser), new AOEShapeCone(18.6f, 30.Degrees())); class TerminusEst(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.TheOrder)) { @@ -30,13 +30,13 @@ class TerminusEst(BossModule module) : Components.GenericAOEs(module, ActionID.M public override void DrawArenaForeground(int pcSlot, Actor pc) { - Arena.Actors(Module.Enemies(OID.TerminusEst).Where(x => !x.IsDead), ArenaColor.Object, true); + Arena.Actors(Module.Enemies(OID.TerminusEst).Where(x => !x.IsDead), Colors.Object, true); } public override IEnumerable ActiveAOEs(int slot, Actor actor) { foreach (var t in Termini) - yield return new AOEInstance(new AOEShapeRect(41f, 2), t.Position, t.Rotation, Activation: CastFinish ?? WorldState.FutureTime(10)); + yield return new(new AOEShapeRect(41f, 2), t.Position, t.Rotation, Activation: CastFinish ?? WorldState.FutureTime(10)); } public override void OnActorCreated(Actor actor) diff --git a/BossMod/Modules/Stormblood/Quest/TheMeasureOfHisReach.cs b/BossMod/Modules/Stormblood/Quest/MSQ/TheMeasureOfHisReach.cs similarity index 58% rename from BossMod/Modules/Stormblood/Quest/TheMeasureOfHisReach.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/TheMeasureOfHisReach.cs index 4d392dfffc..03feeb2ea9 100644 --- a/BossMod/Modules/Stormblood/Quest/TheMeasureOfHisReach.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/TheMeasureOfHisReach.cs @@ -1,10 +1,10 @@ -namespace BossMod.Stormblood.Quest.TheMeasureOfHisReach; +namespace BossMod.Stormblood.Quest.MSQ.TheMeasureOfHisReach; public enum OID : uint { Boss = 0x1C48, - Helper = 0x233C, - Whitefang = 0x1C5A + Whitefang = 0x1C5A, + Helper = 0x233C } public enum AID : uint @@ -15,19 +15,19 @@ public enum AID : uint HowlingBloomshower = 8399, // 1C4F->self, 2.5s cast, range 8+R ?-degree cone } -class Moonlight(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HowlingMoonlight), new AOEShapeCircle(10)) +class Moonlight(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HowlingMoonlight), 10) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { base.AddAIHints(slot, actor, assignment, hints); // hits everyone (proximity damage) foreach (var c in Casters) - hints.PredictedDamage.Add((Raid.WithSlot().Mask(), Module.CastFinishAt(c.CastInfo))); + hints.PredictedDamage.Add((Raid.WithSlot(false, false).Mask(), c.Activation)); } } -class Icewind(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HowlingIcewind), new AOEShapeRect(44, 2)); -class Dragonspirit(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Dragonspirit), new AOEShapeCircle(7.5f)); -class Bloomshower(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.HowlingBloomshower), new AOEShapeDonutSector(4, 8, 45.Degrees())); +class Icewind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HowlingIcewind), new AOEShapeRect(44, 2)); +class Dragonspirit(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Dragonspirit), 7.5f); +class Bloomshower(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.HowlingBloomshower), new AOEShapeDonutSector(4, 8, 45.Degrees())); class HakuroWhitefangStates : StateMachineBuilder { @@ -37,11 +37,9 @@ public HakuroWhitefangStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .ActivateOnEnter() - ; + .ActivateOnEnter(); } } [ModuleInfo(BossModuleInfo.Maturity.Contributed, GroupType = BossModuleInfo.GroupType.Quest, GroupID = 68088, NameID = 5975)] public class HakuroWhitefang(WorldState ws, Actor primary) : BossModule(ws, primary, new(504, -133), new ArenaBoundsCircle(20)); - diff --git a/BossMod/Modules/Stormblood/Quest/TheResonant.cs b/BossMod/Modules/Stormblood/Quest/MSQ/TheResonant.cs similarity index 83% rename from BossMod/Modules/Stormblood/Quest/TheResonant.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/TheResonant.cs index 713d29fdec..70bcec2396 100644 --- a/BossMod/Modules/Stormblood/Quest/TheResonant.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/TheResonant.cs @@ -1,12 +1,12 @@ -namespace BossMod.Stormblood.Quest.TheResonant; +namespace BossMod.Stormblood.Quest.MSQ.TheResonant; public enum OID : uint { Boss = 0x1B7D, - Helper = 0x233C, FordolaRemLupis = 0x18D6, // R0.500, x4, Helper type MarkXLIIIArtilleryCannon = 0x1B7E, // R0.600, x0 (spawn during fight) FordolaRemLupis1 = 0x1BCA, // R1.000, x0 (spawn during fight) + Helper = 0x233C } public enum AID : uint @@ -23,7 +23,7 @@ public enum SID : uint Resonant = 780, } -class Skullbreaker(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Skullbreaker1), new AOEShapeCircle(12)); +class Skullbreaker(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Skullbreaker1), 12); class TerminusEst(BossModule module) : Components.GenericAOEs(module) { @@ -51,15 +51,16 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell) Activation = null; } } -class MagitekRay(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.MagitekRay), new AOEShapeRect(45.6f, 1)); -class ChoppingBlock(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.ChoppingBlock1), 5); +class MagitekRay(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MagitekRay), new AOEShapeRect(45.6f, 1)); +class ChoppingBlock(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ChoppingBlock1), 5); class Siphon(BossModule module) : BossComponent(module) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var h in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var h = hints.PotentialTargets[i]; if (h.Actor.FindStatus(SID.Resonant) != null) { h.Priority = AIHints.Enemy.PriorityForbidden; diff --git a/BossMod/Modules/Stormblood/Quest/TheTimeBetweenTheSeconds.cs b/BossMod/Modules/Stormblood/Quest/MSQ/TheTimeBetweenTheSeconds.cs similarity index 76% rename from BossMod/Modules/Stormblood/Quest/TheTimeBetweenTheSeconds.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/TheTimeBetweenTheSeconds.cs index 3e51ac891c..b20e437f2c 100644 --- a/BossMod/Modules/Stormblood/Quest/TheTimeBetweenTheSeconds.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/TheTimeBetweenTheSeconds.cs @@ -1,15 +1,15 @@ -namespace BossMod.Stormblood.Quest.TheTimeBetweenTheSeconds; +namespace BossMod.Stormblood.Quest.MSQ.TheTimeBetweenTheSeconds; public enum OID : uint { Boss = 0x1A36, - Helper = 0x233C, ZenosYaeGalvus = 0x1CEE, // R0.500, x9 DomanSignifer = 0x1A3A, // R0.500, x3 DomanHoplomachus = 0x1A39, // R0.500, x2 ZenosYaeGalvus1 = 0x1EBC, // R0.920, x1 DarkReflection = 0x1A37, // R0.920, x2 LightlessFlame = 0x1CED, // R1.000, x0 (spawn during fight) + Helper = 0x233C } public enum AID : uint @@ -21,8 +21,8 @@ public enum AID : uint ArtOfTheSword1 = 8993, // 1CEE->self, 3.0s cast, range 40+R width 6 rect } -class ArtOfTheSword(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.ArtOfTheSword1), new AOEShapeRect(41, 3)); -class VeinSplitter(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.VeinSplitter), new AOEShapeCircle(10)); +class ArtOfTheSword(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ArtOfTheSword1), new AOEShapeRect(41, 3)); +class VeinSplitter(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.VeinSplitter), 10); class Concentrativity(BossModule module) : Components.RaidwideCast(module, ActionID.MakeSpell(AID.Concentrativity)); class LightlessFlame(BossModule module) : Components.GenericAOEs(module, ActionID.MakeSpell(AID.LightlessFlame)) { @@ -48,13 +48,13 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell) Flames.Remove(caster.InstanceID); } } -class LightlessSpark(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.LightlessSpark), new AOEShapeCone(40.92f, 45.Degrees())); +class LightlessSpark(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.LightlessSpark), new AOEShapeCone(40.92f, 45.Degrees())); class P2Boss(BossModule module) : BossComponent(module) { public override void DrawArenaForeground(int pcSlot, Actor pc) { - Arena.Actors(Module.Enemies(OID.ZenosYaeGalvus1), ArenaColor.Enemy); - Arena.Actors(Module.Enemies(OID.DarkReflection), ArenaColor.Enemy); + Arena.Actors(Module.Enemies(OID.ZenosYaeGalvus1)); + Arena.Actors(Module.Enemies(OID.DarkReflection)); } } @@ -62,10 +62,10 @@ class ZenosYaeGalvusStates : StateMachineBuilder { public ZenosYaeGalvusStates(BossModule module) : base(module) { - SimplePhase(0, id => BuildState(id, "P1 enrage", 1800), "P1") + SimplePhase(0, id => BuildState(id, ""), "P1") .Raw.Update = () => !Module.PrimaryActor.IsTargetable; - SimplePhase(1, id => BuildState(id, "P2 enrage", 1800).ActivateOnEnter().ActivateOnEnter(), "P2") - .Raw.Update = () => !Module.Enemies(OID.ZenosYaeGalvus1).Any(); + SimplePhase(1, id => BuildState(id, "").ActivateOnEnter().ActivateOnEnter(), "P2") + .Raw.Update = () => Module.Enemies(OID.ZenosYaeGalvus1).Count == 0; } private State BuildState(uint id, string name, float duration = 10000) diff --git a/BossMod/Modules/Stormblood/Quest/TheWillOfTheMoon.cs b/BossMod/Modules/Stormblood/Quest/MSQ/TheWillOfTheMoon.cs similarity index 72% rename from BossMod/Modules/Stormblood/Quest/TheWillOfTheMoon.cs rename to BossMod/Modules/Stormblood/Quest/MSQ/TheWillOfTheMoon.cs index b3da138e51..03135e86f7 100644 --- a/BossMod/Modules/Stormblood/Quest/TheWillOfTheMoon.cs +++ b/BossMod/Modules/Stormblood/Quest/MSQ/TheWillOfTheMoon.cs @@ -1,17 +1,17 @@ using BossMod.QuestBattle; using RPID = BossMod.Roleplay.AID; -namespace BossMod.Stormblood.Quest.TheWillOfTheMoon; +namespace BossMod.Stormblood.Quest.MSQ.TheWillOfTheMoon; public enum OID : uint { Boss = 0x24A0, Magnai = 0x24A1, - Helper = 0x233C, - KhunShavar = 0x252F, // R1.820, x0 (spawn during fight) + KhunShavar = 0x252F, // R1.82 Hien = 0x24A3, - Daidukul = 0x24A2, // R0.500, x1 - TheScaleOfTheFather = 0x2532, // R1.000, x0 (spawn during fight) + Daidukul = 0x24A2, // R0.5 + TheScaleOfTheFather = 0x2532, // R1.0 + Helper = 0x233C } public enum AID : uint @@ -34,36 +34,36 @@ public enum SID : uint Invincibility = 775, // none->Boss, extra=0x0 } -class DispellingWind(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.DispellingWind), new AOEShapeRect(40, 4)); -class Epigraph(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Epigraph), new AOEShapeRect(45, 4)); -class Whisper(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.WhisperOfLivesPast), new AOEShapeDonut(6, 12)); -class Blizzard(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.AncientBlizzard), new AOEShapeCone(40, 22.5f.Degrees())); -class Tornado(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Tornado), 6); -class Epigraph1(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Epigraph2), new AOEShapeRect(45, 4)); +class DispellingWind(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.DispellingWind), new AOEShapeRect(40, 4)); +class Epigraph(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Epigraph), new AOEShapeRect(45, 4)); +class Whisper(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WhisperOfLivesPast), new AOEShapeDonut(6, 12)); +class Blizzard(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.AncientBlizzard), new AOEShapeCone(40, 22.5f.Degrees())); +class Tornado(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Tornado), 6); +class Epigraph1(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Epigraph2), new AOEShapeRect(45, 4)); -public class FlatlandFury(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.FlatlandFury), new AOEShapeCircle(10)) +public class FlatlandFury(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlatlandFury), 10) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { // if all 9 adds are alive, instead of drawing forbidden zones (which would fill the whole arena), force AI to target nearest one to kill it - if (ActiveCasters.Count() == 9) - hints.ForcedTarget = ActiveCasters.MinBy(actor.DistanceToHitbox); + if (ActiveCasters.Count == 9) + hints.ForcedTarget = Module.Enemies(OID.TheScaleOfTheFather).MinBy(actor.DistanceToHitbox); else base.AddAIHints(slot, actor, assignment, hints); } } -public class FlatlandFuryEnrage(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.FlatlandFuryEnrage), new AOEShapeCircle(10)) +public class FlatlandFuryEnrage(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.FlatlandFuryEnrage), 10) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - if (ActiveCasters.Count() < 9) + if (ActiveCasters.Count < 9) base.AddAIHints(slot, actor, assignment, hints); } } -public class ViolentEarth(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.ViolentEarth), 6); -public class WindChisel(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.WindChisel), new AOEShapeCone(34, 10.Degrees())); +public class ViolentEarth(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.ViolentEarth), 6); +public class WindChisel(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WindChisel), new AOEShapeCone(34, 10.Degrees())); public class Scales(BossModule module) : Components.Adds(module, (uint)OID.TheScaleOfTheFather); @@ -107,8 +107,9 @@ class P1Hints(BossModule module) : BossComponent(module) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; if (e.Actor.FindStatus(SID.Invincibility) != null) e.Priority = AIHints.Enemy.PriorityInvincible; @@ -123,8 +124,9 @@ class P2Hints(BossModule module) : BossComponent(module) { public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) { - foreach (var e in hints.PotentialTargets) + for (var i = 0; i < hints.PotentialTargets.Count; ++i) { + var e = hints.PotentialTargets[i]; e.Priority = e.Actor.OID == (uint)OID.Magnai ? 1 : 0; } } @@ -142,7 +144,7 @@ public SaduHeavensflameStates(BossModule module) : base(module) .ActivateOnEnter() .ActivateOnEnter() .ActivateOnEnter() - .Raw.Update = () => Module.Enemies(OID.Magnai).Any(); + .Raw.Update = () => Module.Enemies(OID.Magnai).Count != 0; TrivialPhase(1) .ActivateOnEnter() .ActivateOnEnter() @@ -164,6 +166,6 @@ public SaduHeavensflameStates(BossModule module) : base(module) { protected override void DrawEnemies(int pcSlot, Actor pc) { - Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly), ArenaColor.Enemy); + Arena.Actors(WorldState.Actors.Where(x => !x.IsAlly)); } } diff --git a/BossMod/Modules/Stormblood/Quest/TortoiseInTime.cs b/BossMod/Modules/Stormblood/Quest/TheFourLords/TortoiseInTime.cs similarity index 78% rename from BossMod/Modules/Stormblood/Quest/TortoiseInTime.cs rename to BossMod/Modules/Stormblood/Quest/TheFourLords/TortoiseInTime.cs index 3a59b827e1..9c39d123bf 100644 --- a/BossMod/Modules/Stormblood/Quest/TortoiseInTime.cs +++ b/BossMod/Modules/Stormblood/Quest/TheFourLords/TortoiseInTime.cs @@ -1,12 +1,12 @@ -namespace BossMod.Stormblood.Quest.TortoiseInTime; +namespace BossMod.Stormblood.Quest.FourLords.TortoiseInTime; public enum OID : uint { Boss = 0x2339, - Helper = 0x233C, - Soroban = 0x2351, // R0.500, x8 - MonkeyMagick = 0x23C2, // R1.000, x0 (spawn during fight) - Font = 0x233B, // R4.000, x0 (spawn during fight) + Soroban = 0x2351, // R0.5 + MonkeyMagick = 0x23C2, // R1.0 + Font = 0x233B, // R4.0 + Helper = 0x233C } public enum AID : uint @@ -19,9 +19,9 @@ public enum AID : uint Upwell = 11515, // 233B->self, 3.0s cast, range 37+R ?-degree cone } -class Whitewater(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Whitewater1), new AOEShapeRect(40.5f, 3.5f)); -class Upwell(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.Upwell), new AOEShapeCone(41, 15.Degrees())); -class SpiritBurst(BossModule module) : Components.SelfTargetedAOEs(module, ActionID.MakeSpell(AID.SpiritBurst), new AOEShapeCircle(6)); +class Whitewater(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Whitewater1), new AOEShapeRect(40.5f, 3.5f)); +class Upwell(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Upwell), new AOEShapeCone(41, 15.Degrees())); +class SpiritBurst(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.SpiritBurst), 6); class WaterDrop(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.WaterDrop), 6); class ExplosiveTataru(BossModule module) : BossComponent(module) @@ -51,7 +51,7 @@ public override void OnCastStarted(Actor caster, ActorCastInfo spell) public override void DrawArenaBackground(int pcSlot, Actor pc) { if (Tataru != null) - Arena.AddCircle(Tataru.Position, 6, ArenaColor.Danger); + Arena.AddCircle(Tataru.Position, 6, Colors.Danger); } public override void AddAIHints(int slot, Actor actor, PartyRolesConfig.Assignment assignment, AIHints hints) @@ -67,7 +67,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) } } -class Eddy(BossModule module) : Components.LocationTargetedAOEs(module, ActionID.MakeSpell(AID.Eddy1), 6); +class Eddy(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Eddy1), 6); class ShieldHint(BossModule module) : BossComponent(module) { @@ -83,7 +83,7 @@ public override void OnActorEState(Actor actor, ushort state) public override void DrawArenaBackground(int pcSlot, Actor pc) { if (Shield is Actor s) - Arena.ZoneCircle(s.Position, Radius, ArenaColor.SafeFromAOE); + Arena.ZoneCircle(s.Position, Radius, Colors.SafeFromAOE); } public override void OnEventCast(Actor caster, ActorCastEvent spell) diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheHiddenCanalsOfUznair/Airavata.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheHiddenCanalsOfUznair/Airavata.cs index 2cd6a45c1b..d4d5adcded 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheHiddenCanalsOfUznair/Airavata.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheHiddenCanalsOfUznair/Airavata.cs @@ -73,7 +73,7 @@ class RingOfFire(BossModule module) : Components.SimpleAOEs(module, ActionID.Mak class StoneII(BossModule module) : Components.SingleTargetCast(module, ActionID.MakeSpell(AID.StoneII)); class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.Abharamu); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.Abharamu]); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheLostCanalsOfUznair/CanalIcebeast.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheLostCanalsOfUznair/CanalIcebeast.cs index 589130d4fd..b630ffc8b3 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheLostCanalsOfUznair/CanalIcebeast.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheLostCanalsOfUznair/CanalIcebeast.cs @@ -34,7 +34,7 @@ class Freezeover(BossModule module) : Components.SimpleAOEs(module, ActionID.Mak class PlainPound(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.PlainPound), 4.56f); class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.Abharamu); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.Abharamu]); class CanalIcebeastStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarAiravata.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarAiravata.cs index c9c9160ff7..fa837339c2 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarAiravata.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarAiravata.cs @@ -97,7 +97,7 @@ public override void DrawArenaBackground(int pcSlot, Actor pc) class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class AltarAiravataStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarArachne.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarArachne.cs index ca50a56570..490f035367 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarArachne.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarArachne.cs @@ -41,7 +41,7 @@ class Earthquake1(BossModule module) : Components.SimpleAOEs(module, ActionID.Ma class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class AltarArachneStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarBeast.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarBeast.cs index 204ff82f74..4c43d505c7 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarBeast.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarBeast.cs @@ -54,7 +54,7 @@ class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class AltarBeastStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarChimera.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarChimera.cs index 5d8c72a629..0fd1547705 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarChimera.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarChimera.cs @@ -76,7 +76,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class AltarChimeraStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDiresaur.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDiresaur.cs index 150aa22852..4fba571698 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDiresaur.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDiresaur.cs @@ -82,7 +82,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class AltarDiresaurStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDullahan.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDullahan.cs index 0a99d8a1fa..e19b2d7ff2 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDullahan.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarDullahan.cs @@ -49,7 +49,7 @@ class StygianReleaseKB(BossModule module) : Components.KnockbackFromCastTarget(m class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarKelpie.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarKelpie.cs index 19165a88d2..c2eb0ed05d 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarKelpie.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarKelpie.cs @@ -80,7 +80,7 @@ class RisingSeasKB(BossModule module) : Components.KnockbackFromCastTarget(modul class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); abstract class Mandragoras(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), 6.84f); class PluckAndPrune(BossModule module) : Mandragoras(module, AID.PluckAndPrune); diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarSkatene.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarSkatene.cs index a0613d212f..1b2b6d1dbe 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarSkatene.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarSkatene.cs @@ -32,7 +32,7 @@ class VoidCall(BossModule module) : Components.CastHint(module, ActionID.MakeSpe class RecklessAbandon(BossModule module) : Components.SingleTargetDelayableCast(module, ActionID.MakeSpell(AID.RecklessAbandon)); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class AltarSkateneStates : StateMachineBuilder diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarTotem.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarTotem.cs index 384113e9e4..d07c4b6778 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarTotem.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/AltarTotem.cs @@ -77,7 +77,7 @@ public override void AddHints(int slot, Actor actor, TextHints hints) class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class AltarTotemStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheOlderOne.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheOlderOne.cs index bf34894ce8..19e82d6e7b 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheOlderOne.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheOlderOne.cs @@ -59,7 +59,7 @@ class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class TheOlderOneStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheWinged.cs b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheWinged.cs index b440cb06b7..9e19a590f8 100644 --- a/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheWinged.cs +++ b/BossMod/Modules/Stormblood/TreasureHunt/TheShiftingAltarsOfUznair/TheWinged.cs @@ -54,7 +54,7 @@ class Pollen(BossModule module) : Mandragoras(module, AID.Pollen); class RaucousScritch(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RaucousScritch), new AOEShapeCone(8.42f, 60.Degrees())); class Hurl(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Hurl), 6); -class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), (uint)OID.AltarMatanga); +class Spin(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Spin), new AOEShapeCone(9.42f, 60.Degrees()), [(uint)OID.AltarMatanga]); class TheWingedStates : StateMachineBuilder { diff --git a/BossMod/Modules/Stormblood/Ultimate/UCOB/UCOB.cs b/BossMod/Modules/Stormblood/Ultimate/UCOB/UCOB.cs index ea144edc9b..fc64d90b9b 100644 --- a/BossMod/Modules/Stormblood/Ultimate/UCOB/UCOB.cs +++ b/BossMod/Modules/Stormblood/Ultimate/UCOB/UCOB.cs @@ -1,9 +1,9 @@ namespace BossMod.Stormblood.Ultimate.UCOB; -class P1Plummet(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Plummet), new AOEShapeCone(12, 60.Degrees()), (uint)OID.Twintania); +class P1Plummet(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Plummet), new AOEShapeCone(12, 60.Degrees()), [(uint)OID.Twintania]); class P1Fireball(BossModule module) : Components.StackWithIcon(module, (uint)IconID.Fireball, ActionID.MakeSpell(AID.Fireball), 4, 5.3f, 4, 4); class P2BahamutsClaw(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.BahamutsClaw)); -class P3FlareBreath(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.FlareBreath), new AOEShapeCone(29.2f, 45.Degrees()), (uint)OID.BahamutPrime); // TODO: verify angle +class P3FlareBreath(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.FlareBreath), new AOEShapeCone(29.2f, 45.Degrees()), [(uint)OID.BahamutPrime]); // TODO: verify angle class P5MornAfah(BossModule module) : Components.StackWithCastTargets(module, ActionID.MakeSpell(AID.MornAfah), 4, 8, 8); // TODO: verify radius [ModuleInfo(BossModuleInfo.Maturity.Verified, PrimaryActorOID = (uint)OID.Twintania, GroupType = BossModuleInfo.GroupType.CFC, GroupID = 280, PlanLevel = 70)] diff --git a/BossMod/Modules/Stormblood/Ultimate/UWU/P4ViscousAetheroplasm.cs b/BossMod/Modules/Stormblood/Ultimate/UWU/P4ViscousAetheroplasm.cs index a516d3b5f1..45abd8e385 100644 --- a/BossMod/Modules/Stormblood/Ultimate/UWU/P4ViscousAetheroplasm.cs +++ b/BossMod/Modules/Stormblood/Ultimate/UWU/P4ViscousAetheroplasm.cs @@ -1,6 +1,6 @@ namespace BossMod.Stormblood.Ultimate.UWU; -class P4ViscousAetheroplasmApply(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.ViscousAetheroplasmApply), new AOEShapeCircle(2), (uint)OID.UltimaWeapon, originAtTarget: true); +class P4ViscousAetheroplasmApply(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.ViscousAetheroplasmApply), new AOEShapeCircle(2), [(uint)OID.UltimaWeapon], originAtTarget: true); // TODO: if aetheroplasm target is the same as homing laser target, assume it is being soaked solo; consider merging these two components class P4ViscousAetheroplasmResolve(BossModule module) : Components.UniformStackSpread(module, 4, 0, 7) diff --git a/BossMod/Modules/Stormblood/Ultimate/UWU/UWU.cs b/BossMod/Modules/Stormblood/Ultimate/UWU/UWU.cs index eedca9d423..d78168c96f 100644 --- a/BossMod/Modules/Stormblood/Ultimate/UWU/UWU.cs +++ b/BossMod/Modules/Stormblood/Ultimate/UWU/UWU.cs @@ -5,15 +5,15 @@ class P1EyeOfTheStorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.EyeOfTheStorm), new AOEShapeDonut(12, 25)); class P1Gigastorm(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.Gigastorm), 6.5f); class P2RadiantPlume(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.RadiantPlumeAOE), 8); -class P2Incinerate(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Incinerate), new AOEShapeCone(15, 60.Degrees()), (uint)OID.Ifrit); -class P3RockBuster(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.RockBuster), new AOEShapeCone(10.55f, 60.Degrees()), (uint)OID.Titan); // TODO: verify angle -class P3MountainBuster(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.MountainBuster), new AOEShapeCone(15.55f, 45.Degrees()), (uint)OID.Titan); // TODO: verify angle +class P2Incinerate(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.Incinerate), new AOEShapeCone(15, 60.Degrees()), [(uint)OID.Ifrit]); +class P3RockBuster(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.RockBuster), new AOEShapeCone(10.55f, 60.Degrees()), [(uint)OID.Titan]); // TODO: verify angle +class P3MountainBuster(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.MountainBuster), new AOEShapeCone(15.55f, 45.Degrees()), [(uint)OID.Titan]); // TODO: verify angle class P3WeightOfTheLand(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.WeightOfTheLandAOE), 6); class P3Upheaval(BossModule module) : Components.KnockbackFromCastTarget(module, ActionID.MakeSpell(AID.Upheaval), 24, true); class P3Tumult(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.Tumult)); class P4Blight(BossModule module) : Components.CastCounter(module, ActionID.MakeSpell(AID.Blight)); class P4HomingLasers(BossModule module) : Components.SpreadFromCastTargets(module, ActionID.MakeSpell(AID.HomingLasers), 4); -class P4DiffractiveLaser(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.DiffractiveLaser), new AOEShapeCone(18, 45.Degrees()), (uint)OID.UltimaWeapon); // TODO: verify angle +class P4DiffractiveLaser(BossModule module) : Components.Cleave(module, ActionID.MakeSpell(AID.DiffractiveLaser), new AOEShapeCone(18, 45.Degrees()), [(uint)OID.UltimaWeapon]); // TODO: verify angle class P5MistralSongCone(BossModule module) : Components.SimpleAOEs(module, ActionID.MakeSpell(AID.MistralSongCone), new AOEShapeCone(21.7f, 75.Degrees())); abstract class P5AetherochemicalLaser(BossModule module, AID aid) : Components.SimpleAOEs(module, ActionID.MakeSpell(aid), new AOEShapeRect(46, 4)); diff --git a/BossMod/Util/Color.cs b/BossMod/Util/Color.cs index 6215b8d310..45c2718907 100644 --- a/BossMod/Util/Color.cs +++ b/BossMod/Util/Color.cs @@ -72,6 +72,7 @@ public static class Colors public static uint Other6 => _config.ArenaOther[5].ABGR; public static uint Other7 => _config.ArenaOther[6].ABGR; public static uint Other8 => _config.ArenaOther[7].ABGR; + public static uint Other9 => _config.ArenaOther[8].ABGR; public static uint Shadows => _config.Shadows.ABGR; public static uint CardinalN => _config.CardinalN.ABGR; public static uint CardinalE => _config.CardinalE.ABGR; diff --git a/BossMod/Util/CurveApprox.cs b/BossMod/Util/CurveApprox.cs index 6c6723ec5a..5a225d7d3d 100644 --- a/BossMod/Util/CurveApprox.cs +++ b/BossMod/Util/CurveApprox.cs @@ -94,18 +94,6 @@ public static WPos[] CircleSector(WPos center, float radius, Angle angleStart, A return points; } - public static IEnumerable Ellipse(float axis1, float axis2, float maxError) - { - int numSegments = CalculateCircleSegments((axis1 + axis2) / 2f, (2 * MathF.PI).Radians(), maxError); - var angle = (2 * MathF.PI / numSegments).Radians(); - for (int i = 0; i < numSegments; ++i) - { - var t = i * angle; - yield return new WDir(axis1 * t.Cos(), axis2 * t.Sin()); - } - } - public static IEnumerable Ellipse(WPos center, float axis1, float axis2, float maxError) => Ellipse(axis1, axis2, maxError).Select(off => center + off); - // return polygon points approximating full donut; implicitly closed path - outer arc + inner arc public static WDir[] Donut(float innerRadius, float outerRadius, float maxError) {