From 2c9412614f402728e03de6968470699c075286db Mon Sep 17 00:00:00 2001 From: ksh Date: Thu, 30 Oct 2025 18:40:44 +0900 Subject: [PATCH 1/4] Add Korean translations and improve encounter triggers for Meso Terminal and Necron EX - Added Korean translations for various zone names in zone_info.ts. - Updated trigger settings in pilgrims_traverse_the_final_verse.ts to improve alert timings and added Japanese translations. - Implemented Korean translations for Necron EX encounter abilities in necron-ex.ts. - Enhanced coverage tracking by including DeepDungeonExtras in coverage.ts and encounter_tools.ts. - Created new Meso Terminal encounter triggers and timeline in meso-terminal.ts and meso-terminal.txt. --- resources/zone_info.ts | 8 + .../pilgrims_traverse_the_final_verse.ts | 51 +- .../data/07-dt/dungeon/meso-terminal.ts | 472 ++++++++++++++++++ .../data/07-dt/dungeon/meso-terminal.txt | 180 +++++++ ui/raidboss/data/07-dt/trial/necron-ex.ts | 44 ++ util/coverage/coverage.ts | 1 + util/logtools/encounter_tools.ts | 1 + 7 files changed, 729 insertions(+), 28 deletions(-) create mode 100644 ui/raidboss/data/07-dt/dungeon/meso-terminal.ts create mode 100644 ui/raidboss/data/07-dt/dungeon/meso-terminal.txt diff --git a/resources/zone_info.ts b/resources/zone_info.ts index 705a38fa..29bfdfb3 100644 --- a/resources/zone_info.ts +++ b/resources/zone_info.ts @@ -10674,6 +10674,7 @@ const data: ZoneInfoType = { 'en': 'Vault Oneiron', 'fr': 'Le coffre d\'Oneiron', 'ja': '宝物庫 ボルト・オネイロン', + 'ko': '보물고 볼트 오네이론', }, 'offsetX': -100, 'offsetY': -100, @@ -10829,6 +10830,7 @@ const data: ZoneInfoType = { 'en': 'The Meso Terminal', 'fr': 'Le Mésoterminal', 'ja': '永久幽界 メインターミナル', + 'ko': '메인 터미널', }, 'offsetX': -132, 'offsetY': -113, @@ -10844,6 +10846,7 @@ const data: ZoneInfoType = { 'en': 'The Bayside Battleground', 'fr': 'Le Rivage redoutable', 'ja': 'ベイサイド・バトルグラウンド', + 'ko': '바닷가 전투장', }, 'offsetX': -100, 'offsetY': -100, @@ -10859,6 +10862,7 @@ const data: ZoneInfoType = { 'en': 'Crystalline Conflict (Custom Match - The Bayside Battleground)', 'fr': 'Crys. Conflict (partie perso. - Le Rivage redoutable)', 'ja': 'クリスタルコンフリクト(ベイサイド・バトルグラウンド:カスタムマッチ)', + 'ko': '크리스탈라인 컨플릭트(바닷가 전투장: 친선 경기)', }, 'offsetX': -100, 'offsetY': -100, @@ -10874,6 +10878,7 @@ const data: ZoneInfoType = { 'en': 'The Ageless Necropolis', 'fr': 'La Nécropole intemporelle', 'ja': '永遠の闇討滅戦', + 'ko': '영원한 어둠 토벌전', }, 'offsetX': -100, 'offsetY': -100, @@ -10889,6 +10894,7 @@ const data: ZoneInfoType = { 'en': 'The Minstrel\'s Ballad: Necron\'s Embrace', 'fr': 'La Nécropole intemporelle (extrême)', 'ja': '極永遠の闇討滅戦', + 'ko': '극 영원한 어둠 토벌전', }, 'offsetX': -100, 'offsetY': -100, @@ -10918,6 +10924,7 @@ const data: ZoneInfoType = { 'en': 'The Wreath of Snakes (Unreal)', 'fr': 'L\'Îlot des Amertumes (irréel)', 'ja': '幻青龍征魂戦', + 'ko': '환 청룡 토벌전', }, 'offsetX': -100, 'offsetY': -100, @@ -10949,6 +10956,7 @@ const data: ZoneInfoType = { 'en': 'San d\'Oria: The Second Walk', 'fr': 'San d\'Oria - La deuxième perambulation', 'ja': 'サンドリア:ザ・セカンドウォーク', + 'ko': '산도리아: 두 번째 반향세계', }, 'offsetX': -826, 'offsetY': -871, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts index 1e2d9181..0b1e0b05 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts @@ -50,13 +50,14 @@ const triggerSet: TriggerSet = { // raidwide + applies 11D2 Chains of Condemnation for 3s; heavy damage if moving type: 'StartsUsing', netRegex: { id: ['AC20', 'AC26'], source: 'Eminent Grief', capture: true }, - delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 5, - countdownSeconds: 5, - durationSeconds: 8, - alertText: (_data, _matches, outputs) => outputs.text!(), + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 3, + countdownSeconds: 3, + durationSeconds: 6, + alertText: (_data, _matches, output) => output.text!(), outputStrings: { text: { en: 'AoE + Stop Moving!', + ja: '全体攻撃 + 止まれ!', ko: '전체 공격 + 동작 그만!', }, }, @@ -80,6 +81,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Laser on YOU', + ja: '自分にレーザー', ko: '내게 레이저!', }, }, @@ -92,6 +94,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Avoid laser', + ja: 'レーザーを避ける', ko: '레이저 피해요', }, }, @@ -116,6 +119,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Get Light debuff', + ja: '光デバフを受ける', ko: '빛🟡 받아요', }, }, @@ -132,6 +136,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Get Dark debuff', + ja: '闇デバフを受ける', ko: '어둠⚫️ 받아요', }, }, @@ -148,34 +153,38 @@ const triggerSet: TriggerSet = { type: 'Ability', netRegex: { id: ['AC2A', 'AC2B', 'AC2C', 'AC2D'], source: 'Eminent Grief', capture: true }, durationSeconds: 10, - infoText: (_data, matches, outputs) => { + infoText: (_data, matches, output) => { const id = matches.id; switch (id) { case 'AC2A': - return outputs.text!({ safe: outputs.frontSafe!() }); + return output.text!({ safe: output.front!() }); case 'AC2B': - return outputs.text!({ safe: outputs.leftRightSafe!() }); + return output.text!({ safe: output.side!() }); case 'AC2C': - return outputs.text!({ safe: outputs.backSafe!() }); + return output.text!({ safe: output.back!() }); case 'AC2D': - return outputs.text!({ safe: outputs.leftRightSafe!() }); + return output.text!({ safe: output.side!() }); } }, outputStrings: { text: { en: '${safe}, for later', + ja: '${safe}、あとで', ko: '(나중에 ${safe})', }, - frontSafe: { + front: { en: 'Front safe', + ja: '前方が安置', ko: '앞쪽이 안전', }, - backSafe: { + back: { en: 'Back safe', + ja: '後方が安置', ko: '뒤쪽이 안전', }, - leftRightSafe: { + side: { en: 'Check safe side', + ja: '横の安置を確認', ko: '좌우 안전한 곳 찾아봐요', }, }, @@ -185,29 +194,15 @@ const triggerSet: TriggerSet = { type: 'StartsUsing', netRegex: { id: 'AC2F', source: 'Eminent Grief', capture: false }, suppressSeconds: 1, - alertText: (_data, _matches, outputs) => outputs.text!(), + alertText: (_data, _matches, output) => output.text!(), outputStrings: { text: { en: 'Avoid Exaflares', + ja: 'エクサフレアを避ける', ko: '엑사플레어 피해요', }, }, }, - { - id: 'PT 99 Eminent Grief 불의 알', - type: 'StartsUsing', - netRegex: { id: 'AC2F', source: 'Eminent Grief', capture: false }, - delaySeconds: 20, - durationSeconds: 4, - suppressSeconds: 1, - alertText: (_data, _matches, outputs) => outputs.text!(), - outputStrings: { - text: { - en: '(Spread, later)', - ko: '(곧 구슬, 흩어져요)', - }, - }, - }, ], timelineReplace: [ { diff --git a/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts b/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts new file mode 100644 index 00000000..adcae2fc --- /dev/null +++ b/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts @@ -0,0 +1,472 @@ +import Conditions from '../../../../../resources/conditions'; +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 { PluginCombatantState } from '../../../../../types/event'; +import { TriggerSet } from '../../../../../types/trigger'; + +export interface Data extends RaidbossData { + chirurgeonSpots: chirurgeonCoords[]; + playerExecutionerId?: string; + seenFirstStorm: boolean; + seenFirstBombardment: boolean; + safeTerror?: PluginCombatantState; + orthoKerauNorth?: boolean; + orthoKerauSouth?: boolean; + kerauDiagSafe: DirectionOutputIntercard[]; +} + +type chirurgeonCoords = { + x: number; + y: number; +}; + +// List out the safe spots for diagonals. +const diagPositiveSafe: DirectionOutputIntercard[] = ['dirNW', 'dirSE']; +const diagNegativeSafe: DirectionOutputIntercard[] = ['dirSW', 'dirNE']; + +const findNorthTerror = (terrors: PluginCombatantState[]): PluginCombatantState | undefined => { + return terrors.filter((terror) => { + // For all Bombardments, one of the north corners will have a single add present, + // at one of (-10, -13) (10, -13) (-17, -12) (17, -12). + // The corresponding -X point will have five adds surrounding it. + // We can consistently identify a north safespot by finding this single add. + + // Only X gets run through abs(), since we are only calling north safe. + const terX = Math.round(Math.abs(terror.PosX)); + const terY = Math.round(terror.PosY); + const x1 = 10; + const y1 = -13; + const x2 = 17; + const y2 = -12; + return (terX === x1 && terY === y1) || (terX === x2 && terY === y2); + })[0]; +}; + +const triggerSet: TriggerSet = { + id: 'themesoterminal', + zoneId: ZoneId.TheMesoTerminal, + timelineFile: 'meso-terminal.txt', + initData: () => { + return { + chirurgeonSpots: [], + playerExecutionerId: undefined, + seenFirstStorm: false, + seenFirstBombardment: false, + impressionActive: false, + safeTerror: undefined, + orthoKerauNorth: undefined, + orthoKerauSouth: undefined, + kerauDiagSafe: [], + }; + }, + triggers: [ + { + id: 'Meso Terminal Chirurgeon Medicine Field', + type: 'StartsUsing', + netRegex: { id: 'AB16', source: 'Chirurgeon General', capture: false }, + response: Responses.aoe(), + }, + { + id: 'Meso Terminal Chirurgeon Biochemical Front', + type: 'StartsUsing', + netRegex: { id: 'AB1A', source: 'Chirurgeon General', capture: false }, + response: Responses.getBehind(), + }, + { + // The origin for the Chirurgeon is (270,12). + // Aerosol can be cast at four cardinal points, + // each ten units along an axis from the origin. + // (270,22), (280,12), (270,2),(260,12) + id: 'Meso Terminal Chirurgeon Pungent Aerosol', + type: 'StartsUsingExtra', + netRegex: { id: 'AB1F', capture: true }, + infoText: (_data, matches, output) => { + const x = parseFloat(matches.x); + const y = parseFloat(matches.y); + const kbNum = Directions.xyTo4DirNum(x, y, 270, 12); + const safeDir = Directions.outputFromCardinalNum(kbNum); + return output.knockbackFrom!({ dir: output[safeDir]!() }); + }, + outputStrings: { + knockbackFrom: { + en: 'Knockback from ${dir}', + ko: '${dir}에서 넉백', + }, + dirN: Outputs.north, + dirE: Outputs.east, + dirS: Outputs.south, + dirW: Outputs.west, + unknown: Outputs.unknown, + }, + }, + { + // AB1E is the big Sterile Sphere + // AB1D is small + id: 'Meso Terminal Chirurgeon Sterile Sphere Collect', + type: 'StartsUsingExtra', + netRegex: { id: 'AB1D', capture: true }, + run: (data, matches) => { + const location = { + x: Math.round(parseFloat(matches.x)), + y: Math.round(parseFloat(matches.y)), + }; + data.chirurgeonSpots.push(location); + }, + }, + { + id: 'Meso Terminal Chirurgeon Sterile Sphere Call', + type: 'StartsUsing', + netRegex: { id: 'AB1D', source: 'Chirurgeon General', capture: false }, + delaySeconds: 1, + suppressSeconds: 1, + alertText: (data, _matches, output) => { + if (!data.chirurgeonSpots[0] || !data.chirurgeonSpots[1]) + return; + const spot1 = data.chirurgeonSpots[0]; + const spot2 = data.chirurgeonSpots[1]; + // Both spheres east or both west. + // X value under 270 means east safe. + if (spot1.x === spot2.x) { + if (spot1.x < 270) + return output.goEast!(); + return output.goWest!(); + } + // Both spheres north or south. + // Y values increase from north to south. + // Y value over 12 means north safe. + if (spot1.y === spot2.y) { + if (spot1.y > 12) + return output.goNorth!(); + return output.goSouth!(); + } + return output.unknown!(); + }, + run: (data) => data.chirurgeonSpots = [], + outputStrings: { + goNorth: Outputs.north, + goEast: Outputs.east, + goSouth: Outputs.south, + goWest: Outputs.west, + unknown: Outputs.unknown, + }, + }, + { + id: 'Meso Terminal Chirurgeon Concentrated Dose', + type: 'StartsUsing', + netRegex: { id: 'AB17', source: 'Chirurgeon General', capture: true }, + response: Responses.tankBuster(), + }, + { + id: 'Meso Terminal Chirurgeon Poison', + type: 'GainsEffect', + netRegex: { effectId: '838', source: 'Chirurgeon General', capture: true }, + condition: (data) => data.CanCleanse(), + infoText: (_data, matches, output) => output.cleanse!({ target: matches.target }), + outputStrings: { + cleanse: { + en: 'Cleanse ${target}', + ko: '에스나: ${target}', + }, + }, + }, + { + id: 'Meso Terminal Executioners Shackles Of Fate Tracking', + type: 'StartsUsing', + netRegex: { id: 'AA3D', capture: true }, + condition: Conditions.targetIsYou(), + run: (data, matches) => data.playerExecutionerId = matches.sourceId, + }, + { + id: 'Meso Terminal Executioners Head-Splitting Roar', + type: 'StartsUsing', + netRegex: { id: 'AA3B', source: 'Hooded Headsman', capture: false }, + response: Responses.aoe(), + }, + { + id: 'Meso Terminal Executioners Chopping Block', + type: 'StartsUsing', + netRegex: { id: 'AA4B', capture: true }, + condition: (data, matches) => data.playerExecutionerId === matches.sourceId, + response: Responses.getOut(), + }, + { + id: 'Meso Terminal Executioners Execution Wheel', + type: 'StartsUsing', + netRegex: { id: 'AA4C', capture: true }, + condition: (data, matches) => data.playerExecutionerId === matches.sourceId, + response: Responses.getIn(), + }, + { + id: 'Meso Terminal Executioners Flaying Flail', + type: 'Ability', + netRegex: { id: 'AA47', capture: true }, + condition: (data, matches) => data.playerExecutionerId === matches.sourceId, + delaySeconds: 1, // Wait for visuals + infoText: (_data, _matches, output) => output.avoidFlails!(), + outputStrings: { + avoidFlails: { + en: 'Away from flails', + ko: '플레일 피해요', + }, + }, + }, + { + id: 'Meso Terminal Executioners Hellmaker Adds', + type: 'AddedCombatant', + netRegex: { npcBaseId: '48D2', capture: false }, + condition: (data) => data.role === 'dps', + suppressSeconds: 1, + response: Responses.killAdds(), + }, + { + id: 'Meso Terminal Executioners Will Breaker', + type: 'StartsUsing', + netRegex: { id: 'AF38', capture: true }, + condition: (data, matches) => data.playerExecutionerId === matches.sourceId, + response: Responses.interruptIfPossible(), + }, + { + id: 'Meso Terminal Executioners Relentless Torment', + type: 'StartsUsing', + netRegex: { id: 'AA45', capture: true }, + condition: (data, matches) => data.playerExecutionerId === matches.sourceId, + response: Responses.tankBuster(), + }, + { + id: 'Meso Terminal Executioners Death Penalty', + type: 'GainsEffect', + netRegex: { effectId: '11F2', capture: true }, + condition: (data) => data.CanCleanse(), + alarmText: (_data, matches, output) => output.cleanseDoom!({ target: matches.target }), + outputStrings: { + cleanseDoom: { + en: 'Cleanse ${target}', + ko: '에스나: ${target}', + }, + }, + }, + { + id: 'Meso Terminal Immortal Remains Recollection', + type: 'StartsUsing', + netRegex: { id: 'AB31', source: 'Immortal Remains', capture: false }, + response: Responses.aoe(), + }, + { + id: 'Meso Terminal Immortal Remains Memory Of The Storm', + type: 'StartsUsing', + netRegex: { id: 'AB2D', source: 'Immortal Remains', capture: false }, + response: Responses.stackMarker(), + run: (data) => data.seenFirstStorm = true, + }, + { + id: 'Meso Terminal Immortal Remains Memory Of The Pyre', + type: 'StartsUsing', + netRegex: { id: 'AB30', source: 'Immortal Remains', capture: true }, + response: Responses.tankBuster(), + }, + { + id: 'Meso Terminal Immortal Remains Turmoil Left', + type: 'Ability', + netRegex: { id: 'AB26', source: 'Immortal Remains', capture: false }, + response: Responses.goEast(), + }, + { + id: 'Meso Terminal Immortal Remains Turmoil Right', + type: 'Ability', + netRegex: { id: 'AB27', source: 'Immortal Remains', capture: false }, + response: Responses.goWest(), + }, + + // There aren't a lot of good indications where the Bombardments will go. + // The mechanic places the Preserved Terror adds where the tethers are, + // then does a very short Bombardment cast on the add locations. + // If there is one add, it's a small circle, AB23. + // If there are five adds, it's a large circle, AB24, + // centered equidistant from its five adds. + // On the second and later Bombardments, + // we can trigger off the AB29 Impression cast, but we have nothing like that for the first. + // The best case for finding the locations is to find all the Preserved Terrors, + // then filter down which one is in a safe position in front. + { + id: 'Meso Terminal Immortal Remains First Bombardment Collect', + type: 'GainsEffect', + netRegex: { effectId: '9F8', capture: false }, + // The Preserved Terror adds are used for more mechanics than just Bombardment. + // Unfortunately, we don't have any good way to separate out + // which ones are used for which mechanics. + // The tethers for Bombardment are also used on Electray + // and Keraunography, so we have to be very careful how we find the adds. + condition: (data) => { + // The first Memory of the Storm cast immediately precedes Bombardment. + return data.seenFirstStorm && !data.seenFirstBombardment; + }, + suppressSeconds: 1, + promise: async (data) => { + const callData = await callOverlayHandler({ + call: 'getCombatants', + }); + if (!callData.combatants.length) + return; + const terrors = callData.combatants.filter((actor) => actor.BNpcID === 18624); + data.safeTerror = findNorthTerror(terrors); + }, + }, + { + id: 'Meso Terminal Immortal Remains Bombardment No Knockback', + type: 'GainsEffect', + netRegex: { effectId: '9F8', capture: false }, + condition: (data) => data.seenFirstStorm && !data.seenFirstBombardment, + delaySeconds: 1, + suppressSeconds: 1, + alertText: (data, _matches, output) => { + if (data.safeTerror === undefined) + return output.unknown!(); + const safeDir = data.safeTerror.PosX < 0 ? 'west' : 'east'; + return output.staticBombardment!({ safe: output[safeDir]!() }); + }, + run: (data) => { + data.seenFirstBombardment = true; + data.safeTerror = undefined; + }, + outputStrings: { + staticBombardment: { + en: 'Go ${safe}; Avoid small AoE', + ko: '${safe}으로 가욧! 작은 장판은 피해요', + }, + west: Outputs.west, + east: Outputs.east, + unknown: Outputs.unknown, + }, + }, + { + id: 'Meso Terminal Immortal Remains Bombardment Knockback', + type: 'Ability', + netRegex: { id: 'AB29', source: 'Immortal Remains', capture: false }, // Impression + condition: (data) => data.seenFirstBombardment, + delaySeconds: 1, + suppressSeconds: 1, + promise: async (data) => { + const callData = await callOverlayHandler({ + call: 'getCombatants', + }); + if (!callData.combatants.length) + return; + const terrors = callData.combatants.filter((actor) => actor.BNpcID === 18624); + data.safeTerror = findNorthTerror(terrors); + }, + alertText: (data, _matches, output) => { + if (data.safeTerror === undefined) + return output.unknown!(); + const safeDir = data.safeTerror.PosX < 0 ? 'northwest' : 'northeast'; + return output.knockbackBombardment!({ safe: output[safeDir]!() }); + }, + run: (data) => { + data.safeTerror = undefined; + }, + outputStrings: { + knockbackBombardment: { + en: 'Knockback to ${safe}; Avoid AoE', + ko: '${safe}으로 넉백! 장판은 피해요', + }, + northwest: Outputs.northwest, + northeast: Outputs.northeast, + unknown: Outputs.unknown, + }, + }, + { + // One Keraunography laser is always diagonal, + // one is always orthogonal. + // In all cases but front horizontal, + // orthogonal lasers leave at least a small uptime safespot. + id: 'Meso Terminal Immortal Remains Keraunography Collect', + type: 'StartsUsingExtra', + netRegex: { id: 'AB25', capture: true }, + run: (data, matches) => { + const headingNum = Directions.hdgTo8DirNum(parseFloat(matches.heading)); + // Odd heading numbers are diagonal. + if (headingNum % 2 === 1) { + // Check which diagonal we're working with. + // 1 and 5 are equivalent, as are 3 and 7. + // In practice, only 5 and 3 will ever be seen, + // since the diagonals always originate from the north end of the arena. + const diagIsPositive = (headingNum + 4) % 4 === 1; + const safeDiagonalSpots = diagIsPositive ? diagPositiveSafe : diagNegativeSafe; + data.kerauDiagSafe = safeDiagonalSpots; + } else if (headingNum % 4 === 0) { // Vertical + // As with the diagonals, in practice we will only ever see a 0 heading number. + data.orthoKerauNorth = false; + data.orthoKerauSouth = false; + } else { // Horizontal + // It is possible to see both 2 and 6 in practice, + // but it doesn't matter much. + const isNorth = parseFloat(matches.y) < 0; + data.orthoKerauNorth = isNorth; + data.orthoKerauSouth = !isNorth; + } + }, + }, + { + id: 'Meso Terminal Immortal Remains Keraunography Call', + type: 'StartsUsing', + netRegex: { id: 'AB25', source: 'Immortal Remains', capture: false }, + delaySeconds: 0.1, + suppressSeconds: 1, + alertText: (data, _matches, output) => { + if (data.orthoKerauNorth === undefined || data.orthoKerauSouth === undefined) + return; + if (data.orthoKerauNorth) { + // If the orthogonal laser is horizontal north, + // the only safespots are outside the hitbox, + // but still close enough to be handled with a GCD roll. + const safeDir = data.kerauDiagSafe.filter((dir) => dir === 'dirSW' || dir === 'dirSE')[0]; + if (safeDir !== undefined) + return output[safeDir]!(); + return output.unknown!(); + } else if (data.orthoKerauSouth) { + // If the orthogonal laser is horizontal south, + // the safespot is completely free in front. + const safeDir = data.kerauDiagSafe.filter((dir) => dir === 'dirNW' || dir === 'dirNE')[0]; + if (safeDir !== undefined) + return output[safeDir]!(); + return output.unknown!(); + } + + // If the orthogonal laser is vertical, + // there is a tiny safespot in front, + // as well as a large one on the same side south of the diagonal, + // just outside melee range. + const safeNW = data.kerauDiagSafe.includes('dirSW'); + if (safeNW) + return output.leanLeft!(); + return output.leanRight!(); + }, + run: (data) => { + data.kerauDiagSafe = []; + data.orthoKerauNorth = undefined; + data.orthoKerauSouth = undefined; + }, + outputStrings: { + leanLeft: { + en: 'Front + Lean Left; or Southwest', + ko: '앞 + 왼쪽으로 살짝 또는 남서쪽', + }, + leanRight: { + en: 'Front + Lean Right; or Southeast', + ko: '앞 + 오른쪽으로 살짝 또는 남동쪽', + }, + dirNW: Outputs.northwest, + dirNE: Outputs.northeast, + dirSW: Outputs.southwest, + dirSE: Outputs.southeast, + unknown: Outputs.unknown, + }, + }, + ], + timelineReplace: [], +}; + +export default triggerSet; diff --git a/ui/raidboss/data/07-dt/dungeon/meso-terminal.txt b/ui/raidboss/data/07-dt/dungeon/meso-terminal.txt new file mode 100644 index 00000000..40f711aa --- /dev/null +++ b/ui/raidboss/data/07-dt/dungeon/meso-terminal.txt @@ -0,0 +1,180 @@ +### THE MESO TERMINAL +# ZoneId: 1292 + +hideall "--Reset--" +hideall "--sync--" + +# .*is no longer sealed +0.0 "--Reset--" SystemLogMessage { id: "7DE" } window 0,100000 jump 0 + +#~~~~~~~~~~~~~~~~~~~~# +# Chirurgeon General # +#~~~~~~~~~~~~~~~~~~~~# +# -ii ACD6 + +# The Triage Module will be sealed off +1000.0 "--sync--" SystemLogMessage { id: "7DC", param1: "1496" } window 1000,1 +1009.1 "Medicine Field" Ability { id: "AB16", source: "Chirurgeon General" } +1016.5 "No Man's Land" Ability { id: "AB1C", source: "Chirurgeon General" } +1027.1 "Pungent Aerosol" Ability { id: "AB1F", source: "Chirurgeon General" } +1035.1 "Sterile Sphere" Ability { id: "AB1D", source: "Chirurgeon General" } +1041.7 "Biochemical Front" Ability { id: "AB1A", source: "Chirurgeon General" } +1043.8 "No Man's Land" Ability { id: "AB1C", source: "Chirurgeon General" } +1051.8 "Sensory Deprivation" Ability { id: "AB15", source: "Chirurgeon General" } +1063.2 "Pungent Aerosol" Ability { id: "AB1F", source: "Chirurgeon General" } +1069.9 "Concentrated Dose" Ability { id: "AB17", source: "Chirurgeon General" } + +1072.1 label "chirurgeonLoop" +1072.1 "No Man's Land" Ability { id: "AB1C", source: "Chirurgeon General" } +1077.1 "Sensory Deprivation" Ability { id: "AB15", source: "Chirurgeon General" } +1086.7 "Sterile Sphere/Pungent Aerosol" Ability { id: ["AB1D", "AB1E", "AB1F"], source: "Chirurgeon General" } +1094.7 "Pungent Aerosol/Sterile Sphere" Ability { id: ["AB1D", "AB1E", "AB1F"], source: "Chirurgeon General" } +1101.3 "Biochemical Front" Ability { id: "AB1A", source: "Chirurgeon General" } +1108.3 "Medicine Field" Ability { id: "AB16", source: "Chirurgeon General" } +1118.3 "Concentrated Dose" Ability { id: "AB17", source: "Chirurgeon General" } + +1123.6 "No Man's Land" Ability { id: "AB1C", source: "Chirurgeon General" } forcejump "chirurgeonLoop" + +# ALL ENCOUNTER ABILITIES +# AB15 Sensory Deprivation: Cloaks mechanic indicators +# AB16 Medicine Field: raidwide +# AB17 Concentrated Dose: tank buster +# AB1A Biochemical Front: 180-degree frontal cleave +# AB1C No Man's Land: sets up sphere and aerosol mechanics +# AB1D Sterile Sphere: small sphere explosion +# AB1E Sterile Sphere: large sphere explosion +# AB1F Pungent Aerosol: knockback +# ACD6 --sync--: auto-attack + +#~~~~~~~~~~~~~~# +# Executioners # +#~~~~~~~~~~~~~~# + +# -ii AA3A AA3C AA3D AA4A AA4E AA4F AA50 + +# The Executioner timeline is "best-effort" and will quickly +# desync depending on player or enemy deaths. + +# The Public Forum will be sealed off +2000.0 "--sync--" SystemLogMessage { id: "7DC", param1: "1497" } window 2000,1 +2003.2 "Lawless Pursuit" Ability { id: "AA39" } +2011.8 "Head-splitting Roar" Ability { id: "AA3B", source: "Hooded Headsman" } +2022.5 "Shackles of Fate" #Ability { id: "AA3E" } +2027.4 "Dismemberment (cast)" Ability { id: "AA42" } +2034.3 "Dismemberment 1" Ability { id: "AA43" } +2036.7 "Peal of Judgment (castbar)" Ability { id: "AA49" } +2037.4 "Dismemberment 2" Ability { id: "AA43" } +2042.8 "Peal of Judgment (active)" duration 7 #Ability { id: "AA4A" } +2045.8 "Chopping Block/Execution Wheel" Ability { id: ["AA4B", "AA4C"] } +2050.7 "Flaying Flail (castbar)" Ability { id: "AA47" } +2056.6 "Flaying Flail" Ability { id: "AA48" } +2058.5 "--sync--" StartsUsing { id: "AF38", source: "Pale Headsman" } # Will Breaker +2061.0 "Peal of Judgment" Ability { id: "AA49" } +2063.0 "Death Penalty" Ability { id: "AA44" } +2063.0 "--hellmaker adds--" +2063.9 "Peal of Judgment (active)" duration 7 #Ability { id: "AA4A" } +2065.0 "Will Breaker?" #Ability { id: "AF38", source: "Pale Headsman" } +2067.2 "Flaying Flail (castbar)" Ability { id: "AA47" } window 10,5 +2069.0 "Relentless Torment" Ability { id: "AA45" } +2071.8 "Flaying Flail" Ability { id: "AA48" } + +2081.8 label "executionerLoop" +2081.8 "Serial Torture" Ability { id: "AA4D" } +2088.6 "Dismemberment" Ability { id: "AA43" } +2090.6 "Flaying Flail" Ability { id: "AA48" } +2092.6 "Dismemberment" Ability { id: "AA43" } +2094.3 "Chopping Block/Execution Wheel" Ability { id: ["AA4B", "AA4C"] } +2104.8 "Head-splitting Roar" Ability { id: "AA3B", source: "Hooded Headsman" } +2114.5 "Peal of Judgment" #Ability { id: "AA49", source: "Pestilent Headsman" } +2120.6 "Chopping Block/Execution Wheel" Ability { id: ["AA4B", "AA4C"] } window 10,5 +2121.3 "--hellmaker adds--" +2122.2 "Peal of Judgment (active)" #Ability { id: "AA4A", source: "Bloody Headsman" } +2124.2 "Will Breaker?" #Ability { id: "AF38", source: "Pale Headsman" } +2131.2 "Death Penalty" Ability { id: "AA44", source: "Bloody Headsman" } window 30,10 + +2143.0 "Serial Torture" Ability { id: "AA4D" } forcejump "executionerLoop" + + + +# ALL ENCOUNTER ABILITIES +# AA39 Lawless Pursuit: Tether targeted player +# AA3A Head-splitting Roar: raidwide castbar +# AA3B Head-splitting Roar: raidwide (invisible add) +# AA3C --sync--: reposition in own circle +# AA3D Shackles of Fate: chain castbar +# AA3E Shackles of Fate: chain and draw player in +# AA42 Dismemberment +# AA43 Dismemberment +# AA44 Death Penalty +# AA45 Relentless Torment +# AA46 Relentless Torment +# AA47 Flaying Flail: triangle of circle AoEs castbar +# AA48 Flaying Flail: triangle of circle AoEs +# AA49 Peal of Judgment: lightning lines castbar +# AA4A Peal of Judgment: lightning lines +# AA4B Chopping Block: chariot AoE +# AA4C Execution Wheel: dynamo AoE +# AA4D Serial Torture +# AA4E --sync--: auto-attack +# AA4F --sync--: auto-attack +# AA50 --sync--: auto-attack + +#~~~~~~~~~~~~~~~~~~# +# Immortal Remains # +#~~~~~~~~~~~~~~~~~~# + +# -ii AB32 AB2E AB24 AB25 AB2B AB30 + +# Non-Volatile Memory will be sealed off +3000.0 "--sync--" SystemLogMessage { id: "7DC", param1: "1498" } window 3000,1 +3010.1 "Recollection" Ability { id: "AB31", source: "Immortal Remains" } +3019.9 "Memento" Ability { id: "AB21", source: "Immortal Remains" } +3039.3 "Electray 1" #Ability { id: "AB22", source: "Bygone Aerostat" } +3042.3 "Electray 2" #Ability { id: "AB22", source: "Bygone Aerostat" } +3047.1 "Memory of the Storm" Ability { id: "AB2D", source: "Immortal Remains" } +3057.2 "Memento" Ability { id: "AB21", source: "Immortal Remains" } +3073.3 "Bombardment" Ability { id: "AB23", source: "Immortal Remains" } +3075.3 "--sync--" Ability { id: ["AB26", "AB27"], source: "Immortal Remains" } # Turmoil +3079.7 "Turmoil" Ability { id: "AB28", source: "Immortal Remains" } +3088.5 "--sync--" Ability { id: "AB29", source: "Immortal Remains" } # Impression tethers +3093.5 "Impression" Ability { id: "AB2A", source: "Immortal Remains" } +3096.5 "Bombardment" Ability { id: "AB23", source: "Immortal Remains" } +3105.6 "Memory of the Pyre" Ability { id: "AB2F", source: "Immortal Remains" } +3114.7 "Memento" Ability { id: "AB21", source: "Immortal Remains" } +3126.8 "Keraunography" Ability { id: "B078", source: "Immortal Remains" } + +3141.8 label "remainsLoop" +3141.8 "Keraunography" Ability { id: "B078", source: "Immortal Remains" } +3148.0 "Electray 1" Ability { id: "AB22", source: "Bygone Aerostat" } +3151.0 "Electray 2" Ability { id: "AB22", source: "Bygone Aerostat" } +3153.8 "--sync--" Ability { id: ["AB26", "AB27"], source: "Immortal Remains" } # Turmoil +3158.2 "Turmoil" Ability { id: "AB28", source: "Immortal Remains" } +3171.9 "Keraunography" Ability { id: "B078", source: "Immortal Remains" } +3179.9 "--sync--" Ability { id: "AB29", source: "Immortal Remains" } # Impression tethers +3184.9 "Impression" Ability { id: "AB2A", source: "Immortal Remains" } +3187.9 "Bombardment" Ability { id: "AB23", source: "Immortal Remains" } +3197.0 "Memory of the Storm" Ability { id: "AB2D", source: "Immortal Remains" } +3206.1 "Memory of the Pyre" Ability { id: "AB2F", source: "Immortal Remains" } +3216.2 "Recollection" Ability { id: "AB31", source: "Immortal Remains" } + +3234.0 "Keraunography" Ability { id: "B078", source: "Immortal Remains" } forcejump "remainsLoop" + +# ALL ENCOUNTER ABILITIES +# AB21 Memento: Setup cast for Electray/Bombardment/Keraunography +# AB22 Electray: Cross laser AoEs +# AB23 Bombardment: Small red circle AoE +# AB24 Bombardment: Large red circle AoE +# AB25 Keraunography: Castbar for purple lasers +# AB26 Turmoil: Half-arena cleave, left side castbar +# AB27 Turmoil: Half-arena cleave, right side castbar +# AB28 Turmoil: Half-arena cleave, both sides +# AB29 Impression: Blue knockback circle display +# AB2A Impression: Blue knockback circle failure (standing inside) +# AB2B Impression: Blue knockback circle resolve +# AB2D Memory of the Storm: Stack laser self-cast +# AB2E Memory of the Storm: Stack laser (instant) +# AB2F Memory of the Pyre: Tank buster self-cast +# AB30 Memory of the Pyre: Tank buster +# AB31 Recollection: Raidwide +# AB32 --sync--: Auto-attack +# B078 Keraunography: Large purple lasers diff --git a/ui/raidboss/data/07-dt/trial/necron-ex.ts b/ui/raidboss/data/07-dt/trial/necron-ex.ts index 61a04756..fbe1e5c8 100644 --- a/ui/raidboss/data/07-dt/trial/necron-ex.ts +++ b/ui/raidboss/data/07-dt/trial/necron-ex.ts @@ -759,6 +759,50 @@ const triggerSet: TriggerSet = { 'Twofold Blight': '青之二重波', }, }, + { + 'locale': 'ko', + 'replaceSync': { + 'Azure Aether': '푸른 영혼 덩어리', + 'Beckoning Hands': '죽음으로 이끄는 손', + 'Icy Hands': '죽음을 부르는 손', + 'Necron': '영원한 어둠', + }, + 'replaceText': { + '\\(cast\\)': '(시전)', + '\\(damage\\)': '(피해)', + '\\(intercards\\)': '(대각)', + '\\(lines?\\)': '(직선)', + '\\(puddles?\\)': '(장판)', + '\\(spread\\)': '(산개)', + '\\(tower\\)': '(탑)', + 'Aetherblight': '푸른 파동', + 'Blue Shockwave': '푸른 충격', + 'Choking Grasp': '짓누르기', + 'Circle of Lives': '푸른 고리 파동', + 'Cold Grip': '검은 죽음의 팔', + 'Crop Rotation': '영혼 순환', + 'Darkness of Eternity': '영원한 어둠', + 'Existential Dread': '어두운 기류', + 'Fear of Death': '죽음에 대한 공포', + 'Fourfold Blight': '푸른 사중 파동', + 'Grand Cross': '그랜드크로스', + 'Inevitability': '죽음의 범람', + 'Mass Macabre': '집단 공황', + 'Memento Mori': '메멘토 모리', + 'Muted Struggle': '찍어누르기', + 'Neutron Ring': '중성자 고리', + 'Relentless Reaping': '연속 푸른 영혼', + 'Shock(?!wave)': '방전', + '(? = [ ContentType.ChaoticAllianceRaid, + ContentType.DeepDungeonExtras, ContentType.DeepDungeons, ContentType.Dungeons, ContentType.Eureka, From 16a1a6755f5447030ad6a3da57485be3d0390df8 Mon Sep 17 00:00:00 2001 From: ksh Date: Sun, 2 Nov 2025 12:48:16 +0900 Subject: [PATCH 2/4] Add triggers for Pilgrim's Traverse Stones (1-70) and Meso Terminal dungeon - Implemented triggers for mobs and bosses in Pilgrim's Traverse Stones from levels 1 to 70, including mechanics for various encounters. - Added translations for specific responses in Meso Terminal dungeon. - Introduced new content type for Deep Dungeon Extras in coverage utility. - Created initial trigger sets for Pilgrim's Traverse Stones 01-10, 11-20, 21-30, 31-40. - Enhanced existing triggers with additional output strings and conditions for better player guidance. --- plugin/CactbotEventSource/FFXIVProcessKo.cs | 21 +- .../the_palace_of_the_dead_general.ts | 1 + .../deepdungeon/heaven-on-high_general.ts | 1 + .../deepdungeon/eureka_orthos_floors_51-60.ts | 60 ++--- .../deepdungeon/eureka_orthos_general.ts | 1 + .../deepdungeon/pilgrims_traverse_general.ts | 54 ++++ .../pilgrims_traverse_stones_01-10.ts | 107 ++++++++ .../pilgrims_traverse_stones_11-20.ts | 105 ++++++++ .../pilgrims_traverse_stones_21-30.ts | 173 +++++++++++++ .../pilgrims_traverse_stones_31-40.ts | 120 +++++++++ .../pilgrims_traverse_stones_41-50.ts | 68 ++++- .../pilgrims_traverse_stones_51-60.ts | 86 +++++++ .../pilgrims_traverse_stones_61-70.ts | 131 ++++++++++ .../data/07-dt/dungeon/meso-terminal.ts | 232 +++++++++++++++++- util/coverage/coverage.ts | 8 + 15 files changed, 1118 insertions(+), 50 deletions(-) create mode 100644 ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts create mode 100644 ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts create mode 100644 ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts create mode 100644 ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts diff --git a/plugin/CactbotEventSource/FFXIVProcessKo.cs b/plugin/CactbotEventSource/FFXIVProcessKo.cs index 8f06cf84..936cc507 100644 --- a/plugin/CactbotEventSource/FFXIVProcessKo.cs +++ b/plugin/CactbotEventSource/FFXIVProcessKo.cs @@ -8,7 +8,7 @@ namespace Cactbot { public class FFXIVProcessKo : FFXIVProcess { - // Last updated for FFXIV 7.2 + // Last updated for FFXIV 7.3 // Per aers/FFXIVClientStructs, what we call EntityMemory is actually: // Client::Game::Character::Character (0x22E0) // Client::Game::Object::GameObject (0x190) @@ -25,28 +25,28 @@ public unsafe struct EntityMemory { [FieldOffset(0x30)] public fixed byte Name[nameBytes]; - [FieldOffset(0x74)] + [FieldOffset(0x78)] public uint id; - [FieldOffset(0x8C)] + [FieldOffset(0x90)] public EntityType type; - [FieldOffset(0x92)] + [FieldOffset(0x96)] public ushort distance; - [FieldOffset(0xA0)] + [FieldOffset(0xB0)] public Single pos_x; - [FieldOffset(0xA4)] + [FieldOffset(0xB4)] public Single pos_z; - [FieldOffset(0xA8)] + [FieldOffset(0xB8)] public Single pos_y; - [FieldOffset(0xB0)] + [FieldOffset(0xC0)] public Single rotation; - [FieldOffset(0x190)] + [FieldOffset(0x1A0)] public CharacterDetails charDetails; } @@ -106,7 +106,8 @@ public FFXIVProcessKo(ILogger logger) : base(logger) { } // In combat boolean. // This address is written to by "mov [rax+rcx],bl" and has three readers. // This reader is "cmp byte ptr [ffxiv_dx11.exe+????????],00 { (0),0 }" - private static String kInCombatSignature = "803D??????????74??488B03488BCBFF50"; + // Updated in 7.3, signature was no longer unique, include the preceeding "jz LAB_?????????" + private static String kInCombatSignature = "74??803D??????????74??488B03488BCBFF50"; private static int kInCombatSignatureOffset = -15; private static bool kInCombatSignatureRIP = true; // Because this line is a cmp byte line, the signature is not at the end of the line. diff --git a/ui/raidboss/data/03-hw/deepdungeon/the_palace_of_the_dead_general.ts b/ui/raidboss/data/03-hw/deepdungeon/the_palace_of_the_dead_general.ts index 4011e5ad..cad55177 100644 --- a/ui/raidboss/data/03-hw/deepdungeon/the_palace_of_the_dead_general.ts +++ b/ui/raidboss/data/03-hw/deepdungeon/the_palace_of_the_dead_general.ts @@ -52,6 +52,7 @@ const triggerSet: TriggerSet = { // TODO: some Mimics may spawn after transference between floors and get called early before being found type: 'AddedCombatant', netRegex: { npcNameId: '2566', capture: false }, + suppressSeconds: 1, infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { diff --git a/ui/raidboss/data/04-sb/deepdungeon/heaven-on-high_general.ts b/ui/raidboss/data/04-sb/deepdungeon/heaven-on-high_general.ts index 3a90d4f4..868d64f3 100644 --- a/ui/raidboss/data/04-sb/deepdungeon/heaven-on-high_general.ts +++ b/ui/raidboss/data/04-sb/deepdungeon/heaven-on-high_general.ts @@ -41,6 +41,7 @@ const triggerSet: TriggerSet = { // TODO: some Quivering Coffers may spawn after transference between floors and get called early before being found type: 'AddedCombatant', netRegex: { npcNameId: '739[2-4]', capture: false }, + suppressSeconds: 1, infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { diff --git a/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts b/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts index 5a725186..06c12051 100644 --- a/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts +++ b/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts @@ -1,5 +1,7 @@ import Conditions from '../../../../../resources/conditions'; +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'; @@ -118,7 +120,7 @@ const triggerSet: TriggerSet = { }, { id: 'EO 51-60 Servomechanical Minotaur 16 Octuple Swipe Cleanup', - type: 'StartsUsing', + type: 'Ability', netRegex: { id: '7C80', source: 'Servomechanical Minotaur 16', capture: false }, run: (data) => { delete data.octupleSwipes; @@ -127,63 +129,49 @@ const triggerSet: TriggerSet = { }, { id: 'EO 51-60 Servomechanical Minotaur 16 Octuple Swipe', - type: 'Ability', - netRegex: { id: '7C7B', source: 'Servomechanical Minotaur 16' }, + type: 'StartsUsingExtra', + netRegex: { id: '7C7B', capture: true }, condition: (data) => !data.calledOctupleSwipes, - durationSeconds: 10, + durationSeconds: 18, alertText: (data, matches, output) => { - // convert the heading into 0=N, 1=E, 2=S, 3=W - const heading = Math.round(2 - 2 * parseFloat(matches.heading) / Math.PI) % 4; - + const heading = Directions.hdgTo4DirNum(parseFloat(matches.heading)); data.octupleSwipes ??= []; data.octupleSwipes.push(heading); - if (data.octupleSwipes.length <= 4) + if (data.octupleSwipes.length < 5) return; data.calledOctupleSwipes = true; if (data.octupleSwipes[0] === data.octupleSwipes[4]) // swipe order is Front > Back > Right > Left > Front > Back > Right > Left - return output.text!({ - dir1: output.left!(), - dir2: output.front!(), - dir3: output.left!(), - dir4: output.front!(), - }); + // dodge order is Left > Front > Front > Front > Left > Front > Front > Front + return output.repeat!({ left: output.left!(), front: output.front!() }); if (data.octupleSwipes[3] === data.octupleSwipes[4]) // swipe order is Front > Back > Right > Left > Left > Right > Back > Front - return output.text!({ - dir1: output.left!(), - dir2: output.front!(), - dir3: output.front!(), - dir4: output.left!(), - }); + // dodge order is Left > Front > Front > Front > Front > Front > Front > Left + return output.rewind!({ left: output.left!(), front: output.front!() }); // something went wrong data.calledOctupleSwipes = false; - return; + return output.avoid!(); }, outputStrings: { - front: { - en: 'Front', - ja: '前', - ko: '🡹', + repeat: { + en: '${left} => ${front} x3 => ${left} => ${front} x3', + ko: '${left} 🔜 ${front}x3 🔜 ${left} 🔜 ${front}x3', }, - left: { - en: 'Left', - ja: '左へ', - ko: '🡸', + rewind: { + en: '${left} => ${front} x6 => ${left}', + ko: '${left} 🔜 ${front}x6 🔜 ${left}', }, - text: { - en: '${dir1} > ${dir2} > ${dir3} > ${dir4}', - de: '${dir1} > ${dir2} > ${dir3} > ${dir4}', - fr: '${dir1} > ${dir2} > ${dir3} > ${dir4}', - ja: '${dir1} > ${dir2} > ${dir3} > ${dir4}', - cn: '${dir1} > ${dir2} > ${dir3} > ${dir4}', - ko: '${dir1} ${dir2} ${dir3} ${dir4}', + avoid: { + en: 'Avoid swipes x8', + ko: '스와이프x8 피해요!', }, + left: Outputs.left, + front: Outputs.front, }, }, { diff --git a/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_general.ts b/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_general.ts index a883bf1f..4d2a3513 100644 --- a/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_general.ts +++ b/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_general.ts @@ -42,6 +42,7 @@ const triggerSet: TriggerSet = { // TODO: some Mimics may spawn after transference between floors and get called early before being found type: 'AddedCombatant', netRegex: { npcNameId: '2566', capture: false }, + suppressSeconds: 1, infoText: (_data, _matches, output) => output.text!(), outputStrings: { text: { diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts index 18179fe4..fe6d97ac 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts @@ -218,14 +218,23 @@ const triggerSet: TriggerSet = { }, haste: { en: 'Haste', + de: 'Hast', + fr: 'Hâte', + ja: 'ヘイスト', ko: '헤이스트(Haste)', }, purification: { en: 'Purification', + de: 'Reinigung', + fr: 'Purification', + ja: '浄化の守り', ko: '이상 현상 바리어(Purification)', }, devotion: { en: 'Devotion', + de: 'Weisung', + fr: 'Dévotion', + ja: '巡礼の導き', ko: '헌신(Devotion)', }, unknown: Outputs.unknown, @@ -266,18 +275,31 @@ const triggerSet: TriggerSet = { outputStrings: { duplicate: { en: '${incense} duplicate', + de: 'Doppelter ${incense}', + fr: '${incense} dupliqué(e)', + ja: '${incense} 被り', + cn: '${incense} 重复', ko: '${incense} 또 나옴', }, mazeroot: { en: 'Mazeroot', + de: 'Wandelwurz', + fr: 'Sagacité', + ja: '明敏', ko: '미로뿌리(Mazeroot)', }, barkbalm: { en: 'Barkbalm', + de: 'Sakralharz', + fr: 'Quiétude', + ja: '安寧', ko: '나무껍질연고(Barkbalm)', }, poisonfruit: { en: 'Poisonfruit', + de: 'Todesbeeren', + fr: 'Fatalité', + ja: '宿命', ko: '독과일(Poisonfruit)', }, unknown: Outputs.unknown, @@ -304,6 +326,38 @@ const triggerSet: TriggerSet = { }, }, ], + timelineReplace: [ + { + 'locale': 'de', + 'replaceSync': { + 'Mimic': 'Mimik', + }, + }, + { + 'locale': 'fr', + 'replaceSync': { + 'Mimic': 'Mimic', + }, + }, + { + 'locale': 'ja', + 'replaceSync': { + 'Mimic': 'ミミック', + }, + }, + { + 'locale': 'cn', + 'replaceSync': { + 'Mimic': '拟态怪', + }, + }, + { + 'locale': 'ko', + 'replaceSync': { + 'Mimic': '미믹', + }, + }, + ], }; export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts new file mode 100644 index 00000000..547920bf --- /dev/null +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts @@ -0,0 +1,107 @@ +import { Directions } from '../../../../../resources/util'; +import ZoneId from '../../../../../resources/zone_id'; +import { RaidbossData } from '../../../../../types/data'; +import { TriggerSet } from '../../../../../types/trigger'; + +// Pilgrim's Traverse Stones 01-10 +// TODO: Ornamental Leafman Leafmash jump order/safe spots + +// center of room for Ornamental Leafman encounter +const leafmanCenter = { + 'x': -300, + 'y': -300, +} as const; + +export interface Data extends RaidbossData { + shrubDir?: number[]; +} + +const triggerSet: TriggerSet = { + id: 'PilgrimsTraverseStones1_10', + zoneId: ZoneId.PilgrimsTraverseStones1_10, + + triggers: [ + // ---------------- Stone 01-09 Mobs ---------------- + // intentionally blank + // ---------------- Stone 10 Boss: Ornamental Leafman ---------------- + { + id: 'PT 01-10 Ornamental Leafman Hedge Mazing', + // Branch Out/Hedge Mazing: boss faces south during the entire mechanic + // two adds explode 180° from each other, third add explodes 45° from one of the other two + // adds can be on cardinals or intercardinals + // creates two safe spots; one larger (called out) and one smaller + type: 'StartsUsingExtra', + netRegex: { id: 'AF37', capture: true }, + durationSeconds: 13.2, + infoText: (data, matches, output) => { + const x = parseFloat(matches.x); + const y = parseFloat(matches.y); + const dirNum = Directions.xyTo8DirNum(x, y, leafmanCenter.x, leafmanCenter.y); + + (data.shrubDir ??= []).push(dirNum); + + if (data.shrubDir.length < 3) + return; + + let safeDirNum = -1; + const dirs = data.shrubDir.sort((a, b) => a - b); + const [dir1, dir2, dir3] = [dirs[0], dirs[1], dirs[2]]; + if (dir1 === undefined || dir2 === undefined || dir3 === undefined) + return output.unknownSafe!(); + if (dir2 - dir1 === 4) { + // ex: dir1 = N, dir2 = S, dir3 = NW, safe = E + safeDirNum = (dir1 + 2) % 8; + } else if (dir3 - dir2 === 4) { + // ex: dir1 = N, dir2 = NE, dir3 = SW, safe = SE + safeDirNum = (dir2 + 2) % 8; + } else if (dir3 - dir1 === 4) { + // ex: dir1 = N, dir2 = NE, dir3 = S, safe = W + safeDirNum = (dir3 + 2) % 8; + } + + if (safeDirNum === -1) + return output.unknownSafe!(); + + const safeDir = Directions.output8Dir[safeDirNum]; + if (safeDir === undefined) + return output.unknownSafe!(); + + return output.safe!({ safe: output[safeDir]!() }); + }, + outputStrings: { + safe: { + en: 'Go ${safe} + Out', + ko: '${safe} + 밖으로', + }, + unknownSafe: { + en: 'Out + Avoid shrublet explosions', + ko: '밖으로 + 덤불 폭발 피해요', + }, + ...Directions.outputStrings8Dir, + }, + }, + { + id: 'PT 01-10 Ornamental Leafman Hedge Mazing Cleanup', + type: 'Ability', + netRegex: { id: 'AF36', source: 'Ornamental Leafman', capture: false }, + run: (data) => { + delete data.shrubDir; + }, + }, + { + id: 'PT 01-10 Ornamental Leafman Leafmash', + type: 'StartsUsing', + netRegex: { id: 'AC17', source: 'Ornamental Leafman', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 5, + infoText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Away from jump x4', + ko: '점프 피해요x4', + }, + }, + }, + ], +}; + +export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts new file mode 100644 index 00000000..e8ad63ab --- /dev/null +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts @@ -0,0 +1,105 @@ +import Conditions from '../../../../../resources/conditions'; +import { UnreachableCode } from '../../../../../resources/not_reached'; +import Outputs from '../../../../../resources/outputs'; +import { Directions } from '../../../../../resources/util'; +import ZoneId from '../../../../../resources/zone_id'; +import { RaidbossData } from '../../../../../types/data'; +import { TriggerSet } from '../../../../../types/trigger'; + +// Pilgrim's Traverse Stones 11-20 + +type FootDirId = keyof typeof footDirs; + +const footDirs = { + '395': 'dirNE', + '396': 'dirNW', + '397': 'dirSE', + '398': 'dirSW', +} as const; + +const isFootDirId = (id: string): id is FootDirId => { + return id in footDirs; +}; + +export interface Data extends RaidbossData { + footOrder?: string[]; +} + +const triggerSet: TriggerSet = { + id: 'PilgrimsTraverseStones11_20', + zoneId: ZoneId.PilgrimsTraverseStones11_20, + + triggers: [ + // ---------------- Stone 11-19 Mobs ---------------- + // intentionally blank + // ---------------- Stone 20 Boss: Forgiven Emulation ---------------- + { + id: 'PT 11-20 Forgiven Emulation Touchdown', + // boss always faces north during this mechanic + // 395 = front left foot + // 396 = front right foot + // 397 = back left foot + // 398 = back right foot + type: 'GainsEffect', + netRegex: { effectId: '808', target: 'Forgiven Emulation', capture: true }, + infoText: (data, matches, output) => { + const count = matches.count; + (data.footOrder ??= []).push(count); + + if (data.footOrder.length < 4) + return; + + const foot1 = data.footOrder[0]; + const foot4 = data.footOrder[3]; + + if (foot1 === undefined || foot4 === undefined) + return output.text!({ + knockback: output.knockback!(), + dir1: output.unknown!(), + dir4: output.unknown!(), + }); + + if (!isFootDirId(foot1) || !isFootDirId(foot4)) + throw new UnreachableCode(); + + return output.text!({ + knockback: output.knockback!(), + dir1: output[footDirs[foot1]]!(), + dir4: output[footDirs[foot4]]!(), + }); + }, + outputStrings: { + text: { + en: '${knockback} ${dir4} => ${dir1}', + ko: '${knockback} ${dir4} 🔜 ${dir1}', + }, + knockback: Outputs.knockback, + unknown: Outputs.unknown, + ...Directions.outputStrings8Dir, + }, + }, + { + id: 'PT 11-20 Forgiven Emulation Touchdown Cleanup', + type: 'Ability', + netRegex: { id: 'A9BF', source: 'Forgiven Emulation', capture: false }, + run: (data) => { + delete data.footOrder; + }, + }, + { + id: 'PT 11-20 Forgiven Emulation Bare Root Planting', + type: 'HeadMarker', + netRegex: { id: '0017', capture: true }, + condition: Conditions.targetIsYou(), + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Seed on YOU', + ko: '내게 씨앗!', + }, + }, + }, + ], +}; + +export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts new file mode 100644 index 00000000..685affc1 --- /dev/null +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts @@ -0,0 +1,173 @@ +import Conditions from '../../../../../resources/conditions'; +import Outputs from '../../../../../resources/outputs'; +import { Responses } from '../../../../../resources/responses'; +import ZoneId from '../../../../../resources/zone_id'; +import { RaidbossData } from '../../../../../types/data'; +import { TriggerSet } from '../../../../../types/trigger'; + +// Pilgrim's Traverse Stones 21-30 + +export type Data = RaidbossData; + +const triggerSet: TriggerSet = { + id: 'PilgrimsTraverseStones21_30', + zoneId: ZoneId.PilgrimsTraverseStones21_30, + + triggers: [ + // ---------------- Stone 21-29 Mobs ---------------- + { + id: 'PT 21-30 Traverse Clionid Parasitism', + // enrage on targeted player + type: 'StartsUsing', + netRegex: { id: 'AE89', source: 'Traverse Clionid', capture: true }, + alertText: (data, matches, output) => { + const target = matches.target; + if (target === undefined) + return output.enrage!(); + if (target === data.me) + return output.enrageOnYou!(); + return output.enrageOnPlayer!({ player: data.party.member(target) }); + }, + outputStrings: { + enrage: { + en: 'Parasitism', + ko: '기생충', + }, + enrageOnYou: { + en: 'Parasitism on YOU', + ko: '내게 기생충!', + }, + enrageOnPlayer: { + en: 'Parasitism on ${player}', + ko: '기생충: ${player}', + }, + }, + }, + { + id: 'PT 21-30 Forgiven Intolerance Swinge', + type: 'StartsUsing', + netRegex: { id: 'AE8C', source: 'Forgiven Intolerance', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 21-30 Forgiven Ambition Ripper Claw', + type: 'StartsUsing', + netRegex: { id: 'AE7D', source: 'Forgiven Ambition', capture: false }, + response: Responses.awayFromFront(), + }, + // ---------------- Stone 30 Boss: Forgiven Treachery ---------------- + // 9A3F = Liturgy of Light dummy self-cast + // 9ADA = Brutal Halo inner ring + // 9ADB = Brutal Halo inner-middle ring + // 9AFA = Brutal Halo outer-middle ring + // 9B3F = Brutal Halo outer ring + // 9BC4 = Bounds of Indulgence spinning discs? + // 9DD1 = Grip of Salvation dummy self-cast + // 9E67 = Grip of Salvation damage cast + // 9E65 = Grip of Salvation dummy self-cast + // AF7F = Grip of Salvation damage cast + // 9E66 = Salvation's Reach instant dummy self-cast + // 9DDB = Salvation's Reach instant dummy self-cast + // 9E68 = Salvation's Reach damage cast (very short) + // 9E69 = Salvation's Reach damage cast (very short) + // AF75 = Divine Favor dummy self-cast + // AF76 = Divine Favor environment-targeted telegraph cast + // AF77 = Divine Favor environment-targeted damage cast + { + id: 'PT 21-30 Forgiven Treachery Brutal Halo', + type: 'StartsUsing', + netRegex: { + id: ['9ADA', '9ADB', '9AFA', '9B3F'], + source: 'Forgiven Treachery', + capture: true, + }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 4, + durationSeconds: 4, + countdownSeconds: 4, + infoText: (_data, matches, output) => { + const id = matches.id; + switch (id) { + case '9ADA': + return output.middleOrOuter!(); + case '9ADB': + return output.innerOrOuter!(); + case '9AFA': + return output.innerOrMiddle!(); + case '9B3F': + return output.innerOrMiddle!(); + } + }, + outputStrings: { + middleOrOuter: { + en: 'Get Middle or Outer ring', + ko: '중간 / 바깥 링으로', + }, + innerOrOuter: { + en: 'Get Inner or Outer ring', + ko: '안쪽 / 바깥 링으로', + }, + innerOrMiddle: { + en: 'Get Inner or Middle ring', + ko: '안쪽 / 중간 링으로', + }, + }, + }, + { + id: 'PT 21-30 Forgiven Treachery Grip of Salvation', + type: 'StartsUsing', + netRegex: { id: ['9E67', 'AF7F'], source: 'Forgiven Treachery', capture: true }, + durationSeconds: (_data, matches) => parseFloat(matches.castTime), + alertText: (_data, matches, output) => { + const id = matches.id; + if (id === '9E67') + return output.left!(); + return output.right!(); + }, + outputStrings: { + left: Outputs.left, + right: Outputs.right, + }, + }, + { + id: 'PT 21-30 Forgiven Treachery Salvation\'s Reach', + // damage cast is too short to give a useful notification; use cleave cast as a proxy + type: 'Ability', + netRegex: { id: ['9E67', 'AF7F'], source: 'Forgiven Treachery', capture: true }, + durationSeconds: 8, + alertText: (_data, matches, output) => { + const id = matches.id; + if (id === '9E67') + return output.text!({ dir: output.right!() }); + return output.text!({ dir: output.left!() }); + }, + outputStrings: { + left: Outputs.left, + right: Outputs.right, + text: { + en: '${dir}, Behind Hand', + ko: '${dir}, 손 뒤로', + }, + }, + }, + { + id: 'PT 21-30 Forgiven Treachery Divine Favor', + type: 'HeadMarker', + netRegex: { id: '00C5', capture: true }, + condition: Conditions.targetIsYou(), + durationSeconds: 12, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Chasing AoE on YOU', + de: 'Verfolgende AoE auf DIR', + fr: 'Ruée sur VOUS', + ja: '追跡AOE', + cn: '追踪AOE点名', + ko: '내게 따라오는 장판', + }, + }, + }, + ], +}; + +export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts new file mode 100644 index 00000000..f56a5847 --- /dev/null +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts @@ -0,0 +1,120 @@ +import Outputs from '../../../../../resources/outputs'; +import { Responses } from '../../../../../resources/responses'; +import ZoneId from '../../../../../resources/zone_id'; +import { RaidbossData } from '../../../../../types/data'; +import { TriggerSet } from '../../../../../types/trigger'; + +// Pilgrim's Traverse Stones 31-40 +// TODO: Forgiven Naivety Blown Blessing add order + +export type Data = RaidbossData; + +const triggerSet: TriggerSet = { + id: 'PilgrimsTraverseStones31_40', + zoneId: ZoneId.PilgrimsTraverseStones31_40, + + triggers: [ + // ---------------- Stone 31-39 Mobs ---------------- + { + id: 'PT 31-40 Traverse Pegasus Gallop', + type: 'StartsUsing', + netRegex: { id: 'AE9E', source: 'Traverse Pegasus', capture: true }, + response: Responses.knockbackOn(), + }, + { + id: 'PT 31-40 Traverse Pegasus Nicker', + type: 'StartsUsing', + netRegex: { id: 'AE9F', source: 'Traverse Pegasus', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 31-40 Traverse Inquisitor Death\'s Door', + type: 'StartsUsing', + netRegex: { id: 'AE96', source: 'Traverse Inquisitor', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 31-40 Forgiven Petulance Left Tentacle', + type: 'StartsUsing', + netRegex: { id: 'AE92', source: 'Forgiven Petulance', capture: false }, + response: Responses.goRight(), + }, + { + id: 'PT 31-40 Forgiven Petulance Right Tentacle', + type: 'StartsUsing', + netRegex: { id: 'AE93', source: 'Forgiven Petulance', capture: false }, + response: Responses.goLeft(), + }, + { + id: 'PT 31-40 Traverse Soldierstone Hand of Judgment', + type: 'StartsUsing', + netRegex: { id: '9E6D', source: 'Traverse Soldierstone', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 3, + response: Responses.outOfMelee(), + }, + { + id: 'PT 31-40 Traverse Soldierstone Moatmaker', + // follows-up with 9E6F Buster Knuckles instant medium AoE + type: 'StartsUsing', + netRegex: { id: '9E6E', source: 'Traverse Soldierstone', capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Avoid jump => Out', + ko: '점프 피하고 🔜 밖으로', + }, + }, + }, + { + id: 'PT 31-40 Traverse Soldierstone Buster Knuckles', + type: 'StartsUsing', + netRegex: { id: '9E6F', source: 'Traverse Soldierstone', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 31-40 Forgiven Plague Poison Pollen Pair', + type: 'StartsUsing', + netRegex: { id: 'A180', source: 'Forgiven Plague', capture: false }, + response: Responses.goSides(), + }, + { + id: 'PT 31-40 Forgiven Prejudice Petrifying Light', + type: 'StartsUsing', + netRegex: { id: 'AE8F', source: 'Forgiven Prejudice', capture: true }, + response: Responses.lookAwayFromSource(), + }, + // ---------------- Stone 40 Boss: Forgiven Naivety ---------------- + { + id: 'PT 31-40 Forgiven Naivety Blown Blessing', + type: 'StartsUsing', + netRegex: { id: ['A48B', 'A48C'], source: 'Forgiven Naivety', capture: true }, + durationSeconds: 18, + infoText: (_data, matches, output) => { + const mech = matches.id === 'A48B' ? output.knockback!() : output.aoe!(); + return output.text!({ mech: mech }); + }, + outputStrings: { + text: { + en: '${mech} x3', + ko: '${mech}x3', + }, + knockback: Outputs.knockback, + aoe: Outputs.aoe, + }, + }, + { + id: 'PT 31-40 Forgiven Naivety Near Tide', + type: 'StartsUsing', + netRegex: { id: 'B041', source: 'Forgiven Naivety', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 31-40 Forgiven Naivety Far Tide', + type: 'StartsUsing', + netRegex: { id: 'B042', source: 'Forgiven Naivety', capture: false }, + response: Responses.getIn(), + }, + ], +}; + +export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts index e04787f3..bf637471 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts @@ -4,12 +4,66 @@ import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; +// Pilgrim's Traverse Stones 41-50 + export type Data = RaidbossData; const triggerSet: TriggerSet = { id: 'PilgrimsTraverseStones41_50', zoneId: ZoneId.PilgrimsTraverseStones41_50, + triggers: [ + // ---------------- Stone 41-49 Mobs ---------------- + { + id: 'PT 41-50 Traverse Weapon Smite of Rage', + type: 'StartsUsing', + netRegex: { id: 'AEAA', source: 'Traverse Weapon', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 41-50 Traverse Weapon Whirl of Rage', + type: 'StartsUsing', + netRegex: { id: 'AEAB', source: 'Traverse Weapon', capture: false }, + response: Responses.outOfMelee(), + }, + { + id: 'PT 41-50 Traverse Troubadour Tortoise Stomp', + type: 'StartsUsing', + netRegex: { id: 'A2FC', source: 'Traverse Troubadour', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 3, + response: Responses.outOfMelee(), + }, + { + id: 'PT 41-50 Traverse Triffid Creeping Combination', + type: 'StartsUsing', + netRegex: { id: 'A37E', source: 'Traverse Triffid', capture: false }, + response: Responses.goSides(), + }, + { + id: 'PT 41-50 Traverse Petreffigy Magnetic Shock', + type: 'StartsUsing', + netRegex: { id: 'A1D3', source: 'Traverse Petreffigy', capture: false }, + response: Responses.drawIn(), + }, + { + id: 'PT 41-50 Traverse Petreffigy Plaincracker', + type: 'StartsUsing', + netRegex: { id: 'A228', source: 'Traverse Petreffigy', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 3, + response: Responses.getOut(), + }, + { + id: 'PT 41-50 Traverse Anaconda Dripping Fang', + type: 'StartsUsing', + netRegex: { id: 'A37A', source: 'Traverse Anaconda', capture: true }, + response: Responses.stunOrInterruptIfPossible(), + }, + { + id: 'PT 41-50 Traverse Pincerbeak Tail Smash', + type: 'StartsUsing', + netRegex: { id: 'AEA7', source: 'Traverse Pincerbeak', capture: false }, + response: Responses.getOut(), + }, // ---------------- Stone 50 Boss: Ogbunabali ---------------- { id: 'PT 41-50 Ogbunabali Liquefaction', @@ -32,6 +86,9 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: '4x Chasing AoE on YOU', + de: '4x verfolgende AoE auf DIR', + fr: '4x AoE sur VOUS', + cn: '四连 AOE 点名', ko: '따라오는 장판 x4', }, }, @@ -40,9 +97,14 @@ const triggerSet: TriggerSet = { id: 'PT 41-50 Ogbunabali Biting Wind', type: 'StartsUsing', netRegex: { id: 'AA12', source: 'Ogbunabali', capture: true }, - delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 5, - countdownSeconds: 5, - response: Responses.knockback(), + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 3, + countdownSeconds: 3, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Stand in quicksand', + }, + }, }, ], }; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts index 49ebd313..b62d0bbb 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts @@ -4,12 +4,98 @@ import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; +// Pilgrim's Traverse Stones 51-60 +// TODO: Ancestral Maliktender Branch Out safespots +// TODO: Ancestral Maliktender One/Two-stone March rotation direction + safespots + export type Data = RaidbossData; const triggerSet: TriggerSet = { id: 'PilgrimsTraverseStones51_60', zoneId: ZoneId.PilgrimsTraverseStones51_60, + triggers: [ + // ---------------- Stone 51-59 Mobs ---------------- + { + id: 'PT 51-60 Traverse Phorusrhacos Painful Gust', + type: 'StartsUsing', + netRegex: { id: 'AEB7', source: 'Traverse Phorusrhacos', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 51-60 Traverse Phorusrhacos Pain Storm', + type: 'StartsUsing', + netRegex: { id: 'AEB8', source: 'Traverse Phorusrhacos', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 51-60 Traverse Phorusrhacos Whorl of Hurt', + type: 'StartsUsing', + netRegex: { id: 'AEB9', source: 'Traverse Phorusrhacos', capture: false }, + response: Responses.getIn(), + }, + { + id: 'PT 51-60 Traverse Monitor Smoldering Scales', + // Gains 11E3 Blaze Spikes for 6s, high counterattack damage when hit + type: 'StartsUsing', + netRegex: { id: 'A4E4', source: 'Traverse Monitor', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 1, + durationSeconds: 7, + countdownSeconds: 7, + alertText: (_data, matches, output) => output.text!({ target: matches.target }), + outputStrings: { + text: { + en: 'Stop attacking ${target}', + de: 'Stoppe Angriffe auf ${target}', + fr: 'Arrêtez d\'attaquer ${target}', + ja: '攻撃禁止: ${target}', + cn: '停止攻击 ${target}', + ko: '${target} 공격 중지', + }, + }, + }, + { + id: 'PT 51-60 Traverse Sand Serpent Earthen Auger', + type: 'StartsUsing', + netRegex: { id: 'A46B', source: 'Traverse Sand Serpent', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 51-60 Traverse Gigant Heavy Scrapline', + type: 'StartsUsing', + netRegex: { id: 'AEC1', source: 'Traverse Gigant', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 51-60 Traverse Saichania Bafflement Bulb', + type: 'StartsUsing', + netRegex: { id: 'A4A0', source: 'Traverse Saichania', capture: true }, + response: Responses.stunOrInterruptIfPossible(), + }, + { + id: 'PT 51-60 Traverse Saichania Trounce', + type: 'StartsUsing', + netRegex: { id: 'A4A3', source: 'Traverse Saichania', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 51-60 Traverse Saichania Mighty Spin', + type: 'StartsUsing', + netRegex: { id: 'A4A4', source: 'Traverse Saichania', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 51-60 Traverse Howler Scythe Tail', + type: 'StartsUsing', + netRegex: { id: 'AEBB', source: 'Traverse Howler', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 51-60 Traverse Howler Master of Levin', + type: 'StartsUsing', + netRegex: { id: 'AEBC', source: 'Traverse Howler', capture: false }, + response: Responses.getIn(), + }, // ---------------- Stone 60 Boss: Ancestral Maliktender ---------------- { id: 'PT 51-60 Ancestral Maliktender Spineshot', diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts index 2c5c9107..f02125a9 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts @@ -5,6 +5,8 @@ import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; +// Pilgrim's Traverse Stones 61-70 + type DirectionOutputCardinalRelative = | 'front' | 'right' @@ -31,7 +33,136 @@ export interface Data extends RaidbossData { const triggerSet: TriggerSet = { id: 'PilgrimsTraverseStones61_70', zoneId: ZoneId.PilgrimsTraverseStones61_70, + triggers: [ + // ---------------- Stone 61-69 Mobs ---------------- + { + id: 'PT 61-70 Forgiven Doubt Body Press', + type: 'StartsUsing', + netRegex: { id: 'AECC', source: 'Forgiven Doubt', capture: false }, + response: Responses.outOfMelee(), + }, + { + id: 'PT 61-70 Traverse Cliffmole Head Butt', + type: 'StartsUsing', + netRegex: { id: 'AEC4', source: 'Traverse Cliffmole', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 61-70 Forgiven Riot Right-sided Shockwave', + type: 'StartsUsing', + netRegex: { id: 'A4E6', source: 'Forgiven Riot', capture: false }, + response: Responses.goLeftThenRight(), + }, + { + id: 'PT 61-70 Forgiven Riot Left-sided Shockwave', + type: 'StartsUsing', + netRegex: { id: 'A4E8', source: 'Forgiven Riot', capture: false }, + response: Responses.goRightThenLeft(), + }, + { + id: 'PT 61-70 Traverse Gnome Plain Pound', + type: 'StartsUsing', + netRegex: { id: 'AED1', source: 'Traverse Gnome', capture: false }, + response: Responses.outOfMelee(), + }, + { + id: 'PT 61-70 Forgiven Grudge Crystalline Stingers', + type: 'StartsUsing', + netRegex: { id: 'A610', source: 'Forgiven Grudge', capture: true }, + response: Responses.stunIfPossible(), + }, + { + id: 'PT 61-70 Forgiven Grudge Hailfire', + type: 'StartsUsing', + netRegex: { id: 'A613', source: 'Forgiven Grudge', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 61-70 Traverse Talos Accelerate', + // follows-up with A615 Subduction PBAoE, then A616 Settling Stone donut (both instant cast) + type: 'StartsUsing', + netRegex: { id: 'A614', source: 'Traverse Talos', capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Away from jump => Get Under or Out', + }, + }, + }, + { + id: 'PT 61-70 Forgiven Attachment Sewer Water Front', + type: 'StartsUsing', + netRegex: { id: 'AECE', source: 'Forgiven Attachment', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 61-70 Forgiven Attachment Sewer Water Back', + type: 'StartsUsing', + netRegex: { id: 'AECF', source: 'Forgiven Attachment', capture: false }, + response: Responses.goFront('alert'), + }, + { + id: 'PT 61-70 Forgiven Contention Several Thousand Needles', + type: 'StartsUsing', + netRegex: { id: 'A4EC', source: 'Forgiven Contention', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 61-70 Forgiven Imparity Rockslide', + type: 'StartsUsing', + netRegex: { id: 'AEC7', source: 'Forgiven Imparity', capture: false }, + response: Responses.getIntercards(), + }, + { + id: 'PT 61-70 Traverse Queen Unfinal Sting', + type: 'StartsUsing', + netRegex: { id: 'A60E', source: 'Traverse Queen', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 61-70 Traverse Queen Final Sting', + // enrage on targeted player + type: 'StartsUsing', + netRegex: { id: 'A60F', source: 'Traverse Queen', capture: true }, + alertText: (data, matches, output) => { + const target = matches.target; + if (target === undefined) + return output.sting!(); + if (target === data.me) + return output.stingOnYou!(); + return output.stingOnPlayer!({ player: data.party.member(target) }); + }, + outputStrings: { + sting: { + en: 'Final Sting', + }, + stingOnYou: { + en: 'Final Sting on YOU', + }, + stingOnPlayer: { + en: 'Final Sting on ${player}', + }, + }, + }, + { + id: 'PT 61-70 Traverse Ngozi Landslip', + type: 'StartsUsing', + netRegex: { id: 'AED3', source: 'Traverse Ngozi', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 61-70 Forgiven Voracity Stone Gaze', + type: 'StartsUsing', + netRegex: { id: 'AECA', source: 'Forgiven Voracity', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 61-70 Forgiven Voracity Body Slam', + type: 'StartsUsing', + netRegex: { id: 'AECB', source: 'Forgiven Voracity', capture: false }, + response: Responses.outOfMelee(), + }, // ---------------- Stone 70 Boss: Forgiven Zeal ---------------- // A993 = Zealous Glower dummy self-cast, back-to-front line // A98E = Zealous Glower dummy self-cast, front-to-back line diff --git a/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts b/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts index adcae2fc..0d38625c 100644 --- a/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts +++ b/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts @@ -94,6 +94,7 @@ const triggerSet: TriggerSet = { outputStrings: { knockbackFrom: { en: 'Knockback from ${dir}', + cn: '从 ${dir} 击退', ko: '${dir}에서 넉백', }, dirN: Outputs.north, @@ -169,6 +170,7 @@ const triggerSet: TriggerSet = { outputStrings: { cleanse: { en: 'Cleanse ${target}', + cn: '康复 ${target}', ko: '에스나: ${target}', }, }, @@ -210,6 +212,7 @@ const triggerSet: TriggerSet = { outputStrings: { avoidFlails: { en: 'Away from flails', + cn: '远离铁球', ko: '플레일 피해요', }, }, @@ -245,6 +248,7 @@ const triggerSet: TriggerSet = { outputStrings: { cleanseDoom: { en: 'Cleanse ${target}', + cn: '康复 ${target}', ko: '에스나: ${target}', }, }, @@ -335,6 +339,7 @@ const triggerSet: TriggerSet = { outputStrings: { staticBombardment: { en: 'Go ${safe}; Avoid small AoE', + cn: '前往 ${safe}; 避开小范围 AoE', ko: '${safe}으로 가욧! 작은 장판은 피해요', }, west: Outputs.west, @@ -370,6 +375,7 @@ const triggerSet: TriggerSet = { outputStrings: { knockbackBombardment: { en: 'Knockback to ${safe}; Avoid AoE', + cn: '击退到 ${safe}; 避开 AoE', ko: '${safe}으로 넉백! 장판은 피해요', }, northwest: Outputs.northwest, @@ -452,10 +458,12 @@ const triggerSet: TriggerSet = { outputStrings: { leanLeft: { en: 'Front + Lean Left; or Southwest', + cn: '前方 + 偏左; 或左下', ko: '앞 + 왼쪽으로 살짝 또는 남서쪽', }, leanRight: { en: 'Front + Lean Right; or Southeast', + cn: '前方 + 偏右; 或右下', ko: '앞 + 오른쪽으로 살짝 또는 남동쪽', }, dirNW: Outputs.northwest, @@ -466,7 +474,229 @@ const triggerSet: TriggerSet = { }, }, ], - timelineReplace: [], + timelineReplace: [ + { + 'locale': 'de', + 'missingTranslations': true, + 'replaceSync': { + 'Bloody Headsman': 'blutig(?:e|er|es|en) Henkersmann', + 'Bygone Aerostat': 'vergangen(?:e|er|es|en) Aerostat', + 'Chirurgeon General': 'Erinnerung eines Feldchirurgen', + 'Hooded Headsman': 'falsch(?:e|er|es|en) Henkersmann', + 'Immortal Remains': 'Erinnerungsschmelz', + 'Pale Headsman': 'blass(?:e|er|es|en) Henkersmann', + 'Pestilent Headsman': 'verderblich(?:e|er|es|en) Henkersmann', + }, + 'replaceText': { + 'Biochemical Front': 'Biochemische Front', + 'Bombardment': 'Bombardement', + 'Chopping Block': 'Hackklotzhinrichtung', + 'Concentrated Dose': 'Konzentrierte Dosis', + 'Death Penalty': 'Höchststrafe', + 'Dismemberment': 'Zerstückelung', + 'Electray': 'Elektroblitz', + 'Execution Wheel': 'Folterrad', + 'Flaying Flail': 'Flegel der Sündenläuterung', + 'Head-splitting Roar': 'Schädelspaltergebrüll', + 'Impression': 'Impression', + 'Keraunography': 'Keraunographie', + 'Lawless Pursuit': 'Gesetzlosenverfolgung', + 'Medicine Field': 'Medizinstreuung', + 'Memento': 'Memento', + 'Memory of the Pyre': 'Erinnerung eines Scheiterhaufens', + 'Memory of the Storm': 'Erinnerung eines Sturms', + 'No Man\'s Land': 'Niemandsland', + 'Peal of Judgment': 'Klingen der Sündenläuterung', + 'Pungent Aerosol': 'Stechendes Aerosol', + 'Recollection': 'Rückbesinnung', + 'Relentless Torment': 'Unerbittliche Pein', + 'Sensory Deprivation': 'Sinnesberaubung', + 'Serial Torture': 'Qualen ohne Ende', + 'Shackles of Fate': 'Ketten des Schicksals', + 'Sterile Sphere': 'Sterile Spähre', + 'Turmoil': 'Aufregung', + 'Will Breaker': 'Willensbrecher', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Bloody Headsman': 'mémoire du bourreau rouge', + 'Bygone Aerostat': 'aérostat séculaire', + 'Chirurgeon General': 'mémoire d\'un chef de clinique', + 'Hooded Headsman': 'mémoire d\'un bourreau', + 'Immortal Remains': 'Memoria populi', + 'Pale Headsman': 'mémoire du bourreau jaune', + 'Pestilent Headsman': 'mémoire du bourreau vert', + }, + 'replaceText': { + 'Biochemical Front': 'Pulvérisation avant', + 'Bombardment': 'Bombardement', + 'Chopping Block': 'Lune tranchante', + 'Concentrated Dose': 'Injection concentrée', + 'Death Penalty': 'Condamnation à mort', + 'Dismemberment': 'Lames coupe-jambes', + 'Electray': 'Rayon électrique', + 'Execution Wheel': 'Éclipse tranchante', + 'Flaying Flail': 'Boulets de châtiment', + 'Head-splitting Roar': 'Cri de bourreau', + 'Impression': 'Impression terrestre', + 'Keraunography': 'Fulguration funeste', + 'Lawless Pursuit': 'Astreinte du condamné', + 'Medicine Field': 'Bain thérapeutique', + 'Memento': 'Reconstitution mémorielle', + 'Memory of the Pyre': 'Bombe mémorielle', + 'Memory of the Storm': 'Orage mémoriel', + 'No Man\'s Land': 'Activation des diffuseurs', + 'Peal of Judgment': 'Lames électriques de châtiment', + 'Pungent Aerosol': 'Solution explosive', + 'Recollection': 'Remémoration', + 'Relentless Torment': 'Volée de coups puissante', + 'Sensory Deprivation': 'Anesthésie sensorielle', + 'Serial Torture': 'Châtiments multiples', + 'Shackles of Fate': 'Enchaînement du condamné', + 'Sterile Sphere': 'Diffusion circulaire', + 'Turmoil': 'Commotion terrestre', + 'Will Breaker': 'Bombe pulvérisante', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Bloody Headsman': 'ある処刑人の記憶【緋】', + 'Bygone Aerostat': 'バイゴーン・エアロスタット', + 'Chirurgeon General': 'ある医療長の記憶', + 'Hooded Headsman': 'ある処刑人の記憶', + 'Immortal Remains': 'ある人々の記憶', + 'Pale Headsman': 'ある処刑人の記憶【黄】', + 'Pestilent Headsman': 'ある処刑人の記憶【翠】', + }, + 'replaceText': { + 'Biochemical Front': '前面噴霧', + 'Bombardment': '爆撃', + 'Chopping Block': '円月断', + 'Concentrated Dose': '高圧縮薬弾', + 'Death Penalty': '死刑宣告', + 'Dismemberment': '足切りの刃', + 'Electray': 'エレクトロレイ', + 'Execution Wheel': '月輪断', + 'Flaying Flail': '断罪の鉄球', + 'Head-splitting Roar': '処刑人の咆哮', + 'Impression': 'インプレッション', + 'Keraunography': '雷光', + 'Lawless Pursuit': '罪人捕捉', + 'Medicine Field': '広域散薬', + 'Memento': 'メモリーズ', + 'Memory of the Pyre': 'メモリーボム', + 'Memory of the Storm': 'メモリーストーム', + 'No Man\'s Land': '装置起動', + 'Peal of Judgment': '断罪の雷剣', + 'Pungent Aerosol': '爆発性薬', + 'Recollection': 'リコレクション', + 'Relentless Torment': '強連撃', + 'Sensory Deprivation': '知覚攪乱薬', + 'Serial Torture': '連刑執行', + 'Shackles of Fate': '束縛の鉄鎖', + 'Sterile Sphere': '円状散布', + 'Turmoil': 'ターモイル', + 'Will Breaker': '破砕弾', + }, + }, + { + 'locale': 'cn', + 'replaceSync': { + 'Bloody Headsman': '某个绯红处刑人的记忆', + 'Bygone Aerostat': '旧日航空机', + 'Chirurgeon General': '某个医师长的记忆', + 'Hooded Headsman': '某个处刑人的记忆', + 'Immortal Remains': '某些人的记忆', + 'Pale Headsman': '某个黄褐处刑人的记忆', + 'Pestilent Headsman': '某个翠绿处刑人的记忆', + }, + 'replaceText': { + '--hellmaker adds--': '--焦热刑具出现--', + '\\(active\\)': '(生效)', + '\\(cast\\)': '(咏唱)', + '\\(castbar\\)': '(读条)', + 'Biochemical Front': '正面喷雾', + 'Bombardment': '轰炸', + 'Chopping Block': '圆月断', + 'Concentrated Dose': '高压缩药弹', + 'Death Penalty': '死刑宣告', + 'Dismemberment': '斩足刃', + 'Electray': '雷质射线', + 'Execution Wheel': '月环断', + 'Flaying Flail': '断罪的铁球', + 'Head-splitting Roar': '处刑人的咆哮', + 'Impression': '印象', + 'Keraunography': '雷光', + 'Lawless Pursuit': '捉拿罪犯', + 'Medicine Field': '广域撒药', + 'Memento': '记忆重现', + 'Memory of the Pyre': '记忆爆炸', + 'Memory of the Storm': '记忆风暴', + 'No Man\'s Land': '启动装置', + 'Peal of Judgment': '断罪的雷剑', + 'Pungent Aerosol': '爆炸药液', + 'Recollection': '回忆', + 'Relentless Torment': '强连击', + 'Sensory Deprivation': '知觉扰乱药', + 'Serial Torture': '连续处刑', + 'Shackles of Fate': '铁链束缚', + 'Sterile Sphere': '圆状散布', + 'Turmoil': '慌乱', + 'Will Breaker': '破碎弹', + }, + }, + { + 'locale': 'ko', + 'replaceSync': { + 'Bloody Headsman': '어느 집행인의 기억: 빨강', + 'Bygone Aerostat': '구시대 비행체', + 'Chirurgeon General': '어느 의료장의 기억', + 'Hooded Headsman': '어느 집행인의 기억', + 'Immortal Remains': '어느 사람들의 기억', + 'Pale Headsman': '어느 집행인의 기억: 노랑', + 'Pestilent Headsman': '어느 집행인의 기억: 초록', + }, + 'replaceText': { + '--hellmaker adds--': '--초열 형구 등장--', + '\\(active\\)': '(활성)', + '\\(cast\\)': '(시전)', + '\\(castbar\\)': '(시전바)', + 'Biochemical Front': '전방 분무', + 'Bombardment': '폭격', + 'Chopping Block': '만월참', + 'Concentrated Dose': '고압축 물약', + 'Death Penalty': '사형 언도', + 'Dismemberment': '발목 절단날', + 'Electray': '전기 광선', + 'Execution Wheel': '월륜참', + 'Flaying Flail': '단죄의 철퇴', + 'Head-splitting Roar': '집행인의 포효', + 'Impression': '기억 각인', + 'Keraunography': '뇌광', + 'Lawless Pursuit': '죄인 포착', + 'Medicine Field': '광역 살포제', + 'Memento': '기억 구현', + 'Memory of the Pyre': '기억 폭탄', + 'Memory of the Storm': '기억 폭풍', + 'No Man\'s Land': '장치 기동', + 'Peal of Judgment': '단죄의 뇌검', + 'Pungent Aerosol': '폭발성 약', + 'Recollection': '기억 불러오기', + 'Relentless Torment': '연속 강공격', + 'Sensory Deprivation': '감각 교란제', + 'Serial Torture': '연속 형벌 집행', + 'Shackles of Fate': '속박의 쇠사슬', + 'Sterile Sphere': '원형 살포', + 'Turmoil': '동란', + 'Will Breaker': '파쇄탄', + }, + }, + ], }; export default triggerSet; diff --git a/util/coverage/coverage.ts b/util/coverage/coverage.ts index 4b31cf64..87db6c7f 100644 --- a/util/coverage/coverage.ts +++ b/util/coverage/coverage.ts @@ -329,6 +329,14 @@ const contentTypeToLabel: { ko: '딥 던전', }, }, + [ContentType.DeepDungeonExtras]: { + full: { + en: 'Deep Dungeon Extra Content', + }, + short: { + en: 'DD+', + }, + }, [ContentType.Pvp]: { full: { en: 'PvP', From 20532fc7162f7ae97dab249889ecd447ac510067 Mon Sep 17 00:00:00 2001 From: ksh Date: Sun, 9 Nov 2025 08:25:20 +0900 Subject: [PATCH 3/4] Add Chinese translations for Pilgrim's Traverse and Meso Terminal dungeon triggers --- package.json | 2 +- .../Properties/AssemblyInfo.cs | 4 ++-- .../CactbotOverlay/Properties/AssemblyInfo.cs | 4 ++-- resources/zone_info.ts | 14 ++++++++++++++ .../deepdungeon/eureka_orthos_floors_51-60.ts | 3 +++ .../deepdungeon/pilgrims_traverse_general.ts | 7 +++++++ .../pilgrims_traverse_stones_01-10.ts | 3 +++ .../pilgrims_traverse_stones_11-20.ts | 2 ++ .../pilgrims_traverse_stones_21-30.ts | 7 +++++++ .../pilgrims_traverse_stones_31-40.ts | 2 ++ .../pilgrims_traverse_stones_41-50.ts | 5 ++++- .../pilgrims_traverse_stones_51-60.ts | 4 ++++ .../pilgrims_traverse_stones_61-70.ts | 15 +++++++++++++++ .../pilgrims_traverse_the_final_verse.ts | 19 +++++++++++++++++++ .../data/07-dt/dungeon/meso-terminal.txt | 13 +++++++------ util/coverage/coverage.ts | 4 ++++ 16 files changed, 96 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 68530e28..a3ed73bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cactbot-build", - "version": "99.168.0", + "version": "99.169.0", "license": "Apache-2.0", "type": "module", "types": "./types", diff --git a/plugin/CactbotEventSource/Properties/AssemblyInfo.cs b/plugin/CactbotEventSource/Properties/AssemblyInfo.cs index 449e5782..90f47c1d 100644 --- a/plugin/CactbotEventSource/Properties/AssemblyInfo.cs +++ b/plugin/CactbotEventSource/Properties/AssemblyInfo.cs @@ -21,5 +21,5 @@ // - Revision // GitHub has only 3 version components, so Revision should always be 0. // CactbotOverlay and CactbotEventSource version should match. -[assembly: AssemblyVersion("99.168.0.0")] -[assembly: AssemblyFileVersion("99.168.0.0")] +[assembly: AssemblyVersion("99.169.0.0")] +[assembly: AssemblyFileVersion("99.169.0.0")] diff --git a/plugin/CactbotOverlay/Properties/AssemblyInfo.cs b/plugin/CactbotOverlay/Properties/AssemblyInfo.cs index 8378e11c..501ff7b9 100644 --- a/plugin/CactbotOverlay/Properties/AssemblyInfo.cs +++ b/plugin/CactbotOverlay/Properties/AssemblyInfo.cs @@ -20,5 +20,5 @@ // - Build Number // - Revision // GitHub has only 3 version components, so Revision should always be 0. -[assembly: AssemblyVersion("99.168.0.0")] -[assembly: AssemblyFileVersion("99.168.0.0")] +[assembly: AssemblyVersion("99.169.0.0")] +[assembly: AssemblyFileVersion("99.169.0.0")] diff --git a/resources/zone_info.ts b/resources/zone_info.ts index 29bfdfb3..41e2099c 100644 --- a/resources/zone_info.ts +++ b/resources/zone_info.ts @@ -10685,6 +10685,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第1~10朝圣路', 'de': 'Pilgers Pfad (Ebenen 1-10)', 'en': 'Pilgrim\'s Traverse (Stones 1-10)', 'fr': 'Le Sanctuaire des pèlerins (zones 1-10)', @@ -10699,6 +10700,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第11~20朝圣路', 'de': 'Pilgers Pfad (Ebenen 11-20)', 'en': 'Pilgrim\'s Traverse (Stones 11-20)', 'fr': 'Le Sanctuaire des pèlerins (zones 11-20)', @@ -10713,6 +10715,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第21~30朝圣路', 'de': 'Pilgers Pfad (Ebenen 21-30)', 'en': 'Pilgrim\'s Traverse (Stones 21-30)', 'fr': 'Le Sanctuaire des pèlerins (zones 21-30)', @@ -10727,6 +10730,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第31~40朝圣路', 'de': 'Pilgers Pfad (Ebenen 31-40)', 'en': 'Pilgrim\'s Traverse (Stones 31-40)', 'fr': 'Le Sanctuaire des pèlerins (zones 31-40)', @@ -10741,6 +10745,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第41~50朝圣路', 'de': 'Pilgers Pfad (Ebenen 41-50)', 'en': 'Pilgrim\'s Traverse (Stones 41-50)', 'fr': 'Le Sanctuaire des pèlerins (zones 41-50)', @@ -10755,6 +10760,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第51~60朝圣路', 'de': 'Pilgers Pfad (Ebenen 51-60)', 'en': 'Pilgrim\'s Traverse (Stones 51-60)', 'fr': 'Le Sanctuaire des pèlerins (zones 51-60)', @@ -10769,6 +10775,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第61~70朝圣路', 'de': 'Pilgers Pfad (Ebenen 61-70)', 'en': 'Pilgrim\'s Traverse (Stones 61-70)', 'fr': 'Le Sanctuaire des pèlerins (zones 61-70)', @@ -10783,6 +10790,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第71~80朝圣路', 'de': 'Pilgers Pfad (Ebenen 71-80)', 'en': 'Pilgrim\'s Traverse (Stones 71-80)', 'fr': 'Le Sanctuaire des pèlerins (zones 71-80)', @@ -10797,6 +10805,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第81~90朝圣路', 'de': 'Pilgers Pfad (Ebenen 81-90)', 'en': 'Pilgrim\'s Traverse (Stones 81-90)', 'fr': 'Le Sanctuaire des pèlerins (zones 81-90)', @@ -10811,6 +10820,7 @@ const data: ZoneInfoType = { 'contentType': 21, 'exVersion': 5, 'name': { + 'cn': '朝圣交错路 第91~100朝圣路', 'de': 'Pilgers Pfad (Ebenen 91-100)', 'en': 'Pilgrim\'s Traverse (Stones 91-100)', 'fr': 'Le Sanctuaire des pèlerins (zones 91-100)', @@ -10905,6 +10915,7 @@ const data: ZoneInfoType = { 'contentType': 4, 'exVersion': 5, 'name': { + 'cn': '护锁刃龙狩猎战', 'de': 'Jagd auf Wächter-Arkveld', 'en': 'The Windward Wilds', 'fr': 'Chasse à l\'Arkveld Gardien', @@ -10967,6 +10978,7 @@ const data: ZoneInfoType = { 'contentType': 4, 'exVersion': 5, 'name': { + 'cn': '护锁刃龙上位狩猎战', 'de': 'Jagd auf Wächter-Arkveld (schwer)', 'en': 'The Windward Wilds (Extreme)', 'fr': 'Chasse à l\'Arkveld Gardien (extrême)', @@ -10981,6 +10993,7 @@ const data: ZoneInfoType = { 'contentType': 39, 'exVersion': 5, 'name': { + 'cn': '卓异的悲寂深想战', 'de': 'Eminente Trauer (variabel)', 'en': 'The Final Verse (Quantum)', 'fr': 'Le Verset final (quantique)', @@ -10995,6 +11008,7 @@ const data: ZoneInfoType = { 'contentType': 39, 'exVersion': 5, 'name': { + 'cn': '卓异的悲寂歼灭战', 'de': 'Eminente Trauer', 'en': 'The Final Verse', 'fr': 'Le Verset final', diff --git a/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts b/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts index 06c12051..58201341 100644 --- a/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts +++ b/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts @@ -160,14 +160,17 @@ const triggerSet: TriggerSet = { outputStrings: { repeat: { en: '${left} => ${front} x3 => ${left} => ${front} x3', + cn: '${left} => ${front} x3 => ${left} => ${front} x3', ko: '${left} 🔜 ${front}x3 🔜 ${left} 🔜 ${front}x3', }, rewind: { en: '${left} => ${front} x6 => ${left}', + cn: '${left} => ${front} x6 => ${left}', ko: '${left} 🔜 ${front}x6 🔜 ${left}', }, avoid: { en: 'Avoid swipes x8', + cn: '避开顺劈 x8', ko: '스와이프x8 피해요!', }, left: Outputs.left, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts index fe6d97ac..d4806242 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts @@ -24,6 +24,7 @@ const triggerSet: TriggerSet = { ], zoneLabel: { en: 'Pilgrim\'s Traverse (All Stones)', + cn: '朝圣交错路 (全朝圣路)', ko: '필그림 트래버스 (모든 층)', }, @@ -221,6 +222,7 @@ const triggerSet: TriggerSet = { de: 'Hast', fr: 'Hâte', ja: 'ヘイスト', + cn: '加速', ko: '헤이스트(Haste)', }, purification: { @@ -228,6 +230,7 @@ const triggerSet: TriggerSet = { de: 'Reinigung', fr: 'Purification', ja: '浄化の守り', + cn: '净化护符', ko: '이상 현상 바리어(Purification)', }, devotion: { @@ -235,6 +238,7 @@ const triggerSet: TriggerSet = { de: 'Weisung', fr: 'Dévotion', ja: '巡礼の導き', + cn: '朝圣的指引', ko: '헌신(Devotion)', }, unknown: Outputs.unknown, @@ -286,6 +290,7 @@ const triggerSet: TriggerSet = { de: 'Wandelwurz', fr: 'Sagacité', ja: '明敏', + cn: '敏慧', ko: '미로뿌리(Mazeroot)', }, barkbalm: { @@ -293,6 +298,7 @@ const triggerSet: TriggerSet = { de: 'Sakralharz', fr: 'Quiétude', ja: '安寧', + cn: '安宁', ko: '나무껍질연고(Barkbalm)', }, poisonfruit: { @@ -300,6 +306,7 @@ const triggerSet: TriggerSet = { de: 'Todesbeeren', fr: 'Fatalité', ja: '宿命', + cn: '宿命', ko: '독과일(Poisonfruit)', }, unknown: Outputs.unknown, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts index 547920bf..f61f9f79 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts @@ -71,10 +71,12 @@ const triggerSet: TriggerSet = { outputStrings: { safe: { en: 'Go ${safe} + Out', + cn: '去 ${safe} + 外', ko: '${safe} + 밖으로', }, unknownSafe: { en: 'Out + Avoid shrublet explosions', + cn: '外 + 避开花小人爆炸', ko: '밖으로 + 덤불 폭발 피해요', }, ...Directions.outputStrings8Dir, @@ -97,6 +99,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Away from jump x4', + cn: '远离跳跃 x4', ko: '점프 피해요x4', }, }, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts index e8ad63ab..1c54f852 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts @@ -71,6 +71,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: '${knockback} ${dir4} => ${dir1}', + cn: '${knockback} ${dir4} => ${dir1}', ko: '${knockback} ${dir4} 🔜 ${dir1}', }, knockback: Outputs.knockback, @@ -95,6 +96,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Seed on YOU', + cn: '种子点名', ko: '내게 씨앗!', }, }, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts index 685affc1..98443a82 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts @@ -31,14 +31,17 @@ const triggerSet: TriggerSet = { outputStrings: { enrage: { en: 'Parasitism', + cn: '捕食行动', ko: '기생충', }, enrageOnYou: { en: 'Parasitism on YOU', + cn: '捕食行动点名', ko: '내게 기생충!', }, enrageOnPlayer: { en: 'Parasitism on ${player}', + cn: '捕食行动点 ${player}', ko: '기생충: ${player}', }, }, @@ -100,14 +103,17 @@ const triggerSet: TriggerSet = { outputStrings: { middleOrOuter: { en: 'Get Middle or Outer ring', + cn: '去中圈或外圈', ko: '중간 / 바깥 링으로', }, innerOrOuter: { en: 'Get Inner or Outer ring', + cn: '去内圈或外圈', ko: '안쪽 / 바깥 링으로', }, innerOrMiddle: { en: 'Get Inner or Middle ring', + cn: '去内圈或中圈', ko: '안쪽 / 중간 링으로', }, }, @@ -145,6 +151,7 @@ const triggerSet: TriggerSet = { right: Outputs.right, text: { en: '${dir}, Behind Hand', + cn: '${dir}, 去手后', ko: '${dir}, 손 뒤로', }, }, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts index f56a5847..a203299b 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts @@ -61,6 +61,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Avoid jump => Out', + cn: '避开跳跃 => 外', ko: '점프 피하고 🔜 밖으로', }, }, @@ -96,6 +97,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: '${mech} x3', + cn: '${mech} x3', ko: '${mech}x3', }, knockback: Outputs.knockback, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts index bf637471..771337ad 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts @@ -73,6 +73,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Stand on a rock', + cn: '站在一块岩石上', ko: '바위 위로 올라서요', }, }, @@ -88,7 +89,7 @@ const triggerSet: TriggerSet = { en: '4x Chasing AoE on YOU', de: '4x verfolgende AoE auf DIR', fr: '4x AoE sur VOUS', - cn: '四连 AOE 点名', + cn: '四连追踪 AOE 点名', ko: '따라오는 장판 x4', }, }, @@ -103,6 +104,8 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Stand in quicksand', + cn: '站在流沙里', + ko: '모래 웅덩이에 올라서요', }, }, }, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts index b62d0bbb..0e39bd6a 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts @@ -115,6 +115,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Sides + Rotate ${rotation}', + cn: '两侧 + ${rotation}旋转', ko: '옆쪽에서 + ${rotation}으로 돌아요', }, clockwise: Outputs.clockwise, @@ -134,14 +135,17 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Cactuar move ${count}', + cn: '仙人掌移动 ${count}', ko: '선인장이 ${count} 이동', }, once: { en: 'Once', + cn: '一次', ko: '한 번', }, twice: { en: 'Twice', + cn: '两次', ko: '두 번', }, }, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts index f02125a9..01127a65 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts @@ -87,6 +87,8 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Away from jump => Get Under or Out', + cn: '远离跳跃 => 去脚下或外面', + ko: '점프 먼곳으로 🔜 밑이나 밖으로', }, }, }, @@ -136,12 +138,18 @@ const triggerSet: TriggerSet = { outputStrings: { sting: { en: 'Final Sting', + cn: '终极针', + ko: '파이널 스팅', }, stingOnYou: { en: 'Final Sting on YOU', + cn: '终极针点名', + ko: '내게 파이널 스팅!', }, stingOnPlayer: { en: 'Final Sting on ${player}', + cn: '终极针点${player}', + ko: '파이널 스팅: ${player}', }, }, }, @@ -195,14 +203,17 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Dodge ${dir}', + cn: '${dir} 躲避', ko: '${dir} 피해요!', }, backFront: { en: 'Back-to-front', + cn: '后到前', ko: '앞에서 뒤로', }, frontBack: { en: 'Front-to-back', + cn: '前到后', ko: '뒤에서 앞으로', }, }, @@ -225,6 +236,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Dodge ${dir}', + cn: '${dir} 躲避', ko: '${dir}으로 피해요!', }, clockwise: Outputs.clockwise, @@ -304,14 +316,17 @@ const triggerSet: TriggerSet = { outputStrings: { repeat: { en: '${dir4} => ${dir1} x3 => ${dir8} => ${dir5} x3', + cn: '${dir4} => ${dir1} x3 => ${dir8} => ${dir5} x3', ko: '${dir4} 🔜 ${dir1}x3 🔜 ${dir8} 🔜 ${dir5}x3', }, rewind: { en: '${dir4} => ${dir1} x6 => ${dir4}', + cn: '${dir4} => ${dir1} x6 => ${dir4}', ko: '${dir4} 🔜 ${dir1}x6 🔜 ${dir4}', }, avoid: { en: 'Avoid swipes x8', + cn: '避开顺劈 x8', ko: '스와이프x8 피해요!', }, left: Outputs.left, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts index 0b1e0b05..f8ca6bbe 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts @@ -20,6 +20,8 @@ const triggerSet: TriggerSet = { ], zoneLabel: { en: 'Pilgrim\'s Traverse Stone 99/The Final Verse', + cn: '朝圣交错路 第99朝圣路/卓异的悲寂歼灭战', + ko: '필그림 트래버스 99층/최종장', }, triggers: [ @@ -58,6 +60,7 @@ const triggerSet: TriggerSet = { text: { en: 'AoE + Stop Moving!', ja: '全体攻撃 + 止まれ!', + cn: 'AOE + 停止移动!', ko: '전체 공격 + 동작 그만!', }, }, @@ -82,6 +85,7 @@ const triggerSet: TriggerSet = { text: { en: 'Laser on YOU', ja: '自分にレーザー', + cn: '激光点名', ko: '내게 레이저!', }, }, @@ -95,6 +99,7 @@ const triggerSet: TriggerSet = { text: { en: 'Avoid laser', ja: 'レーザーを避ける', + cn: '避开激光', ko: '레이저 피해요', }, }, @@ -120,6 +125,7 @@ const triggerSet: TriggerSet = { text: { en: 'Get Light debuff', ja: '光デバフを受ける', + cn: '获取光debuff', ko: '빛🟡 받아요', }, }, @@ -137,6 +143,7 @@ const triggerSet: TriggerSet = { text: { en: 'Get Dark debuff', ja: '闇デバフを受ける', + cn: '获取暗debuff', ko: '어둠⚫️ 받아요', }, }, @@ -170,21 +177,25 @@ const triggerSet: TriggerSet = { text: { en: '${safe}, for later', ja: '${safe}、あとで', + cn: '稍后 ${safe}', ko: '(나중에 ${safe})', }, front: { en: 'Front safe', ja: '前方が安置', + cn: '前方安全', ko: '앞쪽이 안전', }, back: { en: 'Back safe', ja: '後方が安置', + cn: '后方安全', ko: '뒤쪽이 안전', }, side: { en: 'Check safe side', ja: '横の安置を確認', + cn: '观察安全侧面', ko: '좌우 안전한 곳 찾아봐요', }, }, @@ -199,6 +210,7 @@ const triggerSet: TriggerSet = { text: { en: 'Avoid Exaflares', ja: 'エクサフレアを避ける', + cn: '躲避地火', ko: '엑사플레어 피해요', }, }, @@ -226,6 +238,13 @@ const triggerSet: TriggerSet = { 'Eminent Grief': 'エミネントグリーフ', }, }, + { + 'locale': 'cn', + 'replaceSync': { + 'Devoured Eater': '被侵蚀的食罪灵', + 'Eminent Grief': '卓异的悲寂', + }, + }, ], }; diff --git a/ui/raidboss/data/07-dt/dungeon/meso-terminal.txt b/ui/raidboss/data/07-dt/dungeon/meso-terminal.txt index 40f711aa..3c7e4aaf 100644 --- a/ui/raidboss/data/07-dt/dungeon/meso-terminal.txt +++ b/ui/raidboss/data/07-dt/dungeon/meso-terminal.txt @@ -50,7 +50,7 @@ hideall "--sync--" # Executioners # #~~~~~~~~~~~~~~# -# -ii AA3A AA3C AA3D AA4A AA4E AA4F AA50 +# -ii AA3A AA3C AA3D AA3F AA4A AA4E AA4F AA50 # The Executioner timeline is "best-effort" and will quickly # desync depending on player or enemy deaths. @@ -103,11 +103,12 @@ hideall "--sync--" # AA3C --sync--: reposition in own circle # AA3D Shackles of Fate: chain castbar # AA3E Shackles of Fate: chain and draw player in -# AA42 Dismemberment -# AA43 Dismemberment -# AA44 Death Penalty -# AA45 Relentless Torment -# AA46 Relentless Torment +# AA3F Shackles of Fate: chain and draw player in when leaving the circle +# AA42 Dismemberment: blade line AoEs castbar +# AA43 Dismemberment blade line AoEs +# AA44 Death Penalty: dooms target +# AA45 Relentless Torment: tank buster headmarker +# AA46 Relentless Torment: tank buster # AA47 Flaying Flail: triangle of circle AoEs castbar # AA48 Flaying Flail: triangle of circle AoEs # AA49 Peal of Judgment: lightning lines castbar diff --git a/util/coverage/coverage.ts b/util/coverage/coverage.ts index 87db6c7f..d77b777d 100644 --- a/util/coverage/coverage.ts +++ b/util/coverage/coverage.ts @@ -332,9 +332,13 @@ const contentTypeToLabel: { [ContentType.DeepDungeonExtras]: { full: { en: 'Deep Dungeon Extra Content', + cn: '深层迷宫额外内容', + ko: '딥 던전 확장 콘텐츠', }, short: { en: 'DD+', + cn: '深宫+', + ko: '딥 던전+', }, }, [ContentType.Pvp]: { From 6e9a4f5151ba5c71337284641ba34e177c4b9200 Mon Sep 17 00:00:00 2001 From: ksh Date: Fri, 14 Nov 2025 18:54:42 +0900 Subject: [PATCH 4/4] Add German translations and improve existing ones for various triggers in Meso Terminal, Underkeep, Occult Crescent South Horn, R5S, R8N, R8S, Necron EX, Queen Eternal, Seiryu UN, and Pilgrim's Traverse Stones 91-100 --- package.json | 2 +- .../Properties/AssemblyInfo.cs | 4 +- .../CactbotOverlay/Properties/AssemblyInfo.cs | 4 +- resources/netlog_defs.ts | 6 + .../data/02-arr/dungeon/cutters_cry.ts | 1 + ui/raidboss/data/04-sb/trial/seiryu-ex.ts | 12 +- ui/raidboss/data/05-shb/etc/the_diadem.ts | 2 + .../deepdungeon/eureka_orthos_floors_51-60.ts | 3 + .../deepdungeon/pilgrims_traverse_general.ts | 1 + .../pilgrims_traverse_stones_01-10.ts | 25 + .../pilgrims_traverse_stones_11-20.ts | 27 + .../pilgrims_traverse_stones_21-30.ts | 38 ++ .../pilgrims_traverse_stones_31-40.ts | 42 ++ .../pilgrims_traverse_stones_41-50.ts | 42 ++ .../pilgrims_traverse_stones_51-60.ts | 44 ++ .../pilgrims_traverse_stones_61-70.ts | 69 +++ .../pilgrims_traverse_stones_71-80.ts | 136 ++++- .../pilgrims_traverse_stones_81-90.ts | 222 +++++++- .../pilgrims_traverse_stones_91-100.ts | 197 +++++++ .../pilgrims_traverse_the_final_verse.ts | 481 +++++++++++++++--- .../data/07-dt/dungeon/meso-terminal.ts | 13 +- .../data/07-dt/dungeon/the_underkeep.ts | 9 + .../eureka/occult_crescent_south_horn.ts | 177 +++++++ ui/raidboss/data/07-dt/raid/r5s.ts | 2 +- ui/raidboss/data/07-dt/raid/r8n.ts | 1 + ui/raidboss/data/07-dt/raid/r8s.ts | 15 +- ui/raidboss/data/07-dt/trial/necron-ex.ts | 1 - ui/raidboss/data/07-dt/trial/queen-eternal.ts | 15 +- ui/raidboss/data/07-dt/trial/seiryu-un.ts | 12 +- 29 files changed, 1524 insertions(+), 79 deletions(-) create mode 100644 ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_91-100.ts diff --git a/package.json b/package.json index a3ed73bc..64c173f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cactbot-build", - "version": "99.169.0", + "version": "99.170.0", "license": "Apache-2.0", "type": "module", "types": "./types", diff --git a/plugin/CactbotEventSource/Properties/AssemblyInfo.cs b/plugin/CactbotEventSource/Properties/AssemblyInfo.cs index 90f47c1d..ca849fdf 100644 --- a/plugin/CactbotEventSource/Properties/AssemblyInfo.cs +++ b/plugin/CactbotEventSource/Properties/AssemblyInfo.cs @@ -21,5 +21,5 @@ // - Revision // GitHub has only 3 version components, so Revision should always be 0. // CactbotOverlay and CactbotEventSource version should match. -[assembly: AssemblyVersion("99.169.0.0")] -[assembly: AssemblyFileVersion("99.169.0.0")] +[assembly: AssemblyVersion("99.170.0.0")] +[assembly: AssemblyFileVersion("99.170.0.0")] diff --git a/plugin/CactbotOverlay/Properties/AssemblyInfo.cs b/plugin/CactbotOverlay/Properties/AssemblyInfo.cs index 501ff7b9..d544097c 100644 --- a/plugin/CactbotOverlay/Properties/AssemblyInfo.cs +++ b/plugin/CactbotOverlay/Properties/AssemblyInfo.cs @@ -20,5 +20,5 @@ // - Build Number // - Revision // GitHub has only 3 version components, so Revision should always be 0. -[assembly: AssemblyVersion("99.169.0.0")] -[assembly: AssemblyFileVersion("99.169.0.0")] +[assembly: AssemblyVersion("99.170.0.0")] +[assembly: AssemblyFileVersion("99.170.0.0")] diff --git a/resources/netlog_defs.ts b/resources/netlog_defs.ts index 1af00fb6..15d38254 100644 --- a/resources/netlog_defs.ts +++ b/resources/netlog_defs.ts @@ -1413,9 +1413,15 @@ const latestLogDefinitions = { blankFields: [6, 7, 8], playerIds: { 2: null, + 10: null, }, canAnonymize: true, firstOptionalField: undefined, + analysisOptions: { + include: 'filter', + filters: { sourceId: '4.{7}' }, // NPC casts only + combatantIdFields: [2, 10], + }, }, ContentFinderSettings: { type: '265', diff --git a/ui/raidboss/data/02-arr/dungeon/cutters_cry.ts b/ui/raidboss/data/02-arr/dungeon/cutters_cry.ts index 709bd3a1..7e4a7c03 100644 --- a/ui/raidboss/data/02-arr/dungeon/cutters_cry.ts +++ b/ui/raidboss/data/02-arr/dungeon/cutters_cry.ts @@ -10,6 +10,7 @@ const triggerSet: TriggerSet = { zoneId: ZoneId.CuttersCry, comments: { en: 'pre-7.3 rework', + de: 'Vor der 7.3 Überarbeitung', fr: 'Avant le remaniement 7.3', cn: '7.3改版前', ko: '7.3 개편 전', diff --git a/ui/raidboss/data/04-sb/trial/seiryu-ex.ts b/ui/raidboss/data/04-sb/trial/seiryu-ex.ts index 9e50da58..141609c2 100644 --- a/ui/raidboss/data/04-sb/trial/seiryu-ex.ts +++ b/ui/raidboss/data/04-sb/trial/seiryu-ex.ts @@ -47,6 +47,7 @@ const triggerSet: TriggerSet = { outputStrings: { grabTether: { en: 'Grab Tank Tether, Point Cleave Away', + de: 'Nimm Tank-Verbindung, zeige den Cleave weg', fr: 'Prenez le lien Tank, visez l\'extérieur', cn: '接走坦克连线,引导扇形远离人群', ko: '줄 채고, 바깥으로 유도', @@ -240,24 +241,28 @@ const triggerSet: TriggerSet = { dirW: Outputs.west, goToSnakes: { en: 'Go ${dir} Toward Snakes', + de: 'Geh Richtung ${dir} zu den Schlangen', fr: 'Allez ${dir} vers les serpents', cn: '向 ${dir} 蛇走', ko: '뱀 ${dir}으로 가요', }, goToUnknownSnakes: { en: 'Go Toward Snakes', + de: 'Geh zu den Schlangen', fr: 'Allez vers les serpents', cn: '向蛇走', ko: '뱀 쪽으로 가요', }, outOfMiddleTowardSnakes: { en: 'Out Of Middle, Knockback To ${dir}', + de: 'Raus aus der Mitte, Rückstoß nach ${dir}', fr: 'Loin du centre, Poussée vers ${dir}', cn: '离开中间,击退到 ${dir}', ko: '가운데는 위험! ${dir}으로 넉백', }, outOfMiddleUnknownSnakes: { en: 'Out Of Middle, Knockback Toward Snakes', + de: 'Raus aus der Mitte, Rückstoß zu den Schlangen', fr: 'Loin du centre, Poussée vers les serpents', cn: '离开中间,向蛇击退', ko: '가운데는 위험! 뱀 쪽으로 넉백', @@ -355,11 +360,10 @@ const triggerSet: TriggerSet = { timelineReplace: [ { 'locale': 'de', - 'missingTranslations': true, 'replaceSync': { 'Aka-no-shiki': 'Aka no Shiki', 'Ao-no-shiki': 'Ao no Shiki', - 'Blue Orochi': 'blau[a] Orochi', + 'Blue Orochi': 'blau(?:e|er|es|en) Orochi', 'Iwa-no-shiki': 'Iwa no Shiki', 'Numa-no-shiki': 'Numa no Shiki', 'Seiryu': 'Seiryu', @@ -367,6 +371,8 @@ const triggerSet: TriggerSet = { 'Yama-no-shiki': 'Yama no Shiki', }, 'replaceText': { + '--large add spawns--': '--großes Add erscheint--', + '--small adds spawn--': '--kleine Adds erscheinen--', '100-tonze Swing': '100-Tonzen-Schwung', 'Blazing Aramitama': 'Flammende Aramitama', 'Blue Bolt': 'Blauer Blitz', @@ -387,7 +393,7 @@ const triggerSet: TriggerSet = { 'Serpent Descending': 'Niedergang der Schlange', 'Serpent\'s Fang': 'Schlangengiftzahn', 'Strength of Spirit': 'Stärke des Geistes', - 'Summon Shiki': 'Shiki-Beschwörung ', + 'Summon Shiki': 'Shiki-Beschwörung', 'Yama-kagura': 'Yamakagura', }, }, diff --git a/ui/raidboss/data/05-shb/etc/the_diadem.ts b/ui/raidboss/data/05-shb/etc/the_diadem.ts index 9749074c..ac85b6c9 100644 --- a/ui/raidboss/data/05-shb/etc/the_diadem.ts +++ b/ui/raidboss/data/05-shb/etc/the_diadem.ts @@ -9,6 +9,8 @@ const triggerSet: TriggerSet = { zoneId: ZoneId.TheDiadem, comments: { en: 'Timed node spawn alert', + de: 'Zeitliche Sammelstellen Erscheinungsalarm', + fr: 'Alerte de génération de nœud programmée', cn: '限时采集点生成警报', ko: '시간제 노드 출현 알림', }, diff --git a/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts b/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts index 58201341..596e483c 100644 --- a/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts +++ b/ui/raidboss/data/06-ew/deepdungeon/eureka_orthos_floors_51-60.ts @@ -160,16 +160,19 @@ const triggerSet: TriggerSet = { outputStrings: { repeat: { en: '${left} => ${front} x3 => ${left} => ${front} x3', + de: '${left} => ${front} x3 => ${left} => ${front} x3', cn: '${left} => ${front} x3 => ${left} => ${front} x3', ko: '${left} 🔜 ${front}x3 🔜 ${left} 🔜 ${front}x3', }, rewind: { en: '${left} => ${front} x6 => ${left}', + de: '${left} => ${front} x6 => ${left}', cn: '${left} => ${front} x6 => ${left}', ko: '${left} 🔜 ${front}x6 🔜 ${left}', }, avoid: { en: 'Avoid swipes x8', + de: 'Vermeide Schwung x8', cn: '避开顺劈 x8', ko: '스와이프x8 피해요!', }, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts index d4806242..d3589354 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_general.ts @@ -24,6 +24,7 @@ const triggerSet: TriggerSet = { ], zoneLabel: { en: 'Pilgrim\'s Traverse (All Stones)', + de: 'Pilgers Pfad (Alle Steine)', cn: '朝圣交错路 (全朝圣路)', ko: '필그림 트래버스 (모든 층)', }, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts index f61f9f79..0a81fa5c 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_01-10.ts @@ -71,11 +71,13 @@ const triggerSet: TriggerSet = { outputStrings: { safe: { en: 'Go ${safe} + Out', + de: 'Geh nach ${safe} + Raus', cn: '去 ${safe} + 外', ko: '${safe} + 밖으로', }, unknownSafe: { en: 'Out + Avoid shrublet explosions', + de: 'Raus + Vermeide Blumling Explosionen', cn: '外 + 避开花小人爆炸', ko: '밖으로 + 덤불 폭발 피해요', }, @@ -99,12 +101,35 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Away from jump x4', + de: 'Weg vom Sprung x4', cn: '远离跳跃 x4', ko: '점프 피해요x4', }, }, }, ], + timelineReplace: [ + { + 'locale': 'de', + 'replaceSync': { + 'Ornamental Leafman': 'Blumerich', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Ornamental Leafman': 'enfleuri', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Ornamental Leafman': '花人', + }, + }, + ], }; export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts index 1c54f852..6e4bfe4c 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_11-20.ts @@ -42,6 +42,9 @@ const triggerSet: TriggerSet = { // 398 = back right foot type: 'GainsEffect', netRegex: { effectId: '808', target: 'Forgiven Emulation', capture: true }, + // rarely, there is a weird doubling of the 808 status loglines + // (possibly due to high latency or server load); suppress to avoid this + suppressSeconds: 2.5, infoText: (data, matches, output) => { const count = matches.count; (data.footOrder ??= []).push(count); @@ -71,6 +74,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: '${knockback} ${dir4} => ${dir1}', + de: '${knockback} ${dir4} => ${dir1}', cn: '${knockback} ${dir4} => ${dir1}', ko: '${knockback} ${dir4} 🔜 ${dir1}', }, @@ -96,12 +100,35 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Seed on YOU', + de: 'Samen auf DIR', cn: '种子点名', ko: '내게 씨앗!', }, }, }, ], + timelineReplace: [ + { + 'locale': 'de', + 'replaceSync': { + 'Forgiven Emulation': 'geläutert(?:e|er|es|en) Wetteifer', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Forgiven Emulation': 'imitation pardonnée', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Forgiven Emulation': 'フォーギヴン・エミュレーション', + }, + }, + ], }; export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts index 98443a82..f6b66496 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_21-30.ts @@ -31,16 +31,19 @@ const triggerSet: TriggerSet = { outputStrings: { enrage: { en: 'Parasitism', + de: 'Instinkt des Räubers', cn: '捕食行动', ko: '기생충', }, enrageOnYou: { en: 'Parasitism on YOU', + de: 'Instinkt des Räubers auf DIR', cn: '捕食行动点名', ko: '내게 기생충!', }, enrageOnPlayer: { en: 'Parasitism on ${player}', + de: 'Instinkt des Räubers auf ${player}', cn: '捕食行动点 ${player}', ko: '기생충: ${player}', }, @@ -103,16 +106,19 @@ const triggerSet: TriggerSet = { outputStrings: { middleOrOuter: { en: 'Get Middle or Outer ring', + de: 'Geh zum mittleren oder äußeren Ring', cn: '去中圈或外圈', ko: '중간 / 바깥 링으로', }, innerOrOuter: { en: 'Get Inner or Outer ring', + de: 'Geh zum inneren oder äußeren Ring', cn: '去内圈或外圈', ko: '안쪽 / 바깥 링으로', }, innerOrMiddle: { en: 'Get Inner or Middle ring', + de: 'Geh zum inneren oder mittleren Ring', cn: '去内圈或中圈', ko: '안쪽 / 중간 링으로', }, @@ -151,6 +157,7 @@ const triggerSet: TriggerSet = { right: Outputs.right, text: { en: '${dir}, Behind Hand', + de: '${dir}, hinter der Hand', cn: '${dir}, 去手后', ko: '${dir}, 손 뒤로', }, @@ -175,6 +182,37 @@ const triggerSet: TriggerSet = { }, }, ], + timelineReplace: [ + { + 'locale': 'de', + 'replaceSync': { + 'Forgiven Ambition': 'geläutert(?:e|er|es|en) Begierde', + 'Forgiven Intolerance': 'geläutert(?:e|er|es|en) Intoleranz', + 'Forgiven Treachery': 'geläutert(?:e|er|es|en) Verrat', + 'Traverse Clionid': 'Wallfahrt-Clionid', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Forgiven Ambition': 'ambition pardonnée', + 'Forgiven Intolerance': 'intolérance pardonnée', + 'Forgiven Treachery': 'traîtrise pardonnée', + 'Traverse Clionid': 'clionide du pèlerinage', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Forgiven Ambition': 'フォーギヴン・アンビション', + 'Forgiven Intolerance': 'フォーギヴン・イントーラランス', + 'Forgiven Treachery': 'フォーギヴン・トレチャリー', + 'Traverse Clionid': 'トラバース・クリオニッド', + }, + }, + ], }; export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts index a203299b..c0477265 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_31-40.ts @@ -61,6 +61,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Avoid jump => Out', + de: 'Sprung vermeiden => Raus', cn: '避开跳跃 => 外', ko: '점프 피하고 🔜 밖으로', }, @@ -97,6 +98,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: '${mech} x3', + de: '${mech} x3', cn: '${mech} x3', ko: '${mech}x3', }, @@ -117,6 +119,46 @@ const triggerSet: TriggerSet = { response: Responses.getIn(), }, ], + timelineReplace: [ + { + 'locale': 'de', + 'replaceSync': { + 'Forgiven Naivety': 'geläutert(?:e|er|es|en) Naivität', + 'Forgiven Petulance': 'geläutert(?:e|er|es|en) Launenhaftigkeit', + 'Forgiven Plague': 'geläutert(?:e|er|es|en) Plage', + 'Forgiven Prejudice': 'geläutert(?:e|er|es|en) Voreingenommenheit', + 'Traverse Inquisitor': 'Wallfahrt-Inquisitor', + 'Traverse Pegasus': 'Wallfahrt-Pegasus', + 'Traverse Soldierstone': 'Wallfahrt-Steinsoldat', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Forgiven Naivety': 'naïveté pardonnée', + 'Forgiven Petulance': 'irascibilité pardonnée', + 'Forgiven Plague': 'peste pardonnée', + 'Forgiven Prejudice': 'préjugé pardonné', + 'Traverse Inquisitor': 'inquisiteur du pèlerinage', + 'Traverse Pegasus': 'pégase du pèlerinage', + 'Traverse Soldierstone': 'soldat de pierre du pèlerinage', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Forgiven Naivety': 'フォーギヴン・ナイヴテイ', + 'Forgiven Petulance': 'フォーギヴン・ペチュランス', + 'Forgiven Plague': 'フォーギヴン・プレイグ', + 'Forgiven Prejudice': 'フォーギヴン・プレジュディス', + 'Traverse Inquisitor': 'トラバース・インクイジター', + 'Traverse Pegasus': 'トラバース・ペガサス', + 'Traverse Soldierstone': 'トラバース・ストーンソルジャー', + }, + }, + ], }; export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts index 771337ad..cbb36f68 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_41-50.ts @@ -73,6 +73,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Stand on a rock', + de: 'Steh auf einem Stein', cn: '站在一块岩石上', ko: '바위 위로 올라서요', }, @@ -104,12 +105,53 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Stand in quicksand', + de: 'Im Treibsand stehen', cn: '站在流沙里', ko: '모래 웅덩이에 올라서요', }, }, }, ], + timelineReplace: [ + { + 'locale': 'de', + 'replaceSync': { + 'Ogbunabali': 'Ogbunabali', + 'Traverse Anaconda': 'Wallfahrt-Anakonda', + 'Traverse Petreffigy': 'Wallfahrt-Bildnis', + 'Traverse Pincerbeak': 'Wallfahrt-Zwicker', + 'Traverse Triffid': 'Wallfahrt-Triffid', + 'Traverse Troubadour': 'Wallfahrt-Tolba', + 'Traverse Weapon': 'Wallfahrt-Waffe', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Ogbunabali': 'Ogbunabali', + 'Traverse Anaconda': 'anaconda du pèlerinage', + 'Traverse Petreffigy': 'effigie du pèlerinage', + 'Traverse Pincerbeak': 'bec-pinceur du pèlerinage', + 'Traverse Triffid': 'triffide du pèlerinage', + 'Traverse Troubadour': 'tolba du pèlerinage', + 'Traverse Weapon': 'arme du pèlerinage', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Ogbunabali': 'オグブナバリ', + 'Traverse Anaconda': 'トラバース・アナコンダ', + 'Traverse Petreffigy': 'トラバース・エフィジィ', + 'Traverse Pincerbeak': 'トラバース・ピンサービーク', + 'Traverse Triffid': 'トラバース・トリフィド', + 'Traverse Troubadour': 'トラバース・トルバ', + 'Traverse Weapon': 'トラバース・ウェポン', + }, + }, + ], }; export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts index 0e39bd6a..92aeef69 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_51-60.ts @@ -115,6 +115,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Sides + Rotate ${rotation}', + de: 'Seiten + Im ${rotation} rotieren', cn: '两侧 + ${rotation}旋转', ko: '옆쪽에서 + ${rotation}으로 돌아요', }, @@ -135,22 +136,65 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Cactuar move ${count}', + de: 'Kaktor Bewegung - ${count}', cn: '仙人掌移动 ${count}', ko: '선인장이 ${count} 이동', }, once: { en: 'Once', + de: 'Einmal', cn: '一次', ko: '한 번', }, twice: { en: 'Twice', + de: 'Zweimal', cn: '两次', ko: '두 번', }, }, }, ], + timelineReplace: [ + { + 'locale': 'de', + 'replaceSync': { + 'Ancestral Maliktender': 'Malikkaktor-Ahn', + 'Traverse Gigant': 'Wallfahrt-Gigant', + 'Traverse Howler': 'Wallfahrt-Heuler', + 'Traverse Monitor': 'Wallfahrt-Waran', + 'Traverse Phorusrhacos': 'Wallfahrt-Phorusrhacos', + 'Traverse Saichania': 'Wallfahrt-Saichania', + 'Traverse Sand Serpent': 'Wallfahrt-Sandschlange', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Ancestral Maliktender': 'Malikpampa l\'ancien', + 'Traverse Gigant': 'géant du pèlerinage', + 'Traverse Howler': 'hurleur du pèlerinage', + 'Traverse Monitor': 'varan du pèlerinage', + 'Traverse Phorusrhacos': 'phorusrhacos du pèlerinage', + 'Traverse Saichania': 'saichania du pèlerinage', + 'Traverse Sand Serpent': 'serpent des sables du pèlerinage', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Ancestral Maliktender': '元祖マリクテンダー', + 'Traverse Gigant': 'トラバース・ギガント', + 'Traverse Howler': 'トラバース・ハウラー', + 'Traverse Monitor': 'トラバース・モニター', + 'Traverse Phorusrhacos': 'トラバース・フォルスラコス', + 'Traverse Saichania': 'トラバース・サイカニア', + 'Traverse Sand Serpent': 'トラバース・サンドサーペント', + }, + }, + ], }; export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts index 01127a65..00841cc6 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_61-70.ts @@ -87,6 +87,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Away from jump => Get Under or Out', + de: 'Weg vom Sprung => Geh Unter oder Raus', cn: '远离跳跃 => 去脚下或外面', ko: '점프 먼곳으로 🔜 밑이나 밖으로', }, @@ -138,16 +139,19 @@ const triggerSet: TriggerSet = { outputStrings: { sting: { en: 'Final Sting', + de: 'Schlussstich', cn: '终极针', ko: '파이널 스팅', }, stingOnYou: { en: 'Final Sting on YOU', + de: 'Schlussstich auf DIR', cn: '终极针点名', ko: '내게 파이널 스팅!', }, stingOnPlayer: { en: 'Final Sting on ${player}', + de: 'Schlussstich auf ${player}', cn: '终极针点${player}', ko: '파이널 스팅: ${player}', }, @@ -203,16 +207,19 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Dodge ${dir}', + de: 'Ausweichen ${dir}', cn: '${dir} 躲避', ko: '${dir} 피해요!', }, backFront: { en: 'Back-to-front', + de: 'Hinten-nach-Vorne', cn: '后到前', ko: '앞에서 뒤로', }, frontBack: { en: 'Front-to-back', + de: 'Vorne-nach-Hinten', cn: '前到后', ko: '뒤에서 앞으로', }, @@ -236,6 +243,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Dodge ${dir}', + de: 'Ausweichen ${dir}', cn: '${dir} 躲避', ko: '${dir}으로 피해요!', }, @@ -316,16 +324,19 @@ const triggerSet: TriggerSet = { outputStrings: { repeat: { en: '${dir4} => ${dir1} x3 => ${dir8} => ${dir5} x3', + de: '${dir4} => ${dir1} x3 => ${dir8} => ${dir5} x3', cn: '${dir4} => ${dir1} x3 => ${dir8} => ${dir5} x3', ko: '${dir4} 🔜 ${dir1}x3 🔜 ${dir8} 🔜 ${dir5}x3', }, rewind: { en: '${dir4} => ${dir1} x6 => ${dir4}', + de: '${dir4} => ${dir1} x6 => ${dir4}', cn: '${dir4} => ${dir1} x6 => ${dir4}', ko: '${dir4} 🔜 ${dir1}x6 🔜 ${dir4}', }, avoid: { en: 'Avoid swipes x8', + de: 'Vermeide Schwung x8', cn: '避开顺劈 x8', ko: '스와이프x8 피해요!', }, @@ -336,6 +347,64 @@ const triggerSet: TriggerSet = { }, }, ], + timelineReplace: [ + { + 'locale': 'de', + 'replaceSync': { + 'Forgiven Attachment': 'geläutert(?:e|er|es|en) Anhänglichkeit', + 'Forgiven Contention': 'geläutert(?:e|er|es|en) Streitlust', + 'Forgiven Doubt': 'geläutert(?:e|er|es|en) Zweifel', + 'Forgiven Grudge': 'geläutert(?:e|er|es|en) Missgunst', + 'Forgiven Imparity': 'geläutert(?:e|er|es|en) Ungleichheit', + 'Forgiven Riot': 'geläutert(?:e|er|es|en) Randale', + 'Forgiven Voracity': 'geläutert(?:e|er|es|en) Unersättlichkeit', + 'Forgiven Zeal': 'geläutert(?:e|er|es|en) Übereifer', + 'Traverse Cliffmole': 'Wallfahrt-Klippenmull', + 'Traverse Gnome': 'Wallfahrt-Gnom', + 'Traverse Ngozi': 'Wallfahrt-Ngozi', + 'Traverse Queen': 'Wallfahrt-Bienenkönigin', + 'Traverse Talos': 'Wallfahrt-Talos', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Forgiven Attachment': 'attachement pardonné', + 'Forgiven Contention': 'contention pardonnée', + 'Forgiven Doubt': 'doute pardonné', + 'Forgiven Grudge': 'rancune pardonnée', + 'Forgiven Imparity': 'inégalité pardonnée', + 'Forgiven Riot': 'révolte pardonnée', + 'Forgiven Voracity': 'voracité pardonnée', + 'Forgiven Zeal': 'zèle pardonné', + 'Traverse Cliffmole': 'taupe des falaises du pèlerinage', + 'Traverse Gnome': 'gnome du pèlerinage', + 'Traverse Ngozi': 'ngozi du pèlerinage', + 'Traverse Queen': 'reine des abeilles du pèlerinage', + 'Traverse Talos': 'talos du pèlerinage', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Forgiven Attachment': 'フォーギヴン・アタッチメント', + 'Forgiven Contention': 'フォーギヴン・コンテンション', + 'Forgiven Doubt': 'フォーギヴン・ダウト', + 'Forgiven Grudge': 'フォーギヴン・グラッジ', + 'Forgiven Imparity': 'フォーギヴン・イムパリティー', + 'Forgiven Riot': 'フォーギヴン・ライオティング', + 'Forgiven Voracity': 'フォーギヴン・ヴォラシティ', + 'Forgiven Zeal': 'フォーギヴン・ズィール', + 'Traverse Cliffmole': 'トラバース・クリフモール', + 'Traverse Gnome': 'トラバース・ノーム', + 'Traverse Ngozi': 'トラバース・ンゴツィ', + 'Traverse Queen': 'トラバース・クイーンビー', + 'Traverse Talos': 'トラバース・タロース', + }, + }, + ], }; export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_71-80.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_71-80.ts index 4cc16a2d..aa64533b 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_71-80.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_71-80.ts @@ -5,6 +5,9 @@ import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; +// Pilgrim's Traverse Stones 71-80 +// TODO: Forgiven Profanity Static Shock safe spot + export interface Data extends RaidbossData { prowlingDeath?: 'shadowOfDeath' | 'nowhereToRun'; } @@ -12,7 +15,136 @@ export interface Data extends RaidbossData { const triggerSet: TriggerSet = { id: 'PilgrimsTraverseStones71_80', zoneId: ZoneId.PilgrimsTraverseStones71_80, + triggers: [ + // ---------------- Stone 71-79 Mobs ---------------- + { + id: 'PT 71-80 Traverse Scissorjaws Sandblast', + type: 'StartsUsing', + netRegex: { id: 'AEE1', source: 'Traverse Scissorjaws', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 71-80 Forgiven Unbelief Gravel Shower', + type: 'StartsUsing', + netRegex: { id: 'AEDB', source: 'Forgiven Unbelief', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 71-80 Traverse Huldu Fracture', + type: 'StartsUsing', + netRegex: { id: 'A712', source: 'Traverse Huldu', capture: false }, + response: Responses.outOfMelee(), + }, + { + id: 'PT 71-80 Traverse Huldu Self-destruct', + // explodes in a letal PBAoE after death + type: 'StartsUsing', + netRegex: { id: 'A713', source: 'Traverse Huldu', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 71-80 Forgiven Spite Growing Circles of Ablution', + type: 'StartsUsing', + netRegex: { id: 'A652', source: 'Forgiven Spite', capture: false }, + response: Responses.getOutThenIn(), + }, + { + id: 'PT 71-80 Forgiven Spite Shrinking Circles of Ablution', + type: 'StartsUsing', + netRegex: { id: 'A6FC', source: 'Forgiven Spite', capture: false }, + response: Responses.getInThenOut(), + }, + { + id: 'PT 71-80 Forgiven Arrogance Hail of Heels', + type: 'StartsUsing', + netRegex: { id: 'AED7', source: 'Forgiven Arrogance', capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Get Behind x4', + ko: '엉댕이로x4', + }, + }, + }, + { + id: 'PT 71-80 Traverse Worm Earthquake', + type: 'StartsUsing', + netRegex: { id: 'AEDF', source: 'Traverse Worm', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 71-80 Forgiven Dissention Mighty Spin', + type: 'StartsUsing', + netRegex: { id: 'A618', source: 'Forgiven Dissention', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 71-80 Forgiven Dissention Trounce', + type: 'StartsUsing', + netRegex: { id: 'A61A', source: 'Forgiven Dissention', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 71-80 Forgiven Corruption Forward Barrage', + type: 'StartsUsing', + netRegex: { id: 'A651', source: 'Forgiven Corruption', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 71-80 Forgiven Corruption Rolling Barrage', + type: 'StartsUsing', + netRegex: { id: 'A61B', source: 'Forgiven Corruption', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 4, + alertText: (_data, matches, output) => output.breakLOS!({ name: matches.source }), + outputStrings: { + breakLOS: { + en: 'Break line-of-sight to ${name}', + de: 'Unterbreche Sichtlinie zu ${name}', + fr: 'Masquez le champ de vision vers ${name}', + ja: '${name}の視線から隠れる', + cn: '利用掩体卡 ${name} 的视线', + ko: '시선 잘라요: ${name}', + }, + }, + }, + { + id: 'PT 71-80 Traverse Amemet Topple', + type: 'StartsUsing', + netRegex: { id: 'AEDD', source: 'Traverse Amemet', capture: false }, + response: Responses.outOfMelee(), + }, + { + id: 'PT 71-80 Forgiven Slander Metamorphic Blast', + type: 'StartsUsing', + netRegex: { id: 'AED9', source: 'Forgiven Slander', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 71-80 Forgiven Slander Orogenic Storm', + // medium-sized AoE, locks-on to a player ground position at start of cast + type: 'StartsUsing', + netRegex: { id: 'AEDA', source: 'Forgiven Slander', capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Avoid AoE', + ko: '장판 피해요!', + }, + }, + }, + { + id: 'PT 71-80 Forgiven Vanity Cross Lasers', + type: 'StartsUsing', + netRegex: { id: 'AED5', source: 'Forgiven Vanity', capture: false }, + response: Responses.getIntercards(), + }, + { + id: 'PT 71-80 Forgiven Vanity Peripheral Lasers', + type: 'StartsUsing', + netRegex: { id: 'AED6', source: 'Forgiven Vanity', capture: false }, + response: Responses.getIn(), + }, // ---------------- Stone 80 Boss: Forgiven Profanity ---------------- // A9C9 = Roaring Ring dummy self-cast, donut + front cleave // A9CB = Roaring Ring dummy self-cast, donut + back cleave @@ -44,7 +176,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: '${in} + ${backFront}', - ko: '${backFront} + ${in}', + ko: '${backFront}+${in}', }, back: Outputs.back, front: Outputs.front, @@ -70,7 +202,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: '${out} + ${backFront}', - ko: '${backFront} + ${out}', + ko: '${backFront}+${out}', }, back: Outputs.back, front: Outputs.front, diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_81-90.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_81-90.ts index 8edcd8bf..e75d19fa 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_81-90.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_81-90.ts @@ -1,8 +1,12 @@ +import Conditions from '../../../../../resources/conditions'; import { Responses } from '../../../../../resources/responses'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; +// Pilgrim's Traverse Stones 81-90 +// TODO: Malacoda Arcane Beacon safespots + export type Data = RaidbossData; const triggerSet: TriggerSet = { @@ -10,18 +14,232 @@ const triggerSet: TriggerSet = { zoneId: ZoneId.PilgrimsTraverseStones81_90, triggers: [ + // ---------------- Stone 81-89 Mobs ---------------- + { + id: 'PT 81-90 Traverse Cubus Dark II', + type: 'StartsUsing', + netRegex: { id: 'AEE7', source: 'Traverse Cubus', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 81-90 Traverse Gnoll Nox Blast', + type: 'StartsUsing', + netRegex: { id: 'AEE6', source: 'Traverse Gnoll', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 81-90 Traverse Gnoll Maul', + // enrage on targeted player, goes through walls + type: 'StartsUsing', + netRegex: { id: 'AEE5', source: 'Traverse Gnoll', capture: true }, + alertText: (data, matches, output) => { + const target = matches.target; + if (target === undefined) + return output.maul!(); + if (target === data.me) + return output.maulOnYou!(); + return output.maulOnPlayer!({ player: data.party.member(target) }); + }, + outputStrings: { + maul: { + en: 'Maul', + ko: '마울', + }, + maulOnYou: { + en: 'Maul on YOU', + ko: '내게 마울', + }, + maulOnPlayer: { + en: 'Maul on ${player}', + ko: '마울: ${player}', + }, + }, + }, + { + id: 'PT 81-90 Invoked Gremlin Claw', + type: 'StartsUsing', + netRegex: { id: 'AEE2', source: 'Invoked Gremlin', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 81-90 Traverse Rider Valfodr', + type: 'StartsUsing', + netRegex: { id: 'A937', source: 'Traverse Rider', capture: true }, + response: Responses.knockbackOn(), + }, + { + id: 'PT 81-90 Traverse Rider Storm Slash', + type: 'StartsUsing', + netRegex: { id: 'A939', source: 'Traverse Rider', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 81-90 Invoked Arch Demon Abyssal Swing', + type: 'StartsUsing', + netRegex: { id: 'AEEC', source: 'Invoked Arch Demon', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 81-90 Invoked Satana Blizzard Trap', + type: 'StartsUsing', + netRegex: { id: 'AEEB', source: 'Invoked Satana', capture: false }, + response: Responses.outOfMelee(), + }, + { + id: 'PT 81-90 Invoked Succubus Passions\' Heat', + // applies 3C0 Pyretic in an AoE for 3s, lethal damage if doing anything + type: 'StartsUsing', + netRegex: { id: 'A93A', source: 'Invoked Succubus', capture: true }, + alarmText: (data, matches, output) => { + const target = matches.target; + if (target === undefined) + return output.heat!(); + if (target === data.me) + return output.heatOnYou!(); + return output.heatOnPlayer!({ player: data.party.member(target) }); + }, + outputStrings: { + heat: { + en: 'Pyretic, Avoid AoE', + ko: '파이레틱, 장판 피해욧', + }, + heatOnYou: { + en: 'Pyretic on YOU, Away from Group => Stop Everything!', + ko: '내게 파이레틱, 혼자 멀리 🔜 그대로 멈춰욧!', + }, + heatOnPlayer: { + en: 'Pyretic on ${player}, Avoid AoE', + ko: '파이레틱: ${player}, 장판 피해욧', + }, + }, + }, + { + id: 'PT 81-90 Invoked Succubus Passions\' Heat Pyretic', + // 3C0 = Pyretic, lethal damage if doing anything + type: 'GainsEffect', + netRegex: { effectId: '3C0', capture: true }, + condition: Conditions.targetIsYou(), + durationSeconds: (_data, matches) => parseFloat(matches.duration), + countdownSeconds: (_data, matches) => parseFloat(matches.duration), + response: Responses.stopEverything(), + }, + { + id: 'PT 81-90 Invoked Troubadour Dark II', + type: 'StartsUsing', + netRegex: { id: 'AEF3', source: 'Invoked Troubadour', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 81-90 Invoked Troubadour Inner Demons', + type: 'StartsUsing', + netRegex: { id: 'AEF4', source: 'Invoked Troubadour', capture: false }, + response: Responses.outOfMelee(), + }, + { + id: 'PT 81-90 Invoked Cerberus Lightning Bolt', + // medium-sized AoE, locks-on to a player ground position at start of cast + type: 'StartsUsing', + netRegex: { id: 'AEF0', source: 'Invoked Cerberus', capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Avoid AoE', + ko: '장판 피해욧', + }, + }, + }, + { + id: 'PT 81-90 Invoked Cerberus Hellclaw', + type: 'StartsUsing', + netRegex: { id: 'AEF1', source: 'Invoked Cerberus', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 81-90 Invoked Cerberus Tail Blow', + type: 'StartsUsing', + netRegex: { id: 'AEF2', source: 'Invoked Cerberus', capture: false }, + response: Responses.goFront(), + }, + { + id: 'PT 81-90 Invoked Humbaba Triple/Quadruple Blow', + type: 'StartsUsing', + netRegex: { id: ['A93B', 'A93C'], source: 'Invoked Humbaba', capture: true }, + infoText: (_data, matches, output) => { + const blows = matches.id === 'A93B' ? 3 : 4; + return output.text!({ count: blows }); + }, + outputStrings: { + text: { + en: '${count}x attacks => Get Behind', + ko: '공격x${count} 🔜 엉댕이로', + }, + }, + }, + { + id: 'PT 81-90 Invoked Humbaba Bellows', + type: 'StartsUsing', + netRegex: { id: 'AD05', source: 'Invoked Humbaba', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 81-90 Invoked Caym Double Hex Eye', + type: 'StartsUsing', + netRegex: { id: 'AEEE', source: 'Invoked Caym', capture: true }, + response: Responses.lookAwayFromSource(), + }, + { + id: 'PT 81-90 Invoked Baal Incinerating Lahar', + type: 'StartsUsing', + netRegex: { id: 'A87D', source: 'Invoked Baal', capture: true }, + delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 4, + alertText: (_data, matches, output) => output.breakLOS!({ name: matches.source }), + outputStrings: { + breakLOS: { + en: 'Break line-of-sight to ${name}', + de: 'Unterbreche Sichtlinie zu ${name}', + fr: 'Masquez le champ de vision vers ${name}', + ja: '${name}の視線を遮れ', + ko: '시선 잘라요: ${name}', + }, + }, + }, + { + id: 'PT 81-90 Invoked Baal Abyssal Ray', + // goes through walls + type: 'StartsUsing', + netRegex: { id: 'A87E', source: 'Invoked Baal', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 81-90 Traverse Cama Claw and Tail', + type: 'StartsUsing', + netRegex: { id: 'A87C', source: 'Traverse Cama', capture: false }, + response: Responses.goSides(), + }, // ---------------- Stone 90 Boss: Malacoda ---------------- { id: 'PT 81-90 Malacoda Backhand Right', type: 'StartsUsing', netRegex: { id: 'ACDA', source: 'Malacoda', capture: false }, - response: Responses.goLeft(), + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Get Behind + Left', + ko: '뒤+왼쪽으로', + }, + }, }, { id: 'PT 81-90 Malacoda Backhand Left', type: 'StartsUsing', netRegex: { id: 'ACDB', source: 'Malacoda', capture: false }, - response: Responses.goRight(), + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Get Behind + Right', + ko: '뒤+오른쪽으로', + }, + }, }, { id: 'PT 81-90 Malacoda Fore-hind Folly', diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_91-100.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_91-100.ts new file mode 100644 index 00000000..9053c567 --- /dev/null +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_stones_91-100.ts @@ -0,0 +1,197 @@ +import Conditions from '../../../../../resources/conditions'; +import { Responses } from '../../../../../resources/responses'; +import ZoneId from '../../../../../resources/zone_id'; +import { RaidbossData } from '../../../../../types/data'; +import { TriggerSet } from '../../../../../types/trigger'; + +// Pilgrim's Traverse Stones 91-100 + +export type Data = RaidbossData; + +const triggerSet: TriggerSet = { + id: 'PilgrimsTraverseStones91_100', + zoneId: ZoneId.PilgrimsTraverseStones91_100, + + triggers: [ + // ---------------- Stone 91-98 Mobs ---------------- + { + id: 'PT 91-100 Invoked Dreamer Dark Vision', + // goes through walls + type: 'StartsUsing', + netRegex: { id: 'AD3D', source: 'Invoked Dreamer', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 91-100 Invoked Dreamer Endless Nightmare', + type: 'StartsUsing', + netRegex: { id: 'AD3E', source: 'Invoked Dreamer', capture: false }, + response: Responses.getOut(), + }, + { + id: 'PT 91-100 Traverse Ya-te-veo Rotten Stench', + // goes through walls + type: 'StartsUsing', + netRegex: { id: 'ADD4', source: 'Traverse Ya-te-veo', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 91-100 Traverse Triffid Creeping Ivy', + type: 'StartsUsing', + netRegex: { id: 'ADD3', source: 'Traverse Triffid', capture: false }, + response: Responses.awayFromFront(), + }, + { + id: 'PT 91-100 Invoked Poppet Whinge', + type: 'StartsUsing', + netRegex: { id: 'ADE0', source: 'Invoked Poppet', capture: false }, + response: Responses.outOfMelee(), + }, + { + id: 'PT 91-100 Invoked Sawtooth Honeyed Front', + type: 'StartsUsing', + netRegex: { id: 'AD44', source: 'Invoked Sawtooth', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 91-100 Invoked Sawtooth Honeyed Left', + type: 'StartsUsing', + netRegex: { id: 'AD45', source: 'Invoked Sawtooth', capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Go Front + Right', + ko: '앞+오른쪽으로', + }, + }, + }, + { + id: 'PT 91-100 Invoked Sawtooth Honeyed Right', + type: 'StartsUsing', + netRegex: { id: 'AD46', source: 'Invoked Sawtooth', capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Go Front + Left', + ko: '앞+왼쪽으로', + }, + }, + }, + { + id: 'PT 91-100 Invoked Bachelor Arachne Web', + type: 'StartsUsing', + netRegex: { id: 'AD41', source: 'Invoked Bachelor', capture: true }, + condition: Conditions.targetIsYou(), + alertText: (_data, matches, output) => output.breakLOS!({ name: matches.source }), + outputStrings: { + breakLOS: { + en: 'Break line-of-sight to ${name}', + de: 'Unterbreche Sichtlinie zu ${name}', + fr: 'Masquez le champ de vision vers ${name}', + ja: '${name}の視線から隠れる', + cn: '利用掩体卡 ${name} 的视线', + ko: '시선 잘라요: ${name}', + }, + }, + }, + { + id: 'PT 91-100 Traverse Warg Triple/Quadruple Skull Dasher', + type: 'StartsUsing', + netRegex: { id: ['AD33', 'AD34'], source: 'Traverse Warg', capture: true }, + infoText: (_data, matches, output) => { + const blows = matches.id === 'AD33' ? 3 : 4; + return output.text!({ count: blows }); + }, + outputStrings: { + text: { + en: '${count}x attacks => Out of Melee', + ko: '공격x${count} 🔜 근접 피해요', + }, + }, + }, + { + id: 'PT 91-100 Traverse Warg Heavy Smash', + type: 'StartsUsing', + netRegex: { id: 'AD36', source: 'Traverse Warg', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 91-100 Invoked Dahak Tail Drive', + type: 'StartsUsing', + netRegex: { id: 'ADDB', source: 'Invoked Dahak', capture: false }, + response: Responses.goFront(), + }, + { + id: 'PT 91-100 Invoked Dahak Lithic Breath', + // might bait Tail Drive if you dodge behind + type: 'StartsUsing', + netRegex: { id: 'ADDC', source: 'Invoked Dahak', capture: false }, + response: Responses.goSides(), + }, + { + id: 'PT 91-100 Invoked Archaeodemon Unholy Darkness', + // ground-targeted medium AoE with late telegraph + type: 'StartsUsing', + netRegex: { id: 'ADE2', source: 'Invoked Archaeodemon', capture: false }, + alertText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Avoid AoE', + ko: '장판 피해욧', + }, + }, + }, + { + id: 'PT 91-100 Invoked Archaeodemon Karma', + type: 'StartsUsing', + netRegex: { id: 'ADE3', source: 'Invoked Archaeodemon', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 91-100 Traverse Malevolence Smashing Blow', + type: 'StartsUsing', + netRegex: { id: 'ADE1', source: 'Traverse Malevolence', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 91-100 Invoked Gusion Right Smite', + type: 'StartsUsing', + netRegex: { id: 'AD39', source: 'Invoked Gusion', capture: false }, + response: Responses.goLeftThenRight(), + }, + { + id: 'PT 91-100 Invoked Gusion Left Smite', + type: 'StartsUsing', + netRegex: { id: 'AD3B', source: 'Invoked Gusion', capture: false }, + response: Responses.goRightThenLeft(), + }, + { + id: 'PT 91-100 Invoked Acheron Authority\'s Edge Right', + type: 'StartsUsing', + netRegex: { id: 'ADDD', source: 'Invoked Acheron', capture: false }, + response: Responses.goLeft(), + }, + { + id: 'PT 91-100 Invoked Acheron Authority\'s Edge Left', + type: 'StartsUsing', + netRegex: { id: 'ADDE', source: 'Invoked Acheron', capture: false }, + response: Responses.goRight(), + }, + { + id: 'PT 91-100 Invoked Destrudo Stare', + // goes through walls + type: 'StartsUsing', + netRegex: { id: 'AD42', source: 'Invoked Destrudo', capture: false }, + response: Responses.getBehind(), + }, + { + id: 'PT 91-100 Invoked Destrudo Mortal Gaze', + type: 'StartsUsing', + netRegex: { id: 'AD43', source: 'Invoked Destrudo', capture: true }, + response: Responses.lookAwayFromSource(), + }, + // ---------------- Stone 99 Boss: Eminent Grief/Devoured Eater ---------------- + // triggers in The Final Verse: pilgrims_traverse_the_final_verse.ts + ], +}; + +export default triggerSet; diff --git a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts index f8ca6bbe..a705f1e6 100644 --- a/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts +++ b/ui/raidboss/data/07-dt/deepdungeon/pilgrims_traverse_the_final_verse.ts @@ -1,16 +1,135 @@ import Conditions from '../../../../../resources/conditions'; +import { UnreachableCode } from '../../../../../resources/not_reached'; import Outputs from '../../../../../resources/outputs'; import { Responses } from '../../../../../resources/responses'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; -import { TriggerSet } from '../../../../../types/trigger'; +import { OutputStrings, TriggerSet } from '../../../../../types/trigger'; // Pilgrim's Traverse Stone 99/The Final Verse -// TODO: Bounds of Sin dodge direction -// TODO: Abysal Blaze left/right safe spots + // TODO: timeline -export type Data = RaidbossData; +// === Map Effect info: === +// --- Bounds of Sin walls --- +// locations: +// 00 +// 0B 01 +// 0A 02 +// 09 03 +// 08 04 +// 07 05 +// 06 +// +// flags: +// 00020001 - walls appearing +// 00080004 - walls disappearing +// +// --- Spinelash glass walls --- +// locations: +// 18 | 19 | 1A +// +// flags: +// 00020001 - glass breaking first time +// 00200010 - glass breaking second time + +// === Abyssal Blaze (exaflares) === +// possible exaflare starting locations [x, y]: +// [-582.019, -288.003] +// [-582.019, -311.991] +// [-588.000, -294.015] +// [-588.000, -306.009] +// [-594.012, -299.997] +// [-599.994, -294.015] +// [-599.994, -306.009] +// [-606.006, -299.997] +// [-612.018, -294.015] +// [-612.018, -306.009] +// [-618.000, -288.003] +// [-618.000, -311.991] + +const center = { + 'x': -600, + 'y': -300, +} as const; + +type DirectionOutput12 = + | 'dirN' + | 'dirNNE' + | 'dirENE' + | 'dirE' + | 'dirESE' + | 'dirSSE' + | 'dirS' + | 'dirSSW' + | 'dirWSW' + | 'dirW' + | 'dirWNW' + | 'dirNNW' + | 'unknown'; + +const output12Dir: DirectionOutput12[] = [ + 'dirN', + 'dirNNE', + 'dirENE', + 'dirE', + 'dirESE', + 'dirSSE', + 'dirS', + 'dirSSW', + 'dirWSW', + 'dirW', + 'dirWNW', + 'dirNNW', +]; + +const outputStrings12Dir: OutputStrings = { + dirN: Outputs.dirN, + dirNNE: Outputs.dirNNE, + dirENE: Outputs.dirENE, + dirE: Outputs.dirE, + dirESE: Outputs.dirESE, + dirSSE: Outputs.dirSSE, + dirS: Outputs.dirS, + dirSSW: Outputs.dirSSW, + dirWSW: Outputs.dirWSW, + dirW: Outputs.dirW, + dirWNW: Outputs.dirWNW, + dirNNW: Outputs.dirNNW, + unknown: Outputs.unknown, +}; + +const xyTo12DirNum = (x: number, y: number, centerX: number, centerY: number): number => { + // N = 0, NNE = 1, ..., NNW = 12 + x = x - centerX; + y = y - centerY; + return Math.round(6 - 6 * Math.atan2(x, y) / Math.PI) % 12; +}; + +const outputFrom12DirNum = (dirNum: number): DirectionOutput12 => { + return output12Dir[dirNum] ?? 'unknown'; +}; + +const chainsOfCondemnationOutputStrings = { + chains: { + en: 'AoE + Stop Moving!', + de: 'AoE + Nicht Bewegen!', + ja: '全体攻撃 + 止まれ!', + cn: 'AOE + 停止移动!', + ko: '전체 공격 + 움직이지마!', + }, +} as const; + +export interface Data extends RaidbossData { + myVengeanceExpiration?: number; + sidesMiddle?: 'sides' | 'middle'; + ballChains?: 'ball' | 'chains'; + walls?: number[]; + abyssalSides: boolean; + abyssalFrontBack?: 'front' | 'back'; + abyssalLeftRight?: 'left' | 'right'; + exaflares?: number[]; +} const triggerSet: TriggerSet = { id: 'TheFinalVerse', @@ -20,55 +139,197 @@ const triggerSet: TriggerSet = { ], zoneLabel: { en: 'Pilgrim\'s Traverse Stone 99/The Final Verse', + de: 'Pilgers Pfad Stein 99/Eminente Trauer', cn: '朝圣交错路 第99朝圣路/卓异的悲寂歼灭战', ko: '필그림 트래버스 99층/최종장', }, + initData: () => ({ + abyssalSides: false, + }), + triggers: [ // ---------------- Stone 99/The Final Verse Boss: Eminent Grief/Devoured Eater ---------------- + { + id: 'PT 99 HP Difference Warning', + // 9F6 = Damage Up + // 105F = Rehabilitation + type: 'GainsEffect', + netRegex: { + effectId: ['9F6', '105F'], + target: ['Eminent Grief', 'Devoured Eater'], + capture: false, + }, + suppressSeconds: 1, + alarmText: (_data, _matches, output) => output.text!(), + outputStrings: { + text: { + en: 'Check Boss HP Difference', + ko: '보스 체력차 확인해요', + }, + }, + }, + { + id: 'PT 99 Petrification/Hysteria', + // 01 = Petrification (failure from Light Vengeance expiring) + // 128 = Hysteria (failure from Dark Vengeance expiring) + type: 'GainsEffect', + netRegex: { effectId: ['01', '128'], capture: true }, + infoText: (_data, matches, output) => { + const effect = matches.effect; + const target = matches.target; + return output.text!({ effect: effect, target: target }); + }, + outputStrings: { + text: { + en: '${effect} on ${target}', + ko: '${target}에게 ${effect}', + }, + }, + }, + { + id: 'PT 99 Light/Dark Vengeance Refresh Warning', + // 11CF = Dark Vengeance + // 11D0 = Light Vengeance + type: 'GainsEffect', + netRegex: { effectId: ['11CF', '11D0'], capture: true }, + condition: Conditions.targetIsYou(), + preRun: (data, matches) => { + const timestamp = Date.parse(matches.timestamp); + const duration = parseFloat(matches.duration); + data.myVengeanceExpiration = timestamp + duration * 1000; + }, + delaySeconds: (_data, matches) => parseFloat(matches.duration) - 10, + infoText: (data, matches, output) => { + const timestamp = Date.parse(matches.timestamp); + const duration = parseFloat(matches.duration); + const thisExpiration = timestamp + duration * 1000; + const myExpiration = data.myVengeanceExpiration; + if (myExpiration === undefined || myExpiration > thisExpiration) + return; + return output.text!(); + }, + outputStrings: { + text: { + en: 'Refresh Vengeance', + ko: '벤젠스 갱신해둬요', + }, + }, + }, { id: 'PT 99 Devoured Eater Blade of First Light', type: 'StartsUsing', netRegex: { id: ['AC21', 'AC22', 'AC27', 'AC28'], source: 'Devoured Eater', capture: true }, - alertText: (_data, matches, output) => { + preRun: (data, matches) => { + const id = matches.id; + if (id === 'AC21' || id === 'AC27') { + data.sidesMiddle = 'sides'; + } else { + data.sidesMiddle = 'middle'; + } + }, + durationSeconds: 9, + alertText: (data, matches, output) => { const id = matches.id; - if (id === 'AC21' || id === 'AC27') - return output.sides!(); - return output.middle!(); + const ballChains = data.ballChains; + const sidesMiddle = data.sidesMiddle; + if (ballChains === undefined || sidesMiddle === undefined) + return; + + if (id === 'AC21' || id === 'AC22') + return output.text!({ mech1: output[sidesMiddle]!(), mech2: output[ballChains]!() }); + return output.text!({ mech1: output[ballChains]!(), mech2: output[sidesMiddle]!() }); }, outputStrings: { + text: { + en: '${mech1} => ${mech2}', + ko: '${mech1} 🔜 ${mech2}', + }, sides: Outputs.sides, middle: Outputs.goIntoMiddle, + ball: Outputs.baitPuddles, + ...chainsOfCondemnationOutputStrings, }, }, { id: 'PT 99 Eminent Grief Ball of Fire', + type: 'StartsUsing', + netRegex: { id: ['AC1D', 'AC24'], source: 'Eminent Grief', capture: true }, + preRun: (data, _matches) => data.ballChains = 'ball', + durationSeconds: 9, + alertText: (data, matches, output) => { + const id = matches.id; + const ballChains = data.ballChains; + const sidesMiddle = data.sidesMiddle; + if (ballChains === undefined || sidesMiddle === undefined) + return; + + if (id === 'AC1D') + return output.text!({ mech1: output[ballChains]!(), mech2: output[sidesMiddle]!() }); + return output.text!({ mech1: output[sidesMiddle]!(), mech2: output[ballChains]!() }); + }, + outputStrings: { + text: { + en: '${mech1} => ${mech2}', + ko: '${mech1} 🔜 ${mech2}', + }, + sides: Outputs.sides, + middle: Outputs.goIntoMiddle, + ball: Outputs.baitPuddles, + ...chainsOfCondemnationOutputStrings, + }, + }, + { + id: 'PT 99 Eminent Grief Ball of Fire Move', type: 'Ability', netRegex: { id: ['AC1D', 'AC24'], source: 'Eminent Grief', capture: false }, - response: Responses.moveAway('alarm'), + response: Responses.moveAway('alert'), }, { id: 'PT 99 Eminent Grief Chains of Condemnation', // raidwide + applies 11D2 Chains of Condemnation for 3s; heavy damage if moving type: 'StartsUsing', netRegex: { id: ['AC20', 'AC26'], source: 'Eminent Grief', capture: true }, - delaySeconds: (_data, matches) => parseFloat(matches.castTime) - 3, - countdownSeconds: 3, - durationSeconds: 6, - alertText: (_data, _matches, output) => output.text!(), + preRun: (data, _matches) => data.ballChains = 'chains', + durationSeconds: 9, + alertText: (data, matches, output) => { + const id = matches.id; + const ballChains = data.ballChains; + const sidesMiddle = data.sidesMiddle; + if (ballChains === undefined || sidesMiddle === undefined) + return; + + if (id === 'AC20') + return output.text!({ mech1: output[ballChains]!(), mech2: output[sidesMiddle]!() }); + return output.text!({ mech1: output[sidesMiddle]!(), mech2: output[ballChains]!() }); + }, outputStrings: { text: { - en: 'AoE + Stop Moving!', - ja: '全体攻撃 + 止まれ!', - cn: 'AOE + 停止移动!', - ko: '전체 공격 + 동작 그만!', + en: '${mech1} => ${mech2}', }, + sides: Outputs.sides, + middle: Outputs.goIntoMiddle, + ball: Outputs.baitPuddles, + ...chainsOfCondemnationOutputStrings, + }, + }, + { + id: 'PT 99 Blade/Ball/Chains Cleanup', + type: 'Ability', + netRegex: { + id: ['AC29', 'AC24', 'AC26'], + source: ['Eminent Grief', 'Devoured Eater'], + capture: false, + }, + suppressSeconds: 1, + run: (data, _matches) => { + delete data.ballChains; + delete data.sidesMiddle; }, }, { id: 'PT 99 Devoured Eater Bounds of Sin', // applies 119E Bind for 3s - // AC33 = sequential damage cast, may have good position data for dodge direction type: 'Ability', netRegex: { id: 'AC32', source: 'Devoured Eater', capture: false }, delaySeconds: 3, @@ -84,6 +345,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Laser on YOU', + de: 'Laser auf DIR', ja: '自分にレーザー', cn: '激光点名', ko: '내게 레이저!', @@ -98,6 +360,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Avoid laser', + de: 'Laser vermeiden', ja: 'レーザーを避ける', cn: '避开激光', ko: '레이저 피해요', @@ -124,6 +387,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Get Light debuff', + de: 'Licht Debuff nehmen', ja: '光デバフを受ける', cn: '获取光debuff', ko: '빛🟡 받아요', @@ -142,6 +406,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Get Dark debuff', + de: 'Dunkel Debuff nehmen', ja: '闇デバフを受ける', cn: '获取暗debuff', ko: '어둠⚫️ 받아요', @@ -149,7 +414,7 @@ const triggerSet: TriggerSet = { }, }, { - id: 'PT 99 Eminent Grief Abyssal Blaze Safe Spots', + id: 'PT 99 Eminent Grief Abyssal Blaze Front/Back Safe Spot', // AC2A = first cast, horizontal exaflares, front safe // AC2B = first cast, vertical exaflares, left or right safe // AC2C = second instant cast, horizontal exaflares, back safe @@ -158,63 +423,163 @@ const triggerSet: TriggerSet = { // AC2F = diamonds glow, exaflares start at end of cast // AC30 = instant, exaflare explosion/damage type: 'Ability', - netRegex: { id: ['AC2A', 'AC2B', 'AC2C', 'AC2D'], source: 'Eminent Grief', capture: true }, - durationSeconds: 10, - infoText: (_data, matches, output) => { + netRegex: { id: ['AC2A', 'AC2C'], source: 'Eminent Grief', capture: true }, + preRun: (data, matches) => { const id = matches.id; - switch (id) { - case 'AC2A': - return output.text!({ safe: output.front!() }); - case 'AC2B': - return output.text!({ safe: output.side!() }); - case 'AC2C': - return output.text!({ safe: output.back!() }); - case 'AC2D': - return output.text!({ safe: output.side!() }); - } + id === 'AC2A' ? data.abyssalFrontBack = 'front' : data.abyssalFrontBack = 'back'; + data.abyssalSides = false; + }, + infoText: (data, _matches, output) => { + const frontBack = data.abyssalFrontBack; + const leftRight = data.abyssalLeftRight; + if (frontBack === undefined || leftRight === undefined) + return; + + return output.text!({ frontBack: output[frontBack]!(), leftRight: output[leftRight]!() }); }, outputStrings: { text: { - en: '${safe}, for later', - ja: '${safe}、あとで', - cn: '稍后 ${safe}', - ko: '(나중에 ${safe})', - }, - front: { - en: 'Front safe', - ja: '前方が安置', - cn: '前方安全', - ko: '앞쪽이 안전', + en: '${frontBack}-${leftRight}, for later', + ko: '(나중에 ${frontBack}+${leftRight})', }, - back: { - en: 'Back safe', - ja: '後方が安置', - cn: '后方安全', - ko: '뒤쪽이 안전', - }, - side: { - en: 'Check safe side', - ja: '横の安置を確認', - cn: '观察安全侧面', - ko: '좌우 안전한 곳 찾아봐요', + front: Outputs.front, + back: Outputs.back, + left: Outputs.left, + right: Outputs.right, + }, + }, + { + id: 'PT 99 Eminent Grief Abyssal Blaze Left/Right Collector', + type: 'Ability', + netRegex: { id: ['AC2B', 'AC2D'], source: 'Eminent Grief', capture: false }, + run: (data, _matches) => { + data.abyssalSides = true; + }, + }, + { + id: 'PT 99 Eminent Grief Abyssal Blaze Left/Right Safe Spot', + type: 'AbilityExtra', + netRegex: { id: 'AC2E', capture: true }, + condition: (data) => data.abyssalSides, + preRun: (data, matches) => { + const x = parseFloat(matches.x); + (data.exaflares ??= []).push(x); + + if (data.exaflares === undefined || data.exaflares.length < 4) + return; + + const exas = data.exaflares.sort((a, b) => a - b); + const [x1, x4] = [exas[0], exas[3]]; + if (x1 === undefined || x4 === undefined) + throw new UnreachableCode(); + + if (x1 < -615) { + data.abyssalLeftRight = 'right'; + } else if (x4 > -585) { + data.abyssalLeftRight = 'left'; + } + }, + infoText: (data, _matches, output) => { + const frontBack = data.abyssalFrontBack; + const leftRight = data.abyssalLeftRight; + if (frontBack === undefined || leftRight === undefined) + return; + + return output.text!({ frontBack: output[frontBack]!(), leftRight: output[leftRight]!() }); + }, + outputStrings: { + text: { + en: '${frontBack}-${leftRight}, for later', + ko: '(나중에 ${frontBack}+${leftRight})', }, + front: Outputs.front, + back: Outputs.back, + left: Outputs.left, + right: Outputs.right, }, }, { id: 'PT 99 Eminent Grief Abyssal Blaze', type: 'StartsUsing', netRegex: { id: 'AC2F', source: 'Eminent Grief', capture: false }, + durationSeconds: 16, suppressSeconds: 1, - alertText: (_data, _matches, output) => output.text!(), + alertText: (data, _matches, output) => { + const frontBack = data.abyssalFrontBack === undefined ? 'unknown' : data.abyssalFrontBack; + const leftRight = data.abyssalLeftRight === undefined ? 'unknown' : data.abyssalLeftRight; + + return output.text!({ frontBack: output[frontBack]!(), leftRight: output[leftRight]!() }); + }, + run: (data) => { + data.abyssalSides = false; + delete data.abyssalFrontBack; + delete data.abyssalLeftRight; + delete data.exaflares; + }, + outputStrings: { + text: { + en: '${frontBack}-${leftRight}, Avoid Exaflares', + ko: '${frontBack}+${leftRight}, 엑사플레어 피해요', + }, + front: Outputs.front, + back: Outputs.back, + left: Outputs.left, + right: Outputs.right, + unknown: Outputs.unknown, + }, + }, + { + id: 'PT 99 Bounds of Sin Dodge Direction', + type: 'StartsUsingExtra', + netRegex: { id: 'AC33', capture: true }, + suppressSeconds: (data) => { + const walls = data.walls; + if (walls === undefined || walls.length < 1) + return 0; + return 6.5; + }, + infoText: (data, matches, output) => { + const [x, y] = [parseFloat(matches.x), parseFloat(matches.y)]; + const dir = xyTo12DirNum(x, y, center.x, center.y); + (data.walls ??= []).push(dir); + + const walls = data.walls; + if (walls === undefined || walls.length < 2) + return; + + const [wall1, wall2] = [walls[0], walls[1]]; + if (wall1 === undefined || wall2 === undefined) + throw new UnreachableCode(); + + const isCW = wall2 - wall1 === 1 || wall1 - wall2 === 11; + const isCCW = wall1 - wall2 === 1 || wall2 - wall1 === 11; + const rotationDir = isCW ? 'cw' : isCCW ? 'ccw' : undefined; + + if (rotationDir === undefined) + return output.text!({ dir: output.unknown!() }); + + if (rotationDir === 'cw') { + const dodgeDir = outputFrom12DirNum((wall2 + 10) % 12); + return output.text!({ dir: output[dodgeDir]!() }); + } + const dodgeDir = outputFrom12DirNum((wall1 + 1) % 12); + return output.text!({ dir: output[dodgeDir]!() }); + }, outputStrings: { text: { - en: 'Avoid Exaflares', - ja: 'エクサフレアを避ける', - cn: '躲避地火', - ko: '엑사플레어 피해요', + en: 'Go ${dir}', + ko: '가세요: ${dir}', }, + unknown: Outputs.unknown, + ...outputStrings12Dir, }, }, + { + id: 'PT 99 Bounds of Sin Dodge Direction Cleanup', + type: 'Ability', + netRegex: { id: 'AC34', source: 'Devoured Eater', capture: false }, + run: (data, _matches, _output) => delete data.walls, + }, ], timelineReplace: [ { diff --git a/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts b/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts index 0d38625c..a3402814 100644 --- a/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts +++ b/ui/raidboss/data/07-dt/dungeon/meso-terminal.ts @@ -94,6 +94,7 @@ const triggerSet: TriggerSet = { outputStrings: { knockbackFrom: { en: 'Knockback from ${dir}', + de: 'Rückstoß von ${dir}', cn: '从 ${dir} 击退', ko: '${dir}에서 넉백', }, @@ -170,6 +171,7 @@ const triggerSet: TriggerSet = { outputStrings: { cleanse: { en: 'Cleanse ${target}', + de: 'Reinige ${target}', cn: '康复 ${target}', ko: '에스나: ${target}', }, @@ -212,6 +214,7 @@ const triggerSet: TriggerSet = { outputStrings: { avoidFlails: { en: 'Away from flails', + de: 'Weg vom Flegel', cn: '远离铁球', ko: '플레일 피해요', }, @@ -248,6 +251,7 @@ const triggerSet: TriggerSet = { outputStrings: { cleanseDoom: { en: 'Cleanse ${target}', + de: 'Reinige ${target}', cn: '康复 ${target}', ko: '에스나: ${target}', }, @@ -339,6 +343,7 @@ const triggerSet: TriggerSet = { outputStrings: { staticBombardment: { en: 'Go ${safe}; Avoid small AoE', + de: 'Geh nach ${safe}; Vermeide kleine AoE', cn: '前往 ${safe}; 避开小范围 AoE', ko: '${safe}으로 가욧! 작은 장판은 피해요', }, @@ -375,6 +380,7 @@ const triggerSet: TriggerSet = { outputStrings: { knockbackBombardment: { en: 'Knockback to ${safe}; Avoid AoE', + de: 'Rückstoß nach ${safe}; Vermeide AoE', cn: '击退到 ${safe}; 避开 AoE', ko: '${safe}으로 넉백! 장판은 피해요', }, @@ -458,11 +464,13 @@ const triggerSet: TriggerSet = { outputStrings: { leanLeft: { en: 'Front + Lean Left; or Southwest', + de: 'Vorne + Links halten; oder Süd-Westen', cn: '前方 + 偏左; 或左下', ko: '앞 + 왼쪽으로 살짝 또는 남서쪽', }, leanRight: { en: 'Front + Lean Right; or Southeast', + de: 'Vorne + Rechts halten; oder Süd-Osten', cn: '前方 + 偏右; 或右下', ko: '앞 + 오른쪽으로 살짝 또는 남동쪽', }, @@ -477,7 +485,6 @@ const triggerSet: TriggerSet = { timelineReplace: [ { 'locale': 'de', - 'missingTranslations': true, 'replaceSync': { 'Bloody Headsman': 'blutig(?:e|er|es|en) Henkersmann', 'Bygone Aerostat': 'vergangen(?:e|er|es|en) Aerostat', @@ -488,6 +495,10 @@ const triggerSet: TriggerSet = { 'Pestilent Headsman': 'verderblich(?:e|er|es|en) Henkersmann', }, 'replaceText': { + '\\(active\\)': '(aktiv)', + '\\(cast\\)': '(wirken)', + '\\(castbar\\)': '(wirken)', + '--hellmaker adds--': '--Höllenerschaffer Adds--', 'Biochemical Front': 'Biochemische Front', 'Bombardment': 'Bombardement', 'Chopping Block': 'Hackklotzhinrichtung', diff --git a/ui/raidboss/data/07-dt/dungeon/the_underkeep.ts b/ui/raidboss/data/07-dt/dungeon/the_underkeep.ts index 8fc551f3..11227085 100644 --- a/ui/raidboss/data/07-dt/dungeon/the_underkeep.ts +++ b/ui/raidboss/data/07-dt/dungeon/the_underkeep.ts @@ -98,6 +98,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Watch boss for dash', + de: 'Boss anschauen für Ansturm', fr: 'Regardez la position du boss pour la ruée', cn: '观察 BOSS 冲锋', ko: '보스 돌진 조심!', @@ -159,6 +160,7 @@ const triggerSet: TriggerSet = { outputStrings: { spread: { en: 'Spread in ${quad} quadrant', + de: 'Im ${quad} Quadranten verteilen', fr: 'Écartez-vous dans le quandrant ${quad}', cn: '在 ${quad} 象限分散', ko: '${quad}쪽에서 흩어져요', @@ -226,6 +228,7 @@ const triggerSet: TriggerSet = { ...Directions.outputStrings8Dir, cleave: { en: '${dir} half safe', + de: '${dir} Hälfte sicher', fr: '${dir} moitié sûre', cn: '${dir} 半安全', ko: '${dir}쪽 절반 안전', @@ -252,6 +255,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Dodge wall turrets', + de: 'Wand-Geschützturm ausweichen', fr: 'Esquivez les tourelles murales', cn: '躲避墙壁炮台', ko: '벽 레이저 피해요', @@ -266,6 +270,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Spread (all cones expand!)', + de: 'Verteilen (Alle Kegel langziehen!)', fr: 'Écartez-vous (les cônes s\'agrandissent)', cn: '分散 (所有扇形扩大!)', ko: '흩어져요! (부채꼴 장판 커져요)', @@ -280,6 +285,7 @@ const triggerSet: TriggerSet = { outputStrings: { text: { en: 'Get behind + Spread', + de: 'geh Hinter + Verteilen', fr: 'Allez derrière + Dispersion', cn: '后 + 分散', ko: '보스 뒤로 + 흩어져요', @@ -382,18 +388,21 @@ const triggerSet: TriggerSet = { unknown: Outputs.unknown, dodge: { en: 'Inner ${first} => Inner ${second} ${move}', + de: 'Innen ${first} => Innen ${second} ${move}', fr: 'Intérieur ${first} => Intérieur ${second} ${move}', cn: '内 ${first} => 内 ${second} ${move}', ko: '안쪽 ${first} => 안쪽 ${second} ${move}', }, moveAfterLaser: { en: '(after wall laser)', + de: '(nach dem Wand-Laser)', fr: '(après les lasers)', cn: '(然后墙壁激光)', ko: '(벽 레이저 쏜 다음)', }, moveAfterOrb: { en: '(after orb explosion)', + de: '(nach Orb-Explosion)', fr: '(après les explosions des orbes)', cn: '(然后球爆炸)', ko: '(구슬 터지고 난 다음)', diff --git a/ui/raidboss/data/07-dt/eureka/occult_crescent_south_horn.ts b/ui/raidboss/data/07-dt/eureka/occult_crescent_south_horn.ts index 3fa9c0ea..cdfea719 100644 --- a/ui/raidboss/data/07-dt/eureka/occult_crescent_south_horn.ts +++ b/ui/raidboss/data/07-dt/eureka/occult_crescent_south_horn.ts @@ -39,6 +39,7 @@ const triggerSet: TriggerSet = { zoneId: ZoneId.TheOccultCrescentSouthHorn, comments: { en: 'Occult Crescent South Horn critical encounter triggers/timeline.', + de: 'Kreszentia Südexpedition kritische Begegnungen Triggers/Timeline.', cn: '蜃景幻界新月岛 南征之章 紧急遭遇战 触发器/时间轴。', }, timelineFile: 'occult_crescent_south_horn.txt', @@ -192,6 +193,182 @@ const triggerSet: TriggerSet = { 'Vertical Crosshatch/Horizontal Crosshatch': 'Vertical/Horizontal Crosshatch', }, }, + { + 'locale': 'de', + 'replaceSync': { + 'Ball of Fire': 'Feuerball', + 'Black Star': 'Schwarz(?:e|er|es|en) Stern', + 'Clawmarks': 'Nagelmal', + 'Cloister Demon': 'Klosterdämon', + 'Crescent Berserker': 'kreszent(?:e|er|es|en) Berserker', + 'Crystal Dragon': 'Kristalldrache', + 'Death Claw': 'Todesklaue', + 'Draconic Double': 'Kristalldrachenphantom', + 'Hinkypunk': 'Irrwisch', + 'Lion Rampant': 'ungezügelt(?:e|er|es|en) Löwe', + 'Neo Garula': 'Neo Garula', + 'Nymian Petalodus': 'nymeisch(?:e|er|es|en) Petalodus', + 'Phantom Claw': 'Illusions-Todesklaue', + 'Repaired Lion': 'restauriert(?:e|er|es|en) Löwe', + }, + 'replaceText': { + '\\(1\\)': '(1)', + '\\(2\\)': '(2)', + '\\(3\\)': '(3)', + '\\(Lightning\\)': '(Blitz)', + '\\(Wind\\)': '(Wind)', + '\\(jump\\)': '(Sprung)', + 'Bedrock Uplift': 'Bodenhebung', + 'Blazing Flare': 'Loderndes Flare', + 'Boil Over': 'Rasender Schlag', + 'Channeled Rage': 'Tobsucht', + 'Clawing Shadow': 'Schattenklauen', + 'Clawmarks': 'Nagelmal', + 'Crystal Call': 'Kristallisierung', + 'Crystal Mirror': 'Kristallene Transposition', + 'Crystallized Energy': 'Kristallene Woge', + 'Dirty Nails': 'Dreckige Klauen', + 'Explosion': 'Explosion', + 'Fearsome Facet': 'Phantomkristalle', + 'Gigaflare': 'Gigaflare', + 'Great Ball of Fire': 'Feuerball', + 'Heated Outburst': 'Jähzorn', + 'Heightened Rage': 'Wilder Furor', + 'Hopping Mad': 'Tobender Stoß', + 'Horizontal Crosshatch': 'Horizontale Doppelnägel', + 'Karmic Drain': 'Karmischer Entzug', + 'Lethal Nails': 'Todesnägel', + 'Made Magic': 'Magiefeuer', + 'Manifold Marks': 'Multimal', + 'Primal Roar': 'Lautes Gebrüll', + 'Prismatic Wing': 'Kristallene Schwingen', + 'Raking Scratch': 'Harkenkratzer', + 'Scathing Sweep': 'Seitenhieb', + 'Seal Asunder': 'Siegelbruch', + 'Skulking Orders': 'Strafbefehl', + 'Sunderseal Roar': 'Berstendes Gebrüll', + 'The Grip of Poison': 'Tückische Resonanz', + 'Threefold Marks': 'Tripelmal', + 'Tidal Breath': 'Hauch der Gezeiten', + 'Vertical Crosshatch': 'Vertikale Doppelnägel', + 'Void Thunder III': 'Nichts-Blitzga', + 'White-hot Rage': 'Jähzorniger Schub', + }, + }, + { + 'locale': 'fr', + 'missingTranslations': true, + 'replaceSync': { + 'Ball of Fire': 'orbe de feu', + 'Black Star': 'Étoile noire', + 'Clawmarks': 'griffure', + 'Cloister Demon': 'démon du Cloître', + 'Crescent Berserker': 'berserker de Lunule', + 'Crystal Dragon': 'dragon cristallin', + 'Death Claw': 'Griffe de mort', + 'Draconic Double': 'double de dragon cristallin', + 'Hinkypunk': 'follet folâtre', + 'Lion Rampant': 'lion rampant', + 'Neo Garula': 'néo-garula', + 'Nymian Petalodus': 'petalodus de Nym', + 'Phantom Claw': 'mirage de Griffe de mort', + 'Repaired Lion': 'lion réparé', + }, + 'replaceText': { + 'Bedrock Uplift': 'Surrection', + 'Blazing Flare': 'Brasier ardent', + 'Boil Over': 'Poussée de colère', + 'Channeled Rage': 'Accès de fureur', + 'Clawing Shadow': 'Serres brumeuses', + 'Clawmarks': 'griffure', + 'Crystal Call': 'Cristallisation', + 'Crystal Mirror': 'Transfert cristallin', + 'Crystallized Energy': 'Onde cristalline', + 'Dirty Nails': 'Serres putrides', + 'Explosion': 'Explosion', + 'Fearsome Facet': 'Cristaux spectraux', + 'Gigaflare': 'GigaBrasier', + 'Great Ball of Fire': 'Orbes de feu', + 'Heated Outburst': 'Courroux ardent', + 'Heightened Rage': 'Déchaînement de rage', + 'Hopping Mad': 'Impulsion frénétique', + 'Horizontal Crosshatch': 'Intersection horizontale', + 'Karmic Drain': 'Érosion d\'existence', + 'Lethal Nails': 'Griffes mortelles', + 'Made Magic': 'Déferlante magique', + 'Manifold Marks': 'Marques multiples', + 'Primal Roar': 'Rugissement furieux', + 'Prismatic Wing': 'Aile cristalline', + 'Raking Scratch': 'Griffes ratisseuses', + 'Scathing Sweep': 'Fauche latérale', + 'Seal Asunder': 'Descellement destructeur', + 'Skulking Orders': 'Ordre d\'élimination', + 'Sunderseal Roar': 'Rugissement libérateur', + 'The Grip of Poison': 'Résonnance de la malfaisance', + 'Threefold Marks': 'Triple marque', + 'Tidal Breath': 'Souffle supratidal', + 'Vertical Crosshatch': 'Intersection verticale', + 'Void Thunder III': 'Méga Foudre du néant', + 'White-hot Rage': 'Rage incandescente', + }, + }, + { + 'locale': 'ja', + 'missingTranslations': true, + 'replaceSync': { + 'Ball of Fire': '火球', + 'Black Star': 'ブラックスター', + 'Clawmarks': 'ネイルマーク', + 'Cloister Demon': 'クロイスターデーモン', + 'Crescent Berserker': 'クレセント・バーサーカー', + 'Crystal Dragon': '水晶竜', + 'Death Claw': 'デスクロー', + 'Draconic Double': '水晶竜の幻影', + 'Hinkypunk': 'ヒンキーパンク', + 'Lion Rampant': 'ランパントライオン', + 'Neo Garula': 'ネオガルラ', + 'Nymian Petalodus': 'ニーム・ペタロドゥス', + 'Phantom Claw': 'ミラージュ・デスクロー', + 'Repaired Lion': 'リペアドライオン', + }, + 'replaceText': { + 'Bedrock Uplift': '地盤隆起', + 'Blazing Flare': 'ブレイジングフレア', + 'Boil Over': '怒発', + 'Channeled Rage': '激怒', + 'Clawing Shadow': 'ヘイズクロー', + 'Clawmarks': 'ネイルマーク', + 'Crystal Call': '晶石生成', + 'Crystal Mirror': '晶石転移', + 'Crystallized Energy': '水晶波動', + 'Dirty Nails': 'ダーティクロー', + 'Explosion': '爆発', + 'Fearsome Facet': '幻影晶石', + 'Gigaflare': 'ギガフレア', + 'Great Ball of Fire': '火球', + 'Heated Outburst': '気炎', + 'Heightened Rage': '大激怒', + 'Hopping Mad': '震撃怒涛', + 'Horizontal Crosshatch': 'ホリゾンタル・ダブルネイル', + 'Karmic Drain': 'ライフエロージョン', + 'Lethal Nails': 'デスネイル', + 'Made Magic': '魔力放出', + 'Manifold Marks': 'マルチプルマーク', + 'Primal Roar': '大咆哮', + 'Prismatic Wing': '水晶の翼', + 'Raking Scratch': 'ネイルストリーク', + 'Scathing Sweep': '横薙ぎ', + 'Seal Asunder': '封印破壊', + 'Skulking Orders': 'パニッシングオーダー', + 'Sunderseal Roar': '壊封の咆哮', + 'The Grip of Poison': '邪気の共振', + 'Threefold Marks': 'トリプルマーク', + 'Tidal Breath': 'タイダルブレス', + 'Vertical Crosshatch': 'バーチカル・ダブルネイル', + 'Void Thunder III': 'ヴォイド・サンダガ', + 'White-hot Rage': '気炎怒涛', + }, + }, { 'locale': 'cn', 'replaceSync': { diff --git a/ui/raidboss/data/07-dt/raid/r5s.ts b/ui/raidboss/data/07-dt/raid/r5s.ts index dd26057a..0b416375 100644 --- a/ui/raidboss/data/07-dt/raid/r5s.ts +++ b/ui/raidboss/data/07-dt/raid/r5s.ts @@ -440,12 +440,12 @@ const triggerSet: TriggerSet = { }, { 'locale': 'de', - 'missingTranslations': true, 'replaceSync': { 'Dancing Green': 'Springhis Khan', 'Frogtourage': 'Schenkelschwinger', }, 'replaceText': { + 'Debuffs': 'Debuffs', '\\(Cleave\\)': '(Cleave)', '\\(Echo\\)': '(Echo)', '\\(In\\+Protean\\+Echo\\)': '(Rein+Himmelsrichtungen+Echo)', diff --git a/ui/raidboss/data/07-dt/raid/r8n.ts b/ui/raidboss/data/07-dt/raid/r8n.ts index 7579e248..313f1299 100644 --- a/ui/raidboss/data/07-dt/raid/r8n.ts +++ b/ui/raidboss/data/07-dt/raid/r8n.ts @@ -284,6 +284,7 @@ const triggerSet: TriggerSet = { outputStrings: { behindClones: { en: 'Behind Clones', + de: 'Hinter den Klonen', fr: 'Derrière les clones', cn: '去分身后', ko: '분신 뒤로', diff --git a/ui/raidboss/data/07-dt/raid/r8s.ts b/ui/raidboss/data/07-dt/raid/r8s.ts index 0289ef54..e322e613 100644 --- a/ui/raidboss/data/07-dt/raid/r8s.ts +++ b/ui/raidboss/data/07-dt/raid/r8s.ts @@ -863,7 +863,6 @@ const triggerSet: TriggerSet = { }, { 'locale': 'de', - 'missingTranslations': true, 'replaceSync': { 'Gleaming Fang': 'Lichtreißer', 'Howling Blade': 'Heulende Klinge', @@ -876,6 +875,11 @@ const triggerSet: TriggerSet = { '--adds-targetable--': '--Adds-anvisierbar--', '--shadow ': '--Schatten ', '--tank/line aoes--': '--Tank/Linien AoEs--', + '\\(circles\\)': '(Kreise)', + '\\(cones\\)': '(Kegel)', + '\\(enrage\\)': '(Finalangriff)', + '\\(Platform\\)': '(Plattform)', + '\\(Towers\\)': '(Türme)', 'Aero III': 'Windga', 'Aerotemporal Blast': 'Temporärer Wind', 'Alpha Stone': 'Erde des Lichtwolfs', @@ -936,7 +940,6 @@ const triggerSet: TriggerSet = { }, { 'locale': 'fr', - 'missingTranslations': true, 'replaceSync': { 'Gleaming Fang': 'croc de lumière', 'Howling Blade': 'Howling Blade', @@ -946,6 +949,14 @@ const triggerSet: TriggerSet = { 'Wolf of Wind': 'loup du vent', }, 'replaceText': { + '--adds-targetable--': '--Adds ciblables--', + '--shadow ': '--Ombre ', + '--tank/line aoes--': '--AOE Tank/En ligne--', + '\\(circles\\)': '(Cercles)', + '\\(cones\\)': '(Cônes)', + '\\(enrage\\)': '(Enrage)', + '\\(Platform\\)': '(Plateforme)', + '\\(Towers\\)': '(Tours)', 'Aero III': 'Méga Vent', 'Aerotemporal Blast': 'Assaut tempétueux à retardement', 'Alpha Stone': 'Terre du loup radieux', diff --git a/ui/raidboss/data/07-dt/trial/necron-ex.ts b/ui/raidboss/data/07-dt/trial/necron-ex.ts index fbe1e5c8..aa6d99f2 100644 --- a/ui/raidboss/data/07-dt/trial/necron-ex.ts +++ b/ui/raidboss/data/07-dt/trial/necron-ex.ts @@ -593,7 +593,6 @@ const triggerSet: TriggerSet = { }, { 'locale': 'de', - 'missingTranslations': true, 'replaceSync': { 'Azure Aether': 'azur(?:e|er|es|en) Äther', 'Beckoning Hands': 'lockend(?:e|er|es|en) Hand', diff --git a/ui/raidboss/data/07-dt/trial/queen-eternal.ts b/ui/raidboss/data/07-dt/trial/queen-eternal.ts index 97522e6c..16ca5529 100644 --- a/ui/raidboss/data/07-dt/trial/queen-eternal.ts +++ b/ui/raidboss/data/07-dt/trial/queen-eternal.ts @@ -85,6 +85,7 @@ const triggerSet: TriggerSet = { repeatedAOE: { en: 'Continuous light AoE', de: 'Durchgehende Licht AoE', + fr: 'AoE légère continue', ja: '連続光属性AoE', cn: '连续小AoE', ko: '연속 격자 장판', @@ -139,6 +140,7 @@ const triggerSet: TriggerSet = { regaliaYou: { en: 'Laser tether on YOU', de: 'Laserverbindung auf DIR', + fr: 'Lien laser sur VOUS', ja: 'レーザー線処理', cn: '激光连线点名', ko: '내게 유도 레이저 줄', @@ -170,6 +172,7 @@ const triggerSet: TriggerSet = { floating: { en: 'Gravitation -- Levitating', de: 'Gravitation -- Schweben', + fr: 'Gravité -- Lévitation', ja: '重力装置 -- 浮上', cn: '重力 -- 上浮', ko: '곧 뜰꺼예요!', @@ -190,6 +193,7 @@ const triggerSet: TriggerSet = { falling: { en: 'Gravitation -- Falling', de: 'Gravitation -- Fallen', + fr: 'Gravité -- Chute', ja: '重力装置 -- 降下', cn: '重力 -- 下降', ko: '곧 내려가요!', @@ -210,6 +214,7 @@ const triggerSet: TriggerSet = { floating: { en: 'Gravitation -- Levitating', de: 'Gravitation -- Schweben', + fr: 'Gravité -- Lévitation', ja: '重力装置 -- 浮上', cn: '重力 -- 上浮', ko: '곧 뜰꺼예요!', @@ -234,6 +239,7 @@ const triggerSet: TriggerSet = { fallCastle: { en: 'In front of ground windows', de: 'Sei vor dem Fenster am Boden', + fr: 'Devant les fenêtres à l\'avant', ja: '下層の窓前へ', cn: '正对下层空洞', ko: '아랫쪽 구멍으로', @@ -241,6 +247,7 @@ const triggerSet: TriggerSet = { floatCastle: { en: 'In front of middle windows', de: 'Sei vor dem Fenster in der Mitte', + fr: 'Devant les fenêtres du milieu', ja: '中層の窓前へ', cn: '正对上层空洞', ko: '윗쪽 구멍으로', @@ -256,6 +263,7 @@ const triggerSet: TriggerSet = { getInDonut: { en: 'Get in robot circle', de: 'Geh in den Roboterkreis', + fr: 'Aller dans le cercle du robot', ja: 'ドローンサークルの中に', cn: '小月环', ko: '로봇 동글이 안으로', @@ -287,6 +295,7 @@ const triggerSet: TriggerSet = { gazeLater: { en: 'Gaze on you soon', de: 'Bald: Blick auf dir', + fr: 'Regard sur vous bientôt', ja: 'まもなく視線攻撃', cn: '石化眼点名', ko: '내게 곧 눈깔', @@ -314,6 +323,7 @@ const triggerSet: TriggerSet = { shriekYou: { en: 'Gaze -- look away from ${otherTarget}', de: 'Blick -- schau weg von ${otherTarget}', + fr: 'Regard -- Ne regardez pas ${otherTarget}', ja: '視線攻撃 -- ${otherTarget} を見ない', cn: '石化眼 -- 背对 ${otherTarget}', ko: '내게 눈깔! 자리 비켜줘욧! (${otherTarget})', @@ -321,6 +331,7 @@ const triggerSet: TriggerSet = { shriekOthers: { en: 'Look away from ${comboTargets}', de: 'Schau weg von ${comboTargets}', + fr: 'Ne regardez pas ${comboTargets}', ja: '${comboTargets} を見ない', cn: '背对 ${comboTargets}', ko: '보면 안되요: ${comboTargets}', @@ -337,6 +348,7 @@ const triggerSet: TriggerSet = { bombLater: { en: 'Acceleration Bomb soon', de: 'Bald: Beschleunigungsbombe', + fr: 'Bombe d\'accélération bientôt', ja: 'まもなく加速度爆弾', cn: '稍后 加速度炸弹', ko: '곧 가속 폭탄', @@ -367,6 +379,7 @@ const triggerSet: TriggerSet = { flareMarker: { en: 'Flare on YOU', de: 'Flare auf DIR', + fr: 'Brasier sur VOUS', ja: 'フレア処理', cn: '核爆点名', ko: '내게 플레어', @@ -396,6 +409,7 @@ const triggerSet: TriggerSet = { fiveAOE: { en: '5x AoEs', de: '5x AoEs', + fr: '5x AoEs', ja: '5連続AoE', cn: 'AoE (5次)', ko: '5x 전체공격', @@ -406,7 +420,6 @@ const triggerSet: TriggerSet = { timelineReplace: [ { 'locale': 'de', - 'missingTranslations': true, 'replaceSync': { 'Queen Eternal': 'Ewig(?:e|er|es|en) Königin', }, diff --git a/ui/raidboss/data/07-dt/trial/seiryu-un.ts b/ui/raidboss/data/07-dt/trial/seiryu-un.ts index 275ee635..c5f9ffbd 100644 --- a/ui/raidboss/data/07-dt/trial/seiryu-un.ts +++ b/ui/raidboss/data/07-dt/trial/seiryu-un.ts @@ -52,6 +52,7 @@ const triggerSet: TriggerSet = { outputStrings: { grabTether: { en: 'Grab Tank Tether, Point Cleave Away', + de: 'Nimm Tank-Verbindung, zeige den Cleave weg', fr: 'Prenez le lien Tank, visez l\'extérieur', cn: '接走坦克连线,引导扇形远离人群', ko: '줄 채고, 바깥으로 유도', @@ -245,24 +246,28 @@ const triggerSet: TriggerSet = { dirW: Outputs.west, goToSnakes: { en: 'Go ${dir} Toward Snakes', + de: 'Geh Richtung ${dir} zu den Schlangen', fr: 'Allez ${dir} vers les serpents', cn: '向 ${dir} 蛇走', ko: '뱀 ${dir}으로 가요', }, goToUnknownSnakes: { en: 'Go Toward Snakes', + de: 'Geh zu den Schlangen', fr: 'Allez vers les serpents', cn: '向蛇走', ko: '뱀 쪽으로 가요', }, outOfMiddleTowardSnakes: { en: 'Out Of Middle, Knockback To ${dir}', + de: 'Raus aus der Mitte, Rückstoß nach ${dir}', fr: 'Loin du centre, Poussée vers ${dir}', cn: '离开中间,击退到 ${dir}', ko: '가운데는 위험! ${dir}으로 넉백', }, outOfMiddleUnknownSnakes: { en: 'Out Of Middle, Knockback Toward Snakes', + de: 'Raus aus der Mitte, Rückstoß zu den Schlangen', fr: 'Loin du centre, Poussée vers les serpents', cn: '离开中间,向蛇击退', ko: '가운데는 위험! 뱀 쪽으로 넉백', @@ -360,11 +365,10 @@ const triggerSet: TriggerSet = { timelineReplace: [ { 'locale': 'de', - 'missingTranslations': true, 'replaceSync': { 'Aka-no-shiki': 'Aka no Shiki', 'Ao-no-shiki': 'Ao no Shiki', - 'Blue Orochi': 'blau[a] Orochi', + 'Blue Orochi': 'blau(?:e|er|es|en) Orochi', 'Iwa-no-shiki': 'Iwa no Shiki', 'Numa-no-shiki': 'Numa no Shiki', 'Seiryu': 'Seiryu', @@ -372,6 +376,8 @@ const triggerSet: TriggerSet = { 'Yama-no-shiki': 'Yama no Shiki', }, 'replaceText': { + '--large add spawns--': '--großes Add erscheint--', + '--small adds spawn--': '--kleine Adds erscheinen--', '100-tonze Swing': '100-Tonzen-Schwung', 'Blazing Aramitama': 'Flammende Aramitama', 'Blue Bolt': 'Blauer Blitz', @@ -392,7 +398,7 @@ const triggerSet: TriggerSet = { 'Serpent Descending': 'Niedergang der Schlange', 'Serpent\'s Fang': 'Schlangengiftzahn', 'Strength of Spirit': 'Stärke des Geistes', - 'Summon Shiki': 'Shiki-Beschwörung ', + 'Summon Shiki': 'Shiki-Beschwörung', 'Yama-kagura': 'Yamakagura', }, },