From 2bb97f6a1d9c98360d1674aa32ec8722d2376f6c Mon Sep 17 00:00:00 2001 From: ForestSageSarah Date: Wed, 3 Jun 2026 13:11:13 -0400 Subject: [PATCH 1/7] raidboss: add Merchant's Tale Advanced baseline --- .../dungeon/the_merchants_tale_advanced.ts | 23 +++++++++++++++++++ .../dungeon/the_merchants_tale_advanced.txt | 17 ++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts create mode 100644 ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.txt diff --git a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts new file mode 100644 index 00000000000..91c259bb6ea --- /dev/null +++ b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts @@ -0,0 +1,23 @@ +import { Responses } from '../../../../../resources/responses'; +import ZoneId from '../../../../../resources/zone_id'; +import { RaidbossData } from '../../../../../types/data'; +import { TriggerSet } from '../../../../../types/trigger'; + +export interface Data extends RaidbossData {} + +const triggerSet: TriggerSet = { + id: 'TheMerchantsTaleAdvanced', + zoneId: ZoneId.TheMerchantsTaleAdvanced, + timelineFile: 'the_merchants_tale_advanced.txt', + + triggers: [ + { + id: 'Pari Heat Burst', + type: 'StartsUsing', + netRegex: { source: 'Pari of Plenty', id: 'B1CC', capture: false }, + response: Responses.aoe(), + }, + ], +}; + +export default triggerSet; diff --git a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.txt b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.txt new file mode 100644 index 00000000000..5e3db8070d6 --- /dev/null +++ b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.txt @@ -0,0 +1,17 @@ +### THE MERCHANT'S TALE (ADVANCED) +# ZoneId: 524 + +hideall "--Reset--" +hideall "--sync--" + +0.0 "--Reset--" SystemLogMessage { id: "7DE" } window 0,100000 jump 0 + +#~~~~~~~~~~~~~~~~# +# PARI OF PLENTY # +#~~~~~~~~~~~~~~~~# + +1000.0 "--sync--" SystemLogMessage { id: "7DC" } window 10000,0 +1013.0 "Heat Burst" Ability { id: "B1CC", source: "Pari of Plenty" } + +# ALL ENCOUNTER ABILITIES +# B1CC Heat Burst \ No newline at end of file From 1a77e922c8f7e3885fbbd255cec0af3763416bc8 Mon Sep 17 00:00:00 2001 From: ForestSageSarah Date: Wed, 3 Jun 2026 13:41:47 -0400 Subject: [PATCH 2/7] raidboss: add Pari basic ability calls --- .../dungeon/the_merchants_tale_advanced.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts index 91c259bb6ea..b8f70c0944c 100644 --- a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts +++ b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts @@ -17,6 +17,38 @@ const triggerSet: TriggerSet = { netRegex: { source: 'Pari of Plenty', id: 'B1CC', capture: false }, response: Responses.aoe(), }, + { + id: 'Pari Fire Of Victory', + type: 'StartsUsing', + netRegex: { source: 'Pari of Plenty', id: 'B1CE' }, + response: Responses.tankBuster(), + }, + { + id: 'Pari Scouring Scorn', + type: 'StartsUsing', + netRegex: { source: 'Pari of Plenty', id: 'B1B2', capture: false }, + response: Responses.aoe(), + }, + { + id: 'Pari Doubling Center For Chains', + type: 'StartsUsing', + netRegex: { source: 'Pari of Plenty', id: 'B093', capture: false }, + durationSeconds: 4, + alertText: (_data, _matches, output) => output.centerForChains!(), + outputStrings: { + centerForChains: { en: 'Center for Chains' }, + }, + }, + { + id: 'Pari Sun Circlet', + type: 'StartsUsing', + netRegex: { source: 'Pari of Plenty', id: 'B187', capture: false }, + suppressSeconds: 3, + alarmText: (_data, _matches, output) => output.inBossHitbox!(), + outputStrings: { + inBossHitbox: { en: 'In Boss Hitbox' }, + }, + }, ], }; From 2e0a364560509de1a88bfb7da81f60866525da97 Mon Sep 17 00:00:00 2001 From: ForestSageSarah Date: Wed, 3 Jun 2026 14:19:19 -0400 Subject: [PATCH 3/7] raidboss: add Pari False Flame safe-side calls --- .../dungeon/the_merchants_tale_advanced.ts | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts index b8f70c0944c..10776ef5374 100644 --- a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts +++ b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts @@ -3,13 +3,56 @@ import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { TriggerSet } from '../../../../../types/trigger'; -export interface Data extends RaidbossData {} +export interface Data extends RaidbossData { + pariFalseFlameFableflightCalled: boolean; + pariFalseFlameSafeHalf?: 'North' | 'South'; +} + +const pariArenaCenterX = -760.0; + +const pariFalseFlameRightFableflight = 'B174'; +const pariFalseFlameLeftFableflight = 'B175'; + +const pariCharmedFableflightSafeHalf = ( + id: string, + x: number, +): 'North' | 'South' | undefined => { + const threshold = 5.0; + const isEast = x > pariArenaCenterX + threshold; + const isWest = x < pariArenaCenterX - threshold; + const isLeft = id === pariFalseFlameLeftFableflight; + const isRight = id === pariFalseFlameRightFableflight; + + if (!isEast && !isWest) + return undefined; + + if (isEast && isRight) + return 'South'; + + if (isEast && isLeft) + return 'North'; + + if (isWest && isRight) + return 'North'; + + if (isWest && isLeft) + return 'South'; + + return undefined; +}; const triggerSet: TriggerSet = { id: 'TheMerchantsTaleAdvanced', zoneId: ZoneId.TheMerchantsTaleAdvanced, timelineFile: 'the_merchants_tale_advanced.txt', + initData: () => { + return { + pariFalseFlameFableflightCalled: false, + pariFalseFlameSafeHalf: undefined, + }; + }, + triggers: [ { id: 'Pari Heat Burst', @@ -49,6 +92,48 @@ const triggerSet: TriggerSet = { inBossHitbox: { en: 'In Boss Hitbox' }, }, }, + { + id: 'Pari False Flame Right Fableflight', + type: 'StartsUsing', + netRegex: { id: pariFalseFlameRightFableflight }, + durationSeconds: 10, + alertText: (data, matches, output) => { + data.pariFalseFlameFableflightCalled = true; + data.pariFalseFlameSafeHalf = pariCharmedFableflightSafeHalf( + matches.id, + parseFloat(matches.x), + ); + + if (data.pariFalseFlameSafeHalf === undefined) + return; + + return output.safeHalf!({ dir: data.pariFalseFlameSafeHalf }); + }, + outputStrings: { + safeHalf: { en: '${dir} Safe' }, + }, + }, + { + id: 'Pari False Flame Left Fableflight', + type: 'StartsUsing', + netRegex: { id: pariFalseFlameLeftFableflight }, + durationSeconds: 10, + alertText: (data, matches, output) => { + data.pariFalseFlameFableflightCalled = true; + data.pariFalseFlameSafeHalf = pariCharmedFableflightSafeHalf( + matches.id, + parseFloat(matches.x), + ); + + if (data.pariFalseFlameSafeHalf === undefined) + return; + + return output.safeHalf!({ dir: data.pariFalseFlameSafeHalf }); + }, + outputStrings: { + safeHalf: { en: '${dir} Safe' }, + }, + }, ], }; From 0e05b13b31166d24b39d5aadac1e0efc1f009768 Mon Sep 17 00:00:00 2001 From: ForestSageSarah Date: Wed, 3 Jun 2026 14:47:45 -0400 Subject: [PATCH 4/7] raidboss: add Pari False Flame safe-side calls --- .../dungeon/the_merchants_tale_advanced.ts | 134 ++++++++++++++---- 1 file changed, 103 insertions(+), 31 deletions(-) diff --git a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts index 10776ef5374..7e20edd9565 100644 --- a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts +++ b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts @@ -1,10 +1,12 @@ +import Conditions from '../../../../../resources/conditions'; import { Responses } from '../../../../../resources/responses'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; +import { NetMatches } from '../../../../../types/net_matches'; import { TriggerSet } from '../../../../../types/trigger'; export interface Data extends RaidbossData { - pariFalseFlameFableflightCalled: boolean; + pariChains: NetMatches['Tether'][]; pariFalseFlameSafeHalf?: 'North' | 'South'; } @@ -13,7 +15,7 @@ const pariArenaCenterX = -760.0; const pariFalseFlameRightFableflight = 'B174'; const pariFalseFlameLeftFableflight = 'B175'; -const pariCharmedFableflightSafeHalf = ( +const pariFalseFlameFableflightSafeHalf = ( id: string, x: number, ): 'North' | 'South' | undefined => { @@ -48,7 +50,7 @@ const triggerSet: TriggerSet = { initData: () => { return { - pariFalseFlameFableflightCalled: false, + pariChains: [], pariFalseFlameSafeHalf: undefined, }; }, @@ -79,59 +81,129 @@ const triggerSet: TriggerSet = { durationSeconds: 4, alertText: (_data, _matches, output) => output.centerForChains!(), outputStrings: { - centerForChains: { en: 'Center for Chains' }, + centerForChains: { + en: 'Center for Chains', + de: 'Mitte für Ketten', + fr: 'Centre pour les chaînes', + ja: '鎖は中央へ', + cn: '中间准备锁链', + ko: '사슬 중앙', + tc: '中間準備鎖鏈', + }, }, }, { - id: 'Pari Sun Circlet', + id: 'Pari Charmed Chains Reset', type: 'StartsUsing', - netRegex: { source: 'Pari of Plenty', id: 'B187', capture: false }, - suppressSeconds: 3, - alarmText: (_data, _matches, output) => output.inBossHitbox!(), - outputStrings: { - inBossHitbox: { en: 'In Boss Hitbox' }, - }, + netRegex: { source: 'Pari of Plenty', id: 'B08F', capture: false }, + run: (data) => data.pariChains = [], }, { - id: 'Pari False Flame Right Fableflight', - type: 'StartsUsing', - netRegex: { id: pariFalseFlameRightFableflight }, - durationSeconds: 10, - alertText: (data, matches, output) => { - data.pariFalseFlameFableflightCalled = true; - data.pariFalseFlameSafeHalf = pariCharmedFableflightSafeHalf( - matches.id, - parseFloat(matches.x), + id: 'Pari Charmed Chains Tether', + type: 'Tether', + netRegex: { id: '0009' }, + condition: (data, matches) => matches.source === data.me || matches.target === data.me, + preRun: (data, matches) => { + data.pariChains.push(matches); + }, + delaySeconds: 0.3, + alertText: (data, _matches, output) => { + const chain = data.pariChains.find((chain) => + chain.source === data.me || chain.target === data.me ); - if (data.pariFalseFlameSafeHalf === undefined) + if (chain === undefined) return; - return output.safeHalf!({ dir: data.pariFalseFlameSafeHalf }); + const partner = chain.source === data.me ? chain.target : chain.source; + return output.chainedTo!({ player: data.party.member(partner) }); + }, + run: (data) => data.pariChains = [], + outputStrings: { + chainedTo: { + en: 'Chained to ${player}', + de: 'Kette mit ${player}', + fr: 'Enchaîné à ${player}', + ja: '${player}と鎖', + cn: '与${player}连线', + ko: '${player}와 사슬', + tc: '與${player}連線', + }, }, + }, + { + id: 'Pari Burning Chains On You', + type: 'GainsEffect', + netRegex: { effectId: '301' }, + condition: Conditions.targetIsYou(), + suppressSeconds: 2, + infoText: (_data, _matches, output) => output.breakChain!(), outputStrings: { - safeHalf: { en: '${dir} Safe' }, + breakChain: { + en: 'Break Chain', + de: 'Kette brechen', + fr: 'Brisez la chaîne', + ja: '鎖を切る', + cn: '拉断锁链', + ko: '사슬 끊기', + tc: '拉斷鎖鏈', + }, }, }, { - id: 'Pari False Flame Left Fableflight', + id: 'Pari Sun Circlet', type: 'StartsUsing', - netRegex: { id: pariFalseFlameLeftFableflight }, + netRegex: { source: 'Pari of Plenty', id: 'B187', capture: false }, + suppressSeconds: 3, + alarmText: (_data, _matches, output) => output.inBossHitbox!(), + outputStrings: { + inBossHitbox: { + en: 'In Boss Hitbox', + de: 'In die Boss-Hitbox', + fr: 'Dans la hitbox du boss', + ja: 'ボスの足元へ', + cn: '进Boss脚下', + ko: '보스 안으로', + tc: '進Boss腳下', + }, + }, + }, + { + id: 'Pari False Flame Fableflight', + type: 'StartsUsing', + netRegex: { id: [pariFalseFlameRightFableflight, pariFalseFlameLeftFableflight] }, durationSeconds: 10, alertText: (data, matches, output) => { - data.pariFalseFlameFableflightCalled = true; - data.pariFalseFlameSafeHalf = pariCharmedFableflightSafeHalf( + data.pariFalseFlameSafeHalf = pariFalseFlameFableflightSafeHalf( matches.id, parseFloat(matches.x), ); - if (data.pariFalseFlameSafeHalf === undefined) - return; + if (data.pariFalseFlameSafeHalf === 'North') + return output.northSafe!(); - return output.safeHalf!({ dir: data.pariFalseFlameSafeHalf }); + if (data.pariFalseFlameSafeHalf === 'South') + return output.southSafe!(); }, outputStrings: { - safeHalf: { en: '${dir} Safe' }, + northSafe: { + en: 'North Safe', + de: 'Norden sicher', + fr: 'Nord sûr', + ja: '北安置', + cn: '北安全', + ko: '북쪽 안전', + tc: '北安全', + }, + southSafe: { + en: 'South Safe', + de: 'Süden sicher', + fr: 'Sud sûr', + ja: '南安置', + cn: '南安全', + ko: '남쪽 안전', + tc: '南安全', + }, }, }, ], From a1ad2dc27c36155140e9a190eeff5bcbdbb0952b Mon Sep 17 00:00:00 2001 From: "Sarah B." <46040612+ForestSageSarah@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:16:49 -0400 Subject: [PATCH 5/7] Update ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts Co-authored-by: Jonathan Garber --- .../07-dt/dungeon/the_merchants_tale_advanced.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts index 7e20edd9565..86a9922a6bb 100644 --- a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts +++ b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts @@ -137,18 +137,7 @@ const triggerSet: TriggerSet = { netRegex: { effectId: '301' }, condition: Conditions.targetIsYou(), suppressSeconds: 2, - infoText: (_data, _matches, output) => output.breakChain!(), - outputStrings: { - breakChain: { - en: 'Break Chain', - de: 'Kette brechen', - fr: 'Brisez la chaîne', - ja: '鎖を切る', - cn: '拉断锁链', - ko: '사슬 끊기', - tc: '拉斷鎖鏈', - }, - }, + response: Responses.breakChains(), }, { id: 'Pari Sun Circlet', From c54696cf710f01d659219cd4d4a7a8225481592e Mon Sep 17 00:00:00 2001 From: "Sarah B." <46040612+ForestSageSarah@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:17:43 -0400 Subject: [PATCH 6/7] Update ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts Co-authored-by: Jonathan Garber --- ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts index 86a9922a6bb..4e31e56d911 100644 --- a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts +++ b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts @@ -66,7 +66,7 @@ const triggerSet: TriggerSet = { id: 'Pari Fire Of Victory', type: 'StartsUsing', netRegex: { source: 'Pari of Plenty', id: 'B1CE' }, - response: Responses.tankBuster(), + response: Responses.tankCleave(), }, { id: 'Pari Scouring Scorn', From 994361f8bbf636c68afa249bf79e130274d2ddb1 Mon Sep 17 00:00:00 2001 From: "Sarah B." <46040612+ForestSageSarah@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:28:16 -0400 Subject: [PATCH 7/7] Update ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts Co-authored-by: Jonathan Garber --- .../07-dt/dungeon/the_merchants_tale_advanced.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts index 4e31e56d911..5b791412591 100644 --- a/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts +++ b/ui/raidboss/data/07-dt/dungeon/the_merchants_tale_advanced.ts @@ -144,18 +144,7 @@ const triggerSet: TriggerSet = { type: 'StartsUsing', netRegex: { source: 'Pari of Plenty', id: 'B187', capture: false }, suppressSeconds: 3, - alarmText: (_data, _matches, output) => output.inBossHitbox!(), - outputStrings: { - inBossHitbox: { - en: 'In Boss Hitbox', - de: 'In die Boss-Hitbox', - fr: 'Dans la hitbox du boss', - ja: 'ボスの足元へ', - cn: '进Boss脚下', - ko: '보스 안으로', - tc: '進Boss腳下', - }, - }, + response: Responses.getUnder(), }, { id: 'Pari False Flame Fableflight',