Skip to content

Commit

Permalink
Codcar improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
xpdota committed Dec 29, 2024
1 parent d3b58ae commit dc5f60c
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import gg.xp.xivsupport.events.actlines.events.HasDuration;
import gg.xp.xivsupport.events.actlines.events.WipeEvent;
import gg.xp.xivsupport.events.misc.pulls.PullStartedEvent;
import org.apache.commons.lang3.function.TriConsumer;
import org.apache.commons.lang3.mutable.MutableInt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -117,6 +118,26 @@ void reset() {
};
}

public static <X> SequentialTrigger<BaseEvent> selfManagedMultiInvocation(
int timeoutMs,
Class<X> startType,
Predicate<X> startCondition,
TriConsumer<X, SequentialTriggerController<BaseEvent>, Integer> trigger) {
MutableInt mint = new MutableInt();
BiConsumer<X, SequentialTriggerController<BaseEvent>> combined = (e1, s) -> {
int index = mint.getAndIncrement();
trigger.accept(e1, s, index);
};
return new AutoWipeSequentialTrigger<>(timeoutMs, startType, startCondition, combined) {
@Override
void reset() {
super.reset();
mint.setValue(0);
}
};

}

/**
* Trigger template for when you want one call at the start of a cast bar, then
* another call at the end of the cast bar.
Expand Down Expand Up @@ -145,7 +166,8 @@ public static SequentialTrigger<BaseEvent> beginningAndEndingOfCast(
* @return A no-op trigger.
*/
public static SequentialTrigger<BaseEvent> nothing() {
return sq(10_000, BaseEvent.class, be -> false, (e1, s) -> {});
return sq(10_000, BaseEvent.class, be -> false, (e1, s) -> {
});
}

