@@ -7,8 +7,17 @@ import { RaidbossData } from '../../../../../types/data';
77import { NetMatches } from '../../../../../types/net_matches' ;
88import { TriggerSet } from '../../../../../types/trigger' ;
99
10+ type CoffinfillerPosition =
11+ | 'outerWest'
12+ | 'innerWest'
13+ | 'innerEast'
14+ | 'outerEast'
15+ | 'inside'
16+ | 'outside' ;
17+
1018export 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