From 7b2cb9a14315fcd4e60f1d6f9f450c4402f608bc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 19 Jan 2026 08:14:23 -0500 Subject: [PATCH 001/215] 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 00000000000..beec50f1111 --- /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/215] 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 beec50f1111..aae6d5e609f 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/215] 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 aae6d5e609f..961273b7470 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/215] 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 b3f0f22ee0f..e3186605a4e 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/215] 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 961273b7470..9394d7cf0ae 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/215] 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 e3186605a4e..faa2d1a78b5 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/215] 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 faa2d1a78b5..9b6e5004459 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/215] 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 9394d7cf0ae..2f6cca8cdc1 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/215] 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 2f6cca8cdc1..a8781ec4558 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/215] 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 a8781ec4558..c7455fea270 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/215] 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 c7455fea270..81947c8f612 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/215] 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 81947c8f612..eebcd89f8b5 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/215] 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 eebcd89f8b5..fa962293254 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/215] 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 fa962293254..60ef978f95d 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/215] 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 60ef978f95d..4417cd6f9db 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/215] 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 4417cd6f9db..8730fd692cd 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/215] 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 8730fd692cd..df32bdf2c24 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/215] 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 df32bdf2c24..74bd2ae5451 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/215] 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 74bd2ae5451..ce6a537fb2e 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/215] 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 ce6a537fb2e..4a309114f49 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/215] 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 4a309114f49..ed9c8f09d53 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/215] 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 ed9c8f09d53..d391bcbab8f 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/215] 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 d391bcbab8f..cbf143dfae6 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/215] 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 cbf143dfae6..de61e2d7131 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/215] 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 de61e2d7131..703ab6cf7ef 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/215] 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 703ab6cf7ef..892679eb113 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/215] 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 9b6e5004459..5fb6dbf9048 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/215] 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 892679eb113..873a9b1e3b6 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/215] 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 873a9b1e3b6..58d50662189 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/215] 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 5fb6dbf9048..e72d73a4dea 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/215] 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 e72d73a4dea..9d3b6c1d365 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/215] 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 9d3b6c1d365..c4398934024 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/215] 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 c4398934024..63f5500fdaf 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/215] 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 63f5500fdaf..ab06c685674 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/215] 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 ab06c685674..7fd55ed4525 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/215] 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 7fd55ed4525..6e478755838 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/215] 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 6e478755838..cd28893ef0e 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/215] 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 cd28893ef0e..c55defecf21 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/215] 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 c55defecf21..64c19ed1eb4 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/215] 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 64c19ed1eb4..6f654e7dff3 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/215] 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 6f654e7dff3..68384da3b72 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/215] 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 68384da3b72..577e5626178 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/215] 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 577e5626178..2ad45431375 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/215] 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 58d50662189..e94b790470b 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/215] 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 e94b790470b..9c7cebc908e 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/215] 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 9c7cebc908e..dc329d58116 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/215] 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 2ad45431375..2ee7c5ea3fb 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/215] 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 2ee7c5ea3fb..0d58311133e 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/215] 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 dc329d58116..b6a8af4fe49 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/215] 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 b6a8af4fe49..482b066639a 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/215] 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 482b066639a..65a71219c8c 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/215] 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 65a71219c8c..5f5da5f84e6 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/215] 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 5f5da5f84e6..614444eb2d8 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/215] 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 0d58311133e..ae9bd9eae76 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/215] 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 614444eb2d8..5b4121726b6 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/215] 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 5b4121726b6..d157e3fc744 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/215] 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 d157e3fc744..61b3ba3ae55 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/215] 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 61b3ba3ae55..a4d9c3cd73e 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/215] 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 a4d9c3cd73e..18c3d11b1ec 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/215] 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 18c3d11b1ec..ce39f0cd7fc 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/215] 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 ce39f0cd7fc..cf51bb7e1a5 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/215] 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 cf51bb7e1a5..94a0a57c650 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/215] 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 94a0a57c650..2f8cb683661 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/215] 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 2f8cb683661..e50d39cd847 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/215] 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 e50d39cd847..cd1da7f3e5b 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/215] 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 cd1da7f3e5b..7404fa5cca0 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/215] 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 7404fa5cca0..ed4c2f36569 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/215] 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 ed4c2f36569..0b7429614f9 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/215] 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 0b7429614f9..d99840dcacc 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/215] 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 d99840dcacc..cc0f504bca4 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/215] 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 cc0f504bca4..64057e0e888 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/215] 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 64057e0e888..9f47660de2a 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/215] 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 9f47660de2a..75fb766ab72 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/215] 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 ae9bd9eae76..581b760d922 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/215] 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 75fb766ab72..04ee5362c32 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/215] 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 04ee5362c32..1dc0db5bd35 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/215] 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 581b760d922..fa2c8f03f78 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/215] 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 1dc0db5bd35..025dd857e58 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/215] 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 025dd857e58..2eb0b8ca383 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/215] 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 2eb0b8ca383..6721da8ca54 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/215] 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 6721da8ca54..9b06f6c2359 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/215] 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 9b06f6c2359..b9ede17a702 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/215] 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 b9ede17a702..481242662c6 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/215] 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 481242662c6..64cf884c0ba 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/215] 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 64cf884c0ba..7d2af0f1ec1 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/215] 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 7d2af0f1ec1..7640479d3a9 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/215] 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 7640479d3a9..a292b8ccbb3 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/215] 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 a292b8ccbb3..42be0d6e8ef 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/215] 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 42be0d6e8ef..34fb39f6228 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/215] 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 34fb39f6228..ba123166e9b 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/215] 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 ba123166e9b..0ace58f3f70 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/215] 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 0ace58f3f70..e9b4d9b955e 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/215] 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 e9b4d9b955e..824365d56f5 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/215] 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 824365d56f5..7eebb5f1f4e 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/215] 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 7eebb5f1f4e..529e45df823 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/215] 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 529e45df823..cefb7ebc342 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/215] 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 cefb7ebc342..097b5e27ef8 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/215] 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 097b5e27ef8..a4ddcdd5cb4 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/215] 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 a4ddcdd5cb4..bf86940d480 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/215] 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 bf86940d480..e35b0e3caef 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; From 105ccea245db02bcf99c0a02e2015010081efdb8 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 02:21:22 -0500 Subject: [PATCH 101/215] replication 4 first set This could work with any strategy... may go back to rep2 later to better track the clone pair + ability pair + player order. It's essentially the same code needed. Sorry for the massive amount of conditionals, the way it seems right now is complex and this was the simplest I came up with. --- ui/raidboss/data/07-dt/raid/r12s.ts | 259 ++++++++++++++++++++++++++-- 1 file changed, 246 insertions(+), 13 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index e35b0e3caef..dca7fc1e889 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -65,8 +65,12 @@ export interface Data extends RaidbossData { manaSpherePopSide?: 'east' | 'west'; twistedVisionCounter: number; replication3CloneOrder: number[]; + replication3CloneDirNumPlayers: { [dirNum: number]: string }; idyllicVision2NorthSouthCleaveSpot?: 'north' | 'south'; - replication4TetherMap: { [dirNum: string]: string }; + replication4DirNumAbility: { [dirNum: number]: string }; + replication4PlayerAbilities: { [player: string]: string }; + replication4PlayerOrder: string[]; + replication4AbilityOrder: string[]; myReplication4Tether?: string; hasLightResistanceDown: boolean; doomPlayers: string[]; @@ -162,7 +166,11 @@ const triggerSet: TriggerSet = { closeManaSphereIds: [], twistedVisionCounter: 0, replication3CloneOrder: [], - replication4TetherMap: {}, + replication3CloneDirNumPlayers: {}, + replication4DirNumAbility: {}, + replication4PlayerAbilities: {}, + replication4PlayerOrder: [], + replication4AbilityOrder: [], hasLightResistanceDown: false, doomPlayers: [], }), @@ -2706,7 +2714,29 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Idyllic Dream Replication Tethered Clone', + id: 'R12S Idyllic Dream Staging 2 Tethered Clone Collect', + // Map the locations to a player name + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: (data) => { + if ( + data.phase === 'idyllic' && + data.replicationCounter === 2 + ) + 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.replication3CloneDirNumPlayers[dirNum] = matches.target; + }, + }, + { + id: 'R12S Idyllic Dream Staging 2 Tethered Clone', type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: true }, condition: (data, matches) => { @@ -2831,20 +2861,21 @@ const triggerSet: TriggerSet = { id: 'R12S Replication 4 Locked Tether 2 Collect', type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: true }, - condition: (data, matches) => { + condition: (data) => { if ( data.phase === 'idyllic' && - data.replicationCounter === 4 && - data.me === matches.target + data.replicationCounter === 4 ) return true; return false; }, run: (data, matches) => { const actor = data.actorPositions[matches.sourceId]; + const target = matches.target; if (actor === undefined) { // Setting to use that we know we have a tether but couldn't determine what ability it is - data.myReplication4Tether = 'unknown'; + if (data.me === target) + data.replication4PlayerAbilities[target] = 'unknown'; return; } @@ -2856,13 +2887,33 @@ const triggerSet: TriggerSet = { ); // Lookup what the tether was at the same location - const ability = data.replication4TetherMap[dirNum]; + const ability = data.replication4DirNumAbility[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'; + data.replication4PlayerAbilities[target] = 'unknown'; return; } - data.myReplication4Tether = ability; + data.replication4PlayerAbilities[target] = ability; + + // Create ability order once we have all 8 players + // If players had more than one tether previously, the extra tethers are randomly assigned + if (Object.keys(data.replication4PlayerAbilities).length === 8) { + const abilities = data.replication4PlayerAbilities; + const order = data.replication3CloneOrder; // Order in which clones spawned + const players = data.replication3CloneDirNumPlayers; // Direction of player's clone + + // Mechanics are resolved clockwise, get create order based on cards/inters + const first = order[0]; + if (first === undefined) + return; + const dirNumOrder = first % 2 === 0 ? [0, 2, 4, 6, 1, 3, 5, 7] : [1, 3, 5, 7, 0, 2, 4, 6]; + for (const dirNum of dirNumOrder) { + const player = players[dirNum] ?? 'unknown'; + const ability = abilities[player] ?? 'unknown'; + data.replication4PlayerOrder.push(player); + data.replication4AbilityOrder.push(ability); + } + } }, }, { @@ -2888,10 +2939,11 @@ const triggerSet: TriggerSet = { groups: output.healerGroups!(), }); const cleaveOrigin = data.idyllicVision2NorthSouthCleaveSpot; + const myAbility = data.replication4PlayerAbilities[data.me]; // Get direction of the tether const actor = data.actorPositions[matches.sourceId]; if (actor === undefined || cleaveOrigin === undefined) { - switch (data.myReplication4Tether) { + switch (myAbility) { case headMarkerData['manaBurstTether']: return output.manaBurstTether!({ meteorAoe: meteorAoe }); case headMarkerData['heavySlamTether']: @@ -2908,7 +2960,7 @@ const triggerSet: TriggerSet = { sides: output.sides!(), }); - switch (data.myReplication4Tether) { + switch (myAbility) { case headMarkerData['manaBurstTether']: return output.manaBurstTetherDir!({ dir: output[dir]!(), @@ -2989,10 +3041,191 @@ const triggerSet: TriggerSet = { }, outputStrings: { text: { - en: 'Soak a White/Star Meteor', + en: 'Soak a White/Star Meteor (later)', }, }, }, + { + id: 'R12S Twisted Vision 4 Stack/Defamation 1', + // Used for keeping track of phases in idyllic + type: 'StartsUsing', + netRegex: { id: 'BBE2', source: 'Lindwurm', capture: false }, + condition: (data) => data.twistedVisionCounter === 4, + response: (data, _matches, output) => { + // cactbot-builtin-response + output.responseOutputStrings = { + ...Directions.outputStrings8Dir, + stacks: Outputs.stacks, + avoidDefamation: { + en: 'Avoid Defamation', + }, + avoidStack: { + en: 'Avoid Stack', + de: 'Vermeide Sammeln', + fr: 'Évitez le package', + cn: '远离分摊', + ko: '쉐어징 피하기', + tc: '遠離分攤', + }, + defamationOnYou: Outputs.defamationOnYou, + stackOnYou: Outputs.stackOnYou, + stackOnPlayer: Outputs.stackOnPlayer, + defamations: { + en: 'Defamations', + de: 'Große AoE auf dir', + fr: 'Grosse AoE sur vous', + ja: '自分に巨大な爆発', + cn: '大圈点名', + ko: '광역 대상자', + tc: '大圈點名', + }, + oneMechThenOne: { + en: '${mech1} => ${mech2}' + }, + oneMechThenTwo: { + en: '${mech1} => ${mech2} + ${mech3}', + }, + twoMechsThenOne: { + en: '${mech1} + ${mech2} => ${mech3}', + }, + twoMechsThenTwo: { + en: '${mech1} + ${mech2} => ${mech3} + ${mech4}', + }, + }; + const abilityOrder = data.replication4AbilityOrder; + const playerOrder = data.replication4PlayerOrder; + if ( + abilityOrder === undefined || + playerOrder === undefined + ) + return; + + const ability1 = abilityOrder[0]; + const ability2 = abilityOrder[1]; + const player1 = playerOrder[0]; + const player2 = playerOrder[1]; + + // Get Stack/Defamation #2 details + const ability3 = abilityOrder[2]; + const ability4 = abilityOrder[3]; + const player3 = playerOrder[2]; + const player4 = playerOrder[3]; + + // Handle some obscure strategies or mistakes + const isThisSame = ability1 === ability2; + const isNextSame = ability3 === ability4; + const defamation = headMarkerData['manaBurstTether']; + let this1; + let this2; + let next1; + let next2; + // Handle This Set + if (player1 === data.me) { + this1 = ability1 === defamation ? 'defamationOnYou' : 'stackOnYou'; + if (!isThisSame) + this2 = ability2 === defamation ? 'avoidDefamation' : 'avoidStack'; + } else if (player2 === data.me) { + if (!isThisSame) { + this1 = ability1 === defamation ? 'avoidDefamation' : 'avoidStack'; + this2 = ability2 === defamation ? 'defamationOnYou' : 'stackOnYou'; + } else { + this1 = ability1 === defamation ? 'defamationOnYou' : 'stackOnYou'; + } + } else if (isThisSame) { + this1 = ability1 === defamation ? 'defamations' : 'stacks'; + } else if (!isThisSame) { + this1 = ability1 === defamation ? 'avoidDefamation' : 'stack'; + this2 = ability2 === defamation ? 'avoidDefamation' : 'stack'; + } + + // Handle Next Set + if (player3 === data.me) { + next1 = ability3 === defamation ? 'defamationOnYou' : 'stackOnYou'; + if (!isThisSame) + next2 = ability4 === defamation ? 'avoidDefamation' : 'avoidStack'; + } else if (player4 === data.me) { + if (!isThisSame) { + next1 = ability4 === defamation ? 'avoidDefamation' : 'avoidStack'; + next2 = ability4 === defamation ? 'defamationOnYou' : 'stackOnYou'; + } else { + next1 = ability4 === defamation ? 'defamationOnYou' : 'stackOnYou'; + } + } else if (isNextSame) { + next1 = ability3 === defamation ? 'defamations' : 'stacks'; + } else if (!isNextSame) { + next1 = ability3 === defamation ? 'avoidDefamation' : 'stack'; + next2 = ability4 === defamation ? 'avoidDefamation' : 'stack'; + } + + // Build output + if (this1 === undefined || next1 === undefined) + return; + const text = (player1 === data.me || player2 === data.me) ? 'alertText' : 'infoText'; + if (isThisSame && isNextSame) { + return { + [text]: output.oneMechThenOne!({ + mech1: output[this1]!(), + mech2: output[next1]!(), + }), + }; + } + + const shortPlayer3 = data.party.member(player3); + const shortPlayer4 = data.party.member(player4); + if (isThisSame && !isNextSame) { + if (next2 === undefined) + return; + return { + [text]: output.oneMechThenTwo!({ + mech1: output[this1]!(), + mech2: next1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer3 }) + : output[next1]!(), + mech3: next2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer4 }) + : output[next2]!(), + }) + }; + } + + const shortPlayer1 = data.party.member(player1); + const shortPlayer2 = data.party.member(player2); + if (!isThisSame && isNextSame) { + if (this2 === undefined) + return; + return { + [text]: output.twoMechsThenOne!({ + mech1: this1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer1 }) + : output[this1]!(), + mech2: this2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer2 }) + : output[this2]!(), + mech3: output[next1]!(), + }) + }; + } + + if (this2 === undefined || next2 === undefined) + return; + return { + [text]: output.twoMechsThenTwo!({ + mech1: this1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer1 }) + : output[this1]!(), + mech2: this2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer2 }) + : output[this2]!(), + mech3: next1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer3 }) + : output[next1]!(), + mech4: next2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer4 }) + : output[next2]!(), + }) + }; + }, + }, { id: 'R12S Doom Collect', type: 'GainsEffect', From 3f10baf000c4c99f61959f56d81c841a03b4924e Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 02:23:14 -0500 Subject: [PATCH 102/215] missed a line --- 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 dca7fc1e889..a84ae7af433 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1799,7 +1799,7 @@ const triggerSet: TriggerSet = { if (data.phase === 'replication2') data.replication2TetherMap[dirNum] = matches.id; if (data.phase === 'idyllic') - data.replication4TetherMap[dirNum] = matches.id; + data.replication4DirNumAbility[dirNum] = matches.id; }, }, { From 9203a9e4c944556da4b9cbbadbf881654a70b0d2 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 02:27:53 -0500 Subject: [PATCH 103/215] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index a84ae7af433..2f2e05ed050 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3025,7 +3025,7 @@ const triggerSet: TriggerSet = { infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { - en: 'Soak Fire/Earth Meteor', + en: 'Soak Fire/Earth Meteor (later)', }, }, }, @@ -3080,7 +3080,7 @@ const triggerSet: TriggerSet = { tc: '大圈點名', }, oneMechThenOne: { - en: '${mech1} => ${mech2}' + en: '${mech1} => ${mech2}', }, oneMechThenTwo: { en: '${mech1} => ${mech2} + ${mech3}', @@ -3184,7 +3184,7 @@ const triggerSet: TriggerSet = { mech3: next2 === 'stack' ? output.stackOnPlayer!({ player: shortPlayer4 }) : output[next2]!(), - }) + }), }; } @@ -3202,7 +3202,7 @@ const triggerSet: TriggerSet = { ? output.stackOnPlayer!({ player: shortPlayer2 }) : output[this2]!(), mech3: output[next1]!(), - }) + }), }; } @@ -3211,18 +3211,18 @@ const triggerSet: TriggerSet = { return { [text]: output.twoMechsThenTwo!({ mech1: this1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer1 }) - : output[this1]!(), + ? output.stackOnPlayer!({ player: shortPlayer1 }) + : output[this1]!(), mech2: this2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer2 }) - : output[this2]!(), + ? output.stackOnPlayer!({ player: shortPlayer2 }) + : output[this2]!(), mech3: next1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer3 }) - : output[next1]!(), + ? output.stackOnPlayer!({ player: shortPlayer3 }) + : output[next1]!(), mech4: next2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer4 }) - : output[next2]!(), - }) + ? output.stackOnPlayer!({ player: shortPlayer4 }) + : output[next2]!(), + }), }; }, }, From 581d18cc1cd5bc2b2b762c282f0abe0ee3facc5b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 21:12:18 -0500 Subject: [PATCH 104/215] some cleanup to p2, add tethers/clones lines --- ui/raidboss/data/07-dt/raid/r12s.txt | 116 +++++++++++++++++---------- 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index fa2c8f03f78..a6010b3aa0b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -285,6 +285,7 @@ hideall "--sync--" 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 @@ -327,12 +328,12 @@ hideall "--sync--" # Enrage sequence 2027.7 label "r12s-p1-enrage" -2036.7 "Refreshing Overkill (Enrage)?" Ability { id: "B538", source: "Lindwurm" } +2036.7 "Refreshing Overkill (Enrage)?" Ability { id: "B538", source: "Lindwurm" } window 510,5 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" } window 510,5 +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" } @@ -340,8 +341,8 @@ hideall "--sync--" ### Phase 2: Lindwurm II -# -p B528:3012.1 -# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 B4FF BCB0 +# -p B528:3015.7 +# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 B4F5 B512 B513 B514 B515 # -it "Lindwurm" 3000.5 label "r12s-p2-start" 3010.7 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 @@ -365,8 +366,16 @@ hideall "--sync--" # NOTE: Depending on clone order and tethers player takes, spells at each instance will differ # TBD: Generalize these? 3091.2 "Staging" Ability { id: "B4E1", source: "Lindwurm" } +3092.5 "--clones x2 1--" ActorControlExtra { category: "0197", param1: "11D2" } +3094.0 "--clones x2 2--" ActorControlExtra { category: "0197", param1: "11D2" } +3095.5 "--clones x2 3--" ActorControlExtra { category: "0197", param1: "11D2" } +3097.0 "--clones x2 4--" ActorControlExtra { category: "0197", param1: "11D2" } +3099.1 "--locked tethers--" Tether { id: "0175", source: "Understudy" } 3102.2 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } 3105.4 "Replication 2" Ability { id: "B4D8", source: "Lindwurm" } +3108.6 "--boss clones x6--" ActorControlExtra { category: "0197", param1: "11D5" } +3113.8 "--tethers--" #Tether { id: ["016F", "0170", "0171", "0176"] } # These could change hands causing sync issue +3121.8 "--locked tethers--" Tether { id: "0175", source: ["Lindschrat", "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" } @@ -396,11 +405,15 @@ hideall "--sync--" 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 +3200.7 "Bloody Burst x2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player 3202.2 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } +3203.2 "--close shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3203.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 +3204.2 "--far shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3206.0 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 2 +3207.2 "--soaked shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3209.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # blackhole 1 -# TBD Clean-up/Generalize this part as its dependent on what was soaked and what spawned 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" } @@ -419,63 +432,73 @@ hideall "--sync--" # 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" } +3276.3 "--clones x4 1--" ActorControlExtra { category: "0197", param1: "11D2" } +3278.3 "--clones x4 2--" ActorControlExtra { category: "0197", param1: "11D2" } +3280.4 "--locked tethers--" Tether { id: "0175", source: "Understudy" } 3283.4 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } -3290.1 "Twisted Vision" Ability { id: "BBE2", source: "Lindwurm" } +3290.1 "Twisted Vision 1" 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" } +3299.4 "--boss clones x3--" ActorControlExtra { category: "0197", param1: "11D5" } +3308.6 "Twisted Vision 2" Ability { id: "BBE2", source: "Lindwurm" } +3309.6 "Power Gusher x2" #Ability { id: ["B50F", "B510"], 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" } +3317.9 "--boss clones x2 1--" ActorControlExtra { category: "0197", param1: "11D5" } +3318.9 "--boss clones x2 2--" ActorControlExtra { category: "0197", param1: "11D5" } +3319.9 "--boss clones x2 3--" ActorControlExtra { category: "0197", param1: "11D5" } +3320.9 "--boss clones x2 4--" ActorControlExtra { category: "0197", param1: "11D5" } +3326.1 "--tethers--" #Tether { id: ["0170", "0171"], source: "Lindschrat" } # These could change hands causing sync issue +3334.1 "--locked tethers--" Tether { id: ["0170", "0171"], source: "Lindschrat" } # 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" } +3334.3 "Twisted Vision 3" Ability { id: "BBE2", source: "Lindwurm" } 3338.7 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } -3338.9 "Power Gusher" #Ability { id: "B516", source: "Lindwurm" } +3338.9 "Power Gusher x4" #Ability { id: "B516", source: "Lindwurm" } # Front/Back are apparently counting as their own casts 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" } +3355.0 "Arcadian Arcanum (castbar)" 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" } +# Orders could be different, but we can detect B517 abiltiy to know if Mana Burst is coming 1.2s before B518 +3363.0 "Twisted Vision 4" Ability { id: "BBE2", source: "Lindwurm" } +3369.6 "Clone 1 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3370.8 "Clone 1 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3374.6 "Clone 2 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3375.8 "Clone 2 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3379.6 "Clone 3 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3380.8 "Clone 3 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3384.6 "Clone 4 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3385.8 "Clone 4 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } + +# Twisted Vision 5: Towers +3393.6 "Twisted Vision 5" Ability { id: "BBE2", source: "Lindwurm" } +3398.0 "Cosmic Kiss" Ability { id: "B4F4", source: "Lindwurm" } + +# fflogs adjusted by 4.1s +3398.7 "Lindwurm's Dark II" Ability { id: "B4F6", source: "Lindwurm" } +3400.7 "Pyretic Wurm" Ability { id: "B4F9", source: "Lindwurm" } +3403.7 "Lindwurm's Stone III" #Ability { id: "B4F7", source: "Lindwurm" } +3408.7 "Lindwurm's Thunder II" #Ability { id: "B4FA", source: "Lindwurm" } +3408.7 "Lindwurm's Glare" #Ability { id: "B4F8", source: "Lindwurm" } +3408.7 "Lindwurm's Thunder II" #Ability { id: "B4FA", source: "Lindwurm" } +3408.7 "Lindwurm's Glare" #Ability { id: "B4F8", source: "Lindwurm" } +3412.0 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } window 10,10 # 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" } +3425.4 "Twisted Vision 6" 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" } +3440.5 "Twisted Vision 7" Ability { id: "BBE2", source: "Lindwurm" } 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" } +3448.2 "Twisted Vision 8" 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" } @@ -533,8 +556,13 @@ 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? +# B4FF --sync--: VFX Mana Spheres eaten by Black Hole +# BCB0 --sync--: VFX Black Hole light eruption +# B4F5 Unmitigated Explosion: Missing Cosmic Kiss Tower (Twisted Vision 5) +# B512 Power Gusher: VFX during Twisted Vision 2 with B50F and B510 +# B513 Power Gusher: VFX during Twisted Vision 3, related to the B50F +# B514 Power Gusher: VFX during Twisted Vision 3, related to the B510 +# B515 Snaking Kick: VFX during Twisted Vision 3 # ALL ENCOUNTER ABILITIES # Phase 1 @@ -599,6 +627,7 @@ hideall "--sync--" # B4D5 Fourth-wall Fusion # B4D6 Visceral Burst # B4D7 The Fixer +# B4F5 Unmitigated Explosion # B538 Refreshing Overkill: Enrage castbar # B539 Refreshing Overkill: Non-enrage # B53A Refreshing Overkill: Enrage @@ -684,7 +713,7 @@ hideall "--sync--" # B514 Power Gusher # B515 Snaking Kick # B516 Power Gusher -# B517 Mana Burst +# B517 Mana Burst: VFX during Twisted Vision 4, happens 1.2s before B518, useful for sync branch # B518 Mana Burst # B519 Heavy Slam # B51A Power Gusher @@ -718,6 +747,7 @@ hideall "--sync--" # BBE2 Twisted Vision # BBE3 Mana Burst # BCAF Snaking Kick +# BCB0 --sync--: Blackhole spawn # BE5D Heavy Slam # BE95 Snaking Kick # BEC1 Arcadian Hell From 20d259f6ae51fe0415e6de2c7cec17199b1d282b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 21:22:58 -0500 Subject: [PATCH 105/215] fixes from test_timeline Apparently the ActorControlExtra matches just backsync with the ~1.5s matches, so commented them out. --- ui/raidboss/data/07-dt/raid/r12s.txt | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index a6010b3aa0b..5079b3eb9f8 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -366,10 +366,10 @@ hideall "--sync--" # NOTE: Depending on clone order and tethers player takes, spells at each instance will differ # TBD: Generalize these? 3091.2 "Staging" Ability { id: "B4E1", source: "Lindwurm" } -3092.5 "--clones x2 1--" ActorControlExtra { category: "0197", param1: "11D2" } -3094.0 "--clones x2 2--" ActorControlExtra { category: "0197", param1: "11D2" } -3095.5 "--clones x2 3--" ActorControlExtra { category: "0197", param1: "11D2" } -3097.0 "--clones x2 4--" ActorControlExtra { category: "0197", param1: "11D2" } +3092.5 "--clones x2 1--" #ActorControlExtra { category: "0197", param1: "11D2" } +3094.0 "--clones x2 2--" #ActorControlExtra { category: "0197", param1: "11D2" } +3095.5 "--clones x2 3--" #ActorControlExtra { category: "0197", param1: "11D2" } +3097.0 "--clones x2 4--" #ActorControlExtra { category: "0197", param1: "11D2" } 3099.1 "--locked tethers--" Tether { id: "0175", source: "Understudy" } 3102.2 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } 3105.4 "Replication 2" Ability { id: "B4D8", source: "Lindwurm" } @@ -408,11 +408,11 @@ hideall "--sync--" 3200.7 "Bloody Burst x2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player 3202.2 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } 3203.2 "--close shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3203.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 -3204.2 "--far shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3206.0 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 2 -3207.2 "--soaked shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3209.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # blackhole 1 +3204.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 +3206.2 "--far shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3207.0 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 2 +3209.2 "--soaked shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3210.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # blackhole 1 3216.7 "Blood Wakening" Ability { id: "B500", source: "Lindwurm" } 3217.9 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } @@ -432,8 +432,8 @@ hideall "--sync--" # 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" } -3276.3 "--clones x4 1--" ActorControlExtra { category: "0197", param1: "11D2" } -3278.3 "--clones x4 2--" ActorControlExtra { category: "0197", param1: "11D2" } +3276.3 "--clones x4 1--" #ActorControlExtra { category: "0197", param1: "11D2" } +3278.3 "--clones x4 2--" #ActorControlExtra { category: "0197", param1: "11D2" } 3280.4 "--locked tethers--" Tether { id: "0175", source: "Understudy" } 3283.4 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } 3290.1 "Twisted Vision 1" Ability { id: "BBE2", source: "Lindwurm" } @@ -443,12 +443,12 @@ hideall "--sync--" 3309.6 "Power Gusher x2" #Ability { id: ["B50F", "B510"], source: "Lindschrat" } 3309.6 "Snaking Kick" #Ability { id: "B511", source: "Lindschrat" } 3314.7 "Replication 4" Ability { id: "B4D8", source: "Lindwurm" } -3317.9 "--boss clones x2 1--" ActorControlExtra { category: "0197", param1: "11D5" } -3318.9 "--boss clones x2 2--" ActorControlExtra { category: "0197", param1: "11D5" } -3319.9 "--boss clones x2 3--" ActorControlExtra { category: "0197", param1: "11D5" } -3320.9 "--boss clones x2 4--" ActorControlExtra { category: "0197", param1: "11D5" } +3317.9 "--boss clones x2 1--" #ActorControlExtra { category: "0197", param1: "11D5" } +3318.9 "--boss clones x2 2--" #ActorControlExtra { category: "0197", param1: "11D5" } +3319.9 "--boss clones x2 3--" #ActorControlExtra { category: "0197", param1: "11D5" } +3320.9 "--boss clones x2 4--" #ActorControlExtra { category: "0197", param1: "11D5" } 3326.1 "--tethers--" #Tether { id: ["0170", "0171"], source: "Lindschrat" } # These could change hands causing sync issue -3334.1 "--locked tethers--" Tether { id: ["0170", "0171"], source: "Lindschrat" } +3334.1 "--locked tethers--" Tether { id: "0175", source: "Lindschrat" } # Towers Preview 3334.3 "Twisted Vision 3" Ability { id: "BBE2", source: "Lindwurm" } From 7acc873fb02674e0380d2447117ee452e83f9729 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 21:26:42 -0500 Subject: [PATCH 106/215] remove double space --- 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 5079b3eb9f8..c52d6bf5117 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -483,7 +483,7 @@ hideall "--sync--" 3408.7 "Lindwurm's Glare" #Ability { id: "B4F8", source: "Lindwurm" } 3408.7 "Lindwurm's Thunder II" #Ability { id: "B4FA", source: "Lindwurm" } 3408.7 "Lindwurm's Glare" #Ability { id: "B4F8", source: "Lindwurm" } -3412.0 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } window 10,10 +3412.0 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } window 10,10 # fflogs 3416.0 "--sync--" Ability { id: "B51D", source: "Lindschrat" } From 60aa6b483adfee7f408d0e3eb43c5bfcbea33af5 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 22:52:16 -0500 Subject: [PATCH 107/215] add trigger for remaining stacks/defamations in vision 4 Also pre-calls a tower positions output. --- ui/raidboss/data/07-dt/raid/r12s.ts | 236 ++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 2f2e05ed050..1b886e90991 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -73,6 +73,7 @@ export interface Data extends RaidbossData { replication4AbilityOrder: string[]; myReplication4Tether?: string; hasLightResistanceDown: boolean; + twistedVision4MechCounter: number; doomPlayers: string[]; } @@ -172,6 +173,7 @@ const triggerSet: TriggerSet = { replication4PlayerOrder: [], replication4AbilityOrder: [], hasLightResistanceDown: false, + twistedVision4MechCounter: 0, doomPlayers: [], }), triggers: [ @@ -3226,6 +3228,240 @@ const triggerSet: TriggerSet = { }; }, }, + { + id: 'R12S Twisted Vision 4 Stack/Defamation 2-4', + // Used for keeping of which Twisted Vision 4 mechanic we are on + // Note: B519 Heavy Slam and B517 Mana Burst cast regardless of players alive + // A B4F0 Unmitigated Impact will occur should the stack be missed + // Note2: B518 Mana Burst seems to not cast if the target is dead, and there doesn't seem to be repercussions + type: 'Ability', + netRegex: { id: ['B519', 'B517'], source: 'Lindschrat', capture: false }, + condition: (data) => data.twistedVisionCounter === 4 && data.twistedVision4MechCounter < 6, + suppressSeconds: 1, + response: (data, _matches, output) => { + // cactbot-builtin-response + output.responseOutputStrings = { + ...Directions.outputStrings8Dir, + stacks: Outputs.stacks, + towers: { + en: 'Tower Positions', + de: 'Turm Positionen', + fr: 'Position tour', + ja: '塔の位置へ', + cn: '八人塔站位', + ko: '기둥 자리잡기', + tc: '八人塔站位', + }, + avoidDefamation: { + en: 'Avoid Defamation', + }, + avoidStack: { + en: 'Avoid Stack', + de: 'Vermeide Sammeln', + fr: 'Évitez le package', + cn: '远离分摊', + ko: '쉐어징 피하기', + tc: '遠離分攤', + }, + defamationOnYou: Outputs.defamationOnYou, + stackOnYou: Outputs.stackOnYou, + stackOnPlayer: Outputs.stackOnPlayer, + defamations: { + en: 'Defamations', + de: 'Große AoE auf dir', + fr: 'Grosse AoE sur vous', + ja: '自分に巨大な爆発', + cn: '大圈点名', + ko: '광역 대상자', + tc: '大圈點名', + }, + oneMechThenOne: { + en: '${mech1} => ${mech2}', + }, + oneMechThenTwo: { + en: '${mech1} => ${mech2} + ${mech3}', + }, + twoMechsThenOne: { + en: '${mech1} + ${mech2} => ${mech3}', + }, + twoMechsThenTwo: { + en: '${mech1} + ${mech2} => ${mech3} + ${mech4}', + }, + oneMechThenTowers: { + en: '${mech1} => ${towers}', + }, + twoMechsThenTowers: { + en: '${mech1} + ${mech2} => ${towers}', + }, + }; + data.twistedVision4MechCounter = data.twistedVision4MechCounter + 2; // Mechanic is done in pairs + // Don't output for first one as it was called 1s prior to this trigger + if (data.twistedVision4MechCounter < 2) + return; + const count = data.twistedVision4MechCounter; + const abilityOrder = data.replication4AbilityOrder; + const playerOrder = data.replication4PlayerOrder; + if ( + abilityOrder === undefined || + playerOrder === undefined + ) + return; + + const ability1 = abilityOrder[0 + count]; + const ability2 = abilityOrder[1 + count]; + const player1 = playerOrder[0 + count]; + const player2 = playerOrder[1 + count]; + let this1; + let this2; + const defamation = headMarkerData['manaBurstTether']; + const isThisSame = ability1 === ability2; + const shortPlayer1 = data.party.member(player1); + const shortPlayer2 = data.party.member(player2); + const text = (player1 === data.me || player2 === data.me) ? 'alertText' : 'infoText'; + + // Handle This Set + if (player1 === data.me) { + this1 = ability1 === defamation ? 'defamationOnYou' : 'stackOnYou'; + if (!isThisSame) + this2 = ability2 === defamation ? 'avoidDefamation' : 'avoidStack'; + } else if (player2 === data.me) { + if (!isThisSame) { + this1 = ability1 === defamation ? 'avoidDefamation' : 'avoidStack'; + this2 = ability2 === defamation ? 'defamationOnYou' : 'stackOnYou'; + } else { + this1 = ability1 === defamation ? 'defamationOnYou' : 'stackOnYou'; + } + } else if (isThisSame) { + this1 = ability1 === defamation ? 'defamations' : 'stacks'; + } else if (!isThisSame) { + this1 = ability1 === defamation ? 'avoidDefamation' : 'stack'; + this2 = ability2 === defamation ? 'avoidDefamation' : 'stack'; + } + + if (count < 6) { + // Handle next set + // Get Stack/Defamation #2 details + const ability3 = abilityOrder[2 + count]; + const ability4 = abilityOrder[3 + count]; + const player3 = playerOrder[2 + count]; + const player4 = playerOrder[3 + count]; + + // Handle some obscure strategies or mistakes + const isNextSame = ability3 === ability4; + let next1; + let next2; + + if (player3 === data.me) { + next1 = ability3 === defamation ? 'defamationOnYou' : 'stackOnYou'; + if (!isThisSame) + next2 = ability4 === defamation ? 'avoidDefamation' : 'avoidStack'; + } else if (player4 === data.me) { + if (!isThisSame) { + next1 = ability4 === defamation ? 'avoidDefamation' : 'avoidStack'; + next2 = ability4 === defamation ? 'defamationOnYou' : 'stackOnYou'; + } else { + next1 = ability4 === defamation ? 'defamationOnYou' : 'stackOnYou'; + } + } else if (isNextSame) { + next1 = ability3 === defamation ? 'defamations' : 'stacks'; + } else if (!isNextSame) { + next1 = ability3 === defamation ? 'avoidDefamation' : 'stack'; + next2 = ability4 === defamation ? 'avoidDefamation' : 'stack'; + } + + // Build output + if (this1 === undefined || next1 === undefined) + return; + if (isThisSame && isNextSame) { + return { + [text]: output.oneMechThenOne!({ + mech1: output[this1]!(), + mech2: output[next1]!(), + }), + }; + } + + const shortPlayer3 = data.party.member(player3); + const shortPlayer4 = data.party.member(player4); + if (isThisSame && !isNextSame) { + if (next2 === undefined) + return; + return { + [text]: output.oneMechThenTwo!({ + mech1: output[this1]!(), + mech2: next1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer3 }) + : output[next1]!(), + mech3: next2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer4 }) + : output[next2]!(), + }), + }; + } + + if (!isThisSame && isNextSame) { + if (this2 === undefined) + return; + return { + [text]: output.twoMechsThenOne!({ + mech1: this1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer1 }) + : output[this1]!(), + mech2: this2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer2 }) + : output[this2]!(), + mech3: output[next1]!(), + }), + }; + } + + if (this2 === undefined || next2 === undefined) + return; + return { + [text]: output.twoMechsThenTwo!({ + mech1: this1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer1 }) + : output[this1]!(), + mech2: this2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer2 }) + : output[this2]!(), + mech3: next1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer3 }) + : output[next1]!(), + mech4: next2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer4 }) + : output[next2]!(), + }), + }; + } + // Build output for last mechanic set to warn of towers + if (this1 === undefined) + return; + if (isThisSame) { + return { + [text]: output.oneMechThenTowers!({ + mech1: output[this1]!(), + towers: output.towers!(), + }), + }; + } + if (!isThisSame) { + if (this2 === undefined) + return; + return { + [text]: output.twoMechsThenTowers!({ + mech1: this1 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer1 }) + : output[this1]!(), + mech2: this2 === 'stack' + ? output.stackOnPlayer!({ player: shortPlayer2 }) + : output[this2]!(), + towers: output.towers!(), + }), + }; + } + }, + }, { id: 'R12S Doom Collect', type: 'GainsEffect', From f4f5f0c198c3456d76c1ea46f947a4aab6940a26 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 22:57:40 -0500 Subject: [PATCH 108/215] filter light resistance early call to just vision 3 --- ui/raidboss/data/07-dt/raid/r12s.ts | 31 ++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 1b886e90991..2ccd6deea3c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3011,19 +3011,15 @@ const triggerSet: TriggerSet = { 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(), - run: (data) => data.hasLightResistanceDown = true, - }, { id: 'R12S Light Resistance Down II', type: 'GainsEffect', netRegex: { effectId: '1044', capture: true }, - condition: Conditions.targetIsYou(), + condition: (data, matches) => { + if (data.twistedVisionCounter === 3 && data.me === matches.target) + return true; + return false; + }, infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { @@ -3031,6 +3027,23 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S No Light Resistance Down II', + type: 'GainsEffect', + netRegex: { effectId: '1044', capture: false }, + condition: (data) => data.twistedVisionCounter === 3, + delaySeconds: 0.1, + suppressSeconds: 9999, + infoText: (data, _matches, output) => { + if (!data.hasLightResistanceDown) + return output.text!(); + }, + outputStrings: { + text: { + en: 'Soak a White/Star Meteor (later)', + }, + }, + }, { id: 'R12S No Light Resistance Down II', type: 'GainsEffect', From cbaad3062e671f839b973d70f25e3f7e97c4de9f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 23:11:25 -0500 Subject: [PATCH 109/215] twisted vision 5 tower call Will likely want to look into which towers were where previously, record that, but I'm not sure if a play position check prior to the end of the cast is adequate since the player could not yet be on the side they need to be at that time. Could add a delayed notification at end of cast of which of the two towers to take and you'd have ~4.4s to adjust. --- ui/raidboss/data/07-dt/raid/r12s.ts | 40 +++++++++++++++++------------ 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 2ccd6deea3c..a5b851f5c8f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3044,25 +3044,8 @@ const triggerSet: TriggerSet = { }, }, }, - { - 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 (later)', - }, - }, - }, { id: 'R12S Twisted Vision 4 Stack/Defamation 1', - // Used for keeping track of phases in idyllic type: 'StartsUsing', netRegex: { id: 'BBE2', source: 'Lindwurm', capture: false }, condition: (data) => data.twistedVisionCounter === 4, @@ -3475,6 +3458,7 @@ const triggerSet: TriggerSet = { } }, }, + { id: 'R12S Doom Collect', type: 'GainsEffect', @@ -3514,6 +3498,28 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Twisted Vision 5', + // TODO: Get Position of the towers and player side and state the front/left back/right + // Towers aren't visible until after cast, but you would have 4.4s to adjust if the trigger was delayed + type: 'StartsUsing', + netRegex: { id: 'BBE2', source: 'Lindwurm', capture: true }, + condition: (data) => data.twistedVisionCounter === 5, + durationSeconds: (_data, matches) => parseFloat(matches.castTime) + 4.1, + alertText: (data, _matches, output) => { + if (data.hasLightResistanceDown) + return output.fireEarthTower!(); + return output.holyTower!(); + }, + outputStrings: { + fireEarthTower: { + en: 'Soak Fire/Earth Meteor', + }, + holyTower: { + en: 'Soak a White/Star Meteor', + }, + }, + }, { id: 'R12S Doom Cleanup', type: 'LosesEffect', From 5b42c756068c47e1a676a9bdfea69ab071e85b39 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 23:13:45 -0500 Subject: [PATCH 110/215] remove extra line --- ui/raidboss/data/07-dt/raid/r12s.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index a5b851f5c8f..0bd98886398 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3458,7 +3458,6 @@ const triggerSet: TriggerSet = { } }, }, - { id: 'R12S Doom Collect', type: 'GainsEffect', From 107b1a50bf4017f722bf0815a9ba016ae5389e08 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 29 Jan 2026 23:21:55 -0500 Subject: [PATCH 111/215] add Lindwurm's Stone III trigger --- ui/raidboss/data/07-dt/raid/r12s.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 0bd98886398..79c71a512bd 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3498,9 +3498,10 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Twisted Vision 5', + id: 'R12S Twisted Vision 5 Towers', // TODO: Get Position of the towers and player side and state the front/left back/right // Towers aren't visible until after cast, but you would have 4.4s to adjust if the trigger was delayed + // 4s castTime type: 'StartsUsing', netRegex: { id: 'BBE2', source: 'Lindwurm', capture: true }, condition: (data) => data.twistedVisionCounter === 5, @@ -3538,6 +3539,21 @@ const triggerSet: TriggerSet = { durationSeconds: (_data, matches) => parseFloat(matches.duration), response: Responses.stopMoving(), }, + { + id: 'R12S Idyllic Dream Lindwurm\'s Stone III', + // TODO: Get their target locations and output avoid + // 5s castTime + type: 'StartsUsing', + netRegex: { id: 'B4F7', source: 'Lindwurm', capture: true }, + durationSeconds: (_data, matches) => parseFloat(matches.castTime), + suppressSeconds: 1, + infoText: (_data, _matches, output) => output.avoidEarthTower!(), + outputStrings: { + avoidEarthTower: { + en: 'Avoid Earth Tower', + }, + }, + }, { id: 'R12S Idyllic Dream Replication Clone Cardinal/Intercardinal Reminder', // Using Temporal Curtain From f6bc69509d52dacb00ce3f3b352660480de5ac75 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 30 Jan 2026 00:09:09 -0500 Subject: [PATCH 112/215] add nearby and faraway portent + baits Delayed until 4.7s as that is about when the Earth will have gone off and it will be safe to move. --- ui/raidboss/data/07-dt/raid/r12s.ts | 121 ++++++++++++++++++---------- 1 file changed, 78 insertions(+), 43 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 79c71a512bd..7986606d3fb 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3458,8 +3458,56 @@ const triggerSet: TriggerSet = { } }, }, + { + id: 'R12S Twisted Vision 5 Towers', + // TODO: Get Position of the towers and player side and state the front/left back/right + // Towers aren't visible until after cast, but you would have 4.4s to adjust if the trigger was delayed + // 4s castTime + type: 'StartsUsing', + netRegex: { id: 'BBE2', source: 'Lindwurm', capture: true }, + condition: (data) => data.twistedVisionCounter === 5, + durationSeconds: (_data, matches) => parseFloat(matches.castTime) + 4.1, + alertText: (data, _matches, output) => { + if (data.hasLightResistanceDown) + return output.fireEarthTower!(); + return output.holyTower!(); + }, + outputStrings: { + fireEarthTower: { + en: 'Soak Fire/Earth Meteor', + }, + holyTower: { + en: 'Soak a White/Star Meteor', + }, + }, + }, + { + 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 Lindwurm\'s Stone III', + // TODO: Get their target locations and output avoid + // 5s castTime + type: 'StartsUsing', + netRegex: { id: 'B4F7', source: 'Lindwurm', capture: true }, + durationSeconds: (_data, matches) => parseFloat(matches.castTime), + suppressSeconds: 1, + infoText: (_data, _matches, output) => output.avoidEarthTower!(), + outputStrings: { + avoidEarthTower: { + en: 'Avoid Earth Tower', + }, + }, + }, { id: 'R12S Doom Collect', + // Happens about 1.3s after Dark Tower when it casts B4F6 Lindwurm's Dark II type: 'GainsEffect', netRegex: { effectId: 'D24', capture: true }, run: (data, matches) => data.doomPlayers.push(matches.target), @@ -3498,59 +3546,46 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Twisted Vision 5 Towers', - // TODO: Get Position of the towers and player side and state the front/left back/right - // Towers aren't visible until after cast, but you would have 4.4s to adjust if the trigger was delayed - // 4s castTime - type: 'StartsUsing', - netRegex: { id: 'BBE2', source: 'Lindwurm', capture: true }, - condition: (data) => data.twistedVisionCounter === 5, - durationSeconds: (_data, matches) => parseFloat(matches.castTime) + 4.1, - alertText: (data, _matches, output) => { - if (data.hasLightResistanceDown) - return output.fireEarthTower!(); - return output.holyTower!(); + id: 'R12S Nearby and Faraway Portent', + // 129D Lindwurm's Portent prevents stacking the portents + // 129E Farwaway Portent + // 129F Nearby Portent + // 10s duration, need to delay to avoid earth + doom trigger overlap + // TODO: Configure for element tower they soaked + type: 'GainsEffect', + netRegex: { effectId: ['129E', '129F'], capture: true }, + condition: Conditions.targetIsYou(), + delaySeconds: (_data, matches) => parseFloat(matches.duration) - 5.3, + infoText: (_data, matches, output) => { + if (matches.id === '129E') + return output.farOnYou!(); + return output.nearOnYou!(); }, outputStrings: { - fireEarthTower: { - en: 'Soak Fire/Earth Meteor', + nearOnYou: { + en: 'Near on YOU: Be on Middle Hitbox', }, - holyTower: { - en: 'Soak a White/Star Meteor', + farOnYou: { + en: 'Far on YOU: Be on N/S Hitbox', // Most parties probably put this North? }, }, }, { - 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 + id: 'R12S Nearby and Faraway Portent Baits', + // TODO: Configure for element tower they soaked type: 'GainsEffect', - netRegex: { effectId: '12A0', capture: true }, - condition: Conditions.targetIsYou(), - durationSeconds: (_data, matches) => parseFloat(matches.duration), - response: Responses.stopMoving(), - }, - { - id: 'R12S Idyllic Dream Lindwurm\'s Stone III', - // TODO: Get their target locations and output avoid - // 5s castTime - type: 'StartsUsing', - netRegex: { id: 'B4F7', source: 'Lindwurm', capture: true }, - durationSeconds: (_data, matches) => parseFloat(matches.castTime), + netRegex: { effectId: ['129E', '129F'], capture: true }, + condition: (data) => data.hasLightResistanceDown, + delaySeconds: (_data, matches) => parseFloat(matches.duration) - 5.3, suppressSeconds: 1, - infoText: (_data, _matches, output) => output.avoidEarthTower!(), + infoText: (_data, _matches, output) => output.bait!(), outputStrings: { - avoidEarthTower: { - en: 'Avoid Earth Tower', + bait: { + en: 'Bait Cone', + de: 'Köder Kegel-AoE', + cn: '诱导扇形', + ko: '부채꼴 유도', + tc: '誘導扇形', }, }, }, From 52a35e8954bb48c3c0631c93b2f6ec7b28e0fca1 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 30 Jan 2026 01:05:29 -0500 Subject: [PATCH 113/215] fix twisted vision 6 early call, add twisted vision 8 I have yet to test these. --- ui/raidboss/data/07-dt/raid/r12s.ts | 92 ++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 15 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7986606d3fb..35e6b8f004c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3590,29 +3590,91 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Idyllic Dream Replication Clone Cardinal/Intercardinal Reminder', - // Using Temporal Curtain - type: 'StartsUsing', - netRegex: { id: 'B51C', source: 'Lindwurm', capture: false }, + id: 'R12S Twisted Vision 6 Light Party Stacks', + // At end of cast it's cardinal or intercard + type: 'Ability', + netRegex: { id: 'BBE2', source: 'Lindwurm', capture: false }, + condition: (data) => data.twistedVisionCounter === 6, infoText: (data, _matches, output) => { - const firstClone = data.replication3CloneOrder[0]; - if (firstClone === undefined) - return; - const actor = data.actorPositions[firstClone]; - if (actor === undefined) + const first = data.replication3CloneOrder[0]; + if (first === undefined) return; + const dirNumOrder = first % 2 === 0 ? [0, 2, 4, 6] : [1, 3, 5, 7]; + + // Need to lookup what ability is at each dir, only need cards or intercard dirs + const abilities = data.replication4AbilityOrder.splice(0,4); + const stackDirs = []; + let i = 0; + + // Find first all stacks in cards or intercards + // Incorrect amount means players made an unsolvable? run + for (const dirNum of dirNumOrder) { + if (abilities[i++] === headMarkerData['heavySlamTether']) + stackDirs.push(dirNum); + } + // Only grabbing first two + const dirNum1 = stackDirs[0]; + const dirNum2 = stackDirs[1]; - const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); - const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + // If we failed to get two stacks, just output generic cards/intercards reminder + if (dirNum1 === undefined || dirNum2 === undefined) { + return first % 2 === 0 ? output.cardinals!() : output.intercards!(); + } + const dir1 = Directions.output8Dir[dirNum1]; + const dir2 = Directions.output8Dir[dirNum2]; + return output.stack!({ dir1: dir1, dir2: dir2 }); + }, + outputStrings: { + ...Directions.outputStrings8Dir, + cardinals: Outputs.cardinals, + intercards: Outputs.intercards, + stack: { + en: 'Stack ${dir1}/${dir2} + Lean Middle Out', + }, + }, + }, + { + id: 'R12S Twisted Vision 8 Light Party Stacks', + // At end of cast it's cardinal or intercard + type: 'Ability', + netRegex: { id: 'BBE2', source: 'Lindwurm', capture: false }, + condition: (data) => data.twistedVisionCounter === 8, + infoText: (data, _matches, output) => { + const first = data.replication3CloneOrder[0]; + if (first === undefined) + return; + const dirNumOrder = first % 2 !== 0 ? [0, 2, 4, 6] : [1, 3, 5, 7]; + + // Need to lookup what ability is at each dir, only need cards or intercard dirs + const abilities = data.replication4AbilityOrder.slice(4,8); + const stackDirs = []; + let i = 0; + + // Find first all stacks in cards or intercards + // Incorrect amount means players made an unsolvable? run + for (const dirNum of dirNumOrder) { + if (abilities[i++] === headMarkerData['heavySlamTether']) + stackDirs.push(dirNum); + } + // Only grabbing first two + const dirNum1 = stackDirs[0]; + const dirNum2 = stackDirs[1]; - if (isCardinalDir(dir)) - return output.cardinals!(); - if (isIntercardDir(dir)) - return output.intercards!(); + // If we failed to get two stacks, just output generic cards/intercards reminder + if (dirNum1 === undefined || dirNum2 === undefined) { + return first % 2 !== 0 ? output.cardinals!() : output.intercards!(); + } + const dir1 = Directions.output8Dir[dirNum1]; + const dir2 = Directions.output8Dir[dirNum2]; + return output.stack!({ dir1: dir1, dir2: dir2 }); }, outputStrings: { + ...Directions.outputStrings8Dir, cardinals: Outputs.cardinals, intercards: Outputs.intercards, + stack: { + en: 'Stack ${dir1}/${dir2} + Lean Middle Out', + }, }, }, ], From de1643c23f7a277e77e3e2eb404fe5396cc28cd7 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 30 Jan 2026 01:19:40 -0500 Subject: [PATCH 114/215] add twisted vision 7 template Will be able to update it with direction later, needed to be able to call the vision 8 stuff earlier because of quickness of mechanics. --- ui/raidboss/data/07-dt/raid/r12s.ts | 62 ++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 35e6b8f004c..7d8b39bff7b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3633,13 +3633,71 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Twisted Vision 7 Safe Platform', + // TODO: Get direction of the safe platform + N/S or E/W? + type: 'StartsUsing', + netRegex: { id: 'BBE2', source: 'Lindwurm', capture: true }, + condition: (data) => data.twistedVisionCounter === 7, + durationSeconds: (_data, matches) => parseFloat(matches.castTime) + 3, + infoText: (data, _matches, output) => { + const first = data.replication3CloneOrder[0]; + if (first === undefined) + return; + const dirNumOrder = first % 2 !== 0 ? [0, 2, 4, 6] : [1, 3, 5, 7]; + + // Need to lookup what ability is at each dir, only need cards or intercard dirs + const abilities = data.replication4AbilityOrder.slice(4,8); + const stackDirs = []; + let i = 0; + + // Find first all stacks in cards or intercards + // Incorrect amount means players made an unsolvable? run + for (const dirNum of dirNumOrder) { + if (abilities[i++] === headMarkerData['heavySlamTether']) + stackDirs.push(dirNum); + } + // Only grabbing first two + const dirNum1 = stackDirs[0]; + const dirNum2 = stackDirs[1]; + + // If we failed to get two stacks, just output generic cards/intercards reminder + if (dirNum1 === undefined || dirNum2 === undefined) { + const card = first % 2 !== 0 ? 'cardinals' : 'intercards'; + return output.platformThenStack!({ + platform: output.safePlatform!(), + stack: output[card]!(), + }); + } + const dir1 = Directions.output8Dir[dirNum1]; + const dir2 = Directions.output8Dir[dirNum2]; + return output.platformThenStack!({ + platform: output.safePlatform!(), + stack: output.stack!({ dir1: dir1, dir2: dir2 }), + }); + }, + outputStrings: { + ...Directions.outputStrings8Dir, + cardinals: Outputs.cardinals, + intercards: Outputs.intercards, + safePlatform: { + en: 'Safe Platform', + }, + stack: { + en: 'Stack ${dir1}/${dir2}', + }, + platformThenStack: { + en: '${platform} => ${stack}', + }, + }, + }, { id: 'R12S Twisted Vision 8 Light Party Stacks', // At end of cast it's cardinal or intercard - type: 'Ability', + type: 'StartsUsing', netRegex: { id: 'BBE2', source: 'Lindwurm', capture: false }, condition: (data) => data.twistedVisionCounter === 8, - infoText: (data, _matches, output) => { + alertText: (data, _matches, output) => { const first = data.replication3CloneOrder[0]; if (first === undefined) return; From 5cbdc6654fe26e5a71a07368d3abe9f6c551d3df Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 30 Jan 2026 01:21:37 -0500 Subject: [PATCH 115/215] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7d8b39bff7b..87d5fb9d66f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3602,7 +3602,7 @@ const triggerSet: TriggerSet = { const dirNumOrder = first % 2 === 0 ? [0, 2, 4, 6] : [1, 3, 5, 7]; // Need to lookup what ability is at each dir, only need cards or intercard dirs - const abilities = data.replication4AbilityOrder.splice(0,4); + const abilities = data.replication4AbilityOrder.splice(0, 4); const stackDirs = []; let i = 0; @@ -3620,8 +3620,8 @@ const triggerSet: TriggerSet = { if (dirNum1 === undefined || dirNum2 === undefined) { return first % 2 === 0 ? output.cardinals!() : output.intercards!(); } - const dir1 = Directions.output8Dir[dirNum1]; - const dir2 = Directions.output8Dir[dirNum2]; + const dir1 = Directions.output8Dir[dirNum1]; + const dir2 = Directions.output8Dir[dirNum2]; return output.stack!({ dir1: dir1, dir2: dir2 }); }, outputStrings: { @@ -3647,7 +3647,7 @@ const triggerSet: TriggerSet = { const dirNumOrder = first % 2 !== 0 ? [0, 2, 4, 6] : [1, 3, 5, 7]; // Need to lookup what ability is at each dir, only need cards or intercard dirs - const abilities = data.replication4AbilityOrder.slice(4,8); + const abilities = data.replication4AbilityOrder.slice(4, 8); const stackDirs = []; let i = 0; @@ -3669,8 +3669,8 @@ const triggerSet: TriggerSet = { stack: output[card]!(), }); } - const dir1 = Directions.output8Dir[dirNum1]; - const dir2 = Directions.output8Dir[dirNum2]; + const dir1 = Directions.output8Dir[dirNum1]; + const dir2 = Directions.output8Dir[dirNum2]; return output.platformThenStack!({ platform: output.safePlatform!(), stack: output.stack!({ dir1: dir1, dir2: dir2 }), @@ -3704,7 +3704,7 @@ const triggerSet: TriggerSet = { const dirNumOrder = first % 2 !== 0 ? [0, 2, 4, 6] : [1, 3, 5, 7]; // Need to lookup what ability is at each dir, only need cards or intercard dirs - const abilities = data.replication4AbilityOrder.slice(4,8); + const abilities = data.replication4AbilityOrder.slice(4, 8); const stackDirs = []; let i = 0; @@ -3722,8 +3722,8 @@ const triggerSet: TriggerSet = { if (dirNum1 === undefined || dirNum2 === undefined) { return first % 2 !== 0 ? output.cardinals!() : output.intercards!(); } - const dir1 = Directions.output8Dir[dirNum1]; - const dir2 = Directions.output8Dir[dirNum2]; + const dir1 = Directions.output8Dir[dirNum1]; + const dir2 = Directions.output8Dir[dirNum2]; return output.stack!({ dir1: dir1, dir2: dir2 }); }, outputStrings: { From 5cd2fe2181e5cc4d045a4f9352e5d16b443409f4 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sat, 31 Jan 2026 14:32:19 -0500 Subject: [PATCH 116/215] fix for dn Clone Stacks + final defamation These can likely be cleared up later when replication 2 is refactored to be like replication 3 and we can determine the ability/location order... --- 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 87d5fb9d66f..afc84d38d3b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -223,7 +223,7 @@ const triggerSet: TriggerSet = { type: 'StartsUsing', netRegex: { id: 'B4EC', source: 'Lindwurm', capture: false }, run: (data) => { - if (data.phase === 'replication1') { + if (data.phase === 'replication2') { data.phase = 'reenactment1'; return; } From 9db5136fe9ccde50ff4731f962e279724d5aca3b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 04:18:04 -0500 Subject: [PATCH 117/215] fix twisted vision 4 calls --- ui/raidboss/data/07-dt/raid/r12s.ts | 514 ++++++++++------------------ 1 file changed, 188 insertions(+), 326 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index afc84d38d3b..5c08e8f4e9c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -69,9 +69,9 @@ export interface Data extends RaidbossData { idyllicVision2NorthSouthCleaveSpot?: 'north' | 'south'; replication4DirNumAbility: { [dirNum: number]: string }; replication4PlayerAbilities: { [player: string]: string }; + replication4BossCloneDirNumPlayers: { [dirNum: number]: string }; replication4PlayerOrder: string[]; replication4AbilityOrder: string[]; - myReplication4Tether?: string; hasLightResistanceDown: boolean; twistedVision4MechCounter: number; doomPlayers: string[]; @@ -170,6 +170,7 @@ const triggerSet: TriggerSet = { replication3CloneDirNumPlayers: {}, replication4DirNumAbility: {}, replication4PlayerAbilities: {}, + replication4BossCloneDirNumPlayers: {}, replication4PlayerOrder: [], replication4AbilityOrder: [], hasLightResistanceDown: false, @@ -2888,6 +2889,9 @@ const triggerSet: TriggerSet = { center.y, ); + // Store the player at each dirNum + data.replication4BossCloneDirNumPlayers[dirNum] = target; + // Lookup what the tether was at the same location const ability = data.replication4DirNumAbility[dirNum]; if (ability === undefined) { @@ -2900,11 +2904,12 @@ const triggerSet: TriggerSet = { // Create ability order once we have all 8 players // If players had more than one tether previously, the extra tethers are randomly assigned if (Object.keys(data.replication4PlayerAbilities).length === 8) { + // Used for Twisted Vision 7 and 8 mechanics const abilities = data.replication4PlayerAbilities; const order = data.replication3CloneOrder; // Order in which clones spawned const players = data.replication3CloneDirNumPlayers; // Direction of player's clone - // Mechanics are resolved clockwise, get create order based on cards/inters + // Mechanics are resolved clockwise, create order based on cards/inters const first = order[0]; if (first === undefined) return; @@ -3052,176 +3057,99 @@ const triggerSet: TriggerSet = { response: (data, _matches, output) => { // cactbot-builtin-response output.responseOutputStrings = { - ...Directions.outputStrings8Dir, stacks: Outputs.stacks, - avoidDefamation: { - en: 'Avoid Defamation', - }, - avoidStack: { - en: 'Avoid Stack', - de: 'Vermeide Sammeln', - fr: 'Évitez le package', - cn: '远离分摊', - ko: '쉐어징 피하기', - tc: '遠離分攤', - }, - defamationOnYou: Outputs.defamationOnYou, stackOnYou: Outputs.stackOnYou, - stackOnPlayer: Outputs.stackOnPlayer, defamations: { - en: 'Defamations', - de: 'Große AoE auf dir', - fr: 'Grosse AoE sur vous', - ja: '自分に巨大な爆発', - cn: '大圈点名', - ko: '광역 대상자', - tc: '大圈點名', + en: 'Avoid Defamations', + }, + defamationOnYou: Outputs.defamationOnYou, + stacksThenDefamations: { + en: '${mech1} => ${mech2}', + }, + defamationsThenStacks: { + en: '${mech1} => ${mech2}', }, - oneMechThenOne: { + stacksThenDefamationOnYou: { en: '${mech1} => ${mech2}', }, - oneMechThenTwo: { - en: '${mech1} => ${mech2} + ${mech3}', + defamationsThenStackOnYou: { + en: '${mech1} => ${mech2}', }, - twoMechsThenOne: { - en: '${mech1} + ${mech2} => ${mech3}', + stackOnYouThenDefamations: { + en: '${mech1} => ${mech2}', }, - twoMechsThenTwo: { - en: '${mech1} + ${mech2} => ${mech3} + ${mech4}', + defamationOnYouThenStack: { + en: '${mech1} => ${mech2}', }, }; - const abilityOrder = data.replication4AbilityOrder; - const playerOrder = data.replication4PlayerOrder; + const player1 = data.replication4BossCloneDirNumPlayers[0]; + const player2 = data.replication4BossCloneDirNumPlayers[4]; + const player3 = data.replication4BossCloneDirNumPlayers[1]; + const player4 = data.replication4BossCloneDirNumPlayers[5]; + const abilityId = data.replication4DirNumAbility[0]; // Only need to know one + if ( - abilityOrder === undefined || - playerOrder === undefined + abilityId === undefined || player1 === undefined || + player2 === undefined || player3 === undefined || + player4 === undefined ) return; - const ability1 = abilityOrder[0]; - const ability2 = abilityOrder[1]; - const player1 = playerOrder[0]; - const player2 = playerOrder[1]; - - // Get Stack/Defamation #2 details - const ability3 = abilityOrder[2]; - const ability4 = abilityOrder[3]; - const player3 = playerOrder[2]; - const player4 = playerOrder[3]; - - // Handle some obscure strategies or mistakes - const isThisSame = ability1 === ability2; - const isNextSame = ability3 === ability4; - const defamation = headMarkerData['manaBurstTether']; - let this1; - let this2; - let next1; - let next2; - // Handle This Set - if (player1 === data.me) { - this1 = ability1 === defamation ? 'defamationOnYou' : 'stackOnYou'; - if (!isThisSame) - this2 = ability2 === defamation ? 'avoidDefamation' : 'avoidStack'; - } else if (player2 === data.me) { - if (!isThisSame) { - this1 = ability1 === defamation ? 'avoidDefamation' : 'avoidStack'; - this2 = ability2 === defamation ? 'defamationOnYou' : 'stackOnYou'; - } else { - this1 = ability1 === defamation ? 'defamationOnYou' : 'stackOnYou'; - } - } else if (isThisSame) { - this1 = ability1 === defamation ? 'defamations' : 'stacks'; - } else if (!isThisSame) { - this1 = ability1 === defamation ? 'avoidDefamation' : 'stack'; - this2 = ability2 === defamation ? 'avoidDefamation' : 'stack'; - } + const ability1 = abilityId === headMarkerData['manaBurstTether'] + ? 'defamations' + : abilityId === headMarkerData['heavySlamTether'] + ? 'stacks' + : 'unknown'; - // Handle Next Set - if (player3 === data.me) { - next1 = ability3 === defamation ? 'defamationOnYou' : 'stackOnYou'; - if (!isThisSame) - next2 = ability4 === defamation ? 'avoidDefamation' : 'avoidStack'; - } else if (player4 === data.me) { - if (!isThisSame) { - next1 = ability4 === defamation ? 'avoidDefamation' : 'avoidStack'; - next2 = ability4 === defamation ? 'defamationOnYou' : 'stackOnYou'; - } else { - next1 = ability4 === defamation ? 'defamationOnYou' : 'stackOnYou'; - } - } else if (isNextSame) { - next1 = ability3 === defamation ? 'defamations' : 'stacks'; - } else if (!isNextSame) { - next1 = ability3 === defamation ? 'avoidDefamation' : 'stack'; - next2 = ability4 === defamation ? 'avoidDefamation' : 'stack'; - } + if (ability1 === 'stacks') { + if (data.me === player1 || data.me === player2) + return { + alertText: output.stackOnYouThenDefamations!({ + mech1: output.stackOnYou!(), + mech2: output.defamations!(), + }) + }; - // Build output - if (this1 === undefined || next1 === undefined) - return; - const text = (player1 === data.me || player2 === data.me) ? 'alertText' : 'infoText'; - if (isThisSame && isNextSame) { - return { - [text]: output.oneMechThenOne!({ - mech1: output[this1]!(), - mech2: output[next1]!(), - }), - }; - } + if (data.me === player3 || data.me === player4) + return { + infoText: output.stacksThenDefamationOnYou!({ + mech1: output.stacks!(), + mech2: output.defamationOnYou!(), + }) + }; - const shortPlayer3 = data.party.member(player3); - const shortPlayer4 = data.party.member(player4); - if (isThisSame && !isNextSame) { - if (next2 === undefined) - return; return { - [text]: output.oneMechThenTwo!({ - mech1: output[this1]!(), - mech2: next1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer3 }) - : output[next1]!(), - mech3: next2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer4 }) - : output[next2]!(), - }), + infoText: output.stacksThenDefamations!({ + mech1: output.stacks!(), + mech2: output.defamations!(), + }) }; } - const shortPlayer1 = data.party.member(player1); - const shortPlayer2 = data.party.member(player2); - if (!isThisSame && isNextSame) { - if (this2 === undefined) - return; + if (ability1 === 'defamations') { + if (data.me === player1 || data.me === player2) + return { + alertText: output.defamationOnYouThenStack!({ + mech1: output.defamationOnYou!(), + mech2: output.stacks!(), + }) + }; + + if (data.me === player3 || data.me === player4) + return { + infoText: output.defamationsThenStackOnYou!({ + mech1: output.defamations!(), + mech2: output.stackOnYou!(), + }) + }; + return { - [text]: output.twoMechsThenOne!({ - mech1: this1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer1 }) - : output[this1]!(), - mech2: this2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer2 }) - : output[this2]!(), - mech3: output[next1]!(), - }), + infoText: output.defamationsThenStacks!({ + mech1: output.defamations!(), + mech2: output.stacks!(), + }) }; } - - if (this2 === undefined || next2 === undefined) - return; - return { - [text]: output.twoMechsThenTwo!({ - mech1: this1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer1 }) - : output[this1]!(), - mech2: this2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer2 }) - : output[this2]!(), - mech3: next1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer3 }) - : output[next1]!(), - mech4: next2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer4 }) - : output[next2]!(), - }), - }; }, }, { @@ -3237,57 +3165,38 @@ const triggerSet: TriggerSet = { response: (data, _matches, output) => { // cactbot-builtin-response output.responseOutputStrings = { - ...Directions.outputStrings8Dir, stacks: Outputs.stacks, - towers: { - en: 'Tower Positions', - de: 'Turm Positionen', - fr: 'Position tour', - ja: '塔の位置へ', - cn: '八人塔站位', - ko: '기둥 자리잡기', - tc: '八人塔站位', - }, - avoidDefamation: { - en: 'Avoid Defamation', - }, - avoidStack: { - en: 'Avoid Stack', - de: 'Vermeide Sammeln', - fr: 'Évitez le package', - cn: '远离分摊', - ko: '쉐어징 피하기', - tc: '遠離分攤', - }, - defamationOnYou: Outputs.defamationOnYou, stackOnYou: Outputs.stackOnYou, - stackOnPlayer: Outputs.stackOnPlayer, defamations: { - en: 'Defamations', - de: 'Große AoE auf dir', - fr: 'Grosse AoE sur vous', - ja: '自分に巨大な爆発', - cn: '大圈点名', - ko: '광역 대상자', - tc: '大圈點名', + en: 'Avoid Defamations', }, - oneMechThenOne: { + defamationOnYou: Outputs.defamationOnYou, + stacksThenDefamations: { en: '${mech1} => ${mech2}', }, - oneMechThenTwo: { - en: '${mech1} => ${mech2} + ${mech3}', + defamationsThenStacks: { + en: '${mech1} => ${mech2}', }, - twoMechsThenOne: { - en: '${mech1} + ${mech2} => ${mech3}', + stacksThenDefamationOnYou: { + en: '${mech1} => ${mech2}', }, - twoMechsThenTwo: { - en: '${mech1} + ${mech2} => ${mech3} + ${mech4}', + defamationsThenStackOnYou: { + en: '${mech1} => ${mech2}', }, - oneMechThenTowers: { - en: '${mech1} => ${towers}', + stackOnYouThenDefamations: { + en: '${mech1} => ${mech2}', }, - twoMechsThenTowers: { - en: '${mech1} + ${mech2} => ${towers}', + defamationOnYouThenStack: { + en: '${mech1} => ${mech2}', + }, + towers: { + en: 'Tower Positions', + de: 'Turm Positionen', + fr: 'Position tour', + ja: '塔の位置へ', + cn: '八人塔站位', + ko: '기둥 자리잡기', + tc: '八人塔站位', }, }; data.twistedVision4MechCounter = data.twistedVision4MechCounter + 2; // Mechanic is done in pairs @@ -3295,165 +3204,118 @@ const triggerSet: TriggerSet = { if (data.twistedVision4MechCounter < 2) return; const count = data.twistedVision4MechCounter; - const abilityOrder = data.replication4AbilityOrder; - const playerOrder = data.replication4PlayerOrder; + const players = data.replication4BossCloneDirNumPlayers; + const abilityIds = data.replication4DirNumAbility; + const player1 = count === 2 + ? players[1] + : count === 4 ? players[2] : players[3]; + const player2 = count === 2 + ? players[5] + : count === 4 ? players[6] : players[7]; + const abilityId = count === 2 + ? abilityIds[1] + : count === 4 ? abilityIds[2] : abilityIds[3]; + if ( - abilityOrder === undefined || - playerOrder === undefined + abilityId === undefined || player1 === undefined || + player2 === undefined ) return; - const ability1 = abilityOrder[0 + count]; - const ability2 = abilityOrder[1 + count]; - const player1 = playerOrder[0 + count]; - const player2 = playerOrder[1 + count]; - let this1; - let this2; - const defamation = headMarkerData['manaBurstTether']; - const isThisSame = ability1 === ability2; - const shortPlayer1 = data.party.member(player1); - const shortPlayer2 = data.party.member(player2); - const text = (player1 === data.me || player2 === data.me) ? 'alertText' : 'infoText'; - - // Handle This Set - if (player1 === data.me) { - this1 = ability1 === defamation ? 'defamationOnYou' : 'stackOnYou'; - if (!isThisSame) - this2 = ability2 === defamation ? 'avoidDefamation' : 'avoidStack'; - } else if (player2 === data.me) { - if (!isThisSame) { - this1 = ability1 === defamation ? 'avoidDefamation' : 'avoidStack'; - this2 = ability2 === defamation ? 'defamationOnYou' : 'stackOnYou'; - } else { - this1 = ability1 === defamation ? 'defamationOnYou' : 'stackOnYou'; - } - } else if (isThisSame) { - this1 = ability1 === defamation ? 'defamations' : 'stacks'; - } else if (!isThisSame) { - this1 = ability1 === defamation ? 'avoidDefamation' : 'stack'; - this2 = ability2 === defamation ? 'avoidDefamation' : 'stack'; - } + const ability1 = abilityId === headMarkerData['manaBurstTether'] + ? 'defamations' + : abilityId === headMarkerData['heavySlamTether'] + ? 'stacks' + : 'unknown'; if (count < 6) { - // Handle next set - // Get Stack/Defamation #2 details - const ability3 = abilityOrder[2 + count]; - const ability4 = abilityOrder[3 + count]; - const player3 = playerOrder[2 + count]; - const player4 = playerOrder[3 + count]; - - // Handle some obscure strategies or mistakes - const isNextSame = ability3 === ability4; - let next1; - let next2; - - if (player3 === data.me) { - next1 = ability3 === defamation ? 'defamationOnYou' : 'stackOnYou'; - if (!isThisSame) - next2 = ability4 === defamation ? 'avoidDefamation' : 'avoidStack'; - } else if (player4 === data.me) { - if (!isThisSame) { - next1 = ability4 === defamation ? 'avoidDefamation' : 'avoidStack'; - next2 = ability4 === defamation ? 'defamationOnYou' : 'stackOnYou'; - } else { - next1 = ability4 === defamation ? 'defamationOnYou' : 'stackOnYou'; - } - } else if (isNextSame) { - next1 = ability3 === defamation ? 'defamations' : 'stacks'; - } else if (!isNextSame) { - next1 = ability3 === defamation ? 'avoidDefamation' : 'stack'; - next2 = ability4 === defamation ? 'avoidDefamation' : 'stack'; - } - - // Build output - if (this1 === undefined || next1 === undefined) + const player3 = count === 2 ? players[2] : players[3]; + const player4 = count === 2 ? players[6] : players[7]; + if (player3 === undefined || player4 === undefined) return; - if (isThisSame && isNextSame) { + + if (ability1 === 'stacks') { + if (data.me === player1 || data.me === player2) + return { + alertText: output.stackOnYouThenDefamations!({ + mech1: output.stackOnYou!(), + mech2: output.defamations!(), + }) + }; + + if (data.me === player3 || data.me === player4) + return { + infoText: output.stacksThenDefamationOnYou!({ + mech1: output.stacks!(), + mech2: output.defamationOnYou!(), + }) + }; + return { - [text]: output.oneMechThenOne!({ - mech1: output[this1]!(), - mech2: output[next1]!(), - }), + infoText: output.stacksThenDefamations!({ + mech1: output.stacks!(), + mech2: output.defamations!(), + }) }; } - const shortPlayer3 = data.party.member(player3); - const shortPlayer4 = data.party.member(player4); - if (isThisSame && !isNextSame) { - if (next2 === undefined) - return; + if (ability1 === 'defamations') { + if (data.me === player1 || data.me === player2) + return { + alertText: output.defamationOnYouThenStack!({ + mech1: output.defamationOnYou!(), + mech2: output.stacks!(), + }) + }; + if (data.me === player3 || data.me === player4) + return { + infoText: output.defamationsThenStackOnYou!({ + mech1: output.defamations!(), + mech2: output.stackOnYou!(), + }) + }; + return { - [text]: output.oneMechThenTwo!({ - mech1: output[this1]!(), - mech2: next1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer3 }) - : output[next1]!(), - mech3: next2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer4 }) - : output[next2]!(), - }), + infoText: output.defamationsThenStacks!({ + mech1: output.defamations!(), + mech2: output.stacks!(), + }) }; } + } - if (!isThisSame && isNextSame) { - if (this2 === undefined) - return; + // Last set followed up with tower positions + if (ability1 === 'stacks') { + if (data.me === player1 || data.me === player2) return { - [text]: output.twoMechsThenOne!({ - mech1: this1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer1 }) - : output[this1]!(), - mech2: this2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer2 }) - : output[this2]!(), - mech3: output[next1]!(), - }), + alertText: output.stackOnYouThenDefamations!({ + mech1: output.stackOnYou!(), + mech2: output.towers!(), + }) }; - } - if (this2 === undefined || next2 === undefined) - return; - return { - [text]: output.twoMechsThenTwo!({ - mech1: this1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer1 }) - : output[this1]!(), - mech2: this2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer2 }) - : output[this2]!(), - mech3: next1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer3 }) - : output[next1]!(), - mech4: next2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer4 }) - : output[next2]!(), - }), - }; - } - // Build output for last mechanic set to warn of towers - if (this1 === undefined) - return; - if (isThisSame) { return { - [text]: output.oneMechThenTowers!({ - mech1: output[this1]!(), - towers: output.towers!(), - }), + infoText: output.stacksThenDefamations!({ + mech1: output.stacks!(), + mech2: output.towers!(), + }) }; } - if (!isThisSame) { - if (this2 === undefined) - return; + + if (ability1 === 'defamations') { + if (data.me === player1 || data.me === player2) + return { + alertText: output.defamationOnYouThenStack!({ + mech1: output.defamationOnYou!(), + mech2: output.towers!(), + }) + }; + return { - [text]: output.twoMechsThenTowers!({ - mech1: this1 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer1 }) - : output[this1]!(), - mech2: this2 === 'stack' - ? output.stackOnPlayer!({ player: shortPlayer2 }) - : output[this2]!(), - towers: output.towers!(), - }), + infoText: output.defamationsThenStacks!({ + mech1: output.defamations!(), + mech2: output.towers!(), + }) }; } }, From b12bf208203d8733bc19ed95d08ec589ed16a887 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 04:21:45 -0500 Subject: [PATCH 118/215] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 52 ++++++++++++++++------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 5c08e8f4e9c..54693cdaf61 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3098,8 +3098,8 @@ const triggerSet: TriggerSet = { const ability1 = abilityId === headMarkerData['manaBurstTether'] ? 'defamations' : abilityId === headMarkerData['heavySlamTether'] - ? 'stacks' - : 'unknown'; + ? 'stacks' + : 'unknown'; if (ability1 === 'stacks') { if (data.me === player1 || data.me === player2) @@ -3107,7 +3107,7 @@ const triggerSet: TriggerSet = { alertText: output.stackOnYouThenDefamations!({ mech1: output.stackOnYou!(), mech2: output.defamations!(), - }) + }), }; if (data.me === player3 || data.me === player4) @@ -3115,14 +3115,14 @@ const triggerSet: TriggerSet = { infoText: output.stacksThenDefamationOnYou!({ mech1: output.stacks!(), mech2: output.defamationOnYou!(), - }) + }), }; return { infoText: output.stacksThenDefamations!({ mech1: output.stacks!(), mech2: output.defamations!(), - }) + }), }; } @@ -3132,7 +3132,7 @@ const triggerSet: TriggerSet = { alertText: output.defamationOnYouThenStack!({ mech1: output.defamationOnYou!(), mech2: output.stacks!(), - }) + }), }; if (data.me === player3 || data.me === player4) @@ -3140,14 +3140,14 @@ const triggerSet: TriggerSet = { infoText: output.defamationsThenStackOnYou!({ mech1: output.defamations!(), mech2: output.stackOnYou!(), - }) + }), }; return { infoText: output.defamationsThenStacks!({ mech1: output.defamations!(), mech2: output.stacks!(), - }) + }), }; } }, @@ -3208,13 +3208,19 @@ const triggerSet: TriggerSet = { const abilityIds = data.replication4DirNumAbility; const player1 = count === 2 ? players[1] - : count === 4 ? players[2] : players[3]; + : count === 4 + ? players[2] + : players[3]; const player2 = count === 2 ? players[5] - : count === 4 ? players[6] : players[7]; + : count === 4 + ? players[6] + : players[7]; const abilityId = count === 2 ? abilityIds[1] - : count === 4 ? abilityIds[2] : abilityIds[3]; + : count === 4 + ? abilityIds[2] + : abilityIds[3]; if ( abilityId === undefined || player1 === undefined || @@ -3225,8 +3231,8 @@ const triggerSet: TriggerSet = { const ability1 = abilityId === headMarkerData['manaBurstTether'] ? 'defamations' : abilityId === headMarkerData['heavySlamTether'] - ? 'stacks' - : 'unknown'; + ? 'stacks' + : 'unknown'; if (count < 6) { const player3 = count === 2 ? players[2] : players[3]; @@ -3240,7 +3246,7 @@ const triggerSet: TriggerSet = { alertText: output.stackOnYouThenDefamations!({ mech1: output.stackOnYou!(), mech2: output.defamations!(), - }) + }), }; if (data.me === player3 || data.me === player4) @@ -3248,14 +3254,14 @@ const triggerSet: TriggerSet = { infoText: output.stacksThenDefamationOnYou!({ mech1: output.stacks!(), mech2: output.defamationOnYou!(), - }) + }), }; return { infoText: output.stacksThenDefamations!({ mech1: output.stacks!(), mech2: output.defamations!(), - }) + }), }; } @@ -3265,21 +3271,21 @@ const triggerSet: TriggerSet = { alertText: output.defamationOnYouThenStack!({ mech1: output.defamationOnYou!(), mech2: output.stacks!(), - }) + }), }; if (data.me === player3 || data.me === player4) return { infoText: output.defamationsThenStackOnYou!({ mech1: output.defamations!(), mech2: output.stackOnYou!(), - }) + }), }; return { infoText: output.defamationsThenStacks!({ mech1: output.defamations!(), mech2: output.stacks!(), - }) + }), }; } } @@ -3291,14 +3297,14 @@ const triggerSet: TriggerSet = { alertText: output.stackOnYouThenDefamations!({ mech1: output.stackOnYou!(), mech2: output.towers!(), - }) + }), }; return { infoText: output.stacksThenDefamations!({ mech1: output.stacks!(), mech2: output.towers!(), - }) + }), }; } @@ -3308,14 +3314,14 @@ const triggerSet: TriggerSet = { alertText: output.defamationOnYouThenStack!({ mech1: output.defamationOnYou!(), mech2: output.towers!(), - }) + }), }; return { infoText: output.defamationsThenStacks!({ mech1: output.defamations!(), mech2: output.towers!(), - }) + }), }; } }, From e114f2f91356c1a9c8497e99c7584f54e997069f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 05:56:53 -0500 Subject: [PATCH 119/215] twisted vision 7 plaform and twisted vision 8 cleave --- ui/raidboss/data/07-dt/raid/r12s.ts | 263 +++++++++++++++++++--------- 1 file changed, 184 insertions(+), 79 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 54693cdaf61..3a449510ed2 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -66,7 +66,10 @@ export interface Data extends RaidbossData { twistedVisionCounter: number; replication3CloneOrder: number[]; replication3CloneDirNumPlayers: { [dirNum: number]: string }; - idyllicVision2NorthSouthCleaveSpot?: 'north' | 'south'; + idyllicVision2NorthSouthCleaveSpot?: 'north' | 'south';\ + idyllicDreamActorEW?: string; + idyllicDreamActorNS?: string; + idyllicDreamActorSnaking?: string; replication4DirNumAbility: { [dirNum: number]: string }; replication4PlayerAbilities: { [player: string]: string }; replication4BossCloneDirNumPlayers: { [dirNum: number]: string }; @@ -2772,18 +2775,31 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Idyllic Dream Power Gusher Collect', - // Need to know this for later + id: 'R12S Idyllic Dream Power Gusher and Snaking Kick Collect', + // Need to know these 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: 'B510', source: 'Lindschrat', capture: true }, + netRegex: { id: ['B50F', 'B510', 'B511'], source: 'Lindschrat', capture: true }, run: (data, matches) => { - const y = parseFloat(matches.y); - data.idyllicVision2NorthSouthCleaveSpot = y < center.y ? 'north' : 'south'; + // Temporal Curtain can have early calls based on matching the id for which add went where + switch (matches.id) { + case 'B510': { + const y = parseFloat(matches.y); + data.idyllicVision2NorthSouthCleaveSpot = y < center.y ? 'north' : 'south'; + data.idyllicDreamActorEW = matches.id; + return; + } + case 'B511': + data.idyllicDreamActorSnaking = matches.id; + return; + case 'B50F': + data.idyllicDreamActorNS = matches.id; + return; + } }, }, { @@ -2820,43 +2836,29 @@ const triggerSet: TriggerSet = { 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; + delaySeconds: 0.1, + suppressSeconds: 9999, + infoText: (data, _matches, output) => { + const first = data.replication4DirNumAbility[0]; + if (first === undefined) { + return output.getTether!(); } - 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]!() }); - } + if (first === headMarkerData['manaBurstTether']) + return output.stacksFirst!(); + if (first === headMarkerData['heavySlamTether']) + return output.defamationsFirst!(); + return output.getTether!(); }, outputStrings: { - ...Directions.outputStrings8Dir, - manaBurstTether: { - en: 'Defamation Tether on YOU', + getTether: { + en: 'Get Tether', }, - manaBurstTetherDir: { - en: '${dir} Defamation Tether on YOU', + defamationsFirst: { + en: 'Defamations First (later); Get Tether', }, - heavySlamTether: { - en: 'Stack Tether on YOU', - }, - heavySlamTetherDir: { - en: '${dir} Stack Tether on YOU', + stacksFirst: { + en: 'Stacks First (later); Get Tether', }, }, }, @@ -3016,6 +3018,14 @@ const triggerSet: TriggerSet = { 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(), + run: (data) => data.hasLightResistanceDown = true, + }, { id: 'R12S Light Resistance Down II', type: 'GainsEffect', @@ -3457,6 +3467,99 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Temporal Curtain Part 1 Collect', + // Describe actor going into portal + type: 'Ability', + netRegex: { id: 'B51D', source: 'Lindschrat', capture: true }, + run: (data, matches) => { + switch (matches.id) { + case data.idyllicDreamActorEW: + data.idyllicVision8SafeSides = 'frontBack'; + return; + case data.idyllicDreamActorNS: + data.idyllicVision8SafeSides = 'sides'; + } + }, + }, + { + id: 'R12S Temporal Curtain Part 1', + // Describe actor going into portal + type: 'Ability', + netRegex: { id: 'B51D', source: 'Lindschrat', capture: true }, + infoText: (data, matches, output) => { + switch (matches.id) { + case data.idyllicDreamActorEW: + return output.frontBackLater!(); + case data.idyllicDreamActorNS: + return output.sidesLater!(); + } + }, + outputStrings: { + frontBackLater: { + en: 'Portal + Front/Back Clone (later)', + }, + sidesLater: { + en: 'Portal + Sides Clone (later)', + }, + }, + }, + { + id: 'R12S Temporal Curtain Part 2 Collect', + // Describe actor going into portal + type: 'AbilityExtra', + netRegex: { id: 'B4D9', capture: true }, + run: (data, matches) => { + switch (matches.id) { + case data.idyllicDreamActorEW: + data.idyllicVision7SafeSides = 'frontBack'; + return; + case data.idyllicDreamActorNS: + data.idyllicVision7SafeSides = 'sides'; + return; + case data.idyllicDreamActorSnaking: { + const x = parseFloat(matches.x); + data.idyllicVision7SafePlatform = x < 100 ? 'west' : 'east'; + } + } + }, + }, + { + id: 'R12S Temporal Curtain Part 2', + // Describe actor going into portal + type: 'AbilityExtra', + netRegex: { id: 'B4D9', capture: false }, + delaySeconds: 0.1, + suppressSeconds: 9999, + infoText: (data, _matches, output) => { + if (data.idyllicVision7SafeSides === 'frontBack') { + if (data.idyllicVision7SafePlatform === 'east') + return output.frontBackEastLater!(); + if (data.idyllicVision7SafePlatform === 'west') + return output.frontBackWestLater!(); + } + if (data.idyllicVision7SafeSides === 'sides') { + if (data.idyllicVision7SafePlatform === 'east') + return output.sidesEastLater!(); + if (data.idyllicVision7SafePlatform === 'west') + return output.sidesWestLater!(); + } + }, + outputStrings: { + frontBackWestLater: { + en: 'West Platform => Front/Back Clone (later)', + }, + sidesWestLater: { + en: 'West Platform => Sides Clone (later)', + }, + frontBackEastLater: { + en: 'East Platform => Front/Back Clone (later)', + }, + sidesEastLater: { + en: 'East Platform => Sides Clone (later)', + }, + }, + }, { id: 'R12S Twisted Vision 6 Light Party Stacks', // At end of cast it's cardinal or intercard @@ -3503,59 +3606,40 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Twisted Vision 7 Safe Platform', - // TODO: Get direction of the safe platform + N/S or E/W? type: 'StartsUsing', netRegex: { id: 'BBE2', source: 'Lindwurm', capture: true }, condition: (data) => data.twistedVisionCounter === 7, - durationSeconds: (_data, matches) => parseFloat(matches.castTime) + 3, + durationSeconds: (_data, matches) => parseFloat(matches.castTime), infoText: (data, _matches, output) => { - const first = data.replication3CloneOrder[0]; - if (first === undefined) - return; - const dirNumOrder = first % 2 !== 0 ? [0, 2, 4, 6] : [1, 3, 5, 7]; - - // Need to lookup what ability is at each dir, only need cards or intercard dirs - const abilities = data.replication4AbilityOrder.slice(4, 8); - const stackDirs = []; - let i = 0; - - // Find first all stacks in cards or intercards - // Incorrect amount means players made an unsolvable? run - for (const dirNum of dirNumOrder) { - if (abilities[i++] === headMarkerData['heavySlamTether']) - stackDirs.push(dirNum); + if (data.idyllicVision7SafeSides === 'frontBack') { + if (data.idyllicVision7SafePlatform === 'east') + return output.northSouthEastPlaform!(); + if (data.idyllicVision7SafePlatform === 'west') + return output.northSouthWestPlaform!(); } - // Only grabbing first two - const dirNum1 = stackDirs[0]; - const dirNum2 = stackDirs[1]; - - // If we failed to get two stacks, just output generic cards/intercards reminder - if (dirNum1 === undefined || dirNum2 === undefined) { - const card = first % 2 !== 0 ? 'cardinals' : 'intercards'; - return output.platformThenStack!({ - platform: output.safePlatform!(), - stack: output[card]!(), - }); + if (data.idyllicVision7SafeSides === 'sides') { + if (data.idyllicVision7SafePlatform === 'east') + return output.eastWestEastPlaform!(); + if (data.idyllicVision7SafePlatform === 'west') + return output.eastWestWestPlaform!(); } - const dir1 = Directions.output8Dir[dirNum1]; - const dir2 = Directions.output8Dir[dirNum2]; - return output.platformThenStack!({ - platform: output.safePlatform!(), - stack: output.stack!({ dir1: dir1, dir2: dir2 }), - }); + return output.safePlatform!(); }, outputStrings: { - ...Directions.outputStrings8Dir, - cardinals: Outputs.cardinals, - intercards: Outputs.intercards, safePlatform: { - en: 'Safe Platform', + en: 'Move to Safe Platform Side => Dodge Cleaves', }, - stack: { - en: 'Stack ${dir1}/${dir2}', + sidesWestPlatform: { + en: 'West Platform => Sides of Clone', + }, + sidesEastPlatform: { + en: 'East Platform => Sides of Clone', }, - platformThenStack: { - en: '${platform} => ${stack}', + frontBackEastPlatform: { + en: 'East Platform => Front/Back of Clone', + }, + frontBackWestPlatform: { + en: 'West Platform => Front/Back of Clone', }, }, }, @@ -3603,6 +3687,27 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Twisted Vision 8 Dodge Cleaves', + // Trigger on Clone's BE5D Heavy Slam + type: 'Ability', + netRegex: { id: 'BE5D', source: 'Lindwurm', capture: false }, + suppressSeconds: 9999, + alertText: (data, _matches, output) => { + if (data.idyllicVision8SafeSides === 'sides') + return output.sides!(); + if (data.idyllicVision8SafeSides === 'frontBack') + return output.frontBack!(); + }, + outputStrings: { + sides: { + en: 'Sides of Clone', + }, + frontBack: { + en: 'Front/Back of Clone', + }, + }, + }, ], timelineReplace: [ { From 1c8b68c1e0e1e88dbbb7d3eca157383e34c2b04b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 05:58:04 -0500 Subject: [PATCH 120/215] minor timing updates --- ui/raidboss/data/07-dt/raid/r12s.txt | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index c52d6bf5117..c873e1e7b24 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -473,22 +473,18 @@ hideall "--sync--" # Twisted Vision 5: Towers 3393.6 "Twisted Vision 5" Ability { id: "BBE2", source: "Lindwurm" } -3398.0 "Cosmic Kiss" Ability { id: "B4F4", source: "Lindwurm" } - -# fflogs adjusted by 4.1s -3398.7 "Lindwurm's Dark II" Ability { id: "B4F6", source: "Lindwurm" } -3400.7 "Pyretic Wurm" Ability { id: "B4F9", source: "Lindwurm" } -3403.7 "Lindwurm's Stone III" #Ability { id: "B4F7", source: "Lindwurm" } -3408.7 "Lindwurm's Thunder II" #Ability { id: "B4FA", source: "Lindwurm" } -3408.7 "Lindwurm's Glare" #Ability { id: "B4F8", source: "Lindwurm" } -3408.7 "Lindwurm's Thunder II" #Ability { id: "B4FA", source: "Lindwurm" } -3408.7 "Lindwurm's Glare" #Ability { id: "B4F8", source: "Lindwurm" } -3412.0 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } window 10,10 +3398.0 "Cosmic Kiss x8" Ability { id: "B4F4", source: "Lindwurm" } +3398.7 "Lindwurm's Dark II x2" Ability { id: "B4F6", source: "Lindwurm" } +3400.7 "Pyretic Wurm x2" Ability { id: "B4F9", source: "Lindwurm" } +3403.7 "Lindwurm's Stone III x2" #Ability { id: "B4F7", source: "Lindwurm" } +3408.7 "Lindwurm's Thunder II x4" #Ability { id: "B4FA", source: "Lindwurm" } +3408.7 "Lindwurm's Glare x4" #Ability { id: "B4F8", source: "Lindwurm" } +3417.1 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } +3420.2 "--clone takes portal--" Ability { id: "B51D", source: "Lindschrat" } +3423.3 "--clones on platform--" Ability { id: "B4D9", source: "Lindschrat" } # fflogs -3416.0 "--sync--" Ability { id: "B51D", source: "Lindschrat" } -3419.1 "--sync--" Ability { id: "B4D9", source: "Lindschrat" } -3425.4 "Twisted Vision 6" Ability { id: "BBE2", source: "Lindwurm" } +3425.4 "Twisted Vision 6" Ability { id: "BBE2", source: "Lindwurm" } window 10,10 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" } From e4bf519a88e8b25399fc143b77abfae21e36f1be Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 05:59:17 -0500 Subject: [PATCH 121/215] remove invalid character --- 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 3a449510ed2..fdcd1536f4e 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -66,7 +66,7 @@ export interface Data extends RaidbossData { twistedVisionCounter: number; replication3CloneOrder: number[]; replication3CloneDirNumPlayers: { [dirNum: number]: string }; - idyllicVision2NorthSouthCleaveSpot?: 'north' | 'south';\ + idyllicVision2NorthSouthCleaveSpot?: 'north' | 'south'; idyllicDreamActorEW?: string; idyllicDreamActorNS?: string; idyllicDreamActorSnaking?: string; From 3e0a73104f883df0c58abf062fb0ccd6df96ace9 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 06:01:30 -0500 Subject: [PATCH 122/215] add missing variables --- ui/raidboss/data/07-dt/raid/r12s.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index fdcd1536f4e..b3487d6decf 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -78,6 +78,9 @@ export interface Data extends RaidbossData { hasLightResistanceDown: boolean; twistedVision4MechCounter: number; doomPlayers: string[]; + idyllicVision8SafeSides?: 'frontBack' | 'sides'; + idyllicVision7SafeSides?: 'frontBack' | 'sides'; + idyllicVision7SafePlatform?: 'east' | 'west'; } const headMarkerData = { From 84c8b87dd377e12b9b6778784de12837c2a82f8a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 06:40:03 -0500 Subject: [PATCH 123/215] fix missing 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 b3487d6decf..923911de741 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3616,15 +3616,15 @@ const triggerSet: TriggerSet = { infoText: (data, _matches, output) => { if (data.idyllicVision7SafeSides === 'frontBack') { if (data.idyllicVision7SafePlatform === 'east') - return output.northSouthEastPlaform!(); + return output.frontBackEastPlaform!(); if (data.idyllicVision7SafePlatform === 'west') - return output.northSouthWestPlaform!(); + return output.frontBackWestPlaform!(); } if (data.idyllicVision7SafeSides === 'sides') { if (data.idyllicVision7SafePlatform === 'east') - return output.eastWestEastPlaform!(); + return output.sidesEastPlaform!(); if (data.idyllicVision7SafePlatform === 'west') - return output.eastWestWestPlaform!(); + return output.sidesWestPlaform!(); } return output.safePlatform!(); }, From 74efb5a47e42c9451981409a5a550374e26d3769 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 15:24:01 -0500 Subject: [PATCH 124/215] typo --- 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 923911de741..443f9a825ba 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3616,15 +3616,15 @@ const triggerSet: TriggerSet = { infoText: (data, _matches, output) => { if (data.idyllicVision7SafeSides === 'frontBack') { if (data.idyllicVision7SafePlatform === 'east') - return output.frontBackEastPlaform!(); + return output.frontBackEastPlatform!(); if (data.idyllicVision7SafePlatform === 'west') - return output.frontBackWestPlaform!(); + return output.frontBackWestPlatform!(); } if (data.idyllicVision7SafeSides === 'sides') { if (data.idyllicVision7SafePlatform === 'east') - return output.sidesEastPlaform!(); + return output.sidesEastPlatform!(); if (data.idyllicVision7SafePlatform === 'west') - return output.sidesWestPlaform!(); + return output.sidesWestPlatform!(); } return output.safePlatform!(); }, From 76b12082bb068b75d0fec3d7db90539ddff22ccc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 1 Feb 2026 20:44:47 -0500 Subject: [PATCH 125/215] fix dir not output --- ui/raidboss/data/07-dt/raid/r12s.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 443f9a825ba..867faf9a1a0 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3594,9 +3594,9 @@ const triggerSet: TriggerSet = { if (dirNum1 === undefined || dirNum2 === undefined) { return first % 2 === 0 ? output.cardinals!() : output.intercards!(); } - const dir1 = Directions.output8Dir[dirNum1]; - const dir2 = Directions.output8Dir[dirNum2]; - return output.stack!({ dir1: dir1, dir2: dir2 }); + const dir1 = Directions.output8Dir[dirNum1] ?? 'unknown'; + const dir2 = Directions.output8Dir[dirNum2] ?? 'unknown'; + return output.stack!({ dir1: output[dir1]!(), dir2: output[dir2]!() }); }, outputStrings: { ...Directions.outputStrings8Dir, @@ -3677,9 +3677,9 @@ const triggerSet: TriggerSet = { if (dirNum1 === undefined || dirNum2 === undefined) { return first % 2 !== 0 ? output.cardinals!() : output.intercards!(); } - const dir1 = Directions.output8Dir[dirNum1]; - const dir2 = Directions.output8Dir[dirNum2]; - return output.stack!({ dir1: dir1, dir2: dir2 }); + const dir1 = Directions.output8Dir[dirNum1] ?? 'unknown'; + const dir2 = Directions.output8Dir[dirNum2] ?? 'unknown'; + return output.stack!({ dir1: output[dir1]!(), dir2: output[dir2]!() }); }, outputStrings: { ...Directions.outputStrings8Dir, From cc58a5c805c9d043d817c5972fbc2aeebd68fa6c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 01:09:34 -0500 Subject: [PATCH 126/215] add additional portent bait calls output at the moment is just default dn --- ui/raidboss/data/07-dt/raid/r12s.ts | 77 +++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 867faf9a1a0..e10b61aec78 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -78,6 +78,8 @@ export interface Data extends RaidbossData { hasLightResistanceDown: boolean; twistedVision4MechCounter: number; doomPlayers: string[]; + hasDoom: boolean; + hasPyretic: boolean; idyllicVision8SafeSides?: 'frontBack' | 'sides'; idyllicVision7SafeSides?: 'frontBack' | 'sides'; idyllicVision7SafePlatform?: 'east' | 'west'; @@ -182,6 +184,8 @@ const triggerSet: TriggerSet = { hasLightResistanceDown: false, twistedVision4MechCounter: 0, doomPlayers: [], + hasDoom: false, + hasPyretic: false, }), triggers: [ { @@ -3362,6 +3366,14 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Hot-blooded Collect', + // Player can still cast, but shouldn't move for 5s duration + type: 'GainsEffect', + netRegex: { effectId: '12A0', capture: true }, + condition: Conditions.targetIsYou(), + run: (data, _matches) => data.hasPyretic = true, + }, { id: 'R12S Hot-blooded', // Player can still cast, but shouldn't move for 5s duration @@ -3391,7 +3403,11 @@ const triggerSet: TriggerSet = { // Happens about 1.3s after Dark Tower when it casts B4F6 Lindwurm's Dark II type: 'GainsEffect', netRegex: { effectId: 'D24', capture: true }, - run: (data, matches) => data.doomPlayers.push(matches.target), + run: (data, matches) => { + data.doomPlayers.push(matches.target); + if (data.me === matches.target) + data.hasDoom = true; + }, }, { id: 'R12S Doom Cleanse', @@ -3432,41 +3448,55 @@ const triggerSet: TriggerSet = { // 129E Farwaway Portent // 129F Nearby Portent // 10s duration, need to delay to avoid earth + doom trigger overlap - // TODO: Configure for element tower they soaked + // This would go out to players that soaked white/holy meteors type: 'GainsEffect', netRegex: { effectId: ['129E', '129F'], capture: true }, condition: Conditions.targetIsYou(), delaySeconds: (_data, matches) => parseFloat(matches.duration) - 5.3, - infoText: (_data, matches, output) => { - if (matches.id === '129E') - return output.farOnYou!(); - return output.nearOnYou!(); + infoText: (data, matches, output) => { + if (matches.id === '129E') { + if (data.hasDoom) + return output.farOnYouDark!(); + return output.farOnYouWind!(); + } + if (data.hasDoom) + return output.nearOnYouDark!(); + return output.nearOnYouWind!(); }, outputStrings: { - nearOnYou: { + nearOnYouWind: { en: 'Near on YOU: Be on Middle Hitbox', }, - farOnYou: { - en: 'Far on YOU: Be on N/S Hitbox', // Most parties probably put this North? + nearOnYouDark: { + en: 'Near on YOU: Be on Hitbox N', + }, + farOnYouWind: { + en: 'Far on YOU: Be on Middle Hitbox', + }, + farOnYouDark: { + en: 'Far on YOU: Be on Hitbox N', }, }, }, { id: 'R12S Nearby and Faraway Portent Baits', - // TODO: Configure for element tower they soaked + // This would go out on players that soaked fire/earth meteors type: 'GainsEffect', netRegex: { effectId: ['129E', '129F'], capture: true }, condition: (data) => data.hasLightResistanceDown, delaySeconds: (_data, matches) => parseFloat(matches.duration) - 5.3, suppressSeconds: 1, - infoText: (_data, _matches, output) => output.bait!(), + infoText: (data, _matches, output) => { + if (data.hasPyretic) + return output.baitFire!(); + return output.baitEarth!(); + }, outputStrings: { - bait: { - en: 'Bait Cone', - de: 'Köder Kegel-AoE', - cn: '诱导扇形', - ko: '부채꼴 유도', - tc: '誘導扇形', + baitFire: { + en: 'Bait Cone N/S', + }, + baitEarth: { + en: 'Bait Cone N/S', }, }, }, @@ -3476,7 +3506,7 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B51D', source: 'Lindschrat', capture: true }, run: (data, matches) => { - switch (matches.id) { + switch (matches.sourceId) { case data.idyllicDreamActorEW: data.idyllicVision8SafeSides = 'frontBack'; return; @@ -3491,7 +3521,7 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B51D', source: 'Lindschrat', capture: true }, infoText: (data, matches, output) => { - switch (matches.id) { + switch (matches.sourceId) { case data.idyllicDreamActorEW: return output.frontBackLater!(); case data.idyllicDreamActorNS: @@ -3513,7 +3543,7 @@ const triggerSet: TriggerSet = { type: 'AbilityExtra', netRegex: { id: 'B4D9', capture: true }, run: (data, matches) => { - switch (matches.id) { + switch (matches.sourceId) { case data.idyllicDreamActorEW: data.idyllicVision7SafeSides = 'frontBack'; return; @@ -3711,6 +3741,13 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Arcadian Hell', + type: 'StartsUsing', + netRegex: { id: 'B533', source: 'Lindwurm', capture: false }, + durationSeconds: 4.7, + response: Responses.bigAoe('alert'), + }, ], timelineReplace: [ { From e4b1b8f9a3d8d7866655dcfa26bfc5bd88f42206 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 18:27:40 -0500 Subject: [PATCH 127/215] fix Replication 4 Ability Tethers Initial Call --- 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 e10b61aec78..8956891dc6f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2851,9 +2851,9 @@ const triggerSet: TriggerSet = { return output.getTether!(); } - if (first === headMarkerData['manaBurstTether']) - return output.stacksFirst!(); if (first === headMarkerData['heavySlamTether']) + return output.stacksFirst!(); + if (first === headMarkerData['manaBurstTether']) return output.defamationsFirst!(); return output.getTether!(); }, From 1614f23d12defb38f85d9e1449a92277c6e273bd Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 19:04:09 -0500 Subject: [PATCH 128/215] fix idyllicVision7SafePlatform it was set to where the add was, woops --- 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 8956891dc6f..322ea259ee1 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3552,7 +3552,7 @@ const triggerSet: TriggerSet = { return; case data.idyllicDreamActorSnaking: { const x = parseFloat(matches.x); - data.idyllicVision7SafePlatform = x < 100 ? 'west' : 'east'; + data.idyllicVision7SafePlatform = x < 100 ? 'east' : 'west'; } } }, From 67cd28f18a500d183e6bc34687066fe1e5154542 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 19:18:53 -0500 Subject: [PATCH 129/215] fix for no output Order of trigger here should mean this always fires after the collect and the collect will have stored the data before this fires. --- 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 322ea259ee1..7a46736334a 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3562,8 +3562,6 @@ const triggerSet: TriggerSet = { // Describe actor going into portal type: 'AbilityExtra', netRegex: { id: 'B4D9', capture: false }, - delaySeconds: 0.1, - suppressSeconds: 9999, infoText: (data, _matches, output) => { if (data.idyllicVision7SafeSides === 'frontBack') { if (data.idyllicVision7SafePlatform === 'east') From 7704ddea87379195a727d3705b7b2e83ff0cd595 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 19:25:28 -0500 Subject: [PATCH 130/215] fix for Twisted Vision 8 cleave call not working --- ui/raidboss/data/07-dt/raid/r12s.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7a46736334a..7851bf1c20e 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3723,13 +3723,16 @@ const triggerSet: TriggerSet = { // Trigger on Clone's BE5D Heavy Slam type: 'Ability', netRegex: { id: 'BE5D', source: 'Lindwurm', capture: false }, - suppressSeconds: 9999, alertText: (data, _matches, output) => { if (data.idyllicVision8SafeSides === 'sides') return output.sides!(); if (data.idyllicVision8SafeSides === 'frontBack') return output.frontBack!(); }, + run: (data) => { + // Prevent re-execution of output + delete data.idyllicVision8SafeSides; + }, outputStrings: { sides: { en: 'Sides of Clone', From 5a90be0ceefd7da021822ac9e799b83e718d35f0 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 19:35:47 -0500 Subject: [PATCH 131/215] remaining p2 timeline network log --- ui/raidboss/data/07-dt/raid/r12s.txt | 87 ++++++++++++++++------------ 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index c873e1e7b24..a96f6b5a2d9 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -342,7 +342,7 @@ hideall "--sync--" ### Phase 2: Lindwurm II # -p B528:3015.7 -# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 B4F5 B512 B513 B514 B515 +# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 B4F5 B512 B513 B514 B515 B4F9 B51B # -it "Lindwurm" 3000.5 label "r12s-p2-start" 3010.7 "--sync--" StartsUsing { id: "B528", source: "Lindwurm" } window 3100,10 @@ -429,7 +429,7 @@ hideall "--sync--" 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 +# Idyllic Dream 3268.8 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } 3275.0 "Staging" Ability { id: "B4E1", source: "Lindwurm" } 3276.3 "--clones x4 1--" #ActorControlExtra { category: "0197", param1: "11D2" } @@ -450,7 +450,7 @@ hideall "--sync--" 3326.1 "--tethers--" #Tether { id: ["0170", "0171"], source: "Lindschrat" } # These could change hands causing sync issue 3334.1 "--locked tethers--" Tether { id: "0175", source: "Lindschrat" } -# Towers Preview +# Twisted Vision 3: Towers Preview 3334.3 "Twisted Vision 3" Ability { id: "BBE2", source: "Lindwurm" } 3338.7 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } 3338.9 "Power Gusher x4" #Ability { id: "B516", source: "Lindwurm" } # Front/Back are apparently counting as their own casts @@ -459,7 +459,7 @@ hideall "--sync--" 3355.0 "Arcadian Arcanum (castbar)" Ability { id: "B529", source: "Lindwurm" } 3356.2 "Arcadian Arcanum" Ability { id: "B9D9", source: "Lindwurm" } -# First Stacks/Defamations +# Twisted Vision 4: First Stacks/Defamations # Orders could be different, but we can detect B517 abiltiy to know if Mana Burst is coming 1.2s before B518 3363.0 "Twisted Vision 4" Ability { id: "BBE2", source: "Lindwurm" } 3369.6 "Clone 1 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here @@ -474,8 +474,9 @@ hideall "--sync--" # Twisted Vision 5: Towers 3393.6 "Twisted Vision 5" Ability { id: "BBE2", source: "Lindwurm" } 3398.0 "Cosmic Kiss x8" Ability { id: "B4F4", source: "Lindwurm" } +3398.6 "--Hot-blooded x2--" duration 5 3398.7 "Lindwurm's Dark II x2" Ability { id: "B4F6", source: "Lindwurm" } -3400.7 "Pyretic Wurm x2" Ability { id: "B4F9", source: "Lindwurm" } +3398.7 "--Doom x2--" duration 8 3403.7 "Lindwurm's Stone III x2" #Ability { id: "B4F7", source: "Lindwurm" } 3408.7 "Lindwurm's Thunder II x4" #Ability { id: "B4FA", source: "Lindwurm" } 3408.7 "Lindwurm's Glare x4" #Ability { id: "B4F8", source: "Lindwurm" } @@ -483,39 +484,46 @@ hideall "--sync--" 3420.2 "--clone takes portal--" Ability { id: "B51D", source: "Lindschrat" } 3423.3 "--clones on platform--" Ability { id: "B4D9", source: "Lindschrat" } -# fflogs -3425.4 "Twisted Vision 6" Ability { id: "BBE2", source: "Lindwurm" } window 10,10 -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 7" Ability { id: "BBE2", source: "Lindwurm" } -3445.1 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } -3445.3 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } -3448.2 "Twisted Vision 8" 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" } +# Twisted Vision 6: Reenactment 2 Part 1 +# NOTE: Practical solution seems to be that you have x2 mana burts + x2 heavy slams +# This is because mana burts hits will knockback and heavy slams give Magic Vulns +# In theory you could do somehow get here and survive with: +# 3x Mana Burst + 1 Heavy Slam => 3x Heavy Slam + 1 Mana Burst or +# 3x Heavy Slam + 1 Mana Burst => 3x Mana Burst + 1 Heavy Slam +# But those would probably require lots of mit and tank immune probably on 2/3 of the heavy slams in the 3 set +3429.6 "Twisted Vision 6" Ability { id: "BBE2", source: "Lindwurm" } +3430.6 "Power Gusher" Ability { id: "B50F", source: "Lindschrat" } +3430.6 "Snaking Kick" Ability { id: "BCAF", source: "Lindschrat" } +3435.7 "Reenactment 2" Ability { id: "B4EC", source: "Lindwurm" } +3439.0 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } +3439.2 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } + +# Twisted Vision 7: Safe Platform + Front/Back or Sides Platform +3444.8 "Twisted Vision 7" Ability { id: "BBE2", source: "Lindwurm" } +3449.2 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } +3449.4 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } + +# Twisted Vision 8: Reenactment 2 Part 2 +3452.3 "Twisted Vision 8" Ability { id: "BBE2", source: "Lindwurm" } +3458.6 "--sync--" Ability { id: "B51E", source: "Lindschrat" } +3459.8 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } +3460.0 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } +3464.8 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } +3470.7 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } +3478.8 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3479.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } +3484.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3486.6 "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" } +3499.8 "Replication 5" Ability { id: "B46C", source: "Lindwurm" } +3513.2 "Arcadian Hell 1 (boss) " Ability { id: "B533", source: "Lindwurm" } +3513.2 "Arcadian Hell 1 x4 (clones)" #Ability { id: "B534", source: "Lindschrat" } +3529.4 "Arcadian Hell 2 (boss)" Ability { id: "B533", source: "Lindwurm" } +3529.4 "Arcadian Hell 2 x8 (clones)" #Ability { id: "B535", source: "Lindschrat" } +3542.3 "--sync--" StartsUsing { id: "B537", source: "Lindwurm" } +3552.3 "Arcadian Hell (Boss Enrage)" Ability { id: "B537", source: "Lindwurm" } +3552.3 "Arcadian Hell x16 (Clones Enrage)" #Ability { id: "BEC1", source: "Lindschrat" } # IGNORED ABILITIES # Phase 1 @@ -559,6 +567,8 @@ hideall "--sync--" # B513 Power Gusher: VFX during Twisted Vision 3, related to the B50F # B514 Power Gusher: VFX during Twisted Vision 3, related to the B510 # B515 Snaking Kick: VFX during Twisted Vision 3 +# B4F9 Pyretic Wurm: Damage suffered when player moves while under affect of 12A0 Hot-blooded +# B51B Power Gusher: VFX during Twisted Vision 8, related to B516 # ALL ENCOUNTER ABILITIES # Phase 1 @@ -624,6 +634,7 @@ hideall "--sync--" # B4D6 Visceral Burst # B4D7 The Fixer # B4F5 Unmitigated Explosion +# B4F9 Pyretic Wurm # B538 Refreshing Overkill: Enrage castbar # B539 Refreshing Overkill: Non-enrage # B53A Refreshing Overkill: Enrage @@ -682,6 +693,7 @@ hideall "--sync--" # B4F2 Lindwurm's Meteor # B4F3 Downfall # B4F4 Cosmic Kiss +# B4F5 Unmitigated Explosion # B4F6 Lindwurm's Dark II # B4F7 Lindwurm's Stone III # B4F8 Lindwurm's Glare @@ -708,11 +720,12 @@ hideall "--sync--" # B513 Power Gusher # B514 Power Gusher # B515 Snaking Kick -# B516 Power Gusher +# B516 Power Gusher: Cast during Twisted Vision 7 and 8 # B517 Mana Burst: VFX during Twisted Vision 4, happens 1.2s before B518, useful for sync branch # B518 Mana Burst # B519 Heavy Slam # B51A Power Gusher +# B51B Power Gusher # B51C Temporal Curtain # B51D --sync-- # B51E --sync-- From 8af3e69aa2432d61179529b7bb1efe76aa447698 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 20:01:35 -0500 Subject: [PATCH 132/215] remove extra space --- 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 a96f6b5a2d9..abc1d59339a 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -511,7 +511,7 @@ hideall "--sync--" 3464.8 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } 3470.7 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } 3478.8 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } -3479.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } +3479.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } 3484.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } 3486.6 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } From 90f4eb7d48d0ff62fc81f8ebe59cde29a7868115 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 20:55:13 -0500 Subject: [PATCH 133/215] add more notes on replication 1 patterns --- ui/raidboss/data/07-dt/raid/r12s.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7851bf1c20e..940bf437c4d 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1607,6 +1607,15 @@ const triggerSet: TriggerSet = { // (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 + // For first set there are two patterns that use these coordinates: + // (100, 86) + // (86, 100) (114, 100) + // (100, 114) + // Either N/S are clones casting Winged Scourge, or the E/W clones cast Winged Scourge + // Each pattern has its own pattern for IDs of the clones, in order + // N/S will have Fire -5 and -6 of its original + // E/W will have Fire -6 and -7 of its original + // Could use -6 to cover both cases, but that doesn't determine which add jumps first type: 'Ability', netRegex: { id: 'B4D9', source: 'Lindschrat', capture: true }, condition: (data, matches) => { From 24418ee245743783189f4fcdb4e1c088e2dc5315 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 21:02:18 -0500 Subject: [PATCH 134/215] add clarity on modulus and heading check --- ui/raidboss/data/07-dt/raid/r12s.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 940bf437c4d..eaa7c973d22 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1623,7 +1623,8 @@ const triggerSet: TriggerSet = { const pos = data.actorPositions[matches.sourceId]; if (pos === undefined) return false; - // These values should be 0 if coords are x.0000 + // These values should be 0 when x or y coord has non-zero decimal values + // Heading is also checked as the non fire clones all face a perfect heading const xFilter = pos.x % 1; const yFilter = pos.y % 1; if (xFilter === 0 && yFilter === 0 && pos.heading === -0.0001) From 9bc5978c10004d6a1cd496077e1c6c4c414b8d85 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 22:35:32 -0500 Subject: [PATCH 135/215] refactor replication2 Instead of a config, this just looks at the setup the players created and matches it to what the player needs to do. Additional triggers can now be added without config by checking the order in which the clones are setting off abilities. --- ui/raidboss/data/07-dt/raid/r12s.ts | 177 ++++++++++++++++++++-------- 1 file changed, 130 insertions(+), 47 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index eaa7c973d22..f8209acfc55 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -49,10 +49,14 @@ export interface Data extends RaidbossData { replicationCounter: number; replication1Debuff?: 'fire' | 'dark'; replication1FireActor?: string; + replication1FireActor2?: string; replication1FollowUp: boolean; - replication2TetherMap: { [dirNum: string]: string }; + replication2CloneDirNumPlayers: { [dirNum: number]: string }; + replication2DirNumAbility: { [dirNum: string]: string }; + replication2PlayerAbilities: { [player: string]: string }; replication2BossId?: string; - myReplication2Tether?: string; + replication2PlayerOrder: string[]; + replication2AbilityOrder: string[]; netherwrathFollowup: boolean; myMutation?: 'alpha' | 'beta'; manaSpheres: { @@ -167,7 +171,11 @@ const triggerSet: TriggerSet = { actorPositions: {}, replicationCounter: 0, replication1FollowUp: false, - replication2TetherMap: {}, + replication2CloneDirNumPlayers: {}, + replication2DirNumAbility: {}, + replication2PlayerAbilities: {}, + replication2PlayerOrder: [], + replication2AbilityOrder: [], netherwrathFollowup: false, manaSpheres: {}, westManaSpheres: {}, @@ -1770,7 +1778,22 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Replication 2 Tethered Clone', + id: 'R12S Staging 1 Tethered Clone Collect', + // Map the locations to a player name + type: 'Tether', + netRegex: { id: headMarkerData['lockedTether'], capture: true }, + condition: (data) => data.replicationCounter === 1, + 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.replication2CloneDirNumPlayers[dirNum] = matches.target; + }, + }, + { + id: 'R12S Staging 1 Tethered Clone', // Combatants are added ~4s before Staging starts casting // Same tether ID is used for "locked" ability tethers type: 'Tether', @@ -1820,7 +1843,7 @@ const triggerSet: TriggerSet = { return; const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); if (data.phase === 'replication2') - data.replication2TetherMap[dirNum] = matches.id; + data.replication2DirNumAbility[dirNum] = matches.id; if (data.phase === 'idyllic') data.replication4DirNumAbility[dirNum] = matches.id; }, @@ -1896,51 +1919,72 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Replication 2 Locked Tether 2 Collect', + id: 'R12S Replication 2 Locked Tether Collect', type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: true }, condition: (data, matches) => { if ( data.phase === 'replication2' && - data.replicationCounter === 2 && - data.me === matches.target + data.replicationCounter === 2 ) return true; return false; }, run: (data, matches) => { + const target = matches.target; + const sourceId = matches.sourceId; // Check if boss tether - if (data.replication2BossId === matches.sourceId) { - data.myReplication2Tether = headMarkerData['fireballSplashTether']; - return; - } + if (data.replication2BossId === sourceId) + data.replication2PlayerAbilities[target] = headMarkerData['fireballSplashTether']; + else if (data.replication2BossId !== sourceId) { + const actor = data.actorPositions[sourceId]; + if (actor === undefined) { + // Setting to use that we know we have a tether but couldn't determine what ability it is + data.replication2PlayerAbilities[target] = 'unknown'; + 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.replication2DirNumAbility[dirNum]; + if (ability === undefined) { + // Setting to use that we know we have a tether but couldn't determine what ability it is + data.replication2PlayerAbilities[target] = 'unknown'; + return; + } + data.replication2PlayerAbilities[target] = ability; } - const dirNum = Directions.xyTo8DirNum( - actor.x, - actor.y, - center.x, - center.y, - ); + // Create ability order once we have all 8 players + // If players had more than one tether previously, the extra tethers are randomly assigned + if (Object.keys(data.replication2PlayerAbilities).length === 7) { + // Fill in for player that had no tether, they are going to be boss' defamation + if (data.replication2PlayerAbilities[data.me] === undefined) + data.replication2PlayerAbilities[data.me] = 'none'; - // 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; + // Used for Twisted Vision 7 and 8 mechanics + const abilities = data.replication2PlayerAbilities; + const order = [0, 4, 1, 5, 2, 6, 3, 7]; // Order in which clones spawned, this is static + const players = data.replication2CloneDirNumPlayers; // Direction of player's clone + + // Mechanics are resolved clockwise + for (const dirNum of order) { + const player = players[dirNum] ?? 'unknown'; + const ability = abilities[player] ?? 'unknown'; + data.replication2PlayerOrder.push(player); + data.replication2AbilityOrder.push(ability); + } } - data.myReplication2Tether = ability; }, }, { - id: 'R12S Replication 2 Locked Tether 2', + id: 'R12S Replication 2 Locked Tether', type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: true }, condition: (data, matches) => { @@ -1954,16 +1998,18 @@ const triggerSet: TriggerSet = { }, delaySeconds: 0.1, infoText: (data, matches, output) => { + const sourceId = matches.sourceId; // Check if it's the boss - if (data.replication2BossId === matches.sourceId) + if (data.replication2BossId === sourceId) return output.fireballSplashTether!({ mech1: output.baitJump!(), }); // Get direction of the tether - const actor = data.actorPositions[matches.sourceId]; + const actor = data.actorPositions[sourceId]; + const ability = data.replication2PlayerAbilities[data.me]; if (actor === undefined) { - switch (data.myReplication2Tether) { + switch (ability) { case headMarkerData['projectionTether']: return output.projectionTether!({ mech1: output.baitProtean!(), @@ -1983,7 +2029,7 @@ const triggerSet: TriggerSet = { const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); const dir = Directions.output8Dir[dirNum] ?? 'unknown'; - switch (data.myReplication2Tether) { + switch (ability) { case headMarkerData['projectionTether']: return output.projectionTetherDir!({ dir: output[dir]!(), @@ -2046,7 +2092,10 @@ const triggerSet: TriggerSet = { delaySeconds: 0.2, suppressSeconds: 1, infoText: (data, _matches, output) => { - if (data.myReplication2Tether !== undefined) + if ( + data.replication2PlayerAbilities[data.me] !== 'none' || + data.replication2PlayerAbilities[data.me] === undefined + ) return; return output.noTether!({ mech1: output.defamationOnYou!(), @@ -2076,7 +2125,7 @@ const triggerSet: TriggerSet = { netRegex: { id: 'B4E7', source: 'Lindwurm', capture: false }, suppressSeconds: 1, alertText: (data, _matches, output) => { - const ability = data.myReplication2Tether; + const ability = data.replication2PlayerAbilities[data.me]; switch (ability) { case headMarkerData['projectionTether']: return output.projectionTether!({ @@ -2175,7 +2224,7 @@ const triggerSet: TriggerSet = { type: 'StartsUsing', netRegex: { id: ['B52E', 'B52F'], source: 'Lindwurm', capture: true }, infoText: (data, matches, output) => { - const ability = data.myReplication2Tether; + const ability = data.replication2PlayerAbilities[data.me]; const isNear = matches.id === 'B52E'; if (isNear) { @@ -2331,7 +2380,24 @@ const triggerSet: TriggerSet = { // NOTE: This is used with DN Strategy type: 'Ability', netRegex: { id: 'BBE3', source: 'Lindwurm', capture: false }, - condition: (data) => data.netherwrathFollowup, + condition: (data) => { + if (data.netherwrathFollowup) { + const order = data.replication2AbilityOrder; + const stack = headMarkerData['heavySlamTether']; + const defamation = headMarkerData['manaBurstTether']; + const projection = headMarkerData['projectionTether']; + // Defined as east/west clones with stacks and SW/NE with defamation + projection + if ( + order[4] === stack && order[5] === stack && + ( + (order[2] === defamation && order[3] === projection) || + (order[2] === projection && order[3] === defamation) + ) + ) + return true; + } + return false; + }, suppressSeconds: 9999, alertText: (_data, _matches, output) => output.text!(), outputStrings: { @@ -2347,7 +2413,24 @@ const triggerSet: TriggerSet = { // NOTE: This is used with DN Strategy type: 'Ability', netRegex: { id: 'BE5D', source: 'Lindwurm', capture: false }, - condition: (data) => data.netherwrathFollowup, + condition: (data) => { + if (data.netherwrathFollowup) { + const order = data.replication2AbilityOrder; + const stack = headMarkerData['heavySlamTether']; + const defamation = headMarkerData['manaBurstTether']; + const projection = headMarkerData['projectionTether']; + // Defined as east/west clones with stacks and NW/SE with defamation + projection + if ( + order[4] === stack && order[5] === stack && + ( + (order[6] === defamation && order[7] === projection) || + (order[7] === projection && order[6] === defamation) + ) + ) + return true; + } + return false; + }, suppressSeconds: 9999, alertText: (_data, _matches, output) => output.north!(), outputStrings: { @@ -2687,7 +2770,7 @@ const triggerSet: TriggerSet = { response: Responses.bigAoe('alert'), }, { - id: 'R12S Idyllic Dream Replication Clone Order Collect', + id: 'R12S Idyllic Dream Staging 2 Clone Order Collect', type: 'ActorControlExtra', netRegex: { category: '0197', param1: '11D2', capture: true }, condition: (data) => { @@ -2704,7 +2787,7 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Idyllic Dream Replication First Clone Cardinal/Intercardinal', + id: 'R12S Idyllic Dream Staging 2 First Clone Cardinal/Intercardinal', type: 'ActorControlExtra', netRegex: { category: '0197', param1: '11D2', capture: true }, condition: (data) => { @@ -2807,14 +2890,14 @@ const triggerSet: TriggerSet = { case 'B510': { const y = parseFloat(matches.y); data.idyllicVision2NorthSouthCleaveSpot = y < center.y ? 'north' : 'south'; - data.idyllicDreamActorEW = matches.id; + data.idyllicDreamActorEW = matches.sourceId; return; } case 'B511': - data.idyllicDreamActorSnaking = matches.id; + data.idyllicDreamActorSnaking = matches.sourceId; return; case 'B50F': - data.idyllicDreamActorNS = matches.id; + data.idyllicDreamActorNS = matches.sourceId; return; } }, @@ -2880,7 +2963,7 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Replication 4 Locked Tether 2 Collect', + id: 'R12S Replication 4 Locked Tether Collect', type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: true }, condition: (data) => { @@ -2943,7 +3026,7 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Replication 4 Locked Tether 2', + id: 'R12S Replication 4 Locked Tether', // 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', From 8643e49b934148b492243731a21eee2769d54acb Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 22:43:09 -0500 Subject: [PATCH 136/215] adjust second snaking kick, use grotesquerie timing --- ui/raidboss/data/07-dt/raid/r12s.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index f8209acfc55..bad1d73191c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1563,16 +1563,11 @@ const triggerSet: TriggerSet = { { id: 'R12S Snaking Kick', // Targets random player + // Second cast of this happens before Grotesquerie, delay until Grotesquerie to reduce chance of none projection players running into it type: 'StartsUsing', netRegex: { id: 'B527', source: 'Lindwurm', capture: true }, - condition: (data) => { - // Use Grotesquerie trigger for projection tethered players - const ability = data.myReplication2Tether; - if (ability === headMarkerData['projectionTether']) - return false; - return true; - }, delaySeconds: 0.1, // Need to delay for actor position update + suppressSeconds: 9999, alertText: (data, matches, output) => { const actor = data.actorPositions[matches.sourceId]; if (actor === undefined) @@ -2192,7 +2187,7 @@ const triggerSet: TriggerSet = { // 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(), + suppressSeconds: 9999, alertText: (data, _matches, output) => { // Get Boss facing const bossId = data.replication2BossId; From cf24c133c38eddfa8966ed727bc035937e5c71bc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 23:13:06 -0500 Subject: [PATCH 137/215] fixes and add config for Towers portent resolution --- ui/raidboss/data/07-dt/raid/r12s.ts | 115 +++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 12 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index bad1d73191c..5abc09e34f1 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -28,6 +28,7 @@ type DirectionIntercard = Exclude; export interface Data extends RaidbossData { readonly triggerSetConfig: { uptimeKnockbackStrat: true | false; + portentStrategy: 'dn' | 'zenith' | 'none'; }; phase: Phase; // Phase 1 @@ -156,6 +157,21 @@ const triggerSet: TriggerSet = { type: 'checkbox', default: false, }, + { + id: 'portentStrategy', + name: { + en: 'Phase 2 Tower Portent Resolution Strategy', + }, + type: 'select', + options: { + en: { + 'DN Strategy: Dark N Hitbox, Wind Middle Hitbox, Earth/Fire N/S Max Melee': 'dn', + 'Zenith Strategy: Wind N Max Melee, Earth/Dark Middle (Lean North), Fire S Max Melee': 'zenith', + 'No strategy: call element and debuff': 'none', + }, + }, + default: 'none', + }, ], timelineFile: 'r12s.txt', initData: () => ({ @@ -2186,7 +2202,7 @@ const triggerSet: TriggerSet = { // 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 }, + netRegex: { id: 'B4EA', source: 'Lindwurm', capture: false }, suppressSeconds: 9999, alertText: (data, _matches, output) => { // Get Boss facing @@ -2389,7 +2405,7 @@ const triggerSet: TriggerSet = { (order[2] === projection && order[3] === defamation) ) ) - return true; + return true; } return false; }, @@ -2422,7 +2438,7 @@ const triggerSet: TriggerSet = { (order[7] === projection && order[6] === defamation) ) ) - return true; + return true; } return false; }, @@ -3543,27 +3559,77 @@ const triggerSet: TriggerSet = { delaySeconds: (_data, matches) => parseFloat(matches.duration) - 5.3, infoText: (data, matches, output) => { if (matches.id === '129E') { - if (data.hasDoom) + if (data.hasDoom) { + switch (data.triggerSetConfig.portentStrategy) { + case 'dn': + return output.farOnYouDarkDN!(); + case 'zenith': + return output.farOnYouDarkZenith!(); + } return output.farOnYouDark!(); + } + switch (data.triggerSetConfig.portentStrategy) { + case 'dn': + return output.farOnYouWindDN!(); + case 'zenith': + return output.farOnYouWindZenith!(); + } return output.farOnYouWind!(); } - if (data.hasDoom) + if (data.hasDoom) { + switch (data.triggerSetConfig.portentStrategy) { + case 'dn': + return output.nearOnYouDarkDN!(); + case 'zenith': + return output.nearOnYouDarkZenith!(); + } return output.nearOnYouDark!(); + } + switch (data.triggerSetConfig.portentStrategy) { + case 'dn': + return output.nearOnYouWindDN!(); + case 'zenith': + return output.nearOnYouWindZenith!(); + } return output.nearOnYouWind!(); }, outputStrings: { - nearOnYouWind: { + nearOnYouWindDN: { en: 'Near on YOU: Be on Middle Hitbox', }, - nearOnYouDark: { + nearOnYouDarkDN: { en: 'Near on YOU: Be on Hitbox N', }, - farOnYouWind: { + farOnYouWindDN: { en: 'Far on YOU: Be on Middle Hitbox', }, - farOnYouDark: { + farOnYouDarkDN: { en: 'Far on YOU: Be on Hitbox N', }, + nearOnYouWindZenith: { + en: 'Near on YOU: Max Melee N', + }, + nearOnYouDarkZenith: { + en: 'Near on YOU: Be on Middle Hitbox (Lean North)', + }, + farOnYouWindZenith: { + en: 'Far on YOU: Max Melee N', + }, + farOnYouDarkZenith: { + en: 'Far on YOU: Be on Middle Hitbox (Lean North)', + }, + nearOnYouWind: { + en: 'Wind: Near on YOU', + }, + nearOnYouDark: { + en: 'Dark: Near on YOU', + }, + farOnYouWind: { + en: 'Wind: Far on YOU', + }, + farOnYouDark: { + en: 'Dark: Far on YOU', + }, }, }, { @@ -3575,16 +3641,41 @@ const triggerSet: TriggerSet = { delaySeconds: (_data, matches) => parseFloat(matches.duration) - 5.3, suppressSeconds: 1, infoText: (data, _matches, output) => { - if (data.hasPyretic) + if (data.hasPyretic) { + switch (data.triggerSetConfig.portentStrategy) { + case 'dn': + return output.baitFireDN!(); + case 'zenith': + return output.baitFireZenith!(); + } return output.baitFire!(); + } + switch (data.triggerSetConfig.portentStrategy) { + case 'dn': + return output.baitEarthDN!(); + case 'zenith': + return output.baitEarthZenith!(); + } return output.baitEarth!(); }, outputStrings: { + baitFireDN: { + en: 'Bait Cone N/S Max Melee', + }, + baitEarthDN: { + en: 'Bait Cone N/S Max Melee', + }, + baitFireZenith: { + en: 'Bait Cone S, Max Melee', + }, + baitEarthZenith: { + en: 'Bait Cone Middle, Max Melee (Lean North)', + }, baitFire: { - en: 'Bait Cone N/S', + en: 'Fire: Bait Cone', }, baitEarth: { - en: 'Bait Cone N/S', + en: 'Earth: Bait Cone', }, }, }, From b07e8600ae1a14af763dc708cc6d8c4b90e29d9a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 23:16:40 -0500 Subject: [PATCH 138/215] lint --- 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 5abc09e34f1..105151052d2 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -166,7 +166,8 @@ const triggerSet: TriggerSet = { options: { en: { 'DN Strategy: Dark N Hitbox, Wind Middle Hitbox, Earth/Fire N/S Max Melee': 'dn', - 'Zenith Strategy: Wind N Max Melee, Earth/Dark Middle (Lean North), Fire S Max Melee': 'zenith', + 'Zenith Strategy: Wind N Max Melee, Earth/Dark Middle (Lean North), Fire S Max Melee': + 'zenith', 'No strategy: call element and debuff': 'none', }, }, @@ -3577,7 +3578,7 @@ const triggerSet: TriggerSet = { return output.farOnYouWind!(); } if (data.hasDoom) { - switch (data.triggerSetConfig.portentStrategy) { + switch (data.triggerSetConfig.portentStrategy) { case 'dn': return output.nearOnYouDarkDN!(); case 'zenith': From eda9360a47889847e5bd008d53ab90327dab9b86 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 2 Feb 2026 23:24:11 -0500 Subject: [PATCH 139/215] remove 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 105151052d2..84b26c61271 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1934,7 +1934,7 @@ const triggerSet: TriggerSet = { id: 'R12S Replication 2 Locked Tether Collect', type: 'Tether', netRegex: { id: headMarkerData['lockedTether'], capture: true }, - condition: (data, matches) => { + condition: (data) => { if ( data.phase === 'replication2' && data.replicationCounter === 2 From 044b2b64a32b7b6dc829ccb77268092e036717fd Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 3 Feb 2026 17:49:15 -0500 Subject: [PATCH 140/215] fix replication2DirNumAbility being defined as dirNum: string not quite sure how I missed this and it was working, but it is supposed ton be a number... --- 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 84b26c61271..0f0e2d3fd54 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -53,7 +53,7 @@ export interface Data extends RaidbossData { replication1FireActor2?: string; replication1FollowUp: boolean; replication2CloneDirNumPlayers: { [dirNum: number]: string }; - replication2DirNumAbility: { [dirNum: string]: string }; + replication2DirNumAbility: { [dirNum: number]: string }; replication2PlayerAbilities: { [player: string]: string }; replication2BossId?: string; replication2PlayerOrder: string[]; From 2f41a4c38fe3a721948e3135bf4435b50cd90eeb Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 3 Feb 2026 18:02:06 -0500 Subject: [PATCH 141/215] replication 4 initial tethers as 8 customizable outputs Using replication 3 tether direction. --- ui/raidboss/data/07-dt/raid/r12s.ts | 109 +++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 9 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 0f0e2d3fd54..36c2a9bd60f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2956,21 +2956,112 @@ const triggerSet: TriggerSet = { return output.getTether!(); } - if (first === headMarkerData['heavySlamTether']) - return output.stacksFirst!(); - if (first === headMarkerData['manaBurstTether']) - return output.defamationsFirst!(); - return output.getTether!(); + const mech = first === headMarkerData['heavySlamTether'] + ? 'stacks' + : first === headMarkerData['manaBurstTether'] + ? 'defamations' + : 'unknown'; + + const clones = data.replication3CloneDirNumPlayers; + const myDirNum = Object.keys(clones).find( + (key) => clones[parseInt(key)] === data.me + ); + if (myDirNum !== undefined) { + // Get dirNum of player for custom output based on replication 3 tether + // Player can replace the get tether with get defamation, get stack and + // the location they want based on custom plan + switch (parseInt(myDirNum)) { + case 0: + return output.mechLaterNClone!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); + case 1: + return output.mechLaterNEClone!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); + case 2: + return output.mechLaterEClone!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); + case 3: + return output.mechLaterSEClone!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); + case 4: + return output.mechLaterSClone!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); + case 5: + return output.mechLaterSWClone!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); + case 6: + return output.mechLaterWClone!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); + case 7: + return output.mechLaterNWClone!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); + } + } + + return output.mechLaterTether!({ + later: output.mechLater!({ mech: output[mech]!() }), + tether: output.getTether!(), + }); }, outputStrings: { getTether: { en: 'Get Tether', }, - defamationsFirst: { - en: 'Defamations First (later); Get Tether', + mechLater: { + en: '${mech} First (later)', + }, + defamations: { + en: 'Defamations', + de: 'Große AoE auf dir', + fr: 'Grosse AoE sur vous', + ja: '自分に巨大な爆発', + cn: '大圈点名', + ko: '광역 대상자', + tc: '大圈點名', + }, + stacks: Outputs.stacks, + mechLaterTether: { + en: '${later}; ${tether}', + }, + mechLaterNClone: { + en: '${later}; ${tether}', + }, + mechLaterNEClone: { + en: '${later}; ${tether}', + }, + mechLaterEClone: { + en: '${later}; ${tether}', + }, + mechLaterSEClone: { + en: '${later}; ${tether}', + }, + mechLaterSClone: { + en: '${later}; ${tether}', + }, + mechLaterSWClone: { + en: '${later}; ${tether}', + }, + mechLaterWClone: { + en: '${later}; ${tether}', }, - stacksFirst: { - en: 'Stacks First (later); Get Tether', + mechLaterNWClone: { + en: '${later}; ${tether}', }, }, }, From 0e32cdf11d98fa604f3f4d37b714f240cf31ce3a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 3 Feb 2026 18:05:21 -0500 Subject: [PATCH 142/215] 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 36c2a9bd60f..f360eb88548 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2964,7 +2964,7 @@ const triggerSet: TriggerSet = { const clones = data.replication3CloneDirNumPlayers; const myDirNum = Object.keys(clones).find( - (key) => clones[parseInt(key)] === data.me + (key) => clones[parseInt(key)] === data.me, ); if (myDirNum !== undefined) { // Get dirNum of player for custom output based on replication 3 tether From be63a3c4ea148ba6ee8a3b4776bb60c06eed356c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 3 Feb 2026 19:38:26 -0500 Subject: [PATCH 143/215] replication 2 add additional 8 outputs for customization From staging 1 clones --- ui/raidboss/data/07-dt/raid/r12s.ts | 302 ++++++++++++++++++++++++++-- 1 file changed, 284 insertions(+), 18 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index f360eb88548..cb02033c8d8 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -54,6 +54,7 @@ export interface Data extends RaidbossData { replication1FollowUp: boolean; replication2CloneDirNumPlayers: { [dirNum: number]: string }; replication2DirNumAbility: { [dirNum: number]: string }; + replication2hasInitialAbilityTether: boolean; replication2PlayerAbilities: { [player: string]: string }; replication2BossId?: string; replication2PlayerOrder: string[]; @@ -190,6 +191,7 @@ const triggerSet: TriggerSet = { replication1FollowUp: false, replication2CloneDirNumPlayers: {}, replication2DirNumAbility: {}, + replication2hasInitialAbilityTether: false, replication2PlayerAbilities: {}, replication2PlayerOrder: [], replication2AbilityOrder: [], @@ -1834,13 +1836,13 @@ const triggerSet: TriggerSet = { { 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', netRegex: { id: [ headMarkerData['projectionTether'], headMarkerData['manaBurstTether'], headMarkerData['heavySlamTether'], + headMarkerData['fireballSplashTether'], ], capture: true, }, @@ -1854,8 +1856,13 @@ const triggerSet: TriggerSet = { if (actor === undefined) return; const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); - if (data.phase === 'replication2') - data.replication2DirNumAbility[dirNum] = matches.id; + if (data.phase === 'replication2') { + // Handle boss tether separately as its direction location is unimportant + if (matches.id !== headMarkerData['fireballSplashTether']) + data.replication2DirNumAbility[dirNum] = matches.id; + if (data.me === matches.target) + data.replication2hasInitialAbilityTether = true; + } if (data.phase === 'idyllic') data.replication4DirNumAbility[dirNum] = matches.id; }, @@ -1876,34 +1883,179 @@ 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) => { - if (matches.id === headMarkerData['fireballSplashTether']) + const id = matches.id; + const clones = data.replication2CloneDirNumPlayers; + const myDirNum = Object.keys(clones).find( + (key) => clones[parseInt(key)] === data.me, + ); + + if (id === headMarkerData['fireballSplashTether']) { + if (myDirNum !== undefined) { + // Get dirNum of player for custom output based on replication 3 tether + // Player can replace the get tether with get defamation, get stack and + // the location they want based on custom plan + switch (parseInt(myDirNum)) { + case 0: + return output.tetherGetTether!({ + tether1: output.fireballSplashTether!(), + tether2: output.getTetherNClone!({ tether: output.getTether!() }), + }); + case 1: + return output.tetherGetTether!({ + tether1: output.fireballSplashTether!(), + tether2: output.getTetherNEClone!({ tether: output.getTether!() }), + }); + case 2: + return output.tetherGetTether!({ + tether1: output.fireballSplashTether!(), + tether2: output.getTetherEClone!({ tether: output.getTether!() }), + }); + case 3: + return output.tetherGetTether!({ + tether1: output.fireballSplashTether!(), + tether2: output.getTetherSEClone!({ tether: output.getTether!() }), + }); + case 4: + return output.tetherGetTether!({ + tether1: output.fireballSplashTether!(), + tether2: output.getTetherSClone!({ tether: output.getTether!() }), + }); + case 5: + return output.tetherGetTether!({ + tether1: output.fireballSplashTether!(), + tether2: output.getTetherSWClone!({ tether: output.getTether!() }), + }); + case 6: + return output.tetherGetTether!({ + tether1: output.fireballSplashTether!(), + tether2: output.getTetherWClone!({ tether: output.getTether!() }), + }); + case 7: + return output.tetherGetTether!({ + tether1: output.fireballSplashTether!(), + tether2: output.getTetherNWClone!({ tether: output.getTether!() }), + }); + } + } return output.fireballSplashTether!(); + } // Get direction of the tether const actor = data.actorPositions[matches.sourceId]; + const tether = id === headMarkerData['heavySlamTether'] + ? 'heavySlamTether' + : id === headMarkerData['manaBurstTether'] + ? 'manaBurstTether' + : id === headMarkerData['projectionTether'] + ? 'projectionTether' + : 'unknown'; if (actor === undefined) { - switch (matches.id) { - case headMarkerData['projectionTether']: - return output.projectionTether!(); - case headMarkerData['manaBurstTether']: - return output.manaBurstTether!(); - case headMarkerData['heavySlamTether']: - return output.heavySlamTether!(); + if (myDirNum !== undefined && tether !== 'unknown') { + // Get dirNum of player for custom output based on replication 3 tether + // Player can replace the get tether with get defamation, get stack and + // the location they want based on custom plan + + switch (parseInt(myDirNum)) { + case 0: + return output.tetherGetTether!({ + tether1: output[tether]!(), + tether2: output.getTetherNClone!({ tether: output.getTether!() }), + }); + case 1: + return output.tetherGetTether!({ + tether1: output[tether]!(), + tether2: output.getTetherNEClone!({ tether: output.getTether!() }), + }); + case 2: + return output.tetherGetTether!({ + tether1: output[tether]!(), + tether2: output.getTetherEClone!({ tether: output.getTether!() }), + }); + case 3: + return output.tetherGetTether!({ + tether1: output[tether]!(), + tether2: output.getTetherSEClone!({ tether: output.getTether!() }), + }); + case 4: + return output.tetherGetTether!({ + tether1: output[tether]!(), + tether2: output.getTetherSClone!({ tether: output.getTether!() }), + }); + case 5: + return output.tetherGetTether!({ + tether1: output[tether]!(), + tether2: output.getTetherSWClone!({ tether: output.getTether!() }), + }); + case 6: + return output.tetherGetTether!({ + tether1: output[tether]!(), + tether2: output.getTetherWClone!({ tether: output.getTether!() }), + }); + case 7: + return output.tetherGetTether!({ + tether1: output[tether]!(), + tether2: output.getTetherNWClone!({ tether: output.getTether!() }), + }); + } } + if (tether !== 'unknown') + return output[tether]!(); return; } const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); const dir = Directions.output8Dir[dirNum] ?? 'unknown'; + const tetherDir = `${tether}Dir`; - switch (matches.id) { - case headMarkerData['projectionTether']: - return output.projectionTetherDir!({ dir: output[dir]!() }); - case headMarkerData['manaBurstTether']: - return output.manaBurstTetherDir!({ dir: output[dir]!() }); - case headMarkerData['heavySlamTether']: - return output.heavySlamTetherDir!({ dir: output[dir]!() }); + if (myDirNum !== undefined && tether !== 'unknown') { + // Get dirNum of player for custom output based on replication 3 tether + // Player can replace the get tether with get defamation, get stack and + // the location they want based on custom plan + switch (parseInt(myDirNum)) { + case 0: + return output.tetherGetTether!({ + tether1: output[tetherDir]!({ dir: output[dir]!() }), + tether2: output.getTetherNClone!({ tether: output.getTether!() }), + }); + case 1: + return output.tetherGetTether!({ + tether1: output[tetherDir]!({ dir: output[dir]!() }), + tether2: output.getTetherNEClone!({ tether: output.getTether!() }), + }); + case 2: + return output.tetherGetTether!({ + tether1: output[tetherDir]!({ dir: output[dir]!() }), + tether2: output.getTetherEClone!({ tether: output.getTether!() }), + }); + case 3: + return output.tetherGetTether!({ + tether1: output[tetherDir]!({ dir: output[dir]!() }), + tether2: output.getTetherSEClone!({ tether: output.getTether!() }), + }); + case 4: + return output.tetherGetTether!({ + tether1: output[tetherDir]!({ dir: output[dir]!() }), + tether2: output.getTetherSClone!({ tether: output.getTether!() }), + }); + case 5: + return output.tetherGetTether!({ + tether1: output[tetherDir]!({ dir: output[dir]!() }), + tether2: output.getTetherSWClone!({ tether: output.getTether!() }), + }); + case 6: + return output.tetherGetTether!({ + tether1: output[tetherDir]!({ dir: output[dir]!() }), + tether2: output.getTetherWClone!({ tether: output.getTether!() }), + }); + case 7: + return output.tetherGetTether!({ + tether1: output[tetherDir]!({ dir: output[dir]!() }), + tether2: output.getTetherNWClone!({ tether: output.getTether!() }), + }); + } } + + return output[tetherDir]!({ dir: output[dir]!() }); }, outputStrings: { ...Directions.outputStrings8Dir, @@ -1928,6 +2080,120 @@ const triggerSet: TriggerSet = { fireballSplashTether: { en: 'Boss Tether on YOU', }, + tetherGetTether: { + en: '${tether1}; ${tether2}', + }, + getTether: { + en: 'Get Tether', + }, + getTetherNClone: { + en: '${tether}', + }, + getTetherNEClone: { + en: '${tether}', + }, + getTetherEClone: { + en: '${tether}', + }, + getTetherSEClone: { + en: '${tether}', + }, + getTetherSClone: { + en: '${tether}', + }, + getTetherSWClone: { + en: '${tether}', + }, + getTetherWClone: { + en: '${tether}', + }, + getTetherNWClone: { + en: '${tether}', + }, + }, + }, + { + id: 'R12S Replication 2 Ability Tethers Initial Call (No Tether)', + type: 'Tether', + netRegex: { id: headMarkerData['fireballSplashTether'], capture: false }, + delaySeconds: 0.1, + suppressSeconds: 9999, // Possible that this changes hands within an instant + infoText: (data, _matches, output) => { + if (data.replication2hasInitialAbilityTether) + return; + const clones = data.replication2CloneDirNumPlayers; + const myDirNum = Object.keys(clones).find( + (key) => clones[parseInt(key)] === data.me, + ); + if (myDirNum !== undefined) { + // Get dirNum of player for custom output based on replication 3 tether + // Player can replace the get tether with get defamation, get stack and + // the location they want based on custom plan + switch (parseInt(myDirNum)) { + case 0: + return output.noTetherCloneN!({ + noTether: output.noTether!(), + }); + case 1: + return output.noTetherCloneNE!({ + noTether: output.noTether!(), + }); + case 2: + return output.noTetherCloneE!({ + noTether: output.noTether!(), + }); + case 3: + return output.noTetherCloneSE!({ + noTether: output.noTether!(), + }); + case 4: + return output.noTetherCloneS!({ + noTether: output.noTether!(), + }); + case 5: + return output.noTetherCloneSW!({ + noTether: output.noTether!(), + }); + case 6: + return output.noTetherCloneW!({ + noTether: output.noTether!(), + }); + case 7: + return output.noTetherCloneNW!({ + noTether: output.noTether!(), + }); + } + } + return output.noTether!(); + }, + outputStrings: { + noTether: { + en: 'No Tether on YOU', + }, + noTetherCloneN: { + en: '${noTether}', + }, + noTetherCloneNE: { + en: '${noTether}', + }, + noTetherCloneE: { + en: '${noTether}', + }, + noTetherCloneSE: { + en: '${noTether}', + }, + noTetherCloneS: { + en: '${noTether}', + }, + noTetherCloneSW: { + en: '${noTether}', + }, + noTetherCloneW: { + en: '${noTether}', + }, + noTetherCloneNW: { + en: '${noTether}', + }, }, }, { From db27320c0eca03d03b032600264eea8f23995a97 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Feb 2026 17:23:20 -0500 Subject: [PATCH 144/215] update initial call with TTS overrides --- ui/raidboss/data/07-dt/raid/r12s.ts | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index cb02033c8d8..02817ab8778 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -630,6 +630,37 @@ const triggerSet: TriggerSet = { return output.beta4!(); } }, + tts: (data, _matches, output) => { + // Greek characters may be the best TTS + 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.alpha1Tts!(); + case 2: + return output.alpha2Tts!(); + case 3: + return output.alpha3Tts!(); + case 4: + return output.alpha4Tts!(); + } + } + switch (myNum) { + case 1: + return output.beta1Tts!(); + case 2: + return output.beta2Tts!(); + case 3: + return output.beta3Tts!(); + case 4: + return output.beta4Tts!(); + } + }, outputStrings: { alpha1: { en: '1α: Wait for Tether 1', @@ -655,6 +686,30 @@ const triggerSet: TriggerSet = { beta4: { en: '4β: Chain Tower 2', }, + alpha1Tts: { + en: '1α: Wait for Tether 1', + }, + alpha2Tts: { + en: '2α: Wait for Tether 2', + }, + alpha3Tts: { + en: '3α: Blob Tower 1', + }, + alpha4Tts: { + en: '4α: Blob Tower 2', + }, + beta1Tts: { + en: '1β: Wait for Tether 1', + }, + beta2Tts: { + en: '2β: Wait for Tether 2', + }, + beta3Tts: { + en: '3β: Chain Tower 1', + }, + beta4Tts: { + en: '4β: Chain Tower 2', + }, order: { en: '${num}', de: '${num}', From 88301e76636ac81ec8302e967226eb6e735d9b99 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Feb 2026 17:27:59 -0500 Subject: [PATCH 145/215] add tts overrides for Mutation alpha/beta call --- ui/raidboss/data/07-dt/raid/r12s.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 02817ab8778..c45df614bf4 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2827,6 +2827,11 @@ const triggerSet: TriggerSet = { return output.alpha!(); return output.beta!(); }, + tts: (_data, matches, output) => { + if (matches.effectId === '12A1') + return output.alphaTts!(); + return output.betaTts!(); + }, outputStrings: { alpha: { en: 'Mutation α on YOU', @@ -2834,6 +2839,12 @@ const triggerSet: TriggerSet = { beta: { en: 'Mutation β on YOU', }, + alphaTts: { + en: 'Mutation α on YOU', + }, + betaTts: { + en: 'Mutation β on YOU', + }, }, }, { From a077ea5b14a63808ade2fda3764da90422efd291 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Feb 2026 17:30:15 -0500 Subject: [PATCH 146/215] additiona tts overrides for netherworld beta --- ui/raidboss/data/07-dt/raid/r12s.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index c45df614bf4..6297ca67643 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3087,6 +3087,15 @@ const triggerSet: TriggerSet = { ? output.betaFar!({ mech: output.maxMelee!() }) : output.alphaFar!({ mech: output.getUnder!() }); }, + tts: (data, matches, output) => { + if (matches.id === 'B52B') + return data.myMutation === 'beta' + ? output.betaNearTts!({ mech: output.getUnder!() }) + : output.alphaNear!({ mech: output.maxMelee!() }); + return data.myMutation === 'beta' + ? output.betaFarTts!({ mech: output.maxMelee!() }) + : output.alphaFar!({ mech: output.getUnder!() }); + }, outputStrings: { getUnder: Outputs.getUnder, maxMelee: { @@ -3104,6 +3113,12 @@ const triggerSet: TriggerSet = { betaFar: { en: 'Far β Stack: ${mech}', }, + betaNearTts: { + en: 'Near β Stack: ${mech}', + }, + betaFarTts: { + en: 'Far β Stack: ${mech}', + }, }, }, { From e21b1dd21fdb0919c8ca170a2fa41d5705430d6c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 8 Feb 2026 15:46:39 -0500 Subject: [PATCH 147/215] add fixer startsUsing sync, grand entrance duration, mortal slayer sync --- ui/raidboss/data/07-dt/raid/r12s.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index abc1d59339a..451a461c065 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -12,6 +12,7 @@ hideall "--sync--" 0.0 "--sync--" InCombat { inGameCombat: "1" } window 0,1 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. +10.6 "--sync--" StartsUsing { id: "B4D7", source: "Lindwurm" } window 15,10 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 b68850601c869461ce7f44d3737ed9817f5197dc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 8 Feb 2026 16:20:28 -0500 Subject: [PATCH 148/215] adjust alpha blob tower location timing using startsUsingExtra 3s earlier --- ui/raidboss/data/07-dt/raid/r12s.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 6297ca67643..8405da1b634 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -724,7 +724,7 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Phagocyte Spotlight Blob Tower Location Collect', - // StartsUsing and StartsUsingExtra can have bad data, there is enough time that Ability is sufficient + // StartsUsing can have bad data // Pattern 1 // Blob 1: (104, 104) SE Inner // Blob 2: (96, 96) NW Inner @@ -745,7 +745,7 @@ const triggerSet: TriggerSet = { // Blob 2: (104, 96) NE Inner // Blob 3: (115, 110) SE Outer // Blob 4: (86, 90) NW Outer - type: 'Ability', + type: 'StartsUsingExtra', netRegex: { id: 'B4B6', capture: true }, suppressSeconds: 10, run: (data, matches) => { @@ -777,7 +777,7 @@ const triggerSet: TriggerSet = { 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', + type: 'StartsUsingExtra', netRegex: { id: 'B4B6', capture: false }, condition: (data) => data.myFleshBonds === 'alpha', delaySeconds: 0.1, @@ -786,13 +786,13 @@ const triggerSet: TriggerSet = { // Timings based on next trigger switch (myNum) { case 1: - return 17; + return 20; case 2: - return 22; + return 25; case 3: - return 18; + return 21; case 4: - return 18; + return 21; } }, suppressSeconds: 10, From d1074102847726848b0462a420f3aa452db4f4bf Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 8 Feb 2026 16:25:23 -0500 Subject: [PATCH 149/215] remove conditions on Actor trackers --- ui/raidboss/data/07-dt/raid/r12s.ts | 36 +++++------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 8405da1b634..e552a0348db 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -278,18 +278,10 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Phase Two ActorSetPos Tracker', + id: 'R12S ActorSetPos Tracker', + // Only in use for replication 1, 2, and idyllic phases 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), @@ -298,18 +290,10 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Phase Two ActorMove Tracker', + id: 'R12S ActorMove Tracker', + // Only in use for replication 1, 2, and idyllic phases 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), @@ -318,18 +302,10 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Phase Two AddedCombatant Tracker', + id: 'R12S AddedCombatant Tracker', + // Only in use for replication 1, 2, and idyllic phases 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), From d2dba608a438006387a499856cab9b3827f2a025 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 8 Feb 2026 16:35:39 -0500 Subject: [PATCH 150/215] blobTowerDirs string[] => DirectionOutputIntercard[] --- 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 e552a0348db..7e5513dfdb6 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -39,7 +39,7 @@ export interface Data extends RaidbossData { | 'rearCleave'; myFleshBonds?: 'alpha' | 'beta'; inLine: { [name: string]: number }; - blobTowerDirs: string[]; + blobTowerDirs: DirectionOutputIntercard[]; fleshBondsCount: number; skinsplitterCount: number; cellChainCount: number; From de97c5e278c15cc3dba2c37567fa77034f83545f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 8 Feb 2026 16:41:59 -0500 Subject: [PATCH 151/215] use modulus instead of isCard/isIntercard --- ui/raidboss/data/07-dt/raid/r12s.ts | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 7e5513dfdb6..a7c69779528 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3,8 +3,6 @@ import { UnreachableCode } from '../../../../../resources/not_reached'; import Outputs from '../../../../../resources/outputs'; import { Responses } from '../../../../../resources/responses'; import { - DirectionOutput8, - DirectionOutputCardinal, DirectionOutputIntercard, Directions, } from '../../../../../resources/util'; @@ -22,9 +20,6 @@ export type Phase = | 'idyllic' | 'reenactment2'; -type DirectionCardinal = Exclude; -type DirectionIntercard = Exclude; - export interface Data extends RaidbossData { readonly triggerSetConfig: { uptimeKnockbackStrat: true | false; @@ -126,14 +121,6 @@ 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, @@ -3137,16 +3124,12 @@ const triggerSet: TriggerSet = { return; const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); - const dir = Directions.output8Dir[dirNum] ?? 'unknown'; - if (isCardinalDir(dir)) + if (dirNum % 2 === 0) return output.firstClone!({ cards: output.cardinals!() }); - if (isIntercardDir(dir)) - return output.firstClone!({ cards: output.intercards!() }); - return output.firstClone!({ cards: output.unknown!() }); + return output.firstClone!({ cards: output.intercards!() }); }, outputStrings: { - unknown: Outputs.unknown, cardinals: Outputs.cardinals, intercards: Outputs.intercards, firstClone: { From e983d0699e3e9d8e9aefca26abf57ae21a1bb568 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 8 Feb 2026 16:44:49 -0500 Subject: [PATCH 152/215] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index a7c69779528..4254a6f0907 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2,10 +2,7 @@ import Conditions from '../../../../../resources/conditions'; import { UnreachableCode } from '../../../../../resources/not_reached'; import Outputs from '../../../../../resources/outputs'; import { Responses } from '../../../../../resources/responses'; -import { - DirectionOutputIntercard, - Directions, -} from '../../../../../resources/util'; +import { DirectionOutputIntercard, Directions } from '../../../../../resources/util'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; From 8d1c58d89edf997d4d0a0f65c46cc0023259667f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 8 Feb 2026 17:09:01 -0500 Subject: [PATCH 153/215] add todos to top --- ui/raidboss/data/07-dt/raid/r12s.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 4254a6f0907..8e2d0f9eff4 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -7,6 +7,15 @@ import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; +// TODO: Mortal Coil calls +// TODO: Cursed Coil Counterclock/clockwise call +// TODO: Cursed Coil break directions +// TODO: Separate Split Scourge and Venomous Scourge triggers +// TODO: Safe spots for Curtain Call's Unbreakable flesh +// TODO: Safe spots for Slaughtershed Stack/Spreads +// TODO: Twisted Vision 5 Tower spots +// TODO: Twisted Vision 5 Lindwurm\'s Stone III (Earth Tower) locations + export type Phase = | 'doorboss' | 'curtainCall' From 4ebec52d3494d1f1aeed05ed9749fe55590654b1 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 8 Feb 2026 17:32:15 -0500 Subject: [PATCH 154/215] use Number.EPSILON for floating point differences --- ui/raidboss/data/07-dt/raid/r12s.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 8e2d0f9eff4..213ed04c87d 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1673,7 +1673,8 @@ const triggerSet: TriggerSet = { // Heading is also checked as the non fire clones all face a perfect heading const xFilter = pos.x % 1; const yFilter = pos.y % 1; - if (xFilter === 0 && yFilter === 0 && pos.heading === -0.0001) + const hdgFilter = Math.abs(pos.heading - 0.0001) < Number.EPSILON; + if (xFilter === 0 && yFilter === 0 && hdgFilter) return false; return true; } From 62f3db8e998116e5f3ce085dbbadc0b3a27f3714 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 10 Feb 2026 21:11:37 -0500 Subject: [PATCH 155/215] use B539 ability instead of B538 startsUsing for alert --- ui/raidboss/data/07-dt/raid/r12s.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 213ed04c87d..722bd57151e 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1502,11 +1502,13 @@ 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, + // B538 has a 10s castTime that could end with enrage or raidwide + // Raidwide cast, B539, happens .2s after but it's not until 5.4s~5.8s later that the damage is applied + // Mits applied after "cast" still count towards the damage application + type: 'Ability', + netRegex: { id: 'B539', source: 'Lindwurm', capture: true }, + durationSeconds: 5, + suppressSeconds: 9999, response: Responses.bigAoe('alert'), }, // Phase 2 From ca9393a7c1c9be09aaf24d11715ab8dd3084f1a9 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 10 Feb 2026 21:15:12 -0500 Subject: [PATCH 156/215] remove 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 722bd57151e..ce99ecfe370 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1506,7 +1506,7 @@ const triggerSet: TriggerSet = { // Raidwide cast, B539, happens .2s after but it's not until 5.4s~5.8s later that the damage is applied // Mits applied after "cast" still count towards the damage application type: 'Ability', - netRegex: { id: 'B539', source: 'Lindwurm', capture: true }, + netRegex: { id: 'B539', source: 'Lindwurm', capture: false }, durationSeconds: 5, suppressSeconds: 9999, response: Responses.bigAoe('alert'), From 04abd07ceb2557e62375e0e892d47ce9ef2261fd Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 11 Feb 2026 19:50:45 -0500 Subject: [PATCH 157/215] updates from p1 --- ui/raidboss/data/07-dt/raid/r12s.txt | 45 +++++++++++++++------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 451a461c065..96007acdf89 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -7,7 +7,7 @@ hideall "--sync--" 0.0 "--Reset--" ActorControl { command: "4000000F" } window 0,100000 jump 0 ### Phase 1: Lindwurm -# -ii B4D3 B495 B4B2 B4B4 B4B3 B4BD B4BE B53E B4B5 B4B1 BE0A B570 B56F B4AD B76A B469 B769 +# -ii B4D3 B4B2 B4B4 B4B3 B4BD B4BE B4BF B4C0 B53E B4B5 B4B1 BE0A B570 B56F B4AD B76A B469 B769 # -it "Lindwurm" 0.0 "--sync--" InCombat { inGameCombat: "1" } window 0,1 @@ -15,10 +15,11 @@ hideall "--sync--" 10.6 "--sync--" StartsUsing { id: "B4D7", source: "Lindwurm" } window 15,10 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" } -43.9 "Mortal Slayer 2" Ability { id: ["B496", "B498"], source: "Lindwurm" } -46.9 "Mortal Slayer 3" Ability { id: ["B496", "B498"], source: "Lindwurm" } -49.9 "Mortal Slayer 4" Ability { id: ["B496", "B498"], source: "Lindwurm" } +40.8 "--sync--" Ability { id: "B495", source: "Lindwurm" } +40.9 "Mortal Slayer 1" #Ability { id: ["B496", "B498"], source: "Lindwurm" } +43.9 "Mortal Slayer 2" #Ability { id: ["B496", "B498"], source: "Lindwurm" } +46.9 "Mortal Slayer 3" #Ability { id: ["B496", "B498"], source: "Lindwurm" } +49.9 "Mortal Slayer 4" #Ability { id: ["B496", "B498"], source: "Lindwurm" } 52.9 "--sync--" Ability { id: "B7C5", source: "Lindwurm" } 61.0 "--sync--" Ability { id: "B9DB", source: "Lindwurm" } @@ -42,7 +43,7 @@ hideall "--sync--" 128.7 "Phagocyte Spotlight 1" #Ability { id: "B4B6", source: "Lindwurm" } 130.7 "Phagocyte Spotlight 2" #Ability { id: "B4B6", source: "Lindwurm" } 132.7 "Phagocyte Spotlight 3" #Ability { id: "B4B6", source: "Lindwurm" } -134.7 "Cruel Coil" Ability { id: ["B4B9", "B4B8"], source: "Lindwurm" } +134.7 "Cruel Coil" Ability { id: ["B4B8", "B4B9", "B4BA", "B4BB"], source: "Lindwurm" } 134.7 "Phagocyte Spotlight 4" #Ability { id: "B4B6", source: "Lindwurm" } 135.7 "--bind--" Ability { id: "B472", source: "Lindwurm" } duration 5 140.7 "Skinsplitter 1" Ability { id: "B4BC", source: "Lindwurm" } @@ -105,10 +106,11 @@ hideall "--sync--" 288.5 "Splattershed" Ability { id: "B9C6", source: "Lindwurm" } 290.2 "--sync--" Ability { id: "B4CC", source: "Lindwurm" } 299.3 "--sync--" Ability { id: "B7C4", source: "Lindwurm" } -314.4 "Mortal Slayer 1" Ability { id: ["B496", "B498"], source: "Lindwurm" } -317.4 "Mortal Slayer 2" Ability { id: ["B496", "B498"], source: "Lindwurm" } -320.4 "Mortal Slayer 3" Ability { id: ["B496", "B498"], source: "Lindwurm" } -323.4 "Mortal Slayer 4" Ability { id: ["B496", "B498"], source: "Lindwurm" } +314.3 "--sync--" Ability { id: "B495", source: "Lindwurm" } +314.4 "Mortal Slayer 1" #Ability { id: ["B496", "B498"], source: "Lindwurm" } +317.4 "Mortal Slayer 2" #Ability { id: ["B496", "B498"], source: "Lindwurm" } +320.4 "Mortal Slayer 3" #Ability { id: ["B496", "B498"], source: "Lindwurm" } +323.4 "Mortal Slayer 4" #Ability { id: ["B496", "B498"], source: "Lindwurm" } 326.4 "--sync--" Ability { id: "B7C5", source: "Lindwurm" } # Slaughershed 1 @@ -529,13 +531,14 @@ hideall "--sync--" # IGNORED ABILITIES # Phase 1 # B4D3 --sync--: Attack autos -# B495 Mortal Slayer: VFX # B4B2 Unmitigated Explosion: Missed blob tower # B4B4 Dramatic Lysis: Damage from breaking a tether; These can be broken at various times # B4B5 Dramatic Lysis: 6s to break tether, else this applies every 1s, doing damage and giving a damage down # B4B3 Roiling Mass: Damage from soaking a tether-created tower; The towers can be created at various times -# B4BE Constrictor: VFX Ending of Cruel Coil B4B8 -# B4BD Constrictor: VFX Ending of Cruel Coil B4B9 +# B4BD Constrictor: VFX Ending of Cruel Coil B4B8 +# B4BE Constrictor: VFX Ending of Cruel Coil B4B9 +# B4BF Constrictor: VFX Ending of Cruel Coil B4BA +# B4C0 Constrictor: VFX Ending of Cruel Coil B4BB # B4B1 Metamitosis: VFX # B469 Ravenous Reach: VFX # B769 Ravenous Reach: VFX @@ -579,7 +582,7 @@ hideall "--sync--" # B46E --sync-- # B472 --sync-- Animation coinciding with boss jumping to middle and binding the players # B479 --sync-- -# B495 Mortal Slayer +# B495 Mortal Slayer: VFX, B496 and B498 have distance and AOE components so this is nearest sync # B496 Mortal Slayer: Green (DPS/Healer) Orbs # B498 Mortal Slayer: Purple (Tank) Orbs # B49A --sync--: Animation for Wyrm moving West (Cleaving East) @@ -610,13 +613,15 @@ hideall "--sync--" # B4B5 Dramatic Lysis # B4B6 Phagocyte Spotlight # B4B7 Roiling Mass: Blob Tower Soaks -# B4B8 Cruel Coil: Boss starting one way? -# B4B9 Cruel Coil: Boss starting the other way? -# B4BA Cruel Coil +# B4B8 Cruel Coil: Starts east, turns counterclock +# B4B9 Cruel Coil: Starts west, turns counterclock +# B4BA Cruel Coil: Starts north, turns counterclock +# B4BB Cruel Coil: Starts south, turns counterclock # B4BC Skinsplitter -# B4BE Constrictor: VFX Ending of Cruel Coil B4B8 -# B4BD Constrictor: VFX Ending of Cruel Coil B4B9 -# B4BF Constrictor +# B4BD Constrictor: VFX Ending of Cruel Coil B4B8 +# B4BE Constrictor: VFX Ending of Cruel Coil B4B9 +# B4BF Constrictor: VFX Ending of Cruel Coil B4BA +# B4C0 Constrictor: VFX Ending of Cruel Coil B4BB # B4C1 --sync-- # B4C2 Constrictor: "soft enrage" damage for Cruel Coil # B4C3 Slaughtershed From d5264ecc002af6b6154a56592fb8978bb613a43a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 11 Feb 2026 19:54:04 -0500 Subject: [PATCH 158/215] remove unused data --- 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 ce99ecfe370..b130dddadea 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -41,7 +41,6 @@ export interface Data extends RaidbossData { myFleshBonds?: 'alpha' | 'beta'; inLine: { [name: string]: number }; blobTowerDirs: DirectionOutputIntercard[]; - fleshBondsCount: number; skinsplitterCount: number; cellChainCount: number; myMitoticPhase?: string; @@ -175,7 +174,6 @@ const triggerSet: TriggerSet = { inLine: {}, blobTowerDirs: [], skinsplitterCount: 0, - fleshBondsCount: 0, cellChainCount: 0, hasRot: false, // Phase 2 From b903d3c57e33b206cdd3f925fd3cda11e74fbdce Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 11 Feb 2026 21:33:08 -0500 Subject: [PATCH 159/215] cruel coil break directions from p1 --- ui/raidboss/data/07-dt/raid/r12s.ts | 106 ++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 21 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index b130dddadea..b25f53bc4cb 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -8,8 +8,6 @@ import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; // TODO: Mortal Coil calls -// TODO: Cursed Coil Counterclock/clockwise call -// TODO: Cursed Coil break directions // TODO: Separate Split Scourge and Venomous Scourge triggers // TODO: Safe spots for Curtain Call's Unbreakable flesh // TODO: Safe spots for Slaughtershed Stack/Spreads @@ -41,6 +39,7 @@ export interface Data extends RaidbossData { myFleshBonds?: 'alpha' | 'beta'; inLine: { [name: string]: number }; blobTowerDirs: DirectionOutputIntercard[]; + cursedCoilDirNum?: number; skinsplitterCount: number; cellChainCount: number; myMitoticPhase?: string; @@ -813,6 +812,30 @@ const triggerSet: TriggerSet = { suppressSeconds: 10, response: Responses.drawIn(), }, + { + id: 'R12S Cursed Coil Initial Direction Collect', + // B4B8 Cruel Coil: Starts east, turns counterclock + // B4B9 Cruel Coil: Starts west, turns counterclock + // B4BA Cruel Coil: Starts north, turns counterclock + // B4BB Cruel Coil: Starts south, turns counterclock + type: 'StartsUsing', + netRegex: { id: ['B4B8', 'B4B9', 'B4BA', 'B4BB'], source: 'Lindwurm', capture: true }, + run: (data, matches) => { + switch (matches.id) { + case 'B4B8': + data.cursedCoilDirNum = 1; + return; + case 'B4B9': + data.cursedCoilDirNum = 3; + return; + case 'B4BA': + data.cursedCoilDirNum = 0; + return; + case 'B4BB': + data.cursedCoilDirNum = 2; + } + }, + }, { id: 'R12S Skinsplitter Counter', // These occur every 5s @@ -998,12 +1021,20 @@ const triggerSet: TriggerSet = { alertText: (data, matches, output) => { const myNum = data.inLine[data.me]; const flesh = matches.effectId === '1291' ? 'alpha' : 'beta'; + // As the coil is moving in reverse, the modulo will have negative values + // 8 has to be used as that is the next number after 7 (number of spins) that divides evenly by 4 + const coilDirNum = data.cursedCoilDirNum !== undefined + ? ((data.cursedCoilDirNum - data.skinsplitterCount) + 8) % 4 + : undefined; + if (flesh === 'alpha') { + const exit = Directions.outputCardinalDir[coilDirNum ?? 4] ?? 'unknown'; // Return 'unknown' if undefined if (myNum === 1) { const dir = data.blobTowerDirs[2]; if (dir !== undefined) return output.alpha1Dir!({ chains: output.breakChains!(), + exit: output[exit]!(), dir: output[dir]!(), }); } @@ -1012,6 +1043,7 @@ const triggerSet: TriggerSet = { if (dir !== undefined) return output.alpha2Dir!({ chains: output.breakChains!(), + exit: output[exit]!(), dir: output[dir]!(), }); } @@ -1019,60 +1051,92 @@ const triggerSet: TriggerSet = { // dir undefined or 3rd/4rth in line switch (myNum) { case 1: - return output.alpha1!({ chains: output.breakChains!() }); + return output.alpha1!({ + chains: output.breakChains!(), + exit: output[exit]!(), + }); case 2: - return output.alpha2!({ chains: output.breakChains!() }); + return output.alpha2!({ + chains: output.breakChains!(), + exit: output[exit]!(), + }); case 3: - return output.alpha3!({ chains: output.breakChains!() }); + return output.alpha3!({ + chains: output.breakChains!(), + exit: output[exit]!(), + }); case 4: - return output.alpha4!({ chains: output.breakChains!() }); + return output.alpha4!({ + chains: output.breakChains!(), + exit: output[exit]!(), + }); } } + + const dir = coilDirNum !== undefined + ? Directions.outputCardinalDir[(coilDirNum + 2) % 4] ?? 'unknown' + : 'unknown'; + switch (myNum) { case 1: - return output.beta1!({ chains: output.breakChains!() }); + return output.beta1!({ + chains: output.breakChains!(), + dir: output[dir]!(), + }); case 2: - return output.beta2!({ chains: output.breakChains!() }); + return output.beta2!({ + chains: output.breakChains!(), + dir: output[dir]!(), + }); case 3: - return output.beta3!({ chains: output.breakChains!() }); + return output.beta3!({ + chains: output.breakChains!(), + dir: output[dir]!(), + }); case 4: - return output.beta4!({ chains: output.breakChains!() }); + return output.beta4!({ + chains: output.breakChains!(), + dir: output[dir]!(), + }); } return output.getTowers!(); }, outputStrings: { - ...Directions.outputStringsIntercardDir, + ...Directions.outputStrings8Dir, breakChains: Outputs.breakChains, getTowers: Outputs.getTowers, alpha1: { - en: '${chains} 1 + Blob Tower 3 (Outer)', + en: '${chains} 1 (${exit}) + Blob Tower 3 (Outer)', }, alpha1Dir: { - en: '${chains} 1 + Blob Tower 3 (Outer ${dir})', + en: '${chains} 1 (${exit}) + Blob Tower 3 (Outer ${dir})', + }, + alpha1ExitDir: { + en: '${chains} 1 (${exit}) + Blob Tower 3 (Outer ${dir})', }, alpha2: { - en: '${chains} 2 + Blob Tower 4 (Outer)', + en: '${chains} 2 (${exit}) + Blob Tower 4 (Outer)', }, alpha2Dir: { - en: '${chains} 2 + Blob Tower 4 (Outer ${dir})', + en: '${chains} 2 (${exit}) + Blob Tower 4 (Outer ${dir})', }, alpha3: { - en: '${chains} 3 + Get Out', + en: '${chains} 3 (${exit}) + Get Out', }, alpha4: { - en: '${chains} 4 + Get Out', + en: '${chains} 4 (${exit}) + Get Out', }, beta1: { - en: '${chains} 1 => Get Middle', + en: '${chains} 1 (${dir}) => Get Middle', }, beta2: { - en: '${chains} 2 => Get Middle', + en: '${chains} 2 (${dir}) => Get Middle', }, beta3: { - en: '${chains} 3 => Wait for last pair', + en: '${chains} 3 (${dir}) => Wait for last pair', }, beta4: { - en: '${chains} 4 => Get Out', + en: '${chains} 4 (${dir}) => Get Out', }, }, }, From dcb80dbada13fb776163f93bc94462f2235d7891 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 13 Feb 2026 22:59:46 -0500 Subject: [PATCH 160/215] add B6F9 from p1 --- ui/raidboss/data/07-dt/raid/r12s.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 96007acdf89..507376edf6b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -7,7 +7,7 @@ hideall "--sync--" 0.0 "--Reset--" ActorControl { command: "4000000F" } window 0,100000 jump 0 ### Phase 1: Lindwurm -# -ii B4D3 B4B2 B4B4 B4B3 B4BD B4BE B4BF B4C0 B53E B4B5 B4B1 BE0A B570 B56F B4AD B76A B469 B769 +# -ii B4D3 B4B2 B6F9 B4B4 B4B3 B4BD B4BE B4BF B4C0 B53E B4B5 B4B1 BE0A B570 B56F B4AD B76A B469 B769 # -it "Lindwurm" 0.0 "--sync--" InCombat { inGameCombat: "1" } window 0,1 @@ -532,6 +532,7 @@ hideall "--sync--" # Phase 1 # B4D3 --sync--: Attack autos # B4B2 Unmitigated Explosion: Missed blob tower +# B6F9 Unmitigated Explosion: Breaking chain before Bonds of Flesh expires # B4B4 Dramatic Lysis: Damage from breaking a tether; These can be broken at various times # B4B5 Dramatic Lysis: 6s to break tether, else this applies every 1s, doing damage and giving a damage down # B4B3 Roiling Mass: Damage from soaking a tether-created tower; The towers can be created at various times @@ -648,6 +649,7 @@ hideall "--sync--" # B56F --sync-- # B570 --sync-- # B571 --sync-- +# B6F9 Unmitigated Explosion # B769 Ravenous Reach: VFX # B76A Ravenous Reach: VFX # B7C4 --sync-- From 979dfab854941ad490403211f8ebc785288a418b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 16 Feb 2026 18:59:19 -0500 Subject: [PATCH 161/215] fix missing outputstring language from p1 --- ui/raidboss/data/07-dt/raid/r12s.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index b25f53bc4cb..c88e568a78f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1430,7 +1430,9 @@ const triggerSet: TriggerSet = { netRegex: { id: 'BEC0', source: 'Lindwurm', capture: false }, infoText: (_data, _matches, output) => output.text!(), outputStrings: { - text: 'Bait 5x Puddles', + text: { + en: 'Bait 5x Puddles', + }, }, }, { From ef5ab53d944573b47d5791b3cbd1f73fbbd19a80 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 17 Feb 2026 20:19:04 -0500 Subject: [PATCH 162/215] adjust arcadian hell aoe level --- ui/raidboss/data/07-dt/raid/r12s.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index c88e568a78f..495a252e15c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4393,11 +4393,22 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Arcadian Hell', + id: 'R12S Arcadian Hell 1', + // B533 + B534 x4, Total ~280k Damage type: 'StartsUsing', netRegex: { id: 'B533', source: 'Lindwurm', capture: false }, durationSeconds: 4.7, - response: Responses.bigAoe('alert'), + suppressSeconds: 9999, + response: Responses.aoe(), + }, + { + id: 'R12S Arcadian Hell 2', + // B533 + B535 x8, Total ~360k Damage + type: 'StartsUsing', + netRegex: { id: 'B535', source: 'Lindschrat', capture: false }, + durationSeconds: 4.7, + suppressSeconds: 9999, + response: Responses.bigAoe(), }, ], timelineReplace: [ From 104d21ffd8aa4737cb2fab788c04c9294b3b03db Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 18 Feb 2026 20:29:15 -0500 Subject: [PATCH 163/215] add replication 2 config for dn and banana codex --- ui/raidboss/data/07-dt/raid/r12s.ts | 431 ++++++++++++++++++++-------- 1 file changed, 308 insertions(+), 123 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 495a252e15c..1ff40558ed2 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -28,6 +28,7 @@ export interface Data extends RaidbossData { readonly triggerSetConfig: { uptimeKnockbackStrat: true | false; portentStrategy: 'dn' | 'zenith' | 'none'; + replication2Strategy: 'dn' | 'banana' | 'none'; }; phase: Phase; // Phase 1 @@ -114,6 +115,88 @@ const headMarkerData = { 'fireballSplashTether': '0176', // Comes from the boss, B4E4 Fireball Splash baited jump } as const; +const replication2OutputStrings = { + ...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', + }, + noTether: { + en: 'No Tether on YOU', + }, + tetherGetTether: { + en: '${tether1}; ${tether2}', + }, + getTether: { + en: 'Get Tether', + }, + getBossTether: { + en: 'Get Boss Tether', + }, + getConeTetherCW: { + en: 'Get Clockwise Cone Tether', + }, + getConeTetherCCW: { + en: 'Get Counterclock Cone Tether', + }, + getStackTetherCW: { + en: 'Get Clockwise Stack Tether', + }, + getStackTetherCCW: { + en: 'Get Counterclock Stack Tether', + }, + getDefamationTetherCW: { + en: 'Get Clockwise Defamation Tether', + }, + getDefamationTetherCCW: { + en: 'Get Counterclock Defamation Tether', + }, + getNoTether: { + en: 'Get Nothing', + }, + getTetherNClone: { + en: '${tether}', + }, + getTetherNEClone: { + en: '${tether}', + }, + getTetherEClone: { + en: '${tether}', + }, + getTetherSEClone: { + en: '${tether}', + }, + getTetherSClone: { + en: '${tether}', + }, + getTetherSWClone: { + en: '${tether}', + }, + getTetherWClone: { + en: '${tether}', + }, + getTetherNWClone: { + en: '${tether}', + }, +}; + const center = { x: 100, y: 100, @@ -149,6 +232,21 @@ const triggerSet: TriggerSet = { type: 'checkbox', default: false, }, + { + id: 'replication2Strategy', + name: { + en: 'Replication 2 Strategy', + }, + type: 'select', + options: { + en: { + 'DN Strategy: Boss North, Cleaves NE/NW, Stacks E/W, Defamations SE/SW, Nothing South': 'dn', + 'Banana Codex Strategy: Boss North, Stacks NW/NE, Cleaves E/W, Defamations SE/SW, Nothing South': 'banana', + 'No strategy: Calls the tether you may have and to get a tether.': 'none', + }, + }, + default: 'none', + }, { id: 'portentStrategy', name: { @@ -1989,42 +2087,82 @@ const triggerSet: TriggerSet = { case 0: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), - tether2: output.getTetherNClone!({ tether: output.getTether!() }), + tether2: output.getTetherNClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getBossTether!(), + }), }); case 1: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), - tether2: output.getTetherNEClone!({ tether: output.getTether!() }), + tether2: output.getTetherNEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCW!() + : output.getTether!(), + }), }); case 2: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), - tether2: output.getTetherEClone!({ tether: output.getTether!() }), + tether2: output.getTetherEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), + }), }); case 3: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), - tether2: output.getTetherSEClone!({ tether: output.getTether!() }), + tether2: output.getTetherSEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCW!(), + }), }); case 4: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), - tether2: output.getTetherSClone!({ tether: output.getTether!() }), + tether2: output.getTetherSClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getNoTether!(), + }), }); case 5: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), - tether2: output.getTetherSWClone!({ tether: output.getTether!() }), + tether2: output.getTetherSWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCCW!(), + }), }); case 6: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), - tether2: output.getTetherWClone!({ tether: output.getTether!() }), + tether2: output.getTetherWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), + }), }); case 7: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), - tether2: output.getTetherNWClone!({ tether: output.getTether!() }), + tether2: output.getTetherNWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), + }), }); } } @@ -2050,42 +2188,82 @@ const triggerSet: TriggerSet = { case 0: return output.tetherGetTether!({ tether1: output[tether]!(), - tether2: output.getTetherNClone!({ tether: output.getTether!() }), + tether2: output.getTetherNClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getBossTether!(), + }), }); case 1: return output.tetherGetTether!({ tether1: output[tether]!(), - tether2: output.getTetherNEClone!({ tether: output.getTether!() }), + tether2: output.getTetherNEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCW!() + : output.getTether!(), + }), }); case 2: return output.tetherGetTether!({ tether1: output[tether]!(), - tether2: output.getTetherEClone!({ tether: output.getTether!() }), + tether2: output.getTetherEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), + }), }); case 3: return output.tetherGetTether!({ tether1: output[tether]!(), - tether2: output.getTetherSEClone!({ tether: output.getTether!() }), + tether2: output.getTetherSEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCW!(), + }), }); case 4: return output.tetherGetTether!({ tether1: output[tether]!(), - tether2: output.getTetherSClone!({ tether: output.getTether!() }), + tether2: output.getTetherSClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getNoTether!(), + }), }); case 5: return output.tetherGetTether!({ tether1: output[tether]!(), - tether2: output.getTetherSWClone!({ tether: output.getTether!() }), + tether2: output.getTetherSWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCCW!(), + }), }); case 6: return output.tetherGetTether!({ tether1: output[tether]!(), - tether2: output.getTetherWClone!({ tether: output.getTether!() }), + tether2: output.getTetherWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), + }), }); case 7: return output.tetherGetTether!({ tether1: output[tether]!(), - tether2: output.getTetherNWClone!({ tether: output.getTether!() }), + tether2: output.getTetherNWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), + }), }); } } @@ -2106,102 +2284,89 @@ const triggerSet: TriggerSet = { case 0: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), - tether2: output.getTetherNClone!({ tether: output.getTether!() }), + tether2: output.getTetherNClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getBossTether!(), + }), }); case 1: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), - tether2: output.getTetherNEClone!({ tether: output.getTether!() }), + tether2: output.getTetherNEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCW!() + : output.getTether!(), + }), }); case 2: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), - tether2: output.getTetherEClone!({ tether: output.getTether!() }), + tether2: output.getTetherEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), + }), }); case 3: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), - tether2: output.getTetherSEClone!({ tether: output.getTether!() }), + tether2: output.getTetherSEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCW!(), + }), }); case 4: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), - tether2: output.getTetherSClone!({ tether: output.getTether!() }), + tether2: output.getTetherSClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getNoTether!(), + }), }); case 5: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), - tether2: output.getTetherSWClone!({ tether: output.getTether!() }), + tether2: output.getTetherSWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCCW!(), + }), }); case 6: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), - tether2: output.getTetherWClone!({ tether: output.getTether!() }), + tether2: output.getTetherWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), + }), }); case 7: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), - tether2: output.getTetherNWClone!({ tether: output.getTether!() }), + tether2: output.getTetherNWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), + }), }); } } return output[tetherDir]!({ dir: output[dir]!() }); }, - 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', - }, - tetherGetTether: { - en: '${tether1}; ${tether2}', - }, - getTether: { - en: 'Get Tether', - }, - getTetherNClone: { - en: '${tether}', - }, - getTetherNEClone: { - en: '${tether}', - }, - getTetherEClone: { - en: '${tether}', - }, - getTetherSEClone: { - en: '${tether}', - }, - getTetherSClone: { - en: '${tether}', - }, - getTetherSWClone: { - en: '${tether}', - }, - getTetherWClone: { - en: '${tether}', - }, - getTetherNWClone: { - en: '${tether}', - }, - }, + outputStrings: replication2OutputStrings, }, { id: 'R12S Replication 2 Ability Tethers Initial Call (No Tether)', @@ -2222,70 +2387,90 @@ const triggerSet: TriggerSet = { // the location they want based on custom plan switch (parseInt(myDirNum)) { case 0: - return output.noTetherCloneN!({ - noTether: output.noTether!(), + return output.tetherGetTether!({ + tether1: output.noTether!(), + tether2: output.getTetherNClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getBossTether!(), + }), }); case 1: - return output.noTetherCloneNE!({ - noTether: output.noTether!(), + return output.tetherGetTether!({ + tether1: output.noTether!(), + tether2: output.getTetherNEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCW!() + : output.getTether!(), + }), }); case 2: - return output.noTetherCloneE!({ - noTether: output.noTether!(), + return output.tetherGetTether!({ + tether1: output.noTether!(), + tether2: output.getTetherEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), + }), }); case 3: - return output.noTetherCloneSE!({ - noTether: output.noTether!(), + return output.tetherGetTether!({ + tether1: output.noTether!(), + tether2: output.getTetherSEClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCW!(), + }), }); case 4: - return output.noTetherCloneS!({ - noTether: output.noTether!(), + return output.tetherGetTether!({ + tether1: output.noTether!(), + tether2: output.getTetherSClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getNoTether!(), + }), }); case 5: - return output.noTetherCloneSW!({ - noTether: output.noTether!(), + return output.tetherGetTether!({ + tether1: output.noTether!(), + tether2: output.getTetherSWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCCW!(), + }), }); case 6: - return output.noTetherCloneW!({ - noTether: output.noTether!(), + return output.tetherGetTether!({ + tether1: output.noTether!(), + tether2: output.getTetherWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), + }), }); case 7: - return output.noTetherCloneNW!({ - noTether: output.noTether!(), + return output.tetherGetTether!({ + tether1: output.noTether!(), + tether2: output.getTetherNWClone!({ + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), + }), }); } } return output.noTether!(); }, - outputStrings: { - noTether: { - en: 'No Tether on YOU', - }, - noTetherCloneN: { - en: '${noTether}', - }, - noTetherCloneNE: { - en: '${noTether}', - }, - noTetherCloneE: { - en: '${noTether}', - }, - noTetherCloneSE: { - en: '${noTether}', - }, - noTetherCloneS: { - en: '${noTether}', - }, - noTetherCloneSW: { - en: '${noTether}', - }, - noTetherCloneW: { - en: '${noTether}', - }, - noTetherCloneNW: { - en: '${noTether}', - }, - }, + outputStrings: replication2OutputStrings, }, { id: 'R12S Replication 2 Locked Tether Collect', From 6b22e7851a2850b0e0fea1fb7d6b232a51c1754d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 18 Feb 2026 20:35:38 -0500 Subject: [PATCH 164/215] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 166 ++++++++++++++-------------- 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 1ff40558ed2..20451238fc9 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -240,8 +240,10 @@ const triggerSet: TriggerSet = { type: 'select', options: { en: { - 'DN Strategy: Boss North, Cleaves NE/NW, Stacks E/W, Defamations SE/SW, Nothing South': 'dn', - 'Banana Codex Strategy: Boss North, Stacks NW/NE, Cleaves E/W, Defamations SE/SW, Nothing South': 'banana', + 'DN Strategy: Boss North, Cleaves NE/NW, Stacks E/W, Defamations SE/SW, Nothing South': + 'dn', + 'Banana Codex Strategy: Boss North, Stacks NW/NE, Cleaves E/W, Defamations SE/SW, Nothing South': + 'banana', 'No strategy: Calls the tether you may have and to get a tether.': 'none', }, }, @@ -2285,81 +2287,81 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getBossTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getBossTether!(), + }), }); case 1: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherNEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.getConeTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCW!() - : output.getTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCW!() + : output.getTether!(), + }), }); case 2: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.getStackTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCW!() - : output.getTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), + }), }); case 3: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCW!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCW!(), + }), }); case 4: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getNoTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getNoTether!(), + }), }); case 5: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCCW!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCCW!(), + }), }); case 6: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.getStackTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCCW!() - : output.getTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), + }), }); case 7: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherNWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.getConeTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCCW!() - : output.getTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), + }), }); } } @@ -2390,81 +2392,81 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getBossTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getBossTether!(), + }), }); case 1: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherNEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.getConeTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCW!() - : output.getTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCW!() + : output.getTether!(), + }), }); case 2: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.getStackTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCW!() - : output.getTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), + }), }); case 3: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCW!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCW!(), + }), }); case 4: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getNoTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getNoTether!(), + }), }); case 5: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCCW!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'none' + ? output.getTether!() + : output.getDefamationTetherCCW!(), + }), }); case 6: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.getStackTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCCW!() - : output.getTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getStackTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), + }), }); case 7: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherNWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.getConeTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCCW!() - : output.getTether!(), - }), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getConeTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), + }), }); } } From 0b2429597cf7f5d61d018e470ba61e00e56d8469 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 20 Feb 2026 20:38:17 -0500 Subject: [PATCH 165/215] increase twisted vision 6 to alert probably 6 and 8 should be same severity, so increase this to alert --- 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 20451238fc9..232a0fb95bd 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4434,7 +4434,7 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'BBE2', source: 'Lindwurm', capture: false }, condition: (data) => data.twistedVisionCounter === 6, - infoText: (data, _matches, output) => { + alertText: (data, _matches, output) => { const first = data.replication3CloneOrder[0]; if (first === undefined) return; From 5db12e5e11e1601847e28d622852690be044452c Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 20 Feb 2026 20:42:13 -0500 Subject: [PATCH 166/215] additional duration for twisted vision 7 It's about 4.6s from end of cast to the power gusher ability going off. --- 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 232a0fb95bd..05b95f0218f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4477,7 +4477,7 @@ const triggerSet: TriggerSet = { type: 'StartsUsing', netRegex: { id: 'BBE2', source: 'Lindwurm', capture: true }, condition: (data) => data.twistedVisionCounter === 7, - durationSeconds: (_data, matches) => parseFloat(matches.castTime), + durationSeconds: (_data, matches) => parseFloat(matches.castTime) + 4.5, infoText: (data, _matches, output) => { if (data.idyllicVision7SafeSides === 'frontBack') { if (data.idyllicVision7SafePlatform === 'east') From 2978b3b6c052d227776fb7ef5f49fce53fd0e0c2 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Fri, 20 Feb 2026 20:49:47 -0500 Subject: [PATCH 167/215] fix twisted vision 8 call happening at 7 Was missing condition to check that it is twisted vision 8. --- ui/raidboss/data/07-dt/raid/r12s.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 05b95f0218f..c894c617102 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4560,6 +4560,7 @@ const triggerSet: TriggerSet = { // Trigger on Clone's BE5D Heavy Slam type: 'Ability', netRegex: { id: 'BE5D', source: 'Lindwurm', capture: false }, + condition: (data) => data.twistedVisionCounter === 8, alertText: (data, _matches, output) => { if (data.idyllicVision8SafeSides === 'sides') return output.sides!(); From bf8b1c44ec82becddfa2e3710e89bcbeb6a59ac9 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 22 Feb 2026 03:20:48 -0500 Subject: [PATCH 168/215] additional p1 triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 122 +++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 4 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index c894c617102..ecef9ab6133 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -7,8 +7,6 @@ import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; -// TODO: Mortal Coil calls -// TODO: Separate Split Scourge and Venomous Scourge triggers // TODO: Safe spots for Curtain Call's Unbreakable flesh // TODO: Safe spots for Slaughtershed Stack/Spreads // TODO: Twisted Vision 5 Tower spots @@ -32,6 +30,9 @@ export interface Data extends RaidbossData { }; phase: Phase; // Phase 1 + mortalSlayerGreenLeft: number; + mortalSlayerGreenRight: number; + mortalSlayerPurpleIsLeft?: boolean; grotesquerieCleave?: | 'rightCleave' | 'leftCleave' @@ -270,6 +271,8 @@ const triggerSet: TriggerSet = { initData: () => ({ phase: 'doorboss', // Phase 1 + mortalSlayerGreenLeft: 0, + mortalSlayerGreenRight: 0, inLine: {}, blobTowerDirs: [], skinsplitterCount: 0, @@ -410,6 +413,80 @@ const triggerSet: TriggerSet = { durationSeconds: 4.7, response: Responses.bigAoe('alert'), }, + { + id: 'R12S Mortal Slayer Collect', + // 19200 Purple Orb + // 19201 Green Orb + type: 'AddedCombatant', + netRegex: { name: 'Lindwurm', npcBaseId: ['19200', '19201'], capture: true }, + run: (data, matches) => { + const npcBaseId = matches.npcBaseId; + const x = parseFloat(matches.x); + + // 4 Green Orbs on one side = we know where purple will be + if (npcBaseId === '19201') { + if (x < 100) { + data.mortalSlayerGreenLeft = data.mortalSlayerGreenLeft + 1; + if ( + data.mortalSlayerGreenLeft === 4 && + data.mortalSlayerPurpleIsLeft === undefined + ) + data.mortalSlayerPurpleIsLeft = false; + } else if (x > 100) { + data.mortalSlayerGreenRight = data.mortalSlayerGreenRight + 1; + if ( + data.mortalSlayerGreenRight === 4 && + data.mortalSlayerPurpleIsLeft === undefined + ) + data.mortalSlayerPurpleIsLeft = true; + } + } else if ( + npcBaseId === '19200' && + data.mortalSlayerPurpleIsLeft === undefined + ) + data.mortalSlayerPurpleIsLeft = x < 100 ? true : false; + }, + }, + { + id: 'R12S Mortal Slayer Tank Side', + type: 'AddedCombatant', + netRegex: { name: 'Lindwurm', npcBaseId: ['19200', '19201'], capture: false }, + condition: (data) => { + if (data.mortalSlayerPurpleIsLeft !== undefined) + return true; + return false; + }, + suppressSeconds: 12, // castTime of Mortal Slayer B495 + response: (data, _matches, output) => { + // cactbot-builtin-response + output.responseOutputStrings = { + tanksLeft: { + en: 'Tanks Left', + }, + tanksRight: { + en: 'Tanks Right', + }, + }; + const severity = data.role === 'tank' ? 'alertText' : 'infoText'; + return { + [severity]: data.mortalSlayerPurpleIsLeft + ? output.tanksLeft!() + : output.tanksRight!(), + }; + }, + }, + { + id: 'R12S Mortal Slayer Cleanup', + // Reset trackers for second Mortal Slayer + type: 'Ability', + netRegex: { id: 'B495', capture: false }, + suppressSeconds: 9999, + run: (data) => { + data.mortalSlayerGreenLeft = 0; + data.mortalSlayerGreenRight = 0; + delete data.mortalSlayerPurpleIsLeft; + }, + }, { id: 'R12S Directed Grotesquerie Direction Collect', // Unknown_DE6 spell contains data in its count: @@ -1363,6 +1440,19 @@ const triggerSet: TriggerSet = { goIntoMiddle: Outputs.goIntoMiddle, }, }, + { + id: 'R12S Skinsplitter Out of Coil Reminder', + type: 'Ability', + netRegex: { id: 'B4BC', capture: false }, + condition: (data) => data.skinsplitterCount === 7, + suppressSeconds: 1, + alertText: (_data, _matches, output) => output.outOfCoil!(), + outputStrings: { + outOfCoil: { + en: 'Out of Coil', + }, + }, + }, { id: 'R12S Splattershed', type: 'StartsUsing', @@ -1502,6 +1592,9 @@ const triggerSet: TriggerSet = { { id: 'R12S Split Scourge and Venomous Scourge', // B4AB Split Scourge and B4A8 Venomous Scourge are instant casts + // Split Scourge happens first: + // Each head will target the nearest player with a tankbuster line AoE + // // This actor control happens along with boss becoming targetable // Seems there are two different data0 values possible: // 1E01: Coming back from Cardinal platforms @@ -1517,10 +1610,31 @@ const triggerSet: TriggerSet = { }, outputStrings: { tank: { - en: 'Bait Line AoE from heads', + en: 'Bait Line AoE from Heads => Get Middle (Avoid Far AoEs)', + }, + party: { + en: 'Away from Heads (Avoid Tank Lines) => Spread near Heads', + }, + }, + }, + { + id: 'R12S Venomous Scourge', + // 2.4s after Split Scourge, Venomous Scourge AoEs happen on 3 furthest players from each head + type: 'Ability', + netRegex: { id: 'B4AB', capture: false }, + durationSeconds: 2.4, + suppressSeconds: 9999, + alertText: (data, _matches, output) => { + if (data.role === 'tank') + return output.tank!(); + return output.party!(); + }, + outputStrings: { + tank: { + en: 'Get Middle (Avoid Far AoEs)', }, party: { - en: 'Spread, Away from heads', + en: 'Spread near Heads', }, }, }, From e59c171b3623cc9904645fd3554ec45d1da7e185 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 22 Feb 2026 14:44:21 -0500 Subject: [PATCH 169/215] change hasDoom detection to be on B4F6 ability A distance of 3 from the source was largest I could see in my logs. --- ui/raidboss/data/07-dt/raid/r12s.ts | 34 ++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ecef9ab6133..49a05c35c45 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4274,16 +4274,40 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Doom Tower Soak Collect', + // Abilities such as Warden's Paean can prevent Doom GainsEffect + type: 'Ability', + netRegex: { id: 'B4F6', capture: true }, + condition: Conditions.targetIsYou(), + run: (data, matches) => { + // Only record those players standing near the Doom tower + const getDistance = ( + x: number, + y: number, + targetX: number, + targetY: number, + ): number => { + const dx = x - targetX; + const dy = y - targetY; + return Math.round(Math.sqrt(dx * dx + dy * dy)); + }; + const x = parseFloat(matches.x); + const y = parseFloat(matches.y); + const targetX = parseFloat(matches.targetX); + const targetY = parseFloat(matches.targetY); + const d = getDistance(x, y, targetX, targetY); + + if (d < 4) + data.hasDoom = true; + }, + }, { id: 'R12S Doom Collect', // Happens about 1.3s after Dark Tower when it casts B4F6 Lindwurm's Dark II type: 'GainsEffect', netRegex: { effectId: 'D24', capture: true }, - run: (data, matches) => { - data.doomPlayers.push(matches.target); - if (data.me === matches.target) - data.hasDoom = true; - }, + run: (data, matches) => data.doomPlayers.push(matches.target), }, { id: 'R12S Doom Cleanse', From 61f0cf8c8eb2611c239ecf93b9edf5d9945ff5dc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 22 Feb 2026 15:12:05 -0500 Subject: [PATCH 170/215] merge avoid earth into doom cleanse, remove for pyretic player --- ui/raidboss/data/07-dt/raid/r12s.ts | 42 +++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 49a05c35c45..3bfd095cb0f 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4265,6 +4265,14 @@ const triggerSet: TriggerSet = { // 5s castTime type: 'StartsUsing', netRegex: { id: 'B4F7', source: 'Lindwurm', capture: true }, + condition: (data) => { + // Avoid simultaneous trigger for Pyretic player as they wouldn't be at the earth location + if (data.hasPyretic) + return false; + // Handle this in Doom clense instead + if (data.CanCleanse()) + return false; + }, durationSeconds: (_data, matches) => parseFloat(matches.castTime), suppressSeconds: 1, infoText: (_data, _matches, output) => output.avoidEarthTower!(), @@ -4321,11 +4329,17 @@ const triggerSet: TriggerSet = { 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 }); + return output.mech!({ + cleanse: output.cleanseDoom2!({ target1: target1, target2: target2 }), + avoid: output.avoidEarthTower!(), + }); } if (players.length === 1) { const target1 = data.party.member(data.doomPlayers[0]); - return output.cleanseDoom!({ target: target1 }); + return output.mech!({ + cleanse: output.cleanseDoom!({ target: target1 }), + avoid: output.avoidEarthTower!(), + }); } }, outputStrings: { @@ -4340,6 +4354,30 @@ const triggerSet: TriggerSet = { cleanseDoom2: { en: 'Cleanse ${target1}/${target2}', }, + avoidEarthTower: { + en: 'Avoid Earth Tower', + }, + mech: { + en: '${cleanse} + ${avoid}', + }, + }, + }, + { + id: 'R12S Avoid Earth Tower (Missing Dooms)', + // Handle scenario where both Dooms end up not being applied + type: 'Ability', + netRegex: { id: 'B4F6', capture: false }, + condition: (data) => data.CanCleanse(), + delaySeconds: 0.5, // Time until after Doom was expected + suppressSeconds: 9999, + infoText: (data, _matches, output) => { + if (data.doomPlayers[0] === undefined) + return output.avoidEarthTower!(); + }, + outputStrings: { + avoidEarthTower: { + en: 'Avoid Earth Tower', + }, }, }, { From cb7612c71959429a9430783f2617e562eb1258e1 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 22 Feb 2026 15:16:06 -0500 Subject: [PATCH 171/215] add comment to missing doom trigger --- ui/raidboss/data/07-dt/raid/r12s.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 3bfd095cb0f..463bb6d0e81 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4365,6 +4365,7 @@ const triggerSet: TriggerSet = { { id: 'R12S Avoid Earth Tower (Missing Dooms)', // Handle scenario where both Dooms end up not being applied + // Triggering on the Lindwurm's Dark II ability that would apply Doom type: 'Ability', netRegex: { id: 'B4F6', capture: false }, condition: (data) => data.CanCleanse(), From 8276037b1fa442df347a481db073d28071482c90 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 22 Feb 2026 17:18:41 -0500 Subject: [PATCH 172/215] fix banana codex tethers to grab --- ui/raidboss/data/07-dt/raid/r12s.ts | 164 +++++++++++++++++----------- 1 file changed, 98 insertions(+), 66 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 463bb6d0e81..8987b1d69db 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -241,9 +241,9 @@ const triggerSet: TriggerSet = { type: 'select', options: { en: { - 'DN Strategy: Boss North, Cleaves NE/NW, Stacks E/W, Defamations SE/SW, Nothing South': + 'DN Strategy: Boss North, Cones NE/NW, Stacks E/W, Defamations SE/SW, Nothing South': 'dn', - 'Banana Codex Strategy: Boss North, Stacks NW/NE, Cleaves E/W, Defamations SE/SW, Nothing South': + 'Banana Codex Strategy: Boss West, Stacks NW/SW, Cones N/S, Defamations NE/SE, Nothing E': 'banana', 'No strategy: Calls the tether you may have and to get a tether.': 'none', }, @@ -2204,9 +2204,11 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getBossTether!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getBossTether!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), }), }); case 1: @@ -2216,7 +2218,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCW!() + ? output.getDefanationTetherCW!() : output.getTether!(), }), }); @@ -2227,7 +2229,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getStackTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCW!() + ? output.getNoTether!() : output.getTether!(), }), }); @@ -2235,27 +2237,33 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCW!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getDefamationTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getDefamationTetherCCW!() + : output.getTether!(), }), }); case 4: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getNoTether!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getNoTether!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), }), }); case 5: return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCCW!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getDefamationTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), }), }); case 6: @@ -2265,7 +2273,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getStackTetherCCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCCW!() + ? output.getBossTether!() : output.getTether!(), }), }); @@ -2276,7 +2284,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCCW!() + ? output.getStackTetherCW!() : output.getTether!(), }), }); @@ -2305,9 +2313,11 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getBossTether!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getBossTether!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), }), }); case 1: @@ -2317,7 +2327,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCW!() + ? output.getDefanationTetherCW!() : output.getTether!(), }), }); @@ -2328,7 +2338,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getStackTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCW!() + ? output.getNoTether!() : output.getTether!(), }), }); @@ -2336,27 +2346,33 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCW!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getDefamationTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getDefamationTetherCCW!() + : output.getTether!(), }), }); case 4: return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getNoTether!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getNoTether!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), }), }); case 5: return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCCW!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getDefamationTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), }), }); case 6: @@ -2366,7 +2382,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getStackTetherCCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCCW!() + ? output.getBossTether!() : output.getTether!(), }), }); @@ -2377,7 +2393,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCCW!() + ? output.getStackTetherCW!() : output.getTether!(), }), }); @@ -2401,9 +2417,11 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getBossTether!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getBossTether!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), }), }); case 1: @@ -2413,7 +2431,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCW!() + ? output.getDefanationTetherCW!() : output.getTether!(), }), }); @@ -2424,7 +2442,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getStackTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCW!() + ? output.getNoTether!() : output.getTether!(), }), }); @@ -2432,27 +2450,33 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCW!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getDefamationTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getDefamationTetherCCW!() + : output.getTether!(), }), }); case 4: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getNoTether!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getNoTether!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), }), }); case 5: return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCCW!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getDefamationTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), }), }); case 6: @@ -2462,7 +2486,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getStackTetherCCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCCW!() + ? output.getBossTether!() : output.getTether!(), }), }); @@ -2473,7 +2497,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCCW!() + ? output.getStackTetherCW!() : output.getTether!(), }), }); @@ -2506,9 +2530,11 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getBossTether!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getBossTether!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCW!() + : output.getTether!(), }), }); case 1: @@ -2518,7 +2544,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCW!() + ? output.getDefanationTetherCW!() : output.getTether!(), }), }); @@ -2529,7 +2555,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getStackTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCW!() + ? output.getNoTether!() : output.getTether!(), }), }); @@ -2537,27 +2563,33 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCW!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getDefamationTetherCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getDefamationTetherCCW!() + : output.getTether!(), }), }); case 4: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getNoTether!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getNoTether!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getConeTetherCCW!() + : output.getTether!(), }), }); case 5: return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'none' - ? output.getTether!() - : output.getDefamationTetherCCW!(), + tether: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.getDefamationTetherCCW!() + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.getStackTetherCCW!() + : output.getTether!(), }), }); case 6: @@ -2567,7 +2599,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getStackTetherCCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getConeTetherCCW!() + ? output.getBossTether!() : output.getTether!(), }), }); @@ -2578,7 +2610,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getStackTetherCCW!() + ? output.getStackTetherCW!() : output.getTether!(), }), }); From 6505d9f34cf64769311fbfdceeb15b2a6926fbb4 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 22 Feb 2026 17:27:11 -0500 Subject: [PATCH 173/215] fix typo --- 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 8987b1d69db..004ba48ba05 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2218,7 +2218,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getDefanationTetherCW!() + ? output.getDefamationTetherCW!() : output.getTether!(), }), }); @@ -2327,7 +2327,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getDefanationTetherCW!() + ? output.getdefamationTetherCW!() : output.getTether!(), }), }); @@ -2431,7 +2431,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getDefanationTetherCW!() + ? output.getdefamationTetherCW!() : output.getTether!(), }), }); @@ -2544,7 +2544,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getDefanationTetherCW!() + ? output.getdefamationTetherCW!() : output.getTether!(), }), }); From cb57f718cf7ee6c713a39f0c8a5f93a52a1e2338 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 22 Feb 2026 17:31:50 -0500 Subject: [PATCH 174/215] another typo --- 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 004ba48ba05..ec211c4878a 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2327,7 +2327,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getdefamationTetherCW!() + ? output.getDefamationTetherCW!() : output.getTether!(), }), }); @@ -2431,7 +2431,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getdefamationTetherCW!() + ? output.getDefamationTetherCW!() : output.getTether!(), }), }); @@ -2544,7 +2544,7 @@ const triggerSet: TriggerSet = { tether: data.triggerSetConfig.replication2Strategy === 'dn' ? output.getConeTetherCW!() : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.getdefamationTetherCW!() + ? output.getDefamationTetherCW!() : output.getTether!(), }), }); From ba4743d60651a8f595b844cb883e84b186d3ea3b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Sun, 22 Feb 2026 23:24:55 -0500 Subject: [PATCH 175/215] add p1 triggers from blob pr --- ui/raidboss/data/07-dt/raid/r12s.ts | 381 +++++++++++++++++++++++++++- 1 file changed, 370 insertions(+), 11 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ec211c4878a..ae1718be6f7 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -1,14 +1,13 @@ import Conditions from '../../../../../resources/conditions'; import { UnreachableCode } from '../../../../../resources/not_reached'; import Outputs from '../../../../../resources/outputs'; +import { callOverlayHandler } from '../../../../../resources/overlay_plugin_api'; import { Responses } from '../../../../../resources/responses'; import { DirectionOutputIntercard, Directions } from '../../../../../resources/util'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; -// TODO: Safe spots for Curtain Call's Unbreakable flesh -// TODO: Safe spots for Slaughtershed Stack/Spreads // TODO: Twisted Vision 5 Tower spots // TODO: Twisted Vision 5 Lindwurm\'s Stone III (Earth Tower) locations @@ -24,6 +23,7 @@ export type Phase = export interface Data extends RaidbossData { readonly triggerSetConfig: { + curtainCallStrat: 'ns' | 'none'; uptimeKnockbackStrat: true | false; portentStrategy: 'dn' | 'zenith' | 'none'; replication2Strategy: 'dn' | 'banana' | 'none'; @@ -33,6 +33,10 @@ export interface Data extends RaidbossData { mortalSlayerGreenLeft: number; mortalSlayerGreenRight: number; mortalSlayerPurpleIsLeft?: boolean; + ravenousReach1SafeSide?: 'east' | 'west'; + act1SafeCorner?: 'northeast' | 'northwest'; + curtainCallSafeCorner?: 'northeast' | 'northwest'; + splattershedStackDir?: 'northeast' | 'northwest'; grotesquerieCleave?: | 'rightCleave' | 'leftCleave' @@ -46,6 +50,7 @@ export interface Data extends RaidbossData { cellChainCount: number; myMitoticPhase?: string; hasRot: boolean; + myCurtainCallSafeSpot?: 'northeast' | 'southeast' | 'southwest' | 'northwest'; // Phase 2 actorPositions: { [id: string]: { x: number; y: number; heading: number } }; replicationCounter: number; @@ -213,6 +218,21 @@ const triggerSet: TriggerSet = { id: 'AacHeavyweightM4Savage', zoneId: ZoneId.AacHeavyweightM4Savage, config: [ + { + id: 'curtainCallStrat', + name: { + en: 'Curtain Call Strategy', + }, + type: 'select', + options: { + en: { + 'North/Side Relative Strategy: North players go Northeast/Northwest, South players go relative to side.': + 'ns', + 'No strategy: Calls both safe spots.': 'none', + }, + }, + default: 'none', + }, { id: 'uptimeKnockbackStrat', name: { @@ -487,6 +507,95 @@ const triggerSet: TriggerSet = { delete data.mortalSlayerPurpleIsLeft; }, }, + { + id: 'R12S CombatantMemory Blob Tracker', + // Appears in Act 1, Curtain Call, and Slaughtershed phases + // 1EBF29 are the blobs + // + // Act 1 Pattern 1 (NW/E): + // (112.5, 88.63) + // (95.93, 91.36) + // (89.93, 100.13) + // (109.18, 109.63) + // (90.67, 112.13) + // + // Act 1 Pattern 2 (NE/W) + a sliver of space along NE to E: + // (88.42, 89.19) + // (107.02, 92.19) + // (112.5, 105.69) + // (94.02, 108.53) + // (82.34, 113.53) + // + // Curtain Call Pattern 1 (NW/SE): + // (110, 87) + // (85, 100) (100, 100) (115, 100) + // (91, 113) + // + // Curtain Call Pattern 2 (NE/SW): + // (91, 87) + // (85, 100) (100, 100) (115, 100) + // (109, 113) + // + // Splattershed (Two Patterns): + // Blob at (110.75, 96.50) => Spreads Northwest, Stacks Northeast + // Blob at (89.25, 96.40) => Spreads Northeast, Stacks Northwest + // The remaining blobs are always in these locations: + // (100.8, 92) + // (86.5, 105.9) (102.5, 106.4) (118.5, 106.16) + type: 'CombatantMemory', + netRegex: { + change: 'Add', + pair: [{ key: 'BNpcID', value: '1EBF29' }], + capture: true, + }, + run: (data, matches) => { + // No need to check remaining blobs if we already found safe spot + if (data.splattershedStackDir) + return; + const x = parseFloat(matches.pairPosX ?? '0'); + const y = parseFloat(matches.pairPosY ?? '0'); + + // The following are unique coordinates for each phase + // Undefined checks to skip additional position checking + if (data.act1SafeCorner === undefined && y > 87.9 && y < 89.7) { + // Act 1 Safe Corner + // Most strategies have tanks move and stack tankbusters regardless of pattern + // Defining safe corner for purpose of labelling the pattern + if (x > 112) + data.act1SafeCorner = 'northwest'; + else if (x < 89) + data.act1SafeCorner = 'northeast'; + } else if ( + data.act1SafeCorner !== undefined && + data.curtainCallSafeCorner === undefined && + y > 86.5 && y < 87.5 + ) { + // Curtain Call Safe Spots + if (x < 92) + data.curtainCallSafeCorner = 'northwest'; + else if (x > 109) + data.curtainCallSafeCorner = 'northeast'; + } else if ( + data.act1SafeCorner !== undefined && + data.curtainCallSafeCorner !== undefined && + y > 96 && y < 97 + ) { + // Splattershed Stack Spot + if (x > 88.75 && x < 89.75) + data.splattershedStackDir = 'northwest'; + else if (x > 110.25 && x < 111.25) + data.splattershedStackDir = 'northeast'; + } + }, + }, + { + id: 'R12S Splattershed Safe Spot Cleanup', + // Only Splattershed value needs to be reset + type: 'HeadMarker', + netRegex: { id: headMarkerData['slaughterStack'], capture: false }, + delaySeconds: 0.1, + run: (data) => delete data.splattershedStackDir, + }, { id: 'R12S Directed Grotesquerie Direction Collect', // Unknown_DE6 spell contains data in its count: @@ -667,6 +776,18 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Ravenous Reach 1 Safe Side Collect', + // 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', + run: (data, matches) => { + data.ravenousReach1SafeSide = matches.id === 'B49A' ? 'west' : 'east'; + }, + }, { id: 'R12S Ravenous Reach 1 Safe Side', // These two syncs indicate the animation of where the head will go to cleave @@ -695,7 +816,71 @@ const triggerSet: TriggerSet = { return true; }, durationSeconds: 5.1, - response: Responses.stackMarkerOn(), + alertText: (data, matches, output) => { + const reach = data.ravenousReach1SafeSide; + const dir1 = data.act1SafeCorner; + const dir2 = dir1 === 'northwest' ? 'east' : 'west'; // NOTE: Not checking undefined here + const target = matches.target; + + // Safe spot of side party is assumed to be on + const dir = dir1 === undefined + ? dir1 + : reach === dir2 + ? dir2 + : reach === dir1.slice(5) + ? dir1 + : undefined; + + if (target === data.me) { + if (dir1) { + if (dir) { + return output.stackSafe!({ + stack: output.stackOnYou!(), + safe: output[dir]!(), + }); + } + return output.stackSafe!({ + stack: output.stackOnYou!(), + safe: output.stackDirs!({ + dir1: output[dir1]!(), + dir2: output[dir2]!(), + }), + }); + } + return output.stackOnYou!(); + } + const player = data.party.member(target); + if (dir1) { + if (dir) { + return output.stackSafe!({ + stack: output.stackOnTarget!({ player: player }), + safe: output[dir]!(), + }); + } + return output.stackSafe!({ + stack: output.stackOnTarget!({ player: player }), + safe: output.stackDirs!({ + dir1: output[dir1]!(), + dir2: output[dir2]!(), + }), + }); + } + return output.stackOnTarget!({ player: player }); + }, + outputStrings: { + northeast: Outputs.northeast, + east: Outputs.east, + west: Outputs.west, + northwest: Outputs.northwest, + stackOnYou: Outputs.stackOnYou, + stackOnTarget: Outputs.stackOnPlayer, + stackSafe: { + en: '${stack} + ${safe}', + }, + stackDirs: { + en: '${dir1}/${dir2}', + }, + }, }, { id: 'R12S Tankbuster', @@ -703,7 +888,49 @@ const triggerSet: TriggerSet = { netRegex: { id: headMarkerData['tankbuster'], capture: true }, condition: Conditions.targetIsYou(), durationSeconds: 5.1, - response: Responses.tankBuster(), + alertText: (data, _matches, output) => { + const reach = data.ravenousReach1SafeSide; + const dir1 = data.act1SafeCorner; + const dir2 = dir1 === 'northwest' ? 'east' : 'west'; // NOTE: Not checking undefined here + + // Safe spot of opposite assumed side party will be + const dir = dir1 === undefined + ? dir1 + : reach === dir2 + ? dir1 + : reach === dir1.slice(5) + ? dir2 + : undefined; + if (dir1) { + if (dir) { + return output.busterSafe!({ + buster: output.busterOnYou!(), + safe: output[dir]!(), + }); + } + return output.busterSafe!({ + buster: output.busterOnYou!(), + safe: output.busterDirs!({ + dir1: output[dir1]!(), + dir2: output[dir2]!(), + }), + }); + } + return output.busterOnYou!(); + }, + outputStrings: { + northeast: Outputs.northeast, + east: Outputs.east, + west: Outputs.west, + northwest: Outputs.northwest, + busterOnYou: Outputs.tankBusterOnYou, + busterSafe: { + en: '${buster} + ${safe}', + }, + busterDirs: { + en: '${dir1}/${dir2}', + }, + }, }, { id: 'R12S In Line Debuff Collector', @@ -1652,7 +1879,6 @@ const triggerSet: TriggerSet = { { id: 'R12S Curtain Call: Unbreakable Flesh α Chains', // All players, including dead, receive α debuffs - // TODO: Find safe spots type: 'GainsEffect', netRegex: { effectId: '1291', capture: true }, condition: (data, matches) => { @@ -1660,15 +1886,34 @@ const triggerSet: TriggerSet = { return true; return false; }, - infoText: (_data, _matches, output) => { + infoText: (data, _matches, output) => { + const dir1 = data.curtainCallSafeCorner; + const dir2 = dir1 === 'northwest' ? 'southeast' : 'southwest'; // NOTE: Not checking for undefined + + if (dir1) { + return output.alphaChains!({ + chains: output.breakChains!(), + safe: output.safeSpots!({ + dir1: output[dir1]!(), + dir2: output[dir2]!(), + }), + }); + } return output.alphaChains!({ chains: output.breakChains!(), - safe: output.safeSpots!(), + safe: output.avoidBlobs!(), }); }, outputStrings: { + northeast: Outputs.northeast, + southeast: Outputs.southeast, + southwest: Outputs.southwest, + northwest: Outputs.northwest, breakChains: Outputs.breakChains, safeSpots: { + en: '${dir1}/${dir2}', + }, + avoidBlobs: { en: 'Avoid Blobs', }, alphaChains: { @@ -1676,6 +1921,76 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'R12S Curtain Call Safe Spot', + type: 'LosesEffect', + netRegex: { effectId: '1291', capture: true }, + condition: (data, matches) => { + if (matches.target === data.me && data.phase === 'curtainCall') + return true; + return false; + }, + promise: async (data) => { + if (data.triggerSetConfig.curtainCallStrat !== 'ns') + return; + const dir1 = data.curtainCallSafeCorner; + const dir2 = dir1 === 'northwest' ? 'southeast' : 'southwest'; // NOTE: Not checking for undefined + const combatants = (await callOverlayHandler({ + call: 'getCombatants', + names: [data.me], + })).combatants; + const me = combatants[0]; + if (combatants.length !== 1 || me === undefined) { + console.error( + `R12S Curtain Call Safe Spot: Wrong combatants count ${combatants.length}`, + ); + return; + } + + const x = me.PosX; + const y = me.PosY; + // Loose detection for "closeness" + if (y > 100) { + // Southern most players, check if they should run north or south + if (x < 100) + data.myCurtainCallSafeSpot = dir1 === 'northeast' ? dir2 : dir1; + else if (x >= 100) + data.myCurtainCallSafeSpot = dir1 === 'northeast' ? dir1 : dir2; + } else if (y <= 100) { + // Northern most players run to the northern most safe spot + data.myCurtainCallSafeSpot = dir1; + } + }, + alertText: (data, _matches, output) => { + if (data.triggerSetConfig.curtainCallStrat === 'none') { + const dir1 = data.curtainCallSafeCorner; + const dir2 = dir1 === 'northwest' ? 'southeast' : 'southwest'; // NOTE: Not checking for undefined + if (dir1 === undefined) + return output.avoidBlobs!(); + return output.safeSpots!({ + dir1: output[dir1]!(), + dir2: output[dir2]!(), + }); + } + + const myCurtainCallSafeSpot = data.myCurtainCallSafeSpot; + if (myCurtainCallSafeSpot === undefined) + return output.avoidBlobs!(); + return output[myCurtainCallSafeSpot]!(); + }, + outputStrings: { + northeast: Outputs.northeast, + southeast: Outputs.southeast, + southwest: Outputs.southwest, + northwest: Outputs.northwest, + avoidBlobs: { + en: 'Avoid Blobs', + }, + safeSpots: { + en: '${dir1}/${dir2}', + }, + }, + }, { id: 'R12S Slaughtershed', type: 'StartsUsing', @@ -1684,7 +1999,6 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Slaughtershed Stack', - // TODO: Get Safe spot type: 'HeadMarker', netRegex: { id: headMarkerData['slaughterStack'], capture: true }, condition: (data, matches) => { @@ -1696,17 +2010,62 @@ const triggerSet: TriggerSet = { return false; }, durationSeconds: 5.1, - response: Responses.stackMarkerOn(), + alertText: (data, matches, output) => { + const dir = data.splattershedStackDir; + const target = matches.target; + if (target === data.me) { + if (dir) + return output.stackDir!({ + stack: output.stackOnYou!(), + dir: output[dir]!(), + }); + return output.stackOnYou!(); + } + + const player = data.party.member(target); + if (dir) + return output.stackDir!({ + stack: output.stackOnPlayer!({ player: player }), + dir: output[dir]!(), + }); + return output.stackOnPlayer!({ player: player }); + }, + outputStrings: { + northeast: Outputs.northeast, + northwest: Outputs.northwest, + stackOnYou: Outputs.stackOnYou, + stackOnPlayer: Outputs.stackOnPlayer, + stackDir: { + en: '${stack} ${dir}', + }, + }, }, { 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(), + alertText: (data, _matches, output) => { + const stackDir = data.splattershedStackDir; + const dir = stackDir === 'northwest' + ? 'northeast' + : stackDir === 'northeast' + ? 'northwest' + : undefined; + if (dir) + return output.spreadDir!({ dir: output[dir]!() }); + return output.spread!(); + }, + outputStrings: { + northeast: Outputs.northeast, + northwest: Outputs.northwest, + spread: Outputs.spread, + spreadDir: { + en: 'Spread ${dir}', + }, + }, }, { id: 'R12S Serpintine Scourge Right Hand First', From 467ad68f3ba3a4ad6bc1dfdcdba6a7114004e770 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 00:56:20 -0500 Subject: [PATCH 176/215] extend replication2 config into locked tether Tells the rough direction of where to go (true north) --- ui/raidboss/data/07-dt/raid/r12s.ts | 325 +++++++++++++++++++++++++++- 1 file changed, 317 insertions(+), 8 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ae1718be6f7..aaed31a8227 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3063,60 +3063,294 @@ const triggerSet: TriggerSet = { // Check if it's the boss if (data.replication2BossId === sourceId) return output.fireballSplashTether!({ - mech1: output.baitJump!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) + : output.baitJump!(), }); // Get direction of the tether const actor = data.actorPositions[sourceId]; const ability = data.replication2PlayerAbilities[data.me]; + const clones = data.replication2CloneDirNumPlayers; + const myDirNum = Object.keys(clones).find( + (key) => clones[parseInt(key)] === data.me, + ); + const myDirNumInt = myDirNum === undefined ? -1 : parseInt(myDirNum); if (actor === undefined) { switch (ability) { case headMarkerData['projectionTether']: + switch (myDirNumInt) { + case 0: // Banana only + return output.projectionTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ + strat: output['dirWSW']!(), + }) // Southmost protean + : output.baitProtean!(), + }); + case 1: // DN only + return output.projectionTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) // Inner NNE + : output.baitProtean!(), + }); + case 4: // Banana only + return output.projectionTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ + strat: output['dirWNW']!(), + }) // Northmost protean + : output.baitProtean!(), + }); + case 7: // DN only + return output.projectionTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) // Inner NNW + : output.baitProtean!(), + }); + } return output.projectionTether!({ - mech1: output.baitProtean!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) + : output.baitProtean!(), }); case headMarkerData['manaBurstTether']: + switch (myDirNumInt) { + case 1: // Banana Only + return output.manaBurstTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.defamationOnYouStrategy!({ + strat: output['dirNNE']!(), + }) // North/NNE + : output.defamationOnYou!(), + }); + case 3: + return output.manaBurstTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.defamationOnYouStrategy!({ + strat: output['dirESE']!(), + }) // East/ESE + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.defamationOnYouStrategy!({ + strat: output['dirSSE']!(), + }) // South/SSE + : output.defamationOnYou!(), + }); + case 5: // DN Only + return output.manaBurstTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.defamationOnYouStrategy!({ + strat: output['dirWSW']!(), + }) // West/WSW + : output.defamationOnYou!(), + }); + } return output.manaBurstTether!({ mech1: output.defamationOnYou!(), }); case headMarkerData['heavySlamTether']: + switch (myDirNumInt) { + case 2: // DN Only + return output.heavySlamTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ + strat: output['dirNNE']!(), + }) // Eastmost Protean + : output.baitProtean!(), + }); + case 5: // Banana Only + return output.heavySlamTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) // Inner WSW + : output.baitProtean!(), + }); + case 6: // DN Only + return output.heavySlamTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ + strat: output['dirNNW']!(), + }) // Westmost Protean + : output.baitProtean!(), + }); + case 7: // Banana Only + return output.heavySlamTether!({ + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) // Inner WNW + : output.baitProtean!(), + }); + } return output.heavySlamTether!({ - mech1: output.baitProtean!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) + : output.baitProtean!(), }); } return; } - const dirNum = Directions.xyTo8DirNum(actor.x, actor.y, center.x, center.y); + const dirNum = Directions.xyTo8DirNum( + actor.x, + actor.y, + center.x, + center.y, + ); const dir = Directions.output8Dir[dirNum] ?? 'unknown'; switch (ability) { case headMarkerData['projectionTether']: + switch (myDirNumInt) { + case 0: // Banana only + return output.projectionTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ + strat: output['dirWSW']!(), + }) // Southmost protean + : output.baitProtean!(), + }); + case 1: // DN only + return output.projectionTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) // Inner NNE + : output.baitProtean!(), + }); + case 4: // Banana only + return output.projectionTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ + strat: output['dirWNW']!(), + }) // Northmost protean + : output.baitProtean!(), + }); + case 7: // DN only + return output.projectionTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) // Inner NNW + : output.baitProtean!(), + }); + } return output.projectionTetherDir!({ dir: output[dir]!(), - mech1: output.baitProtean!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) + : output.baitProtean!(), }); case headMarkerData['manaBurstTether']: + switch (myDirNumInt) { + case 1: // Banana Only + return output.manaBurstTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.defamationOnYouStrategy!({ + strat: output['dirNNE']!(), + }) // North/NNE + : output.defamationOnYou!(), + }); + case 3: + return output.manaBurstTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.defamationOnYouStrategy!({ + strat: output['dirESE']!(), + }) // East/ESE + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.defamationOnYouStrategy!({ + strat: output['dirSSE']!(), + }) // South/SSE + : output.defamationOnYou!(), + }); + case 5: // DN Only + return output.manaBurstTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.defamationOnYouStrategy!({ + strat: output['dirWSW']!(), + }) // West/WSW + : output.defamationOnYou!(), + }); + } return output.manaBurstTetherDir!({ dir: output[dir]!(), mech1: output.defamationOnYou!(), }); case headMarkerData['heavySlamTether']: + switch (myDirNumInt) { + case 2: // DN Only + return output.heavySlamTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ + strat: output['dirNNE']!(), + }) // Eastmost Protean + : output.baitProtean!(), + }); + case 5: // Banana Only + return output.heavySlamTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) // Inner WSW + : output.baitProtean!(), + }); + case 6: // DN Only + return output.heavySlamTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ + strat: output['dirNNW']!(), + }) // Westmost Protean + : output.baitProtean!(), + }); + case 7: // Banana Only + return output.heavySlamTetherDir!({ + dir: output[dir]!(), + mech1: data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) // Inner WNW + : output.baitProtean!(), + }); + } return output.heavySlamTetherDir!({ dir: output[dir]!(), - mech1: output.baitProtean!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.baitProteanStrategy!({ strat: output.north!() }) + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.baitProteanStrategy!({ strat: output.west!() }) + : output.baitProtean!(), }); } }, outputStrings: { - ...Directions.outputStrings8Dir, + ...Directions.outputStrings16Dir, + north: Outputs.north, + east: Outputs.east, + south: Outputs.south, + west: Outputs.west, defamationOnYou: Outputs.defamationOnYou, + defamationOnYouStrategy: { + en: 'Defamation on YOU, Go ${strat}', + }, baitProtean: { en: 'Bait Protean from Boss', }, + baitProteanStrategy: { + en: 'Bait Protean from Boss (${strat})', + }, baitJump: { en: 'Bait Jump', }, + baitJumpStrategy: { + en: 'Bait Jump ${strat}', + }, projectionTetherDir: { en: '${dir} Cone Tether: ${mech1}', }, @@ -3159,12 +3393,21 @@ const triggerSet: TriggerSet = { ) return; return output.noTether!({ - mech1: output.defamationOnYou!(), + mech1: data.triggerSetConfig.replication2Strategy === 'dn' + ? output.defamationOnYouStrategy!({ strat: output.south!() }) + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.defamationOnYouStrategy!({ strat: output.east!() }) + : output.defamationOnYou!(), mech2: output.stackGroups!(), }); }, outputStrings: { + east: Outputs.east, + south: Outputs.south, defamationOnYou: Outputs.defamationOnYou, + defamationOnYouStrategy: { + en: 'Defamation on YOU (Go ${strat})', + }, stackGroups: { en: 'Stack Groups', de: 'Gruppen-Sammeln', @@ -3245,6 +3488,72 @@ const triggerSet: TriggerSet = { }, }, }, + { + 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.replication2PlayerAbilities[data.me]; + 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 From 98f13f93947ea0942bc48360cb95e6706df655d3 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 01:02:39 -0500 Subject: [PATCH 177/215] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index aaed31a8227..e7de6add945 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3086,8 +3086,8 @@ const triggerSet: TriggerSet = { return output.projectionTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'banana' ? output.baitProteanStrategy!({ - strat: output['dirWSW']!(), - }) // Southmost protean + strat: output['dirWSW']!(), + }) // Southmost protean : output.baitProtean!(), }); case 1: // DN only @@ -3100,8 +3100,8 @@ const triggerSet: TriggerSet = { return output.projectionTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'banana' ? output.baitProteanStrategy!({ - strat: output['dirWNW']!(), - }) // Northmost protean + strat: output['dirWNW']!(), + }) // Northmost protean : output.baitProtean!(), }); case 7: // DN only @@ -3123,30 +3123,30 @@ const triggerSet: TriggerSet = { case 1: // Banana Only return output.manaBurstTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouStrategy!({ strat: output['dirNNE']!(), }) // North/NNE - : output.defamationOnYou!(), + : output.defamationOnYou!(), }); case 3: return output.manaBurstTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouStrategy!({ strat: output['dirESE']!(), }) // East/ESE - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.defamationOnYouStrategy!({ strat: output['dirSSE']!(), }) // South/SSE - : output.defamationOnYou!(), + : output.defamationOnYou!(), }); case 5: // DN Only return output.manaBurstTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouStrategy!({ strat: output['dirWSW']!(), }) // West/WSW - : output.defamationOnYou!(), + : output.defamationOnYou!(), }); } return output.manaBurstTether!({ @@ -3158,8 +3158,8 @@ const triggerSet: TriggerSet = { return output.heavySlamTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' ? output.baitProteanStrategy!({ - strat: output['dirNNE']!(), - }) // Eastmost Protean + strat: output['dirNNE']!(), + }) // Eastmost Protean : output.baitProtean!(), }); case 5: // Banana Only @@ -3172,8 +3172,8 @@ const triggerSet: TriggerSet = { return output.heavySlamTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' ? output.baitProteanStrategy!({ - strat: output['dirNNW']!(), - }) // Westmost Protean + strat: output['dirNNW']!(), + }) // Westmost Protean : output.baitProtean!(), }); case 7: // Banana Only @@ -3210,8 +3210,8 @@ const triggerSet: TriggerSet = { dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' ? output.baitProteanStrategy!({ - strat: output['dirWSW']!(), - }) // Southmost protean + strat: output['dirWSW']!(), + }) // Southmost protean : output.baitProtean!(), }); case 1: // DN only @@ -3226,8 +3226,8 @@ const triggerSet: TriggerSet = { dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' ? output.baitProteanStrategy!({ - strat: output['dirWNW']!(), - }) // Northmost protean + strat: output['dirWNW']!(), + }) // Northmost protean : output.baitProtean!(), }); case 7: // DN only @@ -3253,31 +3253,31 @@ const triggerSet: TriggerSet = { dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' ? output.defamationOnYouStrategy!({ - strat: output['dirNNE']!(), - }) // North/NNE + strat: output['dirNNE']!(), + }) // North/NNE : output.defamationOnYou!(), }); case 3: return output.manaBurstTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouStrategy!({ strat: output['dirESE']!(), }) // East/ESE - : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ + : data.triggerSetConfig.replication2Strategy === 'banana' + ? output.defamationOnYouStrategy!({ strat: output['dirSSE']!(), }) // South/SSE - : output.defamationOnYou!(), + : output.defamationOnYou!(), }); case 5: // DN Only return output.manaBurstTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouStrategy!({ strat: output['dirWSW']!(), }) // West/WSW - : output.defamationOnYou!(), + : output.defamationOnYou!(), }); } return output.manaBurstTetherDir!({ @@ -3291,8 +3291,8 @@ const triggerSet: TriggerSet = { dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' ? output.baitProteanStrategy!({ - strat: output['dirNNE']!(), - }) // Eastmost Protean + strat: output['dirNNE']!(), + }) // Eastmost Protean : output.baitProtean!(), }); case 5: // Banana Only @@ -3307,8 +3307,8 @@ const triggerSet: TriggerSet = { dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' ? output.baitProteanStrategy!({ - strat: output['dirNNW']!(), - }) // Westmost Protean + strat: output['dirNNW']!(), + }) // Westmost Protean : output.baitProtean!(), }); case 7: // Banana Only From 83572c1bd8715a9ecb193f5be99057042a8933c8 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 01:05:03 -0500 Subject: [PATCH 178/215] missed lint --- 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 e7de6add945..c78ecc5714d 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3252,10 +3252,10 @@ const triggerSet: TriggerSet = { return output.manaBurstTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ - strat: output['dirNNE']!(), - }) // North/NNE - : output.defamationOnYou!(), + ? output.defamationOnYouStrategy!({ + strat: output['dirNNE']!(), + }) // North/NNE + : output.defamationOnYou!(), }); case 3: return output.manaBurstTetherDir!({ From c550d095d0e5379cabffe973f48419c35ab7209e Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 01:09:06 -0500 Subject: [PATCH 179/215] fix paste error --- ui/raidboss/data/07-dt/raid/r12s.ts | 66 ----------------------------- 1 file changed, 66 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index c78ecc5714d..0a19497ae99 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3488,72 +3488,6 @@ const triggerSet: TriggerSet = { }, }, }, - { - 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.replication2PlayerAbilities[data.me]; - 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 From 7ef3f1a1c8244c7e0e7a0c98f1026e1e6408cb9b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 01:37:28 -0500 Subject: [PATCH 180/215] separate locked tether outputs based on clone dir Will be easier for players to manually modify the outputs based on config. --- ui/raidboss/data/07-dt/raid/r12s.ts | 122 +++++++++++++++++++--------- 1 file changed, 82 insertions(+), 40 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 0a19497ae99..8415cb879b0 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3064,9 +3064,9 @@ const triggerSet: TriggerSet = { if (data.replication2BossId === sourceId) return output.fireballSplashTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) + ? output.baitJumpDNN!({ strat: output.north!() }) : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) + ? output.baitJumpBananaW!({ strat: output.west!() }) : output.baitJump!(), }); @@ -3085,7 +3085,7 @@ const triggerSet: TriggerSet = { case 0: // Banana only return output.projectionTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ + ? output.baitProteanBananaN!({ strat: output['dirWSW']!(), }) // Southmost protean : output.baitProtean!(), @@ -3093,13 +3093,13 @@ const triggerSet: TriggerSet = { case 1: // DN only return output.projectionTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) // Inner NNE + ? output.baitProteanDNNE!({ strat: output.north!() }) // Inner NNE : output.baitProtean!(), }); case 4: // Banana only return output.projectionTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ + ? output.baitProteanBananaS!({ strat: output['dirWNW']!(), }) // Northmost protean : output.baitProtean!(), @@ -3107,15 +3107,15 @@ const triggerSet: TriggerSet = { case 7: // DN only return output.projectionTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) // Inner NNW + ? output.baitProteanDNNW!({ strat: output.north!() }) // Inner NNW : output.baitProtean!(), }); } return output.projectionTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) + ? output.baitProteanDN!({ strat: output.north!() }) : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) + ? output.baitProteanBanana!({ strat: output.west!() }) : output.baitProtean!(), }); case headMarkerData['manaBurstTether']: @@ -3123,7 +3123,7 @@ const triggerSet: TriggerSet = { case 1: // Banana Only return output.manaBurstTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouBananaNE!({ strat: output['dirNNE']!(), }) // North/NNE : output.defamationOnYou!(), @@ -3131,11 +3131,11 @@ const triggerSet: TriggerSet = { case 3: return output.manaBurstTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouDNSE!({ strat: output['dirESE']!(), }) // East/ESE : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouBananaSE!({ strat: output['dirSSE']!(), }) // South/SSE : output.defamationOnYou!(), @@ -3143,7 +3143,7 @@ const triggerSet: TriggerSet = { case 5: // DN Only return output.manaBurstTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouDNSW!({ strat: output['dirWSW']!(), }) // West/WSW : output.defamationOnYou!(), @@ -3157,7 +3157,7 @@ const triggerSet: TriggerSet = { case 2: // DN Only return output.heavySlamTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ + ? output.baitProteanDNE!({ strat: output['dirNNE']!(), }) // Eastmost Protean : output.baitProtean!(), @@ -3165,13 +3165,13 @@ const triggerSet: TriggerSet = { case 5: // Banana Only return output.heavySlamTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) // Inner WSW + ? output.baitProteanBananaSW!({ strat: output.west!() }) // Inner WSW : output.baitProtean!(), }); case 6: // DN Only return output.heavySlamTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ + ? output.baitProteanDNW!({ strat: output['dirNNW']!(), }) // Westmost Protean : output.baitProtean!(), @@ -3179,15 +3179,15 @@ const triggerSet: TriggerSet = { case 7: // Banana Only return output.heavySlamTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) // Inner WNW + ? output.baitProteanBananaNW!({ strat: output.west!() }) // Inner WNW : output.baitProtean!(), }); } return output.heavySlamTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) + ? output.baitProteanDN!({ strat: output.north!() }) : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) + ? output.baitProteanBanana!({ strat: output.west!() }) : output.baitProtean!(), }); } @@ -3209,7 +3209,7 @@ const triggerSet: TriggerSet = { return output.projectionTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ + ? output.baitProteanBananaN!({ strat: output['dirWSW']!(), }) // Southmost protean : output.baitProtean!(), @@ -3218,14 +3218,14 @@ const triggerSet: TriggerSet = { return output.projectionTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) // Inner NNE + ? output.baitProteanDNNE!({ strat: output.north!() }) // Inner NNE : output.baitProtean!(), }); case 4: // Banana only return output.projectionTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ + ? output.baitProteanBananaS!({ strat: output['dirWNW']!(), }) // Northmost protean : output.baitProtean!(), @@ -3234,16 +3234,16 @@ const triggerSet: TriggerSet = { return output.projectionTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) // Inner NNW + ? output.baitProteanDNNW!({ strat: output.north!() }) // Inner NNW : output.baitProtean!(), }); } return output.projectionTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) + ? output.baitProteanDN!({ strat: output.north!() }) : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) + ? output.baitProteanBanana!({ strat: output.west!() }) : output.baitProtean!(), }); case headMarkerData['manaBurstTether']: @@ -3252,7 +3252,7 @@ const triggerSet: TriggerSet = { return output.manaBurstTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouBananaNE!({ strat: output['dirNNE']!(), }) // North/NNE : output.defamationOnYou!(), @@ -3261,11 +3261,11 @@ const triggerSet: TriggerSet = { return output.manaBurstTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouDNSE!({ strat: output['dirESE']!(), }) // East/ESE : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouBananaSE!({ strat: output['dirSSE']!(), }) // South/SSE : output.defamationOnYou!(), @@ -3274,7 +3274,7 @@ const triggerSet: TriggerSet = { return output.manaBurstTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ + ? output.defamationOnYouDNSW!({ strat: output['dirWSW']!(), }) // West/WSW : output.defamationOnYou!(), @@ -3290,7 +3290,7 @@ const triggerSet: TriggerSet = { return output.heavySlamTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ + ? output.baitProteanDNE!({ strat: output['dirNNE']!(), }) // Eastmost Protean : output.baitProtean!(), @@ -3299,14 +3299,14 @@ const triggerSet: TriggerSet = { return output.heavySlamTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) // Inner WSW + ? output.baitProteanBananaSW!({ strat: output.west!() }) // Inner WSW : output.baitProtean!(), }); case 6: // DN Only return output.heavySlamTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ + ? output.baitProteanDNW!({ strat: output['dirNNW']!(), }) // Westmost Protean : output.baitProtean!(), @@ -3315,16 +3315,16 @@ const triggerSet: TriggerSet = { return output.heavySlamTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) // Inner WNW + ? output.baitProteanBananaNW!({ strat: output.west!() }) // Inner WNW : output.baitProtean!(), }); } return output.heavySlamTetherDir!({ dir: output[dir]!(), mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.baitProteanStrategy!({ strat: output.north!() }) + ? output.baitProteanDN!({ strat: output.north!() }) : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.baitProteanStrategy!({ strat: output.west!() }) + ? output.baitProteanBanana!({ strat: output.west!() }) : output.baitProtean!(), }); } @@ -3336,19 +3336,58 @@ const triggerSet: TriggerSet = { south: Outputs.south, west: Outputs.west, defamationOnYou: Outputs.defamationOnYou, - defamationOnYouStrategy: { + defamationOnYouDNSE: { + en: 'Defamation on YOU, Go ${strat}', + }, + defamationOnYouDNSW: { + en: 'Defamation on YOU, Go ${strat}', + }, + defamationOnYouBananaNE: { + en: 'Defamation on YOU, Go ${strat}', + }, + defamationOnYouBananaSE: { en: 'Defamation on YOU, Go ${strat}', }, baitProtean: { en: 'Bait Protean from Boss', }, - baitProteanStrategy: { + baitProteanDN: { // If clone tether num missing + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanDNNE: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanDNE: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanDNW: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanDNNW: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanBanana: { // If clone tether num missing + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanBananaN: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanBananaS: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanBananaSW: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanBananaNW: { en: 'Bait Protean from Boss (${strat})', }, baitJump: { en: 'Bait Jump', }, - baitJumpStrategy: { + baitJumpDNN: { + en: 'Bait Jump ${strat}', + }, + baitJumpBananaW: { en: 'Bait Jump ${strat}', }, projectionTetherDir: { @@ -3394,9 +3433,9 @@ const triggerSet: TriggerSet = { return; return output.noTether!({ mech1: data.triggerSetConfig.replication2Strategy === 'dn' - ? output.defamationOnYouStrategy!({ strat: output.south!() }) + ? output.defamationOnYouDN!({ strat: output.south!() }) : data.triggerSetConfig.replication2Strategy === 'banana' - ? output.defamationOnYouStrategy!({ strat: output.east!() }) + ? output.defamationOnYouBanana!({ strat: output.east!() }) : output.defamationOnYou!(), mech2: output.stackGroups!(), }); @@ -3405,7 +3444,10 @@ const triggerSet: TriggerSet = { east: Outputs.east, south: Outputs.south, defamationOnYou: Outputs.defamationOnYou, - defamationOnYouStrategy: { + defamationOnYouDN: { + en: 'Defamation on YOU (Go ${strat})', + }, + defamationOnYouBanana: { en: 'Defamation on YOU (Go ${strat})', }, stackGroups: { From b33a549100c3d433bcda5ab13e9809bbdfb1bd11 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 01:49:27 -0500 Subject: [PATCH 181/215] Reenactment 1 trigger name adjustments some prep for banana codex handling --- ui/raidboss/data/07-dt/raid/r12s.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 8415cb879b0..923040ce184 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3711,8 +3711,7 @@ 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 + // In DN, Players need to wait for BBE3 Mana Burst Defamations on the clones to complete before next mechanic type: 'Ability', netRegex: { id: 'B8E1', source: 'Lindwurm', capture: false }, condition: (data) => data.phase === 'reenactment1', @@ -3720,7 +3719,7 @@ const triggerSet: TriggerSet = { run: (data) => data.netherwrathFollowup = true, }, { - id: 'R12S Reenactment 1 Clone Stacks', + id: 'R12S Reenactment 1 Clone Stacks E/W', // 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 @@ -3753,7 +3752,7 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Reenactment 1 Final Defamation Dodge Reminder', + id: 'R12S Reenactment 1 Final Defamation SE 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 From e6206e5e43e0c31b0a69b6735cce60ddd6650dae Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 03:19:29 -0500 Subject: [PATCH 182/215] fix 'bug' in setting 'none' This will be important later when checking order as the 'none' attribute is expected and not 'unknown'. 'unknown' will mean something else unexpected. --- 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 923040ce184..773149b1937 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3029,7 +3029,6 @@ const triggerSet: TriggerSet = { if (data.replication2PlayerAbilities[data.me] === undefined) data.replication2PlayerAbilities[data.me] = 'none'; - // Used for Twisted Vision 7 and 8 mechanics const abilities = data.replication2PlayerAbilities; const order = [0, 4, 1, 5, 2, 6, 3, 7]; // Order in which clones spawned, this is static const players = data.replication2CloneDirNumPlayers; // Direction of player's clone @@ -3037,7 +3036,11 @@ const triggerSet: TriggerSet = { // Mechanics are resolved clockwise for (const dirNum of order) { const player = players[dirNum] ?? 'unknown'; - const ability = abilities[player] ?? 'unknown'; + // No Tether player wouldn't have an ability found for other + // players, so this can be set to 'none' here when undefined + // Additional players missing abilities, but received a tether + // would have 'unknown' instead of undefined + const ability = abilities[player] ?? 'none'; data.replication2PlayerOrder.push(player); data.replication2AbilityOrder.push(ability); } From 2b725f7f623b6cdf4b80f622b7a57da02cccdeaa Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 03:44:38 -0500 Subject: [PATCH 183/215] support generic netherwrath far/near also adds strategy detection for DN/Banana Codex --- ui/raidboss/data/07-dt/raid/r12s.ts | 228 +++++++++++++++++++++------- 1 file changed, 176 insertions(+), 52 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 773149b1937..9fe2058e59c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3569,94 +3569,189 @@ const triggerSet: TriggerSet = { }, { id: 'R12S Netherwrath Near/Far', - // Boss jumps onto clone of player that took Firefall Splash, there is an aoe around the clone + proteans + // In DN, Boss jumps onto clone of player that took Firefall Splash, there is an aoe around the clone + proteans + // In Banana Codex, N/S Projections happen at this time type: 'StartsUsing', netRegex: { id: ['B52E', 'B52F'], source: 'Lindwurm', capture: true }, infoText: (data, matches, output) => { const ability = data.replication2PlayerAbilities[data.me]; const isNear = matches.id === 'B52E'; - if (isNear) { + // Determine if it's a strategy we recognize + const order = data.replication2AbilityOrder; + const boss = headMarkerData['fireballSplashTether']; + const defamation = headMarkerData['manaBurstTether']; + const stack = headMarkerData['heavySlamTether']; + const projection = headMarkerData['projectionTether']; + + // DN Strategy + if ( + ( + (order[0] === 'none' && order[1] === boss) || + (order[0] === boss && order[1] === 'none') + ) && ( + (order[2] === defamation && order[3] === projection) || + (order[2] === projection && order[3] === defamation) + ) && (order[4] === stack && order[5] === stack) + ) { + 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.projectionTetherNear!({ - proteanBaits: output.beFar!(), + return output.projectionTetherFar!({ + proteanBaits: output.beNear!(), mech1: output.scaldingWave!(), mech2: output.stacks!(), - spiteBaits: output.near!(), + spiteBaits: output.far!(), }); case headMarkerData['manaBurstTether']: - return output.manaBurstTetherNear!({ - spiteBaits: output.beNear!(), + return output.manaBurstTetherFar!({ + spiteBaits: output.beFar!(), mech1: output.timelessSpite!(), mech2: output.proteans!(), - proteanBaits: output.far!(), + proteanBaits: output.near!(), }); case headMarkerData['heavySlamTether']: - return output.heavySlamTetherNear!({ - proteanBaits: output.beFar!(), + return output.heavySlamTetherFar!({ + proteanBaits: output.beNear!(), mech1: output.scaldingWave!(), mech2: output.stacks!(), - spiteBaits: output.near!(), + spiteBaits: output.far!(), }); case headMarkerData['fireballSplashTether']: - return output.fireballSplashTetherNear!({ - spiteBaits: output.beNear!(), + return output.fireballSplashTetherFar!({ + spiteBaits: output.beFar!(), mech1: output.timelessSpite!(), mech2: output.proteans!(), - proteanBaits: output.far!(), + proteanBaits: output.near!(), }); } - return output.noTetherNear!({ - spiteBaits: output.beNear!(), + return output.noTetherFar!({ + spiteBaits: output.beFar!(), mech1: output.timelessSpite!(), mech2: output.proteans!(), - proteanBaits: output.far!(), + proteanBaits: output.near!(), }); } - // Netherwrath Far - switch (ability) { - case headMarkerData['projectionTether']: - return output.projectionTetherFar!({ - proteanBaits: output.beNear!(), - mech1: output.scaldingWave!(), - mech2: output.stacks!(), - spiteBaits: output.far!(), - }); - case headMarkerData['manaBurstTether']: - return output.manaBurstTetherFar!({ - spiteBaits: output.beFar!(), - mech1: output.timelessSpite!(), - mech2: output.proteans!(), - proteanBaits: output.near!(), - }); - case headMarkerData['heavySlamTether']: - return output.heavySlamTetherFar!({ - proteanBaits: output.beNear!(), - mech1: output.scaldingWave!(), - mech2: output.stacks!(), - spiteBaits: output.far!(), - }); - case headMarkerData['fireballSplashTether']: - return output.fireballSplashTetherFar!({ - spiteBaits: output.beFar!(), - mech1: output.timelessSpite!(), - mech2: output.proteans!(), - proteanBaits: output.near!(), - }); + // Banana Codex Strategy + if ( + (order[0] === projection && order[1] === projection) && ( + (order[2] === stack && order[3] === defamation) || + (order[2] === defamation && order[3] === stack) + ) && ( + (order[4] === boss && order[5] === 'none') || + (order[4] === 'none' && order[5] === boss) + ) + ) { + // Technically, this strategy does not care about Near/Far, but + // included as informational + switch (ability) { + case headMarkerData['projectionTether']: + return output.projectionTetherBait!({ + mech1: output.timelessSpite!(), + spiteBaits: isNear ? output.near!() : output.far!(), + mech2: output.stackDir!({ dir: output.dirSW!() }), + }); + case headMarkerData['manaBurstTether']: + return output.manaBurstTetherHitbox!({ + mech1: output.hitboxWest!(), + spiteBaits: isNear ? output.near!() : output.far!(), + mech2: output.proteans!(), + }); + case headMarkerData['heavySlamTether']: + return output.heavySlamTetherBait!({ + mech1: output.timelessSpite!(), + spiteBaits: isNear ? output.near!() : output.far!(), + mech2: output.stackDir!({ dir: output.dirSW!() }), + }); + case headMarkerData['fireballSplashTether']: + return output.fireballSplashTetherHitbox!({ + mech1: output.hitboxWest!(), + spiteBaits: isNear ? output.near!() : output.far!(), + mech2: output.proteans!(), + }); + } + return output.noTetherHitbox!({ + mech1: output.hitboxWest!(), + spiteBaits: isNear ? output.near!() : output.far!(), + mech2: output.proteans!(), + }); } - return output.noTetherFar!({ - spiteBaits: output.beFar!(), - mech1: output.timelessSpite!(), - mech2: output.proteans!(), - proteanBaits: output.near!(), + + // No built-in strategy / unsupported order, call generic far/near and + // what's happening next + const getMechanic = ( + order: string, + ): 'proteans' | 'defamation' | 'projection' | 'stack' | 'unknown' => { + if (order === boss) + return 'proteans'; + if (order === defamation || order === 'none') + return 'defamation'; + if (order === projection) + return 'projection'; + if (order === stack) + return 'stack'; + return 'unknown'; + }; + const mechanic1 = getMechanic(order[0] ?? 'unknown'); + const mechanic2 = getMechanic(order[1] ?? 'unknown'); + const mechanic3 = getMechanic(order[2] ?? 'unknown'); + const mechanic4 = getMechanic(order[3] ?? 'unknown'); + return output.netherwrathMechThenMech!({ + spiteBaits: isNear ? output.near!() : output.far!(), + mech1: output[mechanic1]!(), + mech2: output[mechanic2]!(), + mech3: output[mechanic3]!(), + mech4: output[mechanic4]!(), }); }, outputStrings: { + dirSW: Outputs.dirSW, scaldingWave: Outputs.protean, timelessSpite: Outputs.stackPartner, stacks: Outputs.stacks, + stackDir: { + en: 'Stack ${dir}', + }, proteans: { en: 'Proteans', }, @@ -3666,6 +3761,9 @@ const triggerSet: TriggerSet = { beFar: { en: 'Be Far', }, + hitboxWest: { + en: 'Be West on Boss Hitbox', + }, near: { en: 'Near', de: 'Nah', @@ -3710,6 +3808,32 @@ const triggerSet: TriggerSet = { noTetherNear: { en: '${spiteBaits} + ${mech1} (${mech2} ${proteanBaits})', }, + projectionTetherBait: { + en: '${mech1} (${spiteBaits} Baits) => ${mech2}', + }, + manaBurstTetherHitbox: { + en: '${mech1} + Avoid ${spiteBaits} Baits => ${mech2}', + }, + heavySlamTetherBait: { + en: '${mech1} (${spiteBaits} Baits) => ${mech2}', + }, + fireballSplashTetherHitbox: { + en: '${mech1} + Avoid ${spiteBaits} Baits => ${mech2}', + }, + noTetherHitbox: { + en: '${mech1} + Avoid ${spiteBaits} Baits => ${mech2}', + }, + stack: Outputs.stackMarker, + projection: { + en: 'Cones', + }, + defamation: { + en: 'Defamation', + }, + unknown: Outputs.unknown, + netherwrathMechThenMech: { + en: '${spiteBaits} Baits + ${mech1} N + ${mech2} S => ${mech3} NE + ${mech4} SW', + }, }, }, { From 6f6636a63eb2966d2f212ce06e90abdbdff5e03f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 04:05:06 -0500 Subject: [PATCH 184/215] add banana codex based clone stack sw trigger --- ui/raidboss/data/07-dt/raid/r12s.ts | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 9fe2058e59c..1408587bcce 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3845,6 +3845,59 @@ const triggerSet: TriggerSet = { suppressSeconds: 9999, run: (data) => data.netherwrathFollowup = true, }, + { + id: 'R12S Reenactment 1 Clone Stack SW', + // In Banana Codex, SW Clone Stack happens after N/S Clone Projections + // Defamation Tether Players, Boss Tether Player, and No Tether Player take stack + // Using B922 Hemorrhagic Projection from clones + type: 'Ability', + netRegex: { id: 'B922', source: 'Lindwurm', capture: false }, + condition: (data) => { + const order = data.replication2AbilityOrder; + const stack = headMarkerData['heavySlamTether']; + const defamation = headMarkerData['manaBurstTether']; + const projection = headMarkerData['projectionTether']; + // Defined as N/S clones with projections and NE/SW with defamation + stack + if ( + order[0] === projection && order[1] === projection && + ( + (order[2] === defamation && order[3] === stack) || + (order[2] === stack && order[3] === defamation) + ) + ) + return true; + return false; + }, + suppressSeconds: 9999, // Projection happens twice here + response: (data, _matches, output) => { + // cactbot-builtin-response + output.responseOutputStrings = { + stackThenStack: { + en: 'Stack on SW Clone => Stack on NW Clone', + }, + avoidStackThenProtean: { + en: 'Avoid Stack => Bait Protean', + }, + stacksThenProtean: { + en: 'SW Clone Stack => West Proteans', + }, + }; + + const ability = data.replication2PlayerAbilities[data.me]; + switch (ability) { + case headMarkerData['projectionTether']: + case headMarkerData['heavySlamTether']: + return { infoText: output.avoidStackThenProtean!() }; + case headMarkerData['manaBurstTether']: + case headMarkerData['fireballSplashTether']: + case 'none': + return { alertText: output.stackThenStack!() }; + } + + // Missing ability data, output mechanic order + return { infoText: output.stacksThenProtean!() }; + }, + }, { id: 'R12S Reenactment 1 Clone Stacks E/W', // Players need to wait for BBE3 Mana Burst defamations on clones to complete From ee27cc532b36fa5e977e8f03a41e0f03335d1a11 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 04:12:33 -0500 Subject: [PATCH 185/215] lint + additional order check Since the trigger is predicting up to Stack on NW clone, that last check is needed --- ui/raidboss/data/07-dt/raid/r12s.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 1408587bcce..56a9a19f0f7 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3857,12 +3857,18 @@ const triggerSet: TriggerSet = { const stack = headMarkerData['heavySlamTether']; const defamation = headMarkerData['manaBurstTether']; const projection = headMarkerData['projectionTether']; + const boss = headMarkerData['fireballSplashTether']; // Defined as N/S clones with projections and NE/SW with defamation + stack + // Followed up with E/W boss + none, then SE/NW stack + defamation + // No need to check 6, 7 as that's all that remains if ( order[0] === projection && order[1] === projection && ( (order[2] === defamation && order[3] === stack) || (order[2] === stack && order[3] === defamation) + ) && ( + (order[4] === boss && order[5] === 'none') || + (order[4] === 'none' && order[5] === boss) ) ) return true; @@ -3895,7 +3901,7 @@ const triggerSet: TriggerSet = { } // Missing ability data, output mechanic order - return { infoText: output.stacksThenProtean!() }; + return { infoText: output.stacksThenProtean!() }; }, }, { From 5d71b237750f33832ae89587de2c5fc27cc9338f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 04:59:08 -0500 Subject: [PATCH 186/215] remaining rep2 banana triggers --- ui/raidboss/data/07-dt/raid/r12s.ts | 144 +++++++++++++++++++++++++--- 1 file changed, 132 insertions(+), 12 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 56a9a19f0f7..dc806dc81ea 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3568,7 +3568,7 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Netherwrath Near/Far', + id: 'R12S Netherwrath Near/Far and First Clones', // In DN, Boss jumps onto clone of player that took Firefall Splash, there is an aoe around the clone + proteans // In Banana Codex, N/S Projections happen at this time type: 'StartsUsing', @@ -3837,8 +3837,11 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Reenactment 1 Scalding Waves Collect', - // In DN, Players need to wait for BBE3 Mana Burst Defamations on the clones to complete before next mechanic + id: 'R12S Reenactment 1 Scalding Waves Collect (DN)', + // NOTE: This is used in DN Strategy + // Players need to wait for BBE3 Mana Burst Defamations on the clones to complete before next mechanic + // There are multiple BBE3s, setting flag to trigger after + // B8E1 Scalding Waves type: 'Ability', netRegex: { id: 'B8E1', source: 'Lindwurm', capture: false }, condition: (data) => data.phase === 'reenactment1', @@ -3846,8 +3849,9 @@ const triggerSet: TriggerSet = { run: (data) => data.netherwrathFollowup = true, }, { - id: 'R12S Reenactment 1 Clone Stack SW', - // In Banana Codex, SW Clone Stack happens after N/S Clone Projections + id: 'R12S Reenactment 1 Clone Stack SW (Second Clones Banana)', + // NOTE: This is used in Banana Codex Strategy + // SW Clone Stack happens after N/S Clone Projections // Defamation Tether Players, Boss Tether Player, and No Tether Player take stack // Using B922 Hemorrhagic Projection from clones type: 'Ability', @@ -3882,9 +3886,9 @@ const triggerSet: TriggerSet = { en: 'Stack on SW Clone => Stack on NW Clone', }, avoidStackThenProtean: { - en: 'Avoid Stack => Bait Protean', + en: 'Avoid SW Stack => Bait Protean West', }, - stacksThenProtean: { + stackThenProteans: { en: 'SW Clone Stack => West Proteans', }, }; @@ -3901,14 +3905,14 @@ const triggerSet: TriggerSet = { } // Missing ability data, output mechanic order - return { infoText: output.stacksThenProtean!() }; + return { infoText: output.stackThenProteans!() }; }, }, { - id: 'R12S Reenactment 1 Clone Stacks E/W', + id: 'R12S Reenactment 1 Clone Stacks E/W (Third Clones DN)', + // NOTE: This is used with DN Strategy // 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) => { @@ -3938,10 +3942,68 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Reenactment 1 Final Defamation SE Dodge Reminder', + id: 'R12S Reenactment 1 Proteans West (Third Clones Banana)', + // NOTE: This is used in Banana Codex Strategy + // Stack Players need to go to the other stack + // Non-stack players need to bait proteans + // Using BE5D Heavy Slam from clones + type: 'Ability', + netRegex: { id: 'BE5D', source: 'Lindwurm', capture: false }, + condition: (data) => { + const order = data.replication2AbilityOrder; + const stack = headMarkerData['heavySlamTether']; + const defamation = headMarkerData['manaBurstTether']; + const projection = headMarkerData['projectionTether']; + const boss = headMarkerData['fireballSplashTether']; + // Banana Codex Strategy Order + if ( + order[0] === projection && order[1] === projection && + ( + (order[2] === defamation && order[3] === stack) || + (order[2] === stack && order[3] === defamation) + ) && ( + (order[4] === boss && order[5] === 'none') || + (order[4] === 'none' && order[5] === boss) + ) + ) + return true; + return false; + }, + suppressSeconds: 9999, + response: (data, _matches, output) => { + // cactbot-builtin-response + output.responseOutputStrings = { + protean: { + en: 'Bait Protean West + Avoid Clone AoE', + }, + avoidThenStack: { + en: 'Avoid West Clone/East Defamation + Stack on NW Clone', + }, + proteansThenStack: { + en: 'West Proteans => NW Clone Stack', + }, + }; + + const ability = data.replication2PlayerAbilities[data.me]; + switch (ability) { + case headMarkerData['projectionTether']: + case headMarkerData['heavySlamTether']: + return { alertText: output.protean!() }; + case headMarkerData['manaBurstTether']: + case headMarkerData['fireballSplashTether']: + case 'none': + return { infoText: output.avoidThenStack!() }; + } + + // Missing ability data, output mechanic order + return { infoText: output.proteansThenStack!() }; + }, + }, + { + id: 'R12S Reenactment 1 Defamation SE Dodge Reminder (Fourth Clones DN)', + // NOTE: This is used with DN Strategy // 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) => { @@ -3968,6 +4030,64 @@ const triggerSet: TriggerSet = { north: Outputs.north, }, }, + { + id: 'R12S Reenactment 1 Clone Stack NW Reminder (Fourth Clones Banana)', + // NOTE: This is used in Banana Codex Strategy + // Reminder for players to Stack + // Reminder for Non-stack players to avoid + // Using B8E1 Scalding Waves from clones + type: 'Ability', + netRegex: { id: 'B8E1', source: 'Lindwurm', capture: false }, + condition: (data) => { + const order = data.replication2AbilityOrder; + const stack = headMarkerData['heavySlamTether']; + const defamation = headMarkerData['manaBurstTether']; + const projection = headMarkerData['projectionTether']; + const boss = headMarkerData['fireballSplashTether']; + // Banana Codex Strategy Order + if ( + order[0] === projection && order[1] === projection && + ( + (order[2] === defamation && order[3] === stack) || + (order[2] === stack && order[3] === defamation) + ) && ( + (order[4] === boss && order[5] === 'none') || + (order[4] === 'none' && order[5] === boss) + ) + ) + return true; + return false; + }, + suppressSeconds: 9999, + response: (data, _matches, output) => { + // cactbot-builtin-response + output.responseOutputStrings = { + stack: { + en: 'Stack on NW Clone', + }, + avoidStack: { + en: 'Avoid NE Stack', + }, + stackAndDefamation: { + en: 'NW Clone Stack + SE Defamation', + }, + }; + + const ability = data.replication2PlayerAbilities[data.me]; + switch (ability) { + case headMarkerData['projectionTether']: + case headMarkerData['heavySlamTether']: + return { infoText: output.avoidStack!() }; + case headMarkerData['manaBurstTether']: + case headMarkerData['fireballSplashTether']: + case 'none': + return { alertText: output.stack!() }; + } + + // Missing ability data, output mechanic order + return { infoText: output.stackAndDefamation!() }; + }, + }, { id: 'R12S Mana Sphere Collect and Label', // Combatants Spawn ~3s before B505 Mutating Cells startsUsing From 2cb053c9f92995c93075272fcfb9aa56393c7d54 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 18:34:32 -0500 Subject: [PATCH 187/215] increase R12s black and shapes delay ran into a log where data came late --- 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 dc806dc81ea..32096888a2b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4233,7 +4233,7 @@ const triggerSet: TriggerSet = { // Black Holes and shapes type: 'Ability', netRegex: { id: 'B4FD', source: 'Mana Sphere', capture: false }, - delaySeconds: 0.1, + delaySeconds: 0.2, durationSeconds: 8.3, suppressSeconds: 9999, infoText: (data, _matches, output) => { From 05dabd6f5a0adb043834cf24eb6b89a03a711cb9 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 20:59:01 -0500 Subject: [PATCH 188/215] fix p1 curtain call blob safe spots --- 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 32096888a2b..678f3a5cf50 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -572,9 +572,9 @@ const triggerSet: TriggerSet = { ) { // Curtain Call Safe Spots if (x < 92) - data.curtainCallSafeCorner = 'northwest'; - else if (x > 109) data.curtainCallSafeCorner = 'northeast'; + else if (x > 109) + data.curtainCallSafeCorner = 'northwest'; } else if ( data.act1SafeCorner !== undefined && data.curtainCallSafeCorner !== undefined && From bee71de73bace5e23d6fc9cb558eab4af2d6be17 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 21:27:19 -0500 Subject: [PATCH 189/215] updates from p1 blobs --- ui/raidboss/data/07-dt/raid/r12s.ts | 74 ++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 678f3a5cf50..ef3549ffe17 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -806,6 +806,78 @@ const triggerSet: TriggerSet = { goWest: Outputs.west, }, }, + { + id: 'R12S Act 1 Blob Safe Spots (early)', + // Activating on B49D Ravenous Reach conclusion + type: 'Ability', + netRegex: { id: 'B49D', source: 'Lindwurm', capture: true }, + delaySeconds: 0.3, // Delay until debuffs ended + suppressSeconds: 9999, // In case players are hit by the ability + infoText: (data, _matches, output) => { + const reach = data.ravenousReach1SafeSide; + const dir1 = data.act1SafeCorner; + const dir2 = dir1 === 'northwest' ? 'east' : 'west'; // NOTE: Not checking undefined here + + // Safe spot of side party is assumed to be on + if (data.role !== 'tank') { + const dir = dir1 === undefined + ? dir1 + : reach === dir2 + ? dir2 + : reach === dir1.slice(5) + ? dir1 + : undefined; + + if (dir1) { + if (dir) { + return output.safeSpot!({ + safe: output[dir]!(), + }); + } + return output.safeSpot!({ + safe: output.safeDirs!({ + dir1: output[dir1]!(), + dir2: output[dir2]!(), + }), + }); + } + } + + // Safe spot of opposite assumed side party will be + const dir = dir1 === undefined + ? dir1 + : reach === dir2 + ? dir1 + : reach === dir1.slice(5) + ? dir2 + : undefined; + if (dir1) { + if (dir) { + return output.safeSpot!({ + safe: output[dir]!(), + }); + } + return output.safeSpot!({ + safe: output.safeDirs!({ + dir1: output[dir1]!(), + dir2: output[dir2]!(), + }), + }); + } + }, + outputStrings: { + northeast: Outputs.northeast, + east: Outputs.east, + west: Outputs.west, + northwest: Outputs.northwest, + safeSpot: { + en: '${safe} (later)', + }, + safeDirs: { + en: '${dir1}/${dir2}', + }, + }, + }, { id: 'R12S Fourth-wall Fusion Stack', type: 'HeadMarker', @@ -875,7 +947,7 @@ const triggerSet: TriggerSet = { stackOnYou: Outputs.stackOnYou, stackOnTarget: Outputs.stackOnPlayer, stackSafe: { - en: '${stack} + ${safe}', + en: '${stack} ${safe}', }, stackDirs: { en: '${dir1}/${dir2}', From 16400fd0de6654cb3f921fba3c42a9233fb53006 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 21:30:31 -0500 Subject: [PATCH 190/215] remove 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 ef3549ffe17..3db2b515222 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -810,7 +810,7 @@ const triggerSet: TriggerSet = { id: 'R12S Act 1 Blob Safe Spots (early)', // Activating on B49D Ravenous Reach conclusion type: 'Ability', - netRegex: { id: 'B49D', source: 'Lindwurm', capture: true }, + netRegex: { id: 'B49D', source: 'Lindwurm', capture: false }, delaySeconds: 0.3, // Delay until debuffs ended suppressSeconds: 9999, // In case players are hit by the ability infoText: (data, _matches, output) => { From e6fc807cb9d6341f6b73b2081a26ba81f6a0ed1b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 22:36:18 -0500 Subject: [PATCH 191/215] flip EW/NS idyllic actor I think this makes sense since the first call is working (north/south) and it cleaves NS early on. --- 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 3db2b515222..16877d1c1c5 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4635,14 +4635,14 @@ const triggerSet: TriggerSet = { case 'B510': { const y = parseFloat(matches.y); data.idyllicVision2NorthSouthCleaveSpot = y < center.y ? 'north' : 'south'; - data.idyllicDreamActorEW = matches.sourceId; + data.idyllicDreamActorNS = matches.sourceId; return; } case 'B511': data.idyllicDreamActorSnaking = matches.sourceId; return; case 'B50F': - data.idyllicDreamActorNS = matches.sourceId; + data.idyllicDreamActorEW = matches.sourceId; return; } }, From b8d929c68f8ced3225bae99a729c290fe31345cc Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 22:46:36 -0500 Subject: [PATCH 192/215] fix mech2 output for banana codex during netherwrath --- 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 16877d1c1c5..084405453f7 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3761,31 +3761,31 @@ const triggerSet: TriggerSet = { return output.projectionTetherBait!({ mech1: output.timelessSpite!(), spiteBaits: isNear ? output.near!() : output.far!(), - mech2: output.stackDir!({ dir: output.dirSW!() }), + mech2: output.proteans!(), }); case headMarkerData['manaBurstTether']: return output.manaBurstTetherHitbox!({ mech1: output.hitboxWest!(), spiteBaits: isNear ? output.near!() : output.far!(), - mech2: output.proteans!(), + mech2: output.stackDir!({ dir: output.dirSW!() }), }); case headMarkerData['heavySlamTether']: return output.heavySlamTetherBait!({ mech1: output.timelessSpite!(), spiteBaits: isNear ? output.near!() : output.far!(), - mech2: output.stackDir!({ dir: output.dirSW!() }), + mech2: output.proteans!(), }); case headMarkerData['fireballSplashTether']: return output.fireballSplashTetherHitbox!({ mech1: output.hitboxWest!(), spiteBaits: isNear ? output.near!() : output.far!(), - mech2: output.proteans!(), + mech2: output.stackDir!({ dir: output.dirSW!() }), }); } return output.noTetherHitbox!({ mech1: output.hitboxWest!(), spiteBaits: isNear ? output.near!() : output.far!(), - mech2: output.proteans!(), + mech2: output.stackDir!({ dir: output.dirSW!() }), }); } From 75ef2c5c36025b52dcacbf1c22c1e5da08e2ef49 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Mon, 23 Feb 2026 23:44:39 -0500 Subject: [PATCH 193/215] reenactment multi-strategy support, add missing gusher at end Now shows generic reenactment 1, but will jump to DN branch if boss clone is found first, jump to Banana Codex branch if Grotesquerie clone is found first, or go through generic output until shapes (forcejump). --- ui/raidboss/data/07-dt/raid/r12s.txt | 261 +++++++++++++++------------ 1 file changed, 146 insertions(+), 115 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index ab8057ceeb2..c13b9445f90 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -335,7 +335,7 @@ hideall "--sync--" ### Phase 2: Lindwurm II -# -p B528:3015.7 +# -p B528:3015.7 B505:3483.8 # -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 B4F5 B512 B513 B514 B515 B4F9 B51B # -it "Lindwurm" 3000.5 label "r12s-p2-start" @@ -378,105 +378,136 @@ hideall "--sync--" 3137.3 "Hemorrhagic Projection x2" Ability { id: "B4EB", source: "Lindwurm" } 3141.1 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } +# NOTE: Without access to data from triggers, make a best guess based on first +# ability detection from clones. 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" } +3159.4 "Firefall Splash?" Ability { id: "B4ED", source: "Lindschrat" } jump "r12s-p2-dn-reenactment2" +3159.4 "--sync--" Ability { id: "B4F1", source: "Lindschrat" } jump "r12s-p2-bc-reenactment2" # Grotesquerie clone VFX +3159.4 "Netherwrath Near/Netherwrath Far" #Ability { id: ["B52E", "B52F"], source: "Lindwurm" } +3160.6 "--n/s clones--" +3164.5 "--ne/sw clones--" +3168.8 "--e/w clones--" +3172.6 "--se/nw clones--" +3178.6 "--middle--" #Ability { id: "B4D9", source: "Lindwurm" } +3180.8 "--sync--" StartsUsing { id: "B505", source: "Lindwurm" } forcejump "r12s-p2-mutating-cells" + +# DN Reenactment 1 +3259.4 label "r12s-p2-dn-reenactment2" +3259.4 "Netherwrath Near/Netherwrath Far" #Ability { id: ["B52E", "B52F"], source: "Lindwurm" } +3260.6 "Mana Burst 1" Ability { id: "BBE3", source: "Lindwurm" } +3260.6 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } +3260.7 "Scalding Waves x4" #Ability { id: "B8E1", source: "Lindwurm" } +3264.5 "Grotesquerie 1" #Ability { id: "B4EA", source: "Lindwurm" } +3264.5 "Mana Burst 2" Ability { id: "BBE3", source: "Lindwurm" } +3265.1 "Hemorrhagic Projection 1" Ability { id: "B922", source: "Lindwurm" } +3268.8 "Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } +3272.6 "Mana Burst 3" Ability { id: "BBE3", source: "Lindwurm" } +3272.6 "Grotesquerie 2" #Ability { id: "B4EA", source: "Lindwurm" } +3273.2 "Hemorrhagic Projection 2" Ability { id: "B922", source: "Lindwurm" } +3278.6 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } +3280.8 "--sync--" StartsUsing { id: "B505", source: "Lindwurm" } forcejump "r12s-p2-mutating-cells" + +# Banana Codex Reenactment 1 +3359.4 label "r12s-p2-bc-reenactment2" +3359.4 "Netherwrath Near/Netherwrath Far" #Ability { id: ["B52E", "B52F"], source: "Lindwurm" } +3360.6 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } +3360.6 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } +3361.0 "Hemorrhagic Projection x2" Ability { id: "B922", source: "Lindwurm" } +3364.4 "Mana Burst 1" Ability { id: "BBE3", source: "Lindwurm" } +3364.6 "Heavy Slam 1" Ability { id: "BE5D", source: "Lindwurm" } +3367.0 "Firefall Splash" Ability { id: "B4ED", source: "Lindschrat" } +3368.2 "Mana Burst 2" Ability { id: "BBE3", source: "Lindwurm" } +3368.4 "Scalding Waves x4" #Ability { id: "B8E1", source: "Lindwurm" } +3372.2 "Mana Burst 3" Ability { id: "BBE3", source: "Lindwurm" } +3372.4 "Heavy Slam 2" #Ability { id: "BE5D", source: "Lindwurm" } +3378.1 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } +3380.3 "--sync--" StartsUsing { id: "B505", source: "Lindwurm" } forcejump "r12s-p2-mutating-cells" # Blood Mana / Blood Wakening Phase (Superchain) -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 x2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player -3202.2 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } -3203.2 "--close shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3204.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 -3206.2 "--far shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3207.0 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 2 -3209.2 "--soaked shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3210.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # blackhole 1 - -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" } +3480.8 label "r12s-p2-mutating-cells" +3483.8 "Mutating Cells" Ability { id: "B505", source: "Lindwurm" } +3485.0 "--sync--" Ability { id: "B506", source: "Lindwurm" } +3490.0 "Blood Mana" Ability { id: "B4FB", source: "Lindwurm" } +3493.3 "--black holes--" Ability { id: "BCB0", source: "Mana Sphere" } +3493.7 "--shapes--" Ability { id: "B4FD", source: "Mana Sphere" } +3500.7 "Bloody Burst x2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player +3502.2 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } +3503.2 "--close shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3504.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 +3506.2 "--far shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3507.0 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 2 +3509.2 "--soaked shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3510.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # blackhole 1 + +3516.7 "Blood Wakening" Ability { id: "B500", source: "Lindwurm" } +3517.9 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } +3518.3 "Black Hole 1" Ability { id: ["B501", "B502", "B503", "B504"], source: "Lindwurm" } +3522.9 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } +3523.3 "Black Hole 2" Ability { id: ["B501", "B502", "B503", "B504"], source: "Lindwurm" } +3527.6 "Netherworld Near/Netherworld Far" Ability { id: ["B52B", "B52C"], source: "Lindwurm" } +3528.8 "Wailing Wave x3" Ability { id: "B52D", source: "Lindwurm" } +3531.8 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } +3535.8 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } +3545.0 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3545.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } +3550.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3552.6 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } +3560.7 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } # Idyllic Dream -3268.8 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } -3275.0 "Staging" Ability { id: "B4E1", source: "Lindwurm" } -3276.3 "--clones x4 1--" #ActorControlExtra { category: "0197", param1: "11D2" } -3278.3 "--clones x4 2--" #ActorControlExtra { category: "0197", param1: "11D2" } -3280.4 "--locked tethers--" Tether { id: "0175", source: "Understudy" } -3283.4 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } -3290.1 "Twisted Vision 1" Ability { id: "BBE2", source: "Lindwurm" } -3296.2 "Replication 3" Ability { id: "B4D8", source: "Lindwurm" } -3299.4 "--boss clones x3--" ActorControlExtra { category: "0197", param1: "11D5" } -3308.6 "Twisted Vision 2" Ability { id: "BBE2", source: "Lindwurm" } -3309.6 "Power Gusher x2" #Ability { id: ["B50F", "B510"], source: "Lindschrat" } -3309.6 "Snaking Kick" #Ability { id: "B511", source: "Lindschrat" } -3314.7 "Replication 4" Ability { id: "B4D8", source: "Lindwurm" } -3317.9 "--boss clones x2 1--" #ActorControlExtra { category: "0197", param1: "11D5" } -3318.9 "--boss clones x2 2--" #ActorControlExtra { category: "0197", param1: "11D5" } -3319.9 "--boss clones x2 3--" #ActorControlExtra { category: "0197", param1: "11D5" } -3320.9 "--boss clones x2 4--" #ActorControlExtra { category: "0197", param1: "11D5" } -3326.1 "--tethers--" #Tether { id: ["0170", "0171"], source: "Lindschrat" } # These could change hands causing sync issue -3334.1 "--locked tethers--" Tether { id: "0175", source: "Lindschrat" } +3568.8 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } +3575.0 "Staging" Ability { id: "B4E1", source: "Lindwurm" } +3576.3 "--clones x4 1--" #ActorControlExtra { category: "0197", param1: "11D2" } +3578.3 "--clones x4 2--" #ActorControlExtra { category: "0197", param1: "11D2" } +3580.4 "--locked tethers--" Tether { id: "0175", source: "Understudy" } +3583.4 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } +3590.1 "Twisted Vision 1" Ability { id: "BBE2", source: "Lindwurm" } +3596.2 "Replication 3" Ability { id: "B4D8", source: "Lindwurm" } +3599.4 "--boss clones x3--" ActorControlExtra { category: "0197", param1: "11D5" } +3608.6 "Twisted Vision 2" Ability { id: "BBE2", source: "Lindwurm" } +3609.6 "Power Gusher x2" #Ability { id: ["B50F", "B510"], source: "Lindschrat" } +3609.6 "Snaking Kick" #Ability { id: "B511", source: "Lindschrat" } +3614.7 "Replication 4" Ability { id: "B4D8", source: "Lindwurm" } +3617.9 "--boss clones x2 1--" #ActorControlExtra { category: "0197", param1: "11D5" } +3618.9 "--boss clones x2 2--" #ActorControlExtra { category: "0197", param1: "11D5" } +3619.9 "--boss clones x2 3--" #ActorControlExtra { category: "0197", param1: "11D5" } +3620.9 "--boss clones x2 4--" #ActorControlExtra { category: "0197", param1: "11D5" } +3626.1 "--tethers--" #Tether { id: ["0170", "0171"], source: "Lindschrat" } # These could change hands causing sync issue +3634.1 "--locked tethers--" Tether { id: "0175", source: "Lindschrat" } # Twisted Vision 3: Towers Preview -3334.3 "Twisted Vision 3" Ability { id: "BBE2", source: "Lindwurm" } -3338.7 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } -3338.9 "Power Gusher x4" #Ability { id: "B516", source: "Lindwurm" } # Front/Back are apparently counting as their own casts -3342.8 "Lindwurm's Meteor" Ability { id: "B4F2", source: "Lindwurm" } -3348.9 "Downfall" Ability { id: "B4F3", source: "Lindwurm" } -3355.0 "Arcadian Arcanum (castbar)" Ability { id: "B529", source: "Lindwurm" } -3356.2 "Arcadian Arcanum" Ability { id: "B9D9", source: "Lindwurm" } +3634.3 "Twisted Vision 3" Ability { id: "BBE2", source: "Lindwurm" } +3638.7 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } +3638.9 "Power Gusher x4" #Ability { id: "B516", source: "Lindwurm" } # Front/Back are apparently counting as their own casts +3642.8 "Lindwurm's Meteor" Ability { id: "B4F2", source: "Lindwurm" } +3648.9 "Downfall" Ability { id: "B4F3", source: "Lindwurm" } +3655.0 "Arcadian Arcanum (castbar)" Ability { id: "B529", source: "Lindwurm" } +3656.2 "Arcadian Arcanum" Ability { id: "B9D9", source: "Lindwurm" } # Twisted Vision 4: First Stacks/Defamations # Orders could be different, but we can detect B517 abiltiy to know if Mana Burst is coming 1.2s before B518 -3363.0 "Twisted Vision 4" Ability { id: "BBE2", source: "Lindwurm" } -3369.6 "Clone 1 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here -3370.8 "Clone 1 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } -3374.6 "Clone 2 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here -3375.8 "Clone 2 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } -3379.6 "Clone 3 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here -3380.8 "Clone 3 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } -3384.6 "Clone 4 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here -3385.8 "Clone 4 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3663.0 "Twisted Vision 4" Ability { id: "BBE2", source: "Lindwurm" } +3669.6 "Clone 1 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3670.8 "Clone 1 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3674.6 "Clone 2 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3675.8 "Clone 2 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3679.6 "Clone 3 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3680.8 "Clone 3 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3684.6 "Clone 4 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3685.8 "Clone 4 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } # Twisted Vision 5: Towers -3393.6 "Twisted Vision 5" Ability { id: "BBE2", source: "Lindwurm" } -3398.0 "Cosmic Kiss x8" Ability { id: "B4F4", source: "Lindwurm" } -3398.6 "--Hot-blooded x2--" duration 5 -3398.7 "Lindwurm's Dark II x2" Ability { id: "B4F6", source: "Lindwurm" } -3398.7 "--Doom x2--" duration 8 -3403.7 "Lindwurm's Stone III x2" #Ability { id: "B4F7", source: "Lindwurm" } -3408.7 "Lindwurm's Thunder II x4" #Ability { id: "B4FA", source: "Lindwurm" } -3408.7 "Lindwurm's Glare x4" #Ability { id: "B4F8", source: "Lindwurm" } -3417.1 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } -3420.2 "--clone takes portal--" Ability { id: "B51D", source: "Lindschrat" } -3423.3 "--clones on platform--" Ability { id: "B4D9", source: "Lindschrat" } +3693.6 "Twisted Vision 5" Ability { id: "BBE2", source: "Lindwurm" } +3698.0 "Cosmic Kiss x8" Ability { id: "B4F4", source: "Lindwurm" } +3698.6 "--Hot-blooded x2--" duration 5 +3698.7 "Lindwurm's Dark II x2" Ability { id: "B4F6", source: "Lindwurm" } +3698.7 "--Doom x2--" duration 8 +3703.7 "Lindwurm's Stone III x2" #Ability { id: "B4F7", source: "Lindwurm" } +3708.7 "Lindwurm's Thunder II x4" #Ability { id: "B4FA", source: "Lindwurm" } +3708.7 "Lindwurm's Glare x4" #Ability { id: "B4F8", source: "Lindwurm" } +3717.1 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } +3720.2 "--clone takes portal--" Ability { id: "B51D", source: "Lindschrat" } +3723.3 "--clones on platform--" Ability { id: "B4D9", source: "Lindschrat" } # Twisted Vision 6: Reenactment 2 Part 1 # NOTE: Practical solution seems to be that you have x2 mana burts + x2 heavy slams @@ -485,39 +516,39 @@ hideall "--sync--" # 3x Mana Burst + 1 Heavy Slam => 3x Heavy Slam + 1 Mana Burst or # 3x Heavy Slam + 1 Mana Burst => 3x Mana Burst + 1 Heavy Slam # But those would probably require lots of mit and tank immune probably on 2/3 of the heavy slams in the 3 set -3429.6 "Twisted Vision 6" Ability { id: "BBE2", source: "Lindwurm" } -3430.6 "Power Gusher" Ability { id: "B50F", source: "Lindschrat" } -3430.6 "Snaking Kick" Ability { id: "BCAF", source: "Lindschrat" } -3435.7 "Reenactment 2" Ability { id: "B4EC", source: "Lindwurm" } -3439.0 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } -3439.2 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } +3729.6 "Twisted Vision 6" Ability { id: "BBE2", source: "Lindwurm" } +3730.6 "Power Gusher" Ability { id: ["B50F", "B510"], source: "Lindschrat" } +3730.6 "Snaking Kick" Ability { id: "BCAF", source: "Lindschrat" } +3735.7 "Reenactment 2" Ability { id: "B4EC", source: "Lindwurm" } +3739.0 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } +3739.2 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } # Twisted Vision 7: Safe Platform + Front/Back or Sides Platform -3444.8 "Twisted Vision 7" Ability { id: "BBE2", source: "Lindwurm" } -3449.2 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } -3449.4 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } +3744.8 "Twisted Vision 7" Ability { id: "BBE2", source: "Lindwurm" } +3749.2 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } +3749.4 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } # Twisted Vision 8: Reenactment 2 Part 2 -3452.3 "Twisted Vision 8" Ability { id: "BBE2", source: "Lindwurm" } -3458.6 "--sync--" Ability { id: "B51E", source: "Lindschrat" } -3459.8 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } -3460.0 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } -3464.8 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } -3470.7 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } -3478.8 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } -3479.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } -3484.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } -3486.6 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } +3752.3 "Twisted Vision 8" Ability { id: "BBE2", source: "Lindwurm" } +3758.6 "--sync--" Ability { id: "B51E", source: "Lindschrat" } +3759.8 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } +3760.0 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } +3764.8 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } +3770.7 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } +3778.8 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3779.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } +3784.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3786.6 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } # Enrage Sequence -3499.8 "Replication 5" Ability { id: "B46C", source: "Lindwurm" } -3513.2 "Arcadian Hell 1 (boss) " Ability { id: "B533", source: "Lindwurm" } -3513.2 "Arcadian Hell 1 x4 (clones)" #Ability { id: "B534", source: "Lindschrat" } -3529.4 "Arcadian Hell 2 (boss)" Ability { id: "B533", source: "Lindwurm" } -3529.4 "Arcadian Hell 2 x8 (clones)" #Ability { id: "B535", source: "Lindschrat" } -3542.3 "--sync--" StartsUsing { id: "B537", source: "Lindwurm" } -3552.3 "Arcadian Hell (Boss Enrage)" Ability { id: "B537", source: "Lindwurm" } -3552.3 "Arcadian Hell x16 (Clones Enrage)" #Ability { id: "BEC1", source: "Lindschrat" } +3799.8 "Replication 5" Ability { id: "B46C", source: "Lindwurm" } +3813.2 "Arcadian Hell 1 (boss) " Ability { id: "B533", source: "Lindwurm" } +3813.2 "Arcadian Hell 1 x4 (clones)" #Ability { id: "B534", source: "Lindschrat" } +3829.4 "Arcadian Hell 2 (boss)" Ability { id: "B533", source: "Lindwurm" } +3829.4 "Arcadian Hell 2 x8 (clones)" #Ability { id: "B535", source: "Lindschrat" } +3842.3 "--sync--" StartsUsing { id: "B537", source: "Lindwurm" } +3852.3 "Arcadian Hell (Boss Enrage)" Ability { id: "B537", source: "Lindwurm" } +3852.3 "Arcadian Hell x16 (Clones Enrage)" #Ability { id: "BEC1", source: "Lindschrat" } # IGNORED ABILITIES # Phase 1 From 30f7fbac5692271a0f745570082e89876cb1b29a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 24 Feb 2026 19:07:47 -0500 Subject: [PATCH 194/215] fix top-tier slam actor collect Check hdg of 0 instead of -0.0001 --- ui/raidboss/data/07-dt/raid/r12s.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 084405453f7..0b87b74b98a 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2384,8 +2384,7 @@ const triggerSet: TriggerSet = { // Heading is also checked as the non fire clones all face a perfect heading const xFilter = pos.x % 1; const yFilter = pos.y % 1; - const hdgFilter = Math.abs(pos.heading - 0.0001) < Number.EPSILON; - if (xFilter === 0 && yFilter === 0 && hdgFilter) + if (xFilter === 0 && yFilter === 0 && pos.heading === 0) return false; return true; } From c39700994ecd75aa8e4b65fa084421dd625aa860 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 24 Feb 2026 19:11:47 -0500 Subject: [PATCH 195/215] add missingTranslations --- ui/raidboss/data/07-dt/raid/r12s.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index ce803b53982..1db49bcf09a 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -5906,6 +5906,7 @@ const triggerSet: TriggerSet = { }, { 'locale': 'ko', + 'missingTranslations': true, 'replaceSync': { 'Blood Vessel': '연환세포', 'Lindschrat': '인간형 분열체', From d7e200f547967118f8c1400c8cf7e537f0ab580f Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 24 Feb 2026 19:40:29 -0500 Subject: [PATCH 196/215] reduce some order checking lines Cases where the order could only be one strategy I replaced with a strategy detection. Some of the DN-based ones could apply to some other strategy as they do not check enough orders... although I don't know if those other strategies would be valid without vuln issues? --- ui/raidboss/data/07-dt/raid/r12s.ts | 123 +++++++++++----------------- 1 file changed, 49 insertions(+), 74 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 1db49bcf09a..39d3e499daa 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -65,6 +65,7 @@ export interface Data extends RaidbossData { replication2BossId?: string; replication2PlayerOrder: string[]; replication2AbilityOrder: string[]; + replication2StrategyDetected?: 'dn' | 'banana' | 'unknown'; netherwrathFollowup: boolean; myMutation?: 'alpha' | 'beta'; manaSpheres: { @@ -3133,9 +3134,11 @@ const triggerSet: TriggerSet = { run: (data, matches) => { const target = matches.target; const sourceId = matches.sourceId; + const boss = headMarkerData['fireballSplashTether']; + // Check if boss tether if (data.replication2BossId === sourceId) - data.replication2PlayerAbilities[target] = headMarkerData['fireballSplashTether']; + data.replication2PlayerAbilities[target] = boss; else if (data.replication2BossId !== sourceId) { const actor = data.actorPositions[sourceId]; if (actor === undefined) { @@ -3183,6 +3186,41 @@ const triggerSet: TriggerSet = { data.replication2PlayerOrder.push(player); data.replication2AbilityOrder.push(ability); } + + // Detect recognized strategy by checking first 6 abilities + const detectStrategy = ( + order: string[], + ): 'dn' | 'banana' | 'unknown' => { + const defamation = headMarkerData['manaBurstTether']; + const stack = headMarkerData['heavySlamTether']; + const projection = headMarkerData['projectionTether']; + // DN + if ( + ( + (order[0] === 'none' && order[1] === boss) || + (order[0] === boss && order[1] === 'none') + ) && ( + (order[2] === defamation && order[3] === projection) || + (order[2] === projection && order[3] === defamation) + ) && (order[4] === stack && order[5] === stack) + ) + return 'dn'; + // Banana Codex + if ( + (order[0] === projection && order[1] === projection) && ( + (order[2] === stack && order[3] === defamation) || + (order[2] === defamation && order[3] === stack) + ) && ( + (order[4] === boss && order[5] === 'none') || + (order[4] === 'none' && order[5] === boss) + ) + ) + return 'banana'; + // Not Yet Supported, File a Feature Request or PR + return 'unknown'; + }; + + data.replication2StrategyDetected = detectStrategy(data.replication2AbilityOrder); } }, }, @@ -3716,23 +3754,8 @@ const triggerSet: TriggerSet = { const ability = data.replication2PlayerAbilities[data.me]; const isNear = matches.id === 'B52E'; - // Determine if it's a strategy we recognize - const order = data.replication2AbilityOrder; - const boss = headMarkerData['fireballSplashTether']; - const defamation = headMarkerData['manaBurstTether']; - const stack = headMarkerData['heavySlamTether']; - const projection = headMarkerData['projectionTether']; - // DN Strategy - if ( - ( - (order[0] === 'none' && order[1] === boss) || - (order[0] === boss && order[1] === 'none') - ) && ( - (order[2] === defamation && order[3] === projection) || - (order[2] === projection && order[3] === defamation) - ) && (order[4] === stack && order[5] === stack) - ) { + if (data.replication2StrategyDetected === 'dn') { if (isNear) { switch (ability) { case headMarkerData['projectionTether']: @@ -3812,15 +3835,7 @@ const triggerSet: TriggerSet = { } // Banana Codex Strategy - if ( - (order[0] === projection && order[1] === projection) && ( - (order[2] === stack && order[3] === defamation) || - (order[2] === defamation && order[3] === stack) - ) && ( - (order[4] === boss && order[5] === 'none') || - (order[4] === 'none' && order[5] === boss) - ) - ) { + if (data.replication2StrategyDetected === 'banana') { // Technically, this strategy does not care about Near/Far, but // included as informational switch (ability) { @@ -3861,6 +3876,10 @@ const triggerSet: TriggerSet = { const getMechanic = ( order: string, ): 'proteans' | 'defamation' | 'projection' | 'stack' | 'unknown' => { + const boss = headMarkerData['fireballSplashTether']; + const defamation = headMarkerData['manaBurstTether']; + const stack = headMarkerData['heavySlamTether']; + const projection = headMarkerData['projectionTether']; if (order === boss) return 'proteans'; if (order === defamation || order === 'none') @@ -3871,6 +3890,7 @@ const triggerSet: TriggerSet = { return 'stack'; return 'unknown'; }; + const order = data.replication2AbilityOrder; const mechanic1 = getMechanic(order[0] ?? 'unknown'); const mechanic2 = getMechanic(order[1] ?? 'unknown'); const mechanic3 = getMechanic(order[2] ?? 'unknown'); @@ -3996,24 +4016,7 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B922', source: 'Lindwurm', capture: false }, condition: (data) => { - const order = data.replication2AbilityOrder; - const stack = headMarkerData['heavySlamTether']; - const defamation = headMarkerData['manaBurstTether']; - const projection = headMarkerData['projectionTether']; - const boss = headMarkerData['fireballSplashTether']; - // Defined as N/S clones with projections and NE/SW with defamation + stack - // Followed up with E/W boss + none, then SE/NW stack + defamation - // No need to check 6, 7 as that's all that remains - if ( - order[0] === projection && order[1] === projection && - ( - (order[2] === defamation && order[3] === stack) || - (order[2] === stack && order[3] === defamation) - ) && ( - (order[4] === boss && order[5] === 'none') || - (order[4] === 'none' && order[5] === boss) - ) - ) + if (data.replication2StrategyDetected === 'banana') return true; return false; }, @@ -4089,22 +4092,8 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'BE5D', source: 'Lindwurm', capture: false }, condition: (data) => { - const order = data.replication2AbilityOrder; - const stack = headMarkerData['heavySlamTether']; - const defamation = headMarkerData['manaBurstTether']; - const projection = headMarkerData['projectionTether']; - const boss = headMarkerData['fireballSplashTether']; // Banana Codex Strategy Order - if ( - order[0] === projection && order[1] === projection && - ( - (order[2] === defamation && order[3] === stack) || - (order[2] === stack && order[3] === defamation) - ) && ( - (order[4] === boss && order[5] === 'none') || - (order[4] === 'none' && order[5] === boss) - ) - ) + if (data.replication2StrategyDetected === 'banana') return true; return false; }, @@ -4178,22 +4167,8 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: 'B8E1', source: 'Lindwurm', capture: false }, condition: (data) => { - const order = data.replication2AbilityOrder; - const stack = headMarkerData['heavySlamTether']; - const defamation = headMarkerData['manaBurstTether']; - const projection = headMarkerData['projectionTether']; - const boss = headMarkerData['fireballSplashTether']; // Banana Codex Strategy Order - if ( - order[0] === projection && order[1] === projection && - ( - (order[2] === defamation && order[3] === stack) || - (order[2] === stack && order[3] === defamation) - ) && ( - (order[4] === boss && order[5] === 'none') || - (order[4] === 'none' && order[5] === boss) - ) - ) + if (data.replication2StrategyDetected === 'banana') return true; return false; }, From 287bebd726d59efd724190811eafb58264be9dd1 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 24 Feb 2026 19:43:52 -0500 Subject: [PATCH 197/215] 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 39d3e499daa..f1b0f1ec880 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3135,7 +3135,7 @@ const triggerSet: TriggerSet = { const target = matches.target; const sourceId = matches.sourceId; const boss = headMarkerData['fireballSplashTether']; - + // Check if boss tether if (data.replication2BossId === sourceId) data.replication2PlayerAbilities[target] = boss; From 6b5afc6550a9d4f8ca2fd35308943f39761ae62b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Tue, 24 Feb 2026 21:18:13 -0500 Subject: [PATCH 198/215] p1 slaughtershed changes --- ui/raidboss/data/07-dt/raid/r12s.ts | 263 +++++++++++++++++++++------- 1 file changed, 200 insertions(+), 63 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index f1b0f1ec880..2c36fd2f254 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -51,6 +51,7 @@ export interface Data extends RaidbossData { myMitoticPhase?: string; hasRot: boolean; myCurtainCallSafeSpot?: 'northeast' | 'southeast' | 'southwest' | 'northwest'; + slaughtershed?: 'left' | 'right' | 'northeastKnockback' | 'northwestKnockback'; // Phase 2 actorPositions: { [id: string]: { x: number; y: number; heading: number } }; replicationCounter: number; @@ -595,14 +596,6 @@ const triggerSet: TriggerSet = { } }, }, - { - id: 'R12S Splattershed Safe Spot Cleanup', - // Only Splattershed value needs to be reset - type: 'HeadMarker', - netRegex: { id: headMarkerData['slaughterStack'], capture: false }, - delaySeconds: 0.1, - run: (data) => delete data.splattershedStackDir, - }, { id: 'R12S Directed Grotesquerie Direction Collect', // Unknown_DE6 spell contains data in its count: @@ -2136,6 +2129,35 @@ const triggerSet: TriggerSet = { netRegex: { id: ['B4C6', 'B4C3'], source: 'Lindwurm', capture: false }, response: Responses.bigAoe('alert'), }, + { + id: 'R12S Serpintine Scourge/Raptor Knuckles Collect', + // B4CB Serpintine Scourge Left Hand first, then Right Hand + // B4CD Serpintine Scourge Right Hand first, then Left Hand + // B4CC Raptor Knuckles Right Hand first, then Left Hand + // B4CE Raptor Knuckles Left Hand first, then Right Hand + type: 'Ability', + netRegex: { + id: ['B4CB', 'B4CD', 'B4CC', 'B4CE'], + source: 'Lindwurm', + capture: true, + }, + condition: (data) => data.phase === 'slaughtershed', + run: (data, matches) => { + switch (matches.id) { + case 'B4CB': + data.slaughtershed = 'right'; + break; + case 'B4CD': + data.slaughtershed = 'left'; + break; + case 'B4CC': + data.slaughtershed = 'northwestKnockback'; + break; + case 'B4CE': + data.slaughtershed = 'northeastKnockback'; + } + }, + }, { id: 'R12S Slaughtershed Stack', type: 'HeadMarker', @@ -2148,28 +2170,70 @@ const triggerSet: TriggerSet = { return true; return false; }, - durationSeconds: 5.1, + delaySeconds: 0.1, // Delay for followup direction + durationSeconds: 6, alertText: (data, matches, output) => { const dir = data.splattershedStackDir; const target = matches.target; + const slaughter = data.slaughtershed; + if (target === data.me) { - if (dir) - return output.stackDir!({ - stack: output.stackOnYou!(), - dir: output[dir]!(), + if (dir) { + if (slaughter === undefined) + return output.stackDir!({ + stack: output.stackOnYou!(), + dir: output[dir]!(), + }); + + return output.stackThenDodge!({ + stack: output.stackDir!({ + stack: output.stackOnYou!(), + dir: output[dir]!(), + }), + dodge: output[slaughter]!(), }); - return output.stackOnYou!(); + } + if (slaughter === undefined) + return output.stackOnYou!(); + + return output.stackThenDodge!({ + stack: output.stackOnYou!(), + dodge: output[slaughter]!(), + }); } const player = data.party.member(target); - if (dir) - return output.stackDir!({ - stack: output.stackOnPlayer!({ player: player }), - dir: output[dir]!(), + if (dir) { + if (slaughter === undefined) + return output.stackDir!({ + stack: output.stackOnPlayer!({ player: player }), + dir: output[dir]!(), + }); + + return output.stackThenDodge!({ + stack: output.stackDir!({ + stack: output.stackOnPlayer!({ player: player }), + dir: output[dir]!(), + }), + dodge: output[slaughter]!(), }); - return output.stackOnPlayer!({ player: player }); + } + if (slaughter === undefined) + return output.stackOnPlayer!({ player: player }); + return output.stackThenDodge!({ + stack: output.stackOnPlayer!({ player: player }), + dodge: output[slaughter]!(), + }); }, outputStrings: { + left: Outputs.left, + right: Outputs.right, + northeastKnockback: { + en: 'Knockback from Northeast', + }, + northwestKnockback: { + en: 'Knockback from Northwest', + }, northeast: Outputs.northeast, northwest: Outputs.northwest, stackOnYou: Outputs.stackOnYou, @@ -2177,6 +2241,9 @@ const triggerSet: TriggerSet = { stackDir: { en: '${stack} ${dir}', }, + stackThenDodge: { + en: '${stack} => ${dodge}', + }, }, }, { @@ -2184,7 +2251,8 @@ const triggerSet: TriggerSet = { type: 'HeadMarker', netRegex: { id: headMarkerData['slaughterSpread'], capture: true }, condition: Conditions.targetIsYou(), - durationSeconds: 5.1, + delaySeconds: 0.1, // Delay for followup direction + durationSeconds: 6, suppressSeconds: 1, alertText: (data, _matches, output) => { const stackDir = data.splattershedStackDir; @@ -2193,68 +2261,70 @@ const triggerSet: TriggerSet = { : stackDir === 'northeast' ? 'northwest' : undefined; - if (dir) - return output.spreadDir!({ dir: output[dir]!() }); - return output.spread!(); + const slaughter = data.slaughtershed; + + if (dir) { + if (slaughter === undefined) + return output.spreadDir!({ dir: output[dir]!() }); + return output.spreadThenDodge!({ + spread: output.spreadDir!({ dir: output[dir]!() }), + dodge: output[slaughter]!(), + }); + } + if (slaughter === undefined) + return output.spread!(); + return output.spreadThenDodge!({ + spread: output.spread!(), + dodge: output[slaughter]!(), + }); }, outputStrings: { + left: Outputs.left, + right: Outputs.right, + northeastKnockback: { + en: 'Knockback from Northeast', + }, + northwestKnockback: { + en: 'Knockback from Northwest', + }, northeast: Outputs.northeast, northwest: Outputs.northwest, spread: Outputs.spread, spreadDir: { en: 'Spread ${dir}', }, + spreadThenDodge: { + en: '${spread} => ${dodge}', + }, }, }, { - 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 Splattershed Safe Spot Cleanup', + type: 'HeadMarker', + netRegex: { id: headMarkerData['slaughterStack'], capture: false }, + delaySeconds: 0.2, + run: (data) => delete data.splattershedStackDir, }, { - id: 'R12S Serpintine Scourge Left Hand First', - // Right Hand first, then Left Hand + id: 'R12S Serpintine Scourge and Raptor Knuckles', + // Trigger on B4D4 Dramatic Lysis or B4D5 Fourth-wall Fusion 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, + netRegex: { id: ['B4D4', 'B4D5'], source: 'Lindwurm', capture: false }, + durationSeconds: 5.5, + suppressSeconds: 1, + alertText: (data, _matches, output) => { + const slaughtershed = data.slaughtershed; + if (slaughtershed) + return output[slaughtershed]!(); }, - }, - { - 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: 15, - infoText: (_data, _matches, output) => output.text!(), outputStrings: { - text: { + right: Outputs.rightThenLeft, + left: Outputs.leftThenRight, + northwestKnockback: { en: 'Knockback from Northwest => Knockback from Northeast', ko: '북서에서 넉백 => 북동에서 넉백', }, - }, - }, - { - 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: 15, - infoText: (_data, _matches, output) => output.text!(), - outputStrings: { - text: { + northeastKnockback: { en: 'Knockback from Northeast => Knockback from Northwest', ko: '북동에서 넉백 => 북서에서 넉백', }, @@ -2278,6 +2348,73 @@ const triggerSet: TriggerSet = { durationSeconds: 1.8, response: Responses.knockback(), }, + { + id: 'R12S Serpentine Scourge Left Followup', + type: 'Ability', + netRegex: { id: 'B4D1', source: 'Lindwurm', capture: false }, + condition: (data) => { + if (data.slaughtershed) + return true; + return false; + }, + response: Responses.goLeft(), + }, + { + id: 'R12S Serpentine Scourge Right Followup', + type: 'Ability', + netRegex: { id: 'B4D2', source: 'Lindwurm', capture: false }, + condition: (data) => { + if (data.slaughtershed) + return true; + return false; + }, + response: Responses.goRight(), + }, + { + id: 'R12S Raptor Knuckles Northeast Followup', + type: 'Ability', + netRegex: { id: 'B4D0', source: 'Lindwurm', capture: false }, + condition: (data) => { + if (data.slaughtershed) + return true; + return false; + }, + delaySeconds: 0.8, // Time until B9C7 knockback + alertText: (_data, _matches, output) => output.northwestKnockback!(), + outputStrings: { + northwestKnockback: { + en: 'Knockback from Northwest', + }, + }, + }, + { + id: 'R12S Raptor Knuckles Northwest Followup', + type: 'Ability', + netRegex: { id: 'B4CF', source: 'Lindwurm', capture: false }, + condition: (data) => { + if (data.slaughtershed) + return true; + return false; + }, + delaySeconds: 0.8, // Time until B9C7 knockback + alertText: (_data, _matches, output) => output.northeastKnockback!(), + outputStrings: { + northeastKnockback: { + en: 'Knockback from Northeast', + }, + }, + }, + { + id: 'R12S Slaughtershed Cleanup', + type: 'Ability', + netRegex: { id: ['B4D1', 'B4D2', 'B4D0', 'B4CF'], source: 'Lindwurm', capture: false }, + condition: (data) => { + if (data.slaughtershed) + return true; + return false; + }, + run: (data) => delete data.slaughtershed, + }, { id: 'R12S Refreshing Overkill', // B538 has a 10s castTime that could end with enrage or raidwide From 65a64c84272f3e67d054a374e66103ed9b291bfe Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 25 Feb 2026 21:20:16 -0500 Subject: [PATCH 199/215] minor capitalization nit in comment --- 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 c13b9445f90..75ef87940e8 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -437,7 +437,7 @@ hideall "--sync--" 3506.2 "--far shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } 3507.0 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 2 3509.2 "--soaked shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3510.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # blackhole 1 +3510.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 3516.7 "Blood Wakening" Ability { id: "B500", source: "Lindwurm" } 3517.9 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } From 6ce0c4a073ad80d302317dc08608920c1b68af46 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 26 Feb 2026 00:25:25 -0500 Subject: [PATCH 200/215] shorten p1 slaughtershed blob call --- 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 2c36fd2f254..de12416a629 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2234,8 +2234,8 @@ const triggerSet: TriggerSet = { northwestKnockback: { en: 'Knockback from Northwest', }, - northeast: Outputs.northeast, - northwest: Outputs.northwest, + northeast: Outputs.dirNE, + northwest: Outputs.dirNW, stackOnYou: Outputs.stackOnYou, stackOnPlayer: Outputs.stackOnPlayer, stackDir: { @@ -2287,8 +2287,8 @@ const triggerSet: TriggerSet = { northwestKnockback: { en: 'Knockback from Northwest', }, - northeast: Outputs.northeast, - northwest: Outputs.northwest, + northeast: Outputs.dirNE, + northwest: Outputs.dirNW, spread: Outputs.spread, spreadDir: { en: 'Spread ${dir}', From 9e9e420f9f1717b5e2e26d865145c2517343cc6a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 26 Feb 2026 00:52:44 -0500 Subject: [PATCH 201/215] p1 early stack/spread trigger for slaughtershed --- ui/raidboss/data/07-dt/raid/r12s.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index de12416a629..60a3202591e 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2129,6 +2129,27 @@ const triggerSet: TriggerSet = { netRegex: { id: ['B4C6', 'B4C3'], source: 'Lindwurm', capture: false }, response: Responses.bigAoe('alert'), }, + { + id: 'R12S Slaughershed Stack/Spread Spots (Early)', + // Data available by StartsUsing, trigger on ability 3s after to avoid conflict + type: 'Ability', + netRegex: { id: ['B4C6', 'B4C3'], source: 'Lindwurm', capture: false }, + suppressSeconds: 1, + infoText: (data, _matches, output) => { + const slaughtershed = data.splattershedStackDir; + if (slaughtershed === undefined) + return; + return output[slaughtershed]!(); + }, + outputStrings: { + northeast: { + en: 'Stack NE/Spread NW (later)', + }, + northwest: { + en: 'Spread NE/Stack NW (later)', + }, + }, + }, { id: 'R12S Serpintine Scourge/Raptor Knuckles Collect', // B4CB Serpintine Scourge Left Hand first, then Right Hand From bc55bad0b74bcdbca867ac32135a6dac50fec6d8 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 26 Feb 2026 03:20:42 -0500 Subject: [PATCH 202/215] cleanup replication 2 timeline Changes which abilities are ignored and which ones are synced. --- ui/raidboss/data/07-dt/raid/r12s.txt | 300 ++++++++++++--------------- 1 file changed, 138 insertions(+), 162 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.txt b/ui/raidboss/data/07-dt/raid/r12s.txt index 75ef87940e8..5d5e8a12bad 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -335,13 +335,13 @@ hideall "--sync--" ### Phase 2: Lindwurm II -# -p B528:3015.7 B505:3483.8 -# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B4F1 B4EE B4EF B508 B4F5 B512 B513 B514 B515 B4F9 B51B +# -p B528:3015.7 +# -ii B51F B4DA B4DB B4DD B4DF B4E3 B4E6 B4F0 B4E9 B8E1 B4EA B922 BE5D BBE3 B508 B4F5 B512 B513 B514 B515 B4F9 B51B # -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" } +3022.9 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } window 5,5 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" } @@ -357,8 +357,6 @@ hideall "--sync--" 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.2 "Staging" Ability { id: "B4E1", source: "Lindwurm" } 3092.5 "--clones x2 1--" #ActorControlExtra { category: "0197", param1: "11D2" } 3094.0 "--clones x2 2--" #ActorControlExtra { category: "0197", param1: "11D2" } @@ -378,136 +376,112 @@ hideall "--sync--" 3137.3 "Hemorrhagic Projection x2" Ability { id: "B4EB", source: "Lindwurm" } 3141.1 "Snaking Kick" Ability { id: "B527", source: "Lindwurm" } -# NOTE: Without access to data from triggers, make a best guess based on first -# ability detection from clones. +# Reenactment 1 +# NOTE: Order dependent on tethers during and Staging 1 and Replication 2 +# Initial VFX spells happen at same time, but damage casts differ: +# +0s B4ED Fireball Splash (Initial VFX abilities also happen here) +# +1.2s BBE3 Mana Burst +# +1.4s BE5D Heavy Slam, B8E1 Scalding Waves +# +1.6s B922 Hemorrhagic Projection +# These Abilities Sync same time: +# B4ED Fireball Splash +# B4EE Mana Burst (VFX) +# B4EF Heavy Slam (VFX) +# B4F1 Grotesquerie (VFX) 3151.3 "Reenactment 1" Ability { id: "B4EC", source: "Lindwurm" } -3159.4 "Firefall Splash?" Ability { id: "B4ED", source: "Lindschrat" } jump "r12s-p2-dn-reenactment2" -3159.4 "--sync--" Ability { id: "B4F1", source: "Lindschrat" } jump "r12s-p2-bc-reenactment2" # Grotesquerie clone VFX -3159.4 "Netherwrath Near/Netherwrath Far" #Ability { id: ["B52E", "B52F"], source: "Lindwurm" } -3160.6 "--n/s clones--" -3164.5 "--ne/sw clones--" -3168.8 "--e/w clones--" -3172.6 "--se/nw clones--" -3178.6 "--middle--" #Ability { id: "B4D9", source: "Lindwurm" } -3180.8 "--sync--" StartsUsing { id: "B505", source: "Lindwurm" } forcejump "r12s-p2-mutating-cells" - -# DN Reenactment 1 -3259.4 label "r12s-p2-dn-reenactment2" -3259.4 "Netherwrath Near/Netherwrath Far" #Ability { id: ["B52E", "B52F"], source: "Lindwurm" } -3260.6 "Mana Burst 1" Ability { id: "BBE3", source: "Lindwurm" } +3159.4 "--n/s clones--" duration 1.6 +3159.4 "Netherwrath Near/Netherwrath Far" Ability { id: ["B52E", "B52F"], source: "Lindwurm" } 3260.6 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } -3260.7 "Scalding Waves x4" #Ability { id: "B8E1", source: "Lindwurm" } -3264.5 "Grotesquerie 1" #Ability { id: "B4EA", source: "Lindwurm" } -3264.5 "Mana Burst 2" Ability { id: "BBE3", source: "Lindwurm" } -3265.1 "Hemorrhagic Projection 1" Ability { id: "B922", source: "Lindwurm" } -3268.8 "Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } -3272.6 "Mana Burst 3" Ability { id: "BBE3", source: "Lindwurm" } -3272.6 "Grotesquerie 2" #Ability { id: "B4EA", source: "Lindwurm" } -3273.2 "Hemorrhagic Projection 2" Ability { id: "B922", source: "Lindwurm" } -3278.6 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } -3280.8 "--sync--" StartsUsing { id: "B505", source: "Lindwurm" } forcejump "r12s-p2-mutating-cells" - -# Banana Codex Reenactment 1 -3359.4 label "r12s-p2-bc-reenactment2" -3359.4 "Netherwrath Near/Netherwrath Far" #Ability { id: ["B52E", "B52F"], source: "Lindwurm" } -3360.6 "Grotesquerie x2" Ability { id: "B4EA", source: "Lindwurm" } -3360.6 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } -3361.0 "Hemorrhagic Projection x2" Ability { id: "B922", source: "Lindwurm" } -3364.4 "Mana Burst 1" Ability { id: "BBE3", source: "Lindwurm" } -3364.6 "Heavy Slam 1" Ability { id: "BE5D", source: "Lindwurm" } -3367.0 "Firefall Splash" Ability { id: "B4ED", source: "Lindschrat" } -3368.2 "Mana Burst 2" Ability { id: "BBE3", source: "Lindwurm" } -3368.4 "Scalding Waves x4" #Ability { id: "B8E1", source: "Lindwurm" } -3372.2 "Mana Burst 3" Ability { id: "BBE3", source: "Lindwurm" } -3372.4 "Heavy Slam 2" #Ability { id: "BE5D", source: "Lindwurm" } -3378.1 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } -3380.3 "--sync--" StartsUsing { id: "B505", source: "Lindwurm" } forcejump "r12s-p2-mutating-cells" +3163.3 "--ne/sw clones--" Ability { id: ["B4ED", "B4EE", "B4EF", "B4F1"], source: "Lindschrat" } duration 1.6 +3167.4 "--e/w clones--" Ability { id: ["B4ED", "B4EE", "B4EF", "B4F1"], source: "Lindschrat" } duration 1.6 +3171.4 "--se/nw clones--" Ability { id: ["B4ED", "B4EE", "B4EF", "B4F1"], source: "Lindschrat" } duration 1.6 + +3178.6 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } window 5,5 # Blood Mana / Blood Wakening Phase (Superchain) -3480.8 label "r12s-p2-mutating-cells" -3483.8 "Mutating Cells" Ability { id: "B505", source: "Lindwurm" } -3485.0 "--sync--" Ability { id: "B506", source: "Lindwurm" } -3490.0 "Blood Mana" Ability { id: "B4FB", source: "Lindwurm" } -3493.3 "--black holes--" Ability { id: "BCB0", source: "Mana Sphere" } -3493.7 "--shapes--" Ability { id: "B4FD", source: "Mana Sphere" } -3500.7 "Bloody Burst x2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player -3502.2 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } -3503.2 "--close shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3504.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 -3506.2 "--far shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3507.0 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 2 -3509.2 "--soaked shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } -3510.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 - -3516.7 "Blood Wakening" Ability { id: "B500", source: "Lindwurm" } -3517.9 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } -3518.3 "Black Hole 1" Ability { id: ["B501", "B502", "B503", "B504"], source: "Lindwurm" } -3522.9 "--sync--" Ability { id: "B4FC", source: "Mana Sphere" } -3523.3 "Black Hole 2" Ability { id: ["B501", "B502", "B503", "B504"], source: "Lindwurm" } -3527.6 "Netherworld Near/Netherworld Far" Ability { id: ["B52B", "B52C"], source: "Lindwurm" } -3528.8 "Wailing Wave x3" Ability { id: "B52D", source: "Lindwurm" } -3531.8 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } -3535.8 "Arcadia Aflame" Ability { id: "B528", source: "Lindwurm" } -3545.0 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } -3545.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } -3550.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } -3552.6 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } -3560.7 "--middle--" Ability { id: "B4D9", source: "Lindwurm" } +3183.8 "Mutating Cells" Ability { id: "B505", source: "Lindwurm" } window 10,10 +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 x2" #Ability { id: "B4FE", source: "Lindwurm" } # Goes off when soaked by player +3202.2 "Dramatic Lysis x8" Ability { id: "B507", source: "Lindwurm" } +3203.2 "--close shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3204.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 +3206.2 "--far shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3207.0 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 2 +3209.2 "--soaked shapes eaten--" Ability { id: "B4FF", source: "Mana Sphere" } +3210.1 "--sync--" Ability { id: "BCB0", source: "Mana Sphere" } # Blackhole 1 + +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" } window 5,5 # Idyllic Dream -3568.8 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } -3575.0 "Staging" Ability { id: "B4E1", source: "Lindwurm" } -3576.3 "--clones x4 1--" #ActorControlExtra { category: "0197", param1: "11D2" } -3578.3 "--clones x4 2--" #ActorControlExtra { category: "0197", param1: "11D2" } -3580.4 "--locked tethers--" Tether { id: "0175", source: "Understudy" } -3583.4 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } -3590.1 "Twisted Vision 1" Ability { id: "BBE2", source: "Lindwurm" } -3596.2 "Replication 3" Ability { id: "B4D8", source: "Lindwurm" } -3599.4 "--boss clones x3--" ActorControlExtra { category: "0197", param1: "11D5" } -3608.6 "Twisted Vision 2" Ability { id: "BBE2", source: "Lindwurm" } -3609.6 "Power Gusher x2" #Ability { id: ["B50F", "B510"], source: "Lindschrat" } -3609.6 "Snaking Kick" #Ability { id: "B511", source: "Lindschrat" } -3614.7 "Replication 4" Ability { id: "B4D8", source: "Lindwurm" } -3617.9 "--boss clones x2 1--" #ActorControlExtra { category: "0197", param1: "11D5" } -3618.9 "--boss clones x2 2--" #ActorControlExtra { category: "0197", param1: "11D5" } -3619.9 "--boss clones x2 3--" #ActorControlExtra { category: "0197", param1: "11D5" } -3620.9 "--boss clones x2 4--" #ActorControlExtra { category: "0197", param1: "11D5" } -3626.1 "--tethers--" #Tether { id: ["0170", "0171"], source: "Lindschrat" } # These could change hands causing sync issue -3634.1 "--locked tethers--" Tether { id: "0175", source: "Lindschrat" } +3268.8 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } +3275.0 "Staging" Ability { id: "B4E1", source: "Lindwurm" } +3276.3 "--clones x4 1--" #ActorControlExtra { category: "0197", param1: "11D2" } +3278.3 "--clones x4 2--" #ActorControlExtra { category: "0197", param1: "11D2" } +3280.4 "--locked tethers--" Tether { id: "0175", source: "Understudy" } +3283.4 "--sync--" Ability { id: "B4E2", source: "Lindwurm" } +3290.1 "Twisted Vision 1" Ability { id: "BBE2", source: "Lindwurm" } +3296.2 "Replication 3" Ability { id: "B4D8", source: "Lindwurm" } +3299.4 "--boss clones x3--" ActorControlExtra { category: "0197", param1: "11D5" } +3308.6 "Twisted Vision 2" Ability { id: "BBE2", source: "Lindwurm" } +3309.6 "Power Gusher x2" #Ability { id: ["B50F", "B510"], source: "Lindschrat" } +3309.6 "Snaking Kick" #Ability { id: "B511", source: "Lindschrat" } +3314.7 "Replication 4" Ability { id: "B4D8", source: "Lindwurm" } +3317.9 "--boss clones x2 1--" #ActorControlExtra { category: "0197", param1: "11D5" } +3318.9 "--boss clones x2 2--" #ActorControlExtra { category: "0197", param1: "11D5" } +3319.9 "--boss clones x2 3--" #ActorControlExtra { category: "0197", param1: "11D5" } +3320.9 "--boss clones x2 4--" #ActorControlExtra { category: "0197", param1: "11D5" } +3326.1 "--tethers--" #Tether { id: ["0170", "0171"], source: "Lindschrat" } # These could change hands causing sync issue +3334.1 "--locked tethers--" Tether { id: "0175", source: "Lindschrat" } # Twisted Vision 3: Towers Preview -3634.3 "Twisted Vision 3" Ability { id: "BBE2", source: "Lindwurm" } -3638.7 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } -3638.9 "Power Gusher x4" #Ability { id: "B516", source: "Lindwurm" } # Front/Back are apparently counting as their own casts -3642.8 "Lindwurm's Meteor" Ability { id: "B4F2", source: "Lindwurm" } -3648.9 "Downfall" Ability { id: "B4F3", source: "Lindwurm" } -3655.0 "Arcadian Arcanum (castbar)" Ability { id: "B529", source: "Lindwurm" } -3656.2 "Arcadian Arcanum" Ability { id: "B9D9", source: "Lindwurm" } +3334.3 "Twisted Vision 3" Ability { id: "BBE2", source: "Lindwurm" } +3338.7 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } +3338.9 "Power Gusher x4" #Ability { id: "B516", source: "Lindwurm" } # Front/Back are apparently counting as their own casts +3342.8 "Lindwurm's Meteor" Ability { id: "B4F2", source: "Lindwurm" } +3348.9 "Downfall" Ability { id: "B4F3", source: "Lindwurm" } +3355.0 "Arcadian Arcanum (castbar)" Ability { id: "B529", source: "Lindwurm" } +3356.2 "Arcadian Arcanum" Ability { id: "B9D9", source: "Lindwurm" } # Twisted Vision 4: First Stacks/Defamations # Orders could be different, but we can detect B517 abiltiy to know if Mana Burst is coming 1.2s before B518 -3663.0 "Twisted Vision 4" Ability { id: "BBE2", source: "Lindwurm" } -3669.6 "Clone 1 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here -3670.8 "Clone 1 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } -3674.6 "Clone 2 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here -3675.8 "Clone 2 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } -3679.6 "Clone 3 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here -3680.8 "Clone 3 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } -3684.6 "Clone 4 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here -3685.8 "Clone 4 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3363.0 "Twisted Vision 4" Ability { id: "BBE2", source: "Lindwurm" } +3369.6 "Clone 1 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3370.8 "Clone 1 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3374.6 "Clone 2 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3375.8 "Clone 2 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3379.6 "Clone 3 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3380.8 "Clone 3 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } +3384.6 "Clone 4 Heavy Slam?" Ability { id: "B519", source: "Lindschrat" } # Or B517 Mana Burst (Lindschrat) happens here +3385.8 "Clone 4 Mana Burst?" Ability { id: "B518", source: "Lindwurm" } # Twisted Vision 5: Towers -3693.6 "Twisted Vision 5" Ability { id: "BBE2", source: "Lindwurm" } -3698.0 "Cosmic Kiss x8" Ability { id: "B4F4", source: "Lindwurm" } -3698.6 "--Hot-blooded x2--" duration 5 -3698.7 "Lindwurm's Dark II x2" Ability { id: "B4F6", source: "Lindwurm" } -3698.7 "--Doom x2--" duration 8 -3703.7 "Lindwurm's Stone III x2" #Ability { id: "B4F7", source: "Lindwurm" } -3708.7 "Lindwurm's Thunder II x4" #Ability { id: "B4FA", source: "Lindwurm" } -3708.7 "Lindwurm's Glare x4" #Ability { id: "B4F8", source: "Lindwurm" } -3717.1 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } -3720.2 "--clone takes portal--" Ability { id: "B51D", source: "Lindschrat" } -3723.3 "--clones on platform--" Ability { id: "B4D9", source: "Lindschrat" } +3393.6 "Twisted Vision 5" Ability { id: "BBE2", source: "Lindwurm" } +3398.0 "Cosmic Kiss x8" Ability { id: "B4F4", source: "Lindwurm" } +3398.6 "--Hot-blooded x2--" duration 5 +3398.7 "Lindwurm's Dark II x2" Ability { id: "B4F6", source: "Lindwurm" } +3398.7 "--Doom x2--" duration 8 +3403.7 "Lindwurm's Stone III x2" #Ability { id: "B4F7", source: "Lindwurm" } +3408.7 "Lindwurm's Thunder II x4" #Ability { id: "B4FA", source: "Lindwurm" } +3408.7 "Lindwurm's Glare x4" #Ability { id: "B4F8", source: "Lindwurm" } +3417.1 "Temporal Curtain" Ability { id: "B51C", source: "Lindwurm" } +3420.2 "--clone takes portal--" Ability { id: "B51D", source: "Lindschrat" } +3423.3 "--clones on platform--" Ability { id: "B4D9", source: "Lindschrat" } # Twisted Vision 6: Reenactment 2 Part 1 # NOTE: Practical solution seems to be that you have x2 mana burts + x2 heavy slams @@ -516,39 +490,39 @@ hideall "--sync--" # 3x Mana Burst + 1 Heavy Slam => 3x Heavy Slam + 1 Mana Burst or # 3x Heavy Slam + 1 Mana Burst => 3x Mana Burst + 1 Heavy Slam # But those would probably require lots of mit and tank immune probably on 2/3 of the heavy slams in the 3 set -3729.6 "Twisted Vision 6" Ability { id: "BBE2", source: "Lindwurm" } -3730.6 "Power Gusher" Ability { id: ["B50F", "B510"], source: "Lindschrat" } -3730.6 "Snaking Kick" Ability { id: "BCAF", source: "Lindschrat" } -3735.7 "Reenactment 2" Ability { id: "B4EC", source: "Lindwurm" } -3739.0 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } -3739.2 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } +3429.6 "Twisted Vision 6" Ability { id: "BBE2", source: "Lindwurm" } +3430.6 "Power Gusher" Ability { id: ["B50F", "B510"], source: "Lindschrat" } +3430.6 "Snaking Kick" Ability { id: "BCAF", source: "Lindschrat" } +3435.7 "Reenactment 2" Ability { id: "B4EC", source: "Lindwurm" } +3439.0 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } +3439.2 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } # Twisted Vision 7: Safe Platform + Front/Back or Sides Platform -3744.8 "Twisted Vision 7" Ability { id: "BBE2", source: "Lindwurm" } -3749.2 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } -3749.4 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } +3444.8 "Twisted Vision 7" Ability { id: "BBE2", source: "Lindwurm" } +3449.2 "Snaking Kick" Ability { id: "BE95", source: "Lindwurm" } +3449.4 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } # Twisted Vision 8: Reenactment 2 Part 2 -3752.3 "Twisted Vision 8" Ability { id: "BBE2", source: "Lindwurm" } -3758.6 "--sync--" Ability { id: "B51E", source: "Lindschrat" } -3759.8 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } -3760.0 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } -3764.8 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } -3770.7 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } -3778.8 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } -3779.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } -3784.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } -3786.6 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } +3452.3 "Twisted Vision 8" Ability { id: "BBE2", source: "Lindwurm" } +3458.6 "--sync--" Ability { id: "B51E", source: "Lindschrat" } +3459.8 "Clone Mana Burst x2" Ability { id: "BBE3", source: "Lindwurm" } +3460.0 "Clone Heavy Slam x2" Ability { id: "BE5D", source: "Lindwurm" } +3464.8 "Power Gusher" Ability { id: "B516", source: "Lindwurm" } +3470.7 "Idyllic Dream" Ability { id: "B509", source: "Lindwurm" } +3478.8 "Double Sobat (castbar)" Ability { id: "B520", source: "Lindwurm" } +3479.6 "Double Sobat 1" Ability { id: ["B521", "B522", "B523", "B524"], source: "Lindwurm" } +3484.2 "Double Sobat 2" Ability { id: "B525", source: "Lindwurm" } +3486.6 "Esoteric Finisher" Ability { id: "B526", source: "Lindwurm" } # Enrage Sequence -3799.8 "Replication 5" Ability { id: "B46C", source: "Lindwurm" } -3813.2 "Arcadian Hell 1 (boss) " Ability { id: "B533", source: "Lindwurm" } -3813.2 "Arcadian Hell 1 x4 (clones)" #Ability { id: "B534", source: "Lindschrat" } -3829.4 "Arcadian Hell 2 (boss)" Ability { id: "B533", source: "Lindwurm" } -3829.4 "Arcadian Hell 2 x8 (clones)" #Ability { id: "B535", source: "Lindschrat" } -3842.3 "--sync--" StartsUsing { id: "B537", source: "Lindwurm" } -3852.3 "Arcadian Hell (Boss Enrage)" Ability { id: "B537", source: "Lindwurm" } -3852.3 "Arcadian Hell x16 (Clones Enrage)" #Ability { id: "BEC1", source: "Lindschrat" } +3499.8 "Replication 5" Ability { id: "B46C", source: "Lindwurm" } +3513.2 "Arcadian Hell 1 (boss) " Ability { id: "B533", source: "Lindwurm" } +3513.2 "Arcadian Hell 1 x4 (clones)" #Ability { id: "B534", source: "Lindschrat" } +3529.4 "Arcadian Hell 2 (boss)" Ability { id: "B533", source: "Lindwurm" } +3529.4 "Arcadian Hell 2 x8 (clones)" #Ability { id: "B535", source: "Lindschrat" } +3542.3 "--sync--" StartsUsing { id: "B537", source: "Lindwurm" } +3552.3 "Arcadian Hell (Boss Enrage)" Ability { id: "B537", source: "Lindwurm" } +3552.3 "Arcadian Hell x16 (Clones Enrage)" #Ability { id: "BEC1", source: "Lindschrat" } # IGNORED ABILITIES # Phase 1 @@ -583,9 +557,11 @@ hideall "--sync--" # 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 -# B4EF Heavy Slam: VFX used in Reenactment +# B8E1 Scalding Waves: Used in Reenactment (Proteans), Ignored due to timing being strategy-based +# B4EA Grotesquerie: Used in Reenactment, Ignored due to timing being strategy-based +# BBE3 Mana Burst: Used in Reenactment (Damage + Knockback), Ignored due to timing being strategy-based +# BE5D Heavy Slam: Used in Reenactment (Stack with Clone, requires at least 1 player), Ignored due to timing being strategy-based +# B922 Hemorrhagic Projection: Used in Reenactment (Damage), Ignored due to timing being strategy-based # B508 Unmitigated Explosion: Getting hit when you have Mitigation α or failing to get hit with Mitigation β, applies 30s damage down # B4FF --sync--: VFX Mana Spheres eaten by Black Hole # BCB0 --sync--: VFX Black Hole light eruption @@ -710,16 +686,16 @@ hideall "--sync--" # B4E6 Mana Burst # B4E7 Mana Burst # B51F --sync-- -# B4E8 Heavy Slam +# B4E8 Heavy Slam: Stack on Player, requires at least 1 additional player # B4E9 Grotesquerie -# B4EA Grotesquerie +# B4EA Grotesquerie: Used in Reenactment # B4EB Hemorrhagic Projection # B4EC Reenactment -# B4ED Firefall Splash -# B4EE Mana Burst -# B4EF Heavy Slam +# B4ED Firefall Splash: Used in Reenactment (Damage) +# B4EE Mana Burst: VFX used in Reenactment +# B4EF Heavy Slam: VFX used in Reenactment # B4F0 Unmitigated Impact -# B4F1 Grotesquerie +# B4F1 Grotesquerie: VFX used in Reenactment # B4F2 Lindwurm's Meteor # B4F3 Downfall # B4F4 Cosmic Kiss @@ -780,13 +756,13 @@ hideall "--sync--" # B534 Arcadian Hell # B535 Arcadian Hell # B537 Arcadian Hell -# B8E1 Scalding Waves -# B922 Hemorrhagic Projection +# B8E1 Scalding Waves: Used in Reenactment (Proteans) +# B922 Hemorrhagic Projection: Used in Reenactment (Damage) # B9D9 Arcadian Arcanum # BBE2 Twisted Vision -# BBE3 Mana Burst +# BBE3 Mana Burst: Used in Reenactment (Damage + Knockback) # BCAF Snaking Kick # BCB0 --sync--: Blackhole spawn -# BE5D Heavy Slam +# BE5D Heavy Slam: Used in Reenactment (Stack with Clone, requires at least 1 player) # BE95 Snaking Kick # BEC1 Arcadian Hell From f7cf2464bcc04f5f89caa7d88d164e754c815f13 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 26 Feb 2026 03:27:00 -0500 Subject: [PATCH 203/215] fix missed time change --- 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 5d5e8a12bad..9a4369370b0 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.txt +++ b/ui/raidboss/data/07-dt/raid/r12s.txt @@ -391,7 +391,7 @@ hideall "--sync--" 3151.3 "Reenactment 1" Ability { id: "B4EC", source: "Lindwurm" } 3159.4 "--n/s clones--" duration 1.6 3159.4 "Netherwrath Near/Netherwrath Far" Ability { id: ["B52E", "B52F"], source: "Lindwurm" } -3260.6 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } +3160.6 "Timeless Spite x2" Ability { id: "B530", source: "Lindwurm" } 3163.3 "--ne/sw clones--" Ability { id: ["B4ED", "B4EE", "B4EF", "B4F1"], source: "Lindschrat" } duration 1.6 3167.4 "--e/w clones--" Ability { id: ["B4ED", "B4EE", "B4EF", "B4F1"], source: "Lindschrat" } duration 1.6 3171.4 "--se/nw clones--" Ability { id: ["B4ED", "B4EE", "B4EF", "B4F1"], source: "Lindschrat" } duration 1.6 From 642b9c0c5e2ad68fbc351d5082c3d12897daaa92 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Mar 2026 19:10:40 -0500 Subject: [PATCH 204/215] remove incorrect calls for flipped strategies This also adds a map for simplifying retrieval of what ability is where when using the replication2DirNumAbility array. --- ui/raidboss/data/07-dt/raid/r12s.ts | 74 ++++++++++++++++++----------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 60a3202591e..48874f6dd52 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -66,7 +66,7 @@ export interface Data extends RaidbossData { replication2BossId?: string; replication2PlayerOrder: string[]; replication2AbilityOrder: string[]; - replication2StrategyDetected?: 'dn' | 'banana' | 'unknown'; + replication2StrategyDetected?: 'dn' | 'banana' | 'nukemaru' | 'unknown'; netherwrathFollowup: boolean; myMutation?: 'alpha' | 'beta'; manaSpheres: { @@ -205,6 +205,20 @@ const replication2OutputStrings = { }, }; +// Replication 2: Map for retreiving index by direction +// Abilities are stored in replication2AbilityOrder with the following dirNum order: +// 0, 4, 1, 5, 2, 6, 3, 7 +const rep2DirIndexMap = { + 'north': 0, + 'south': 1, + 'northeast': 2, + 'southwest': 3, + 'east': 4, + 'west': 5, + 'southeast': 6, + 'northwest': 7, +}; + const center = { x: 100, y: 100, @@ -3348,32 +3362,40 @@ const triggerSet: TriggerSet = { // Detect recognized strategy by checking first 6 abilities const detectStrategy = ( order: string[], - ): 'dn' | 'banana' | 'unknown' => { + ): 'dn' | 'banana' | 'nukemaru' | 'unknown' => { const defamation = headMarkerData['manaBurstTether']; const stack = headMarkerData['heavySlamTether']; const projection = headMarkerData['projectionTether']; // DN if ( - ( - (order[0] === 'none' && order[1] === boss) || - (order[0] === boss && order[1] === 'none') - ) && ( - (order[2] === defamation && order[3] === projection) || - (order[2] === projection && order[3] === defamation) - ) && (order[4] === stack && order[5] === stack) + order[rep2DirIndexMap['north']] === boss && + order[rep2DirIndexMap['south']] === 'none' && + order[rep2DirIndexMap['northeast']] === projection && + order[rep2DirIndexMap['southwest']] === defamation && + order[rep2DirIndexMap['east']] === stack && + order[rep2DirIndexMap['west']] === stack ) return 'dn'; // Banana Codex if ( - (order[0] === projection && order[1] === projection) && ( - (order[2] === stack && order[3] === defamation) || - (order[2] === defamation && order[3] === stack) - ) && ( - (order[4] === boss && order[5] === 'none') || - (order[4] === 'none' && order[5] === boss) - ) + order[rep2DirIndexMap['north']] === projection && + order[rep2DirIndexMap['south']] === projection && + order[rep2DirIndexMap['northeast']] === defamation && + order[rep2DirIndexMap['southwest']] === stack && + order[rep2DirIndexMap['east']] === 'none' && + order[rep2DirIndexMap['west']] === boss ) return 'banana'; + // Nukemaru + if ( + order[rep2DirIndexMap['north']] === projection && + order[rep2DirIndexMap['south']] === projection && + order[rep2DirIndexMap['northeast']] === stack && + order[rep2DirIndexMap['southwest']] === defamation && + order[rep2DirIndexMap['east']] === boss && + order[rep2DirIndexMap['west']] === 'none' + ) + return 'nukemaru'; // Not Yet Supported, File a Feature Request or PR return 'unknown'; }; @@ -4221,13 +4243,11 @@ const triggerSet: TriggerSet = { const stack = headMarkerData['heavySlamTether']; const defamation = headMarkerData['manaBurstTether']; const projection = headMarkerData['projectionTether']; - // Defined as east/west clones with stacks and SW/NE with defamation + projection if ( - order[4] === stack && order[5] === stack && - ( - (order[2] === defamation && order[3] === projection) || - (order[2] === projection && order[3] === defamation) - ) + order[rep2DirIndexMap['east']] === stack && + order[rep2DirIndexMap['west']] === stack && + order[rep2DirIndexMap['northeast']] === projection && + order[rep2DirIndexMap['southwest']] === defamation ) return true; } @@ -4298,13 +4318,11 @@ const triggerSet: TriggerSet = { const stack = headMarkerData['heavySlamTether']; const defamation = headMarkerData['manaBurstTether']; const projection = headMarkerData['projectionTether']; - // Defined as east/west clones with stacks and NW/SE with defamation + projection if ( - order[4] === stack && order[5] === stack && - ( - (order[6] === defamation && order[7] === projection) || - (order[7] === projection && order[6] === defamation) - ) + order[rep2DirIndexMap['east']] === stack && + order[rep2DirIndexMap['west']] === stack && + order[rep2DirIndexMap['southeast']] === defamation && + order[rep2DirIndexMap['northwest']] === projection ) return true; } From 12229cd5519fb8ee6b3c5baed31a5d292271849a Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Mar 2026 19:15:42 -0500 Subject: [PATCH 205/215] additionally check southeast position for detection Not sure it's even viable to do some of these in reverse, but just to be complete in case of unexpected output on a final trigger. --- ui/raidboss/data/07-dt/raid/r12s.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 48874f6dd52..9e923069ef4 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3359,7 +3359,7 @@ const triggerSet: TriggerSet = { data.replication2AbilityOrder.push(ability); } - // Detect recognized strategy by checking first 6 abilities + // Detect recognized strategy by checking first 7 abilities const detectStrategy = ( order: string[], ): 'dn' | 'banana' | 'nukemaru' | 'unknown' => { @@ -3373,7 +3373,8 @@ const triggerSet: TriggerSet = { order[rep2DirIndexMap['northeast']] === projection && order[rep2DirIndexMap['southwest']] === defamation && order[rep2DirIndexMap['east']] === stack && - order[rep2DirIndexMap['west']] === stack + order[rep2DirIndexMap['west']] === stack && + order[rep2DirIndexMap['southeast']] === defamation ) return 'dn'; // Banana Codex @@ -3383,7 +3384,8 @@ const triggerSet: TriggerSet = { order[rep2DirIndexMap['northeast']] === defamation && order[rep2DirIndexMap['southwest']] === stack && order[rep2DirIndexMap['east']] === 'none' && - order[rep2DirIndexMap['west']] === boss + order[rep2DirIndexMap['west']] === boss && + order[rep2DirIndexMap['southeast']] === defamation ) return 'banana'; // Nukemaru @@ -3393,7 +3395,8 @@ const triggerSet: TriggerSet = { order[rep2DirIndexMap['northeast']] === stack && order[rep2DirIndexMap['southwest']] === defamation && order[rep2DirIndexMap['east']] === boss && - order[rep2DirIndexMap['west']] === 'none' + order[rep2DirIndexMap['west']] === 'none' && + order[rep2DirIndexMap['southeast']] === stack ) return 'nukemaru'; // Not Yet Supported, File a Feature Request or PR From a9e6d61232e9dd68c97f3d470101d3c55f25df2d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Mar 2026 19:41:32 -0500 Subject: [PATCH 206/215] add second, third, fourth clone nukemaru calls --- ui/raidboss/data/07-dt/raid/r12s.ts | 136 ++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 30 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 9e923069ef4..df7cb80077c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4191,15 +4191,19 @@ const triggerSet: TriggerSet = { run: (data) => data.netherwrathFollowup = true, }, { - id: 'R12S Reenactment 1 Clone Stack SW (Second Clones Banana)', - // NOTE: This is used in Banana Codex Strategy - // SW Clone Stack happens after N/S Clone Projections + id: 'R12S Reenactment 1 Clone Stack SW (Second Clones Banana/Nukemaru)', + // NOTE: This is used in Banana Codex Strategy and Nukemaru + // SW (Banana)/NE (Nukemaru) Clone Stack happens after N/S Clone Projections // Defamation Tether Players, Boss Tether Player, and No Tether Player take stack // Using B922 Hemorrhagic Projection from clones type: 'Ability', netRegex: { id: 'B922', source: 'Lindwurm', capture: false }, condition: (data) => { - if (data.replication2StrategyDetected === 'banana') + // Banana Codex and Nukemaru Strategy Order + if ( + data.replication2StrategyDetected === 'banana' || + data.replication2StrategyDetected === 'nukemaru' + ) return true; return false; }, @@ -4207,30 +4211,52 @@ const triggerSet: TriggerSet = { response: (data, _matches, output) => { // cactbot-builtin-response output.responseOutputStrings = { - stackThenStack: { + stackThenStackBanana: { en: 'Stack on SW Clone => Stack on NW Clone', }, - avoidStackThenProtean: { + avoidStackThenProteanBanana: { en: 'Avoid SW Stack => Bait Protean West', }, - stackThenProteans: { + stackThenProteansBanana: { en: 'SW Clone Stack => West Proteans', }, + stackThenStackNukemaru: { + en: 'Stack on NE Clone => Stack on SE Clone', + }, + avoidStackThenProteanNukemaru: { + en: 'Avoid NE Stack => Bait Protean East', + }, + stackThenProteansNukemaru: { + en: 'NE Clone Stack => East Proteans', + }, }; + const strat = data.replication2StrategyDetected; const ability = data.replication2PlayerAbilities[data.me]; switch (ability) { case headMarkerData['projectionTether']: case headMarkerData['heavySlamTether']: - return { infoText: output.avoidStackThenProtean!() }; + return { + infoText: strat === 'banana' + ? output.avoidStackThenProteanBanana!() + : output.avoidStackThenProteanNukemaru!() + }; case headMarkerData['manaBurstTether']: case headMarkerData['fireballSplashTether']: case 'none': - return { alertText: output.stackThenStack!() }; + return { + alertText: strat === 'banana' + ? output.stackThenStackBanana!() + : output.statckThenStackNukemaru!(), + }; } // Missing ability data, output mechanic order - return { infoText: output.stackThenProteans!() }; + return { + infoText: strat === 'banana' + ? output.stackThenProteansBanana!() + : output.stackThenProteansNukemaru!(), + }; }, }, { @@ -4265,16 +4291,19 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Reenactment 1 Proteans West (Third Clones Banana)', - // NOTE: This is used in Banana Codex Strategy + id: 'R12S Reenactment 1 Proteans West (Third Clones Banana/Nukemaru)', + // NOTE: This is used in Banana Codex Strategy and Nukemaru // Stack Players need to go to the other stack // Non-stack players need to bait proteans // Using BE5D Heavy Slam from clones type: 'Ability', netRegex: { id: 'BE5D', source: 'Lindwurm', capture: false }, condition: (data) => { - // Banana Codex Strategy Order - if (data.replication2StrategyDetected === 'banana') + // Banana Codex and Nukemaru Strategy Order + if ( + data.replication2StrategyDetected === 'banana' || + data.replication2StrategyDetected === 'nukemaru' + ) return true; return false; }, @@ -4282,30 +4311,52 @@ const triggerSet: TriggerSet = { response: (data, _matches, output) => { // cactbot-builtin-response output.responseOutputStrings = { - protean: { + proteanBanana: { en: 'Bait Protean West + Avoid Clone AoE', }, - avoidThenStack: { + avoidThenStackBanana: { en: 'Avoid West Clone/East Defamation + Stack on NW Clone', }, - proteansThenStack: { + proteansThenStackBanana: { en: 'West Proteans => NW Clone Stack', }, + proteanNukemaru: { + en: 'Bait Protean East + Avoid Clone AoE', + }, + avoidThenStackNukemaru: { + en: 'Avoid East Clone/West Defamation + Stack on SE Clone', + }, + proteansThenStackNukemaru: { + en: 'East Proteans => SE Clone Stack', + }, }; + const strat = data.replication2StrategyDetected; const ability = data.replication2PlayerAbilities[data.me]; switch (ability) { case headMarkerData['projectionTether']: case headMarkerData['heavySlamTether']: - return { alertText: output.protean!() }; + return { + alertText: strat === 'banana' + ? output.proteanBanana!() + : output.proteanNukemaru!(), + }; case headMarkerData['manaBurstTether']: case headMarkerData['fireballSplashTether']: case 'none': - return { infoText: output.avoidThenStack!() }; + return { + infoText: strat === 'banana' + ? output.avoidThenStackBanana!() + : output.avoidThenStackNukemaru!(), + }; } // Missing ability data, output mechanic order - return { infoText: output.proteansThenStack!() }; + return { + infoText: strat === 'banana' + ? output.proteansThenStackBanana!() + : output.proteansThenStackNukemaru!(), + }; }, }, { @@ -4338,16 +4389,19 @@ const triggerSet: TriggerSet = { }, }, { - id: 'R12S Reenactment 1 Clone Stack NW Reminder (Fourth Clones Banana)', - // NOTE: This is used in Banana Codex Strategy + id: 'R12S Reenactment 1 Clone Stack NW Reminder (Fourth Clones Banana/Nukemaru)', + // NOTE: This is used in Banana Codex Strategy and Nukemaru // Reminder for players to Stack // Reminder for Non-stack players to avoid // Using B8E1 Scalding Waves from clones type: 'Ability', netRegex: { id: 'B8E1', source: 'Lindwurm', capture: false }, condition: (data) => { - // Banana Codex Strategy Order - if (data.replication2StrategyDetected === 'banana') + // Banana Codex and Nukemaru Strategy Order + if ( + data.replication2StrategyDetected === 'banana' || + data.replication2StrategyDetected === 'nukemaru' + ) return true; return false; }, @@ -4355,30 +4409,52 @@ const triggerSet: TriggerSet = { response: (data, _matches, output) => { // cactbot-builtin-response output.responseOutputStrings = { - stack: { + stackBanana: { en: 'Stack on NW Clone', }, - avoidStack: { + avoidStackBanana: { en: 'Avoid NE Stack', }, - stackAndDefamation: { + stackAndDefamationBanana: { en: 'NW Clone Stack + SE Defamation', }, + stackNukemaru: { + en: 'Stack on SE Clone', + }, + avoidStackNukemaru: { + en: 'Avoid SE Stack', + }, + stackAndDefamationNukemaru: { + en: 'SE Clone Stack + NW Defamation', + }, }; + const strat = data.replication2StrategyDetected; const ability = data.replication2PlayerAbilities[data.me]; switch (ability) { case headMarkerData['projectionTether']: case headMarkerData['heavySlamTether']: - return { infoText: output.avoidStack!() }; + return { + infoText: strat === 'banana' + ? output.avoidStackBanana!() + : output.avoidStackNukemaru!(), + }; case headMarkerData['manaBurstTether']: case headMarkerData['fireballSplashTether']: case 'none': - return { alertText: output.stack!() }; + return { + alertText: strat === 'banana' + ? output.stackBanana!() + : output.stackNukemaru!(), + }; } // Missing ability data, output mechanic order - return { infoText: output.stackAndDefamation!() }; + return { + infoText: strat === 'banana' + ? output.stackAndDefamationBanana!() + : output.stackAndDefamationNukemaru!(), + }; }, }, { From 3021b19f73a5ef629d261d1f7bef1dd1e56857eb Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Mar 2026 19:44:07 -0500 Subject: [PATCH 207/215] 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 df7cb80077c..d256f5bad05 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4239,7 +4239,7 @@ const triggerSet: TriggerSet = { return { infoText: strat === 'banana' ? output.avoidStackThenProteanBanana!() - : output.avoidStackThenProteanNukemaru!() + : output.avoidStackThenProteanNukemaru!(), }; case headMarkerData['manaBurstTether']: case headMarkerData['fireballSplashTether']: From f6c592e8b97686a0f543140cd6a8fa96cb07a554 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Mar 2026 19:55:50 -0500 Subject: [PATCH 208/215] add nukemaru support for netherwrath (first clones) --- ui/raidboss/data/07-dt/raid/r12s.ts | 47 +++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index d256f5bad05..2f8af127aec 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3930,15 +3930,16 @@ const triggerSet: TriggerSet = { { id: 'R12S Netherwrath Near/Far and First Clones', // In DN, Boss jumps onto clone of player that took Firefall Splash, there is an aoe around the clone + proteans - // In Banana Codex, N/S Projections happen at this time + // In Banana Codex and Nukemaru, N/S Projections happen at this time type: 'StartsUsing', netRegex: { id: ['B52E', 'B52F'], source: 'Lindwurm', capture: true }, infoText: (data, matches, output) => { + const strat = data.replication2StrategyDetected; const ability = data.replication2PlayerAbilities[data.me]; const isNear = matches.id === 'B52E'; // DN Strategy - if (data.replication2StrategyDetected === 'dn') { + if (strat === 'dn') { if (isNear) { switch (ability) { case headMarkerData['projectionTether']: @@ -4017,9 +4018,9 @@ const triggerSet: TriggerSet = { }); } - // Banana Codex Strategy - if (data.replication2StrategyDetected === 'banana') { - // Technically, this strategy does not care about Near/Far, but + // Banana Codex and Nukemaru Strategies + if (strat === 'banana' || strat === 'nukemaru') { + // Technically, these strategies do not care about Near/Far, but // included as informational switch (ability) { case headMarkerData['projectionTether']: @@ -4030,9 +4031,15 @@ const triggerSet: TriggerSet = { }); case headMarkerData['manaBurstTether']: return output.manaBurstTetherHitbox!({ - mech1: output.hitboxWest!(), + mech1: strat === 'banana' + ? output.hitboxBanana!() + : output.hitboxNukemaru!(), spiteBaits: isNear ? output.near!() : output.far!(), - mech2: output.stackDir!({ dir: output.dirSW!() }), + mech2: output.stackDir!({ + dir: strat === 'banana' + ? output.dirSW!() + : output.dirNE!(), + }), }); case headMarkerData['heavySlamTether']: return output.heavySlamTetherBait!({ @@ -4042,15 +4049,27 @@ const triggerSet: TriggerSet = { }); case headMarkerData['fireballSplashTether']: return output.fireballSplashTetherHitbox!({ - mech1: output.hitboxWest!(), + mech1: strat === 'banana' + ? output.hitboxBanana!() + : output.hitboxNukemaru!(), spiteBaits: isNear ? output.near!() : output.far!(), - mech2: output.stackDir!({ dir: output.dirSW!() }), + mech2: output.stackDir!({ + dir: strat === 'banana' + ? output.dirSW!() + : output.dirNE!(), + }), }); } return output.noTetherHitbox!({ - mech1: output.hitboxWest!(), + mech1: strat === 'banana' + ? output.hitboxBanana!() + : output.hitboxNukemaru!(), spiteBaits: isNear ? output.near!() : output.far!(), - mech2: output.stackDir!({ dir: output.dirSW!() }), + mech2: output.stackDir!({ + dir: strat === 'banana' + ? output.dirSW!() + : output.dirNE!(), + }), }); } @@ -4087,6 +4106,7 @@ const triggerSet: TriggerSet = { }); }, outputStrings: { + dirNE: Outputs.dirNE, dirSW: Outputs.dirSW, scaldingWave: Outputs.protean, timelessSpite: Outputs.stackPartner, @@ -4103,7 +4123,10 @@ const triggerSet: TriggerSet = { beFar: { en: 'Be Far', }, - hitboxWest: { + hitboxBanana: { + en: 'Be West on Boss Hitbox', + }, + hitboxNukemaru: { en: 'Be West on Boss Hitbox', }, near: { From a6a009979028730c773e88f467b75e084316fb8b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Mar 2026 19:56:50 -0500 Subject: [PATCH 209/215] fix typo --- 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 2f8af127aec..dddc8f9094c 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -4270,7 +4270,7 @@ const triggerSet: TriggerSet = { return { alertText: strat === 'banana' ? output.stackThenStackBanana!() - : output.statckThenStackNukemaru!(), + : output.stackThenStackNukemaru!(), }; } From 6158a3a4ed4e337ba994dac225e590ec5e4db9f2 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Mar 2026 20:43:01 -0500 Subject: [PATCH 210/215] add nukemaru replication 2 config --- ui/raidboss/data/07-dt/raid/r12s.ts | 198 +++++++++++++++++++--------- 1 file changed, 133 insertions(+), 65 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index dddc8f9094c..5bebb80b3bc 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -26,7 +26,7 @@ export interface Data extends RaidbossData { curtainCallStrat: 'ns' | 'none'; uptimeKnockbackStrat: true | false; portentStrategy: 'dn' | 'zenith' | 'none'; - replication2Strategy: 'dn' | 'banana' | 'none'; + replication2Strategy: 'dn' | 'banana' | 'nukemaru' | 'none'; }; phase: Phase; // Phase 1 @@ -285,6 +285,8 @@ const triggerSet: TriggerSet = { 'dn', 'Banana Codex Strategy: Boss West, Stacks NW/SW, Cones N/S, Defamations NE/SE, Nothing E': 'banana', + 'Nukemaru Strategy: Boss East, Stacks NE/SE, Cones N/S, Defamations NW/SW, Nothing W': + 'nukemaru', 'No strategy: Calls the tether you may have and to get a tether.': 'none', }, }, @@ -2861,6 +2863,7 @@ const triggerSet: TriggerSet = { infoText: (data, matches, output) => { const id = matches.id; const clones = data.replication2CloneDirNumPlayers; + const strat = data.triggerSetConfig.replication2Strategy; const myDirNum = Object.keys(clones).find( (key) => clones[parseInt(key)] === data.me, ); @@ -2875,10 +2878,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getBossTether!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getConeTetherCW!() + : strat === 'nukemaru' + ? output.getConeTetherCCW!() : output.getTether!(), }), }); @@ -2886,10 +2891,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherNEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getConeTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getDefamationTetherCW!() + : strat === 'nukemaru' + ? output.getStackTetherCCW!() : output.getTether!(), }), }); @@ -2897,10 +2904,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getStackTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getNoTether!() + : strat === 'nukemaru' + ? output.getBossTether!() : output.getTether!(), }), }); @@ -2908,10 +2917,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getDefamationTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getDefamationTetherCCW!() + : strat === 'nukemaru' + ? output.getStackTetherCW!() : output.getTether!(), }), }); @@ -2919,10 +2930,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getNoTether!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getConeTetherCCW!() + : strat === 'nukemaru' + ? output.getConeTetherCW!() : output.getTether!(), }), }); @@ -2930,10 +2943,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getDefamationTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getStackTetherCCW!() + : strat === 'nukemaru' + ? output.getDefamationTetherCW!() : output.getTether!(), }), }); @@ -2941,10 +2956,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getStackTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getBossTether!() + : strat === 'nukemaru' + ? output.getNoTether!() : output.getTether!(), }), }); @@ -2952,10 +2969,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.fireballSplashTether!(), tether2: output.getTetherNWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getConeTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getStackTetherCW!() + : strat === 'nukemaru' + ? output.getDefamationTetherCCW!() : output.getTether!(), }), }); @@ -2984,10 +3003,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getBossTether!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getConeTetherCW!() + : strat === 'nukemaru' + ? output.getConeTetherCCW!() : output.getTether!(), }), }); @@ -2995,10 +3016,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherNEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getConeTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getDefamationTetherCW!() + : strat === 'nukemaru' + ? output.getStackTetherCCW!() : output.getTether!(), }), }); @@ -3006,10 +3029,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getStackTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getNoTether!() + : strat === 'nukemaru' + ? output.getBossTether!() : output.getTether!(), }), }); @@ -3017,10 +3042,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getDefamationTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getDefamationTetherCCW!() + : strat === 'nukemaru' + ? output.getStackTetherCW!() : output.getTether!(), }), }); @@ -3028,10 +3055,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getNoTether!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getConeTetherCCW!() + : strat === 'nukemaru' + ? output.getConeTetherCW!() : output.getTether!(), }), }); @@ -3039,10 +3068,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getDefamationTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getStackTetherCCW!() + : strat === 'nukemaru' + ? output.getDefamationTetherCW!() : output.getTether!(), }), }); @@ -3050,10 +3081,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getStackTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getBossTether!() + : strat === 'nukemaru' + ? output.getNoTether!() : output.getTether!(), }), }); @@ -3061,10 +3094,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tether]!(), tether2: output.getTetherNWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getConeTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getStackTetherCW!() + : strat === 'nukemaru' + ? output.getDefamationTetherCCW!() : output.getTether!(), }), }); @@ -3088,10 +3123,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getBossTether!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getConeTetherCW!() + : strat === 'nukemaru' + ? output.getConeTetherCCW!() : output.getTether!(), }), }); @@ -3099,10 +3136,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherNEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getConeTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getDefamationTetherCW!() + : strat === 'nukemaru' + ? output.getStackTetherCCW!() : output.getTether!(), }), }); @@ -3110,10 +3149,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getStackTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getNoTether!() + : strat === 'nukemaru' + ? output.getBossTether!() : output.getTether!(), }), }); @@ -3121,10 +3162,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getDefamationTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getDefamationTetherCCW!() + : strat === 'nukemaru' + ? output.getStackTetherCW!() : output.getTether!(), }), }); @@ -3132,10 +3175,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getNoTether!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getConeTetherCCW!() + : strat === 'nukemaru' + ? output.getConeTetherCW!() : output.getTether!(), }), }); @@ -3143,10 +3188,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getDefamationTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getStackTetherCCW!() + : strat === 'nukemaru' + ? output.getDefamationTetherCW!() : output.getTether!(), }), }); @@ -3154,10 +3201,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getStackTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getBossTether!() + : strat === 'nukemaru' + ? output.getNoTether!() : output.getTether!(), }), }); @@ -3165,10 +3214,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output[tetherDir]!({ dir: output[dir]!() }), tether2: output.getTetherNWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getConeTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getStackTetherCW!() + : strat === 'nukemaru' + ? output.getDefamationTetherCCW!() : output.getTether!(), }), }); @@ -3188,6 +3239,7 @@ const triggerSet: TriggerSet = { infoText: (data, _matches, output) => { if (data.replication2hasInitialAbilityTether) return; + const strat = data.triggerSetConfig.replication2Strategy; const clones = data.replication2CloneDirNumPlayers; const myDirNum = Object.keys(clones).find( (key) => clones[parseInt(key)] === data.me, @@ -3201,10 +3253,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherNClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getBossTether!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getConeTetherCW!() + : strat === 'nukemaru' + ? output.getConeTetherCCW!() : output.getTether!(), }), }); @@ -3212,10 +3266,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherNEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getConeTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getDefamationTetherCW!() + : strat === 'nukemaru' + ? output.getStackTetherCCW!() : output.getTether!(), }), }); @@ -3223,10 +3279,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getStackTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getNoTether!() + : strat === 'nukemaru' + ? output.getBossTether!() : output.getTether!(), }), }); @@ -3234,10 +3292,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSEClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getDefamationTetherCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getDefamationTetherCCW!() + : strat === 'nukemaru' + ? output.getStackTetherCW!() : output.getTether!(), }), }); @@ -3245,10 +3305,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getNoTether!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getConeTetherCCW!() + : strat === 'nukemaru' + ? output.getConeTetherCW!() : output.getTether!(), }), }); @@ -3256,10 +3318,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherSWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getDefamationTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getStackTetherCCW!() + : strat === 'nukemaru' + ? output.getDefamationTetherCW!() : output.getTether!(), }), }); @@ -3267,10 +3331,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getStackTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getBossTether!() + : strat === 'nukemaru' + ? output.getNoTether!() : output.getTether!(), }), }); @@ -3278,10 +3344,12 @@ const triggerSet: TriggerSet = { return output.tetherGetTether!({ tether1: output.noTether!(), tether2: output.getTetherNWClone!({ - tether: data.triggerSetConfig.replication2Strategy === 'dn' + tether: strat === 'dn' ? output.getConeTetherCCW!() - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.getStackTetherCW!() + : strat === 'nukemaru' + ? output.getDefamationTetherCCW!() : output.getTether!(), }), }); From b6131985741855061ca96ca237e57211df775a3b Mon Sep 17 00:00:00 2001 From: Legends0 Date: Wed, 4 Mar 2026 21:14:06 -0500 Subject: [PATCH 211/215] additional nukemaru update --- ui/raidboss/data/07-dt/raid/r12s.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 5bebb80b3bc..a2bb3ed7742 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3857,16 +3857,17 @@ const triggerSet: TriggerSet = { delaySeconds: 0.2, suppressSeconds: 1, infoText: (data, _matches, output) => { - if ( - data.replication2PlayerAbilities[data.me] !== 'none' || - data.replication2PlayerAbilities[data.me] === undefined - ) + const ability = data.replication2PlayerAbilities[data.me]; + const strat = data.triggerSetConfig.replication2Strategy; + if (ability !== 'none' || ability === undefined) return; return output.noTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.defamationOnYouDN!({ strat: output.south!() }) - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.defamationOnYouBanana!({ strat: output.east!() }) + : strat === 'nukemaru' + ? output.defamationOnYouNukemaru!({ strat: output.west!() }) : output.defamationOnYou!(), mech2: output.stackGroups!(), }); @@ -3874,6 +3875,7 @@ const triggerSet: TriggerSet = { outputStrings: { east: Outputs.east, south: Outputs.south, + west: Outputs.west, defamationOnYou: Outputs.defamationOnYou, defamationOnYouDN: { en: 'Defamation on YOU (Go ${strat})', @@ -3881,6 +3883,9 @@ const triggerSet: TriggerSet = { defamationOnYouBanana: { en: 'Defamation on YOU (Go ${strat})', }, + defamationOnYouNukemaru: { + en: 'Defamation on YOU (Go ${strat})', + }, stackGroups: { en: 'Stack Groups', de: 'Gruppen-Sammeln', From 57bfbc953f23ef6c2fa8d9290690ac9974746b81 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 5 Mar 2026 00:16:18 -0500 Subject: [PATCH 212/215] grab tether calls for nukemaru in replication 2 --- ui/raidboss/data/07-dt/raid/r12s.ts | 184 +++++++++++++++++++++------- 1 file changed, 142 insertions(+), 42 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index a2bb3ed7742..8e89ac66dbe 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3491,13 +3491,16 @@ const triggerSet: TriggerSet = { delaySeconds: 0.1, infoText: (data, matches, output) => { const sourceId = matches.sourceId; + const strat = data.triggerSetConfig.replication2Strategy; // Check if it's the boss if (data.replication2BossId === sourceId) return output.fireballSplashTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitJumpDNN!({ strat: output.north!() }) - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.baitJumpBananaW!({ strat: output.west!() }) + : strat === 'nukemaru' + ? output.baitJumpNukemaruE!({ strat: output.east!() }) : output.baitJump!(), }); @@ -3513,95 +3516,129 @@ const triggerSet: TriggerSet = { switch (ability) { case headMarkerData['projectionTether']: switch (myDirNumInt) { - case 0: // Banana only + case 0: // Banana and Nukemaru return output.projectionTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.baitProteanBananaN!({ strat: output['dirWSW']!(), }) // Southmost protean + : strat === 'nukemaru' + ? output.baitProteanNukemaruN!({ + strat: output['dirENE']!(), + }) // Northmost protean : output.baitProtean!(), }); case 1: // DN only return output.projectionTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDNNE!({ strat: output.north!() }) // Inner NNE : output.baitProtean!(), }); - case 4: // Banana only + case 4: // Banana and Nukemaru return output.projectionTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.baitProteanBananaS!({ strat: output['dirWNW']!(), }) // Northmost protean + : strat === 'nukemaru' + ? output.baitProteanNukemaruN!({ + strat: output['dirESE']!(), + }) // Southmost protean : output.baitProtean!(), }); case 7: // DN only return output.projectionTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDNNW!({ strat: output.north!() }) // Inner NNW : output.baitProtean!(), }); } return output.projectionTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDN!({ strat: output.north!() }) - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.baitProteanBanana!({ strat: output.west!() }) + : strat === 'nukemaru' + ? output.baitProteanNukemaru!({ strat: output.east!() }) : output.baitProtean!(), }); case headMarkerData['manaBurstTether']: switch (myDirNumInt) { case 1: // Banana Only return output.manaBurstTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.defamationOnYouBananaNE!({ strat: output['dirNNE']!(), }) // North/NNE : output.defamationOnYou!(), }); - case 3: + case 3: // DN and Banana return output.manaBurstTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.defamationOnYouDNSE!({ strat: output['dirESE']!(), }) // East/ESE - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.defamationOnYouBananaSE!({ strat: output['dirSSE']!(), }) // South/SSE : output.defamationOnYou!(), }); - case 5: // DN Only + case 5: // DN and Nukemaru return output.manaBurstTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.defamationOnYouDNSW!({ strat: output['dirWSW']!(), }) // West/WSW + : strat === 'nukemaru' + ? output.defamationOnYouNukemaruSW!({ + strat: output['dirSSW']!(), + }) // South/SSW : output.defamationOnYou!(), }); + case 7: // Nukemaru Only + return output.manaBurstTether!({ + mech1: strat === 'nukemaru' + ? output.defamationOnYouNukemaruNW!({ + strat: output['dirNNW']!(), + }) // North/NNW + : output.defamationOnYou!(), + }); } return output.manaBurstTether!({ mech1: output.defamationOnYou!(), }); case headMarkerData['heavySlamTether']: switch (myDirNumInt) { + case 1: // Nukemaru Only + return output.heavySlamTether!({ + mech1: strat === 'nukemaru' + ? output.baitProteanNukemaruNE!({ strat: output.east!() }) // Inner ENE + : output.baitProtean!(), + }); case 2: // DN Only return output.heavySlamTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDNE!({ strat: output['dirNNE']!(), }) // Eastmost Protean : output.baitProtean!(), }); + case 3: // Nukemaru Only + return output.heavySlamTether!({ + mech1: strat === 'nukemaru' + ? output.baitProteanNukemaruSE!({ strat: output.east!() }) // Inner ESE + : output.baitProtean!(), + }); case 5: // Banana Only return output.heavySlamTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.baitProteanBananaSW!({ strat: output.west!() }) // Inner WSW : output.baitProtean!(), }); case 6: // DN Only return output.heavySlamTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDNW!({ strat: output['dirNNW']!(), }) // Westmost Protean @@ -3609,15 +3646,15 @@ const triggerSet: TriggerSet = { }); case 7: // Banana Only return output.heavySlamTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.baitProteanBananaNW!({ strat: output.west!() }) // Inner WNW : output.baitProtean!(), }); } return output.heavySlamTether!({ - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDN!({ strat: output.north!() }) - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.baitProteanBanana!({ strat: output.west!() }) : output.baitProtean!(), }); @@ -3636,45 +3673,55 @@ const triggerSet: TriggerSet = { switch (ability) { case headMarkerData['projectionTether']: switch (myDirNumInt) { - case 0: // Banana only + case 0: // Banana and Nukemaru return output.projectionTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.baitProteanBananaN!({ strat: output['dirWSW']!(), }) // Southmost protean + : strat === 'nukemaru' + ? output.baitProteanNukemaruN!({ + strat: output['dirENE']!(), + }) // Northmost protean : output.baitProtean!(), }); case 1: // DN only return output.projectionTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDNNE!({ strat: output.north!() }) // Inner NNE : output.baitProtean!(), }); - case 4: // Banana only + case 4: // Banana and Nukemaru return output.projectionTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.baitProteanBananaS!({ strat: output['dirWNW']!(), }) // Northmost protean + : strat === 'nukemaru' + ? output.baitProteanNukemaruS!({ + strat: output['dirESE']!(), + }) // Southmost protean : output.baitProtean!(), }); case 7: // DN only return output.projectionTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDNNW!({ strat: output.north!() }) // Inner NNW : output.baitProtean!(), }); } return output.projectionTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDN!({ strat: output.north!() }) - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.baitProteanBanana!({ strat: output.west!() }) + : strat === 'nukemaru' + ? output.baitProteanNukemaru!({ strat: output.east!() }) : output.baitProtean!(), }); case headMarkerData['manaBurstTether']: @@ -3682,32 +3729,45 @@ const triggerSet: TriggerSet = { case 1: // Banana Only return output.manaBurstTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.defamationOnYouBananaNE!({ strat: output['dirNNE']!(), }) // North/NNE : output.defamationOnYou!(), }); - case 3: + case 3: // DN and Banana return output.manaBurstTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.defamationOnYouDNSE!({ strat: output['dirESE']!(), }) // East/ESE - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.defamationOnYouBananaSE!({ strat: output['dirSSE']!(), }) // South/SSE : output.defamationOnYou!(), }); - case 5: // DN Only + case 5: // DN and Nukemaru return output.manaBurstTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.defamationOnYouDNSW!({ strat: output['dirWSW']!(), }) // West/WSW + : strat === 'nukemaru' + ? output.defamationOnYouNukemaruSW!({ + strat: output['dirSSW']!(), + }) // South/SSW + : output.defamationOnYou!(), + }); + case 7: // Nukemaru Only + return output.manaBurstTetherDir!({ + dir: output[dir]!(), + mech1: strat === 'nukemaru' + ? output.defamationOnYouNukemaruNW!({ + strat: output['dirNNW']!(), + }) // North/NNW : output.defamationOnYou!(), }); } @@ -3717,26 +3777,40 @@ const triggerSet: TriggerSet = { }); case headMarkerData['heavySlamTether']: switch (myDirNumInt) { + case 1: // Nukemaru Only + return output.heavySlamTetherDir!({ + dir: output[dir]!(), + mech1: strat === 'nukemaru' + ? output.baitProteanNukemaruNE!({ strat: output.east!() }) // Inner ENE + : output.baitProtean!(), + }); case 2: // DN Only return output.heavySlamTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDNE!({ strat: output['dirNNE']!(), }) // Eastmost Protean : output.baitProtean!(), }); + case 3: // Nukemaru Only + return output.heavySlamTetherDir!({ + dir: output[dir]!(), + mech1: strat === 'nukemaru' + ? output.baitProteanNukemaruSE!({ strat: output.east!() }) // Inner ESE + : output.baitProtean!(), + }); case 5: // Banana Only return output.heavySlamTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.baitProteanBananaSW!({ strat: output.west!() }) // Inner WSW : output.baitProtean!(), }); case 6: // DN Only return output.heavySlamTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDNW!({ strat: output['dirNNW']!(), }) // Westmost Protean @@ -3745,17 +3819,19 @@ const triggerSet: TriggerSet = { case 7: // Banana Only return output.heavySlamTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'banana' + mech1: strat === 'banana' ? output.baitProteanBananaNW!({ strat: output.west!() }) // Inner WNW : output.baitProtean!(), }); } return output.heavySlamTetherDir!({ dir: output[dir]!(), - mech1: data.triggerSetConfig.replication2Strategy === 'dn' + mech1: strat === 'dn' ? output.baitProteanDN!({ strat: output.north!() }) - : data.triggerSetConfig.replication2Strategy === 'banana' + : strat === 'banana' ? output.baitProteanBanana!({ strat: output.west!() }) + : strat === 'nukemaru' + ? output.baitProteanBanana!({ strat: output.east!() }) : output.baitProtean!(), }); } @@ -3779,6 +3855,12 @@ const triggerSet: TriggerSet = { defamationOnYouBananaSE: { en: 'Defamation on YOU, Go ${strat}', }, + defamationOnYouNukemaruSW: { + en: 'Defamation on YOU, Go ${strat}', + }, + defamationOnYouNukermaruNW: { + en: 'Defamation on YOU, Go ${strat}', + }, baitProtean: { en: 'Bait Protean from Boss', }, @@ -3812,6 +3894,21 @@ const triggerSet: TriggerSet = { baitProteanBananaNW: { en: 'Bait Protean from Boss (${strat})', }, + baitProteanNukemaru: { // If clone tether num missing + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanNukemaruN: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanNukemaruS: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanNukemaruNE: { + en: 'Bait Protean from Boss (${strat})', + }, + baitProteanNukemaruSE: { + en: 'Bait Protean from Boss (${strat})', + }, baitJump: { en: 'Bait Jump', }, @@ -3821,6 +3918,9 @@ const triggerSet: TriggerSet = { baitJumpBananaW: { en: 'Bait Jump ${strat}', }, + baitJumpNukemaruE: { + en: 'Bait Jump ${strat}', + }, projectionTetherDir: { en: '${dir} Cone Tether: ${mech1}', }, From 70b43e2797444ab71ae013b1643f26a609339ed6 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 5 Mar 2026 00:20:29 -0500 Subject: [PATCH 213/215] lint --- ui/raidboss/data/07-dt/raid/r12s.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 8e89ac66dbe..e386f40fefc 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3590,20 +3590,20 @@ const triggerSet: TriggerSet = { ? output.defamationOnYouDNSW!({ strat: output['dirWSW']!(), }) // West/WSW - : strat === 'nukemaru' - ? output.defamationOnYouNukemaruSW!({ - strat: output['dirSSW']!(), - }) // South/SSW + : strat === 'nukemaru' + ? output.defamationOnYouNukemaruSW!({ + strat: output['dirSSW']!(), + }) // South/SSW + : output.defamationOnYou!(), + }); + case 7: // Nukemaru Only + return output.manaBurstTether!({ + mech1: strat === 'nukemaru' + ? output.defamationOnYouNukemaruNW!({ + strat: output['dirNNW']!(), + }) // North/NNW : output.defamationOnYou!(), }); - case 7: // Nukemaru Only - return output.manaBurstTether!({ - mech1: strat === 'nukemaru' - ? output.defamationOnYouNukemaruNW!({ - strat: output['dirNNW']!(), - }) // North/NNW - : output.defamationOnYou!(), - }); } return output.manaBurstTether!({ mech1: output.defamationOnYou!(), From 3db81d7170b492527f60603f008519fa019e0065 Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 5 Mar 2026 00:21:49 -0500 Subject: [PATCH 214/215] fix typo --- 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 e386f40fefc..2de3f1b9694 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -3858,7 +3858,7 @@ const triggerSet: TriggerSet = { defamationOnYouNukemaruSW: { en: 'Defamation on YOU, Go ${strat}', }, - defamationOnYouNukermaruNW: { + defamationOnYouNukemaruNW: { en: 'Defamation on YOU, Go ${strat}', }, baitProtean: { From 7d419442a7f2653b4f88db8854130927bb5ae95d Mon Sep 17 00:00:00 2001 From: Legends0 Date: Thu, 5 Mar 2026 17:27:44 -0500 Subject: [PATCH 215/215] target/source x,y for double sobat instead of heading --- ui/raidboss/data/07-dt/raid/r12s.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/raidboss/data/07-dt/raid/r12s.ts b/ui/raidboss/data/07-dt/raid/r12s.ts index 2de3f1b9694..43d7fed4c0b 100644 --- a/ui/raidboss/data/07-dt/raid/r12s.ts +++ b/ui/raidboss/data/07-dt/raid/r12s.ts @@ -2712,8 +2712,12 @@ const triggerSet: TriggerSet = { 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); + const x = parseFloat(matches.x); + const y = parseFloat(matches.y); + const targetX = parseFloat(matches.targetX); + const targetY = parseFloat(matches.targetY); + // Boss snaps to the player position which could be different from heading at time of ability + const dirNum = Directions.xyTo16DirNum(targetX, targetY, x, y); const getNewDirNum = ( dirNum: number, id: string,