private static class AutoWipeSequentialTrigger<X> extends SequentialTrigger<BaseEvent> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public boolean enabled(EventContext context) {
s.updateCall(isFront ? grimEmbraceFrontInitial : grimEmbraceRearInitial, b);
s.waitDuration(b.remainingDurationPlus(Duration.ofSeconds(-5)));
s.updateCall(isFront ? grimEmbraceFrontSoon : grimEmbraceRearSoon, b);
s.waitDuration(b.remainingDurationPlus(Duration.ofMillis(-1_200)));
s.waitDuration(b.remainingDurationPlus(Duration.ofMillis(-1_000)));
s.updateCall(isFront ? grimEmbraceFrontMove : grimEmbraceRearMove, b);
});
});
Expand Down Expand Up @@ -220,8 +220,7 @@ public boolean enabled(EventContext context) {
private final SequentialTrigger<BaseEvent> floodOfDarknessAddsSq = SqtTemplates.sq(30_000,
AbilityCastStart.class, acs -> acs.abilityIdMatches(0x9E37),
(e1, s) -> {
// TODO
if (doWeCareAboutStygian(e1.getSource()) || state.playerJobMatches(Job::caresAboutInterrupt)) {
if (doWeCareAboutStygian(e1.getSource()) && state.playerJobMatches(Job::caresAboutInterrupt)) {
RawModifiedCallout<AbilityCastStart> call = s.updateCall(floodOfDarknessAdds, e1);
// Unfortunately, AbilityCastCancel currently does not work for interrupts, so we need to get creative
s.waitEventsUntil(1, AbilityUsedEvent.class, aue -> {
Expand Down Expand Up @@ -336,14 +335,14 @@ private boolean doWeCareAboutStygian(XivCombatant combatant) {
}

@AutoFeed
private final SequentialTrigger<BaseEvent> sq = SqtTemplates.sq(30_000,
AbilityCastStart.class, acs -> acs.abilityIdMatches(0x9E20, 0x9E23),
(e1, s) -> {
private final SequentialTrigger<BaseEvent> sq = SqtTemplates.selfManagedMultiInvocation(30_000,
AbilityCastStart.class, acs -> {
return acs.abilityIdMatches(0x9E20, 0x9E23)
&& doWeCareAboutStygian(acs.getSource());
},
(e1, s, count) -> {
XivCombatant npc = e1.getSource();
boolean isEast = npc.getPos().x() > 0;
if (!doWeCareAboutStygian(npc)) {
return;
}

var mech1 = ArtOfDarknessMech.forHm(s.waitEvent(HeadMarkerEvent.class, hme -> hme.getTarget().equals(npc)));
ModifiableCallout<?> mc1 = calloutForMech(mech1, isEast);
Expand Down Expand Up @@ -381,20 +380,21 @@ else if (mech == ArtOfDarknessMech.PROTEANS) {
RawModifiedCallout<?> mc2a = s.call(mc2);
mc2a.setReplaces(call2);
// Debounce
s.waitMs(1000);
s.waitMs(1300);

waitMech.accept(mech2);

mc2a.forceExpire();
RawModifiedCallout<?> mc3a = s.call(mc3);
mc3a.setReplaces(call3);
s.waitMs(1000);
s.waitMs(1300);

waitMech.accept(mech3);

RawModifiedCallout<?> towerCall = s.call(artOfDarknessTowers);
towerCall.setReplaces(mc3a);

if (count == 0) {
RawModifiedCallout<?> towerCall = s.call(artOfDarknessTowers);
towerCall.setReplaces(mc3a);
}
});

private final ModifiableCallout<HeadMarkerEvent> evilSeedOnYou = new ModifiableCallout<>("Evil Seed: On You", "Drop Bramble");
Expand All @@ -413,30 +413,38 @@ else if (mech == ArtOfDarknessMech.PROTEANS) {
}, () -> s.updateCall(evilSeedNotOnYou));
});

// TODO: might be nice to have a player-to-player version of this that calls who you're tethered to
@PlayerStatusCallout(value = 0x1BD, cancellable = true)
private final ModifiableCallout<BuffApplied> thornyVine = ModifiableCallout.durationBasedCall("Thorny Vine", "Break Tether");

private final ModifiableCallout<AbilityCastStart> lateralCore = ModifiableCallout.durationBasedCallWithOffset("Lateral-Core Phaser", "Sides then In", Duration.ofMillis(2000));
private final ModifiableCallout<AbilityCastStart> coreLateral = ModifiableCallout.durationBasedCallWithOffset("Core-Lateral Phaser", "In then Sides", Duration.ofMillis(2000));
private final ModifiableCallout<?> coreWithTower = new ModifiableCallout<>("Lateral-Core: Follow-Up with Tower", "In then Tower");
private final ModifiableCallout<?> lateralWithTower = new ModifiableCallout<>("Core-Lateral: Follow-Up with Tower", "Out and Tower");
private final ModifiableCallout<?> core = new ModifiableCallout<>("Lateral-Core: Follow-Up", "In");
private final ModifiableCallout<?> lateral = new ModifiableCallout<>("Core-Lateral: Follow-Up", "Out");
private final ModifiableCallout<?> coreWithPivot = new ModifiableCallout<>("Lateral-Core: Follow-Up with Pivot", "In then {rotationSafe}");
private final ModifiableCallout<?> lateralWithPivot = new ModifiableCallout<>("Core-Lateral: Follow-Up with Pivot", "Out and {rotationSafe}");

@AutoFeed
private final SequentialTrigger<BaseEvent> phaser = SqtTemplates.sq(60_000,
AbilityCastStart.class, acs -> acs.abilityIdMatches(0x9E2F, 0x9E30),
(e1, s) -> {
if (!doWeCareAboutStygian(e1.getSource())) {
return;
}
private final SequentialTrigger<BaseEvent> phaser = SqtTemplates.selfManagedMultiInvocation(60_000,
AbilityCastStart.class, acs -> acs.abilityIdMatches(0x9E2F, 0x9E30)
&& doWeCareAboutStygian(acs.getSource()),
(e1, s, count) -> {
log.info("Phaser #{}", count);
boolean sidesFirst = e1.abilityIdMatches(0x9E2F);
AbilityCastStart pivotCast = casts.getActiveCastById(0x9E13, 0x9E15).stream().map(CastTracker::getCast).findFirst()
.orElse(null);
if (pivotCast == null) {
// TODO: there is a version of this with neither towers nor pivot
s.updateCall(sidesFirst ? lateralCore : coreLateral, e1);
s.waitCastFinished(casts, e1);
s.updateCall(sidesFirst ? coreWithTower : lateralWithTower);
s.waitEvent(AbilityUsedEvent.class, aue -> aue.abilityIdMatches(0x9E31));
if (count >= 2) {
s.updateCall(sidesFirst ? core : lateral);
}
else {
s.updateCall(sidesFirst ? coreWithTower : lateralWithTower);
}
}
else {
boolean cw = pivotCast.abilityIdMatches(0x9E13);
Expand Down

0 comments on commit dc5f60c

Please sign in to comment.