From c5832a832de0cd1eff974257d465691aeccac37a Mon Sep 17 00:00:00 2001 From: valarnin Date: Sat, 4 Nov 2023 11:14:03 -0400 Subject: [PATCH] raidboss: UWU - Add ifrit phase change triggers (#5900) Add trigger for initial Ifrit position pre-dash, as well as safe spot away from dashes and radiant plumes. There might be a better way to detect Ifrit's initial positioning but I can't think of it. Maybe our next custom log line should be `ActorSetPos` or something, if that gets sent here? --- .../04-sb/ultimate/ultima_weapon_ultimate.ts | 144 +++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/ui/raidboss/data/04-sb/ultimate/ultima_weapon_ultimate.ts b/ui/raidboss/data/04-sb/ultimate/ultima_weapon_ultimate.ts index afe038384e..1029a0734f 100644 --- a/ui/raidboss/data/04-sb/ultimate/ultima_weapon_ultimate.ts +++ b/ui/raidboss/data/04-sb/ultimate/ultima_weapon_ultimate.ts @@ -3,7 +3,7 @@ import Outputs from '../../../../../resources/outputs'; import { callOverlayHandler } from '../../../../../resources/overlay_plugin_api'; import { Responses } from '../../../../../resources/responses'; import { NamedConfigEntry } from '../../../../../resources/user_config'; -import Util, { Directions } from '../../../../../resources/util'; +import Util, { DirectionOutputCardinal, Directions } from '../../../../../resources/util'; import ZoneId from '../../../../../resources/zone_id'; import { RaidbossData } from '../../../../../types/data'; import { PluginCombatantState } from '../../../../../types/event'; @@ -68,6 +68,8 @@ export interface Data extends RaidbossData { titanGaols: string[]; seenTitanGaols?: boolean; titanBury: NetMatches['AddedCombatant'][]; + ifritRadiantPlumeLocations: DirectionOutputCardinal[]; + possibleIfritIDs: string[]; } type GaolKey = Extract; @@ -147,6 +149,8 @@ const triggerSet: TriggerSet = { ifritUntargetableCount: 0, titanGaols: [], titanBury: [], + ifritRadiantPlumeLocations: [], + possibleIfritIDs: [], }; }, timelineTriggers: [ @@ -527,6 +531,144 @@ const triggerSet: TriggerSet = { }, }, // --------- Ifrit ---------- + { + id: 'UWU Ifrit Possible ID Locator', + type: 'StartsUsing', + netRegex: { id: '2B55', source: 'Garuda', capture: false }, + // Run this after the initial Garuda trigger and just piggyback off its call to `getCombatants` + // We're just looking to pluck the four possible IDs from the array pre-emptively to avoid doing + // that filter on every `CombatantMemory` line + delaySeconds: 25, + run: (data) => { + data.possibleIfritIDs = data.combatantData + .filter((c) => c.BNpcNameID === 0x4A1) + .map((c) => c.ID?.toString(16).toUpperCase() ?? ''); + }, + }, + { + id: 'UWU Ifrit Initial Dash Collector', + type: 'CombatantMemory', + // Filter to only enemy actors for performance + netRegex: { id: '4[0-9A-Fa-f]{7}', capture: true }, + condition: (data, matches) => { + if (!data.possibleIfritIDs.includes(matches.id)) + return false; + const posXVal = parseFloat(matches.pairPosX ?? '0'); + const posYVal = parseFloat(matches.pairPosY ?? '0'); + + if (posXVal === 0 || posYVal === 0) + return false; + + // If the Ifrit actor has jumped to exactly 19.5 out on a cardinal, that's our dash spot + if ( + Math.abs(posXVal - 100) - 19.5 < Number.EPSILON || + Math.abs(posYVal - 100) - 19.5 < Number.EPSILON + ) + return true; + + return false; + }, + suppressSeconds: 9999, + infoText: (data, matches, output) => { + const posXVal = parseFloat(matches.pairPosX ?? '0'); + const posYVal = parseFloat(matches.pairPosY ?? '0'); + + let ifritDir: DirectionOutputCardinal = 'unknown'; + + // Flag both sides that ifrit is dashing through as unsafe, while also tracking where he's actually + // jumped to so we can use it for the infoText + if (posXVal < 95) { + data.ifritRadiantPlumeLocations.push('dirW', 'dirE'); + ifritDir = 'dirW'; + } else if (posXVal > 105) { + data.ifritRadiantPlumeLocations.push('dirW', 'dirE'); + ifritDir = 'dirE'; + } else if (posYVal < 95) { + data.ifritRadiantPlumeLocations.push('dirN', 'dirS'); + ifritDir = 'dirN'; + } else if (posYVal > 105) { + data.ifritRadiantPlumeLocations.push('dirN', 'dirS'); + ifritDir = 'dirS'; + } + + // Remove duplicates + data.ifritRadiantPlumeLocations = data.ifritRadiantPlumeLocations + .filter((pos, index) => data.ifritRadiantPlumeLocations.indexOf(pos) === index); + + return output.text!({ dir: output[ifritDir]!() }); + }, + outputStrings: { + text: { + en: 'Ifrit ${dir}', + }, + unknown: Outputs.unknown, + ...Directions.outputStringsCardinalDir, + }, + }, + { + id: 'UWU Ifrit Initial Radiant Plume Collector', + type: 'StartsUsingExtra', + netRegex: { id: '2B61' }, + condition: (data, matches) => { + const posXVal = parseFloat(matches.x); + const posYVal = parseFloat(matches.y); + + // Possible plume locations: + // 100.009, 106.998 + // 100.009, 118.015 = south + // 100.009, 92.990 + // 100.009, 82.003 = north + // 106.998, 100.009 + // 110.996, 110.996 + // 110.996, 88.992 + // 118.015, 100.009 = east + // 82.003, 100.009 = west + // 88.992, 110.996 + // 88.992, 88.992 + // 92.990, 100.009 + + if (Math.abs(posXVal - 100) < 1) { + if (Math.abs(posYVal - 83) < 1) { + // North unsafe + data.ifritRadiantPlumeLocations.push('dirN'); + } else if (Math.abs(posYVal - 118) < 1) { + // South unsafe + data.ifritRadiantPlumeLocations.push('dirS'); + } + } else if (Math.abs(posYVal - 100) < 1) { + if (Math.abs(posXVal - 83) < 1) { + // West unsafe + data.ifritRadiantPlumeLocations.push('dirW'); + } else if (Math.abs(posXVal - 118) < 1) { + // East unsafe + data.ifritRadiantPlumeLocations.push('dirE'); + } + } + + // Remove duplicates + data.ifritRadiantPlumeLocations = data.ifritRadiantPlumeLocations + .filter((pos, index) => data.ifritRadiantPlumeLocations.indexOf(pos) === index); + + // 3 danger spots means we only have one safe spot left + return data.ifritRadiantPlumeLocations.length === 3; + }, + suppressSeconds: 5, + infoText: (data, _matches, output) => { + if (data.ifritRadiantPlumeLocations.length < 3) + return; + + const safeDir = + Directions.outputCardinalDir.filter((dir) => + !data.ifritRadiantPlumeLocations.includes(dir) + )[0]; + + return output[safeDir ?? 'unknown']!(); + }, + outputStrings: { + unknown: Outputs.unknown, + ...Directions.outputStringsCardinalDir, + }, + }, { id: 'UWU Ifrit Vulcan Burst', type: 'StartsUsing',