From 86db41cd113b5fab3de7d807cd6a153364d4484a Mon Sep 17 00:00:00 2001 From: XP Date: Sat, 6 Jul 2024 22:57:02 -0700 Subject: [PATCH] Ex2 --- .../gg/xp/xivsupport/triggers/dtex/DTEx2.java | 151 +++++++++++++++++- .../events/CastLocationDataEvent.java | 9 ++ .../events/DescribesCastLocation.java | 9 ++ .../xp/xivsupport/gui/map/omen/OmenShape.java | 3 + 4 files changed, 168 insertions(+), 4 deletions(-) diff --git a/triggers/triggers-dt/src/main/java/gg/xp/xivsupport/triggers/dtex/DTEx2.java b/triggers/triggers-dt/src/main/java/gg/xp/xivsupport/triggers/dtex/DTEx2.java index 01bb9f02ac11..43e668c1dbff 100644 --- a/triggers/triggers-dt/src/main/java/gg/xp/xivsupport/triggers/dtex/DTEx2.java +++ b/triggers/triggers-dt/src/main/java/gg/xp/xivsupport/triggers/dtex/DTEx2.java @@ -1,7 +1,9 @@ package gg.xp.xivsupport.triggers.dtex; +import gg.xp.reevent.events.BaseEvent; import gg.xp.reevent.events.EventContext; import gg.xp.reevent.scan.AutoChildEventHandler; +import gg.xp.reevent.scan.AutoFeed; import gg.xp.reevent.scan.FilteredEventHandler; import gg.xp.xivdata.data.duties.*; import gg.xp.xivsupport.callouts.CalloutRepo; @@ -9,10 +11,18 @@ import gg.xp.xivsupport.events.actlines.events.AbilityCastStart; import gg.xp.xivsupport.events.actlines.events.BuffApplied; import gg.xp.xivsupport.events.actlines.events.HeadMarkerEvent; +import gg.xp.xivsupport.events.actlines.events.TetherEvent; import gg.xp.xivsupport.events.state.XivState; +import gg.xp.xivsupport.events.triggers.seq.SequentialTrigger; +import gg.xp.xivsupport.events.triggers.seq.SqtTemplates; import gg.xp.xivsupport.events.triggers.support.NpcCastCallout; import gg.xp.xivsupport.events.triggers.support.PlayerHeadmarker; import gg.xp.xivsupport.events.triggers.support.PlayerStatusCallout; +import gg.xp.xivsupport.models.ArenaPos; +import gg.xp.xivsupport.models.ArenaSector; +import gg.xp.xivsupport.models.XivCombatant; + +import java.time.Duration; @CalloutRepo(name = "EX2", duty = KnownDuty.DtEx2) public class DTEx2 extends AutoChildEventHandler implements FilteredEventHandler { @@ -36,20 +46,153 @@ public boolean enabled(EventContext context) { @NpcCastCallout(0x993b) private final ModifiableCallout regicidalRage = ModifiableCallout.durationBasedCall("Regicidal Rage", "Tank Tethers"); + @NpcCastCallout(0x993e) + private final ModifiableCallout bitterWhirlwind = ModifiableCallout.durationBasedCall("Bitter Whirlwind", "Buster on {event.target}"); + @PlayerHeadmarker(value = 0, offset = true) private final ModifiableCallout yellowMarker = new ModifiableCallout<>("Yellow Marker", "Spread on Tiles"); + @NpcCastCallout(0x9374) + private final ModifiableCallout dutysEdge = ModifiableCallout.durationBasedCall("Duty's Edge", "Knockback - Multiple Hits"); + @NpcCastCallout(0x9397) private final ModifiableCallout dawnOfAnAge = ModifiableCallout.durationBasedCall("Dawn of an Age", "Raidwide"); - @PlayerStatusCallout(0x301) - private final ModifiableCallout burningChains = new ModifiableCallout<>("Burning Chains", "Break Chains"); - - @NpcCastCallout(0x938a) + @NpcCastCallout(value = 0x938a, suppressMs = 15_000) private final ModifiableCallout projectionOfTriumph = ModifiableCallout.durationBasedCall("Projection of Triumph", "Avoid Balls, Follow Donuts"); + @NpcCastCallout(0x9357) + private final ModifiableCallout vollok = ModifiableCallout.durationBasedCall("Vollok (Five Platforms)", "Watch Swords"); + + @NpcCastCallout(0x9392) + private final ModifiableCallout vollokTwoPlatforms = ModifiableCallout.durationBasedCall("Vollok (Two Platforms)", "Watch Swords"); + + @NpcCastCallout(0x9359) + private final ModifiableCallout sync = ModifiableCallout.durationBasedCall("Sync", "Swords Mirroring"); + + @NpcCastCallout(value = 0x939C, suppressMs = 5000) + private final ModifiableCallout forgedTrack = ModifiableCallout.durationBasedCall("Forged Track", "Watch Swords and Tracks"); + @NpcCastCallout(0x9a88) private final ModifiableCallout projectionOfTurmoil = ModifiableCallout.durationBasedCall("Projection of Turmoil", "Take Stacks Sequentially"); + private static final Duration cleaveOffset = Duration.ofMillis(1_200); + + private final ModifiableCallout leftHalfFull = ModifiableCallout.durationBasedCallWithOffset("Half Full (Left Safe)", "Left/{safe}", cleaveOffset); + private final ModifiableCallout rightHalfFull = ModifiableCallout.durationBasedCallWithOffset("Half Full (Right Safe)", "Right/{safe}", cleaveOffset); + + // TODO: do these exist as standalone casts? +// private final ModifiableCallout backwardEdge = ModifiableCallout.durationBasedCall("Backward Edge (Cleaving Front)", "Rear/{safe}"); +// private final ModifiableCallout forwardEdge = ModifiableCallout.durationBasedCall("Forward Edge (Cleaving Rear)", "Front/{safe}"); + + private final ModifiableCallout backwardHalfLeft = ModifiableCallout.durationBasedCallWithOffset("Backward Half (Back Left Safe)", "Back Left/{safe}", cleaveOffset); + private final ModifiableCallout backwardHalfRight = ModifiableCallout.durationBasedCallWithOffset("Backward Half (Back Right Safe)", "Back Right/{safe}", cleaveOffset); + + private final ModifiableCallout forwardHalfLeft = ModifiableCallout.durationBasedCallWithOffset("Forward Half (Front Left Safe)", "Front Left/{safe}", cleaveOffset); + private final ModifiableCallout forwardHalfRight = ModifiableCallout.durationBasedCallWithOffset("Forward Half (Front Right Safe)", "Front Right/{safe}", cleaveOffset); + + /* + Potentially relevant: + 0x9368 - half full (6.0) - left safe + 0x9369 - half full (6.0) - right safe + 0x936A - half full (6.3, actual aoe) + 0x937B - forward half (8.0) - front right safe, plus some distance + 0x937C - forward half (8.0) - front left safe, plus some distance + 0x937D - backward half (8.0) - rear left safe, plus some distance + 0x937E - backward half (8.0) - right right safe? plus some distance + 0x9380 - half full (1.0, actual aoe) + 0x939E - half full (6.3, actual aoe) + 0x9972 - backward edge (1.0, actual aoe) + 0x999A - forward half (9.0) - front right safe, no extra distance + 0x999B - forward half (9.0) - front left safe? no extra distance + 0x999C - backward half (9.0) - back left safe + 0x999D - backward half (9.0) - back right safe + */ + + @AutoFeed + private final SequentialTrigger bossCleaves = SqtTemplates.sq(10_000, + AbilityCastStart.class, acs -> { + long id = acs.getAbility().getId(); + return id == 0x9368 || id == 0x9369 + || (id >= 0x937B && id <= 0x937E) + || (id >= 0x999A && id <= 0x999D); + }, + (e1, s) -> { + s.waitMs(100); + var locationInfo = e1.getLocationInfo(); + ArenaSector bossFacing; + if (locationInfo == null) { + s.waitThenRefreshCombatants(100); + bossFacing = ArenaPos.combatantFacing(e1.getSource()); + } + else { + bossFacing = ArenaPos.combatantFacing(locationInfo.getBestHeading()); + } + switch ((int) e1.getAbility().getId()) { + case 0x9368 -> { + s.setParam("safe", bossFacing.plusEighths(-2)); + s.updateCall(leftHalfFull, e1); + } + case 0x9369 -> { + // left safe + s.setParam("safe", bossFacing.plusEighths(2)); + s.updateCall(rightHalfFull, e1); + } + case 0x937B, 0x999A -> { + // forward half, front right safe + s.setParam("safe", bossFacing.plusEighths(1)); + s.updateCall(forwardHalfRight, e1); + } + case 0x937C, 0x999B -> { + // forward half, front left safe + s.setParam("safe", bossFacing.plusEighths(-1)); + s.updateCall(forwardHalfLeft, e1); + } + case 0x937D, 0x999C -> { + // backward half, back left safe + s.setParam("safe", bossFacing.plusEighths(-3)); + s.updateCall(backwardHalfLeft, e1); + } + case 0x937E, 0x999D -> { + // backward half, back right safe + s.setParam("safe", bossFacing.plusEighths(3)); + s.updateCall(backwardHalfRight, e1); + } + } + }); + + private final ModifiableCallout bumpOnYou = ModifiableCallout.durationBasedCall("Drum of Vollok: Knockback on You", "Knock Buddy Back"); + private final ModifiableCallout getBumped = ModifiableCallout.durationBasedCall("Drum of Vollok: Knockback not on You", "Get Knocked Back"); + + @AutoFeed + private final SequentialTrigger drumOfVollokSq = SqtTemplates.sq(30_000, + AbilityCastStart.class, acs -> acs.abilityIdMatches(0x938E), + (e1, s) -> { + var bumps = s.waitEventsQuickSuccession(4, AbilityCastStart.class, acs -> acs.abilityIdMatches(0x938F)); + AbilityCastStart myBump = bumps.stream().filter(bump -> bump.getTarget().isThePlayer()).findFirst().orElse(null); + if (myBump != null) { + s.updateCall(bumpOnYou, myBump); + } + else { + s.updateCall(getBumped, bumps.isEmpty() ? e1 : bumps.get(0)); + } + }); + + private final ModifiableCallout burningChainsInitial = new ModifiableCallout<>("Burning Chains Initial", "Stack"); + @PlayerStatusCallout(0x301) + private final ModifiableCallout burningChains = ModifiableCallout.durationBasedCall("Burning Chains", "Break Chains (with {buddy})") + .statusIcon(0x301); + + @AutoFeed + private final SequentialTrigger burningChainSq = SqtTemplates.sq(30_000, + AbilityCastStart.class, acs -> acs.abilityIdMatches(0x9395), + (e1, s) -> { + s.updateCall(burningChainsInitial, e1); + var buff = s.waitEvent(BuffApplied.class, ba -> ba.buffIdMatches(0x301) && ba.getTarget().isThePlayer()); + var tether = s.waitEvent(TetherEvent.class, te -> te.tetherIdMatches(0x80) && te.eitherTargetMatches(XivCombatant::isThePlayer)); + XivCombatant buddy = tether.getTargetMatching(cbt -> !cbt.isThePlayer()); + s.setParam("buddy", buddy); + s.updateCall(burningChains, buff); + }); } diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/events/actlines/events/CastLocationDataEvent.java b/xivsupport/src/main/java/gg/xp/xivsupport/events/actlines/events/CastLocationDataEvent.java index 3e9fc935037e..300d675e33f2 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/events/actlines/events/CastLocationDataEvent.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/events/actlines/events/CastLocationDataEvent.java @@ -56,4 +56,13 @@ public XivAbility getAbility() { public XivCombatant getSource() { return event.getSource(); } + + @Override + public String toString() { + return "CastLocationDataEvent{" + + "id=" + event.getAbility().getId() + + ", pos=" + pos + + ", heading=" + heading + + '}'; + } } diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/events/actlines/events/DescribesCastLocation.java b/xivsupport/src/main/java/gg/xp/xivsupport/events/actlines/events/DescribesCastLocation.java index 620651af727a..f9ee216f3a67 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/events/actlines/events/DescribesCastLocation.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/events/actlines/events/DescribesCastLocation.java @@ -31,4 +31,13 @@ public interface DescribesCastLocation { sb.append(" Raidwide"); } + case CROSS -> { + sb.append(" Cross"); + } case UNKNOWN -> { sb.append(" Unknown (").append(ai.castType()).append(", ").append(ai.xAxisModifier()).append(')'); }