Skip to content

Commit

Permalink
oopsy: add initData support (#5817)
Browse files Browse the repository at this point in the history
  • Loading branch information
g0shu authored Sep 30, 2023
1 parent 8d39935 commit 463e5a1
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 25 deletions.
25 changes: 21 additions & 4 deletions types/oopsy.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,17 @@ export type OopsyTrigger<Data extends OopsyData> =

type MistakeMap = { [mistakeId: string]: string };

type SimpleOopsyTriggerSet = {
export type DataInitializeFunc<Data extends OopsyData> = () => Omit<Data, keyof OopsyData>;

// This helper takes all of the properties in Type and checks to see if they can be assigned to a
// blank object, and if so excludes them from the returned union. The `-?` syntax removes the
// optional modifier from the attribute which prevents `undefined` from being included in the union
// See also: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers
type RequiredFieldsAsUnion<Type> = {
[key in keyof Type]-?: Record<string, never> extends Pick<Type, key> ? never : key;
}[keyof Type];

type SimpleOopsyTriggerSet<Data extends OopsyData> = {
zoneId: ZoneIdType | ZoneIdType[];
zoneLabel?: LocaleText;
damageWarn?: MistakeMap;
Expand All @@ -116,12 +126,19 @@ type SimpleOopsyTriggerSet = {
shareFail?: MistakeMap;
soloWarn?: MistakeMap;
soloFail?: MistakeMap;
};

export type OopsyTriggerSet<Data extends OopsyData> = SimpleOopsyTriggerSet & {
triggers?: OopsyTrigger<Data>[];
};

// If Data contains required properties that are not on OopsyData, require initData
export type OopsyTriggerSet<Data extends OopsyData = OopsyData> =
& SimpleOopsyTriggerSet<Data>
& (RequiredFieldsAsUnion<Data> extends RequiredFieldsAsUnion<OopsyData> ? {
initData?: DataInitializeFunc<Data>;
}
: {
initData: DataInitializeFunc<Data>;
});

export type LooseOopsyTrigger = Partial<
BaseOopsyTrigger<OopsyData, 'None'> & OopsyTriggerRegex<'None'>
>;
Expand Down
33 changes: 32 additions & 1 deletion ui/oopsyraidsy/damage_tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Job, Role } from '../../types/job';
import { Matches, NetMatches } from '../../types/net_matches';
import { CactbotBaseRegExp } from '../../types/net_trigger';
import {
DataInitializeFunc,
LooseOopsyTrigger,
LooseOopsyTriggerSet,
MistakeMap,
Expand Down Expand Up @@ -117,6 +118,10 @@ export class DamageTracker {
private zoneName?: string;
private zoneId: ZoneIdType = ZoneId.MatchAll;
private contentType = 0;
protected dataInitializers: {
file: string;
func: DataInitializeFunc<OopsyData>;
}[] = [];

constructor(
private options: OopsyOptions,
Expand Down Expand Up @@ -153,7 +158,7 @@ export class DamageTracker {
}

GetDataObject(): OopsyData {
return {
const data: OopsyData = {
me: this.me,
job: this.job,
role: this.role,
Expand All @@ -174,6 +179,23 @@ export class DamageTracker {
// Deprecated.
ParseLocaleFloat: parseFloat,
};

let triggerData = {};

for (const initObj of this.dataInitializers) {
const init = initObj.func;
const initData = init();
if (typeof initData === 'object') {
triggerData = {
...triggerData,
...initData,
};
} else {
console.log(`Error in file: ${initObj.file}: these triggers may not work;
initData function returned invalid object: ${init.toString()}`);
}
}
return { ...triggerData, ...data };
}

// TODO: this shouldn't clear timers and triggers
Expand Down Expand Up @@ -673,6 +695,15 @@ export class DamageTracker {
console.log('Loading user triggers for zone');
}

const setFilename = set.filename ?? 'Unknown';

if (set.initData) {
this.dataInitializers.push({
file: setFilename,
func: set.initData,
});
}

this.AddDamageTriggers('warn', set.damageWarn);
this.AddDamageTriggers('fail', set.damageFail);
this.AddGainsEffectTriggers('warn', set.gainsEffectWarn);
Expand Down
41 changes: 23 additions & 18 deletions ui/oopsyraidsy/data/00-misc/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ type MitTracker = {
};

export interface Data extends OopsyData {
lostFood?: { [name: string]: boolean };
originalRaiser?: { [targetId: string]: string };
lastRaisedLostTime?: { [targetId: string]: string };
raiseTargetTracker?: { [sourceId: string]: string };
targetMitTracker?: {
lostFood: { [name: string]: boolean };
originalRaiser: { [targetId: string]: string };
lastRaisedLostTime: { [targetId: string]: string };
raiseTargetTracker: { [sourceId: string]: string };
targetMitTracker: {
[targetId: string]: MitTracker;
};
partyMitTracker?: MitTracker;
partyMitTracker: MitTracker;
}

const raiseAbilityIds = [
Expand Down Expand Up @@ -76,6 +76,16 @@ const shieldEffectIdToAbilityId: { [id: string]: string } = {
// General mistakes; these apply everywhere.
const triggerSet: OopsyTriggerSet<Data> = {
zoneId: ZoneId.MatchAll,
initData: () => {
return {
lostFood: {},
originalRaiser: {},
lastRaisedLostTime: {},
raiseTargetTracker: {},
targetMitTracker: {},
partyMitTracker: {},
};
},
triggers: [
{
// Trigger id for internally generated early pull warning.
Expand All @@ -93,7 +103,6 @@ const triggerSet: OopsyTriggerSet<Data> = {
return matches.target === matches.source;
},
mistake: (data, matches) => {
data.lostFood ??= {};
// Well Fed buff happens repeatedly when it falls off (WHY),
// so suppress multiple occurrences.
if (!data.inCombat || data.lostFood[matches.target])
Expand All @@ -119,8 +128,6 @@ const triggerSet: OopsyTriggerSet<Data> = {
type: 'GainsEffect',
netRegex: NetRegexes.gainsEffect({ effectId: '30' }),
run: (data, matches) => {
if (!data.lostFood)
return;
delete data.lostFood[matches.target];
},
},
Expand Down Expand Up @@ -151,16 +158,14 @@ const triggerSet: OopsyTriggerSet<Data> = {
type: 'LosesEffect',
netRegex: NetRegexes.losesEffect({ effectId: '94' }),
run: (data, matches) => {
(data.lastRaisedLostTime ??= {})[matches.targetId] = matches.timestamp;
data.lastRaisedLostTime[matches.targetId] = matches.timestamp;
},
},
{
id: 'General Double Raise',
type: 'GainsEffect',
netRegex: NetRegexes.gainsEffect({ effectId: '94' }),
mistake: (data, matches) => {
data.lastRaisedLostTime ??= {};
data.originalRaiser ??= {};
const originalRaiser = data.originalRaiser[matches.targetId];
// 30 and 26 lines having the same timestamp means effect was overwritten and the target is still dead
const overwrittenRaise = data.lastRaisedLostTime[matches.targetId] === matches.timestamp;
Expand Down Expand Up @@ -190,17 +195,17 @@ const triggerSet: OopsyTriggerSet<Data> = {
type: 'StartsUsing',
netRegex: NetRegexes.startsUsing({ id: raiseAbilityIds }),
run: (data, matches) => {
(data.raiseTargetTracker ??= {})[matches.sourceId] = matches.targetId;
data.raiseTargetTracker[matches.sourceId] = matches.targetId;
},
},
{
id: 'General Targetless Raise', // target raised before cast finished
type: 'Ability',
netRegex: NetRegexes.ability({ id: raiseAbilityIds, targetId: 'E0000000' }),
mistake: (data, matches) => {
const targetId = (data.raiseTargetTracker ??= {})[matches.sourceId];
const targetId = data.raiseTargetTracker[matches.sourceId];
if (targetId !== undefined) {
const originalRaiser = (data.originalRaiser ??= {})[targetId];
const originalRaiser = data.originalRaiser[targetId];
if (originalRaiser !== undefined) {
return {
type: 'warn',
Expand Down Expand Up @@ -231,8 +236,8 @@ const triggerSet: OopsyTriggerSet<Data> = {
return;

const mitTracker = isTargetMit
? ((data.targetMitTracker ??= {})[matches.targetId] ??= {})
: (data.partyMitTracker ??= {});
? (data.targetMitTracker[matches.targetId] ??= {})
: data.partyMitTracker;
const newTime = new Date(matches.timestamp).getTime();
const newSource = data.ShortName(matches.source);
const lastTime = mitTracker[matches.id]?.time;
Expand Down Expand Up @@ -270,7 +275,7 @@ const triggerSet: OopsyTriggerSet<Data> = {
run: (data, matches) => {
const abilityId = shieldEffectIdToAbilityId[matches.effectId];
if (abilityId !== undefined)
delete (data.partyMitTracker ??= {})?.[abilityId];
delete data.partyMitTracker[abilityId];
},
},
],
Expand Down
4 changes: 2 additions & 2 deletions ui/oopsyraidsy/data/05-shb/raid/e6s.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import ZoneId from '../../../../../resources/zone_id';
import { SimpleOopsyTriggerSet } from '../../../../../types/oopsy';
import { OopsyTriggerSet } from '../../../../../types/oopsy';

// TODO: check tethers being cut (when they shouldn't)
// TODO: check for concussed debuff
// TODO: check for taking tankbuster with lightheaded
// TODO: check for one person taking multiple Storm Of Fury Tethers (4C01/4C08)

const triggerSet: SimpleOopsyTriggerSet = {
const triggerSet: OopsyTriggerSet = {
zoneId: ZoneId.EdensVerseFurorSavage,
damageWarn: {
// It's common to just ignore futbol mechanics, so don't warn on Strike Spark.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ const stackMistake = (

const triggerSet: OopsyTriggerSet<Data> = {
zoneId: ZoneId.AnotherSildihnSubterraneSavage,
initData: () => {
return {
hasRiteOfPassage: {},
};
},
damageWarn: {
'ASSS Aqueduct Kaluk Right Sweep': '797B', // right 200 degree cleave
'ASSS Aqueduct Kaluk Left Sweep': '797C', // left 200 degree cleave
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ const stackMistake = (

const triggerSet: OopsyTriggerSet<Data> = {
zoneId: ZoneId.AnotherSildihnSubterrane,
initData: () => {
return {
hasRiteOfPassage: {},
};
},
damageWarn: {
'ASS Aqueduct Kaluk Right Sweep': '7963', // right 200 degree cleave
'ASS Aqueduct Kaluk Left Sweep': '7964', // left 200 degree cleave
Expand Down

0 comments on commit 463e5a1

Please sign in to comment.