diff --git a/ui/raidboss/data/07-dt/trial/arkveld-ex.ts b/ui/raidboss/data/07-dt/trial/arkveld-ex.ts index 9c2b2e8df38..98387d0e9e3 100644 --- a/ui/raidboss/data/07-dt/trial/arkveld-ex.ts +++ b/ui/raidboss/data/07-dt/trial/arkveld-ex.ts @@ -1,14 +1,240 @@ +import Conditions from '../../../../../resources/conditions'; +import Outputs from '../../../../../resources/outputs'; +import { Responses } from '../../../../../resources/responses'; +import { DirectionOutputCardinal, Directions } from '../../../../../resources/util'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; -export type Data = RaidbossData; +const limitCutMap: { [id: string]: number } = { + ['0194']: 1, + ['0195']: 2, + ['0196']: 3, + ['0197']: 4, + ['0198']: 5, + ['0199']: 6, + ['019A']: 7, + ['019B']: 8, +} as const; + +const limitCutIds: readonly string[] = Object.keys(limitCutMap); + +export interface Data extends RaidbossData { + limitCutNumber?: number; +} + +// TODO: baits + towers const triggerSet: TriggerSet = { id: 'TheWindwardWildsExtreme', zoneId: ZoneId.TheWindwardWildsExtreme, timelineFile: 'arkveld-ex.txt', - triggers: [], + triggers: [ + { + id: 'Arkveld Ex Roar', + type: 'StartsUsing', + netRegex: { source: 'Guardian Arkveld', id: 'ABA[EF]', capture: false }, + response: Responses.aoe(), + }, + { + id: 'Arkveld Ex Chainblade Blow Left', + type: 'StartsUsing', + // This is relative to the front of the boss, even when he's not on + // the edge. + netRegex: { source: 'Guardian Arkveld', id: ['AB6F', 'B019'], capture: false }, + response: Responses.goLeftThenRight(), + }, + { + id: 'Arkveld Ex Chainblade Blow Right', + type: 'StartsUsing', + // This is relative to the front of the boss, even when he's not on + // the edge. + netRegex: { source: 'Guardian Arkveld', id: ['AB70', 'B01A'], capture: false }, + response: Responses.goRightThenLeft(), + }, + { + id: 'Arkveld Ex Guardian Siegeflight', + type: 'StartsUsing', + netRegex: { source: 'Guardian Arkveld', id: ['AB7B', 'B029'], capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Follow Dash => Out + Healer Stacks', + }, + }, + }, + { + id: 'Arkveld Ex Wyvern Siegeflight', + type: 'StartsUsing', + netRegex: { source: 'Guardian Arkveld', id: ['AB7E', 'B02A'], capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Follow Dash => In + Healer Stacks', + }, + }, + }, + { + id: 'Arkveld Ex Wyverns Ouroblade Left', + type: 'StartsUsing', + netRegex: { source: 'Guardian Arkveld', id: ['AB8B', 'B031'], capture: true }, + suppressSeconds: 1, + alertText: (_data, matches, output) => { + const bossDirNum = Directions.hdgTo8DirNum(parseFloat(matches.heading)); + // Safe area is 90* clockwise of heading + const safeDirNum = (bossDirNum + 2) % 8; + const safeDir = Directions.outputFrom8DirNum(safeDirNum); + + return output.text!({ dir: output[safeDir]!() }); + }, + outputStrings: { + ...Directions.outputStrings8Dir, + text: { + en: '${dir} (Right) + Spread', + }, + }, + }, + { + id: 'Arkveld Ex Wyverns Ouroblade Right', + type: 'StartsUsing', + netRegex: { source: 'Guardian Arkveld', id: ['AB8D', 'B032'], capture: true }, + suppressSeconds: 1, + alertText: (_data, matches, output) => { + const bossDirNum = Directions.hdgTo8DirNum(parseFloat(matches.heading)); + // Safe area is 270* clockwise of heading (90* ccw) + const safeDirNum = (bossDirNum + 6) % 8; + const safeDir = Directions.outputFrom8DirNum(safeDirNum); + + return output.text!({ dir: output[safeDir]!() }); + }, + outputStrings: { + ...Directions.outputStrings8Dir, + text: { + en: '${dir} (Left) + Spread', + }, + }, + }, + { + id: 'Arkveld Ex Spread Marker', + type: 'HeadMarker', + netRegex: { id: '0065', capture: false }, + suppressSeconds: 1, + response: Responses.spread(), + }, + { + id: 'Arkveld Ex Steeltail Thrust', + type: 'StartsUsing', + netRegex: { source: 'Guardian Arkveld', id: ['ABAD', 'B035'], capture: false }, + response: Responses.goFrontOrSides(), + }, + { + id: 'Arkveld Ex Forged Fury', + type: 'StartsUsing', + // Appears alongside AB9E, AEF9, and AB9F + netRegex: { source: 'Guardian Arkveld', id: 'AEF8', capture: false }, + response: Responses.bigAoe(), + }, + { + id: 'Arkveld Ex Limit Cut', + type: 'HeadMarker', + netRegex: { id: limitCutIds, capture: true }, + condition: Conditions.targetIsYou(), + suppressSeconds: 1, + run: (data, matches) => { + if (!limitCutIds.includes(matches.id)) + return; + const num = limitCutMap[matches.id]; + data.limitCutNumber = num; + }, + }, + { + id: 'Arkveld Ex Roar 2', + type: 'StartsUsing', + netRegex: { source: 'Guardian Arkveld', id: 'B092', capture: false }, + response: Responses.bigAoe(), + }, + { + id: 'Arkveld Ex Clamorous Chase', + type: 'StartsUsing', + // This assumes the popular Diamond Cut strategy + netRegex: { source: 'Guardian Arkveld', id: ['ABB3', 'ABB6'], capture: true }, + delaySeconds: 0.1, + durationSeconds: 20, + alertText: (data, matches, output) => { + const startEast: { [id: number]: DirectionOutputCardinal } = { + [1]: 'dirE', + [2]: 'dirS', + [3]: 'dirW', + [4]: 'dirN', + [5]: 'dirE', + [6]: 'dirS', + [7]: 'dirW', + [8]: 'dirN', + } as const; + const startWest: { [id: number]: DirectionOutputCardinal } = { + [1]: 'dirW', + [2]: 'dirS', + [3]: 'dirE', + [4]: 'dirN', + [5]: 'dirW', + [6]: 'dirS', + [7]: 'dirE', + [8]: 'dirN', + } as const; + + const directions = matches.id === 'ABB3' ? startEast : startWest; + const num = data.limitCutNumber; + const dir = num === undefined ? directions[1] : directions[num]; + if (dir === undefined) { + if (num !== undefined) { + return output.number!({ num: num }); + } + return output.unknown!(); + } + + const dirStr = output[dir]!(); + + if (num === undefined) { + return output.first!({ dir: dirStr }); + } + + return output.text!({ dir: dirStr, num: num }); + }, + outputStrings: { + ...Directions.outputStringsCardinalDir, + text: { + en: '${dir} (${num})', + }, + number: { + en: '${num}', + }, + first: { + en: '1 starts ${dir}', + }, + unknown: Outputs.unknown, + }, + }, + { + id: 'Arkveld Ex Laser Target', + type: 'HeadMarker', + netRegex: { id: '01D6', capture: true }, + suppressSeconds: 1, + alertText: (data, matches, output) => { + if (matches.target === data.me) + return output.laserOnYou!(); + + return output.laserOnPlayer!({ player: data.party.member(matches.target) }); + }, + outputStrings: { + laserOnYou: { + en: 'Laser on you', + }, + laserOnPlayer: { + en: 'Laser on ${player}', + }, + }, + }, + ], timelineReplace: [ { 'locale': 'de', diff --git a/ui/raidboss/data/07-dt/trial/arkveld-ex.txt b/ui/raidboss/data/07-dt/trial/arkveld-ex.txt index ed3489ad209..f12de301790 100644 --- a/ui/raidboss/data/07-dt/trial/arkveld-ex.txt +++ b/ui/raidboss/data/07-dt/trial/arkveld-ex.txt @@ -130,7 +130,7 @@ hideall "--sync--" # AB8C and AB8E are the secondary follow-up hit similar to chainblade blow # # After the power-up: -# B032 and B032 are the first hit, each being a different half +# B031 and B032 are the first hit, each being a different half # B033 and B034 are the secondary follow-up hit similar to chainblade blow # # AB96 Wyvern's Vengeance @@ -169,7 +169,7 @@ hideall "--sync--" # AF05 Steeltail Thrust # AF06 Steeltail Thrust # B035 Steeltail Thrust -# Tail thrust. One might be the animation while one is thie hit, not sure. +# Tail thrust. One might be the animation while one is the hit, not sure. # It looks like damage is on the second skill. # # ABAE Roar