Skip to content

Commit

Permalink
M4S triggers
Browse files Browse the repository at this point in the history
  • Loading branch information
xpdota committed Aug 1, 2024
1 parent 599f21e commit 99d8c99
Show file tree
Hide file tree
Showing 6 changed files with 597 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ private int getPlayerHeartStacks() {
}

private final ModifiableCallout<AbilityCastStart> temptingTwistInitial = ModifiableCallout.durationBasedCall("Tempting Twist: Initial", "In");
// private final ModifiableCallout<?> temptingTwistAvoidBlobs = new ModifiableCallout<>("Tempting Twist: Initial", "Avoid Blobs");
// private final ModifiableCallout<?> temptingTwistAvoidBlobs = new ModifiableCallout<>("Tempting Twist: Initial", "Avoid Blobs");
private final ModifiableCallout<AbilityCastStart> beelineInitial = ModifiableCallout.durationBasedCall("Beeline: Initial", "Out of Middle");
// private final ModifiableCallout<?> beelineAvoidBlobs = new ModifiableCallout<>("Tempting Twist: Initial", "In - Avoid Blobs");
// private final ModifiableCallout<?> beelineAvoidBlobs = new ModifiableCallout<>("Tempting Twist: Initial", "In - Avoid Blobs");
private final ModifiableCallout<?> spread = new ModifiableCallout<>("Poison: Spread", "Spread", 10_000);
private final ModifiableCallout<?> buddies = new ModifiableCallout<>("Poison: Stack", "Buddy", 10_000);

