@@ -6,8 +6,18 @@ import { RaidbossData } from '../../../../../types/data';
6
6
import { TriggerSet } from '../../../../../types/trigger' ;
7
7
8
8
export interface Data extends RaidbossData {
9
+ // The in/out comes before the stacks/spread markers, this value is the
10
+ // "current" mechanic so that we can call "spread out" after hair raid finishes.
11
+ barberyMechanic ?: 'stack' | 'spread' ;
12
+ // This value records once we've seen a given savage barbery mechanic,
13
+ // what the next one is going to be to call out slightly earlier.
14
+ nextBarberyMechanic ?: 'stack' | 'spread' ;
15
+ secretBreezeCount : number ;
16
+ boulderBreakCount : number ;
9
17
boldBoulderTargets : string [ ] ;
10
18
hairFlayUpbraidTargets : string [ ] ;
19
+ blowAwayCount : number ;
20
+ blowAwayPuddleCount : number ;
11
21
}
12
22
13
23
const triggerSet : TriggerSet < Data > = {
@@ -16,25 +26,49 @@ const triggerSet: TriggerSet<Data> = {
16
26
timelineFile : 'barbariccia-ex.txt' ,
17
27
initData : ( ) => {
18
28
return {
29
+ secretBreezeCount : 0 ,
19
30
boldBoulderTargets : [ ] ,
31
+ boulderBreakCount : 0 ,
20
32
hairFlayUpbraidTargets : [ ] ,
33
+ blowAwayCount : 0 ,
34
+ blowAwayPuddleCount : 0 ,
21
35
} ;
22
36
} ,
23
37
timelineTriggers : [
24
38
{
25
39
id : 'BarbaricciaEx Knuckle Drum' ,
26
40
regex : / K n u c k l e D r u m / ,
27
41
beforeSeconds : 5 ,
42
+ suppressSeconds : 15 ,
28
43
response : Responses . bigAoe ( ) ,
29
44
} ,
30
45
{
31
46
id : 'BarbaricciaEx Blow Away' ,
32
47
regex : / B l o w A w a y / ,
33
- beforeSeconds : 5 ,
34
- response : Responses . getTogether ( 'info' ) ,
48
+ beforeSeconds : 10 ,
49
+ durationSeconds : 5 ,
50
+ suppressSeconds : 15 ,
51
+ infoText : ( _data , _matches , output ) => output . text ! ( ) ,
52
+ outputStrings : {
53
+ text : {
54
+ en : 'Stack to Bait Puddles' ,
55
+ } ,
56
+ } ,
35
57
} ,
36
58
] ,
37
59
triggers : [
60
+ {
61
+ id : 'BarbaricciaEx Curling Iron Cleanup' ,
62
+ type : 'StartsUsing' ,
63
+ netRegex : { id : '75B2' , source : 'Barbariccia' , capture : false } ,
64
+ suppressSeconds : 5 ,
65
+ run : ( data ) => {
66
+ // This is mostly to clean up the rogue "Hair Spray" that happens
67
+ // not during Savage Barbery.
68
+ delete data . barberyMechanic ;
69
+ delete data . nextBarberyMechanic ;
70
+ } ,
71
+ } ,
38
72
{
39
73
id : 'BarbaricciaEx Void Aero IV' ,
40
74
type : 'StartsUsing' ,
@@ -78,62 +112,151 @@ const triggerSet: TriggerSet<Data> = {
78
112
id : 'BarbaricciaEx Hair Raid Donut' ,
79
113
type : 'StartsUsing' ,
80
114
netRegex : { id : '757E' , source : 'Barbariccia' , capture : false } ,
81
- response : Responses . getIn ( ) ,
115
+ durationSeconds : ( data ) => data . nextBarberyMechanic === undefined ? undefined : 5 ,
116
+ alertText : ( data , _matches , output ) => {
117
+ if ( data . nextBarberyMechanic === 'stack' )
118
+ return output . inAndHealerGroups ! ( ) ;
119
+ if ( data . nextBarberyMechanic === 'spread' )
120
+ return output . inThenSpread ! ( ) ;
121
+ return output . in ! ( ) ;
122
+ } ,
123
+ outputStrings : {
124
+ in : Outputs . in ,
125
+ inThenSpread : {
126
+ en : 'In => Spread' ,
127
+ } ,
128
+ inAndHealerGroups : {
129
+ en : 'In => Healer Groups' ,
130
+ } ,
131
+ } ,
132
+ } ,
133
+ {
134
+ id : 'BarbaricciaEx Hair Raid Donut Move' ,
135
+ type : 'Ability' ,
136
+ netRegex : { id : '757F' , source : 'Barbariccia' , capture : false } ,
137
+ condition : ( data ) => data . barberyMechanic === 'spread' ,
138
+ suppressSeconds : 5 ,
139
+ alertText : ( _data , _matches , output ) => output . text ! ( ) ,
140
+ outputStrings : {
141
+ text : {
142
+ en : 'Spread Out' ,
143
+ } ,
144
+ } ,
82
145
} ,
83
146
{
84
147
id : 'BarbaricciaEx Hair Raid Wall' ,
85
148
type : 'StartsUsing' ,
86
149
netRegex : { id : '757C' , source : 'Barbariccia' , capture : false } ,
87
- alertText : ( _data , _matches , output ) => output . text ! ( ) ,
150
+ durationSeconds : ( data ) => data . nextBarberyMechanic === undefined ? undefined : 5 ,
151
+ alertText : ( data , _matches , output ) => {
152
+ if ( data . nextBarberyMechanic === 'stack' )
153
+ return output . wallAndHealerGroups ! ( ) ;
154
+ if ( data . nextBarberyMechanic === 'spread' )
155
+ return output . wallThenSpread ! ( ) ;
156
+ return output . wall ! ( ) ;
157
+ } ,
88
158
outputStrings : {
89
- text : {
159
+ wall : {
90
160
en : 'Wall' ,
91
161
de : 'Wand' ,
92
162
fr : 'Mur' ,
93
163
ja : '壁へ' ,
94
164
cn : '去场边' ,
95
165
ko : '벽으로' ,
96
166
} ,
167
+ wallAndHealerGroups : {
168
+ en : 'Wall + Healer Groups' ,
169
+ } ,
170
+ wallThenSpread : {
171
+ en : 'Wall => Spread' ,
172
+ } ,
173
+ } ,
174
+ } ,
175
+ {
176
+ id : 'BarbaricciaEx Hair Raid Wall Move' ,
177
+ type : 'Ability' ,
178
+ netRegex : { id : '757D' , source : 'Barbariccia' , capture : false } ,
179
+ condition : ( data ) => data . barberyMechanic === 'spread' ,
180
+ suppressSeconds : 5 ,
181
+ alertText : ( _data , _matches , output ) => output . text ! ( ) ,
182
+ outputStrings : {
183
+ text : {
184
+ en : 'Spread Out' ,
185
+ } ,
97
186
} ,
98
187
} ,
99
188
{
100
189
id : 'BarbaricciaEx Hair Spray' ,
101
190
type : 'StartsUsing' ,
102
- // This spread mechanic is used later in other phases of the fight as well.
103
191
netRegex : { id : '75A6' , source : 'Barbariccia' , capture : false } ,
104
192
suppressSeconds : 1 ,
105
- response : Responses . spread ( ) ,
193
+ infoText : ( data , _matches , output ) => {
194
+ // This spread mechanic is used later in other phases of the fight as well.
195
+ // However, that extra usage is fixed in the Curling Iron Cleanup trigger.
196
+ data . barberyMechanic = 'spread' ;
197
+ data . nextBarberyMechanic ??= 'stack' ;
198
+
199
+ // Suppress extra "spread" if we handled it in Hair Raid.
200
+ if ( data . nextBarberyMechanic === 'spread' ) {
201
+ delete data . nextBarberyMechanic ;
202
+ return ;
203
+ }
204
+ return output . spread ! ( ) ;
205
+ } ,
206
+ outputStrings : {
207
+ spread : Outputs . spread ,
208
+ } ,
106
209
} ,
107
210
{
108
211
id : 'BarbaricciaEx Deadly Twist' ,
109
212
type : 'StartsUsing' ,
110
213
netRegex : { id : '75A7' , source : 'Barbariccia' , capture : false } ,
111
214
suppressSeconds : 2 ,
112
- infoText : ( _data , _matches , output ) => output . groups ! ( ) ,
215
+ infoText : ( data , _matches , output ) => {
216
+ data . barberyMechanic = 'stack' ;
217
+ data . nextBarberyMechanic ??= 'spread' ;
218
+
219
+ // Suppress extra "stack" if we handled it in Hair Raid.
220
+ if ( data . nextBarberyMechanic === 'stack' ) {
221
+ delete data . nextBarberyMechanic ;
222
+ return ;
223
+ }
224
+ return output . groups ! ( ) ;
225
+ } ,
113
226
outputStrings : {
114
- groups : {
115
- en : 'Healer Groups' ,
116
- de : 'Heiler-Gruppen' ,
117
- fr : 'Groupes sur les heals' ,
118
- ja : 'ヒラに頭割り' ,
119
- cn : '治疗分组分摊' ,
120
- ko : '힐러 그룹 쉐어' ,
121
- } ,
227
+ groups : Outputs . healerGroups ,
122
228
} ,
123
229
} ,
124
230
{
125
231
id : 'BarbaricciaEx Void Aero III' ,
126
232
type : 'StartsUsing' ,
127
233
netRegex : { id : '7571' , source : 'Barbariccia' } ,
128
- condition : Conditions . caresAboutPhysical ( ) ,
129
234
response : Responses . tankBusterSwap ( ) ,
130
235
} ,
131
236
{
132
- id : 'BarbaricciaEx Secret Breeze' ,
237
+ id : 'BarbaricciaEx Secret Breeze 1' ,
238
+ type : 'Ability' ,
239
+ // Trigger on 7413 Hair Flay (large spreads during partner stacks)
240
+ netRegex : { id : '7413' , source : 'Barbariccia' , capture : false } ,
241
+ suppressSeconds : 1 ,
242
+ alertText : ( _data , _matches , output ) => output . protean ! ( ) ,
243
+ outputStrings : {
244
+ protean : {
245
+ en : 'Protean Spread' ,
246
+ } ,
247
+ } ,
248
+ } ,
249
+ {
250
+ id : 'BarbaricciaEx Secret Breeze Others' ,
133
251
type : 'StartsUsing' ,
134
252
netRegex : { id : '7580' , source : 'Barbariccia' , capture : false } ,
253
+ preRun : ( data ) => data . secretBreezeCount ++ ,
135
254
durationSeconds : 3 ,
136
- alertText : ( _data , _matches , output ) => output . protean ! ( ) ,
255
+ alertText : ( data , _matches , output ) => {
256
+ // On the first one, don't call too early. Call after the spread/partner stacks go off.
257
+ if ( data . secretBreezeCount !== 1 )
258
+ return output . protean ! ( ) ;
259
+ } ,
137
260
outputStrings : {
138
261
protean : {
139
262
en : 'Protean' ,
@@ -152,14 +275,15 @@ const triggerSet: TriggerSet<Data> = {
152
275
response : Responses . sharedTankBuster ( ) ,
153
276
} ,
154
277
{
155
- id : 'BarbaricciaEx Brittle Boulder' ,
156
- type : 'HeadMarker' ,
157
- netRegex : { id : '016D' , capture : false } ,
158
- suppressSeconds : 2 ,
278
+ id : 'BarbaricciaEx Brittle Boulder 1' ,
279
+ type : 'Ability' ,
280
+ netRegex : { id : '7383' , source : 'Barbariccia' , capture : false } ,
281
+ durationSeconds : 8 ,
282
+ suppressSeconds : 5 ,
159
283
alertText : ( _data , _matches , output ) => output . text ! ( ) ,
160
284
outputStrings : {
161
285
text : {
162
- en : 'Bait Middle => Out ( Spread) ' ,
286
+ en : 'Bait Middle => Out + Spread' ,
163
287
de : 'In der Mitte Ködern => Raus (verteilen)' ,
164
288
fr : 'Posez au centre -> Écartez-vous à l\'extérieur' ,
165
289
ja : '真ん中で誘導 => 8方向散開' ,
@@ -168,6 +292,18 @@ const triggerSet: TriggerSet<Data> = {
168
292
} ,
169
293
} ,
170
294
} ,
295
+ {
296
+ id : 'BarbaricciaEx Boulder' ,
297
+ type : 'HeadMarker' ,
298
+ netRegex : { id : '0173' , capture : false } ,
299
+ suppressSeconds : 2 ,
300
+ infoText : ( _data , _matches , output ) => output . text ! ( ) ,
301
+ outputStrings : {
302
+ text : {
303
+ en : 'Out + Spread' ,
304
+ } ,
305
+ } ,
306
+ } ,
171
307
{
172
308
// These also favor a certain order of Tank/Healer for first set then DPS second set,
173
309
// but if people are dead anybody can get these.
@@ -191,8 +327,13 @@ const triggerSet: TriggerSet<Data> = {
191
327
id : 'BarbaricciaEx Brutal Rush Move' ,
192
328
type : 'Ability' ,
193
329
// When the Brutal Rush hits you, the follow-up Brutal Gust has locked in.
194
- netRegex : { id : '7583' , source : 'Barbariccia' } ,
195
- condition : Conditions . targetIsYou ( ) ,
330
+ netRegex : { id : [ '7583' , '7584' ] , source : 'Barbariccia' } ,
331
+ condition : ( data , matches ) => {
332
+ // Suppress during the middle of puddles where these are (usually) naturally dodged.
333
+ if ( data . blowAwayPuddleCount !== 0 && data . blowAwayPuddleCount !== 4 )
334
+ return false ;
335
+ return matches . target === data . me ;
336
+ } ,
196
337
response : Responses . moveAway ( ) ,
197
338
} ,
198
339
{
@@ -290,6 +431,39 @@ const triggerSet: TriggerSet<Data> = {
290
431
stackMarker : Outputs . stackMarker ,
291
432
} ,
292
433
} ,
434
+ {
435
+ id : 'BarbaricciaEx Blow Away Reset' ,
436
+ type : 'Ability' ,
437
+ netRegex : { id : '7595' , source : 'Barbariccia' , capture : false } ,
438
+ run : ( data ) => {
439
+ data . blowAwayCount ++ ;
440
+ data . blowAwayPuddleCount = 0 ;
441
+ } ,
442
+ } ,
443
+ {
444
+ id : 'BarbaricciaEx Blow Away Puddle Count' ,
445
+ type : 'StartsUsing' ,
446
+ netRegex : { id : '7596' , source : 'Barbariccia' , capture : false } ,
447
+ preRun : ( data ) => data . blowAwayPuddleCount ++ ,
448
+ suppressSeconds : 1 ,
449
+ alertText : ( data , _matches , output ) => {
450
+ // This handles Brittle Boulder 2 as well.
451
+ if ( data . blowAwayCount === 2 && data . blowAwayPuddleCount === 4 )
452
+ return output . stackMiddle ! ( ) ;
453
+ } ,
454
+ infoText : ( data , _matches , output ) => {
455
+ return output [ `num${ data . blowAwayPuddleCount } ` ] ! ( ) ;
456
+ } ,
457
+ outputStrings : {
458
+ num1 : Outputs . num1 ,
459
+ num2 : Outputs . num2 ,
460
+ num3 : Outputs . num3 ,
461
+ num4 : Outputs . num4 ,
462
+ stackMiddle : {
463
+ en : 'Bait Middle' ,
464
+ } ,
465
+ } ,
466
+ } ,
293
467
{
294
468
id : 'BarbaricciaEx Impact' ,
295
469
type : 'StartsUsing' ,
0 commit comments