From 7b2cb9a14315fcd4e60f1d6f9f450c4402f608bc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 08:14:23 -0500 Subject: [PATCH 001/100] add initial triggers and timeline for p1 --- ui/raidboss/data/07-dt/raid/r12s.ts | 1103 ++++++++++++++++++++++++++ ui/raidboss/data/07-dt/raid/r12s.txt | 454 +++++++++++ 2 files changed, 1557 insertions(+) create mode 100644 ui/raidboss/data/07-dt/raid/r12s.ts create mode 100644 ui/raidboss/data/07-dt/raid/r12s.txt diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts new file mode 100644 index 0000000000..beec50f111 --- /dev/null +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -0,0 +1,1103 @@ +import Conditions from '../../../../../resources/conditions'; +import { UnreachableCode } from '../../../../../resources/not_reached'; +import Outputs from '../../../../../resources/outputs'; +import { Responses } from '../../../../../resources/responses'; +import { Directions } from '../../../../../resources/util'; +import ZoneId from '../../../../../resources/zone_id'; +import { RaidbossData } from '../../../../../types/data'; +import { TriggerSet } from '../../../../../types/trigger'; + +export type Phase = 'doorboss' | 'curtainCall' | 'slaughtershed' | 'two'; + +export interface Data extends RaidbossData { + phase: Phase; + // Phase 1 + grotesquerieCleave?: + | 'rightCleave' + | 'leftCleave' + | 'frontCleave' + | 'rearCleave'; + myFleshBonds?: 'alpha' | 'beta'; + inLine: { [name: string]: number }; + blobTowerDirs: string[]; + fleshBondsCount: number; + cellChainCount: number; + cellTowerCount: number; + myMitoticPhase?: string; + hasRot: boolean; + // Phase 2 +} + +const headMarkerData = { + // Phase 1 + // VFX: com_share3t + 'stack': '00A1', + // VFX: tank_lockonae_6m_5s_01t + 'tankbuster': '0158', + // VFX: VFX: x6rc_cellchain_01x + 'cellChain': '0291', + // VFX: com_share3_7s0p + 'slaughterStack': '013D', + // VFX: target_ae_s7k1 + 'slaughterSpread': '0177', + 'cellChainTether': '016E', + // Phase 2 +} as const; + +const center = { + x: 100, + y: 100, +} as const; + +const phaseMap: { [id: string]: Phase } = { + 'BEC0': 'curtainCall', + 'B4C6': 'slaughtershed', +}; + +const triggerSet: TriggerSet = { + id: 'AacHeavyweightM4Savage', + zoneId: ZoneId.AacHeavyweightM4Savage, + timelineFile: 'r12s.txt', + initData: () => ({ + phase: 'doorboss', + // Phase 1 + inLine: {}, + blobTowerDirs: [], + fleshBondsCount: 0, + cellChainCount: 0, + cellTowerCount: 0, + hasRot: false, + // Phase 2 + }), + triggers: [ + { + id: 'R12S Phase Tracker', + type: 'StartsUsing', + netRegex: { id: Object.keys(phaseMap), source: 'Lindwurm' }, + suppressSeconds: 1, + run: (data, matches) => { + const phase = phaseMap[matches.id]; + if (phase === undefined) + throw new UnreachableCode(); + + data.phase = phase; + }, + }, + { + id: 'R12S The Fixer', + type: 'StartsUsing', + netRegex: { id: 'B4D7', source: 'Lindwurm', capture: false }, + durationSeconds: 4.7, + response: Responses.bigAoe('alert'), + }, + { + id: 'R12S Directed Grotesquerie Direction Collect', + // Unknown_DE6 spell contains data in its count: + // 40C, Front Cone + // 40D, Right Cone + // 40E, Rear Cone + // 40F, Left Cone + type: 'GainsEffect', + netRegex: { effectId: 'DE6', capture: true }, + condition: Conditions.targetIsYou(), + run: (data, matches) => { + switch (matches.count) { + case '40C': + data.grotesquerieCleave = 'frontCleave'; + return; + case '40D': + data.grotesquerieCleave = 'rightCleave'; + return; + case '40E': + data.grotesquerieCleave = 'rearCleave'; + return; + case '40F': + data.grotesquerieCleave = 'leftCleave'; + return; + } + }, + }, + { + id: 'R12S Shared Grotesquerie', + type: 'GainsEffect', + netRegex: { effectId: '129A', capture: true }, + delaySeconds: 0.2, + durationSeconds: 17, + infoText: (data, matches, output) => { + const cleave = data.grotesquerieCleave; + const target = matches.target; + if (target === data.me) { + if (cleave === undefined) + return output.baitThenStack!({ stack: output.stackOnYou!() }); + return output.baitThenStackCleave!({ + stack: output.stackOnYou!(), + cleave: output[cleave]!(), + }); + } + + const player = data.party.member(target); + const isDPS = data.party.isDPS(target); + if (isDPS && data.role === 'dps') { + if (cleave === undefined) + return output.baitThenStack!({ + stack: output.stackOnPlayer!({ player: player }), + }); + return output.baitThenStackCleave!({ + stack: output.stackOnPlayer!({ player: player }), + cleave: output[cleave]!(), + }); + } + if (!isDPS && data.role !== 'dps') { + if (cleave === undefined) + return output.baitThenStack!({ + stack: output.stackOnPlayer!({ player: player }), + }); + return output.baitThenStackCleave!({ + stack: output.stackOnPlayer!({ player: player }), + cleave: output[cleave]!(), + }); + } + }, + outputStrings: { + stackOnYou: Outputs.stackOnYou, + stackOnPlayer: Outputs.stackOnPlayer, + frontCleave: { + en: 'Front Cleave', + de: 'Kegel Aoe nach Vorne', + fr: 'Cleave Avant', + ja: '口からおくび', + cn: '前方扇形', + ko: '전방 부채꼴 장판', + tc: '前方扇形', + }, + rearCleave: { + en: 'Rear Cleave', + de: 'Kegel Aoe nach Hinten', + fr: 'Cleave Arrière', + ja: '尻からおなら', + cn: '背后扇形', + ko: '후방 부채꼴 장판', + tc: '背後扇形', + }, + leftCleave: { + en: 'Left Cleave', + de: 'Linker Cleave', + fr: 'Cleave gauche', + ja: '左半面へ攻撃', + cn: '左刀', + ko: '왼쪽 공격', + tc: '左刀', + }, + rightCleave: { + en: 'Right Cleave', + de: 'Rechter Cleave', + fr: 'Cleave droit', + ja: '右半面へ攻撃', + cn: '右刀', + ko: '오른쪽 공격', + tc: '右刀', + }, + baitThenStack: { + en: 'Bait 4x Puddles => ${stack}', + }, + baitThenStackCleave: { + en: 'Bait 4x Puddles => ${stack} + ${cleave}', + }, + }, + }, + { + id: 'R12S Bursting Grotesquerie', + type: 'GainsEffect', + netRegex: { effectId: '1299', capture: true }, + condition: Conditions.targetIsYou(), + delaySeconds: 0.2, + durationSeconds: 17, + infoText: (data, _matches, output) => { + const cleave = data.grotesquerieCleave; + if (cleave === undefined) + return data.phase === 'doorboss' + ? output.baitThenSpread!() + : output.spreadCurtain!(); + return data.phase === 'doorboss' + ? output.baitThenSpreadCleave!({ cleave: output[cleave]!() }) + : output.spreadCurtain!(); + }, + outputStrings: { + frontCleave: { + en: 'Front Cleave', + de: 'Kegel Aoe nach Vorne', + fr: 'Cleave Avant', + ja: '口からおくび', + cn: '前方扇形', + ko: '전방 부채꼴 장판', + tc: '前方扇形', + }, + rearCleave: { + en: 'Rear Cleave', + de: 'Kegel Aoe nach Hinten', + fr: 'Cleave Arrière', + ja: '尻からおなら', + cn: '背后扇形', + ko: '후방 부채꼴 장판', + tc: '背後扇形', + }, + leftCleave: { + en: 'Left Cleave', + de: 'Linker Cleave', + fr: 'Cleave gauche', + ja: '左半面へ攻撃', + cn: '左刀', + ko: '왼쪽 공격', + tc: '左刀', + }, + rightCleave: { + en: 'Right Cleave', + de: 'Rechter Cleave', + fr: 'Cleave droit', + ja: '右半面へ攻撃', + cn: '右刀', + ko: '오른쪽 공격', + tc: '右刀', + }, + baitThenSpread: { + en: 'Bait 4x Puddles => Spread', + }, + baitThenSpreadCleave: { + en: 'Bait 4x Puddles => Spread + ${cleave}', + }, + spreadCurtain: { + en: 'Spread Debuff on YOU', + }, + }, + }, + { + id: 'R12S Ravenous Reach 1 Safe Side', + // These two syncs indicate the animation of where the head will go to cleave + // B49A => West Safe + // B49B => East Safe + type: 'Ability', + netRegex: { id: ['B49A', 'B49B'], source: 'Lindwurm', capture: true }, + condition: (data) => data.phase === 'doorboss', + infoText: (_data, matches, output) => { + if (matches.id === 'B49A') + return output.goWest!(); + return output.goEast!(); + }, + outputStrings: { + goEast: Outputs.east, + goWest: Outputs.west, + }, + }, + { + id: 'R12S Fourth-wall Fusion Stack', + type: 'HeadMarker', + netRegex: { id: headMarkerData['stack'], capture: true }, + condition: (data) => { + if (data.role === 'tank') + return false; + return true; + }, + durationSeconds: 5.1, + response: Responses.stackMarkerOn(), + }, + { + id: 'R12S Tankbuster', + type: 'HeadMarker', + netRegex: { id: headMarkerData['tankbuster'], capture: true }, + condition: Conditions.targetIsYou(), + durationSeconds: 5.1, + response: Responses.tankBuster(), + }, + { + id: 'R12S In Line Debuff Collector', + type: 'GainsEffect', + netRegex: { effectId: ['BBC', 'BBD', 'BBE', 'D7B'] }, + run: (data, matches) => { + const effectToNum: { [effectId: string]: number } = { + BBC: 1, + BBD: 2, + BBE: 3, + D7B: 4, + } as const; + const num = effectToNum[matches.effectId]; + if (num === undefined) + return; + data.inLine[matches.target] = num; + }, + }, + { + id: 'R12S Bonds of Flesh Flesh α/β Collect', + // Bonds of Flesh has the following timings: + // 1st - 26s + // 2nd - 31s + // 3rd - 36s + // 4rth - 41s + type: 'GainsEffect', + netRegex: { effectId: ['1290', '1292'], capture: true }, + condition: Conditions.targetIsYou(), + run: (data, matches) => { + data.myFleshBonds = matches.effectId === '1290' ? 'alpha' : 'beta'; + }, + }, + { + id: 'R12S In Line Debuff', + type: 'GainsEffect', + netRegex: { effectId: ['BBC', 'BBD', 'BBE', 'D7B'], capture: false }, + delaySeconds: 0.5, + durationSeconds: 10, + suppressSeconds: 1, + infoText: (data, _matches, output) => { + const myNum = data.inLine[data.me]; + if (myNum === undefined) + return; + const flesh = data.myFleshBonds; + if (flesh === undefined) + return output.order!({ + num: myNum + }); + if (flesh === 'alpha') { + switch (myNum) { + case 1: + return output.alpha1!(); + case 2: + return output.alpha2!(); + case 3: + return output.alpha3!(); + case 4: + return output.alpha4!(); + } + } + switch (myNum) { + case 1: + return output.beta1!(); + case 2: + return output.beta2!(); + case 3: + return output.beta3!(); + case 4: + return output.beta4!(); + } + }, + outputStrings: { + alpha1: { + en: '1α: Wait for Tether 1', + }, + alpha2: { + en: '2α: Wait for Tether 2', + }, + alpha3: { + en: '3α: Blob Tower 1', + }, + alpha4: { + en: '4α: Blob Tower 2', + }, + beta1: { + en: '1β: Wait for Tether 1', + }, + beta2: { + en: '2β: Wait for Tether 2', + }, + beta3: { + en: '3β: Chain Tower 1', + }, + beta4: { + en: '4β: Chain Tower 2', + }, + order: { + en: '${num}', + de: '${num}', + fr: '${num}', + ja: '${num}', + cn: '${num}', + ko: '${num}', + tc: '${num}', + }, + unknown: Outputs.unknown, + }, + }, + { + id: 'R12S Phagocyte Spotlight Blob Tower Location Collect', + // StartsUsing and StartsUsingExtra can have bad data, there is enough time that Ability is sufficient + // Pattern 1 + // Blob 1: (104, 104) SE Inner + // Blob 2: (96, 96) NW Inner + // Blob 3: (85, 110) SW Outer + // Blob 4: (115, 90) NE Outer + // Pattern 2 + // Blob 1: (104, 96) NE Inner + // Blob 2: (96, 104) SW Inner + // Blob 3: (85, 90) NW Outer + // Blob 4: (115, 110) SE Outer + // Pattern 3 + // Blob 1: (96, 96) NW Inner + // Blob 2: (104, 104) SE Inner + // Blob 3: (115, 90) NE Outer + // Blob 4: (85, 110) SW Outer + // Pattern 4 + // Blob 1: (96, 104) SW Inner + // Blob 2: (104, 96) NE Inner + // Blob 3: (115, 110) SE Outer + // Blob 4: (86, 90) NW Outer + type: 'Ability', + netRegex: { id: 'B4B6', capture: true }, + run: (data, matches) => { + const x = parseFloat(matches.x); + const y = parseFloat(matches.y); + data.blobTowerDirs.push(Directions.xyToIntercardDirOutput(x, y, center.x, center.y)); + }, + }, + { + id: 'R12S Phagocyte Spotlight Blob Tower Location (Early)', + // 23.8s until B4B7 Rolling Mass Blob Tower Hit + type: 'Ability', + netRegex: { id: 'B4B6', capture: true }, + condition: (data) => { + if (data.myFleshBonds === 'alpha') { + const myNum = data.inLine[data.me]; + if ( + (myNum === 1 && data.blobTowerDirs.length === 3) || + (myNum === 2 && data.blobTowerDirs.length === 4) || + (myNum === 3 && data.blobTowerDirs.length === 1) || + (myNum === 4 && data.blobTowerDirs.length === 2) + ) + return true; + } + return false; + }, + delaySeconds: 0.1, + durationSeconds: (data) => { + const myNum = data.inLine[data.me]; + // Timings based on next trigger + switch (myNum) { + case 1: + return 13; + case 2: + return 16; + case 3: + return 17; + case 4: + return 15; + } + }, + infoText: (data, _matches, output) => { + const myNum = data.inLine[data.me]; + if (myNum === undefined) + return; + + type index = { + [key: number]: number; + }; + const myNumToDirIndex: index = { + 1: 2, + 2: 3, + 3: 0, + 4: 1, + }; + const dirIndex = myNumToDirIndex[myNum]; + if (dirIndex === undefined) + return; + const towerNum = dirIndex + 1; + + const dir = data.blobTowerDirs[dirIndex]; + if (dir === undefined) + return; + + if (myNum > 2) + return output.innerBlobTower!({ + num: towerNum, + dir: output[dir]!(), + }); + return output.outerBlobTower!({ num: towerNum, dir: output[dir]!() }); + }, + outputStrings: { + ...Directions.outputStringsIntercardDir, + innerBlobTower: { + en: 'Blob Tower ${num} Inner ${dir} (later)', + }, + outerBlobTower: { + en: 'Blob Tower ${num} Outer ${dir} (later)', + }, + }, + }, + { + id: 'R12S Cell Chain Counter', + type: 'Tether', + netRegex: { id: headMarkerData['cellChainTether'], capture: false }, + condition: (data) => data.phase === 'doorboss', + run: (data) => data.cellChainCount = data.cellChainCount + 1, + }, + { + id: 'R12S Cell Chain Tether Number', + // Helpful for players to keep track of which chain tower is next + // Does not output when it is their turn to break the tether + type: 'Tether', + netRegex: { id: headMarkerData['cellChainTether'], capture: false }, + condition: (data) => { + if (data.phase === 'doorboss' && data.myFleshBonds === 'beta') + return true; + return false; + }, + infoText: (data, _matches, output) => { + const myNum = data.inLine[data.me]; + const num = data.cellChainCount; + if (myNum !== num) + return output.tether!({ num: num }); + if (myNum === undefined) + return output.tether!({ num: num }); + }, + outputStrings: { + tether: { + en: 'Tether ${num}', + de: 'Verbindung ${num}', + fr: 'Lien ${num}', + ja: '線 ${num}', + cn: '线 ${num}', + ko: '선 ${num}', + tc: '線 ${num}', + }, + }, + }, + { + id: 'R12S Chain Tower Number', + // Using B4B4 Dramatic Lysis to detect chain broken + type: 'Ability', + netRegex: { id: 'B4B4', capture: false }, + condition: (data) => { + if (data.phase === 'doorboss' && data.myFleshBonds === 'beta') + return true; + return false; + }, + suppressSeconds: 1, + alertText: (data, _matches, output) => { + const mechanicNum = data.cellChainCount; + const myNum = data.inLine[data.me]; + if (myNum === undefined) + return; + + type index = { + [key: number]: number; + }; + const myNumToOrder: index = { + 1: 3, + 2: 4, + 3: 1, + 4: 2, + }; + + const myOrder = myNumToOrder[myNum]; + if (myOrder === undefined) + return; + + if (myOrder === mechanicNum) + return output.tower!({ num: mechanicNum }); + }, + outputStrings: { + tower: { + en: 'Get Chain Tower ${num}', + }, + }, + }, + { + id: 'R12S Chain Tower Counter', + // Using B4B3 Roiling Mass to detect chain tower soak + // Also using B4B2 Unmitigated Explosion if missed tower + type: 'Ability', + netRegex: { id: ['B4B3', 'B4B2'], capture: false }, + suppressSeconds: 1, + run: (data) => data.cellTowerCount = data.cellTowerCount + 1, + }, + { + id: 'R12S Chain Tower Followup', + // Using B4B3 Roiling Mass to detect chain tower soak + // Beta player leaving early may get hit by alpha's chain break aoe + type: 'Ability', + netRegex: { id: 'B4B3', capture: true }, + condition: (data, matches) => { + if (data.myFleshBonds === 'beta' && data.me === matches.target) + return true; + return false; + }, + infoText: (data, _matches, output) => { + const mechanicNum = data.cellTowerCount; + const myNum = data.inLine[data.me]; + if (myNum === undefined) + return; + + type index = { + [key: number]: number; + }; + const myNumToOrder: index = { + 1: 3, + 2: 4, + 3: 1, + 4: 2, + }; + + const myOrder = myNumToOrder[myNum]; + if (myOrder === undefined) + return; + + if (myOrder === mechanicNum) { + if (mechanicNum < 4) + return output.goIntoMiddle!(); + return output.getOut!(); + } + }, + outputStrings: { + getOut: { + en: 'Get Out', + de: 'Raus da', + fr: 'Sortez', + ja: '外へ', + cn: '远离', + ko: '밖으로', + tc: '遠離', + }, + goIntoMiddle: Outputs.goIntoMiddle, + }, + }, + { + id: 'R12S Bonds of Flesh Flesh α First Two Towers', + // These are not dependent on player timings and so can be hard coded by duration + type: 'GainsEffect', + netRegex: { effectId: '1290', capture: true }, + condition: (data, matches) => { + if (matches.target === data.me) { + const duration = parseFloat(matches.duration); + if (duration < 35) + return false; + return true; + } + return false; + }, + delaySeconds: (_data, matches) => { + const duration = parseFloat(matches.duration); + if (duration > 35) + return 27; + return 32; + }, + infoText: (data, matches, output) => { + const duration = parseFloat(matches.duration); + const dir = data.blobTowerDirs[duration > 40 ? 1 : 0]; + if (duration > 40) { + if (dir !== undefined) + return output.alpha4Dir!({ dir: output[dir]!() }); + return output.alpha4!(); + } + if (dir !== undefined) + return output.alpha3Dir!({ dir: output[dir]!() }); + return output.alpha3!(); + }, + outputStrings: { + ...Directions.outputStringsIntercardDir, + alpha3: { + en: 'Get Blob Tower 1', + }, + alpha4: { + en: 'Get Blob Tower 2', + }, + alpha3Dir: { + en: 'Blob Tower 1 (Inner ${dir})', + }, + alpha4Dir: { + en: 'Blob Tower 2 (Inner ${dir})', + }, + }, + }, + { + id: 'R12S Unbreakable Flesh α/β Chains and Last Two Towers', + type: 'GainsEffect', + netRegex: { effectId: ['1291', '1293'], capture: true }, + condition: (data, matches) => { + if (matches.target === data.me && data.phase === 'doorboss') + return true; + return false; + }, + infoText: (data, matches, output) => { + const myNum = data.inLine[data.me]; + const flesh = matches.effectId === '1291' ? 'alpha' : 'beta'; + if (flesh === 'alpha') { + if (myNum === 1) { + const dir = data.blobTowerDirs[2]; + if (dir !== undefined) + return output.alpha1Dir!({ + chains: output.breakChains!(), + dir: output[dir]!(), + }); + } + if (myNum === 2) { + const dir = data.blobTowerDirs[3]; + if (dir !== undefined) + return output.alpha2Dir!({ + chains: output.breakChains!(), + dir: output[dir]!(), + }); + } + + // dir undefined or 3rd/4rth in line + switch (myNum) { + case 1: + return output.alpha1!({ chains: output.breakChains!() }); + case 2: + return output.alpha2!({ chains: output.breakChains!() }); + case 3: + return output.alpha3!({ chains: output.breakChains!() }); + case 4: + return output.alpha4!({ chains: output.breakChains!() }); + } + } + switch (myNum) { + case 1: + return output.beta1!({ chains: output.breakChains!() }); + case 2: + return output.beta2!({ chains: output.breakChains!() }); + case 3: + return output.beta3!({ chains: output.breakChains!() }); + case 4: + return output.beta4!({ chains: output.breakChains!() }); + } + return output.getTowers!(); + }, + outputStrings: { + ...Directions.outputStringsIntercardDir, + breakChains: Outputs.breakChains, + getTowers: Outputs.getTowers, + alpha1: { + en: '${chains} 1 + Blob Tower 3 (Outer)', + }, + alpha1Dir: { + en: '${chains} 1 + Blob Tower 3 (Outer ${dir})', + }, + alpha2: { + en: '${chains} 2 + Blob Tower 4 (Outer)', + }, + alpha2Dir: { + en: '${chains} 2 + Blob Tower 4 (Outer ${dir})', + }, + alpha3: { + en: '${chains} 3 + Get Out', + }, + alpha4: { + en: '${chains} 4 + Get Out', + }, + beta1: { + en: '${chains} 1 => Get Middle', + }, + beta2: { + en: '${chains} 2 => Get Middle', + }, + beta3: { + en: '${chains} 3 => Wait for last pair', + }, + beta4: { + en: '${chains} 4 + Get Out', + }, + }, + }, + { + id: 'R12S Splattershed', + type: 'StartsUsing', + netRegex: { id: ['B9C3', 'B9C4'], source: 'Lindwurm', capture: false }, + response: Responses.aoe(), + }, + { + id: 'R12S Mitotic Phase Direction Collect', + // Unknown_DE6 spell contains data in its count + type: 'GainsEffect', + netRegex: { effectId: 'DE6', capture: true }, + condition: Conditions.targetIsYou(), + durationSeconds: 10, + infoText: (data, matches, output) => { + data.myMitoticPhase = matches.count; + switch (matches.count) { + case '436': + return output.frontTower!(); + case '437': + return output.rightTower!(); + case '438': + return output.rearTower!(); + case '439': + return output.leftTower!(); + } + }, + outputStrings: { + frontTower: { + en: 'Tower (S/SW)', + }, + rearTower: { + en: 'Tower (N/NE)', + }, + leftTower: { + en: 'Tower (E/SE)', + }, + rightTower: { + en: 'Tower (W/NW)', + }, + }, + }, + { + id: 'R12S Grand Entrance Intercards/Cardinals', + // B4A1 is only cast when cardinals are safe + // B4A2 is only cast when intercardinals are safe + // These casts more than once, so just capture first event + type: 'StartsUsing', + netRegex: { id: ['B4A1', 'B4A2'], capture: false }, + suppressSeconds: 5, + infoText: (data, matches, output) => { + const count = data.myMitoticPhase; + if (count === undefined) + return; + if (matches.id === 'B4A1') { + switch (count) { + case '436': + return output.frontCardinals!(); + case '437': + return output.rightCardinals!(); + case '438': + return output.rearCardinals!(); + case '439': + return output.leftCardinals!(); + } + } + switch (count) { + case '436': + return output.frontIntercards!(); + case '437': + return output.rightIntercards!(); + case '438': + return output.rearIntercards!(); + case '439': + return output.leftIntercards!(); + } + }, + outputStrings: { + frontIntercards: Outputs.southwest, + rearIntercards: Outputs.northeast, + leftIntercards: Outputs.southeast, + rightIntercards: Outputs.northwest, + frontCardinals: Outputs.south, + rearCardinals: Outputs.north, + leftCardinals: Outputs.east, + rightCardinals: Outputs.west, + }, + }, + { + id: 'R12S Rotting Flesh', + type: 'GainsEffect', + netRegex: { effectId: '129B', capture: true }, + condition: Conditions.targetIsYou(), + durationSeconds: 10, + infoText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Rotting Flesh on YOU', + }, + }, + }, + { + id: 'R12S Rotting Flesh Collect', + type: 'GainsEffect', + netRegex: { effectId: '129B', capture: true }, + condition: Conditions.targetIsYou(), + run: (data) => data.hasRot === true, + }, + { + id: 'R12S Ravenous Reach 2', + // These two syncs indicate the animation of where the head will go to cleave + // B49A => West Safe + // B49B => East Safe + type: 'Ability', + netRegex: { id: ['B49A', 'B49B'], source: 'Lindwurm', capture: true }, + condition: (data) => data.phase === 'curtainCall', + alertText: (data, matches, output) => { + if (matches.id === 'B49A') { + return data.hasRot ? output.getHitEast!() : output.safeWest!(); + } + return data.hasRot ? output.getHitWest!() : output.safeEast!(); + }, + outputStrings: { + getHitWest: { + en: 'Spread in West Breadth', + }, + getHitEast: { + en: 'Spread in East Breadth', + }, + safeEast: { + en: 'Spread East', + }, + safeWest: { + en: 'Spread West', + }, + }, + }, + { + id: 'R12S Split Scourge and Venomous Scourge', + // B4AB Split Scourge and B4A8 Venomous Scourge are instant casts + // This actor control happens along with boss becoming targetable + type: 'ActorControl', + netRegex: { command: '8000000D', data0: '1E01', capture: false }, + durationSeconds: 9, + suppressSeconds: 1, + infoText: (data, _matches, output) => { + if (data.role === 'tank') + return output.tank!(); + return output.party!(); + }, + outputStrings: { + tank: { + en: 'Bait Line AoE from heads', + }, + party: { + en: 'Spread, Away from heads', + }, + }, + }, + { + id: 'R12S Grotesquerie: Curtain Call Spreads', + type: 'StartsUsing', + netRegex: { id: 'BEC0', source: 'Lindwurm', capture: false }, + infoText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: 'Bait 5x Puddles', + }, + }, + { + id: 'R12S Curtain Call: Unbreakable Flesh α/β Chains', + type: 'GainsEffect', + netRegex: { effectId: ['1291', '1293'], capture: true }, + condition: (data, matches) => { + if (matches.target === data.me && data.phase === 'curtainCall') + return true; + return false; + }, + infoText: (_data, matches, output) => { + const flesh = matches.effectId === '1291' ? 'alpha' : 'beta'; + if (flesh === 'alpha') + return output.alphaChains!(); + return output.betaChains!(); + }, + outputStrings: { + alphaChains: Outputs.breakChains, + betaChains: Outputs.breakChains, + }, + }, + { + id: 'R12S Slaughtershed', + type: 'StartsUsing', + netRegex: { id: ['B4C6', 'B4C3'], source: 'Lindwurm', capture: false }, + response: Responses.bigAoe('alert'), + }, + { + id: 'R12S Slaughtershed Stack', + // TODO: Get Safe spot + type: 'HeadMarker', + netRegex: { id: headMarkerData['slaughterStack'], capture: true }, + condition: (data, matches) => { + const isDPS = data.party.isDPS(matches.target); + if (isDPS && data.role === 'dps') + return true; + if (!isDPS && data.role !== 'dps') + return true; + return false; + }, + durationSeconds: 5.1, + response: Responses.stackMarkerOn(), + }, + { + id: 'R12S Slaughtershed Spread', + // TODO: Get Safe spot + type: 'HeadMarker', + netRegex: { id: headMarkerData['slaughterSpread'], capture: true }, + condition: Conditions.targetIsYou(), + durationSeconds: 5.1, + suppressSeconds: 1, + response: Responses.spread(), + }, + { + id: 'R12S Serpintine Scourge Right Hand First', + // Left Hand first, then Right Hand + type: 'Ability', + netRegex: { id: 'B4CB', source: 'Lindwurm', capture: false }, + condition: (data) => data.phase === 'slaughtershed', + durationSeconds: 12, + infoText: (_data, _matches, output) => output.rightThenLeft!(), + outputStrings: { + rightThenLeft: Outputs.rightThenLeft, + }, + }, + { + id: 'R12S Serpintine Scourge Left Hand First', + // Right Hand first, then Left Hand + type: 'Ability', + netRegex: { id: 'B4CD', source: 'Lindwurm', capture: false }, + condition: (data) => data.phase === 'slaughtershed', + durationSeconds: 12, + infoText: (_data, _matches, output) => output.leftThenRight!(), + outputStrings: { + leftThenRight: Outputs.leftThenRight, + }, + }, + { + id: 'R12S Raptor Knuckles Right Hand First', + // Right Hand first, then Left Hand + type: 'Ability', + netRegex: { id: 'B4CC', source: 'Lindwurm', capture: false }, + condition: (data) => data.phase === 'slaughtershed', + durationSeconds: 12, + infoText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Northwest: Knockback to Northeast', + }, + }, + }, + { + id: 'R12S Raptor Knuckles Left Hand First', + // Left Hand first, then Right Hand + type: 'Ability', + netRegex: { id: 'B4CE', source: 'Lindwurm', capture: false }, + condition: (data) => data.phase === 'slaughtershed', + durationSeconds: 12, + infoText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Northeast: Knockback to Northwest', + }, + }, + }, + ], + timelineReplace: [ + { + 'locale': 'cn', + 'replaceSync': { + 'Lindwurm': '林德布鲁姆', + }, + 'replaceText': { + '\\(huge\\)': '(大)', + 'Bloodshed': '流血', + 'Bring Down the House': '震场', + '(? Date: Mon, 19 Jan 2026 08:24:37 -0500 Subject: [PATCH 002/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index beec50f111..aae6d5e609 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -216,8 +216,8 @@ const triggerSet: TriggerSet = { const cleave = data.grotesquerieCleave; if (cleave === undefined) return data.phase === 'doorboss' - ? output.baitThenSpread!() - : output.spreadCurtain!(); + ? output.baitThenSpread!() + : output.spreadCurtain!(); return data.phase === 'doorboss' ? output.baitThenSpreadCleave!({ cleave: output[cleave]!() }) : output.spreadCurtain!(); @@ -352,9 +352,7 @@ const triggerSet: TriggerSet = { return; const flesh = data.myFleshBonds; if (flesh === undefined) - return output.order!({ - num: myNum - }); + return output.order!({ num: myNum }); if (flesh === 'alpha') { switch (myNum) { case 1: From 4d181c4c2486aacbb5565ba6199b74d7f03fad16 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 08:27:20 -0500 Subject: [PATCH 003/100] unused capture, remove timelinereplace copy from r12n --- ui/raidboss/data/07-dt/raid/r12s.ts | 35 ++--------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index aae6d5e609..961273b747 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -448,7 +448,7 @@ const triggerSet: TriggerSet = { id: 'R12S Phagocyte Spotlight Blob Tower Location (Early)', // 23.8s until B4B7 Rolling Mass Blob Tower Hit type: 'Ability', - netRegex: { id: 'B4B6', capture: true }, + netRegex: { id: 'B4B6', capture: false }, condition: (data) => { if (data.myFleshBonds === 'alpha') { const myNum = data.inLine[data.me]; @@ -1064,38 +1064,7 @@ const triggerSet: TriggerSet = { }, }, ], - timelineReplace: [ - { - 'locale': 'cn', - 'replaceSync': { - 'Lindwurm': '林德布鲁姆', - }, - 'replaceText': { - '\\(huge\\)': '(大)', - 'Bloodshed': '流血', - 'Bring Down the House': '震场', - '(? Date: Mon, 19 Jan 2026 08:29:28 -0500 Subject: [PATCH 004/100] fix typo/paste error with labels --- ui/raidboss/data/07-dt/raid/r12s.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index b3f0f22ee0..e3186605a4 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -136,10 +136,10 @@ hideall "--sync--" 456.1 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 459.8 "Serpentine Scourge Right" Ability { id: "B4D2", source: "Lindwurm" } 460.8 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -464.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-slaughtershed2" +464.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" # Serpentine Scourge Right First -540.6 label jump "r12s-p1-scourge-right-1" +540.6 label "r12s-p1-scourge-right-1" 547.6 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } 547.6 "Fourth-wall Fusion" Ability { id: "B4D5", source: "Lindwurm" } 548.0 "Burst" Ability { id: "B49F", source: "Lindwurm" } @@ -147,7 +147,7 @@ hideall "--sync--" 554.1 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 557.7 "Serpentine Scourge Left" Ability { id: "B4D1", source: "Lindwurm" } 558.7 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -562.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-slaughtershed2" +562.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" # Raptor Knuckles Left First 641.1 label "r12s-p1-raptor-left-1" @@ -158,7 +158,7 @@ hideall "--sync--" 654.4 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 658.3 "Raptor Knuckles Northwest" Ability { id: "B4CF", source: "Lindwurm" } 659.1 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -662.9 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-slaughtershed2" +662.9 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" # Raptor Knuckles Right First 742.7 label "r12s-p1-raptor-right-1" @@ -169,10 +169,10 @@ hideall "--sync--" 756.1 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 759.9 "Raptor Knuckles Northeast" Ability { id: "B4D0", source: "Lindwurm" } 760.7 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -764.5 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-slaughtershed2" +764.5 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" # Slaughtershed 2 -864.4 label "r12s-slaughtershed2" +864.4 label "r12s-p1-slaughtershed2" 867.4 "Slaughtershed 2 (castbar)" Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } 869.8 "Slaughtershed 2" Ability { id: "ADC9", source: "Lindwurm" } From d0a69406bc9a60243f2309a5ce714ae9a77291a2 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 08:35:12 -0500 Subject: [PATCH 005/100] add missing capture --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 961273b747..9394d7cf0a 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -839,7 +839,7 @@ const triggerSet: TriggerSet = { // B4A2 is only cast when intercardinals are safe // These casts more than once, so just capture first event type: 'StartsUsing', - netRegex: { id: ['B4A1', 'B4A2'], capture: false }, + netRegex: { id: ['B4A1', 'B4A2'], capture: true }, suppressSeconds: 5, infoText: (data, matches, output) => { const count = data.myMitoticPhase; From e6bbdf107ad4bfc6f1962e6b334414deabd8dfa7 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 08:35:40 -0500 Subject: [PATCH 006/100] remove erroneous 3 character --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index e3186605a4..faa2d1a78b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -245,7 +245,7 @@ hideall "--sync--" 1400.4 "--sync--" Ability { id: "B4CC", source: "Lindwurm" } jump "r12s-p1-raptor-right-3" 1407.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } 1407.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -1407.8 "Burst" 3Ability { id: "B49F", source: "Lindwurm" } +1407.8 "Burst" Ability { id: "B49F", source: "Lindwurm" } 1412.9 "Serpentine Scourge/Raptor Knuckles?" #Ability { id: ["B4D1", "B4D2", "B4CD", "B4CE"], source: "Lindwurm" } 1413.9 "Serpentine Scourge/--knockback--?" #Ability { id: ["B9BC", "B9C7"], source: "Lindwurm" } 1417.6 "Serpentine Scourge/Raptor Knuckles?" #Ability { id: ["B4D2", "B4D1", "B4CE", "B4CD"], source: "Lindwurm" } From 4226f7bd86b4bff0b6f2d36a0d5c812c6763e0b6 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 08:39:26 -0500 Subject: [PATCH 007/100] paste error --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index faa2d1a78b..9b6e500445 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -288,7 +288,7 @@ hideall "--sync--" 1636.8 "Refreshing Overkill (Enrage)?" #Ability { id: "B53A", source: "Lindwurm" } # Raptor Knuckles Left Third -1700.4 label "r12s-p1-raptor-right-3" +1700.4 label "r12s-p1-raptor-left-3" 1707.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } 1707.4 "Fourth-wall Fusion" Ability { id: "B4D5", source: "Lindwurm" } 1707.8 "Burst" Ability { id: "B49F", source: "Lindwurm" } From e62af8d9ec709631ddc6987c8588319b648d14ed Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 16:08:59 -0500 Subject: [PATCH 008/100] fix ravenous reach 2 calls --- ui/raidboss/data/07-dt/raid/r12s.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 9394d7cf0a..2f6cca8cdc 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -672,7 +672,7 @@ const triggerSet: TriggerSet = { const duration = parseFloat(matches.duration); if (duration > 35) return 27; - return 32; + return 34; }, infoText: (data, matches, output) => { const duration = parseFloat(matches.duration); @@ -909,9 +909,9 @@ const triggerSet: TriggerSet = { condition: (data) => data.phase === 'curtainCall', alertText: (data, matches, output) => { if (matches.id === 'B49A') { - return data.hasRot ? output.getHitEast!() : output.safeWest!(); + return data.hasRot ? output.safeWest!() : output.getHitEast!(); } - return data.hasRot ? output.getHitWest!() : output.safeEast!(); + return data.hasRot ? output.safeEast!() : output.getHitWest!(); }, outputStrings: { getHitWest: { From 2ab3724d8fda030c607dc3ca1fe1331762e0c605 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 17:15:16 -0500 Subject: [PATCH 009/100] update curtain call break chains TODO: Find safe spots. --- ui/raidboss/data/07-dt/raid/r12s.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 2f6cca8cdc..a8781ec455 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -961,6 +961,7 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Curtain Call: Unbreakable Flesh α/β Chains', + // TODO: Find safe spots type: 'GainsEffect', netRegex: { effectId: ['1291', '1293'], capture: true }, condition: (data, matches) => { @@ -970,13 +971,23 @@ const triggerSet: TriggerSet = { }, infoText: (_data, matches, output) => { const flesh = matches.effectId === '1291' ? 'alpha' : 'beta'; + const safeSpots = output.safeSpots!(); + const chains = output.breakChains!(); if (flesh === 'alpha') - return output.alphaChains!(); - return output.betaChains!(); + return output.alphaChains!( chains: chains, safe: safeSpots ); + return output.betaChains!( chains: chains, safeSpots ); }, outputStrings: { - alphaChains: Outputs.breakChains, - betaChains: Outputs.breakChains, + breakChains: Outputs.breakChains, + safeSpots: { + en: 'Avoid Blobs', + }, + alphaChains: { + en: '${chains} => ${safeSpots}', + }, + betaChains: { + en: '${chains} => ${safeSpots}', + }, }, }, { From 467ee5b0f913deb39c642058706bf5417ac0c9b1 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 17:17:53 -0500 Subject: [PATCH 010/100] fix previous commit --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index a8781ec455..c7455fea27 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -974,8 +974,8 @@ const triggerSet: TriggerSet = { const safeSpots = output.safeSpots!(); const chains = output.breakChains!(); if (flesh === 'alpha') - return output.alphaChains!( chains: chains, safe: safeSpots ); - return output.betaChains!( chains: chains, safeSpots ); + return output.alphaChains!({ chains: chains, safe: safeSpots }); + return output.betaChains!({ chains: chains, safe: safeSpots }); }, outputStrings: { breakChains: Outputs.breakChains, From 3a166e7ea1ba75ded13edfd16a64d7e5d07b4e72 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 18:00:59 -0500 Subject: [PATCH 011/100] blob towers called via pattern, add knockback for bind --- ui/raidboss/data/07-dt/raid/r12s.ts | 81 +++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index c7455fea27..81947c8f61 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -438,43 +438,56 @@ const triggerSet: TriggerSet = { // Blob 4: (86, 90) NW Outer type: 'Ability', netRegex: { id: 'B4B6', capture: true }, + suppressSeconds: 10, run: (data, matches) => { const x = parseFloat(matches.x); const y = parseFloat(matches.y); + const dir = Directions.xyToIntercardDirOutput(x, y, center.x, center.y); data.blobTowerDirs.push(Directions.xyToIntercardDirOutput(x, y, center.x, center.y)); + + if (dir === 'dirSE') { + data.blobTowerDirs.push('dirNW'); + data.blobTowerDirs.push('dirSW'); + data.blobTowerDirs.push('dirNE'); + } + else if (dir === 'dirNE') { + data.blobTowerDirs.push('dirSW'); + data.blobTowerDirs.push('dirNW'); + data.blobTowerDirs.push('dirSE'); + } + else if (dir === 'dirNW') { + data.blobTowerDirs.push('dirSE'); + data.blobTowerDirs.push('dirNE'); + data.blobTowerDirs.push('dirSW'); + } + else if (dir === 'dirSW') { + data.blobTowerDirs.push('dirNE'); + data.blobTowerDirs.push('dirSE'); + data.blobTowerDirs.push('dirNW'); + } }, }, { id: 'R12S Phagocyte Spotlight Blob Tower Location (Early)', // 23.8s until B4B7 Rolling Mass Blob Tower Hit + // Only need to know first blob location type: 'Ability', netRegex: { id: 'B4B6', capture: false }, - condition: (data) => { - if (data.myFleshBonds === 'alpha') { - const myNum = data.inLine[data.me]; - if ( - (myNum === 1 && data.blobTowerDirs.length === 3) || - (myNum === 2 && data.blobTowerDirs.length === 4) || - (myNum === 3 && data.blobTowerDirs.length === 1) || - (myNum === 4 && data.blobTowerDirs.length === 2) - ) - return true; - } - return false; - }, + condition: (data) => data.myFleshBonds === 'alpha', + suppressSeconds: 10, delaySeconds: 0.1, durationSeconds: (data) => { const myNum = data.inLine[data.me]; // Timings based on next trigger switch (myNum) { case 1: - return 13; + return 17; case 2: - return 16; + return 22; case 3: - return 17; + return 18; case 4: - return 15; + return 18; } }, infoText: (data, _matches, output) => { @@ -517,6 +530,16 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Cursed Coil Bind Knocbkack', + // Using Phagocyte Spotlight, 1st one happens 7s before bind + // Delayed additionally to reduce overlap with alpha tower location calls + type: 'Ability', + netRegex: { id: 'B4B6', capture: false }, + suppressSeconds: 10, + delaySeconds: 4, // 4s warning + response: Responses.knockback(), + }, { id: 'R12S Cell Chain Counter', type: 'Tether', @@ -971,11 +994,20 @@ const triggerSet: TriggerSet = { }, infoText: (_data, matches, output) => { const flesh = matches.effectId === '1291' ? 'alpha' : 'beta'; - const safeSpots = output.safeSpots!(); - const chains = output.breakChains!(); if (flesh === 'alpha') - return output.alphaChains!({ chains: chains, safe: safeSpots }); - return output.betaChains!({ chains: chains, safe: safeSpots }); + return output.alphaChains!({ + chains: output.breakChains!(), + safe: output.safeSpots!(), + }); + if (flesh === 'beta') + return output.betaChains!({ + chains: output.breakChains!(), + safe: output.breakChains!(), + }); + return output.unknownChains!({ + chains: output.breakChains!(), + safe: output.breakChains!(), + }); }, outputStrings: { breakChains: Outputs.breakChains, @@ -983,10 +1015,13 @@ const triggerSet: TriggerSet = { en: 'Avoid Blobs', }, alphaChains: { - en: '${chains} => ${safeSpots}', + en: '${chains} => ${safe}', }, betaChains: { - en: '${chains} => ${safeSpots}', + en: '${chains} => ${safe}', + }, + unknownChains: { + en: '${chains} => ${safe}', }, }, }, From de6493fc1bd27c7608c99421a0983df82680ce6d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 18:03:42 -0500 Subject: [PATCH 012/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 81947c8f61..eebcd89f8b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -449,18 +449,15 @@ const triggerSet: TriggerSet = { data.blobTowerDirs.push('dirNW'); data.blobTowerDirs.push('dirSW'); data.blobTowerDirs.push('dirNE'); - } - else if (dir === 'dirNE') { + } else if (dir === 'dirNE') { data.blobTowerDirs.push('dirSW'); data.blobTowerDirs.push('dirNW'); data.blobTowerDirs.push('dirSE'); - } - else if (dir === 'dirNW') { + } else if (dir === 'dirNW') { data.blobTowerDirs.push('dirSE'); data.blobTowerDirs.push('dirNE'); data.blobTowerDirs.push('dirSW'); - } - else if (dir === 'dirSW') { + } else if (dir === 'dirSW') { data.blobTowerDirs.push('dirNE'); data.blobTowerDirs.push('dirSE'); data.blobTowerDirs.push('dirNW'); From f8651f991e14fd32dfd17b91a45a40390ba25a33 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 18:06:05 -0500 Subject: [PATCH 013/100] replace function with previous dir const --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index eebcd89f8b..fa96229325 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -443,7 +443,7 @@ const triggerSet: TriggerSet = { const x = parseFloat(matches.x); const y = parseFloat(matches.y); const dir = Directions.xyToIntercardDirOutput(x, y, center.x, center.y); - data.blobTowerDirs.push(Directions.xyToIntercardDirOutput(x, y, center.x, center.y)); + data.blobTowerDirs.push(dir); if (dir === 'dirSE') { data.blobTowerDirs.push('dirNW'); From 996bab0dc754ccfebe4a593c2f63c050b0e25263 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 18:07:28 -0500 Subject: [PATCH 014/100] fix suppressSeconds order --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index fa96229325..60ef978f95 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -471,7 +471,6 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B4B6', capture: false }, condition: (data) => data.myFleshBonds === 'alpha', - suppressSeconds: 10, delaySeconds: 0.1, durationSeconds: (data) => { const myNum = data.inLine[data.me]; @@ -487,6 +486,7 @@ const triggerSet: TriggerSet = { return 18; } }, + suppressSeconds: 10, infoText: (data, _matches, output) => { const myNum = data.inLine[data.me]; if (myNum === undefined) @@ -533,8 +533,8 @@ const triggerSet: TriggerSet = { // Delayed additionally to reduce overlap with alpha tower location calls type: 'Ability', netRegex: { id: 'B4B6', capture: false }, - suppressSeconds: 10, delaySeconds: 4, // 4s warning + suppressSeconds: 10, response: Responses.knockback(), }, { From b81f1f649e3c9fc2b32126a649c92279f463ba8a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 18:27:04 -0500 Subject: [PATCH 015/100] add beta Tether => Tower outputs --- ui/raidboss/data/07-dt/raid/r12s.ts | 33 ++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 60ef978f95..4417cd6f9d 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -558,8 +558,27 @@ const triggerSet: TriggerSet = { infoText: (data, _matches, output) => { const myNum = data.inLine[data.me]; const num = data.cellChainCount; - if (myNum !== num) + if (myNum !== num) { + if (myNum === 1 && num === 3) + return output.beta1Tower!({ + tether: output.tether!({ num: num }) + }); + if (myNum === 2 && num === 4) + return output.beta2Tower!({ + tether: output.tether!({ num: num }), + }); + if (myNum === 3 && num === 1) + return output.beta3Tower!({ + tether: output.tether!({num: num }), + }); + if (myNum === 4 && num === 2) + return output.beta4Tower!({ + tether: output.tether!({ num: num }), + }); + return output.tether!({ num: num }); + } + if (myNum === undefined) return output.tether!({ num: num }); }, @@ -573,6 +592,18 @@ const triggerSet: TriggerSet = { ko: '선 ${num}', tc: '線 ${num}', }, + beta1Tower: { + en: '${tether} => Chain Tower 3', + }, + beta2Tower: { + en: '${tether} => Chain Tower 4', + }, + beta3Tower: { + en: '${tether} => Chain Tower 1', + }, + beta4Tower: { + en: '${tether} => Chain Tower 2', + }, }, }, { From 55173924e6c5c2717a3fbe15b31166fe7a837d6b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 18:29:09 -0500 Subject: [PATCH 016/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 4417cd6f9d..8730fd692c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -561,7 +561,7 @@ const triggerSet: TriggerSet = { if (myNum !== num) { if (myNum === 1 && num === 3) return output.beta1Tower!({ - tether: output.tether!({ num: num }) + tether: output.tether!({ num: num }), }); if (myNum === 2 && num === 4) return output.beta2Tower!({ @@ -569,7 +569,7 @@ const triggerSet: TriggerSet = { }); if (myNum === 3 && num === 1) return output.beta3Tower!({ - tether: output.tether!({num: num }), + tether: output.tether!({ num: num }), }); if (myNum === 4 && num === 2) return output.beta4Tower!({ From b298c9552bb7d58bc782432516a83c1d4f8a877d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 19:06:02 -0500 Subject: [PATCH 017/100] fix delay for fist two blob towers --- ui/raidboss/data/07-dt/raid/r12s.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 8730fd692c..df32bdf2c2 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -721,20 +721,21 @@ const triggerSet: TriggerSet = { }, delaySeconds: (_data, matches) => { const duration = parseFloat(matches.duration); - if (duration > 35) - return 27; - return 34; + // The following gives 5s warning to take tower + if (duration > 37) + return 31; // Alpha4 Time + return 26; // Alpha3 Time }, infoText: (data, matches, output) => { const duration = parseFloat(matches.duration); const dir = data.blobTowerDirs[duration > 40 ? 1 : 0]; if (duration > 40) { if (dir !== undefined) - return output.alpha4Dir!({ dir: output[dir]!() }); + return output.alpha4Dir!({ dir: output[dir]!(), dur: duration }); return output.alpha4!(); } if (dir !== undefined) - return output.alpha3Dir!({ dir: output[dir]!() }); + return output.alpha3Dir!({ dir: output[dir]!(), dur: duration }); return output.alpha3!(); }, outputStrings: { @@ -746,10 +747,10 @@ const triggerSet: TriggerSet = { en: 'Get Blob Tower 2', }, alpha3Dir: { - en: 'Blob Tower 1 (Inner ${dir})', + en: 'Blob Tower 1 (Inner ${dir}) ${dur}', }, alpha4Dir: { - en: 'Blob Tower 2 (Inner ${dir})', + en: 'Blob Tower 2 (Inner ${dir}) ${dur}', }, }, }, From e502f7030ff264eaeb0efb26607c86ee32b1672d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 19:10:45 -0500 Subject: [PATCH 018/100] add blob tower followup, reorder triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 149 ++++++++++++++++++---------- 1 file changed, 95 insertions(+), 54 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index df32bdf2c2..74bd2ae545 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -21,6 +21,7 @@ export interface Data extends RaidbossData { inLine: { [name: string]: number }; blobTowerDirs: string[]; fleshBondsCount: number; + skinsplitterCount: number; cellChainCount: number; cellTowerCount: number; myMitoticPhase?: string; @@ -63,6 +64,7 @@ const triggerSet: TriggerSet = { // Phase 1 inLine: {}, blobTowerDirs: [], + skinsplitterCount: 0, fleshBondsCount: 0, cellChainCount: 0, cellTowerCount: 0, @@ -537,6 +539,21 @@ const triggerSet: TriggerSet = { suppressSeconds: 10, response: Responses.knockback(), }, + { + id: 'R12S Skinsplitter Counter', + // These occur every 5s + // Useful for blob tower tracking that happen 2s after + // 2: Tether 1 + // 3: Tether 2 + Blob Tower 1 + // 4: Tether 3 + Blob Tower 2 + // 5: Tether 4 + Blob Tower 3 + // 6: Blob Tower 4 + // 7: Last time to exit + type: 'Ability', + netRegex: { id: 'B4BC', capture: false }, + suppressSeconds: 1, + run: (data) => data.skinsplitterCount = data.skinsplitterCount + 1, + }, { id: 'R12S Cell Chain Counter', type: 'Tether', @@ -655,56 +672,6 @@ const triggerSet: TriggerSet = { suppressSeconds: 1, run: (data) => data.cellTowerCount = data.cellTowerCount + 1, }, - { - id: 'R12S Chain Tower Followup', - // Using B4B3 Roiling Mass to detect chain tower soak - // Beta player leaving early may get hit by alpha's chain break aoe - type: 'Ability', - netRegex: { id: 'B4B3', capture: true }, - condition: (data, matches) => { - if (data.myFleshBonds === 'beta' && data.me === matches.target) - return true; - return false; - }, - infoText: (data, _matches, output) => { - const mechanicNum = data.cellTowerCount; - const myNum = data.inLine[data.me]; - if (myNum === undefined) - return; - - type index = { - [key: number]: number; - }; - const myNumToOrder: index = { - 1: 3, - 2: 4, - 3: 1, - 4: 2, - }; - - const myOrder = myNumToOrder[myNum]; - if (myOrder === undefined) - return; - - if (myOrder === mechanicNum) { - if (mechanicNum < 4) - return output.goIntoMiddle!(); - return output.getOut!(); - } - }, - outputStrings: { - getOut: { - en: 'Get Out', - de: 'Raus da', - fr: 'Sortez', - ja: '外へ', - cn: '远离', - ko: '밖으로', - tc: '遠離', - }, - goIntoMiddle: Outputs.goIntoMiddle, - }, - }, { id: 'R12S Bonds of Flesh Flesh α First Two Towers', // These are not dependent on player timings and so can be hard coded by duration @@ -844,6 +811,80 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Chain Tower Followup', + // Using B4B3 Roiling Mass to detect chain tower soak + // Beta player leaving early may get hit by alpha's chain break aoe + type: 'Ability', + netRegex: { id: 'B4B3', capture: true }, + condition: (data, matches) => { + if (data.myFleshBonds === 'beta' && data.me === matches.target) + return true; + return false; + }, + infoText: (data, _matches, output) => { + const mechanicNum = data.cellTowerCount; + const myNum = data.inLine[data.me]; + if (myNum === undefined) + return; + + type index = { + [key: number]: number; + }; + const myNumToOrder: index = { + 1: 3, + 2: 4, + 3: 1, + 4: 2, + }; + + const myOrder = myNumToOrder[myNum]; + if (myOrder === undefined) + return; + + if (myOrder === mechanicNum) { + if (mechanicNum < 4) + return output.goIntoMiddle!(); + return output.getOut!(); + } + }, + outputStrings: { + getOut: { + en: 'Get Out', + de: 'Raus da', + fr: 'Sortez', + ja: '外へ', + cn: '远离', + ko: '밖으로', + tc: '遠離', + }, + goIntoMiddle: Outputs.goIntoMiddle, + }, + }, + { + id: 'R12S Blob Tower Followup', + // Using B4B7 Roiling Mass to detect chain tower soak + // Alpha 3 and Alpha 4 get the inner towers before their chains + type: 'Ability', + netRegex: { id: 'B4B7', capture: true }, + condition: (data, matches) => { + if (data.myFleshBonds === 'alpha' && data.me === matches.target) + return true; + return false; + }, + infoText: (data, _matches, output) => { + const mechanicNum = data.skinsplitterCount; + const myNum = data.inLine[data.me]; + if (myNum === undefined) + return; + + if (myNum === mechanicNum) + return output.goIntoMiddle!(); + }, + outputStrings: { + goIntoMiddle: Outputs.goIntoMiddle, + }, + }, { id: 'R12S Splattershed', type: 'StartsUsing', @@ -967,10 +1008,10 @@ const triggerSet: TriggerSet = { }, outputStrings: { getHitWest: { - en: 'Spread in West Breadth', + en: 'Spread in West Cleave', }, getHitEast: { - en: 'Spread in East Breadth', + en: 'Spread in East Cleave', }, safeEast: { en: 'Spread East', @@ -1116,7 +1157,7 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B4CC', source: 'Lindwurm', capture: false }, condition: (data) => data.phase === 'slaughtershed', - durationSeconds: 12, + durationSeconds: 15, infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { @@ -1130,7 +1171,7 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B4CE', source: 'Lindwurm', capture: false }, condition: (data) => data.phase === 'slaughtershed', - durationSeconds: 12, + durationSeconds: 15, infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { From 310a608cfcf4f6027173b51f57b504264e382e2e Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 20:25:14 -0500 Subject: [PATCH 019/100] rework chain tower to use skinsplitter count --- ui/raidboss/data/07-dt/raid/r12s.ts | 109 +++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 11 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 74bd2ae545..ce6a537fb2 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -23,7 +23,6 @@ export interface Data extends RaidbossData { fleshBondsCount: number; skinsplitterCount: number; cellChainCount: number; - cellTowerCount: number; myMitoticPhase?: string; hasRot: boolean; // Phase 2 @@ -67,7 +66,6 @@ const triggerSet: TriggerSet = { skinsplitterCount: 0, fleshBondsCount: 0, cellChainCount: 0, - cellTowerCount: 0, hasRot: false, // Phase 2 }), @@ -663,15 +661,6 @@ const triggerSet: TriggerSet = { }, }, }, - { - id: 'R12S Chain Tower Counter', - // Using B4B3 Roiling Mass to detect chain tower soak - // Also using B4B2 Unmitigated Explosion if missed tower - type: 'Ability', - netRegex: { id: ['B4B3', 'B4B2'], capture: false }, - suppressSeconds: 1, - run: (data) => data.cellTowerCount = data.cellTowerCount + 1, - }, { id: 'R12S Bonds of Flesh Flesh α First Two Towers', // These are not dependent on player timings and so can be hard coded by duration @@ -860,6 +849,104 @@ const triggerSet: TriggerSet = { }, goIntoMiddle: Outputs.goIntoMiddle, }, + }, { + id: 'R12S Chain Tower Followup', + // Using B4B3 Roiling Mass to detect chain tower soak + // Beta player leaving early may get hit by alpha's chain break aoe + type: 'Ability', + netRegex: { id: 'B4B3', capture: true }, + condition: (data, matches) => { + if (data.myFleshBonds === 'beta' && data.me === matches.target) + return true; + return false; + }, + infoText: (data, _matches, output) => { + // Possibly the count could be off if break late (giving damage and damage down) + // Ideal towers are soaked: + // Beta 1 at 5th Skinsplitter + // Beta 2 at 6th Skinsplitter + // Beta 3 at 3rd Skinsplitter + // Beta 4 at 4rth Skinsplitter + const mechanicNum = data.skinsplitterCount; + const myNum = data.inLine[data.me]; + if (myNum === undefined) { + // This can be corrected by the player later + if (mechanicNum < 5) + return output.goIntoMiddle!(); + return output.getOut!(); + } + + if (mechanicNum < 5) { + if (myNum === 1) + return output.beta1Middle!(); + if (myNum === 2) + return output.beta2Middle!(); + if (myNum === 3) + return output.beta3Middle!(); + if (myNum === 4) + return output.beta4Middle!(); + } + if (myNum === 1) + return output.beta1Out!(); + if (myNum === 2) + return output.beta2Out!(); + if (myNum === 3) + return output.beta3Out!(); + if (myNum === 4) + return output.beta4Out!(); + }, + outputStrings: { + getOut: { + en: 'Get Out', + de: 'Raus da', + fr: 'Sortez', + ja: '外へ', + cn: '远离', + ko: '밖으로', + tc: '遠離', + }, + goIntoMiddle: Outputs.goIntoMiddle, + beta1Middle: Outputs.goIntoMiddle, + beta2Middle: Outputs.goIntoMiddle, // Should not happen under ideal situation + beta3Middle: Outputs.goIntoMiddle, + beta4Middle: Outputs.goIntoMiddle, + beta1Out: { // Should not happen under ideal situation + en: 'Get Out', + de: 'Raus da', + fr: 'Sortez', + ja: '外へ', + cn: '远离', + ko: '밖으로', + tc: '遠離', + }, + beta2Out: { + en: 'Get Out', + de: 'Raus da', + fr: 'Sortez', + ja: '外へ', + cn: '远离', + ko: '밖으로', + tc: '遠離', + }, + beta3Out: { // Should not happen under ideal situation + en: 'Get Out', + de: 'Raus da', + fr: 'Sortez', + ja: '外へ', + cn: '远离', + ko: '밖으로', + tc: '遠離', + }, + beta4Out: { // Should not happen under ideal situation + en: 'Get Out', + de: 'Raus da', + fr: 'Sortez', + ja: '外へ', + cn: '远离', + ko: '밖으로', + tc: '遠離', + }, + }, }, { id: 'R12S Blob Tower Followup', From 52e9f7f859d3fa56f632ae0054f6a24ba3553050 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 20:26:21 -0500 Subject: [PATCH 020/100] remove a duration from output --- ui/raidboss/data/07-dt/raid/r12s.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ce6a537fb2..4a309114f4 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -687,11 +687,11 @@ const triggerSet: TriggerSet = { const dir = data.blobTowerDirs[duration > 40 ? 1 : 0]; if (duration > 40) { if (dir !== undefined) - return output.alpha4Dir!({ dir: output[dir]!(), dur: duration }); + return output.alpha4Dir!({ dir: output[dir]!() }); return output.alpha4!(); } if (dir !== undefined) - return output.alpha3Dir!({ dir: output[dir]!(), dur: duration }); + return output.alpha3Dir!({ dir: output[dir]!() }); return output.alpha3!(); }, outputStrings: { @@ -703,10 +703,10 @@ const triggerSet: TriggerSet = { en: 'Get Blob Tower 2', }, alpha3Dir: { - en: 'Blob Tower 1 (Inner ${dir}) ${dur}', + en: 'Blob Tower 1 (Inner ${dir})', }, alpha4Dir: { - en: 'Blob Tower 2 (Inner ${dir}) ${dur}', + en: 'Blob Tower 2 (Inner ${dir})', }, }, }, From 29da224ebab32b97f532ea0c4f8b8d0b08e8060a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 20:29:43 -0500 Subject: [PATCH 021/100] fix paste error --- ui/raidboss/data/07-dt/raid/r12s.ts | 49 ----------------------------- 1 file changed, 49 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 4a309114f4..ed9c8f09d5 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -801,55 +801,6 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Chain Tower Followup', - // Using B4B3 Roiling Mass to detect chain tower soak - // Beta player leaving early may get hit by alpha's chain break aoe - type: 'Ability', - netRegex: { id: 'B4B3', capture: true }, - condition: (data, matches) => { - if (data.myFleshBonds === 'beta' && data.me === matches.target) - return true; - return false; - }, - infoText: (data, _matches, output) => { - const mechanicNum = data.cellTowerCount; - const myNum = data.inLine[data.me]; - if (myNum === undefined) - return; - - type index = { - [key: number]: number; - }; - const myNumToOrder: index = { - 1: 3, - 2: 4, - 3: 1, - 4: 2, - }; - - const myOrder = myNumToOrder[myNum]; - if (myOrder === undefined) - return; - - if (myOrder === mechanicNum) { - if (mechanicNum < 4) - return output.goIntoMiddle!(); - return output.getOut!(); - } - }, - outputStrings: { - getOut: { - en: 'Get Out', - de: 'Raus da', - fr: 'Sortez', - ja: '外へ', - cn: '远离', - ko: '밖으로', - tc: '遠離', - }, - goIntoMiddle: Outputs.goIntoMiddle, - }, - }, { id: 'R12S Chain Tower Followup', // Using B4B3 Roiling Mass to detect chain tower soak // Beta player leaving early may get hit by alpha's chain break aoe From 01b9d528850c6d52f1830ecc37e8a7fe51f012f8 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 20:32:03 -0500 Subject: [PATCH 022/100] fix hasRot collect --- ui/raidboss/data/07-dt/raid/r12s.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ed9c8f09d5..d391bcbab8 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1028,7 +1028,7 @@ const triggerSet: TriggerSet = { type: 'GainsEffect', netRegex: { effectId: '129B', capture: true }, condition: Conditions.targetIsYou(), - run: (data) => data.hasRot === true, + run: (data) => data.hasRot = true, }, { id: 'R12S Ravenous Reach 2', @@ -1040,9 +1040,9 @@ const triggerSet: TriggerSet = { condition: (data) => data.phase === 'curtainCall', alertText: (data, matches, output) => { if (matches.id === 'B49A') { - return data.hasRot ? output.safeWest!() : output.getHitEast!(); + return data.hasRot ? output.getHitEast!(): output.safeWest!(); } - return data.hasRot ? output.safeEast!() : output.getHitWest!(); + return data.hasRot ? output.getHitWest!(): output.safeEast!(); }, outputStrings: { getHitWest: { From 6f4802c4b4d0f109904fc6bb83121224ba9c9e63 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 20:41:29 -0500 Subject: [PATCH 023/100] missing space --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index d391bcbab8..cbf143dfae 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1040,9 +1040,9 @@ const triggerSet: TriggerSet = { condition: (data) => data.phase === 'curtainCall', alertText: (data, matches, output) => { if (matches.id === 'B49A') { - return data.hasRot ? output.getHitEast!(): output.safeWest!(); + return data.hasRot ? output.getHitEast!() : output.safeWest!(); } - return data.hasRot ? output.getHitWest!(): output.safeEast!(); + return data.hasRot ? output.getHitWest!() : output.safeEast!(); }, outputStrings: { getHitWest: { From 17afe3c640065053007d604d9d83ea7253eea56d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 20:43:53 -0500 Subject: [PATCH 024/100] reduce 1s delay for knockback --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index cbf143dfae..de61e2d713 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -533,7 +533,7 @@ const triggerSet: TriggerSet = { // Delayed additionally to reduce overlap with alpha tower location calls type: 'Ability', netRegex: { id: 'B4B6', capture: false }, - delaySeconds: 4, // 4s warning + delaySeconds: 3, // 5s warning suppressSeconds: 10, response: Responses.knockback(), }, From a355b827545ce50affecdfeb7af588e6dfa5a4d6 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 20:48:02 -0500 Subject: [PATCH 025/100] increase break chains to alert and adjust output slightly --- ui/raidboss/data/07-dt/raid/r12s.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index de61e2d713..703ab6cf7e 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -682,7 +682,7 @@ const triggerSet: TriggerSet = { return 31; // Alpha4 Time return 26; // Alpha3 Time }, - infoText: (data, matches, output) => { + alertText: (data, matches, output) => { const duration = parseFloat(matches.duration); const dir = data.blobTowerDirs[duration > 40 ? 1 : 0]; if (duration > 40) { @@ -703,10 +703,10 @@ const triggerSet: TriggerSet = { en: 'Get Blob Tower 2', }, alpha3Dir: { - en: 'Blob Tower 1 (Inner ${dir})', + en: 'Get Blob Tower 1 (Inner ${dir})', }, alpha4Dir: { - en: 'Blob Tower 2 (Inner ${dir})', + en: 'Get Blob Tower 2 (Inner ${dir})', }, }, }, @@ -719,7 +719,7 @@ const triggerSet: TriggerSet = { return true; return false; }, - infoText: (data, matches, output) => { + alertText: (data, matches, output) => { const myNum = data.inLine[data.me]; const flesh = matches.effectId === '1291' ? 'alpha' : 'beta'; if (flesh === 'alpha') { @@ -796,7 +796,7 @@ const triggerSet: TriggerSet = { en: '${chains} 3 => Wait for last pair', }, beta4: { - en: '${chains} 4 + Get Out', + en: '${chains} 4 => Get Out', }, }, }, From 260cebde0ce1bb4bd2c9e05c27f606ca8d000e12 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 20 Jan 2026 20:18:14 -0500 Subject: [PATCH 026/100] add refreshing overkill, some initial p2 triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 703ab6cf7e..892679eb11 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1217,6 +1217,34 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Refreshing Overkill', + // 10s castTime that could end with enrage or raidwide + type: 'StartsUsing', + netRegex: { id: 'B538', source: 'Lindwurm', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 4, + durationSeconds: 4.7, + response: Responses.bigAoe('alert'), + }, + // Phase 2 + { + id: 'R12S Arcadia Aflame', + type: 'StartsUsing', + netRegex: { id: 'B528', source: 'Lindwurm', capture: false }, + response: Responses.bigAoe('alert'), + }, + { + id: 'R12S Snaking Kick', + type: 'StartsUsing', + netRegex: { id: 'B527', source: 'Lindwurm', capture: true }, + response: Responses.getBehind(), + }, + { + id: 'R12S Double Sobat', + type: 'StartsUsing', + netRegex: { id: 'B520', source: 'Lindwurm', capture: true }, + response: Responses.tankCleave(), + }, ], timelineReplace: [], }; From f6ddae7d29cbbe0d4d51ae24550091f47f9d5565 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 20 Jan 2026 20:22:29 -0500 Subject: [PATCH 027/100] fix enrage startsUsing, clean p2 output using addedcombatant sync, add transition --- ui/raidboss/data/07-dt/raid/r12s.txt | 43 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 9b6e500445..5fb6dbf904 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -11,7 +11,7 @@ hideall "--sync--" # -it "Lindwurm" 0.0 "--sync--" InCombat { inGameCombat: "1" } window 0,1 -#1.0 "--sync--" AddedCombatant { npcNameId: "", name: "Lindwurm", job: "00", level: "5A", ownerId: "0{4}", worldId: "00" } window 10,3 jump 3000.5 # Sync to P2 immediately through AddCombatant. +1.0 "--sync--" AddedCombatant { npcNameId: "14378", name: "Lindwurm", job: "00", level: "1", ownerId: "0{4}", worldId: "00" } window 10,3 jump r12s-p2-start # Sync to P2 immediately through AddCombatant. 15.6 "The Fixer" Ability { id: "B4D7", source: "Lindwurm" } window 20,10 25.8 "--sync--" Ability { id: "B7C4", source: "Lindwurm" } 40.9 "Mortal Slayer 1" Ability { id: ["B496", "B498"], source: "Lindwurm" } @@ -264,7 +264,7 @@ hideall "--sync--" 1516.9 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1526.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1526.5 "--untargetable?--" -1527.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" +1526.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" 1531.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1536.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1536.8 "--untargetable?--" @@ -281,7 +281,7 @@ hideall "--sync--" 1618.6 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1626.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1626.5 "--untargetable?--" -1627.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" +1626.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" 1631.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1636.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1636.8 "--untargetable?--" @@ -298,7 +298,7 @@ hideall "--sync--" 1718.3 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1726.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1726.5 "--untargetable?--" -1727.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" +1726.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" 1731.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1736.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1736.8 "--untargetable?--" @@ -315,28 +315,39 @@ hideall "--sync--" 1818.3 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1826.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1826.5 "--untargetable?--" -1827.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" +1826.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" 1831.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1836.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1836.8 "--untargetable?--" 1836.8 "Refreshing Overkill (Enrage)?" #Ability { id: "B53A", source: "Lindwurm" } -# Enrage sequence 1 -1927.7 label "r12s-p1-enrage" -1936.7 "Refreshing Overkill (Enrage)" Ability { id: "B538", source: "Lindwurm" } -1936.8 "--untargetable--" -1936.8 "Refreshing Overkill (Enrage)" Ability { id: "B53A", source: "Lindwurm" } +# Enrage sequence (Above 20%?) +1926.5 label "r12s-p1-enrage-alt" +1931.5 "The Fixer (Enrage)" Ability { id: "B2C7", source: "Lindwurm" } -# Enrage sequence 2 (Above 20%?) -2026.5 label "r12s-p1-enrage-alt" -2031.5 "The Fixer (Enrage)" Ability { id: "B2C7", source: "Lindwurm" } +# Enrage sequence +2027.7 label "r12s-p1-enrage" +2036.7 "Refreshing Overkill (Enrage)?" Ability { id: "B538", source: "Lindwurm" } +2036.8 "--untargetable--" +2036.8 "Refreshing Overkill (Enrage)?" Ability { id: "B53A", source: "Lindwurm" } + +# Kill/Transition sequence +2036.8 "Refreshing Overkill" Ability { id: "B539", source: "Lindwurm" } +2073.0 "--sync--" Ability { id: "BB9C", source: "Lindwurm" } +2073.5 "Down for the Count" duration 42 +2075.7 "--sync--" Ability { id: "B53B", source: "Lindwurm" } +2117.7 "--targetable--" ### Phase 2: Lindwurm II -# -p B528:3014.9 +# -p B528:3012.1 # -ii B51F -3010.2 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 -3014.9 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } +# -it "Lindwurm" +3000.5 label "r12s-p2-start" +3007.1 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 +3012.1 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } +3019.3 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } +3024.4 "Replication" Ability { id: "B4D8", source: "Lindwurm" } # TBD # IGNORED ABILITIES From cbcc8635a71604ec37fa478f74f2591246adc1bf Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 20 Jan 2026 20:23:08 -0500 Subject: [PATCH 028/100] unused capture --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 892679eb11..873a9b1e3b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1236,7 +1236,7 @@ const triggerSet: TriggerSet = { { id: 'R12S Snaking Kick', type: 'StartsUsing', - netRegex: { id: 'B527', source: 'Lindwurm', capture: true }, + netRegex: { id: 'B527', source: 'Lindwurm', capture: false }, response: Responses.getBehind(), }, { From 02615e765616000729a2e2d552f4cb36c8d11654 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 20 Jan 2026 20:23:53 -0500 Subject: [PATCH 029/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 873a9b1e3b..58d5066218 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1222,7 +1222,7 @@ const triggerSet: TriggerSet = { // 10s castTime that could end with enrage or raidwide type: 'StartsUsing', netRegex: { id: 'B538', source: 'Lindwurm', capture: true }, - delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 4, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 4, durationSeconds: 4.7, response: Responses.bigAoe('alert'), }, From 87a0c92bb8fa5063126516bdf2a8c97ba7f1de42 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 20 Jan 2026 20:27:34 -0500 Subject: [PATCH 030/100] add quotes to jump --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 5fb6dbf904..e72d73a4de 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -11,7 +11,7 @@ hideall "--sync--" # -it "Lindwurm" 0.0 "--sync--" InCombat { inGameCombat: "1" } window 0,1 -1.0 "--sync--" AddedCombatant { npcNameId: "14378", name: "Lindwurm", job: "00", level: "1", ownerId: "0{4}", worldId: "00" } window 10,3 jump r12s-p2-start # Sync to P2 immediately through AddCombatant. +1.0 "--sync--" AddedCombatant { npcNameId: "14378", name: "Lindwurm", job: "00", level: "1", ownerId: "0{4}", worldId: "00" } window 10,3 jump "r12s-p2-start" # Sync to P2 immediately through AddCombatant. 15.6 "The Fixer" Ability { id: "B4D7", source: "Lindwurm" } window 20,10 25.8 "--sync--" Ability { id: "B7C4", source: "Lindwurm" } 40.9 "Mortal Slayer 1" Ability { id: ["B496", "B498"], source: "Lindwurm" } From 3016544fbce2ae33e561e9d87ec9f3f991da8810 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 01:53:21 -0500 Subject: [PATCH 031/100] replace forcejumps with jumps + lookahead lines --- ui/raidboss/data/07-dt/raid/r12s.txt | 59 ++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index e72d73a4de..9d3b6c1d36 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -136,7 +136,12 @@ hideall "--sync--" 456.1 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 459.8 "Serpentine Scourge Right" Ability { id: "B4D2", source: "Lindwurm" } 460.8 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -464.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" +464.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed2" +467.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } +469.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } +478.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } +478.5 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } +478.9 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Serpentine Scourge Right First 540.6 label "r12s-p1-scourge-right-1" @@ -147,7 +152,12 @@ hideall "--sync--" 554.1 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 557.7 "Serpentine Scourge Left" Ability { id: "B4D1", source: "Lindwurm" } 558.7 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -562.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" +562.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed2" +567.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } +569.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } +578.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } +578.5 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } +578.9 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Raptor Knuckles Left First 641.1 label "r12s-p1-raptor-left-1" @@ -158,7 +168,12 @@ hideall "--sync--" 654.4 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 658.3 "Raptor Knuckles Northwest" Ability { id: "B4CF", source: "Lindwurm" } 659.1 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -662.9 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" +662.9 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed2" +667.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } +669.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } +678.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } +678.5 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } +678.9 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Raptor Knuckles Right First 742.7 label "r12s-p1-raptor-right-1" @@ -169,7 +184,12 @@ hideall "--sync--" 756.1 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 759.9 "Raptor Knuckles Northeast" Ability { id: "B4D0", source: "Lindwurm" } 760.7 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -764.5 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" +764.5 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed2" +767.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } +769.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } +778.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } +778.5 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } +778.9 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Slaughtershed 2 864.4 label "r12s-p1-slaughtershed2" @@ -199,7 +219,13 @@ hideall "--sync--" 985.1 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 988.7 "Serpentine Scourge Right" Ability { id: "B4D2", source: "Lindwurm" } 989.7 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -993.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" +993.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed3" +996.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } +998.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } +1007.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } +1007.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } +1007.8 "Burst" #Ability { id: "B49F", source: "Lindwurm" } + # Serpentine Scourge Right Second 1069.9 label "r12s-p1-scourge-right-2" @@ -210,7 +236,13 @@ hideall "--sync--" 1083.4 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1087.0 "Serpentine Scourge Left" Ability { id: "B4D1", source: "Lindwurm" } 1088.0 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -1091.7 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" +1091.7 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed3" +1096.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } +1098.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } +1107.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } +1107.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } +1107.8 "Burst" #Ability { id: "B49F", source: "Lindwurm" } + # Raptor Knuckles Left Second 1171.5 label "r12s-p1-raptor-left-2" @@ -221,7 +253,13 @@ hideall "--sync--" 1184.8 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1188.6 "Raptor Knuckles Northwest" Ability { id: "B4CF", source: "Lindwurm" } 1189.4 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -1193.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" +1193.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed3" +1196.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } +1198.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } +1207.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } +1207.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } +1207.8 "Burst" #Ability { id: "B49F", source: "Lindwurm" } + # Raptor Knuckles Right Second 1271.5 label "r12s-p1-raptor-right-2" @@ -232,7 +270,12 @@ hideall "--sync--" 1284.8 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1288.6 "Raptor Knuckles Left" Ability { id: "B4D0", source: "Lindwurm" } 1289.4 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -1293.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" +1293.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed3" +1296.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } +1298.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } +1307.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } +1307.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } +1307.8 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Slaughtershed 3 1393.3 label "r12s-p1-slaughtershed3" From e2b389751a58e5bddf67bc15b471140fc7c3aa0b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:02:27 -0500 Subject: [PATCH 032/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 9d3b6c1d36..c439893402 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -136,7 +136,7 @@ hideall "--sync--" 456.1 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 459.8 "Serpentine Scourge Right" Ability { id: "B4D2", source: "Lindwurm" } 460.8 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -464.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed2" +464.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" 467.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } 469.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } 478.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } From 90d95901cfaff59abe1e810a303fd8d93a29eeb1 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:02:35 -0500 Subject: [PATCH 033/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index c439893402..63f5500fda 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -152,7 +152,7 @@ hideall "--sync--" 554.1 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 557.7 "Serpentine Scourge Left" Ability { id: "B4D1", source: "Lindwurm" } 558.7 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -562.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed2" +562.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" 567.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } 569.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } 578.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } From f6e0782a78a84a54fc9d3e9b747fbe7a9cc35f16 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:02:42 -0500 Subject: [PATCH 034/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 63f5500fda..ab06c68567 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -168,7 +168,7 @@ hideall "--sync--" 654.4 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 658.3 "Raptor Knuckles Northwest" Ability { id: "B4CF", source: "Lindwurm" } 659.1 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -662.9 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed2" +662.9 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" 667.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } 669.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } 678.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } From 3b5dfc088640432896bcb6e3e3d1aa382549997f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:02:49 -0500 Subject: [PATCH 035/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index ab06c68567..7fd55ed452 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -184,7 +184,7 @@ hideall "--sync--" 756.1 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 759.9 "Raptor Knuckles Northeast" Ability { id: "B4D0", source: "Lindwurm" } 760.7 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -764.5 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed2" +764.5 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" 767.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } 769.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } 778.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } From 2b8da9919a4d3135f6034ccdfc00f20e1a41f314 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:02:56 -0500 Subject: [PATCH 036/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 7fd55ed452..6e47875583 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -219,7 +219,7 @@ hideall "--sync--" 985.1 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 988.7 "Serpentine Scourge Right" Ability { id: "B4D2", source: "Lindwurm" } 989.7 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -993.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed3" +993.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" 996.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } 998.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } 1007.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } From a8cfcb285950bc6f357e2e72223c47c4aba1af56 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:03:04 -0500 Subject: [PATCH 037/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 6e47875583..cd28893ef0 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -236,7 +236,7 @@ hideall "--sync--" 1083.4 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1087.0 "Serpentine Scourge Left" Ability { id: "B4D1", source: "Lindwurm" } 1088.0 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } -1091.7 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed3" +1091.7 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" 1096.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } 1098.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } 1107.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } From 86fdb34168f715ec5509cf46005389b4e705735c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:03:12 -0500 Subject: [PATCH 038/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index cd28893ef0..c55defecf2 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -270,7 +270,7 @@ hideall "--sync--" 1284.8 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1288.6 "Raptor Knuckles Left" Ability { id: "B4D0", source: "Lindwurm" } 1289.4 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -1293.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed3" +1293.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" 1296.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } 1298.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } 1307.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } From 72aabfd73e6d3b42ed3af050ef3fdfe46162911b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:03:18 -0500 Subject: [PATCH 039/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index c55defecf2..64c19ed1eb 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -307,7 +307,7 @@ hideall "--sync--" 1516.9 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1526.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1526.5 "--untargetable?--" -1526.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" +1526.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } forcejump "r12s-p1-enrage" 1531.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1536.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1536.8 "--untargetable?--" From 370ae23627b4aca849b17f507d1b1d0a486ecbff Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:03:24 -0500 Subject: [PATCH 040/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 64c19ed1eb..6f654e7dff 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -324,7 +324,7 @@ hideall "--sync--" 1618.6 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1626.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1626.5 "--untargetable?--" -1626.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" +1626.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } forcejump "r12s-p1-enrage" 1631.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1636.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1636.8 "--untargetable?--" From ce82687de3bc08e761854aa58fda9626fe691e76 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:03:30 -0500 Subject: [PATCH 041/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 6f654e7dff..68384da3b7 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -341,7 +341,7 @@ hideall "--sync--" 1718.3 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1726.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1726.5 "--untargetable?--" -1726.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" +1726.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } forcejump "r12s-p1-enrage" 1731.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1736.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1736.8 "--untargetable?--" From ee1274fcd8ff48fb5cd7125f2ff11f850f3e6000 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:03:36 -0500 Subject: [PATCH 042/100] convert to forcejump Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 68384da3b7..577e562617 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -358,7 +358,7 @@ hideall "--sync--" 1818.3 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1826.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1826.5 "--untargetable?--" -1826.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } jump "r12s-p1-enrage" +1826.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } forcejump "r12s-p1-enrage" 1831.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1836.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1836.8 "--untargetable?--" From 5a1d50c78a0a71e8d342c8d6ebd5e9b00d7c053e Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 22 Jan 2026 21:13:35 -0500 Subject: [PATCH 043/100] move enrage forcejump and add window This should let the jump still have a lookahead without the forcejump incorrectly overwriting it. --- ui/raidboss/data/07-dt/raid/r12s.txt | 55 +++------------------------- 1 file changed, 6 insertions(+), 49 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 577e562617..2ad4543137 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -137,11 +137,6 @@ hideall "--sync--" 459.8 "Serpentine Scourge Right" Ability { id: "B4D2", source: "Lindwurm" } 460.8 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 464.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" -467.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } -469.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } -478.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } -478.5 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -478.9 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Serpentine Scourge Right First 540.6 label "r12s-p1-scourge-right-1" @@ -153,11 +148,6 @@ hideall "--sync--" 557.7 "Serpentine Scourge Left" Ability { id: "B4D1", source: "Lindwurm" } 558.7 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 562.4 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" -567.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } -569.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } -578.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } -578.5 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -578.9 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Raptor Knuckles Left First 641.1 label "r12s-p1-raptor-left-1" @@ -169,11 +159,6 @@ hideall "--sync--" 658.3 "Raptor Knuckles Northwest" Ability { id: "B4CF", source: "Lindwurm" } 659.1 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 662.9 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" -667.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } -669.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } -678.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } -678.5 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -678.9 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Raptor Knuckles Right First 742.7 label "r12s-p1-raptor-right-1" @@ -185,11 +170,6 @@ hideall "--sync--" 759.9 "Raptor Knuckles Northeast" Ability { id: "B4D0", source: "Lindwurm" } 760.7 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 764.5 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed2" -767.4 "Slaughtershed 2 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } -769.8 "Slaughtershed 2" #Ability { id: "ADC9", source: "Lindwurm" } -778.5 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } -778.5 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -778.9 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Slaughtershed 2 864.4 label "r12s-p1-slaughtershed2" @@ -220,12 +200,6 @@ hideall "--sync--" 988.7 "Serpentine Scourge Right" Ability { id: "B4D2", source: "Lindwurm" } 989.7 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 993.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" -996.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } -998.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } -1007.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } -1007.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -1007.8 "Burst" #Ability { id: "B49F", source: "Lindwurm" } - # Serpentine Scourge Right Second 1069.9 label "r12s-p1-scourge-right-2" @@ -237,12 +211,6 @@ hideall "--sync--" 1087.0 "Serpentine Scourge Left" Ability { id: "B4D1", source: "Lindwurm" } 1088.0 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1091.7 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" -1096.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } -1098.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } -1107.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } -1107.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -1107.8 "Burst" #Ability { id: "B49F", source: "Lindwurm" } - # Raptor Knuckles Left Second 1171.5 label "r12s-p1-raptor-left-2" @@ -253,13 +221,7 @@ hideall "--sync--" 1184.8 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1188.6 "Raptor Knuckles Northwest" Ability { id: "B4CF", source: "Lindwurm" } 1189.4 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } -1193.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } jump "r12s-p1-slaughtershed3" -1196.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } -1198.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } -1207.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } -1207.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -1207.8 "Burst" #Ability { id: "B49F", source: "Lindwurm" } - +1193.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" # Raptor Knuckles Right Second 1271.5 label "r12s-p1-raptor-right-2" @@ -271,11 +233,6 @@ hideall "--sync--" 1288.6 "Raptor Knuckles Left" Ability { id: "B4D0", source: "Lindwurm" } 1289.4 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1293.3 "--sync--" StartsUsing { id: ["B4C3", "B4C6"], source: "Lindwurm" } forcejump "r12s-p1-slaughtershed3" -1296.3 "Slaughtershed 3 (castbar)" #Ability { id: ["B4C3", "B4C6"], source: "Lindwurm" } -1298.7 "Slaughtershed 3" #Ability { id: "ADC9", source: "Lindwurm" } -1307.4 "Dramatic Lysis x4" #Ability { id: "B4D4", source: "Lindwurm" } -1307.4 "Fourth-wall Fusion" #Ability { id: "B4D5", source: "Lindwurm" } -1307.8 "Burst" #Ability { id: "B49F", source: "Lindwurm" } # Slaughtershed 3 1393.3 label "r12s-p1-slaughtershed3" @@ -307,11 +264,11 @@ hideall "--sync--" 1516.9 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1526.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1526.5 "--untargetable?--" -1526.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } forcejump "r12s-p1-enrage" 1531.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1536.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1536.8 "--untargetable?--" 1536.8 "Refreshing Overkill (Enrage)?" #Ability { id: "B53A", source: "Lindwurm" } +1546.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } window 20,3 forcejump "r12s-p1-enrage" # Serpentine Scourge Right Third 1600.4 label "r12s-p1-scourge-right-3" @@ -324,11 +281,11 @@ hideall "--sync--" 1618.6 "Serpentine Scourge" Ability { id: "B9BC", source: "Lindwurm" } 1626.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1626.5 "--untargetable?--" -1626.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } forcejump "r12s-p1-enrage" 1631.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1636.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1636.8 "--untargetable?--" 1636.8 "Refreshing Overkill (Enrage)?" #Ability { id: "B53A", source: "Lindwurm" } +1646.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } window 20,3 forcejump "r12s-p1-enrage" # Raptor Knuckles Left Third 1700.4 label "r12s-p1-raptor-left-3" @@ -341,11 +298,11 @@ hideall "--sync--" 1718.3 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1726.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1726.5 "--untargetable?--" -1726.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } forcejump "r12s-p1-enrage" 1731.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1736.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1736.8 "--untargetable?--" 1736.8 "Refreshing Overkill (Enrage)?" #Ability { id: "B53A", source: "Lindwurm" } +1746.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } window 20,3 forcejump "r12s-p1-enrage" # Raptor Knuckles Right Third 1800.4 label "r12s-p1-raptor-right-3" @@ -358,11 +315,11 @@ hideall "--sync--" 1818.3 "--knockback--" Ability { id: "B9C7", source: "Lindwurm" } 1826.5 "--sync--" StartsUsing { id: "B2C7", source: "Lindwurm" } jump "r12s-p1-enrage-alt" 1826.5 "--untargetable?--" -1826.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } forcejump "r12s-p1-enrage" 1831.5 "The Fixer (Enrage)?" #Ability { id: "B2C7", source: "Lindwurm" } 1836.7 "Refreshing Overkill (Enrage)?" #Ability { id: "B538", source: "Lindwurm" } 1836.8 "--untargetable?--" 1836.8 "Refreshing Overkill (Enrage)?" #Ability { id: "B53A", source: "Lindwurm" } +1846.7 "--sync--" StartsUsing { id: "B538", source: "Lindwurm" } window 20,3 forcejump "r12s-p1-enrage" # Enrage sequence (Above 20%?) 1926.5 label "r12s-p1-enrage-alt" @@ -375,7 +332,7 @@ hideall "--sync--" 2036.8 "Refreshing Overkill (Enrage)?" Ability { id: "B53A", source: "Lindwurm" } # Kill/Transition sequence -2036.8 "Refreshing Overkill" Ability { id: "B539", source: "Lindwurm" } +2036.8 "Refreshing Overkill" Ability { id: "B539", source: "Lindwurm" } window 510,5 2073.0 "--sync--" Ability { id: "BB9C", source: "Lindwurm" } 2073.5 "Down for the Count" duration 42 2075.7 "--sync--" Ability { id: "B53B", source: "Lindwurm" } From dab93fd3f68e405c70b69a484769c19ec32b7c6c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 23 Jan 2026 21:14:04 -0500 Subject: [PATCH 044/100] change p2 tankbuster to use headmarker --- ui/raidboss/data/07-dt/raid/r12s.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 58d5066218..e94b790470 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -42,6 +42,8 @@ const headMarkerData = { 'slaughterSpread': '0177', 'cellChainTether': '016E', // Phase 2 + // VFX: sharelaser2tank5sec_c0k1, used by Double Sobat (B520) + 'sharedTankbuster': '0256', } as const; const center = { @@ -1241,9 +1243,11 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Double Sobat', - type: 'StartsUsing', - netRegex: { id: 'B520', source: 'Lindwurm', capture: true }, - response: Responses.tankCleave(), + // Two half-room cleaves + // First hit targets highest emnity target, second targets second highest + type: 'HeadMarker', + netRegex: { id: headMarkerData['sharedTankbuster'], capture: true }, + response: Responses.sharedTankBuster(), }, ], timelineReplace: [], From 9a16fd09853a473afc9b77ac3a42487717cbcf91 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sat, 24 Jan 2026 20:01:49 -0500 Subject: [PATCH 045/100] add p2 replication 1 triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 225 +++++++++++++++++++++++++++- 1 file changed, 224 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index e94b790470..9c7cebc908 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -7,7 +7,13 @@ import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; -export type Phase = 'doorboss' | 'curtainCall' | 'slaughtershed' | 'two'; +export type Phase = + | 'doorboss' + | 'curtainCall' + | 'slaughtershed' + | 'replication1' + | 'replication2' + | 'idyllic'; export interface Data extends RaidbossData { phase: Phase; @@ -26,6 +32,10 @@ export interface Data extends RaidbossData { myMitoticPhase?: string; hasRot: boolean; // Phase 2 + actorPositions: { [id: string]: { x: number; y: number; heading: number } }; + replication1Debuff?: 'fire' | 'dark'; + replication1FireActor?: string; + replication1FollowUp: boolean; } const headMarkerData = { @@ -54,6 +64,7 @@ const center = { const phaseMap: { [id: string]: Phase } = { 'BEC0': 'curtainCall', 'B4C6': 'slaughtershed', + 'B509': 'idyllic', }; const triggerSet: TriggerSet = { @@ -70,6 +81,8 @@ const triggerSet: TriggerSet = { cellChainCount: 0, hasRot: false, // Phase 2 + actorPositions: {}, + replication1FollowUp: false, }), triggers: [ { @@ -85,6 +98,63 @@ const triggerSet: TriggerSet = { data.phase = phase; }, }, + { + id: 'R12S Phase Two Replication Tracker', + // B4D8 Replication happens more than once, only track the first one + type: 'StartsUsing', + netRegex: { id: 'B4D8', source: 'Lindwurm', capture: false }, + suppressSeconds: 9999, + run: (data) => data.phase = 'replication1', + }, + { + id: 'R12S Phase Two Staging Tracker', + // B4E1 Staging happens more than once, only track the first one + type: 'StartsUsing', + netRegex: { id: 'B4E1', source: 'Lindwurm', capture: false }, + condition: (data) => data.phase === 'replication1', + suppressSeconds: 9999, + run: (data) => data.phase = 'replication2', + }, + { + id: 'R12S Phase Two ActorSetPos Tracker', + type: 'ActorSetPos', + netRegex: { id: '4[0-9A-Fa-f]{7}', capture: true }, + condition: (data) => { + if ( + data.phase === 'replication1' || + data.phase === 'replication2' || + data.phase === 'idyllic' + ) + return true; + return false; + }, + run: (data, matches) => + data.actorPositions[matches.id] = { + x: parseFloat(matches.x), + y: parseFloat(matches.y), + heading: parseFloat(matches.heading), + }, + }, + { + id: 'R12S Phase Two ActorMove Tracker', + type: 'ActorMove', + netRegex: { id: '4[0-9A-Fa-f]{7}', capture: true }, + condition: (data) => { + if ( + data.phase === 'replication1' || + data.phase === 'replication2' || + data.phase === 'idyllic' + ) + return true; + return false; + }, + run: (data, matches) => + data.actorPositions[matches.id] = { + x: parseFloat(matches.x), + y: parseFloat(matches.y), + heading: parseFloat(matches.heading), + }, + }, { id: 'R12S The Fixer', type: 'StartsUsing', @@ -1235,11 +1305,164 @@ const triggerSet: TriggerSet = { netRegex: { id: 'B528', source: 'Lindwurm', capture: false }, response: Responses.bigAoe('alert'), }, + { + id: 'R12S Fire and Dark Resistance Down II Collector', + // CFB Dark Resistance Down II + // B79 Fire Resistance Down II + type: 'GainsEffect', + netRegex: { effectId: ['CFB', 'B79'], capture: true }, + condition: Conditions.targetIsYou(), + suppressSeconds: 9999, + run: (data, matches) => { + data.replication1Debuff = matches.effectId === 'CFB' ? 'dark' : 'fire'; + }, + }, + { + id: 'R12S Fire and Dark Resistance Down II', + // CFB Dark Resistance Down II + // B79 Fire Resistance Down II + type: 'GainsEffect', + netRegex: { effectId: ['CFB', 'B79'], capture: true }, + condition: (data, matches) => { + if (data.me === matches.target) + return !data.replication1FollowUp; + return false; + }, + suppressSeconds: 9999, + infoText: (_data, matches, output) => { + return matches.effectId === 'CFB' ? output.dark!() : output.fire!(); + }, + outputStrings: { + fire: { + en: 'Fire Debuff: Spread near Dark Clone (later)', + }, + dark: { + en: 'Dark Debuff: Stack near Fire Clone (later)', + }, + }, + }, + { + id: 'R12S Fake Fire Resistance Down II', + // Two players will not receive a debuff, they will need to act as if they had + type: 'GainsEffect', + netRegex: { effectId: ['CFB', 'B79'], capture: false }, + condition: (data) => !data.replication1FollowUp, + delaySeconds: 0.3, // Delay for debuff/damage propagation + suppressSeconds: 9999, + infoText: (data, _matches, output) => { + if (data.replication1Debuff === undefined) + return output.noDebuff!(); + }, + outputStrings: { + noDebuff: { + en: 'No Debuff: Spread near Dark Clone (later)', + }, + }, + }, { id: 'R12S Snaking Kick', type: 'StartsUsing', netRegex: { id: 'B527', source: 'Lindwurm', capture: false }, response: Responses.getBehind(), + run: (data) => data.replication1FollowUp = true, + }, + { + id: 'R12S Replication 1 Follow-up Tracker', + // Tracking from B527 Snaking Kick + type: 'StartsUsing', + netRegex: { id: 'B527', source: 'Lindwurm', capture: false }, + suppressSeconds: 9999, + run: (data) => data.replication1FollowUp = true, + }, + { + id: 'R12S Top-Tier Slam Actor Collect', + // Fire NPCs always move in the first Set + // Locations are static + // Fire => Dark => Fire => Dark + // Dark => Fire => Dark => Fire + // The other 4 cleave in a line + // (90, 90) (110, 90) + // (95, 95) (105, 95) + // Boss + // (95, 100) (105, 105) + // (90, 110) (110, 110) + // ActorMove ~0.3s later will have the data + // ActorSet from the clones splitting we can infer the fire entities since their positions and headings are not perfect + type: 'Ability', + netRegex: { id: 'B4D9', source: 'Lindschrat', capture: true }, + condition: (data, matches) => { + if (data.replication1FollowUp) { + const pos = data.actorPositions[matches.sourceId]; + if (pos === undefined) + return false; + // These values should be 0 if coords are x.0000 + const xFilter = pos.x % 1; + const yFilter = pos.y % 1; + if (xFilter === 0 && yFilter === 0 && pos.heading === -0.0001) + return false; + return true; + } + return false; + }, + suppressSeconds: 9999, // Only need one of the two + run: (data, matches) => data.replication1FireActor = matches.sourceId, + }, + { + id: 'R12S Top-Tier Slam/Mighty Magic Locations', + type: 'Ability', + netRegex: { id: 'B4D9', source: 'Lindschrat', capture: false }, + condition: (data) => { + if (data.replication1FollowUp && data.replication1FireActor !== undefined) + return true; + return false; + }, + delaySeconds: 1, // Data is sometimes not available right away + suppressSeconds: 9999, + infoText: (data, _matches, output) => { + const fireId = data.replication1FireActor; + if (fireId === undefined) + return; + + const actor = data.actorPositions[fireId]; + if (actor === undefined) + return; + + const x = actor.x; + const dirNum = Directions.xyTo8DirNum(x, actor.y, center.x, center.y); + const dir1 = Directions.output8Dir[dirNum] ?? 'unknown'; + const dirNum2 = (dirNum + 4) % 8; + const dir2 = Directions.output8Dir[dirNum2] ?? 'unknown'; + + // Check if combatant moved to inner or outer + const isIn = (x > 94 && x < 106); + const fireIn = isIn ? dir1 : dir2; + const fireOut = isIn ? dir2 : dir1; + + if (data.replication1Debuff === 'dark') + return output.fire!({ + dir1: output[fireIn]!(), + dir2: output[fireOut]!(), + }); + + // Dark will be opposite pattern of Fire + const darkIn = isIn ? dir2 : dir1; + const darkOut = isIn ? dir1 : dir2; + + // Fire debuff players and unmarked bait Dark + return output.dark!({ + dir1: output[darkIn]!(), + dir2: output[darkOut]!(), + }); + }, + outputStrings: { + ...Directions.outputStringsIntercardDir, // Cardinals should result in '???' + fire: { + en: 'Bait Fire near In ${dir1}/Out ${dir2} (Partners)', + }, + dark: { + en: 'Bait Dark near In ${dir1}/Out ${dir2} (Solo)', + }, + }, }, { id: 'R12S Double Sobat', From 1bb17bb86372bd2181d27918ec55425e1dc55609 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sat, 24 Jan 2026 20:27:06 -0500 Subject: [PATCH 046/100] add p2 Winged Scourge cleaves --- ui/raidboss/data/07-dt/raid/r12s.ts | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 9c7cebc908..dc329d5811 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1305,6 +1305,38 @@ const triggerSet: TriggerSet = { netRegex: { id: 'B528', source: 'Lindwurm', capture: false }, response: Responses.bigAoe('alert'), }, + { + id: 'R12S Winged Scourge', + // B4DA E/W clones Facing S, Cleaving Front/Back (North/South) + // B4DB N/S clones Facing W, Cleaving Front/Back (East/West) + type: 'StartsUsing', + netRegex: { id: ['B4DA', 'B4DB'], source: 'Lindschrat', capture: true }, + suppressSeconds: 1, + infoText: (data, matches, output) => { + if (matches.id === 'B4DA') { + if (data.replication1FollowUp) + return output.northSouthCleaves2!(); + return output.northSouthCleaves!(); + } + if (data.replication1FollowUp) + return output.eastWestCleaves2!(); + return output.eastWestCleaves!(); + }, + outputStrings: { + northSouthCleaves: { + en: 'North/South Cleaves', + }, + eastWestCleaves: { + en: 'East/West Cleaves', + }, + northSouthCleaves2: { + en: 'North/South Cleaves', + }, + eastWestCleaves2: { + en: 'East/West Cleaves', + }, + }, + }, { id: 'R12S Fire and Dark Resistance Down II Collector', // CFB Dark Resistance Down II From 24e01ec5d0303acace0420d5c697f8ca199d73bc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sat, 24 Jan 2026 20:33:58 -0500 Subject: [PATCH 047/100] p2 timeline up to Replication 2 --- ui/raidboss/data/07-dt/raid/r12s.txt | 120 +++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 6 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 2ad4543137..2ee7c5ea3f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -340,14 +340,31 @@ hideall "--sync--" ### Phase 2: Lindwurm II -# -p B528:3012.1 -# -ii B51F +# -p B528:3015.7 +# -ii B51F B4DA B4DB B4DD B4DF # -it "Lindwurm" 3000.5 label "r12s-p2-start" -3007.1 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 -3012.1 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } -3019.3 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } -3024.4 "Replication" Ability { id: "B4D8", source: "Lindwurm" } +3010.7 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 +3015.7 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } +3022.9 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } +3028.0 "Replication 1" Ability { id: "B4D8", source: "Lindwurm" } +3039.6 "Top-tier Slam x2" #Ability { id: "B4DE", source: "Lindschrat" } +3040.4 "Winged Scourge x4" Ability { id: "B4DC", source: "Lindwurm" } +3040.6 "Mighty Magic x4" #Ability { id: "B4E0", source: "Lindwurm" } +3045.2 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } +3053.8 "--clones move 1--" #Ability { id: "B4D9", source: "Lindschrat" } +3054.8 "--clones move 2--" #Ability { id: "B4D9", source: "Lindschrat" } +3061.0 "Top-tier Slam x2" #Ability { id: "B4DE", source: "Lindschrat" } +3061.8 "Winged Scourge x4" Ability { id: "B4DC", source: "Lindwurm" } +3062.1 "Mighty Magic x4" #Ability { id: "B4E0", source: "Lindwurm" } +3069.3 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3070.0 "Double Sobat 1" Ability { id: "B522", source: "Lindwurm" } +3074.6 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3077.0 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } + +3091.2 "Staging" Ability { id: "B4E1", source: "Lindwurm" } +3102.2 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } +3105.4 "Replication 2" Ability { id: "B4D8", source: "Lindwurm" } # TBD # IGNORED ABILITIES @@ -373,6 +390,11 @@ hideall "--sync--" # Phase 2 # B51F --sync--: Attack autos +# B51F --sync--: Attack autos +# B4DA Winged Scourge: VFX E/W clones Facing S, Cleaving Front/Back (North/South) +# B4DB Winged Scourge: VFX N/S clones Facing W, Cleaving Front/Back (East/West) +# B4DD Top-tier Slam: VFX (cast that gives Fire Debuff) +# B4DF Mighty Magic: VFX (cast that gives Dark Debuff) # ALL ENCOUNTER ABILITIES # Phase 1 @@ -463,3 +485,89 @@ hideall "--sync--" # BEC0 Grotesquerie: Curtain Call # Phase 2 +# B46C Replication +# B4D8 Replication +# B4D9 --sync-- +# B4DA Winged Scourge +# B4DB Winged Scourge +# B4DC Winged Scourge +# B4DD Top-tier Slam +# B4DE Top-tier Slam +# B4DF Mighty Magic +# B4E0 Mighty Magic +# B4E1 Staging +# B4E2 --sync-- +# B4E3 Firefall Splash +# B4E4 Firefall Splash +# B4E5 Scalding Waves +# B4E6 Mana Burst +# B4E7 Mana Burst +# B51F --sync-- +# B4E8 Heavy Slam +# B4E9 Grotesquerie +# B4EA Grotesquerie +# B4EB Hemorrhagic Projection +# B4EC Reenactment +# B4ED Firefall Splash +# B4EE Mana Burst +# B4EF Heavy Slam +# B4F1 Grotesquerie +# B4F2 Lindwurm's Meteor +# B4F3 Downfall +# B4F4 Cosmic Kiss +# B4F6 Lindwurm's Dark II +# B4F7 Lindwurm's Stone III +# B4F8 Lindwurm's Glare +# B4FA Lindwurm's Thunder II +# B4FB Blood Mana +# B4FE Bloody Burst +# B500 Blood Wakening +# B501 Lindwurm's Water III +# B502 Lindwurm's Aero III +# B503 Straightforward Thunder II +# B504 Sideways Fire II +# B505 Mutating Cells +# B506 --sync-- +# B507 Dramatic Lysis +# B509 Idyllic Dream +# B50F Power Gusher +# B510 Power Gusher +# B511 Snaking Kick +# B512 Power Gusher +# B513 Power Gusher +# B514 Power Gusher +# B515 Snaking Kick +# B516 Power Gusher +# B517 Mana Burst +# B518 Mana Burst +# B519 Heavy Slam +# B51A Power Gusher +# B51C Temporal Curtain +# B51D --sync-- +# B51E --sync-- +# B51F Attack +# B520 Double Sobat +# B522 Double Sobat +# B524 Double Sobat +# B525 Double Sobat +# B526 Esoteric Finisher +# B527 Snaking Kick +# B528 Arcadia Aflame +# B529 Arcadian Arcanum +# B52B Netherworld Near +# B52D Wailing Wave +# B52E Netherwrath Near +# B530 Timeless Spite +# B533 Arcadian Hell +# B534 Arcadian Hell +# B535 Arcadian Hell +# B537 Arcadian Hell +# B8E1 Scalding Waves +# B922 Hemorrhagic Projection +# B9D9 Arcadian Arcanum +# BBE2 Twisted Vision +# BBE3 Mana Burst +# BCAF Snaking Kick +# BE5D Heavy Slam +# BE95 Snaking Kick +# BEC1 Arcadian Hell From 0c49083a618fac41c549e5851ae8d2d63ef50f9d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 00:57:59 -0500 Subject: [PATCH 048/100] p2 timeline up to reenactment 1 --- ui/raidboss/data/07-dt/raid/r12s.txt | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 2ee7c5ea3f..0d58311133 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -341,7 +341,7 @@ hideall "--sync--" ### Phase 2: Lindwurm II # -p B528:3015.7 -# -ii B51F B4DA B4DB B4DD B4DF +# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE # -it "Lindwurm" 3000.5 label "r12s-p2-start" 3010.7 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 @@ -365,6 +365,21 @@ hideall "--sync--" 3091.2 "Staging" Ability { id: "B4E1", source: "Lindwurm" } 3102.2 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } 3105.4 "Replication 2" Ability { id: "B4D8", source: "Lindwurm" } +3128.0 "Firefall Splash" Ability { id: "B4E4", source: "Lindwurm" } +3128.7 "Scalding Waves x4" Ability { id: "B4E5", source: "Lindwurm" } +3130.1 "Mana Burst x3" Ability { id: "B4E7", source: "Lindwurm" } +3135.5 "Heavy Slam x2" Ability { id: "B4E8", source: "Lindschrat" } +3136.7 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } +3137.3 "Hemorrhagic Projection x2" Ability { id: "B4EB", source: "Lindwurm" } +3141.1 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } +3151.3 "Reenactment 1" Ability { id: "B4EC", source: "Lindwurm" } +3159.4 "Firefall Splash" Ability { id: "B4ED", source: "Lindschrat" } +3159.4 "Netherwrath Near/Netherwrath Far" Ability { id: ["B52E", "B52F"], source: "Lindwurm" } +3160.6 "Timeless Spite" Ability { id: "B530", source: "Lindwurm" } +3160.8 "Scalding Waves x4" Ability { id: "B8E1", source: "Lindwurm" } +3164.4 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } +3164.4 "Mana Burst x3" Ability { id: "BBE3", source: "Lindwurm" } +3165.0 "Hemorrhagic Projection x2" Ability { id: "B922", source: "Lindwurm" } # TBD # IGNORED ABILITIES @@ -390,11 +405,16 @@ hideall "--sync--" # Phase 2 # B51F --sync--: Attack autos -# B51F --sync--: Attack autos # B4DA Winged Scourge: VFX E/W clones Facing S, Cleaving Front/Back (North/South) # B4DB Winged Scourge: VFX N/S clones Facing W, Cleaving Front/Back (East/West) # B4DD Top-tier Slam: VFX (cast that gives Fire Debuff) # B4DF Mighty Magic: VFX (cast that gives Dark Debuff) +# B4E3 Firefall Splash: VFX +# B4E6 Mana Burst: VFX +# B4F0 Unmitigated Impact: No one stacked in a Heavy Slam, causes 1035 Sustained Damage DoT +# B4E9 Grotesquerie: VFX +# B4F1 Grotesquerie: VFX used in Reenactment +# B4EE Mana Burst: VFX used in Reenactment # ALL ENCOUNTER ABILITIES # Phase 1 @@ -510,6 +530,7 @@ hideall "--sync--" # B4EC Reenactment # B4ED Firefall Splash # B4EE Mana Burst +# B4F0 Unmitigated Impact # B4EF Heavy Slam # B4F1 Grotesquerie # B4F2 Lindwurm's Meteor @@ -547,6 +568,7 @@ hideall "--sync--" # B51E --sync-- # B51F Attack # B520 Double Sobat +# B521 Double Sobat # B522 Double Sobat # B524 Double Sobat # B525 Double Sobat @@ -555,8 +577,10 @@ hideall "--sync--" # B528 Arcadia Aflame # B529 Arcadian Arcanum # B52B Netherworld Near +# B52C Netherworld Far # B52D Wailing Wave # B52E Netherwrath Near +# B52F Netherwrath Far # B530 Timeless Spite # B533 Arcadian Hell # B534 Arcadian Hell From e7db5d637313367dc834d520744897f993565dc0 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 01:06:46 -0500 Subject: [PATCH 049/100] add replication 2 triggers up to reenactment --- ui/raidboss/data/07-dt/raid/r12s.ts | 386 +++++++++++++++++++++++++++- 1 file changed, 378 insertions(+), 8 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index dc329d5811..b6a8af4fe4 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -13,7 +13,9 @@ export type Phase = | 'slaughtershed' | 'replication1' | 'replication2' - | 'idyllic'; + | 'reenactment1' + | 'idyllic' + | 'reenactment2'; export interface Data extends RaidbossData { phase: Phase; @@ -33,9 +35,13 @@ export interface Data extends RaidbossData { hasRot: boolean; // Phase 2 actorPositions: { [id: string]: { x: number; y: number; heading: number } }; + replicationCounter: number; replication1Debuff?: 'fire' | 'dark'; replication1FireActor?: string; replication1FollowUp: boolean; + replication2TetherMap: { [dirNum: string]: string }; + replication2BossId?: string; + myReplication2Tether?: string; } const headMarkerData = { @@ -54,6 +60,12 @@ const headMarkerData = { // Phase 2 // VFX: sharelaser2tank5sec_c0k1, used by Double Sobat (B520) 'sharedTankbuster': '0256', + // Replication 2 Tethers + 'lockedTether': '0175', // Clone tethers + 'projectionTether': '016F', // Comes from Lindschrat, B4EA Grotesquerie + B4EB Hemorrhagic Projection cleave based on player facing + 'manaBurstTether': '0170', // Comes from Lindschrat, B4E7 Mana Burst defamation + 'heavySlamTether': '0171', // Comes from Lindschrat, B4E8 Heavy Slam stack with projection followup + 'fireballSplashTether': '0176', // Comes from the boss, B4E4 Fireball Splash baited jump } as const; const center = { @@ -82,7 +94,9 @@ const triggerSet: TriggerSet = { hasRot: false, // Phase 2 actorPositions: {}, + replicationCounter: 0, replication1FollowUp: false, + replication2TetherMap: {}, }), triggers: [ { @@ -100,20 +114,38 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Phase Two Replication Tracker', - // B4D8 Replication happens more than once, only track the first one type: 'StartsUsing', netRegex: { id: 'B4D8', source: 'Lindwurm', capture: false }, - suppressSeconds: 9999, - run: (data) => data.phase = 'replication1', + run: (data) => { + if (data.replicationCounter === 0) + data.phase = 'replication1'; + data.replicationCounter = data.replicationCounter + 1; + }, }, { id: 'R12S Phase Two Staging Tracker', // B4E1 Staging happens more than once, only track the first one type: 'StartsUsing', - netRegex: { id: 'B4E1', source: 'Lindwurm', capture: false }, + netRegex: { id: 'B4E1', source: 'Lindwurm', capture: true }, condition: (data) => data.phase === 'replication1', suppressSeconds: 9999, - run: (data) => data.phase = 'replication2', + run: (data, matches) => { + data.phase = 'replication2'; + // Store the boss' id later for checking against tether + data.replication2BossId = matches.sourceId; + }, + }, + { + id: 'R12S Phase Two Reenactment Tracker', + type: 'StartsUsing', + netRegex: { id: 'B4EC', source: 'Lindwurm', capture: false }, + run: (data) => { + if (data.phase === 'replication1') { + data.phase = 'reenactment1'; + return; + } + data.phase = 'reenactment2'; + }, }, { id: 'R12S Phase Two ActorSetPos Tracker', @@ -155,6 +187,26 @@ const triggerSet: TriggerSet = { heading: parseFloat(matches.heading), }, }, + { + id: 'R12S Phase Two AddedCombatant Tracker', + type: 'AddedCombatant', + netRegex: { id: '4[0-9A-Fa-f]{7}', capture: true }, + condition: (data) => { + if ( + data.phase === 'replication1' || + data.phase === 'replication2' || + data.phase === 'idyllic' + ) + return true; + return false; + }, + run: (data, matches) => + data.actorPositions[matches.id] = { + x: parseFloat(matches.x), + y: parseFloat(matches.y), + heading: parseFloat(matches.heading), + }, + }, { id: 'R12S The Fixer', type: 'StartsUsing', @@ -1395,8 +1447,14 @@ const triggerSet: TriggerSet = { id: 'R12S Snaking Kick', type: 'StartsUsing', netRegex: { id: 'B527', source: 'Lindwurm', capture: false }, + condition: (data) => { + // Use Grotesquerie trigger for projection tethered players + const ability = data.myReplication2Tether; + if (ability === headMarkerData['projectionTether']) + return false; + return true; + }, response: Responses.getBehind(), - run: (data) => data.replication1FollowUp = true, }, { id: 'R12S Replication 1 Follow-up Tracker', @@ -1504,8 +1562,320 @@ const triggerSet: TriggerSet = { netRegex: { id: headMarkerData['sharedTankbuster'], capture: true }, response: Responses.sharedTankBuster(), }, + { + id: 'R12S Replication 2 Tethered Clone', + // Combatants are added ~4s before Staging starts casting + // Same tether ID is used for "locked" ability tethers + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: Conditions.targetIsYou(), + suppressSeconds: 9999, + infoText: (data, matches, output) => { + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) + return output.cloneTether!(); + + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + return output.cloneTetherDir!({ dir: output[dir]!() }); + }, + outputStrings: { + ...Directions.outputStrings8Dir, + cloneTether: { + en: 'Tethered to Clone', + }, + cloneTetherDir: { + en: 'Tethered to ${dir} Clone', + }, + }, + }, + { + id: 'R12S Replication 2 Ability Tethers Collect', + // Record and store a map of where the tethers come from and what they do for later + // Boss tether handled separately since boss can move around + type: 'Tether', + netRegex: { + id: [ + headMarkerData['projectionTether'], + headMarkerData['manaBurstTether'], + headMarkerData['heavySlamTether'], + ], + capture: true, + }, + condition: (data) => data.phase === 'replication2', + run: (data, matches) => { + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) + return; + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + data.replication2TetherMap[dirNum] = matches.id; + }, + }, + { + id: 'R12S Replication 2 Ability Tethers Initial Call', + // Occur ~8s after end of Replication 2 cast + type: 'Tether', + netRegex: { + id: [ + headMarkerData['projectionTether'], + headMarkerData['manaBurstTether'], + headMarkerData['heavySlamTether'], + headMarkerData['fireballSplashTether'], + ], + capture: true, + }, + condition: Conditions.targetIsYou(), + suppressSeconds: 9999, // Can get spammy if players have more than 1 tether or swap a lot + infoText: (_data, matches, output) => { + switch (matches.id) { + case headMarkerData['projectionTether']: + return output.projectionTether!(); + case headMarkerData['manaBurstTether']: + return output.manaBurstTether!(); + case headMarkerData['heavySlamTether']: + return output.heavySlamTether!(); + } + return output.fireballSplashTether!(); + }, + outputStrings: { + ...Directions.outputStrings8Dir, + projectionTether: { + en: 'Projection Tether on YOU', + }, + manaBurstTether: { + en: 'Defamation Tether on YOU', + }, + heavySlamTether: { + en: 'Stack Tether on YOU', + }, + fireballSplashTether: { + en: 'Boss Tether on YOU', + }, + }, + }, + { + id: 'R12S Replication 2 Locked Tether 2 Collect', + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: (data, matches) => { + return data.replicationCounter === 2 && data.me === matches.target; + }, + run: (data, matches) => { + // Check if boss tether + if (data.replication2BossId === matches.sourceId) { + data.myReplication2Tether = headMarkerData['fireballSplashTether']; + return; + } + + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) { + // Setting to use that we know we have a tether but couldn't determine what ability it is + data.myReplication2Tether = 'unknown'; + return; + } + + const dirNum = Directions.xyTo8DirNum( + actor.x, + actor.y, + center.x, + center.y, + ); + + // Lookup what the tether was at the same location + const ability = data.replication2TetherMap[dirNum]; + if (ability === undefined) { + // Setting to use that we know we have a tether but couldn't determine what ability it is + data.myReplication2Tether = 'unknown'; + return; + } + data.myReplication2Tether = ability; + } + }, + { + id: 'R12S Replication 2 Locked Tether 2', + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: (data, matches) => { + return data.replicationCounter === 2 && data.me === matches.target; + }, + delaySeconds: 0.1, + infoText: (data, matches, output) => { + // Check if it's the boss + if (data.replication2BossId === matches.sourceId) + return output.fireballSplashTether!({ + mech1: output.baitJump!(), + mech2: output.stackGroups!(), + }); + + switch (data.myReplication2Tether) { + case headMarkerData['projectionTether']: + return output.projectionTether!({ + mech1: output.baitProtean!(), + mech2: output.stackGroups!(), + }); + case headMarkerData['manaBurstTether']: + return output.manaBurstTether!({ + mech1: output.defamationOnYou!(), + mech2: output.stackGroups!(), + }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTether!({ + mech1: output.baitProtean!(), + mech2: output.stackGroups!(), + }); + } + }, + outputStrings: { + defamationOnYou: Outputs.defamationOnYou, + stackGroups: { + en: 'Stack Groups', + de: 'Gruppen-Sammeln', + fr: 'Package en groupes', + ja: '組み分け頭割り', + cn: '分组分摊', + ko: '그룹별 쉐어', + tc: '分組分攤', + }, + baitProtean: { + en: 'Bait Protean from Boss', + }, + baitJump: { + en: 'Bait Boss Jump', + }, + projectionTether: { + en: '${mech1} => ${mech2}', + }, + manaBurstTether: { + en: '${mech1} => ${mech2}', + }, + heavySlamTether: { + en: '${mech1} => ${mech2}', + }, + fireballSplashTether: { + en: '${mech1} => ${mech2}', + }, + }, + }, + { + id: 'R12S Replication 2 Mana Burst Target', + // A player without a tether will be target for defamation + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: false }, + condition: (data) => { + return data.replicationCounter === 2; + }, + delaySeconds: 0.1, + suppressSeconds: 1, + infoText: (data, _matches, output) => { + if (data.myReplication2Tether !== undefined) + return; + return output.noTether!({ + mech1: output.defamationOnYou!(), + mech2: output.stackGroups!(), + }); + }, + outputStrings: { + defamationOnYou: Outputs.defamationOnYou, + stackGroups: { + en: 'Stack Groups', + de: 'Gruppen-Sammeln', + fr: 'Package en groupes', + ja: '組み分け頭割り', + cn: '分组分摊', + ko: '그룹별 쉐어', + tc: '分組分攤', + }, + noTether: { + en: '${mech1} => ${mech2}', + }, + }, + }, + { + id: 'R12S Heavy Slam', + // After B4E7 Mana Burst, Groups must stack up on the heavy slam targetted players + type: 'Ability', + netRegex: { id: 'B4E7', source: 'Lindwurm', capture: false }, + suppressSeconds: 1, + alertText: (data, _matches, output) => { + const ability = data.myReplication2Tether; + switch (ability) { + case headMarkerData['projectionTether']: + return output.projectionTether!({ + mech1: output.stackGroups!(), + mech2: output.lookAway!(), + mech3: output.getBehind!(), + }); + case headMarkerData['manaBurstTether']: + return output.manaBurstTether!({ + mech1: output.stackGroups!(), + mech2: output.getBehind!(), + }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTether!({ + mech1: output.stackGroups!(), + mech2: output.getBehind!(), + }); + case headMarkerData['fireballSplashTether']: + return output.fireballSplashTether!({ + mech1: output.stackGroups!(), + mech2: output.getBehind!(), + }); + } + return output.noTether!({ + mech1: output.stackGroups!(), + mech2: output.getBehind!(), + }); + }, + outputStrings: { + getBehind: Outputs.getBehind, + lookAway: Outputs.lookAway, + stackGroups: { + en: 'Stack Groups', + de: 'Gruppen-Sammeln', + fr: 'Package en groupes', + ja: '組み分け頭割り', + cn: '分组分摊', + ko: '그룹별 쉐어', + tc: '分組分攤', + }, + stackOnYou: Outputs.stackOnYou, + projectionTether: { + en: '${mech1} + ${mech2} => ${mech3}', + }, + manaBurstTether: { + en: '${mech1} => ${mech2}', + }, + heavySlamTether: { + en: '${mech1} => ${mech2}', + }, + fireballSplashTether: { + en: '${mech1} => ${mech2}', + }, + noTether: { + en: '${mech1} => ${mech2}', + }, + }, + }, + { + id: 'R12S Grotesquerie', + // This seems to be the point at which the look for the Snaking Kick is snapshot + // The VFX B4E9 happens ~0.6s before Snaking Kick + // B4EA has the targetted player in it + // B4EB Hemorrhagic Projection conal aoe goes off ~0.5s after in the direction the player was facing + type: 'Ability', + netRegex: { id: 'B4EA', source: 'Lindwurm', capture: true }, + condition: Conditions.targetIsYou(), + response: Responses.getBehind(), + }, + ], + timelineReplace: [ + { + 'locale': 'en', + 'replaceText': { + 'Netherwrath Near/Netherwrath Far': 'Netherwrath Near/Far', + }, + }, ], - timelineReplace: [], }; export default triggerSet; From 6cab7ead8ba6203299e72d93c0a610c1d05f4669 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 01:09:54 -0500 Subject: [PATCH 050/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index b6a8af4fe4..482b066639 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1689,7 +1689,7 @@ const triggerSet: TriggerSet = { return; } data.myReplication2Tether = ability; - } + }, }, { id: 'R12S Replication 2 Locked Tether 2', From 2b265f71850288a40fccdf9305b2f64fb47654bd Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 02:00:17 -0500 Subject: [PATCH 051/100] add Netherwrath Near/Far This mechanic could probably be done several ways, but for consistency I think basing on the tether the player had is a start. Otherwise a default would probably just say to everyone Stacks out, Proteans in or vice versa. --- ui/raidboss/data/07-dt/raid/r12s.ts | 83 +++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 482b066639..65a71219c8 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1867,6 +1867,89 @@ const triggerSet: TriggerSet = { condition: Conditions.targetIsYou(), response: Responses.getBehind(), }, + { + id: 'R12S Netherwrath Near/Far', + type: 'StartsUsing', + netRegex: { id: ['B52E', 'B52F'], source: 'Lindwurm', capture: true }, + infoText: (data, matches, output) => { + const ability = data.myReplication2Tether; + // For telling player in relation to their bait + const spiteBaits = matches.id === 'B52E' ? 'near' : 'far'; + const proteanBaits = matches.id === 'B52E' ? 'far' : 'near'; + + // For telling player in relation to what others will bait + const avoidProtean = matches.id === 'B52E' ? 'out' : 'in'; + const avoidSpite = matches.id === 'B52E' ? 'in' : 'out'; + + switch (ability) { + case headMarkerData['projectionTether']: + return output.projectionTether!({ + proteanBaits: output[proteanBaits]!(), + mech1: output.scaldingWave!(), + mech2: output.stacks!(), + spiteBaits: output[avoidSpite]!(), + }); + case headMarkerData['manaBurstTether']: + return output.manaBurstTether!({ + spiteBaits: output[spiteBaits]!(), + mech1: output.timelessSpite!(), + mech2: output.proteans!(), + proteanBaits: output[avoidProtean]!(), + }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTether!({ + proteanBaits: output[proteanBaits]!(), + mech1: output.scaldingWave!(), + mech2: output.stacks!(), + spiteBaits: output[avoidSpite]!(), + }); + case headMarkerData['fireballSplashTether']: + return output.fireballSplashTether!({ + spiteBaits: output[spiteBaits]!(), + mech1: output.timelessSpite!(), + mech2: output.proteans!(), + proteanBaits: output[avoidProtean]!(), + }); + } + return output.noTether!({ + spiteBaits: output[spiteBaits]!(), + mech1: output.timelessSpite!(), + mech2: output.proteans!(), + proteanBaits: output[avoidProtean]!(), + }); + }, + outputStrings: { + scaldingWave: Outputs.protean, + timelessSpite: Outputs.stackPartner, + stacks: Outputs.stacks, + proteans: { + en: 'Proteans', + }, + near: { + en: 'Be In', + }, + in: Outputs.in, + far: { + en: 'Be Out', + }, + out: Outputs.out, + projectionTether: { + en: '${proteanBaits} + ${mech1} (${mech2} ${spiteBaits})', + }, + manaBurstTether: { + en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', + }, + heavySlamTether: { + en: '${proteanBaits} + ${mech1} (${mech2} ${spiteBaits})', + }, + fireballSplashTether: { + en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', + }, + noTether: { + en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', + }, + }, + }, ], timelineReplace: [ { From a78d8279e60f5cb5d904fea2d80f8e165737a1b9 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 02:22:41 -0500 Subject: [PATCH 052/100] adjust wording for netherwrath and jump bait --- ui/raidboss/data/07-dt/raid/r12s.ts | 32 +++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 65a71219c8..5f5da5f84e 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1740,7 +1740,8 @@ const triggerSet: TriggerSet = { en: 'Bait Protean from Boss', }, baitJump: { - en: 'Bait Boss Jump', + // This must be north to resolve later Netherwrath mechanic + en: 'Bait Jump North', }, projectionTether: { en: '${mech1} => ${mech2}', @@ -1869,17 +1870,18 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Netherwrath Near/Far', + // Boss jumps onto north clone (Firefall Splash mechanic), aoe around the clone + proteans type: 'StartsUsing', netRegex: { id: ['B52E', 'B52F'], source: 'Lindwurm', capture: true }, infoText: (data, matches, output) => { const ability = data.myReplication2Tether; // For telling player in relation to their bait - const spiteBaits = matches.id === 'B52E' ? 'near' : 'far'; - const proteanBaits = matches.id === 'B52E' ? 'far' : 'near'; + const spiteBaits = matches.id === 'B52E' ? 'beNear' : 'beFar'; + const proteanBaits = matches.id === 'B52E' ? 'beFar' : 'beNear'; // For telling player in relation to what others will bait - const avoidProtean = matches.id === 'B52E' ? 'out' : 'in'; - const avoidSpite = matches.id === 'B52E' ? 'in' : 'out'; + const avoidProtean = matches.id === 'B52E' ? 'far' : 'near'; + const avoidSpite = matches.id === 'B52E' ? 'near' : 'far'; switch (ability) { case headMarkerData['projectionTether']: @@ -1925,14 +1927,26 @@ const triggerSet: TriggerSet = { proteans: { en: 'Proteans', }, + beNear: { + en: 'Be Near', + }, + beFar: { + en: 'Be Far', + }, near: { - en: 'Be In', + en: 'Near', + de: 'Nah', + fr: 'Proche', + cn: '近', + ko: '가까이', }, - in: Outputs.in, far: { - en: 'Be Out', + en: 'Far', + de: 'Fern', + fr: 'Loin', + cn: '远', + ko: '멀리', }, - out: Outputs.out, projectionTether: { en: '${proteanBaits} + ${mech1} (${mech2} ${spiteBaits})', }, From 90128e7c64bbff04162708b22d346665262b33d1 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 03:14:21 -0500 Subject: [PATCH 053/100] use drawIn insterad of knockback Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 5f5da5f84e..614444eb2d 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -652,14 +652,14 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Cursed Coil Bind Knocbkack', + id: 'R12S Cursed Coil Bind Draw-in', // Using Phagocyte Spotlight, 1st one happens 7s before bind // Delayed additionally to reduce overlap with alpha tower location calls type: 'Ability', netRegex: { id: 'B4B6', capture: false }, delaySeconds: 3, // 5s warning suppressSeconds: 10, - response: Responses.knockback(), + response: Responses.drawIn(), }, { id: 'R12S Skinsplitter Counter', From 9a050138833e5f5e5126d6b17c85100ede6e8c37 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 03:29:25 -0500 Subject: [PATCH 054/100] fix p2 jump --- ui/raidboss/data/07-dt/raid/r12s.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 0d58311133..ae9bd9eae7 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -11,7 +11,7 @@ hideall "--sync--" # -it "Lindwurm" 0.0 "--sync--" InCombat { inGameCombat: "1" } window 0,1 -1.0 "--sync--" AddedCombatant { npcNameId: "14378", name: "Lindwurm", job: "00", level: "1", ownerId: "0{4}", worldId: "00" } window 10,3 jump "r12s-p2-start" # Sync to P2 immediately through AddCombatant. +1.0 "--sync--" AddedCombatant { npcNameId: "14380", name: "Lindschrat", job: "00", level: "64", ownerId: "0{4}", worldId: "00" } window 10,3 jump "r12s-p2-start" # Sync to P2 immediately through AddCombatant. 15.6 "The Fixer" Ability { id: "B4D7", source: "Lindwurm" } window 20,10 25.8 "--sync--" Ability { id: "B7C4", source: "Lindwurm" } 40.9 "Mortal Slayer 1" Ability { id: ["B496", "B498"], source: "Lindwurm" } From 936de78c2f7dcc3770f6901ba1829a0fb2c25906 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 03:34:16 -0500 Subject: [PATCH 055/100] remove comment about north --- ui/raidboss/data/07-dt/raid/r12s.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 614444eb2d..5b4121726b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1740,8 +1740,7 @@ const triggerSet: TriggerSet = { en: 'Bait Protean from Boss', }, baitJump: { - // This must be north to resolve later Netherwrath mechanic - en: 'Bait Jump North', + en: 'Bait Jump', }, projectionTether: { en: '${mech1} => ${mech2}', @@ -1870,7 +1869,7 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Netherwrath Near/Far', - // Boss jumps onto north clone (Firefall Splash mechanic), aoe around the clone + proteans + // Boss jumps onto clone of player that took Firefall Splash, there is an aoe around the clone + proteans type: 'StartsUsing', netRegex: { id: ['B52E', 'B52F'], source: 'Lindwurm', capture: true }, infoText: (data, matches, output) => { From a23a49a183c3a202467c22268cc1f9a94af14c92 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 04:29:26 -0500 Subject: [PATCH 056/100] add basic Blood Mana/Blood Awakening triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 103 ++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 5b4121726b..d157e3fc74 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -42,6 +42,7 @@ export interface Data extends RaidbossData { replication2TetherMap: { [dirNum: string]: string }; replication2BossId?: string; myReplication2Tether?: string; + myMutation?: 'alpha' | 'beta'; } const headMarkerData = { @@ -1963,6 +1964,108 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Mutation α/β Collect', + // Used in Blood Mana / Blood Awakening Mechanics + // 12A1 Mutation α: Don't get hit + // 12A3 Mutation β: Get Hit + // Players will get opposite debuff after Blood Mana + type: 'GainsEffect', + netRegex: { effectId: ['12A1', '12A3'], capture: true }, + condition: Conditions.targetIsYou(), + run: (data, matches) => { + data.myMutation = matches.effectId === '12A1' ? 'alpha' : 'beta'; + }, + }, + { + id: 'R12S Mutation α/β', + type: 'GainsEffect', + netRegex: { effectId: ['12A1', '12A3'], capture: true }, + condition: Conditions.targetIsYou(), + infoText: (_data, matches, output) => { + if (matches.effectId === '12A1') + return output.alpha!(); + return output.beta!(); + }, + outputStrings: { + alpha: { + en: 'Mutation α on YOU', + }, + beta: { + en: 'Mutation β on YOU', + }, + }, + }, + { + id: 'R12S Blood Mana', + // Black Holes and shapes + // TODO: Tell what shape to pop + which Black Hole mechanics and side? + type: 'Ability', + netRegex: { id: 'B4FB', source: 'Lindwurm', capture: false }, + infoText: (data, _matches, output) => { + if (data.myMutation === 'alpha') + return output.alpha!(); + return output.beta!(); + }, + outputStrings: { + alpha: { + en: 'Avoid Shape AoEs, Wait by Black Hole', + }, + beta: { + en: 'Shared Shape Soak => Get by Black Hole', + }, + }, + }, + { + id: 'R12S Blood Wakening Followup', + // Run to the other Black Hole after abilities go off + // B501 Lindwurm's Water III + // B502 Lindwurm's Aero III + // B503 Straightforward Thunder II + // B504 Sideways Fire II + // TODO: Tell which Black Hole and its mechanics? + type: 'StartsUsing', + netRegex: { id: ['B501', 'B502', 'B503', 'B504'], source: 'Lindwurm', capture: false }, + suppressSeconds: 9999, + alertText: (_data, _matches, output) => output.move!(), + outputStrings: { + move: { + en: 'Move to other Black Hole', + }, + }, + }, + { + id: 'R12S Netherworld Near/Far', + type: 'StartsUsing', + netRegex: { id: ['B52B', 'B52C'], source: 'Lindwurm', capture: true }, + alertText: (data, matches, output) => { + if (matches.id === 'B52B') + return data.myMutation === 'beta' + ? output.betaNear!({ mech: output.getUnder!() }) + : output.alphaNear!({ mech: output.maxMelee!() }); + return data.myMutation === 'beta' + ? output.betaFar!({ mech: output.maxMelee!() }) + : output.alphaFar!({ mech: output.getUnder!() }); + }, + outputStrings: { + getUnder: Outputs.getUnder, + maxMelee: { + en: 'Max Melee', + }, + alphaNear: { + en: '${mech} (Avoid Near Stack)', + }, + alphaFar: { + en: '${mech} (Avoid Far Stack)', + }, + betaNear: { + en: 'Near β Stack: ${mech}', + }, + betaFar: { + en: 'Far β Stack: ${mech}', + }, + }, + }, ], timelineReplace: [ { From d4a93979d316525edffa231c7ade2905f3b5bd09 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 04:42:57 -0500 Subject: [PATCH 057/100] breakout netherwrath into near/far outputs May make it for easier to add configs later. --- ui/raidboss/data/07-dt/raid/r12s.ts | 101 +++++++++++++++++++++------- 1 file changed, 75 insertions(+), 26 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index d157e3fc74..61b3ba3ae5 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1875,49 +1875,83 @@ const triggerSet: TriggerSet = { netRegex: { id: ['B52E', 'B52F'], source: 'Lindwurm', capture: true }, infoText: (data, matches, output) => { const ability = data.myReplication2Tether; - // For telling player in relation to their bait - const spiteBaits = matches.id === 'B52E' ? 'beNear' : 'beFar'; - const proteanBaits = matches.id === 'B52E' ? 'beFar' : 'beNear'; + const isNear = matches.id === 'B52E'; - // For telling player in relation to what others will bait - const avoidProtean = matches.id === 'B52E' ? 'far' : 'near'; - const avoidSpite = matches.id === 'B52E' ? 'near' : 'far'; + if (isNear) { + switch (ability) { + case headMarkerData['projectionTether']: + return output.projectionTetherNear!({ + proteanBaits: output.beFar!(), + mech1: output.scaldingWave!(), + mech2: output.stacks!(), + spiteBaits: output.near!(), + }); + case headMarkerData['manaBurstTether']: + return output.manaBurstTetherNear!({ + spiteBaits: output.beNear!(), + mech1: output.timelessSpite!(), + mech2: output.proteans!(), + proteanBaits: output.far!(), + }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTetherNear!({ + proteanBaits: output.beFar!(), + mech1: output.scaldingWave!(), + mech2: output.stacks!(), + spiteBaits: output.near!(), + }); + case headMarkerData['fireballSplashTether']: + return output.fireballSplashTetherNear!({ + spiteBaits: output.beNear!(), + mech1: output.timelessSpite!(), + mech2: output.proteans!(), + proteanBaits: output.far!(), + }); + } + return output.noTetherNear!({ + spiteBaits: output.beNear!(), + mech1: output.timelessSpite!(), + mech2: output.proteans!(), + proteanBaits: output.far!(), + }); + } + // Netherwrath Far switch (ability) { case headMarkerData['projectionTether']: - return output.projectionTether!({ - proteanBaits: output[proteanBaits]!(), + return output.projectionTetherFar!({ + proteanBaits: output.beNear!(), mech1: output.scaldingWave!(), mech2: output.stacks!(), - spiteBaits: output[avoidSpite]!(), + spiteBaits: output.far!(), }); case headMarkerData['manaBurstTether']: - return output.manaBurstTether!({ - spiteBaits: output[spiteBaits]!(), + return output.manaBurstTetherFar!({ + spiteBaits: output.beFar!(), mech1: output.timelessSpite!(), mech2: output.proteans!(), - proteanBaits: output[avoidProtean]!(), + proteanBaits: output.near!(), }); case headMarkerData['heavySlamTether']: - return output.heavySlamTether!({ - proteanBaits: output[proteanBaits]!(), + return output.heavySlamTetherFar!({ + proteanBaits: output.beNear!(), mech1: output.scaldingWave!(), mech2: output.stacks!(), - spiteBaits: output[avoidSpite]!(), + spiteBaits: output.far!(), }); case headMarkerData['fireballSplashTether']: - return output.fireballSplashTether!({ - spiteBaits: output[spiteBaits]!(), + return output.fireballSplashTetherFar!({ + spiteBaits: output.beFar!(), mech1: output.timelessSpite!(), mech2: output.proteans!(), - proteanBaits: output[avoidProtean]!(), + proteanBaits: output.near!(), }); } - return output.noTether!({ - spiteBaits: output[spiteBaits]!(), + return output.noTetherFar!({ + spiteBaits: output.beFar!(), mech1: output.timelessSpite!(), mech2: output.proteans!(), - proteanBaits: output[avoidProtean]!(), + proteanBaits: output.near!(), }); }, outputStrings: { @@ -1947,19 +1981,34 @@ const triggerSet: TriggerSet = { cn: '远', ko: '멀리', }, - projectionTether: { + projectionTetherFar: { en: '${proteanBaits} + ${mech1} (${mech2} ${spiteBaits})', }, - manaBurstTether: { + manaBurstTetherFar: { en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', }, - heavySlamTether: { + heavySlamTetherFar: { en: '${proteanBaits} + ${mech1} (${mech2} ${spiteBaits})', }, - fireballSplashTether: { + fireballSplashTetherFar: { en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', }, - noTether: { + noTetherFar: { + en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', + }, + projectionTetherNear: { + en: '${proteanBaits} + ${mech1} (${mech2} ${spiteBaits})', + }, + manaBurstTetherNear: { + en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', + }, + heavySlamTetherNear: { + en: '${proteanBaits} + ${mech1} (${mech2} ${spiteBaits})', + }, + fireballSplashTetherNear: { + en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', + }, + noTetherNear: { en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', }, }, From 9b9ac7fd8a9bd57634d11af3017b26aa970c1405 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 04:48:20 -0500 Subject: [PATCH 058/100] change wording for initial tether calls and locked tethers --- ui/raidboss/data/07-dt/raid/r12s.ts | 71 ++++++++++------------------- 1 file changed, 24 insertions(+), 47 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 61b3ba3ae5..a4d9c3cd73 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1641,7 +1641,7 @@ const triggerSet: TriggerSet = { outputStrings: { ...Directions.outputStrings8Dir, projectionTether: { - en: 'Projection Tether on YOU', + en: 'Cone Tether on YOU', }, manaBurstTether: { en: 'Defamation Tether on YOU', @@ -1693,67 +1693,44 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Replication 2 Locked Tether 2', + id: 'R12S Replication 2 Ability Tethers Initial Call', + // Occur ~8s after end of Replication 2 cast type: 'Tether', - netRegex: { id: headMarkerData['lockedTether'], capture: true }, - condition: (data, matches) => { - return data.replicationCounter === 2 && data.me === matches.target; + netRegex: { + id: [ + headMarkerData['projectionTether'], + headMarkerData['manaBurstTether'], + headMarkerData['heavySlamTether'], + headMarkerData['fireballSplashTether'], + ], + capture: true, }, - delaySeconds: 0.1, - infoText: (data, matches, output) => { - // Check if it's the boss - if (data.replication2BossId === matches.sourceId) - return output.fireballSplashTether!({ - mech1: output.baitJump!(), - mech2: output.stackGroups!(), - }); - - switch (data.myReplication2Tether) { + condition: Conditions.targetIsYou(), + suppressSeconds: 9999, // Can get spammy if players have more than 1 tether or swap a lot + infoText: (_data, matches, output) => { + switch (matches.id) { case headMarkerData['projectionTether']: - return output.projectionTether!({ - mech1: output.baitProtean!(), - mech2: output.stackGroups!(), - }); + return output.projectionTether!(); case headMarkerData['manaBurstTether']: - return output.manaBurstTether!({ - mech1: output.defamationOnYou!(), - mech2: output.stackGroups!(), - }); + return output.manaBurstTether!(); case headMarkerData['heavySlamTether']: - return output.heavySlamTether!({ - mech1: output.baitProtean!(), - mech2: output.stackGroups!(), - }); + return output.heavySlamTether!(); } + return output.fireballSplashTether!(); }, outputStrings: { - defamationOnYou: Outputs.defamationOnYou, - stackGroups: { - en: 'Stack Groups', - de: 'Gruppen-Sammeln', - fr: 'Package en groupes', - ja: '組み分け頭割り', - cn: '分组分摊', - ko: '그룹별 쉐어', - tc: '分組分攤', - }, - baitProtean: { - en: 'Bait Protean from Boss', - }, - baitJump: { - en: 'Bait Jump', - }, + ...Directions.outputStrings8Dir, projectionTether: { - en: '${mech1} => ${mech2}', + en: 'Cone Tether on YOU', }, manaBurstTether: { - en: '${mech1} => ${mech2}', + en: 'Defamation Tether on YOU', }, heavySlamTether: { - en: '${mech1} => ${mech2}', + en: 'Stack Tether on YOU', }, fireballSplashTether: { - en: '${mech1} => ${mech2}', + en: 'Boss Tether on YOU', }, }, }, From 058d45696669feeb6d0f01aa7691adbf80863e80 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 04:51:34 -0500 Subject: [PATCH 059/100] fix copy/paste error --- ui/raidboss/data/07-dt/raid/r12s.ts | 65 +++++++++++++++++++---------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index a4d9c3cd73..18c3d11b1e 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1693,44 +1693,63 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Replication 2 Ability Tethers Initial Call', - // Occur ~8s after end of Replication 2 cast + id: 'R12S Replication 2 Locked Tether 2', type: 'Tether', - netRegex: { - id: [ - headMarkerData['projectionTether'], - headMarkerData['manaBurstTether'], - headMarkerData['heavySlamTether'], - headMarkerData['fireballSplashTether'], - ], - capture: true, + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: (data, matches) => { + return data.replicationCounter === 2 && data.me === matches.target; }, - condition: Conditions.targetIsYou(), - suppressSeconds: 9999, // Can get spammy if players have more than 1 tether or swap a lot - infoText: (_data, matches, output) => { - switch (matches.id) { + delaySeconds: 0.1, + infoText: (data, matches, output) => { + // Check if it's the boss + if (data.replication2BossId === matches.sourceId) + return output.fireballSplashTether!({ + mech1: output.baitJump!(), + }); + + switch (data.myReplication2Tether) { case headMarkerData['projectionTether']: - return output.projectionTether!(); + return output.projectionTether!({ + mech1: output.baitProtean!(), + }); case headMarkerData['manaBurstTether']: - return output.manaBurstTether!(); + return output.manaBurstTether!({ + mech1: output.defamationOnYou!(), + }); case headMarkerData['heavySlamTether']: - return output.heavySlamTether!(); + return output.heavySlamTether!({ + mech1: output.baitProtean!(), + }); } - return output.fireballSplashTether!(); }, outputStrings: { - ...Directions.outputStrings8Dir, + defamationOnYou: Outputs.defamationOnYou, + stackGroups: { + en: 'Stack Groups', + de: 'Gruppen-Sammeln', + fr: 'Package en groupes', + ja: '組み分け頭割り', + cn: '分组分摊', + ko: '그룹별 쉐어', + tc: '分組分攤', + }, + baitProtean: { + en: 'Bait Protean from Boss', + }, + baitJump: { + en: 'Bait Jump', + }, projectionTether: { - en: 'Cone Tether on YOU', + en: 'Cone Tether: ${mech1}', }, manaBurstTether: { - en: 'Defamation Tether on YOU', + en: 'Defamation Tether: ${mech1}', }, heavySlamTether: { - en: 'Stack Tether on YOU', + en: 'Stack Tether: ${mech1}', }, fireballSplashTether: { - en: 'Boss Tether on YOU', + en: 'Boss Tether: ${mech1}', }, }, }, From 565f3c941864ebc46981bf12039238f38332b623 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 04:56:18 -0500 Subject: [PATCH 060/100] add p2 idyllic dream bigAoe --- ui/raidboss/data/07-dt/raid/r12s.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 18c3d11b1e..ce39f0cd7f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2111,6 +2111,13 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Idyllic Dream', + type: 'StartsUsing', + netRegex: { id: 'B509', source: 'Lindwurm', capture: false }, + durationSeconds: 4.7, + response: Responses.bigAoe('alert'), + }, ], timelineReplace: [ { From 60aa9d2232811b11a021d8ba04c3f547721dbbf6 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 06:05:55 -0500 Subject: [PATCH 061/100] add direction to initial ability tethers and locked tethers --- ui/raidboss/data/07-dt/raid/r12s.ts | 103 +++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ce39f0cd7f..cf51bb7e1a 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -113,6 +113,14 @@ const triggerSet: TriggerSet = { data.phase = phase; }, }, + { + id: 'R12S Phase Two Staging Tracker', + // Due to the way the combatants are added in prior to the cast of Staging, this is used to set the phase + type: 'AddedCombatant', + netRegex: { name: 'Understudy', capture: false }, + condition: (data) => data.phase === 'replication1', + run: (data) => data.phase = 'replication2', + }, { id: 'R12S Phase Two Replication Tracker', type: 'StartsUsing', @@ -124,17 +132,14 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Phase Two Staging Tracker', - // B4E1 Staging happens more than once, only track the first one + id: 'R12S Phase Two Boss ID Collect', + // Store the boss' id later for checking against tether + // Using first B4E1 Staging type: 'StartsUsing', netRegex: { id: 'B4E1', source: 'Lindwurm', capture: true }, - condition: (data) => data.phase === 'replication1', + condition: (data) => data.phase === 'replication2', suppressSeconds: 9999, - run: (data, matches) => { - data.phase = 'replication2'; - // Store the boss' id later for checking against tether - data.replication2BossId = matches.sourceId; - }, + run: (data, matches) => data.replication2BossId = matches.sourceId, }, { id: 'R12S Phase Two Reenactment Tracker', @@ -1627,28 +1632,56 @@ const triggerSet: TriggerSet = { }, condition: Conditions.targetIsYou(), suppressSeconds: 9999, // Can get spammy if players have more than 1 tether or swap a lot - infoText: (_data, matches, output) => { + infoText: (data, matches, output) => { + if (matches.id === headMarkerData['fireballSplashTether']) + return output.fireballSplashTether!(); + + // Get direction of the tether + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) { + switch (matches.id) { + case headMarkerData['projectionTether']: + return output.projectionTether!(); + case headMarkerData['manaBurstTether']: + return output.manaBurstTether!(); + case headMarkerData['heavySlamTether']: + return output.heavySlamTether!(); + } + return; + } + + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + switch (matches.id) { case headMarkerData['projectionTether']: - return output.projectionTether!(); + return output.projectionTetherDir!({ dir: output[dir]!() }); case headMarkerData['manaBurstTether']: - return output.manaBurstTether!(); + return output.manaBurstTetherDir!({ dir: output[dir]!() }); case headMarkerData['heavySlamTether']: - return output.heavySlamTether!(); + return output.heavySlamTetherDir!({ dir: output[dir]!() }); } - return output.fireballSplashTether!(); }, outputStrings: { ...Directions.outputStrings8Dir, projectionTether: { en: 'Cone Tether on YOU', }, + projectionTetherDir: { + en: '${dir} Cone Tether on YOU', + }, manaBurstTether: { en: 'Defamation Tether on YOU', }, + manaBurstTetherDir: { + en: '${dir} Defamation Tether on YOU', + }, heavySlamTether: { en: 'Stack Tether on YOU', }, + heavySlamTetherDir: { + en: '${dir} Stack Tether on YOU', + }, fireballSplashTether: { en: 'Boss Tether on YOU', }, @@ -1707,22 +1740,49 @@ const triggerSet: TriggerSet = { mech1: output.baitJump!(), }); + // Get direction of the tether + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) { + switch (data.myReplication2Tether) { + case headMarkerData['projectionTether']: + return output.projectionTether!({ + mech1: output.baitProtean!(), + }); + case headMarkerData['manaBurstTether']: + return output.manaBurstTether!({ + mech1: output.defamationOnYou!(), + }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTether!({ + mech1: output.baitProtean!(), + }); + } + return; + } + + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + switch (data.myReplication2Tether) { case headMarkerData['projectionTether']: - return output.projectionTether!({ + return output.projectionTetherDir!({ + dir: output[dir]!(), mech1: output.baitProtean!(), }); case headMarkerData['manaBurstTether']: - return output.manaBurstTether!({ + return output.manaBurstTetherDir!({ + dir: output[dir]!(), mech1: output.defamationOnYou!(), }); case headMarkerData['heavySlamTether']: - return output.heavySlamTether!({ + return output.heavySlamTetherDir!({ + dir: output[dir]!(), mech1: output.baitProtean!(), }); } }, outputStrings: { + ...Directions.outputStrings8Dir, defamationOnYou: Outputs.defamationOnYou, stackGroups: { en: 'Stack Groups', @@ -1739,12 +1799,21 @@ const triggerSet: TriggerSet = { baitJump: { en: 'Bait Jump', }, + projectionTetherDir: { + en: '${dir} Cone Tether: ${mech1}', + }, projectionTether: { en: 'Cone Tether: ${mech1}', }, + manaBurstTetherDir: { + en: '${dir} Defamation Tether: ${mech1}', + }, manaBurstTether: { en: 'Defamation Tether: ${mech1}', }, + heavySlamTetherDir: { + en: '${dir} Stack Tether: ${mech1}', + }, heavySlamTether: { en: 'Stack Tether: ${mech1}', }, @@ -1783,7 +1852,7 @@ const triggerSet: TriggerSet = { tc: '分組分攤', }, noTether: { - en: '${mech1} => ${mech2}', + en: 'No Tether: ${mech1} => ${mech2}', }, }, }, From 384b8ed9abaf051d4f9018ff4f67960ca81d50de Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 06:46:42 -0500 Subject: [PATCH 062/100] add some idyllic clone triggers I do not have a log to test these, but they work for replication 2 so maybe they are the same for idyllic. I noticed the tethers in idyllic will come out before the replication cast so would need an additional phase filter for replication 2 on those tethers. --- ui/raidboss/data/07-dt/raid/r12s.ts | 121 +++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 4 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index cf51bb7e1a..94a0a57c65 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2,7 +2,12 @@ import Conditions from '../../../../../resources/conditions'; import { UnreachableCode } from '../../../../../resources/not_reached'; import Outputs from '../../../../../resources/outputs'; import { Responses } from '../../../../../resources/responses'; -import { Directions } from '../../../../../resources/util'; +import { + DirectionOutput8, + DirectionOutputCardinal, + DirectionOutputIntercard, + Directions, +} from '../../../../../resources/util'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; @@ -43,6 +48,7 @@ export interface Data extends RaidbossData { replication2BossId?: string; myReplication2Tether?: string; myMutation?: 'alpha' | 'beta'; + replication3CloneOrder: number[]; } const headMarkerData = { @@ -98,6 +104,7 @@ const triggerSet: TriggerSet = { replicationCounter: 0, replication1FollowUp: false, replication2TetherMap: {}, + replication3CloneOrder: [], }), triggers: [ { @@ -1692,7 +1699,13 @@ const triggerSet: TriggerSet = { type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: true }, condition: (data, matches) => { - return data.replicationCounter === 2 && data.me === matches.target; + if ( + data.phase === 'replication2' && + data.replicationCounter === 2 && + data.me === matches.target + ) + return true; + return false; }, run: (data, matches) => { // Check if boss tether @@ -1730,7 +1743,13 @@ const triggerSet: TriggerSet = { type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: true }, condition: (data, matches) => { - return data.replicationCounter === 2 && data.me === matches.target; + if ( + data.phase === 'replication2' && + data.replicationCounter === 2 && + data.me === matches.target + ) + return true; + return false; }, delaySeconds: 0.1, infoText: (data, matches, output) => { @@ -1828,7 +1847,9 @@ const triggerSet: TriggerSet = { type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: false }, condition: (data) => { - return data.replicationCounter === 2; + if (data.phase === 'replication2' && data.replicationCounter === 2) + return true; + return false; }, delaySeconds: 0.1, suppressSeconds: 1, @@ -2187,6 +2208,98 @@ const triggerSet: TriggerSet = { durationSeconds: 4.7, response: Responses.bigAoe('alert'), }, + { + id: 'R12S Idyllic Dream Replication Clone Order Collect', + type: 'ActorControlExtra', + netRegex: { category: '0197', param1: '11D2', capture: true }, + condition: (data) => { + if (data.phase === 'idyllic' && data.replicationCounter === 2) + return true; + return false; + }, + run: (data, matches) => { + const actor = data.actorPositions[matches.id]; + if (actor === undefined) + return; + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + data.replication3CloneOrder.push(dirNum); + }, + }, + { + id: 'R12S Idyllic Dream Replication First Clone Cardinal/Intercardinal', + type: 'ActorControlExtra', + netRegex: { category: '0197', param1: '11D2', capture: true }, + condition: (data) => { + if (data.phase === 'idyllic' && data.replicationCounter === 2) + return true; + return false; + }, + suppressSeconds: 9999, + infoText: (data, matches, output) => { + const actor = data.actorPositions[matches.id]; + if (actor === undefined) + return; + + type DirectionCardinal = Exclude; + type DirectionIntercard = Exclude; + const isCardinalDir = (dir: DirectionOutput8): dir is DirectionCardinal => { + return (Directions.outputCardinalDir as string[]).includes(dir); + }; + const isIntercardDir = (dir: DirectionOutput8): dir is DirectionIntercard => { + return (Directions.outputIntercardDir as string[]).includes(dir); + }; + + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + + if (isCardinalDir(dir)) + return output.firstClone!({ cards: output.cardinals!() }); + if (isIntercardDir(dir)) + return output.firstClone!({ cards: output.intercards!() }); + return output.firstClone!({ cards: output.unknown!() }); + }, + outputStrings: { + unknown: Outputs.unknown, + cardinals: Outputs.cardinals, + intercards: Outputs.intercards, + firstClone: { + en: 'First Clone: ${cards}', + }, + }, + }, + { + id: 'R12S Idyllic Dream Replication Tethered Clone', + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: (data, matches) => { + if ( + data.phase === 'idyllic' && + data.replicationCounter === 2 && + data.me === matches.target + ) + return true; + return false; + }, + suppressSeconds: 9999, + infoText: (data, matches, output) => { + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) + return output.cloneTether!(); + + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + return output.cloneTetherDir!({ dir: output[dir]!() }); + }, + outputStrings: { + ...Directions.outputStrings8Dir, + cloneTether: { + en: 'Tethered to Clone', + }, + cloneTetherDir: { + en: 'Tethered to ${dir} Clone', + }, + }, + }, ], timelineReplace: [ { From 1a3ec2eaba3ce2b1d51e9bc4ad95cb59fdce1040 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 06:51:57 -0500 Subject: [PATCH 063/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 94a0a57c65..2f8cb68366 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2239,7 +2239,7 @@ const triggerSet: TriggerSet = { const actor = data.actorPositions[matches.id]; if (actor === undefined) return; - + type DirectionCardinal = Exclude; type DirectionIntercard = Exclude; const isCardinalDir = (dir: DirectionOutput8): dir is DirectionCardinal => { @@ -2248,7 +2248,7 @@ const triggerSet: TriggerSet = { const isIntercardDir = (dir: DirectionOutput8): dir is DirectionIntercard => { return (Directions.outputIntercardDir as string[]).includes(dir); }; - + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); const dir = Directions.output8Dir[dirNum] ?? 'unknown'; From c93971ee21c0f1c0fc6674db667dd5e8eabf8d6c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 08:05:53 -0500 Subject: [PATCH 064/100] add some Lindwurm's Meteor triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 152 ++++++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 9 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 2f8cb68366..e50d39cd84 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -22,6 +22,9 @@ export type Phase = | 'idyllic' | 'reenactment2'; +type DirectionCardinal = Exclude; +type DirectionIntercard = Exclude; + export interface Data extends RaidbossData { phase: Phase; // Phase 1 @@ -49,6 +52,8 @@ export interface Data extends RaidbossData { myReplication2Tether?: string; myMutation?: 'alpha' | 'beta'; replication3CloneOrder: number[]; + hasLightResistanceDown: boolean; + doomPlayers: string[]; } const headMarkerData = { @@ -86,6 +91,14 @@ const phaseMap: { [id: string]: Phase } = { 'B509': 'idyllic', }; +const isCardinalDir = (dir: DirectionOutput8): dir is DirectionCardinal => { + return (Directions.outputCardinalDir as string[]).includes(dir); +}; + +const isIntercardDir = (dir: DirectionOutput8): dir is DirectionIntercard => { + return (Directions.outputIntercardDir as string[]).includes(dir); +}; + const triggerSet: TriggerSet = { id: 'AacHeavyweightM4Savage', zoneId: ZoneId.AacHeavyweightM4Savage, @@ -105,6 +118,8 @@ const triggerSet: TriggerSet = { replication1FollowUp: false, replication2TetherMap: {}, replication3CloneOrder: [], + hasLightResistanceDown: false, + doomPlayers: [], }), triggers: [ { @@ -2240,15 +2255,6 @@ const triggerSet: TriggerSet = { if (actor === undefined) return; - type DirectionCardinal = Exclude; - type DirectionIntercard = Exclude; - const isCardinalDir = (dir: DirectionOutput8): dir is DirectionCardinal => { - return (Directions.outputCardinalDir as string[]).includes(dir); - }; - const isIntercardDir = (dir: DirectionOutput8): dir is DirectionIntercard => { - return (Directions.outputIntercardDir as string[]).includes(dir); - }; - const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); const dir = Directions.output8Dir[dirNum] ?? 'unknown'; @@ -2300,6 +2306,134 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Lindwurm\'s Meteor', + type: 'StartsUsing', + netRegex: { id: 'B4F2', source: 'Lindwurm', capture: false }, + infoText: (_data, _matches, output) => output.healerGroups!(), + outputStrings: { + healerGroups: Outputs.healerGroups, + }, + }, + { + id: 'R12S Light Resistance Down II Collect', + type: 'GainsEffect', + netRegex: { effectId: '1044', capture: true }, + condition: Conditions.targetIsYou(), + run: (data) => data.hasLightResistanceDown = true, + }, + { + id: 'R12S Light Resistance Down II', + type: 'GainsEffect', + netRegex: { effectId: '1044', capture: true }, + condition: Conditions.targetIsYou(), + infoText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Soak Fire/Earth Meteor', + }, + }, + }, + { + id: 'R12S No Light Resistance Down II', + type: 'GainsEffect', + netRegex: { effectId: '1044', capture: false }, + delaySeconds: 0.1, + suppressSeconds: 9999, + infoText: (data, _matches, output) => { + if (!data.hasLightResistanceDown) + return output.text!(); + }, + outputStrings: { + text: { + en: 'Soak a White/Star Meteor', + }, + }, + }, + { + id: 'R12S Doom Collect', + type: 'GainsEffect', + netRegex: { effectId: 'D24', capture: true }, + run: (data, matches) => data.doomPlayers.push(matches.target), + }, + { + id: 'R12S Doom Collect', + type: 'GainsEffect', + netRegex: { effectId: 'D24', capture: true }, + condition: (data) => data.CanCleanse(), + delaySeconds: 0.1, + suppressSeconds: 1, + infoText: (data, _matches, output) => { + const players = data.doomPlayers; + if (players.length === 2) { + const target1 = data.party.member(data.doomPlayers[0]); + const target2 = data.party.member(data.doomPlayers[1]); + return output.cleanseDoom2!({ target1: target1, target2: target2 }); + } + if (players.length === 1) { + const target1 = data.party.member(data.doomPlayers[0]); + return output.cleanseDoom!({ target: target1 }); + } + }, + outputStrings: { + cleanseDoom: { + en: 'Cleanse ${target}', + de: 'Reinige ${target}', + fr: 'Guérison sur ${target}', + cn: '康复 ${target}', + ko: '${target} 에스나', + tc: '康復 ${target}', + }, + cleanseDoom2: { + en: 'Cleanse ${target1}/${target2}', + }, + }, + }, + { + id: 'R12S Doom Cleanup', + type: 'LosesEffect', + netRegex: { effectId: 'D24', capture: true }, + run: (data, matches) => { + data.doomPlayers = data.doomPlayers.filter( + (player) => player === matches.target + ); + }, + }, + { + id: 'R12S Hot-blooded', + // Player can still cast, but shouldn't move for 5s duration + type: 'GainsEffect', + netRegex: { effectId: '12A0', capture: true }, + condition: Conditions.targetIsYou(), + durationSeconds: (_data, matches) => parseFloat(matches.duration), + response: Responses.stopMoving(), + }, + { + id: 'R12S Idyllic Dream Replication Clone Cardinal/Intercardinal Reminder', + // Using Temporal Curtain + type: 'StartsUsing', + netRegex: { id: 'B51C', source: 'Lindwurm', capture: false }, + infoText: (data, _matches, output) => { + const firstClone = data.replication3CloneOrder[0]; + if (firstClone === undefined) + return; + const actor = data.actorPositions[firstClone]; + if (actor === undefined) + return; + + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + + if (isCardinalDir(dir)) + return output.cardinals!(); + if (isIntercardDir(dir)) + return output.intercards!(); + }, + outputStrings: { + cardinals: Outputs.cardinals, + intercards: Outputs.intercards, + }, + }, ], timelineReplace: [ { From c2dee83860574ed45fe1c850c7c3f566c9b0ce7c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 08:07:52 -0500 Subject: [PATCH 065/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index e50d39cd84..cd1da7f3e5 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2395,7 +2395,7 @@ const triggerSet: TriggerSet = { netRegex: { effectId: 'D24', capture: true }, run: (data, matches) => { data.doomPlayers = data.doomPlayers.filter( - (player) => player === matches.target + (player) => player === matches.target, ); }, }, From 5ad055166dc21293b51a534664ed7fd22d33e334 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 08:10:12 -0500 Subject: [PATCH 066/100] fix doom cleanse id --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index cd1da7f3e5..7404fa5cca 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2357,9 +2357,9 @@ const triggerSet: TriggerSet = { run: (data, matches) => data.doomPlayers.push(matches.target), }, { - id: 'R12S Doom Collect', + id: 'R12S Doom Cleanse', type: 'GainsEffect', - netRegex: { effectId: 'D24', capture: true }, + netRegex: { effectId: 'D24', capture: false }, condition: (data) => data.CanCleanse(), delaySeconds: 0.1, suppressSeconds: 1, From 25bcc985fd14bd1b5f562ed5b50e9cce691c671b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 18:32:49 -0500 Subject: [PATCH 067/100] increase rep1 and rep2 delays for nodebuffs/notethers --- ui/raidboss/data/07-dt/raid/r12s.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7404fa5cca..ed4c2f3656 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1456,10 +1456,11 @@ const triggerSet: TriggerSet = { { id: 'R12S Fake Fire Resistance Down II', // Two players will not receive a debuff, they will need to act as if they had + // Mechanics happen across 1.1s type: 'GainsEffect', netRegex: { effectId: ['CFB', 'B79'], capture: false }, condition: (data) => !data.replication1FollowUp, - delaySeconds: 0.3, // Delay for debuff/damage propagation + delaySeconds: 1.2, // +0.1s Delay for debuff/damage propagation suppressSeconds: 9999, infoText: (data, _matches, output) => { if (data.replication1Debuff === undefined) @@ -1866,7 +1867,7 @@ const triggerSet: TriggerSet = { return true; return false; }, - delaySeconds: 0.1, + delaySeconds: 0.2, suppressSeconds: 1, infoText: (data, _matches, output) => { if (data.myReplication2Tether !== undefined) From 144ab874fe0b0bed2e3d456e85bb59aefc3e8a8d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 20:01:15 -0500 Subject: [PATCH 068/100] add Double Sobat followup triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 54 +++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ed4c2f3656..0b7429614f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1585,12 +1585,62 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Double Sobat', - // Two half-room cleaves - // First hit targets highest emnity target, second targets second highest + // Shared half-room cleave on tank => random turn half-room cleave => + // Esoteric Finisher big circle aoes that hits two highest emnity targets type: 'HeadMarker', netRegex: { id: headMarkerData['sharedTankbuster'], capture: true }, response: Responses.sharedTankBuster(), }, + { + id: 'R12S Double Sobat 2', + // Followup half-room cleave: + // - No turn + // - 90 degree turn + // - 180 degree turn + // - 270 degree turn + type: 'StartsUsing', + netRegex: { id: 'B525', source: 'Lindwurm', capture: true }, + alertText: (data, matches, output) => { + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) + return output.getBehind!(); + + const dirNum = (Directions.hdgTo16DirNum(actor.heading) + 8) % 16; + const dir = Directions.output16Dir[dirNum] ?? 'unknown'; + return output.getBehindDir!({ + dir: output[dir]!(), + mech: output.getBehind!(), + }); + }, + outputStrings: { + ...Directions.outputStrings16Dir, + getBehind: Outputs.getBehind, + getBehindDir: { + en: '${dir}: ${mech}', + }, + }, + }, + { + id: 'R12S Esoteric Finisher', + // After Double Sobat 2, boss hits targets highest emnity target, second targets second highest + type: 'StartsUsing', + netRegex: { id: 'B525', source: 'Lindwurm', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime), + response: (data, _matches, output) => { + // cactbot-builtin-response + output.responseOutputStrings = { + tankBusterCleaves: Outputs.tankBusterCleaves, + avoidTankCleaves: Outputs.avoidTankCleaves, + }; + + if (data.role === 'tank' || data.role === 'healer') { + if (data.role === 'healer') + return { infoText: output.tankBusterCleaves!() }; + return { alertText: output.tankBusterCleaves!() }; + } + return { infoText: output.avoidTankCleaves!() }; + }, + }, { id: 'R12S Replication 2 Tethered Clone', // Combatants are added ~4s before Staging starts casting From 35423f2a26689d258aec7338d5327b26116479e3 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 20:06:53 -0500 Subject: [PATCH 069/100] add direction to Snaking Kick and Grotesquerie --- ui/raidboss/data/07-dt/raid/r12s.ts | 57 +++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 0b7429614f..d99840dcac 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1474,8 +1474,9 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Snaking Kick', + // Targets random player type: 'StartsUsing', - netRegex: { id: 'B527', source: 'Lindwurm', capture: false }, + netRegex: { id: 'B527', source: 'Lindwurm', capture: true }, condition: (data) => { // Use Grotesquerie trigger for projection tethered players const ability = data.myReplication2Tether; @@ -1483,7 +1484,25 @@ const triggerSet: TriggerSet = { return false; return true; }, - response: Responses.getBehind(), + alertText: (data, matches, output) => { + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) + return output.getBehind!(); + + const dirNum = (Directions.hdgTo16DirNum(actor.heading) + 8) % 16; + const dir = Directions.output16Dir[dirNum] ?? 'unknown'; + return output.getBehindDir!({ + dir: output[dir]!(), + mech: output.getBehind!(), + }); + }, + outputStrings: { + ...Directions.outputStrings16Dir, + getBehind: Outputs.getBehind, + getBehindDir: { + en: '${dir}: ${mech}', + }, + }, }, { id: 'R12S Replication 1 Follow-up Tracker', @@ -2018,7 +2037,39 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B4EA', source: 'Lindwurm', capture: true }, condition: Conditions.targetIsYou(), - response: Responses.getBehind(), + { + id: 'R12S Grotesquerie', + // This seems to be the point at which the look for the Snaking Kick is snapshot + // The VFX B4E9 happens ~0.6s before Snaking Kick + // B4EA has the targetted player in it + // B4EB Hemorrhagic Projection conal aoe goes off ~0.5s after in the direction the player was facing + type: 'Ability', + netRegex: { id: 'B4EA', source: 'Lindwurm', capture: true }, + condition: Conditions.targetIsYou(), + alertText: (data, matches, output) => { + // Get Boss facing + const bossId = data.replication2BossId; + if (bossId === undefined) + return output.getBehind!(); + + const actor = data.actorPositions[bossId]; + if (actor === undefined) + return output.getBehind!(); + + const dirNum = (Directions.hdgTo16DirNum(actor.heading) + 8) % 16; + const dir = Directions.output16Dir[dirNum] ?? 'unknown'; + return output.getBehindDir!({ + dir: output[dir]!(), + mech: output.getBehind!(), + }); + }, + outputStrings: { + ...Directions.outputStrings16Dir, + getBehind: Outputs.getBehind, + getBehindDir: { + en: '${dir}: ${mech}', + }, + }, }, { id: 'R12S Netherwrath Near/Far', From 6b47d89ae4a8889e0a4dd38bd17ee0a0d481173a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 20:10:20 -0500 Subject: [PATCH 070/100] fix paste error --- ui/raidboss/data/07-dt/raid/r12s.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index d99840dcac..cc0f504bca 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2028,15 +2028,6 @@ const triggerSet: TriggerSet = { }, }, }, - { - id: 'R12S Grotesquerie', - // This seems to be the point at which the look for the Snaking Kick is snapshot - // The VFX B4E9 happens ~0.6s before Snaking Kick - // B4EA has the targetted player in it - // B4EB Hemorrhagic Projection conal aoe goes off ~0.5s after in the direction the player was facing - type: 'Ability', - netRegex: { id: 'B4EA', source: 'Lindwurm', capture: true }, - condition: Conditions.targetIsYou(), { id: 'R12S Grotesquerie', // This seems to be the point at which the look for the Snaking Kick is snapshot From 009332af92f9e2cfff9296f9b92c21c9b6744c38 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 20:24:35 -0500 Subject: [PATCH 071/100] fix missing debuff calls in rep1 snaking startsCasting happens prior to half the debuffs going out (which has its own issue with the calls overlapping). Switch to ability. --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index cc0f504bca..64057e0e88 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1507,7 +1507,7 @@ const triggerSet: TriggerSet = { { id: 'R12S Replication 1 Follow-up Tracker', // Tracking from B527 Snaking Kick - type: 'StartsUsing', + type: 'Ability', netRegex: { id: 'B527', source: 'Lindwurm', capture: false }, suppressSeconds: 9999, run: (data) => data.replication1FollowUp = true, From 169a2f84879c9320a2e5abdcf2466e2544f7a288 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 20:25:33 -0500 Subject: [PATCH 072/100] unused matches --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 64057e0e88..9f47660de2 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2037,7 +2037,7 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B4EA', source: 'Lindwurm', capture: true }, condition: Conditions.targetIsYou(), - alertText: (data, matches, output) => { + alertText: (data, _matches, output) => { // Get Boss facing const bossId = data.replication2BossId; if (bossId === undefined) From 7b03634b350dc387e411813da19c341ea735b765 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 21:20:19 -0500 Subject: [PATCH 073/100] shorten wording for rep1 baits/clones --- ui/raidboss/data/07-dt/raid/r12s.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 9f47660de2..75fb766ab7 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1446,10 +1446,10 @@ const triggerSet: TriggerSet = { }, outputStrings: { fire: { - en: 'Fire Debuff: Spread near Dark Clone (later)', + en: 'Fire Debuff: Spread near Dark (later)', }, dark: { - en: 'Dark Debuff: Stack near Fire Clone (later)', + en: 'Dark Debuff: Stack near Fire (later)', }, }, }, @@ -1468,7 +1468,7 @@ const triggerSet: TriggerSet = { }, outputStrings: { noDebuff: { - en: 'No Debuff: Spread near Dark Clone (later)', + en: 'No Debuff: Spread near Dark (later)', }, }, }, @@ -1595,10 +1595,10 @@ const triggerSet: TriggerSet = { outputStrings: { ...Directions.outputStringsIntercardDir, // Cardinals should result in '???' fire: { - en: 'Bait Fire near In ${dir1}/Out ${dir2} (Partners)', + en: 'Bait Fire In ${dir1}/Out ${dir2} (Partners)', }, dark: { - en: 'Bait Dark near In ${dir1}/Out ${dir2} (Solo)', + en: 'Bait Dark In ${dir1}/Out ${dir2} (Solo)', }, }, }, From c6da383a3528dd631ebe90beeb1d12dd986216ca Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 25 Jan 2026 21:44:39 -0500 Subject: [PATCH 074/100] timeline to end of shapes --- ui/raidboss/data/07-dt/raid/r12s.txt | 121 +++++++++++++++++++-------- 1 file changed, 87 insertions(+), 34 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index ae9bd9eae7..581b760d92 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -343,43 +343,89 @@ hideall "--sync--" # -p B528:3015.7 # -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE # -it "Lindwurm" +# -p B528:3012.1 +# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 +# -it "Lindwurm" 3000.5 label "r12s-p2-start" 3010.7 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 3015.7 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } 3022.9 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } -3028.0 "Replication 1" Ability { id: "B4D8", source: "Lindwurm" } -3039.6 "Top-tier Slam x2" #Ability { id: "B4DE", source: "Lindschrat" } -3040.4 "Winged Scourge x4" Ability { id: "B4DC", source: "Lindwurm" } -3040.6 "Mighty Magic x4" #Ability { id: "B4E0", source: "Lindwurm" } -3045.2 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } -3053.8 "--clones move 1--" #Ability { id: "B4D9", source: "Lindschrat" } -3054.8 "--clones move 2--" #Ability { id: "B4D9", source: "Lindschrat" } -3061.0 "Top-tier Slam x2" #Ability { id: "B4DE", source: "Lindschrat" } -3061.8 "Winged Scourge x4" Ability { id: "B4DC", source: "Lindwurm" } -3062.1 "Mighty Magic x4" #Ability { id: "B4E0", source: "Lindwurm" } -3069.3 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } -3070.0 "Double Sobat 1" Ability { id: "B522", source: "Lindwurm" } -3074.6 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } -3077.0 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } - -3091.2 "Staging" Ability { id: "B4E1", source: "Lindwurm" } -3102.2 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } -3105.4 "Replication 2" Ability { id: "B4D8", source: "Lindwurm" } -3128.0 "Firefall Splash" Ability { id: "B4E4", source: "Lindwurm" } -3128.7 "Scalding Waves x4" Ability { id: "B4E5", source: "Lindwurm" } -3130.1 "Mana Burst x3" Ability { id: "B4E7", source: "Lindwurm" } -3135.5 "Heavy Slam x2" Ability { id: "B4E8", source: "Lindschrat" } -3136.7 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } -3137.3 "Hemorrhagic Projection x2" Ability { id: "B4EB", source: "Lindwurm" } -3141.1 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } -3151.3 "Reenactment 1" Ability { id: "B4EC", source: "Lindwurm" } -3159.4 "Firefall Splash" Ability { id: "B4ED", source: "Lindschrat" } -3159.4 "Netherwrath Near/Netherwrath Far" Ability { id: ["B52E", "B52F"], source: "Lindwurm" } -3160.6 "Timeless Spite" Ability { id: "B530", source: "Lindwurm" } -3160.8 "Scalding Waves x4" Ability { id: "B8E1", source: "Lindwurm" } -3164.4 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } -3164.4 "Mana Burst x3" Ability { id: "BBE3", source: "Lindwurm" } -3165.0 "Hemorrhagic Projection x2" Ability { id: "B922", source: "Lindwurm" } +3028.2 "Replication 1" Ability { id: "B4D8", source: "Lindwurm" } +3040.0 "Top-tier Slam x2" Ability { id: "B4DE", source: "Lindschrat" } +3040.8 "Winged Scourge x4" Ability { id: "B4DC", source: "Lindwurm" } +3041.0 "Mighty Magic x4" Ability { id: "B4E0", source: "Lindwurm" } +3045.7 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } +3054.1 "--clones move 1--" #Ability { id: "B4D9", source: "Lindschrat" } +3055.1 "--clones move 2--" #Ability { id: "B4D9", source: "Lindschrat" } +3061.4 "Top-tier Slam x2" Ability { id: "B4DE", source: "Lindschrat" } +3062.2 "Winged Scourge x4" #Ability { id: "B4DC", source: "Lindwurm" } +3062.5 "Mighty Magic x4" Ability { id: "B4E0", source: "Lindwurm" } +3069.8 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3070.4 "Double Sobat 1" Ability { id: "B522", source: "Lindwurm" } +3075.0 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3077.4 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } + +# NOTE: Depending on clone order and tethers player takes, spells at each instance will differ +# TBD: Generalize these? +3091.6 "Staging" Ability { id: "B4E1", source: "Lindwurm" } +3102.6 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } +3105.8 "Replication 2" Ability { id: "B4D8", source: "Lindwurm" } +3128.2 "Firefall Splash" Ability { id: "B4E4", source: "Lindwurm" } +3128.9 "Scalding Waves x4" Ability { id: "B4E5", source: "Lindwurm" } +3130.3 "Mana Burst x3" Ability { id: "B4E7", source: "Lindwurm" } +3135.7 "Heavy Slam x2" Ability { id: "B4E8", source: "Lindschrat" } +3136.9 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } +3137.5 "Hemorrhagic Projection x2" Ability { id: "B4EB", source: "Lindwurm" } +3141.4 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } + +3151.6 "Reenactment 1" Ability { id: "B4EC", source: "Lindwurm" } +3159.7 "Firefall Splash" Ability { id: "B4ED", source: "Lindschrat" } +3159.7 "Netherwrath Near/Netherwrath Far" Ability { id: ["B52E", "B52F"], source: "Lindwurm" } +3160.9 "Mana Burst 1" #Ability { id: "BBE3", source: "Lindwurm" } +3160.9 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } +3161.0 "Scalding Waves x4" Ability { id: "B8E1", source: "Lindwurm" } +3164.8 "Mana Burst 2" Ability { id: "BBE3", source: "Lindwurm" } +3164.8 "Grotesquerie 1" Ability { id: "B4EA", source: "Lindwurm" } +3165.4 "Hemorrhagic Projection 1" Ability { id: "B922", source: "Lindwurm" } +3169.1 "Heavy Slam" Ability { id: "BE5D", source: "Lindwurm" } +3172.9 "Grotesquerie 2" Ability { id: "B4EA", source: "Lindwurm" } +3172.9 "Mana Burst 3" Ability { id: "BBE3", source: "Lindwurm" } +3173.5 "Hemorrhagic Projection 2" Ability { id: "B922", source: "Lindwurm" } +3178.9 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } + +# Blood Mana / Blood Wakening Phase (Superchain) +3184.1 "Mutating Cells" Ability { id: "B505", source: "Lindwurm" } +3185.3 "--sync--" #Ability { id: "B506", source: "Lindwurm" } +3185.3 "--sync--" #Ability { id: "B506", source: "Lindwurm" } +3190.3 "Blood Mana" Ability { id: "B4FB", source: "Lindwurm" } +3193.6 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } +3194.0 "--sync--" Ability { id: "B4FD", source: "Mana Sphere" } +3202.8 "Dramatic Lysis x8" #Ability { id: "B507", source: "Lindwurm" } +3203.0 "Bloody Burst 1" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player +3203.4 "Bloody Burst 2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player +3206.7 "--sync--" Ability { id: "B4FF", source: "Mana Sphere" } +3207.6 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } +3209.8 "--sync--" Ability { id: "B4FF", source: "Mana Sphere" } +3210.7 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } + +# TBD Clean-up/Generalize this part as its dependent on what was soaked and what spawned +3217.4 "Blood Wakening" Ability { id: "B500", source: "Lindwurm" } +3218.6 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } +3219.0 "Straightforward Thunder II" #Ability { id: "B503", source: "Lindwurm" } +3219.0 "Lindwurm's Aero III" #Ability { id: "B502", source: "Lindwurm" } +3219.0 "Sideways Fire II" #Ability { id: "B504", source: "Lindwurm" } +3219.0 "Lindwurm's Water III" #Ability { id: "B501", source: "Lindwurm" } +3219.0 "Lindwurm's Aero III" #Ability { id: "B502", source: "Lindwurm" } +3219.0 "Sideways Fire II" #Ability { id: "B504", source: "Lindwurm" } +3223.6 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } +3224.0 "Sideways Fire II" #Ability { id: "B504", source: "Lindwurm" } +3224.0 "Straightforward Thunder II" #Ability { id: "B503", source: "Lindwurm" } +3224.0 "Sideways Fire II" #Ability { id: "B504", source: "Lindwurm" } +3224.0 "Lindwurm's Water III" #Ability { id: "B501", source: "Lindwurm" } +3224.0 "Straightforward Thunder II" #Ability { id: "B503", source: "Lindwurm" } +3228.3 "Netherworld Near/Netherworld Far" Ability { id: ["B52B", "B52C"], source: "Lindwurm" } +3229.5 "Wailing Wave" Ability { id: "B52D", source: "Lindwurm" } +3236.4 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } # TBD # IGNORED ABILITIES @@ -415,6 +461,8 @@ hideall "--sync--" # B4E9 Grotesquerie: VFX # B4F1 Grotesquerie: VFX used in Reenactment # B4EE Mana Burst: VFX used in Reenactment +# B4EF Heavy Slam: VFX used in Reenactment +# B508 Unmitigated Explosion: Getting hit when you have Mitigation α or failing to get hit with Mitigation β, applies 30s damage down # ALL ENCOUNTER ABILITIES # Phase 1 @@ -480,6 +528,7 @@ hideall "--sync--" # B4D6 Visceral Burst # B4D7 The Fixer # B538 Refreshing Overkill: Enrage castbar +# B539 Refreshing Overkill: Non-enrage # B53A Refreshing Overkill: Enrage # B53E Skinsplitter: Damage from running into snake during Cruel Coil # B56F --sync-- @@ -541,7 +590,10 @@ hideall "--sync--" # B4F8 Lindwurm's Glare # B4FA Lindwurm's Thunder II # B4FB Blood Mana +# B4FC --sync-- +# B4FD --sync-- # B4FE Bloody Burst +# B4FF --sync-- # B500 Blood Wakening # B501 Lindwurm's Water III # B502 Lindwurm's Aero III @@ -550,6 +602,7 @@ hideall "--sync--" # B505 Mutating Cells # B506 --sync-- # B507 Dramatic Lysis +# B508 Unmitigated Explosion # B509 Idyllic Dream # B50F Power Gusher # B510 Power Gusher @@ -566,7 +619,7 @@ hideall "--sync--" # B51C Temporal Curtain # B51D --sync-- # B51E --sync-- -# B51F Attack +# B51F --sync--: Attack # B520 Double Sobat # B521 Double Sobat # B522 Double Sobat From 872d2c5a6ebfe960a7f252570d5186a255f1b433 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 00:56:16 -0500 Subject: [PATCH 075/100] add some delay to double sobat 2 and snaking kick --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 75fb766ab7..04ee5362c3 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1484,6 +1484,7 @@ const triggerSet: TriggerSet = { return false; return true; }, + delaySeconds: 0.1, // Need to delay for actor position update alertText: (data, matches, output) => { const actor = data.actorPositions[matches.sourceId]; if (actor === undefined) @@ -1619,6 +1620,7 @@ const triggerSet: TriggerSet = { // - 270 degree turn type: 'StartsUsing', netRegex: { id: 'B525', source: 'Lindwurm', capture: true }, + delaySeconds: 0.1, // Need to delay for actor position update alertText: (data, matches, output) => { const actor = data.actorPositions[matches.sourceId]; if (actor === undefined) From 6e14e7d858a143380fa797d85a30a38a15d070e3 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 06:14:16 -0500 Subject: [PATCH 076/100] additional control data0 for split scourge venomous --- ui/raidboss/data/07-dt/raid/r12s.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 04ee5362c3..1dc0db5bd3 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1215,10 +1215,13 @@ const triggerSet: TriggerSet = { id: 'R12S Split Scourge and Venomous Scourge', // B4AB Split Scourge and B4A8 Venomous Scourge are instant casts // This actor control happens along with boss becoming targetable + // Seems there are two different data0 values possible: + // 1E01: Coming back from Cardinal platforms + // 1E001: Coming back from Intercardinal platforms type: 'ActorControl', - netRegex: { command: '8000000D', data0: '1E01', capture: false }, + netRegex: { command: '8000000D', data0: ['1E01', '1E001'], capture: false }, durationSeconds: 9, - suppressSeconds: 1, + suppressSeconds: 9999, infoText: (data, _matches, output) => { if (data.role === 'tank') return output.tank!(); From c8395804f9b5ee80eb9d464e27791c3e69738f45 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 07:32:24 -0500 Subject: [PATCH 077/100] more p2 updates, some idyllic + extended rest with fflogs --- ui/raidboss/data/07-dt/raid/r12s.txt | 233 ++++++++++++++++++--------- 1 file changed, 153 insertions(+), 80 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 581b760d92..fa2c8f03f7 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -340,93 +340,163 @@ hideall "--sync--" ### Phase 2: Lindwurm II -# -p B528:3015.7 -# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE -# -it "Lindwurm" # -p B528:3012.1 -# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 +# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 B4FF BCB0 # -it "Lindwurm" 3000.5 label "r12s-p2-start" 3010.7 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 3015.7 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } 3022.9 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } -3028.2 "Replication 1" Ability { id: "B4D8", source: "Lindwurm" } -3040.0 "Top-tier Slam x2" Ability { id: "B4DE", source: "Lindschrat" } -3040.8 "Winged Scourge x4" Ability { id: "B4DC", source: "Lindwurm" } -3041.0 "Mighty Magic x4" Ability { id: "B4E0", source: "Lindwurm" } -3045.7 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } -3054.1 "--clones move 1--" #Ability { id: "B4D9", source: "Lindschrat" } -3055.1 "--clones move 2--" #Ability { id: "B4D9", source: "Lindschrat" } -3061.4 "Top-tier Slam x2" Ability { id: "B4DE", source: "Lindschrat" } -3062.2 "Winged Scourge x4" #Ability { id: "B4DC", source: "Lindwurm" } -3062.5 "Mighty Magic x4" Ability { id: "B4E0", source: "Lindwurm" } -3069.8 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } -3070.4 "Double Sobat 1" Ability { id: "B522", source: "Lindwurm" } -3075.0 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } -3077.4 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } +3028.0 "Replication 1" Ability { id: "B4D8", source: "Lindwurm" } +3039.7 "Top-tier Slam x2" Ability { id: "B4DE", source: "Lindschrat" } +3040.5 "Winged Scourge x4" Ability { id: "B4DC", source: "Lindwurm" } +3040.7 "Mighty Magic x4" #Ability { id: "B4E0", source: "Lindwurm" } +3045.3 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } +3053.7 "--clones move 1--" #Ability { id: "B4D9", source: "Lindschrat" } +3054.7 "--clones move 2--" #Ability { id: "B4D9", source: "Lindschrat" } +3061.0 "Top-tier Slam x2" Ability { id: "B4DE", source: "Lindschrat" } +3061.8 "Winged Scourge x4" Ability { id: "B4DC", source: "Lindwurm" } +3062.1 "Mighty Magic x4" #Ability { id: "B4E0", source: "Lindwurm" } +3069.4 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3070.0 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } +3074.6 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3077.0 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } # NOTE: Depending on clone order and tethers player takes, spells at each instance will differ # TBD: Generalize these? -3091.6 "Staging" Ability { id: "B4E1", source: "Lindwurm" } -3102.6 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } -3105.8 "Replication 2" Ability { id: "B4D8", source: "Lindwurm" } -3128.2 "Firefall Splash" Ability { id: "B4E4", source: "Lindwurm" } -3128.9 "Scalding Waves x4" Ability { id: "B4E5", source: "Lindwurm" } -3130.3 "Mana Burst x3" Ability { id: "B4E7", source: "Lindwurm" } -3135.7 "Heavy Slam x2" Ability { id: "B4E8", source: "Lindschrat" } -3136.9 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } -3137.5 "Hemorrhagic Projection x2" Ability { id: "B4EB", source: "Lindwurm" } -3141.4 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } - -3151.6 "Reenactment 1" Ability { id: "B4EC", source: "Lindwurm" } -3159.7 "Firefall Splash" Ability { id: "B4ED", source: "Lindschrat" } -3159.7 "Netherwrath Near/Netherwrath Far" Ability { id: ["B52E", "B52F"], source: "Lindwurm" } -3160.9 "Mana Burst 1" #Ability { id: "BBE3", source: "Lindwurm" } -3160.9 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } -3161.0 "Scalding Waves x4" Ability { id: "B8E1", source: "Lindwurm" } -3164.8 "Mana Burst 2" Ability { id: "BBE3", source: "Lindwurm" } -3164.8 "Grotesquerie 1" Ability { id: "B4EA", source: "Lindwurm" } -3165.4 "Hemorrhagic Projection 1" Ability { id: "B922", source: "Lindwurm" } -3169.1 "Heavy Slam" Ability { id: "BE5D", source: "Lindwurm" } -3172.9 "Grotesquerie 2" Ability { id: "B4EA", source: "Lindwurm" } -3172.9 "Mana Burst 3" Ability { id: "BBE3", source: "Lindwurm" } -3173.5 "Hemorrhagic Projection 2" Ability { id: "B922", source: "Lindwurm" } -3178.9 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } +3091.2 "Staging" Ability { id: "B4E1", source: "Lindwurm" } +3102.2 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } +3105.4 "Replication 2" Ability { id: "B4D8", source: "Lindwurm" } +3127.8 "Firefall Splash" Ability { id: "B4E4", source: "Lindwurm" } +3128.5 "Scalding Waves x4" Ability { id: "B4E5", source: "Lindwurm" } +3129.9 "Mana Burst x3" Ability { id: "B4E7", source: "Lindwurm" } +3135.5 "Heavy Slam x2" Ability { id: "B4E8", source: "Lindschrat" } +3136.7 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } +3137.3 "Hemorrhagic Projection x2" Ability { id: "B4EB", source: "Lindwurm" } +3141.1 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } + +3151.3 "Reenactment 1" Ability { id: "B4EC", source: "Lindwurm" } +3159.4 "Firefall Splash" #Ability { id: "B4ED", source: "Lindschrat" } +3159.4 "Netherwrath Near/Netherwrath Far" Ability { id: ["B52E", "B52F"], source: "Lindwurm" } +3160.6 "Mana Burst 1" Ability { id: "BBE3", source: "Lindwurm" } +3160.6 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } +3160.7 "Scalding Waves x4" #Ability { id: "B8E1", source: "Lindwurm" } +3164.5 "Grotesquerie 1" #Ability { id: "B4EA", source: "Lindwurm" } +3164.5 "Mana Burst 2" Ability { id: "BBE3", source: "Lindwurm" } +3165.1 "Hemorrhagic Projection 1" Ability { id: "B922", source: "Lindwurm" } +3168.8 "Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } +3172.6 "Mana Burst 3" Ability { id: "BBE3", source: "Lindwurm" } +3172.6 "Grotesquerie 2" #Ability { id: "B4EA", source: "Lindwurm" } +3173.2 "Hemorrhagic Projection 2" Ability { id: "B922", source: "Lindwurm" } +3178.6 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } # Blood Mana / Blood Wakening Phase (Superchain) -3184.1 "Mutating Cells" Ability { id: "B505", source: "Lindwurm" } -3185.3 "--sync--" #Ability { id: "B506", source: "Lindwurm" } -3185.3 "--sync--" #Ability { id: "B506", source: "Lindwurm" } -3190.3 "Blood Mana" Ability { id: "B4FB", source: "Lindwurm" } -3193.6 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } -3194.0 "--sync--" Ability { id: "B4FD", source: "Mana Sphere" } -3202.8 "Dramatic Lysis x8" #Ability { id: "B507", source: "Lindwurm" } -3203.0 "Bloody Burst 1" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player -3203.4 "Bloody Burst 2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player -3206.7 "--sync--" Ability { id: "B4FF", source: "Mana Sphere" } -3207.6 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } -3209.8 "--sync--" Ability { id: "B4FF", source: "Mana Sphere" } -3210.7 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } +3183.8 "Mutating Cells" Ability { id: "B505", source: "Lindwurm" } +3185.0 "--sync--" Ability { id: "B506", source: "Lindwurm" } +3190.0 "Blood Mana" Ability { id: "B4FB", source: "Lindwurm" } +3193.3 "--black holes--" Ability { id: "BCB0", source: "Mana Sphere" } +3193.7 "--shapes--" Ability { id: "B4FD", source: "Mana Sphere" } +3200.7 "Bloody Burst 1" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player +3201.0 "Bloody Burst 2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player +3202.2 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } # TBD Clean-up/Generalize this part as its dependent on what was soaked and what spawned -3217.4 "Blood Wakening" Ability { id: "B500", source: "Lindwurm" } -3218.6 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } -3219.0 "Straightforward Thunder II" #Ability { id: "B503", source: "Lindwurm" } -3219.0 "Lindwurm's Aero III" #Ability { id: "B502", source: "Lindwurm" } -3219.0 "Sideways Fire II" #Ability { id: "B504", source: "Lindwurm" } -3219.0 "Lindwurm's Water III" #Ability { id: "B501", source: "Lindwurm" } -3219.0 "Lindwurm's Aero III" #Ability { id: "B502", source: "Lindwurm" } -3219.0 "Sideways Fire II" #Ability { id: "B504", source: "Lindwurm" } -3223.6 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } -3224.0 "Sideways Fire II" #Ability { id: "B504", source: "Lindwurm" } -3224.0 "Straightforward Thunder II" #Ability { id: "B503", source: "Lindwurm" } -3224.0 "Sideways Fire II" #Ability { id: "B504", source: "Lindwurm" } -3224.0 "Lindwurm's Water III" #Ability { id: "B501", source: "Lindwurm" } -3224.0 "Straightforward Thunder II" #Ability { id: "B503", source: "Lindwurm" } -3228.3 "Netherworld Near/Netherworld Far" Ability { id: ["B52B", "B52C"], source: "Lindwurm" } -3229.5 "Wailing Wave" Ability { id: "B52D", source: "Lindwurm" } -3236.4 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } -# TBD +3216.7 "Blood Wakening" Ability { id: "B500", source: "Lindwurm" } +3217.9 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } +3218.3 "Black Hole 1" Ability { id: ["B501", "B502", "B503", "B504"], source: "Lindwurm" } +3222.9 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } +3223.3 "Black Hole 2" Ability { id: ["B501", "B502", "B503", "B504"], source: "Lindwurm" } +3227.6 "Netherworld Near/Netherworld Far" Ability { id: ["B52B", "B52C"], source: "Lindwurm" } +3228.8 "Wailing Wave x3" Ability { id: "B52D", source: "Lindwurm" } +3231.8 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } +3235.8 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } +3245.0 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3245.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } +3250.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3252.6 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } +3260.7 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } + +# TBD Clean-up/Generalize this as well since stacks/defamation order is tether dependent +3268.8 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } +3275.0 "Staging" Ability { id: "B4E1", source: "Lindwurm" } +3283.4 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } +3290.1 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } +3296.2 "Replication 3" Ability { id: "B4D8", source: "Lindwurm" } +3308.6 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } +3309.6 "Power Gusher" #Ability { id: "B512", source: "Lindwurm" } +3309.6 "Power Gusher" #Ability { id: "B50F", source: "Lindschrat" } +3309.6 "Snaking Kick" #Ability { id: "B511", source: "Lindschrat" } +3309.6 "Power Gusher" #Ability { id: "B510", source: "Lindschrat" } +3314.7 "Replication 4" Ability { id: "B4D8", source: "Lindwurm" } + +# Towers Preview +3334.3 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } +3337.7 "Power Gusher" #Ability { id: "B513", source: "Lindschrat" } +3337.7 "Snaking Kick" Ability { id: "B515", source: "Lindschrat" } +3337.7 "Power Gusher" #Ability { id: "B514", source: "Lindschrat" } +3338.7 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } +3338.9 "Power Gusher" #Ability { id: "B516", source: "Lindwurm" } +3342.8 "Lindwurm's Meteor" Ability { id: "B4F2", source: "Lindwurm" } +3348.9 "Downfall" Ability { id: "B4F3", source: "Lindwurm" } +3355.0 "Arcadian Arcanum" Ability { id: "B529", source: "Lindwurm" } +3356.2 "Arcadian Arcanum" Ability { id: "B9D9", source: "Lindwurm" } + +# First Stacks/Defamations +3363.0 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } +3369.6 "Heavy Slam" Ability { id: "B519", source: "Lindschrat" } +3374.6 "Mana Burst" Ability { id: "B517", source: "Lindschrat" } +3375.8 "Mana Burst" Ability { id: "B518", source: "Lindwurm" } +3379.6 "Heavy Slam" Ability { id: "B519", source: "Lindschrat" } +3384.6 "Mana Burst" Ability { id: "B517", source: "Lindschrat" } + +# fflogs +3389.5 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } window 10,10 +3393.9 "Cosmic Kiss" Ability { id: "B4F4", source: "Lindwurm" } +3394.6 "Lindwurm's Dark II" Ability { id: "B4F6", source: "Lindwurm" } +3396.6 "Pyretic Wurm" Ability { id: "B4F9", source: "Lindwurm" } +3399.6 "Lindwurm's Stone III" #Ability { id: "B4F7", source: "Lindwurm" } +3404.6 "Lindwurm's Thunder II" #Ability { id: "B4FA", source: "Lindwurm" } +3404.6 "Lindwurm's Glare" #Ability { id: "B4F8", source: "Lindwurm" } +3404.6 "Lindwurm's Thunder II" #Ability { id: "B4FA", source: "Lindwurm" } +3404.6 "Lindwurm's Glare" #Ability { id: "B4F8", source: "Lindwurm" } +3412.9 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } + +3416.0 "--sync--" Ability { id: "B51D", source: "Lindschrat" } +3419.1 "--sync--" Ability { id: "B4D9", source: "Lindschrat" } +3425.4 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } +3426.4 "Power Gusher" #Ability { id: "B50F", source: "Lindschrat" } +3426.4 "Snaking Kick" Ability { id: "BCAF", source: "Lindschrat" } +3431.5 "Reenactment 2" Ability { id: "B4EC", source: "Lindwurm" } +3433.5 "Heavy Slam" Ability { id: "B4EF", source: "Lindschrat" } +3434.7 "Mana Burst" Ability { id: "BBE3", source: "Lindwurm" } +3434.9 "Heavy Slam" #Ability { id: "BE5D", source: "Lindwurm" } +3440.5 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } +3444.1 "Power Gusher" #Ability { id: "B513", source: "Lindschrat" } +3444.1 "Snaking Kick" Ability { id: "B515", source: "Lindschrat" } +3445.1 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } +3445.3 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } +3448.2 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } +3454.5 "Heavy Slam" #Ability { id: "B4EF", source: "Lindschrat" } +3454.5 "--sync--" Ability { id: "B51E", source: "Lindschrat" } +3455.7 "Mana Burst" Ability { id: "BBE3", source: "Lindwurm" } +3455.9 "Heavy Slam" Ability { id: "BE5D", source: "Lindwurm" } +3459.5 "Power Gusher" Ability { id: "B51B", source: "Lindschrat" } +3460.6 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } +3466.5 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } +3474.6 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3475.2 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } +3479.8 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3482.2 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } + +# Enrage Sequence +3496.0 "Replication 5" Ability { id: "B46C", source: "Lindwurm" } +3509.4 "Arcadian Hell 1" Ability { id: "B533", source: "Lindwurm" } +3509.4 "Arcadian Hell" #Ability { id: "B534", source: "Lindschrat" } +3525.6 "Arcadian Hell 2" Ability { id: "B533", source: "Lindwurm" } +3525.6 "Arcadian Hell" #Ability { id: "B535", source: "Lindschrat" } +3538.4 "--sync--" StartsUsing { id: "B537", source: "Lindwurm" } +3548.4 "Arcadian Hell (Enrage)" Ability { id: "B537", source: "Lindwurm" } +3548.4 "Arcadian Hell (Enrage)" #Ability { id: "BEC1", source: "Lindschrat" } # IGNORED ABILITIES # Phase 1 @@ -463,6 +533,8 @@ hideall "--sync--" # B4EE Mana Burst: VFX used in Reenactment # B4EF Heavy Slam: VFX used in Reenactment # B508 Unmitigated Explosion: Getting hit when you have Mitigation α or failing to get hit with Mitigation β, applies 30s damage down +# B4FF --sync--: VFX related to Mana Spheres being eaten by Black Hole? +# BCB0 --sync--: VFX related to Mana Spheres being eaten by Black Hole? # ALL ENCOUNTER ABILITIES # Phase 1 @@ -579,8 +651,8 @@ hideall "--sync--" # B4EC Reenactment # B4ED Firefall Splash # B4EE Mana Burst -# B4F0 Unmitigated Impact # B4EF Heavy Slam +# B4F0 Unmitigated Impact # B4F1 Grotesquerie # B4F2 Lindwurm's Meteor # B4F3 Downfall @@ -620,11 +692,12 @@ hideall "--sync--" # B51D --sync-- # B51E --sync-- # B51F --sync--: Attack -# B520 Double Sobat -# B521 Double Sobat -# B522 Double Sobat -# B524 Double Sobat -# B525 Double Sobat +# B520 Double Sobat: Castbar +# B521 Double Sobat: 0 degree left turn then B525 +# B522 Double Sobat: 90 degree left turn then B525 +# B523 Double Sobat: 180 degree left turn then B525 +# B524 Double Sobat: 270 degree left turn (turns to the right) +# B525 Double Sobat: Followup cleave # B526 Esoteric Finisher # B527 Snaking Kick # B528 Arcadia Aflame From c1e61330a52d77012065c6236ca179ff041c1cda Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 07:37:09 -0500 Subject: [PATCH 078/100] add Blood Mana/Blood Wakening solution triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 246 +++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 8 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 1dc0db5bd3..025dd857e5 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -50,7 +50,16 @@ export interface Data extends RaidbossData { replication2TetherMap: { [dirNum: string]: string }; replication2BossId?: string; myReplication2Tether?: string; + netherwrathFollowup: boolean; myMutation?: 'alpha' | 'beta'; + manaSpheres: { + [id: string]: 'lightning' | 'fire' | 'water' | 'wind' | 'blackHole'; + }; + westManaSpheres: { [id: string]: { x: number; y: number } }; + eastManaSpheres: { [id: string]: { x: number; y: number } }; + closeManaSphereIds: string[]; + firstBlackHole?: 'east' | 'west'; + manaSpherePopSide?: 'east' | 'west'; replication3CloneOrder: number[]; hasLightResistanceDown: boolean; doomPlayers: string[]; @@ -117,6 +126,11 @@ const triggerSet: TriggerSet = { replicationCounter: 0, replication1FollowUp: false, replication2TetherMap: {}, + netherwrathFollowup: false, + manaSpheres: {}, + westManaSpheres: {}, + eastManaSpheres: {}, + closeManaSphereIds: [], replication3CloneOrder: [], hasLightResistanceDown: false, doomPlayers: [], @@ -2212,6 +2226,80 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Reenactment 1 Scalding Waves Collect', + // Players need to wait for BBE3 Mana Burst Defamations on the clones to complete before next mechanic + // NOTE: This is used with DN Strategy + type: 'Ability', + netRegex: { id: 'B8E1', source: 'Lindwurm', capture: false }, + condition: (data) => data.phase === 'reenactment1', + suppressSeconds: 9999, + run: (data) => data.netherwrathFollowup = true, + }, + { + id: 'R12S Reenactment 1 Clone Stacks', + // Players need to wait for BBE3 Mana Burst defamations on clones to complete + // This happens three times during reenactment and the third one (which is after the proteans) is the trigger + // NOTE: This is used with DN Strategy + type: 'Ability', + netRegex: { id: 'BBE3', source: 'Lindwurm', capture: false }, + condition: (data) => data.netherwrathFollowup, + suppressSeconds: 9999, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'East/West Clone Stacks', + }, + }, + }, + { + id: 'R12S Reenactment 1 Clone Stacks', + // Players need to run back to north after clone stacks (BE5D Heavy Slam) + // The clone stacks become a defamation and the other a cleave going East or West through the room + // NOTE: This is used with DN Strategy + type: 'Ability', + netRegex: { id: 'BE5D', source: 'Lindwurm', capture: false }, + condition: (data) => data.netherwrathFollowup, + suppressSeconds: 9999, + alertText: (_data, _matches, output) => output.north!(), + outputStrings: { + north: Outputs.north, + }, + }, + { + id: 'R12S Mana Sphere Collect and Label', + // Combatants Spawn ~3s before B505 Mutating Cells startsUsing + // Their positions are available at B4FD in the 264 AbilityExtra lines and updated periodically after with 270 lines + // 19208 => Lightning Bowtie (N/S Cleave) + // 19209 => Fire Bowtie (E/W Cleave) + // 19205 => Black Hole + // 19206 => Water Sphere/Chariot + // 19207 => Wind Donut + // Position at add is center, so not useful here yet + type: 'AddedCombatant', + netRegex: { name: 'Mana Sphere', capture: true }, + run: (data, matches) => { + const id = matches.id; + const npcBaseId = parseInt(matches.npcBaseId); + switch (npcBaseId) { + case 19205: + data.manaSpheres[id] = 'blackHole'; + return; + case 19206: + data.manaSpheres[id] = 'water'; + return; + case 19207: + data.manaSpheres[id] = 'wind'; + return; + case 19208: + data.manaSpheres[id] = 'lightning'; + return; + case 19209: + data.manaSpheres[id] = 'fire'; + return; + } + }, + }, { id: 'R12S Mutation α/β Collect', // Used in Blood Mana / Blood Awakening Mechanics @@ -2245,23 +2333,143 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Blood Mana', + id: 'R12S Mana Sphere Position Collect', + // BCB0 Black Holes: + // These are (90, 100) and (110, 100) + // B4FD Shapes + // Side that needs to be exploded will have pairs with 2 of the same x or y coords + // Side to get the shapes to explode will be closest distance to black hole + type: 'AbilityExtra', + netRegex: { id: 'B4FD', capture: true }, + run: (data, matches) => { + // Calculate Distance to Black Hole + const getDistance = ( + x: number, + y: number, + ): number => { + const blackHoleX = x < 100 ? 90 : 110; + const dx = x - blackHoleX; + const dy = y - 100; + return Math.round(Math.sqrt(dx * dx + dy * dy)); + }; + const x = parseFloat(matches.x); + const y = parseFloat(matches.y); + const d = getDistance(x, y); + const id = matches.sourceId; + + // Put into different objects for easier lookup + if (x < 100) { + data.westManaSpheres[id] = { x: x, y: y }; + } + data.eastManaSpheres[id] = { x: x, y: y }; + + // Shapes with 6 distance are close, Shapes with 12 are far + if (d < 7) { + data.closeManaSphereIds.push(id); + + // Have enough data to solve at this point + if (data.closeManaSphereIds.length === 2) { + const popSide = x < 100 ? 'east' : 'west'; + data.manaSpherePopSide = popSide; + + const sphereId1 = data.closeManaSphereIds[0]; + const sphereId2 = id; + if (sphereId1 === undefined) + return; + + const sphereType1 = data.manaSpheres[sphereId1]; + const sphereType2 = data.manaSpheres[sphereId2]; + if (sphereType1 === undefined || sphereType2 === undefined) + return; + + // If you see Water, pop side first + // If you see Wind, non-pop side + // Can't be Lightning + Wind because Fire hits the donut + // Fire + Lightning would hit whole room + // Water + Wind would hit whole room + const nonPopSide = popSide === 'east' ? 'west' : 'east'; + const first = [sphereType1, sphereType2]; + const dir2 = first.includes('water') ? popSide : nonPopSide; + data.firstBlackHole = dir2; + } + } + }, + }, + { + id: 'R12S Black Hole and Shapes', // Black Holes and shapes - // TODO: Tell what shape to pop + which Black Hole mechanics and side? type: 'Ability', - netRegex: { id: 'B4FB', source: 'Lindwurm', capture: false }, + netRegex: { id: 'B4FD', source: 'Mana Sphere', capture: false }, + delaySeconds: 0.1, + suppressSeconds: 9999, infoText: (data, _matches, output) => { + const popSide = data.manaSpherePopSide; + const blackHole = data.firstBlackHole; + const sphereId1 = data.closeManaSphereIds[0]; + const sphereId2 = data.closeManaSphereIds[1]; + if ( + popSide === undefined || + blackHole === undefined || + sphereId1 === undefined || + sphereId2 === undefined + ) + return data.myMutation === 'alpha' ? output.alpha!() : output.beta!(); + + const sphereType1 = data.manaSpheres[sphereId1]; + const sphereType2 = data.manaSpheres[sphereId2]; + if (sphereType1 === undefined || sphereType2 === undefined) + return data.myMutation === 'alpha' ? output.alpha!() : output.beta!(); + if (data.myMutation === 'alpha') - return output.alpha!(); - return output.beta!(); + return output.alphaDir!({ + dir1: output[popSide]!(), + northSouth: output.northSouth!(), + dir2: output[blackHole]!(), + }); + return output.betaDir!({ + dir1: output[popSide]!(), + shape1: output[sphereType1]!(), + shape2: output[sphereType2]!(), + northSouth: output.northSouth!(), + dir2: output[blackHole]!(), + }); }, outputStrings: { + east: Outputs.east, + west: Outputs.west, + northSouth: { + en: 'N/S', + de: 'N/S', + fr: 'N/S', + ja: '南/北', + cn: '上/下', + ko: '남/북', + tc: '上/下', + }, + water: { + en: 'Orb', + }, + lightning: { + en: 'Lightning', + }, + fire: { + en: 'Fire', + }, + wind: { + en: 'Donut', + }, alpha: { en: 'Avoid Shape AoEs, Wait by Black Hole', }, beta: { en: 'Shared Shape Soak => Get by Black Hole', }, + alphaDir: { + en: 'Avoid ${dir1} Shape AoEs => ${dir2} Black Hole + ${northSouth}', + }, + betaDir: { + en: 'Share ${dir1} ${shape1}/${shape2} => ${dir2} Black Hole + ${northSouth}', + }, }, }, { @@ -2271,15 +2479,37 @@ const triggerSet: TriggerSet = { // B502 Lindwurm's Aero III // B503 Straightforward Thunder II // B504 Sideways Fire II - // TODO: Tell which Black Hole and its mechanics? - type: 'StartsUsing', + type: 'Ability', netRegex: { id: ['B501', 'B502', 'B503', 'B504'], source: 'Lindwurm', capture: false }, suppressSeconds: 9999, - alertText: (_data, _matches, output) => output.move!(), + alertText: (data, _matches, output) => { + const blackHole = data.firstBlackHole; + if (blackHole === undefined) + return output.move!(); + const next = blackHole === 'east' ? 'west' : 'east'; + return output.moveDir!({ + northSouth: output.northSouth!(), + dir: output[next]!(), + }); + }, outputStrings: { + east: Outputs.east, + west: Outputs.west, + northSouth: { + en: 'N/S', + de: 'N/S', + fr: 'N/S', + ja: '南/北', + cn: '上/下', + ko: '남/북', + tc: '上/下', + }, move: { en: 'Move to other Black Hole', }, + moveDir: { + en: '${dir} Black Hole + ${northSouth}', + }, }, }, { From 58925a914bdfbd7e314a1060aec040a8ae06a6a2 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 07:41:31 -0500 Subject: [PATCH 079/100] fixes + timelineReplace for netherworld --- ui/raidboss/data/07-dt/raid/r12s.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 025dd857e5..2eb0b8ca38 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2253,7 +2253,7 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Reenactment 1 Clone Stacks', + id: 'R12S Reenactment 1 Final Defamation Dodge Reminder', // Players need to run back to north after clone stacks (BE5D Heavy Slam) // The clone stacks become a defamation and the other a cleave going East or West through the room // NOTE: This is used with DN Strategy @@ -2487,7 +2487,7 @@ const triggerSet: TriggerSet = { if (blackHole === undefined) return output.move!(); const next = blackHole === 'east' ? 'west' : 'east'; - return output.moveDir!({ + return output.moveDir!({ northSouth: output.northSouth!(), dir: output[next]!(), }); @@ -2768,6 +2768,7 @@ const triggerSet: TriggerSet = { 'locale': 'en', 'replaceText': { 'Netherwrath Near/Netherwrath Far': 'Netherwrath Near/Far', + 'Netherworld Near/Netherwworld Far': 'Netherworld Near/Far', }, }, ], From 3c991caeab655faa5c4c8b51f1854c672ac792d9 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 08:32:37 -0500 Subject: [PATCH 080/100] refactor double sobat 2 This appears to be more accurate and not require delay by just predicting what the boss is going to turn to. --- ui/raidboss/data/07-dt/raid/r12s.ts | 41 ++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 2eb0b8ca38..6721da8ca5 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1631,20 +1631,35 @@ const triggerSet: TriggerSet = { { id: 'R12S Double Sobat 2', // Followup half-room cleave: - // - No turn - // - 90 degree turn - // - 180 degree turn - // - 270 degree turn - type: 'StartsUsing', - netRegex: { id: 'B525', source: 'Lindwurm', capture: true }, - delaySeconds: 0.1, // Need to delay for actor position update - alertText: (data, matches, output) => { - const actor = data.actorPositions[matches.sourceId]; - if (actor === undefined) - return output.getBehind!(); + // B521 Double Sobat: 0 degree left turn then B525 + // B522 Double Sobat: 90 degree left turn then B525 + // B523 Double Sobat: 180 degree left turn then B525 + // B524 Double Sobat: 270 degree left turn (this ends up 90 degrees to the right) + type: 'Ability', + suppressSeconds: 1, + netRegex: { id: ['B521', 'B522', 'B523', 'B524'], source: 'Lindwurm', capture: true }, + alertText: (_data, matches, output) => { + const hdg = parseFloat(matches.heading); + const dirNum = Directions.hdgTo16DirNum(hdg); + const getNewDirNum = ( + dirNum: number, + id: string, + ): number => { + switch (id) { + case 'B521': + return dirNum; + case 'B522': + return dirNum - 4; + case 'B523': + return dirNum - 8; + case 'B524': + return dirNum - 12; + } + throw new UnreachableCode(); + }; - const dirNum = (Directions.hdgTo16DirNum(actor.heading) + 8) % 16; - const dir = Directions.output16Dir[dirNum] ?? 'unknown'; + const newDirNum = (getNewDirNum(dirNum, matches.id) + 8) % 16; + const dir = Directions.output16Dir[newDirNum] ?? 'unknown'; return output.getBehindDir!({ dir: output[dir]!(), mech: output.getBehind!(), From 112f32496b4a865eedc69270fb4b7b8c6dc0508d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 08:35:46 -0500 Subject: [PATCH 081/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 6721da8ca5..9b06f6c235 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1636,8 +1636,8 @@ const triggerSet: TriggerSet = { // B523 Double Sobat: 180 degree left turn then B525 // B524 Double Sobat: 270 degree left turn (this ends up 90 degrees to the right) type: 'Ability', - suppressSeconds: 1, netRegex: { id: ['B521', 'B522', 'B523', 'B524'], source: 'Lindwurm', capture: true }, + suppressSeconds: 1, alertText: (_data, matches, output) => { const hdg = parseFloat(matches.heading); const dirNum = Directions.hdgTo16DirNum(hdg); From bddcba6462ed8ad462877b3bcbc290e3b34ca780 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 08:50:17 -0500 Subject: [PATCH 082/100] lindwurm's meteor is a bigAoe and healer group split There's also cleaves to avoid at this time, which possibly will be called a second or two before this. --- ui/raidboss/data/07-dt/raid/r12s.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 9b06f6c235..b9ede17a70 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2653,9 +2653,18 @@ const triggerSet: TriggerSet = { id: 'R12S Lindwurm\'s Meteor', type: 'StartsUsing', netRegex: { id: 'B4F2', source: 'Lindwurm', capture: false }, - infoText: (_data, _matches, output) => output.healerGroups!(), + alertText: (_data, _matches, output) => { + return output.text!({ + mech1: output.bigAoe!(), + mech2: output.healerGroups!() + }); + }, outputStrings: { healerGroups: Outputs.healerGroups, + bigAoe: Outputs.bigAoe, + text: { + en: '${mech1} => ${mech2}', + }, }, }, { From a81c4554a7a171f6d557137616e46e478e364bea Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 08:51:50 -0500 Subject: [PATCH 083/100] wording Both events happen with the ability. --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index b9ede17a70..481242662c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2663,7 +2663,7 @@ const triggerSet: TriggerSet = { healerGroups: Outputs.healerGroups, bigAoe: Outputs.bigAoe, text: { - en: '${mech1} => ${mech2}', + en: '${mech1} + ${mech2}', }, }, }, From be619209487191b14316b433b6aed9ee5369af59 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 08:52:37 -0500 Subject: [PATCH 084/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 481242662c..64cf884c0b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2656,7 +2656,7 @@ const triggerSet: TriggerSet = { alertText: (_data, _matches, output) => { return output.text!({ mech1: output.bigAoe!(), - mech2: output.healerGroups!() + mech2: output.healerGroups!(), }); }, outputStrings: { From bef2f65b312a66d2569bc2a4c008131e3372095e Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 09:58:53 -0500 Subject: [PATCH 085/100] remove unused output --- ui/raidboss/data/07-dt/raid/r12s.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 64cf884c0b..7d2af0f1ec 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1922,15 +1922,6 @@ const triggerSet: TriggerSet = { outputStrings: { ...Directions.outputStrings8Dir, defamationOnYou: Outputs.defamationOnYou, - stackGroups: { - en: 'Stack Groups', - de: 'Gruppen-Sammeln', - fr: 'Package en groupes', - ja: '組み分け頭割り', - cn: '分组分摊', - ko: '그룹별 쉐어', - tc: '分組分攤', - }, baitProtean: { en: 'Bait Protean from Boss', }, From c2487f8b7ba692344e313eeba2a1124d77b31374 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 11:28:42 -0500 Subject: [PATCH 086/100] add idyllic dream triggers up to start of 4th vision Replication 4 Locked Tether 2 is replacing the Lindwurm Meteor trigger, however there are a lot of things going on that need to be resolved in a quick order. The duration has been set to 8, which is when the cast ends. Unsure on the limit to the room split, it looks like it's halfway through the Downfall cast, so maybe 3.1 to 4.6s extra after the meteor hit? I imagine there is some MapEffect or control for this. Immediately on tether snap, you have a few seconds to dodge clone cleaves. Technically you could try to position prior to this with risk that your tether hasn't yet locked in. Simultaneously with the cleaves is the big Aoe and room split. Also, there is a chance the tether you got was messed up and you end up with a different tether than you picked up but right now it's still reminding which tether you locked with which. The tether itself will probably get a trigger to address the 4rth vision so that detail could be dropped, the right clone order still needs to be checked and matched to the tether the player chose. --- ui/raidboss/data/07-dt/raid/r12s.ts | 229 ++++++++++++++++++++++++++-- 1 file changed, 217 insertions(+), 12 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7d2af0f1ec..7640479d3a 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -60,7 +60,11 @@ export interface Data extends RaidbossData { closeManaSphereIds: string[]; firstBlackHole?: 'east' | 'west'; manaSpherePopSide?: 'east' | 'west'; + twistedVisionCounter: number; replication3CloneOrder: number[]; + idyllicVision2NorthSouthCleaveSpot?: 'north' | 'south'; + replication4TetherMap: { [dirNum: string]: string }; + myReplication4Tether?: string; hasLightResistanceDown: boolean; doomPlayers: string[]; } @@ -131,7 +135,9 @@ const triggerSet: TriggerSet = { westManaSpheres: {}, eastManaSpheres: {}, closeManaSphereIds: [], + twistedVisionCounter: 0, replication3CloneOrder: [], + replication4TetherMap: {}, hasLightResistanceDown: false, doomPlayers: [], }), @@ -189,6 +195,15 @@ const triggerSet: TriggerSet = { data.phase = 'reenactment2'; }, }, + { + id: 'R12S Phase Two Twisted Vision Tracker', + // Used for keeping track of phases in idyllic + type: 'StartsUsing', + netRegex: { id: 'BBE2', source: 'Lindwurm', capture: false }, + run: (data) => { + data.twistedVisionCounter = data.twistedVisionCounter + 1; + }, + }, { id: 'R12S Phase Two ActorSetPos Tracker', type: 'ActorSetPos', @@ -1722,7 +1737,7 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Replication 2 Ability Tethers Collect', + id: 'R12S Replication 2 and Replication 4 Ability Tethers Collect', // Record and store a map of where the tethers come from and what they do for later // Boss tether handled separately since boss can move around type: 'Tether', @@ -1734,13 +1749,20 @@ const triggerSet: TriggerSet = { ], capture: true, }, - condition: (data) => data.phase === 'replication2', + condition: (data) => { + if (data.phase === 'replication2' || data.phase === 'idyllic') + return true; + return false; + }, run: (data, matches) => { const actor = data.actorPositions[matches.sourceId]; if (actor === undefined) return; const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); - data.replication2TetherMap[dirNum] = matches.id; + if (data.phase === 'replication2') + data.replication2TetherMap[dirNum] = matches.id; + if (data.phase === 'idyllic') + data.replication4TetherMap[dirNum] = matches.id; }, }, { @@ -2641,25 +2663,208 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Lindwurm\'s Meteor', + id: 'R12S Idyllic Dream Power Gusher Collect', + // Need to know this for later + // B511 Snaking Kick + // B512 from boss is the VFX and has headings that show directions for B50F and B510 + // B50F Power Gusher is the East/West caster + // B510 Power Gusher is the North/South caster + // Right now just the B510 caster is needed to resolve type: 'StartsUsing', - netRegex: { id: 'B4F2', source: 'Lindwurm', capture: false }, - alertText: (_data, _matches, output) => { - return output.text!({ - mech1: output.bigAoe!(), - mech2: output.healerGroups!(), + netRegex: { id: 'B510', source: 'Lindschrat', capture: true }, + run: (data, matches) => { + const y = parseFloat(matches.y); + data.idyllicVision2NorthSouthCleaveSpot = y < center.y ? 'north' : 'south'; + }, + }, + { + id: 'R12S Replication 4 Ability Tethers Initial Call', + type: 'Tether', + netRegex: { + id: [ + headMarkerData['manaBurstTether'], + headMarkerData['heavySlamTether'], + ], + capture: true, + }, + condition: (data, matches) => { + if (data.me === matches.target && data.phase === 'idyllic') + return true; + return false; + }, + suppressSeconds: 9999, // Can get spammy if players have more than 1 tether or swap a lot + infoText: (data, matches, output) => { + // Get direction of the tether + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) { + switch (matches.id) { + case headMarkerData['manaBurstTether']: + return output.manaBurstTether!(); + case headMarkerData['heavySlamTether']: + return output.heavySlamTether!(); + } + return; + } + + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + + switch (matches.id) { + case headMarkerData['manaBurstTether']: + return output.manaBurstTetherDir!({ dir: output[dir]!() }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTetherDir!({ dir: output[dir]!() }); + } + }, + outputStrings: { + ...Directions.outputStrings8Dir, + manaBurstTether: { + en: 'Defamation Tether on YOU', + }, + manaBurstTetherDir: { + en: '${dir} Defamation Tether on YOU', + }, + heavySlamTether: { + en: 'Stack Tether on YOU', + }, + heavySlamTetherDir: { + en: '${dir} Stack Tether on YOU', + }, + }, + }, + { + id: 'R12S Replication 4 Locked Tether 2 Collect', + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: (data, matches) => { + if ( + data.phase === 'idyllic' && + data.replicationCounter === 4 && + data.me === matches.target + ) + return true; + return false; + }, + run: (data, matches) => { + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined) { + // Setting to use that we know we have a tether but couldn't determine what ability it is + data.myReplication4Tether = 'unknown'; + return; + } + + const dirNum = Directions.xyTo8DirNum( + actor.x, + actor.y, + center.x, + center.y, + ); + + // Lookup what the tether was at the same location + const ability = data.replication4TetherMap[dirNum]; + if (ability === undefined) { + // Setting to use that we know we have a tether but couldn't determine what ability it is + data.myReplication4Tether = 'unknown'; + return; + } + data.myReplication4Tether = ability; + }, + }, + { + id: 'R12S Replication 4 Locked Tether 2', + // At this point the player needs to dodge the north/south cleaves + chariot + // Simultaneously there will be a B4F2 Lindwurm's Meteor bigAoe that ends with room split + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: (data, matches) => { + if ( + data.phase === 'idyllic' && + data.twistedVisionCounter === 3 && + data.me === matches.target + ) + return true; + return false; + }, + delaySeconds: 0.1, + durationSeconds: 8, + alertText: (data, matches, output) => { + const meteorAoe = output.meteorAoe!({ + bigAoe: output.bigAoe!(), + groups: output.healerGroups!(), + }); + const cleaveOrigin = data.idyllicVision2NorthSouthCleaveSpot; + // Get direction of the tether + const actor = data.actorPositions[matches.sourceId]; + if (actor === undefined || cleaveOrigin === undefined) { + switch (data.myReplication4Tether) { + case headMarkerData['manaBurstTether']: + return output.manaBurstTether!({ meteorAoe: meteorAoe }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTether!({ meteorAoe: meteorAoe }); + } + return; + } + + const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + + const dodge = output.dodgeCleaves!({ + dir: output[cleaveOrigin]!(), + sides: output.sides!(), }); + + switch (data.myReplication4Tether) { + case headMarkerData['manaBurstTether']: + return output.manaBurstTetherDir!({ + dir: output[dir]!(), + dodgeCleaves: dodge, + meteorAoe: meteorAoe, + }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTetherDir!({ + dir: output[dir]!(), + dodgeCleaves: dodge, + meteorAoe: meteorAoe, + }); + } }, outputStrings: { - healerGroups: Outputs.healerGroups, + ...Directions.outputStrings8Dir, + north: Outputs.north, + south: Outputs.south, + sides: Outputs.sides, bigAoe: Outputs.bigAoe, - text: { - en: '${mech1} + ${mech2}', + healerGroups: Outputs.healerGroups, + meteorAoe: { + en: '${bigAoe} + ${groups}', + }, + dodgeCleaves: { + en: '${dir} + ${sides}', + }, + manaBurstTetherDir: { + en: '${dodgeCleaves} (${dir} Defamation Tether) => ${meteorAoe}', + }, + manaBurstTether: { + en: ' N/S Clone (Defamation Tether) => ${meteorAoe}', + }, + heavySlamTetherDir: { + en: '${dodgeCleaves} (${dir} Stack Tether) => ${meteorAoe}', + }, + heavySlamTether: { + en: ' N/S Clone (Stack Tether) => ${meteorAoe}', }, }, }, + { + id: 'R12S Arcadian Arcanum', + // Players hit will receive 1044 Light Resistance Down II debuff + type: 'StartsUsing', + netRegex: { id: 'B529', source: 'Lindwurm', capture: false }, + response: Responses.spread(), + }, { id: 'R12S Light Resistance Down II Collect', + // Players cannot soak a tower that has holy (triple element towers) type: 'GainsEffect', netRegex: { effectId: '1044', capture: true }, condition: Conditions.targetIsYou(), From 5794f8df3cf5fbedfadf331e264f1aa93105e5c7 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 17:43:43 -0500 Subject: [PATCH 087/100] add avoid cleave for non-rotting flesh players Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7640479d3a..a292b8ccbb 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1233,10 +1233,10 @@ const triggerSet: TriggerSet = { en: 'Spread in East Cleave', }, safeEast: { - en: 'Spread East', + en: 'Spread East + Avoid Cleave', }, safeWest: { - en: 'Spread West', + en: 'Spread West + Avoid Cleave', }, }, }, From 1370f03f456799fdef702e8a6ea67b061f6635dc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 17:48:26 -0500 Subject: [PATCH 088/100] remove unnecessary beta/unknown chains for curtain call --- ui/raidboss/data/07-dt/raid/r12s.ts | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index a292b8ccbb..42be0d6e8e 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1275,30 +1275,20 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Curtain Call: Unbreakable Flesh α/β Chains', + id: 'R12S Curtain Call: Unbreakable Flesh α Chains', + // All players, including dead, receive α debuffs // TODO: Find safe spots type: 'GainsEffect', - netRegex: { effectId: ['1291', '1293'], capture: true }, + netRegex: { effectId: '1291', capture: true }, condition: (data, matches) => { if (matches.target === data.me && data.phase === 'curtainCall') return true; return false; }, - infoText: (_data, matches, output) => { - const flesh = matches.effectId === '1291' ? 'alpha' : 'beta'; - if (flesh === 'alpha') - return output.alphaChains!({ - chains: output.breakChains!(), - safe: output.safeSpots!(), - }); - if (flesh === 'beta') - return output.betaChains!({ - chains: output.breakChains!(), - safe: output.breakChains!(), - }); - return output.unknownChains!({ + infoText: (_data, _matches, output) => { + return output.alphaChains!({ chains: output.breakChains!(), - safe: output.breakChains!(), + safe: output.safeSpots!(), }); }, outputStrings: { @@ -1309,12 +1299,6 @@ const triggerSet: TriggerSet = { alphaChains: { en: '${chains} => ${safe}', }, - betaChains: { - en: '${chains} => ${safe}', - }, - unknownChains: { - en: '${chains} => ${safe}', - }, }, }, { From 0fac8e7baf2ed76b9100899bb48d0bd887c46fce Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 17:50:59 -0500 Subject: [PATCH 089/100] increase Raptor Knuckles Right details Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 42be0d6e8e..34fb39f622 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1367,7 +1367,7 @@ const triggerSet: TriggerSet = { infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { - en: 'Northwest: Knockback to Northeast', + en: 'Knockback from Northwest => Knockback from Northeast', }, }, }, From 52fd452a5d95cca3a8758ec84e48f7ca165cfd0e Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 17:51:26 -0500 Subject: [PATCH 090/100] increase Raptor Knuckles Right output Co-authored-by: xiashtra <91220277+xiashtra@users.noreply.github.com> --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 34fb39f622..ba123166e9 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1381,7 +1381,7 @@ const triggerSet: TriggerSet = { infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { - en: 'Northeast: Knockback to Northwest', + en: 'Knockback from Northeast => Knockback from Northwest', }, }, }, From ae8a11c63ddd52970f25578722f6d78059372c95 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 18:22:43 -0500 Subject: [PATCH 091/100] add config for uptime knockback It's back and with the same timing from e8s. --- ui/raidboss/data/07-dt/raid/r12s.ts | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ba123166e9..0ace58f3f7 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -26,6 +26,9 @@ type DirectionCardinal = Exclude; type DirectionIntercard = Exclude; export interface Data extends RaidbossData { + readonly triggerSetConfig: { + uptimeKnockbackStrat: true | false; + }; phase: Phase; // Phase 1 grotesquerieCleave?: @@ -115,6 +118,28 @@ const isIntercardDir = (dir: DirectionOutput8): dir is DirectionIntercard => { const triggerSet: TriggerSet = { id: 'AacHeavyweightM4Savage', zoneId: ZoneId.AacHeavyweightM4Savage, + config: [ + { + id: 'uptimeKnockbackStrat', + name: { + en: 'Enable uptime knockback strat', + de: 'Aktiviere Uptime Rückstoß Strategie', + fr: 'Activer la strat Poussée-Uptime', + ja: 'エデン零式共鳴編4層:cactbot「ヘヴンリーストライク (ノックバック)」ギミック', // FIXME + cn: '启用击退镜 uptime 策略', + ko: '정확한 타이밍 넉백방지 공략 사용', + tc: '啟用擊退鏡 uptime 策略', + }, + comment: { + en: `If you want cactbot to callout Raptor Knuckles double knockback, enable this option. + Callout happens during/after first animation and requires <1.4s reaction time + to avoid both Northwest and Northeast knockbacks. + NOTE: This will call for each set.`, + }, + type: 'checkbox', + default: false, + }, + ], timelineFile: 'r12s.txt', initData: () => ({ phase: 'doorboss', @@ -1385,6 +1410,22 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Raptor Knuckles Uptime Knockback', + // First knockback is at 7.3s + // Second knockback is at 11.9s + // Use knockback at 5.9s to hit both with ~1.4s leniency + type: 'Ability', + netRegex: { id: ['B4CC', 'B4CD'], source: 'Lindwurm', capture: false }, + condition: (data) => { + if (data.phase === 'slaughtershed' && data.triggerSetConfig.uptimeKnockbackStrat) + return true; + return false; + }, + delaySeconds: 5.9, + durationSeconds: 1.4, + response: Responses.knockback(), + }, { id: 'R12S Refreshing Overkill', // 10s castTime that could end with enrage or raidwide From 1ef1552d270e68e76297f1e1269b8bba40ab4175 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 18:25:23 -0500 Subject: [PATCH 092/100] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 0ace58f3f7..e9b4d9b955 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -27,7 +27,7 @@ type DirectionIntercard = Exclude; export interface Data extends RaidbossData { readonly triggerSetConfig: { - uptimeKnockbackStrat: true | false; + uptimeKnockbackStrat: true | false; }; phase: Phase; // Phase 1 From d5ea00466573edf3df44666e1cdf88325d4fce4f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 21:17:37 -0500 Subject: [PATCH 093/100] update kb timing, add shapes reminder, add idyllic gush later --- ui/raidboss/data/07-dt/raid/r12s.ts | 74 +++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index e9b4d9b955..824365d56f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1412,9 +1412,9 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Raptor Knuckles Uptime Knockback', - // First knockback is at 7.3s - // Second knockback is at 11.9s - // Use knockback at 5.9s to hit both with ~1.4s leniency + // First knockback is at ~13.2s + // Second knockback is at ~18s + // Use knockback at 11.9s to hit both with ~1.4s leniency type: 'Ability', netRegex: { id: ['B4CC', 'B4CD'], source: 'Lindwurm', capture: false }, condition: (data) => { @@ -1422,7 +1422,7 @@ const triggerSet: TriggerSet = { return true; return false; }, - delaySeconds: 5.9, + delaySeconds: 11.8, durationSeconds: 1.4, response: Responses.knockback(), }, @@ -2454,6 +2454,7 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B4FD', source: 'Mana Sphere', capture: false }, delaySeconds: 0.1, + durationSeconds: 8.3, suppressSeconds: 9999, infoText: (data, _matches, output) => { const popSide = data.manaSpherePopSide; @@ -2525,6 +2526,52 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Dramatic Lysis Black Hole 1 Reminder', + // This may not happen if all shapes are failed + type: 'Ability', + netRegex: { id: ['B507'], source: 'Lindwurm', capture: false }, + suppressSeconds: 9999, + alertText: (data, _matches, output) => { + const blackHole = data.firstBlackHole; + if (blackHole === undefined) + return data.myMutation === 'alpha' ? output.alpha!() : output.beta!(); + return data.myMutation === 'alpha' + ? output.alphaDir!({ + northSouth: output.northSouth!(), + dir2: output[blackHole]!(), + }) + : output.betaDir!({ + northSouth: output.northSouth!(), + dir2: output[blackHole]!(), + }); + }, + outputStrings: { + east: Outputs.east, + west: Outputs.west, + northSouth: { + en: 'N/S', + de: 'N/S', + fr: 'N/S', + ja: '南/北', + cn: '上/下', + ko: '남/북', + tc: '上/下', + }, + alpha: { + en: 'Get by Black Hole', + }, + beta: { + en: 'Get by Black Hole', + }, + alphaDir: { + en: '${dir2} Black Hole + ${northSouth}', + }, + betaDir: { + en: '${dir2} Black Hole + ${northSouth}', + }, + }, + }, { id: 'R12S Blood Wakening Followup', // Run to the other Black Hole after abilities go off @@ -2702,6 +2749,25 @@ const triggerSet: TriggerSet = { data.idyllicVision2NorthSouthCleaveSpot = y < center.y ? 'north' : 'south'; }, }, + { + id: 'R12S Idyllic Dream Power Gusher Vision', + // Call where the E/W safe spots will be later + type: 'StartsUsing', + netRegex: { id: 'B510', source: 'Lindschrat', capture: true }, + infoText: (_data, matches, output) => { + const y = parseFloat(matches.y); + const dir = y < center.y ? 'north' : 'south'; + return output.text!({ dir: output[dir]!(), sides: output.sides!() }); + }, + outputStrings: { + north: Outputs.north, + south: Outputs.south, + sides: Outputs.sides, + text: { + en: '${dir} + ${sides} (later)', + }, + }, + }, { id: 'R12S Replication 4 Ability Tethers Initial Call', type: 'Tether', From e64f9f853c63a2748d98b0094c380fd181dcd1fb Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 21:21:55 -0500 Subject: [PATCH 094/100] comment --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 824365d56f..7eebb5f1f4 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1414,7 +1414,7 @@ const triggerSet: TriggerSet = { id: 'R12S Raptor Knuckles Uptime Knockback', // First knockback is at ~13.2s // Second knockback is at ~18s - // Use knockback at 11.9s to hit both with ~1.4s leniency + // Use knockback at ~11.8s to hit both with ~1.4s leniency type: 'Ability', netRegex: { id: ['B4CC', 'B4CD'], source: 'Lindwurm', capture: false }, condition: (data) => { From fa0a141d818c60e9294997b5049360eedb7c0964 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 21:55:49 -0500 Subject: [PATCH 095/100] fix wrong id used --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7eebb5f1f4..529e45df82 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1416,7 +1416,7 @@ const triggerSet: TriggerSet = { // Second knockback is at ~18s // Use knockback at ~11.8s to hit both with ~1.4s leniency type: 'Ability', - netRegex: { id: ['B4CC', 'B4CD'], source: 'Lindwurm', capture: false }, + netRegex: { id: ['B4CC', 'B4CE'], source: 'Lindwurm', capture: false }, condition: (data) => { if (data.phase === 'slaughtershed' && data.triggerSetConfig.uptimeKnockbackStrat) return true; From 8ca40621af82112d5697100ec7c16d86e1354b91 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 23:16:35 -0500 Subject: [PATCH 096/100] fix for -dirNum in sobat call --- ui/raidboss/data/07-dt/raid/r12s.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 529e45df82..cefb7ebc34 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1698,8 +1698,14 @@ const triggerSet: TriggerSet = { throw new UnreachableCode(); }; - const newDirNum = (getNewDirNum(dirNum, matches.id) + 8) % 16; - const dir = Directions.output16Dir[newDirNum] ?? 'unknown'; + const newDirNum = getNewDirNum(dirNum, matches.id); + + // Handle case where we have negative value + const positiveDirNum = ( + newDirNum + 8 < 0 ? Math.abs(newDirNum) : newDirNum + 8 + ) % 16; + + const dir = Directions.output16Dir[positiveDirNum] ?? 'unknown'; return output.getBehindDir!({ dir: output[dir]!(), mech: output.getBehind!(), From 5a75ca5ed4477b728debb4a6cd9a30694370c30c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 23:43:01 -0500 Subject: [PATCH 097/100] adjust timing compared to some more logs --- ui/raidboss/data/07-dt/raid/r12s.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index cefb7ebc34..097b5e27ef 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -132,7 +132,7 @@ const triggerSet: TriggerSet = { }, comment: { en: `If you want cactbot to callout Raptor Knuckles double knockback, enable this option. - Callout happens during/after first animation and requires <1.4s reaction time + Callout happens during/after first animation and requires <1.8s reaction time to avoid both Northwest and Northeast knockbacks. NOTE: This will call for each set.`, }, @@ -1412,9 +1412,11 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Raptor Knuckles Uptime Knockback', - // First knockback is at ~13.2s - // Second knockback is at ~18s - // Use knockback at ~11.8s to hit both with ~1.4s leniency + // First knockback is at ~13.374s + // Second knockback is at ~17.964s + // Use knockback at ~11.5s to hit both with ~1.8s leniency + // ~11.457s before is too late as it comes off the same time as hit + // ~11.554s before works (~0.134 before hit) type: 'Ability', netRegex: { id: ['B4CC', 'B4CE'], source: 'Lindwurm', capture: false }, condition: (data) => { @@ -1422,8 +1424,8 @@ const triggerSet: TriggerSet = { return true; return false; }, - delaySeconds: 11.8, - durationSeconds: 1.4, + delaySeconds: 11.5, + durationSeconds: 1.8, response: Responses.knockback(), }, { From 283fb08a60c274ec52d2aa8a3698ae7467dd8533 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 26 Jan 2026 23:45:06 -0500 Subject: [PATCH 098/100] clarify timing --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 097b5e27ef..a4ddcdd5cb 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1416,7 +1416,7 @@ const triggerSet: TriggerSet = { // Second knockback is at ~17.964s // Use knockback at ~11.5s to hit both with ~1.8s leniency // ~11.457s before is too late as it comes off the same time as hit - // ~11.554s before works (~0.134 before hit) + // ~11.554s before works (surecast ends ~0.134 after hit) type: 'Ability', netRegex: { id: ['B4CC', 'B4CE'], source: 'Lindwurm', capture: false }, condition: (data) => { From 69ad3bde6a2c7d12ab5d5b8d91b3aba501438f52 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 27 Jan 2026 00:00:18 -0500 Subject: [PATCH 099/100] cleanup negative value handling this actually is the same issue report in p8s which should be fixed --- ui/raidboss/data/07-dt/raid/r12s.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index a4ddcdd5cb..bf86940d48 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1702,12 +1702,10 @@ const triggerSet: TriggerSet = { const newDirNum = getNewDirNum(dirNum, matches.id); - // Handle case where we have negative value - const positiveDirNum = ( - newDirNum + 8 < 0 ? Math.abs(newDirNum) : newDirNum + 8 - ) % 16; + // Adding 16 incase of negative values + const newDirNum = (getNewDirNum(dirNum, matches.id) + 16 + 8) % 16; - const dir = Directions.output16Dir[positiveDirNum] ?? 'unknown'; + const dir = Directions.output16Dir[newDirNum] ?? 'unknown'; return output.getBehindDir!({ dir: output[dir]!(), mech: output.getBehind!(), From cb4066021461d1df753a69891f41ce89ef4af66f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 27 Jan 2026 00:07:33 -0500 Subject: [PATCH 100/100] fix paste error --- ui/raidboss/data/07-dt/raid/r12s.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index bf86940d48..e35b0e3cae 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1700,8 +1700,6 @@ const triggerSet: TriggerSet = { throw new UnreachableCode(); }; - const newDirNum = getNewDirNum(dirNum, matches.id); - // Adding 16 incase of negative values const newDirNum = (getNewDirNum(dirNum, matches.id) + 16 + 8) % 16;