Skip to content

Commit ca9edf4

Browse files
authored
raidboss: r9s Half Moon cleaves (#933)
Vamp Fatale uses Half Moon several times during the coffinmaker add phase, as well as once later in the fight. Use her heading to determine the facing direction for a callout. This works for all uses, so that we don't have to track phases in the data object. This does not take into account the aoes from the coffin maker. I don't yet know how to track which sections will get hit first, and we'll need to figure out a decent callout system. For the last section when its east/west hits, it could be something like using in or out to indicate, but that doesn't work well for north/south cleaves, and a short callout could be tricky. Either way, calling out the halfmoon should be helpful. Signed-off-by: Jacob Keller <jacob.keller@gmail.com> --------- Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
1 parent 19f363f commit ca9edf4

2 files changed

Lines changed: 197 additions & 0 deletions

File tree

resources/outputs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,9 @@ export default {
600600
ko: '오른쪽',
601601
tc: '右',
602602
},
603+
rightEast: {
604+
en: 'Right/East',
605+
},
603606
left: {
604607
en: 'Left',
605608
de: 'Links',
@@ -609,6 +612,9 @@ export default {
609612
ko: '왼쪽',
610613
tc: '左',
611614
},
615+
leftWest: {
616+
en: 'Left/West',
617+
},
612618
getLeftAndWest: {
613619
en: '<= Get Left/West',
614620
de: '<= Nach Links/Westen',

ui/raidboss/data/07-dt/raid/r9s.ts

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@ import { RaidbossData } from '../../../../../types/data';
77
import { NetMatches } from '../../../../../types/net_matches';
88
import { TriggerSet } from '../../../../../types/trigger';
99

10+
type CoffinfillerPosition =
11+
| 'outerWest'
12+
| 'innerWest'
13+
| 'innerEast'
14+
| 'outerEast'
15+
| 'inside'
16+
| 'outside';
17+
1018
export interface Data extends RaidbossData {
1119
flailPositions: NetMatches['StartsUsingExtra'][];
20+
coffinfillers: CoffinfillerPosition[];
1221
actorPositions: { [id: string]: { x: number; y: number; heading: number } };
1322
bats: {
1423
inner: DirectionOutput16[];
@@ -42,6 +51,7 @@ const triggerSet: TriggerSet<Data> = {
4251
timelineFile: 'r9s.txt',
4352
initData: () => ({
4453
flailPositions: [],
54+
coffinfillers: [],
4555
actorPositions: {},
4656
bats: { inner: [], middle: [], outer: [] },
4757
satisfiedCount: 0,
@@ -228,6 +238,187 @@ const triggerSet: TriggerSet<Data> = {
228238
netRegex: { id: 'B333', source: 'Vamp Fatale', capture: false },
229239
response: Responses.bigAoe(),
230240
},
241+
{
242+
id: 'R9S Coffinfiller',
243+
type: 'StartsUsingExtra',
244+
netRegex: { id: ['B368', 'B369', 'B36A'], capture: true },
245+
suppressSeconds: (data) => data.coffinfillers.length === 0 ? 0 : 5,
246+
run: (data, matches) => {
247+
let danger: CoffinfillerPosition;
248+
const xPos = parseFloat(matches.x);
249+
if (xPos < 95)
250+
danger = 'outerWest';
251+
else if (xPos < 100)
252+
danger = 'innerWest';
253+
else if (xPos < 105)
254+
danger = 'innerEast';
255+
else
256+
danger = 'outerEast';
257+
data.coffinfillers.push(danger);
258+
},
259+
},
260+
{
261+
id: 'R9S Half Moon',
262+
type: 'StartsUsingExtra',
263+
netRegex: { id: ['B377', 'B379', 'B37B', 'B37D'], capture: true },
264+
delaySeconds: 0.3,
265+
alertText: (data, matches, output) => {
266+
if (data.coffinfillers.length < 2) {
267+
if (matches.id === 'B377')
268+
return output.rightThenLeft!();
269+
if (matches.id === 'B37B')
270+
return output.leftThenRight!();
271+
return output.bigHalfmoonNoCoffin!({
272+
dir1: output[matches.id === 'B379' ? 'right' : 'left']!(),
273+
dir2: output[matches.id === 'B379' ? 'left' : 'right']!(),
274+
});
275+
}
276+
277+
const attackDirNum = Directions.hdgTo4DirNum(parseFloat(matches.heading));
278+
const dirNum1 = (attackDirNum + 2) % 4;
279+
const dir1 = Directions.outputFromCardinalNum(dirNum1);
280+
const dirNum2 = attackDirNum;
281+
const dir2 = Directions.outputFromCardinalNum(dirNum2);
282+
const bigCleave = matches.id === 'B379' || matches.id === 'B37D';
283+
284+
const insidePositions: CoffinfillerPosition[] = [
285+
'innerWest',
286+
'innerEast',
287+
];
288+
289+
const outsidePositions: CoffinfillerPosition[] = [
290+
'outerWest',
291+
'outerEast',
292+
];
293+
294+
const westPositions: CoffinfillerPosition[] = [
295+
'innerWest',
296+
'outerWest',
297+
];
298+
299+
const eastPositions: CoffinfillerPosition[] = [
300+
'innerEast',
301+
'outerEast',
302+
];
303+
304+
let coffinSafe1: CoffinfillerPosition[] = [
305+
'outerWest',
306+
'innerWest',
307+
'innerEast',
308+
'outerEast',
309+
];
310+
coffinSafe1 = coffinSafe1.filter((pos) => !data.coffinfillers.includes(pos));
311+
312+
let coffinSafe2: CoffinfillerPosition[] = [
313+
'outerWest',
314+
'innerWest',
315+
'innerEast',
316+
'outerEast',
317+
];
318+
// Whatever gets hit first round will be safe second round
319+
coffinSafe2 = coffinSafe2.filter((pos) => data.coffinfillers.includes(pos));
320+
321+
data.coffinfillers = [];
322+
323+
let dir1Text = output[dir1]!();
324+
let dir2Text = output[dir2]!();
325+
326+
if (dir1 === 'dirW') {
327+
coffinSafe1 = coffinSafe1.filter((pos) => !westPositions.includes(pos));
328+
dir1Text = output.leftWest!();
329+
}
330+
331+
if (dir1 === 'dirE') {
332+
coffinSafe1 = coffinSafe1.filter((pos) => !eastPositions.includes(pos));
333+
dir1Text = output.rightEast!();
334+
}
335+
336+
if (dir2 === 'dirW') {
337+
coffinSafe2 = coffinSafe2.filter((pos) => !westPositions.includes(pos));
338+
dir2Text = output.leftWest!();
339+
}
340+
341+
if (dir2 === 'dirE') {
342+
coffinSafe2 = coffinSafe2.filter((pos) => !eastPositions.includes(pos));
343+
dir2Text = output.rightEast!();
344+
}
345+
346+
let coffin1: CoffinfillerPosition | 'unknown';
347+
let coffin2: CoffinfillerPosition | 'unknown';
348+
349+
if (coffinSafe1.every((pos) => insidePositions.includes(pos)))
350+
coffin1 = 'inside';
351+
else if (coffinSafe1.every((pos) => outsidePositions.includes(pos)))
352+
coffin1 = 'outside';
353+
else
354+
coffin1 = coffinSafe1.find((pos) => insidePositions.includes(pos)) ?? 'unknown';
355+
356+
if (coffinSafe2.every((pos) => insidePositions.includes(pos)))
357+
coffin2 = 'inside';
358+
else if (coffinSafe2.every((pos) => outsidePositions.includes(pos)))
359+
coffin2 = 'outside';
360+
else
361+
coffin2 = coffinSafe2.find((pos) => insidePositions.includes(pos)) ?? 'unknown';
362+
363+
if (bigCleave) {
364+
return output.bigHalfmoonCombined!({
365+
coffin1: output[coffin1]!(),
366+
dir1: dir1Text,
367+
coffin2: output[coffin2]!(),
368+
dir2: dir2Text,
369+
});
370+
}
371+
372+
return output.combined!({
373+
coffin1: output[coffin1]!(),
374+
dir1: dir1Text,
375+
coffin2: output[coffin2]!(),
376+
dir2: dir2Text,
377+
});
378+
},
379+
outputStrings: {
380+
...Directions.outputStringsCardinalDir,
381+
text: {
382+
en: '${first} => ${second}',
383+
},
384+
combined: {
385+
en: '${coffin1} + ${dir1} => ${coffin2} + ${dir2}',
386+
},
387+
bigHalfmoonCombined: {
388+
en: '${coffin1} + ${dir1} (big) => ${coffin2} + ${dir2} (big)',
389+
},
390+
rightThenLeft: Outputs.rightThenLeft,
391+
leftThenRight: Outputs.leftThenRight,
392+
left: Outputs.left,
393+
leftWest: Outputs.leftWest,
394+
right: Outputs.right,
395+
rightEast: Outputs.rightEast,
396+
inside: {
397+
en: 'Inside',
398+
},
399+
outside: {
400+
en: 'Outside',
401+
},
402+
outerWest: {
403+
en: 'Outer West',
404+
},
405+
innerWest: {
406+
en: 'Inner West',
407+
},
408+
innerEast: {
409+
en: 'Inner East',
410+
},
411+
outerEast: {
412+
en: 'Outer East',
413+
},
414+
bigHalfmoonNoCoffin: {
415+
en: '${dir1} max melee => ${dir2} max melee',
416+
fr: '${dir1} max melée => ${dir2} max melée',
417+
cn: '${dir1} 最大近战距离 => ${dir2} 最大近战距离',
418+
ko: '${dir1} 칼끝딜 => ${dir2} 칼끝딜',
419+
},
420+
},
421+
},
231422
{
232423
id: 'R9S Crowd Kill',
233424
type: 'StartsUsing',

0 commit comments

Comments
 (0)