@@ -692,19 +692,17 @@ export default class Move implements Localizable {
692
692
/**
693
693
* Sees if a move has a custom failure text (by looking at each {@linkcode MoveAttr} of this move)
694
694
* @param user {@linkcode Pokemon } using the move
695
- * @param target {@linkcode Pokemon } receiving the move
696
- * @param move {@linkcode Move } using the move
697
- * @param cancelled {@linkcode Utils.BooleanHolder } to hold boolean value
695
+ * @param target {@linkcode Pokemon } target of the move
696
+ * @param move {@linkcode Move } with this attribute
698
697
* @returns string of the custom failure text, or `null` if it uses the default text ("But it failed!")
699
698
*/
700
- getFailedText ( user : Pokemon , target : Pokemon , move : Move , cancelled : Utils . BooleanHolder ) : string | null {
699
+ getFailedText ( user : Pokemon , target : Pokemon , move : Move ) : string | undefined {
701
700
for ( const attr of this . attrs ) {
702
- const failedText = attr . getFailedText ( user , target , move , cancelled ) ;
703
- if ( failedText !== null ) {
701
+ const failedText = attr . getFailedText ( user , target , move ) ;
702
+ if ( failedText ) {
704
703
return failedText ;
705
704
}
706
705
}
707
- return null ;
708
706
}
709
707
710
708
/**
@@ -1089,11 +1087,10 @@ export abstract class MoveAttr {
1089
1087
* @param user {@linkcode Pokemon } using the move
1090
1088
* @param target {@linkcode Pokemon } target of the move
1091
1089
* @param move {@linkcode Move } with this attribute
1092
- * @param cancelled {@linkcode Utils.BooleanHolder } which stores if the move should fail
1093
1090
* @returns the string representing failure of this {@linkcode Move}
1094
1091
*/
1095
- getFailedText ( user : Pokemon , target : Pokemon , move : Move , cancelled : Utils . BooleanHolder ) : string | null {
1096
- return null ;
1092
+ getFailedText ( user : Pokemon , target : Pokemon , move : Move ) : string | undefined {
1093
+ return ;
1097
1094
}
1098
1095
1099
1096
/**
@@ -1335,6 +1332,54 @@ export class PreMoveMessageAttr extends MoveAttr {
1335
1332
}
1336
1333
}
1337
1334
1335
+ /**
1336
+ * Attribute for moves that can be conditionally interrupted to be considered to
1337
+ * have failed before their "useMove" message is displayed. Currently used by
1338
+ * Focus Punch.
1339
+ * @extends MoveAttr
1340
+ */
1341
+ export class PreUseInterruptAttr extends MoveAttr {
1342
+ protected message ?: string | ( ( user : Pokemon , target : Pokemon , move : Move ) => string ) ;
1343
+ protected overridesFailedMessage : boolean ;
1344
+ protected conditionFunc : MoveConditionFunc ;
1345
+
1346
+ /**
1347
+ * Create a new MoveInterruptedMessageAttr.
1348
+ * @param message The message to display when the move is interrupted, or a function that formats the message based on the user, target, and move.
1349
+ */
1350
+ constructor ( message ?: string | ( ( user : Pokemon , target : Pokemon , move : Move ) => string ) , conditionFunc ?: MoveConditionFunc ) {
1351
+ super ( ) ;
1352
+ this . message = message ;
1353
+ this . conditionFunc = conditionFunc ?? ( ( ) => true ) ;
1354
+ }
1355
+
1356
+ /**
1357
+ * Message to display when a move is interrupted.
1358
+ * @param user {@linkcode Pokemon } using the move
1359
+ * @param target {@linkcode Pokemon } target of the move
1360
+ * @param move {@linkcode Move } with this attribute
1361
+ */
1362
+ override apply ( user : Pokemon , target : Pokemon , move : Move ) : boolean {
1363
+ return this . conditionFunc ( user , target , move ) ;
1364
+ }
1365
+
1366
+ /**
1367
+ * Message to display when a move is interrupted.
1368
+ * @param user {@linkcode Pokemon } using the move
1369
+ * @param target {@linkcode Pokemon } target of the move
1370
+ * @param move {@linkcode Move } with this attribute
1371
+ */
1372
+ override getFailedText ( user : Pokemon , target : Pokemon , move : Move ) : string | undefined {
1373
+ if ( this . message && this . conditionFunc ( user , target , move ) ) {
1374
+ const message =
1375
+ typeof this . message === "string"
1376
+ ? ( this . message as string )
1377
+ : this . message ( user , target , move ) ;
1378
+ return message ;
1379
+ }
1380
+ }
1381
+ }
1382
+
1338
1383
/**
1339
1384
* Attribute for Status moves that take attack type effectiveness
1340
1385
* into consideration (i.e. {@linkcode https://bulbapedia.bulbagarden.net/wiki/Thunder_Wave_(move) | Thunder Wave})
@@ -1754,13 +1799,16 @@ export class AddSubstituteAttr extends MoveEffectAttr {
1754
1799
return ( user , target , move ) => ! user . getTag ( SubstituteTag ) && user . hp > Math . floor ( user . getMaxHp ( ) * this . hpCost ) && user . getMaxHp ( ) > 1 ;
1755
1800
}
1756
1801
1757
- getFailedText ( user : Pokemon , target : Pokemon , move : Move , cancelled : Utils . BooleanHolder ) : string | null {
1802
+ /**
1803
+ * Get the substitute-specific failure message if one should be displayed.
1804
+ * @param user The pokemon using the move.
1805
+ * @returns The substitute-specific failure message if the conditions apply, otherwise `undefined`
1806
+ */
1807
+ getFailedText ( user : Pokemon , _target : Pokemon , _move : Move ) : string | undefined {
1758
1808
if ( user . getTag ( SubstituteTag ) ) {
1759
1809
return i18next . t ( "moveTriggers:substituteOnOverlap" , { pokemonName : getPokemonNameWithAffix ( user ) } ) ;
1760
1810
} else if ( user . hp <= Math . floor ( user . getMaxHp ( ) / 4 ) || user . getMaxHp ( ) === 1 ) {
1761
1811
return i18next . t ( "moveTriggers:substituteNotEnoughHp" ) ;
1762
- } else {
1763
- return i18next . t ( "battle:attackFailed" ) ;
1764
1812
}
1765
1813
}
1766
1814
}
@@ -6230,10 +6278,12 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
6230
6278
return ( user , target , move ) => ( move . category !== MoveCategory . STATUS || this . getSwitchOutCondition ( ) ( user , target , move ) ) ;
6231
6279
}
6232
6280
6233
- getFailedText ( user : Pokemon , target : Pokemon , move : Move , cancelled : Utils . BooleanHolder ) : string | null {
6281
+ getFailedText ( _user : Pokemon , target : Pokemon , _move : Move ) : string | undefined {
6234
6282
const blockedByAbility = new Utils . BooleanHolder ( false ) ;
6235
6283
applyAbAttrs ( ForceSwitchOutImmunityAbAttr , target , blockedByAbility ) ;
6236
- return blockedByAbility . value ? i18next . t ( "moveTriggers:cannotBeSwitchedOut" , { pokemonName : getPokemonNameWithAffix ( target ) } ) : null ;
6284
+ if ( blockedByAbility . value ) {
6285
+ return i18next . t ( "moveTriggers:cannotBeSwitchedOut" , { pokemonName : getPokemonNameWithAffix ( target ) } ) ;
6286
+ }
6237
6287
}
6238
6288
6239
6289
getSwitchOutCondition ( ) : MoveConditionFunc {
@@ -9185,8 +9235,8 @@ export function initMoves() {
9185
9235
. attr ( BypassBurnDamageReductionAttr ) ,
9186
9236
new AttackMove ( Moves . FOCUS_PUNCH , Type . FIGHTING , MoveCategory . PHYSICAL , 150 , 100 , 20 , - 1 , - 3 , 3 )
9187
9237
. attr ( MessageHeaderAttr , ( user , move ) => i18next . t ( "moveTriggers:isTighteningFocus" , { pokemonName : getPokemonNameWithAffix ( user ) } ) )
9188
- . punchingMove ( )
9189
- . condition ( ( user , target , move ) => ! user . turnData . attacksReceived . find ( r => r . damage ) ) ,
9238
+ . attr ( PreUseInterruptAttr , i18next . t ( "moveTriggers:lostFocus" ) , user => ! ! user . turnData . attacksReceived . find ( r => r . damage ) )
9239
+ . punchingMove ( ) ,
9190
9240
new AttackMove ( Moves . SMELLING_SALTS , Type . NORMAL , MoveCategory . PHYSICAL , 70 , 100 , 10 , - 1 , 0 , 3 )
9191
9241
. attr ( MovePowerMultiplierAttr , ( user , target , move ) => target . status ?. effect === StatusEffect . PARALYSIS ? 2 : 1 )
9192
9242
. attr ( HealStatusEffectAttr , true , StatusEffect . PARALYSIS ) ,
0 commit comments