Skip to content

Commit

Permalink
Merge pull request #522 from IminhaK/master
Browse files Browse the repository at this point in the history
Arcadion initial
  • Loading branch information
xpdota authored Jul 19, 2024
2 parents 5dcd1f3 + 349e26e commit 8e18d06
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package gg.xp.xivsupport.triggers.Arcadion;

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;
import gg.xp.xivsupport.callouts.ModifiableCallout;
import gg.xp.xivsupport.events.actlines.events.AbilityCastStart;
import gg.xp.xivsupport.events.actlines.events.AbilityUsedEvent;
import gg.xp.xivsupport.events.actlines.events.SnapshotLocationDataEvent;
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.models.Position;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

@CalloutRepo(name = "M1N", duty = KnownDuty.M1N)
public class M1N extends AutoChildEventHandler implements FilteredEventHandler {
public static final Logger log = LoggerFactory.getLogger(M1N.class);

@NpcCastCallout(0x9309)
private final ModifiableCallout<AbilityCastStart> oneTwoPawEastWest = ModifiableCallout.durationBasedCall("One-Two Paw: West safe", "West then East");
@NpcCastCallout(0x930C)
private final ModifiableCallout<AbilityCastStart> oneTwoPawWestEast = ModifiableCallout.durationBasedCall("One-Two Paw: East safe", "East then West");
@NpcCastCallout(0x0)
private final ModifiableCallout<AbilityCastStart> blackCatCrossingCardInter = ModifiableCallout.durationBasedCall("Black Cat Crossing: Inter safe", "Intercardinals then cardinals");
@NpcCastCallout(0x930F)
private final ModifiableCallout<AbilityCastStart> blackCatCrossingInterCard = ModifiableCallout.durationBasedCall("Black Cat Crossing: Card safe", "Cardinals then intercardinals");
@NpcCastCallout({0x9321, 0x931F})
private final ModifiableCallout<AbilityCastStart> leapingOneTwoPawEastWest = ModifiableCallout.durationBasedCall("Leaping One-Two Paw: West safe", "West then East");
@NpcCastCallout({0x9320, 0x9322}) //dont know what the difference is (maybe leap direction?)
private final ModifiableCallout<AbilityCastStart> leapingOneTwoPawWestEast = ModifiableCallout.durationBasedCall("Leaping One-Two Paw: East safe", "East then West");
@NpcCastCallout(0x0) //TODO: confirm these
private final ModifiableCallout<AbilityCastStart> leapingBlackCatCrossingCardInter = ModifiableCallout.durationBasedCall("Leaping Black Cat Crossing: Inter safe", "Inter then Cardinal");
@NpcCastCallout(0x9329)
private final ModifiableCallout<AbilityCastStart> leapingBlackCatCrossingInterCard = ModifiableCallout.durationBasedCall("Leaping Black Cat Crossing: Card safe", "Cardinal then inter");

public M1N(XivState state) {
this.state = state;
}
private final XivState state;

@Override
public boolean enabled(EventContext context) {
return state.dutyIs(KnownDuty.M1N);
}

private final ModifiableCallout<?> startSW = new ModifiableCallout<>("Mouser: Start SW", "Start South West");
private final ModifiableCallout<?> startSE = new ModifiableCallout<>("Mouser: Start SE", "Start South East");
private final ModifiableCallout<?> swSafe = new ModifiableCallout<>("Mouser: SW", "South West");
private final ModifiableCallout<?> seSafe = new ModifiableCallout<>("Mouser: SE", "South East");

private boolean isSouthernTile(Position pos) {
return pos.getY() > 100 //below the center horizontal
&& pos.getX() < 106 //clamps to middle two tiles
&& pos.getX() > 94;
}
private boolean isWestTile(Position pos) {
return pos.getX() < 100;
}

@AutoFeed
private final SequentialTrigger<BaseEvent> mouser = SqtTemplates.sq(20_000, AbilityCastStart.class,
acs -> acs.abilityIdMatches(0x9313),
(e1, s) -> {
log.info("Mouser: Start");
//check both damage hits, plus the shatter hit. may be double or single movement
List<AbilityUsedEvent> hits = s.waitEvents(3, AbilityUsedEvent.class, aue ->
aue.abilityIdMatches(0x9315, 0x996B)
&& isSouthernTile(aue.getTarget().getPos()));

Position hit1Pos = hits.get(0).getTarget().getPos();
Position hit2Pos = hits.get(1).getTarget().getPos();
Position hit3Pos = hits.get(2).getTarget().getPos();

//which tile was most recently hit
boolean wasWest = true;
//Starting position
if(isWestTile(hit1Pos))
s.updateCall(startSE);
else {
s.updateCall(startSW);
wasWest = false;
}

//Wait for each southern mouser cast
//hit 1
s.waitEvent(SnapshotLocationDataEvent.class, slde ->
slde.originalEvent().abilityIdMatches(0x9316, 0x94A5)
&& isSouthernTile(slde.getPos()));
//Call new if its different
if(isWestTile(hit2Pos) && !wasWest)
s.updateCall(seSafe);
else if(!isWestTile(hit2Pos) && wasWest)
s.updateCall(swSafe);

wasWest = isWestTile(hit2Pos);

//hit 2
s.waitEvent(SnapshotLocationDataEvent.class, slde ->
slde.originalEvent().abilityIdMatches(0x9316, 0x94A5)
&& isSouthernTile(slde.getPos()));
//Call new if its different
if(isWestTile(hit3Pos) && !wasWest)
s.updateCall(seSafe);
else if(!isWestTile(hit3Pos) && wasWest)
s.updateCall(swSafe);

//hit 3, dont need to move again
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package gg.xp.xivsupport.triggers.Arcadion;

import gg.xp.reevent.events.EventContext;
import gg.xp.reevent.scan.AutoChildEventHandler;
import gg.xp.reevent.scan.FilteredEventHandler;
import gg.xp.xivdata.data.duties.*;
import gg.xp.xivsupport.callouts.CalloutRepo;
import gg.xp.xivsupport.callouts.ModifiableCallout;
import gg.xp.xivsupport.events.actlines.events.AbilityCastStart;
import gg.xp.xivsupport.events.state.XivState;
import gg.xp.xivsupport.events.triggers.support.NpcCastCallout;

@CalloutRepo(name = "M3N", duty = KnownDuty.M3N)
public class M3N extends AutoChildEventHandler implements FilteredEventHandler {

@NpcCastCallout(0x9AD4)
private final ModifiableCallout<AbilityCastStart> brutalLariatWest = ModifiableCallout.durationBasedCall("Brutal Lariat: East safe", "East");
@NpcCastCallout(0x9AD5)
private final ModifiableCallout<AbilityCastStart> brutalLariatEast = ModifiableCallout.durationBasedCall("Brutal Lariat: West safe", "West");
@NpcCastCallout(0x9ADC)
private final ModifiableCallout<AbilityCastStart> lariatComboWestEast = ModifiableCallout.durationBasedCall("Lariat Combo: East then west", "East then West");
@NpcCastCallout(0x9ADE)
private final ModifiableCallout<AbilityCastStart> lariatComboEastWest = ModifiableCallout.durationBasedCall("Lariat Combo: West then east", "West then East");
@NpcCastCallout(0x9ADD)
private final ModifiableCallout<AbilityCastStart> lariatComboWestWest = ModifiableCallout.durationBasedCall("Lariat Combo: East safe", "East, stay east");
@NpcCastCallout(0x9ADF)
private final ModifiableCallout<AbilityCastStart> lariatComboEastEast = ModifiableCallout.durationBasedCall("Lariat Combo: West safe", "West, stay west");

public M3N(XivState state) {
this.state = state;
}
private final XivState state;

@Override
public boolean enabled(EventContext context) {
return state.dutyIs(KnownDuty.M3N);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package gg.xp.xivsupport.triggers.Arcadion;

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;
import gg.xp.xivsupport.callouts.ModifiableCallout;
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.vfx.StatusLoopVfxApplied;
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.NpcAbilityUsedCallout;
import gg.xp.xivsupport.events.triggers.support.NpcCastCallout;
import gg.xp.xivsupport.models.ArenaPos;
import gg.xp.xivsupport.models.ArenaSector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

@CalloutRepo(name = "M4N", duty = KnownDuty.M4N)
public class M4N extends AutoChildEventHandler implements FilteredEventHandler {
public static final Logger log = LoggerFactory.getLogger(M4N.class);

@NpcCastCallout({0x92BD, 0x92BF}) //second ID is while wings are active
private final ModifiableCallout<AbilityCastStart> sidewiseSparkWest = ModifiableCallout.durationBasedCall("Sidewise Spark: East safe", "East safe");
@NpcCastCallout({0x92BC, 0x92BE})
private final ModifiableCallout<AbilityCastStart> sidewiseSparkEast = ModifiableCallout.durationBasedCall("Sidewise Spark: West safe", "West safe");
@NpcAbilityUsedCallout(0x92AB)
private final ModifiableCallout<AbilityUsedEvent> stampedingThunderWest = new ModifiableCallout<>("Stampeding Thunder: Go East", "East safe");
@NpcAbilityUsedCallout(0x92AC)
private final ModifiableCallout<AbilityUsedEvent> stampedingThunderEast = new ModifiableCallout<>("Stampeding Thunder: Go West", "West safe");

public M4N(XivState state) {
this.state = state;
}
private final XivState state;

@Override
public boolean enabled(EventContext context) {
return state.dutyIs(KnownDuty.M4N);
}

public static final List<Long> validStacks = List.of(723L,724L);

public ArenaSector getSafeDirectionForBA(BuffApplied ba) {
//723 hits north, go south
//724 hits south, go north
long stacks = ba.getRawStacks();
return stacks == 723 ? ArenaSector.SOUTH : ArenaSector.NORTH;
}

private final ModifiableCallout<?> gunStart = new ModifiableCallout<>("Gun Blasts: Start", "Start {safe}");
private final ModifiableCallout<?> gunSafe = new ModifiableCallout<>("Gun Blasts: Next Safe", "{safe}");

@AutoFeed
private final SequentialTrigger<BaseEvent> gunBlast = SqtTemplates.sq(30_000, AbilityCastStart.class,
acs -> acs.abilityIdMatches(0x92B0, 0x9B4F, 0x9B56, 0x92AD, 0x9B55, 0x9B57),
(e1, s) -> {
log.info("Gun Blasts: Start");
int iterations = switch((int)e1.getAbility().getId()) {
case 0x92B0, 0x92AD -> 2;
case 0x9B4F, 0x9B55 -> 3;
case 0x9B56, 0x9B57 -> 4;
default -> 0;
};

//Buff 0xB9A
ArenaSector buff1 = getSafeDirectionForBA(s.waitEvent(BuffApplied.class, ba -> validStacks.contains(ba.getRawStacks()) && ba.buffIdMatches(0xB9A)));
log.info("Gun Blasts Start: {}", buff1);
s.setParam("safe", buff1);
s.updateCall(gunStart);

List<BuffApplied> furtherBuffs = s.waitEvents(iterations, BuffApplied.class, ba -> validStacks.contains(ba.getRawStacks()) && ba.buffIdMatches(0xB9A));

boolean wasNorth = buff1 != ArenaSector.SOUTH;
//repeats up to 4 times
for(int i = 0; i < iterations; i++) {
//many IDs. Some may be missing. Ability name "Wicked Cannon"
//0x4E40, 0x9BAC, 0x92AE, 0x9BBE, 0x92AF
s.waitEvent(AbilityUsedEvent.class, aue -> aue.abilityIdMatches(0x4E40, 0x9BAC, 0x92AE, 0x9BBE, 0x92AF) && aue.isFirstTarget());
ArenaSector safeSide = getSafeDirectionForBA(furtherBuffs.get(i));
log.info("Gun Blasts {}: {}", i, safeSide);
if(wasNorth && safeSide == ArenaSector.SOUTH) {
s.setParam("safe", ArenaSector.SOUTH);
s.updateCall(gunSafe);
wasNorth = false;
}
else if(!wasNorth && safeSide == ArenaSector.NORTH) {
s.setParam("safe", ArenaSector.NORTH);
s.updateCall(gunSafe);
wasNorth = true;
}
}
});

public static final List<Long> validIDs = List.of(793L, 794L);

private final ArenaPos arenaPos = new ArenaPos(100, 100, 5, 5);

private final ModifiableCallout<?> shadowSafe = new ModifiableCallout<>("Shadow's Sabbath", "{safe} safe");

@AutoFeed
//TODO:these calls overlap slightly when it does four in a row, especially when she also does a cleave
private final SequentialTrigger<BaseEvent> shadowsSabbeth = SqtTemplates.sq(20_000, StatusLoopVfxApplied.class,
slva -> validIDs.contains(slva.getStatusLoopVfx().getId()),
(e1, s) -> {
ArenaSector addDir = arenaPos.forCombatant(e1.getTarget());
boolean hittingLeft = e1.getStatusLoopVfx().getId() == 794;
//794 left
//793 right
ArenaSector safeDir = switch(addDir) {
case SOUTH -> hittingLeft ? ArenaSector.EAST : ArenaSector.WEST;
case NORTH -> hittingLeft ? ArenaSector.WEST : ArenaSector.EAST;
case EAST -> hittingLeft ? ArenaSector.NORTH : ArenaSector.SOUTH;
case WEST -> hittingLeft ? ArenaSector.SOUTH : ArenaSector.NORTH;
default -> ArenaSector.UNKNOWN;
};

s.setParam("safe", safeDir);
s.updateCall(shadowSafe);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public enum KnownDuty implements Duty {
DtEx1("EX1", 1196, Expansion.DT, DutyType.TRIAL_EX),
DtEx2("EX2", 1201, Expansion.DT, DutyType.TRIAL_EX),

M1N("M1N", 1225,Expansion.DT, DutyType.RAID),
M2N("M2N", 1227,Expansion.DT, DutyType.RAID),
M3N("M3N", 1229,Expansion.DT, DutyType.RAID),
M4N("M4N", 1231,Expansion.DT, DutyType.RAID),

;

private final String name;
Expand Down

0 comments on commit 8e18d06

Please sign in to comment.