diff --git a/ui/raidboss/data/06-ew/dungeon/the_lunar_subterrane.ts b/ui/raidboss/data/06-ew/dungeon/the_lunar_subterrane.ts index 7e720fa03e..edc0935d52 100644 --- a/ui/raidboss/data/06-ew/dungeon/the_lunar_subterrane.ts +++ b/ui/raidboss/data/06-ew/dungeon/the_lunar_subterrane.ts @@ -1,9 +1,10 @@ import Conditions from '../../../../../resources/conditions'; import Outputs from '../../../../../resources/outputs'; import { Responses } from '../../../../../resources/responses'; -import Util from '../../../../../resources/util'; +import Util, { Directions } from '../../../../../resources/util'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; +import { Matches } from '../../../../../types/net_matches'; import { TriggerSet } from '../../../../../types/trigger'; // TODO: Dark Elf tell people where to go for hidden staves @@ -13,8 +14,19 @@ export interface Data extends RaidbossData { fountsSeen: number; fountX: number[]; fountY: number[]; + staffMatches: Matches[]; } +const elfCenterX = -401.02; +const elfCenterY = -231.01; + +const dirNumberToOutput: { [number: number]: string } = { + 1: 'northeast', + 3: 'southeast', + 5: 'southwest', + 7: 'northwest', +}; + const triggerSet: TriggerSet = { id: 'TheLunarSubteranne', zoneId: ZoneId.TheLunarSubterrane, @@ -24,6 +36,7 @@ const triggerSet: TriggerSet = { fountsSeen: 0, fountX: [], fountY: [], + staffMatches: [], }; }, triggers: [ @@ -74,6 +87,98 @@ const triggerSet: TriggerSet = { }, }, }, + { + id: 'Lunar Subterrane Dark Elf Ruinous Hex Collect', + type: 'StartsUsing', + netRegex: { id: ['89B6', '87DF'], source: 'Hexing Staff' }, // Ruinous Hex cast + run: (data, matches) => data.staffMatches.push(matches), + }, + { + id: 'Lunar Subterrane Dark Elf Ruinous Hex Call', + type: 'StartsUsing', + netRegex: { id: '8985', source: 'Dark Elf', capture: false }, // Cue off Ruinous Confluence + delaySeconds: 0.5, + alertText: (data, _matches, output) => { + // The origin for this encounter is -401.02,-231.01 + // On rounds 1/2, there is almost always a staff in a close square. + // The safespot in this situation is always diagonally opposite this close square. + // If there's no close staff, the pattern is always south safe or (assumedly) west safe. + // On round 3 and later, there is always one staff in a far corner, + // while two spawn framing the close square opposite this far one: + + // |-413|-405|-397|-389| + // |----|----|----|----| + // -243 |0000| | | | + // |----|----|----|----| + // -235 | | | |0000| + // |----|----|----|----| + // -227 | | | | | + // |----|----|----|----| + // -219 | |0000| | | + // |----|----|----|----| + + // (This can also be rotated 180 degrees.) + + // To date, only some squares have been observed to be populated. + // Blank squares here indicate locations that never have a staff. + // All coordinates are exact, although the log lines include two digits of precision. + // (-413.00, for instance.) + + // |-413|-405|-397|-389| + // |----|----|----|----| + // -243 |0000| |0000|0000| + // |----|----|----|----| + // -235 | | |0000|0000| + // |----|----|----|----| + // -227 |0000|0000|0000| | + // |----|----|----|----| + // -219 |0000|0000| |0000| + // |----|----|----|----| + + // There will *always* be a close safe square. + // Don't bother with potential safe outer squares. + let safeX = [-405, -397]; + let safeY = [-235, -227]; + + for (const staff of data.staffMatches) { + if (staff.x === undefined || staff.y === undefined) + return output.unknown!(); + const staffX = Math.round(parseFloat(staff.x)); + const staffY = Math.round(parseFloat(staff.y)); + safeX = safeX.filter((col) => col !== staffX); + safeY = safeY.filter((col) => col !== staffY); + } + + const finalX = safeX[0]; + const finalY = safeY[0]; + + // We don't really care about the specific safe coordinates, + // the important thing is that there's at least one safe in each of row and column. + if (finalX === undefined || finalY === undefined) + return output.unknown!(); + const safeNumber = Directions.xyTo8DirNum(finalX, finalY, elfCenterX, elfCenterY); + const outputSelect = dirNumberToOutput[safeNumber]; + if (outputSelect === undefined) + return output.unknown!(); + return output[outputSelect]!(); + }, + run: (data) => data.staffMatches = [], + outputStrings: { + northeast: { + en: 'Inner northeast safe', + }, + northwest: { + en: 'Inner northwest safe', + }, + southeast: { + en: 'Inner southeast safe', + }, + southwest: { + en: 'Inner southwest safe', + }, + unknown: Outputs.unknown, + }, + }, { id: 'Lunar Subterrane Dark Elf Doom', type: 'GainsEffect', @@ -331,6 +436,7 @@ const triggerSet: TriggerSet = { timelineReplace: [ { 'locale': 'de', + 'missingTranslations': true, 'replaceSync': { 'Aetheric Charge': 'magisch(?:e|er|es|en) Sphäre', 'Damcyan Antlion': 'damcyanisch(?:e|er|es|en) Ameisenlöwe', @@ -416,6 +522,7 @@ const triggerSet: TriggerSet = { }, { 'locale': 'ja', + 'missingTranslations': true, 'replaceSync': { 'Aetheric Charge': '魔力球', 'Damcyan Antlion': 'ダムシアン・アントリオン',