Expand All @@ -114,6 +114,7 @@ private int getPlayerHeartStacks() {
// Wait
PoisonBuff pb = getPoisonBuff();
// s.waitMs(1000);
// TODO: reports of this being broken
if (pb == PoisonBuff.SPREAD) {
s.updateCall(spread);
}
Expand Down Expand Up @@ -147,7 +148,7 @@ private int getPlayerHeartStacks() {
private final ModifiableCallout<AbilityCastStart> beeSting = ModifiableCallout.durationBasedCall("Bee Sting", "Light Parties");

private final ModifiableCallout<?> outCards = new ModifiableCallout<>("Center/Outer Stage: Out+Cardinals", "Out+Cardinals");
// private final ModifiableCallout<?> outInter = new ModifiableCallout<>("Center/Outer Stage: Out+Intercards", "Out+Intercards");
// private final ModifiableCallout<?> outInter = new ModifiableCallout<>("Center/Outer Stage: Out+Intercards", "Out+Intercards");
// private final ModifiableCallout<?> inCards = new ModifiableCallout<>("Center/Outer Stage: In+Cardinals", "In+Cardinals");
private final ModifiableCallout<?> inInter = new ModifiableCallout<>("Center/Outer Stage: In+Intercards", "In+Intercards");
private final ModifiableCallout<?> cross = new ModifiableCallout<>("Center/Outer Stage: Cross", "Out+Intercards");
Expand Down Expand Up @@ -185,7 +186,6 @@ private int getPlayerHeartStacks() {
});

private static final Duration hblOffset = Duration.ofMillis(8200);
// TODO: these have extra cast time
private final ModifiableCallout<AbilityCastStart> hbl1Initial = ModifiableCallout.durationBasedCallWithOffset("Honey B. Live: 1st Beat", "Raidwide", hblOffset);
private final ModifiableCallout<?> hb1towers = new ModifiableCallout<>("Honey B. Live: 1st Beat: Take Towers", "Take {towers} Towers");
private final ModifiableCallout<?> hb1noTowers = new ModifiableCallout<>("Honey B. Live: 1st Beat: Avoid Towers", "Avoid Towers");
Expand Down Expand Up @@ -300,7 +300,7 @@ private int getPlayerHeartStacks() {
// Given that there is a magic vuln, I do not see how there can be different strategies for this mech
// 4 people have short defa, 4 have long defa
int defa = 0xF5E;
List<BuffApplied> all = s.waitEventsQuickSuccession(8, BuffApplied.class, ba -> ba.buffIdMatches(defa));
// List<BuffApplied> all = s.waitEventsQuickSuccession(8, BuffApplied.class, ba -> ba.buffIdMatches(defa));
BuffApplied playerBuff = buffs.findStatusOnTarget(state.getPlayer(), defa);
// List<BuffApplied> shorts = all.stream().filter(ba -> ba.getInitialDuration().toSeconds() < 30).toList();
// List<BuffApplied> longs = all.stream().filter(ba -> ba.getInitialDuration().toSeconds() > 30).toList();
Expand Down Expand Up @@ -359,7 +359,7 @@ else if (playerBuff.getInitialDuration().toSeconds() < 30) {
.disabledByDefault()
.extendedDescription("This is an optional callout which will call out every pair to pop.");

private int nisiBuffGroup(BuffApplied buff) {
private static int nisiBuffGroup(BuffApplied buff) {
return ((int) buff.getInitialDuration().toSeconds() + 4) / 16;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@
import gg.xp.xivsupport.events.actlines.events.AbilityCastStart;
import gg.xp.xivsupport.events.actlines.events.AbilityUsedEvent;
import gg.xp.xivsupport.events.actlines.events.BuffApplied;
import gg.xp.xivsupport.events.actlines.events.BuffRemoved;
import gg.xp.xivsupport.events.actlines.events.TetherEvent;
import gg.xp.xivsupport.events.state.XivState;
import gg.xp.xivsupport.events.state.combatstate.StatusEffectRepository;
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.models.ArenaPos;
import gg.xp.xivsupport.models.XivCombatant;
import gg.xp.xivsupport.models.ArenaSector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

@CalloutRepo(name = "M3S", duty = KnownDuty.M3S)
public class M3S extends AutoChildEventHandler implements FilteredEventHandler {
private static final Logger log = LoggerFactory.getLogger(M3S.class);
Expand All @@ -47,10 +47,14 @@ public boolean enabled(EventContext context) {
private static final long TODO = 0;

@NpcCastCallout(0x93EB)
private final ModifiableCallout<AbilityCastStart> quadrupleLariat = ModifiableCallout.durationBasedCall("Quadruple Lariat", "In and Partners");
private final ModifiableCallout<AbilityCastStart> quadrupleLariatIn = ModifiableCallout.durationBasedCall("Quadruple Lariat In", "In and Partners");
@NpcCastCallout(0x93EA)
private final ModifiableCallout<AbilityCastStart> quadrupleLariatOut = ModifiableCallout.durationBasedCall("Quadruple Lariat Out", "Out and Partners");
// Boss cast is 93D8 but it is shorter duration
@NpcCastCallout(0x93E9)
private final ModifiableCallout<AbilityCastStart> octupleLariatIn = ModifiableCallout.durationBasedCall("Octuple Lariat In", "In and Spread");
@NpcCastCallout(0x93E8)
private final ModifiableCallout<AbilityCastStart> octupleLariat = ModifiableCallout.durationBasedCall("Octuple Lariat", "Out and Spread");
private final ModifiableCallout<AbilityCastStart> octupleLariatOut = ModifiableCallout.durationBasedCall("Octuple Lariat Out", "Out and Spread");
@NpcCastCallout(0x9425)
private final ModifiableCallout<AbilityCastStart> brutalImpact = ModifiableCallout.durationBasedCall("Brutal Impact", "Raidwide - Multi Hit");
@NpcCastCallout(0x9423)
Expand All @@ -67,18 +71,52 @@ public boolean enabled(EventContext context) {
@NpcCastCallout(0x93ED)
private final ModifiableCallout<AbilityCastStart> octoboomDiveKb = ModifiableCallout.durationBasedCall("Quadroboom Dive (KB)", "Knockback into Spreads");

private final ModifiableCallout<?> tagTeamSafeSpot = new ModifiableCallout<>("Tag Team 1: Safe Spot", "{safe} safe");

@AutoFeed
private final SequentialTrigger<BaseEvent> tagTeam = SqtTemplates.multiInvocation(60_000,
AbilityCastStart.class, acs -> acs.abilityIdMatches(0x93E7),
(e1, s) -> {
log.info("Tag team: start");
var tether = s.waitEvent(TetherEvent.class, te -> te.eitherTargetMatches(XivCombatant::isThePlayer));
var tetherAdd = tether.getTargetMatching(cbt -> !cbt.isThePlayer());
log.info("Tethered to: {} at {}", tetherAdd, tetherAdd.getPos());
var otherAdd = state.npcsById(tetherAdd.getbNpcId()).stream().filter(cbt -> !(cbt.equals(tetherAdd))).findFirst().orElseThrow(() -> new RuntimeException("Could not find other add"));
log.info("Other add: {} at {}", otherAdd, otherAdd.getPos());
// The tether units do not move into place until after the "Chain Deathmatch" cast starts
// var tether = s.waitEvent(TetherEvent.class, te -> te.eitherTargetMatches(XivCombatant::isThePlayer));
// var tetherAdd = tether.getTargetMatching(cbt -> !cbt.isThePlayer());
// log.info("Tag team: Tethered to: {}", tetherAdd);
// var otherAdd = state.npcsById(tetherAdd.getbNpcId()).stream().filter(cbt -> !(cbt.equals(tetherAdd))).findFirst().orElseThrow(() -> new RuntimeException("Could not find other add"));
// log.info("Tag team: Other add: {} at {}", otherAdd, otherAdd.getPos());

// The tether comes out earlier, but we can't do anything with the information anyway, so just use the
// buff instead since we don't have to figure out what the real unit is.
BuffApplied myBuff = s.waitEvent(BuffApplied.class, ba -> ba.buffIdMatches(0xFB3) && ba.getTarget().isThePlayer());
List<AbilityCastStart> casts = s.waitEventsQuickSuccession(2, AbilityCastStart.class, acs -> acs.abilityIdMatches(0x9b2c, 0x9b3e));

// The one that we want to get hit by
AbilityCastStart goodCast = casts.stream().filter(acs -> acs.getSource().equals(myBuff.getSource())).findFirst().orElseThrow();
// The one that we don't want to get hit by
AbilityCastStart badCast = casts.stream().filter(acs -> !acs.getSource().equals(myBuff.getSource())).findFirst().orElseThrow();

ArenaSector goodArea = ap.forCombatant(goodCast.getSource()).plusQuads(
// If the enemy is hitting the right, that is 1 quarter CCW
goodCast.abilityIdMatches(0x9b2c) ? -1 : 1
);
ArenaSector badArea = ap.forCombatant(badCast.getSource()).plusQuads(
// If the enemy is hitting the right, that is 1 quarter CCW
badCast.abilityIdMatches(0x9b2c) ? -1 : 1
);

// If good is N, and bad is E, then the spot we want is W, so we take the arc from good to bad, and
// go the opposite way.
ArenaSector neededSpot = goodArea.plusEighths(-goodArea.eighthsTo(badArea));

s.setParam("safe", neededSpot);
s.updateCall(tagTeamSafeSpot);

// Next part is to avoid both hits - is this always the spot that got double hit initially?
// The hits aren't obvious - maybe it's 9B34 lariat combo?
// 9b34/9b2c might just be right?
// 9b35/9b2e might be left?
// At least one seems to be missing its cast location data
// 2c/2e seem to come from the same units that the buff comes from
}, (e1, s) -> {
// Double tether version

Expand Down Expand Up @@ -165,6 +203,13 @@ public boolean enabled(EventContext context) {
*/
/*
Spinny mechanic TBD
need to look at rotation and initial position, plus the cross-tthrough
*/

/*
TODO: bombarian specials
There is a towers + kb mechanic, but you dodge a side cleave instead of 270 at the end
*/
}

Expand Down
Loading

0 comments on commit 99d8c99

Please sign in to comment.