Skip to content

Commit

Permalink
use an APL to estimate unavoidable downtime for Cata Arms
Browse files Browse the repository at this point in the history
Arms is a downtime spec in Cata: you do not have enough cooldowns
or Rage to fill every GCD, so some are unavoidably empty.

this uses an APL-based approach to attempt to identify situations
where there isn't an appropriate spell to cast. such periods are then
added to the `AlwaysBeCasting` as "uptime" regions, boosting overall uptime
  • Loading branch information
emallson committed Nov 2, 2024
1 parent d334e93 commit 700ab66
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
import CLASSIC_SPELLS from 'common/SPELLS/classic';
import { ThresholdStyle, type NumberThreshold } from 'parser/core/ParseResults';
import { AplChecker, build } from 'parser/shared/metrics/apl';
import CoreAlwaysBeCasting from 'parser/shared/modules/AlwaysBeCasting';
import SpellUsable from 'parser/shared/modules/SpellUsable';
import * as cnd from 'parser/shared/metrics/apl/conditions';
import RESOURCE_TYPES from 'game/RESOURCE_TYPES';
import { Options } from 'parser/core/Analyzer';
import Events, { AnyEvent, FightEndEvent } from 'parser/core/Events';

export default class AlwaysBeCasting extends CoreAlwaysBeCasting.withDependencies({
spellUsable: SpellUsable,
}) {
private aplChecker;

private lastUptimeStart?: number;

constructor(options: Options) {
super(options);

this.aplChecker = new AplChecker(apl, this.owner.info);

this.addEventListener(Events.any, this.processAplDowntime);
this.addEventListener(Events.fightend, this.finalize);
}

export default class AlwaysBeCasting extends CoreAlwaysBeCasting {
get downtimeSuggestionThresholds(): NumberThreshold {
return {
actual: this.downtimePercentage,
Expand All @@ -13,4 +35,60 @@ export default class AlwaysBeCasting extends CoreAlwaysBeCasting {
style: ThresholdStyle.PERCENTAGE,
};
}

private processAplDowntime(event: AnyEvent) {
// the idea here is that we add "uptime" from the point where the APL says "don't cast anything" to the next point where the APL says "cast something"
const expectedCast = this.aplChecker.expectedCast();

this.aplChecker.processEvent(event);

if (expectedCast && this.lastUptimeStart && event.timestamp >= this.owner.fight.start_time) {
// apl: "cast something"
if (this.lastUptimeStart !== event.timestamp) {
this.addNewUptime(this.lastUptimeStart, event.timestamp, false, 'Arms APL-based downtime');
}
this.lastUptimeStart = undefined;
} else if (!expectedCast && !this.lastUptimeStart) {
// apl: "don't cast anything"
this.lastUptimeStart = event.timestamp;
}
}

private finalize(event: FightEndEvent) {
if (this.lastUptimeStart) {
this.addNewUptime(
this.lastUptimeStart,
event.timestamp,
false,
'Arms APL-based downtime (finalizer)',
);
}
}
}

const apl = build([
{
spell: CLASSIC_SPELLS.REND,
condition: cnd.debuffMissing(CLASSIC_SPELLS.REND_DEBUFF),
},
{
spell: CLASSIC_SPELLS.COLOSSUS_SMASH,
condition: cnd.debuffMissing(CLASSIC_SPELLS.COLOSSUS_SMASH),
},
CLASSIC_SPELLS.MORTAL_STRIKE,
{
spell: CLASSIC_SPELLS.EXECUTE,
condition: cnd.inExecute(),
},
{
spell: CLASSIC_SPELLS.OVERPOWER,
condition: cnd.buffPresent(CLASSIC_SPELLS.TASTE_FOR_BLOOD),
},
{
spell: CLASSIC_SPELLS.HEROIC_STRIKE,
condition: cnd.or(
cnd.buffPresent(CLASSIC_SPELLS.BATTLE_TRANCE),
cnd.hasResource(RESOURCE_TYPES.RAGE, { atLeast: 800 }, 0),
),
},
]);
10 changes: 10 additions & 0 deletions src/common/SPELLS/classic/warrior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ const spells = {
name: 'Taste for Blood',
icon: 'ability_rogue_hungerforblood.jpg.jpg',
},
BATTLE_TRANCE: {
id: 12964,
name: 'Battle Trance',
icon: 'inv_helmet_06',
},
PUMMEL: {
id: 6552,
name: 'Pummel',
Expand All @@ -130,6 +135,11 @@ const spells = {
name: 'Rend',
icon: 'ability_gouge.jpg',
},
REND_DEBUFF: {
id: 94009,
name: 'Rend',
icon: 'ability_gouge.jpg',
},
RETALIATION: {
id: 20230,
name: 'Retaliation',
Expand Down
2 changes: 1 addition & 1 deletion src/parser/shared/modules/AlwaysBeCasting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class AlwaysBeCasting extends Analyzer {
}

/** Validates and logs inputs, then adds to activeTimeEdges list */
private addNewUptime(start: number, end: number, isHealingAbility: boolean, reason: string) {
protected addNewUptime(start: number, end: number, isHealingAbility: boolean, reason: string) {
DEBUG &&
console.log(
`Active Time: adding from ${reason}: ${this.owner.formatTimestamp(start, 3)} to ${this.owner.formatTimestamp(end, 3)}${isHealingAbility ? ' (heal)' : ''}`,
Expand Down

0 comments on commit 700ab66

Please sign in to comment.