2024-02-29 20:08:50 -05:00
import Pokemon , { HitResult , PokemonMove } from "../field/pokemon" ;
2024-01-13 12:24:24 -05:00
import { Type } from "./type" ;
2024-06-19 12:00:26 -04:00
import { Constructor } from "#app/utils" ;
2023-04-26 23:33:13 -04:00
import * as Utils from "../utils" ;
2023-04-27 01:14:15 -04:00
import { BattleStat , getBattleStatName } from "./battle-stat" ;
2024-05-25 06:00:58 +02:00
import { MovePhase , PokemonHealPhase , ShowAbilityPhase , StatChangePhase } from "../phases" ;
2024-06-06 15:36:12 +02:00
import { getPokemonMessage , getPokemonNameWithAffix } from "../messages" ;
2023-04-27 14:30:03 -04:00
import { Weather , WeatherType } from "./weather" ;
2024-06-23 09:48:49 -07:00
import { BattlerTag , GroundedTag } from "./battler-tags" ;
2024-05-27 05:01:03 -06:00
import { StatusEffect , getNonVolatileStatusEffects , getStatusEffectDescriptor , getStatusEffectHealText } from "./status-effect" ;
2024-04-14 13:15:01 -04:00
import { Gender } from "./gender" ;
2024-06-26 13:03:14 -07:00
import Move , { AttackMove , MoveCategory , MoveFlags , MoveTarget , FlinchAttr , OneHitKOAttr , HitHealAttr , allMoves , StatusMove , SelfStatusMove , VariablePowerAttr , applyMoveAttrs , IncrementMovePriorityAttr , VariableMoveTypeAttr , RandomMovesetMoveAttr , RandomMoveAttr , NaturePowerAttr , CopyMoveAttr , MoveAttr , MultiHitAttr , ChargeAttr , SacrificialAttr , SacrificialAttrOnHit } from "./move" ;
2024-04-21 23:05:36 -04:00
import { ArenaTagSide , ArenaTrapTag } from "./arena-tag" ;
2024-06-11 06:37:10 -07:00
import { Stat , getStatName } from "./pokemon-stat" ;
2024-05-22 08:52:45 -04:00
import { BerryModifier , PokemonHeldItemModifier } from "../modifier/modifier" ;
2024-03-13 12:23:31 -05:00
import { TerrainType } from "./terrain" ;
2024-03-30 00:53:35 -04:00
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms" ;
2024-06-17 17:05:33 -04:00
import i18next from "i18next" ;
import { Localizable } from "#app/interfaces/locales.js" ;
2024-04-25 14:29:05 -04:00
import { Command } from "../ui/command-ui-handler" ;
2024-05-22 08:52:45 -04:00
import { BerryModifierType } from "#app/modifier/modifier-type" ;
2024-05-25 05:51:36 -04:00
import { getPokeballName } from "./pokeball" ;
2024-06-05 19:10:24 +02:00
import { BattlerIndex } from "#app/battle" ;
2024-06-13 18:44:23 -04:00
import { Abilities } from "#enums/abilities" ;
import { ArenaTagType } from "#enums/arena-tag-type" ;
import { BattlerTagType } from "#enums/battler-tag-type" ;
import { Moves } from "#enums/moves" ;
import { Species } from "#enums/species" ;
2023-04-26 23:33:13 -04:00
2024-04-25 03:10:09 +02:00
export class Ability implements Localizable {
2023-04-15 20:36:19 -04:00
public id : Abilities ;
2024-04-24 22:42:09 -04:00
private nameAppend : string ;
2023-04-15 20:36:19 -04:00
public name : string ;
public description : string ;
public generation : integer ;
2024-04-11 09:24:03 -04:00
public isBypassFaint : boolean ;
2024-03-14 00:40:57 -04:00
public isIgnorable : boolean ;
2023-04-27 14:30:03 -04:00
public attrs : AbAttr [ ] ;
public conditions : AbAttrCondition [ ] ;
2023-04-15 20:36:19 -04:00
2024-04-25 03:10:09 +02:00
constructor ( id : Abilities , generation : integer ) {
2023-04-15 20:36:19 -04:00
this . id = id ;
2024-04-24 22:42:09 -04:00
2024-05-23 17:03:10 +02:00
this . nameAppend = "" ;
2023-04-15 20:36:19 -04:00
this . generation = generation ;
2023-04-26 23:33:13 -04:00
this . attrs = [ ] ;
2023-04-27 14:30:03 -04:00
this . conditions = [ ] ;
2024-04-25 03:10:09 +02:00
this . localize ( ) ;
}
localize ( ) : void {
2024-05-23 17:03:10 +02:00
const i18nKey = Abilities [ this . id ] . split ( "_" ) . filter ( f = > f ) . map ( ( f , i ) = > i ? ` ${ f [ 0 ] } ${ f . slice ( 1 ) . toLowerCase ( ) } ` : f . toLowerCase ( ) ) . join ( "" ) as string ;
2024-04-25 03:10:09 +02:00
2024-05-23 17:03:10 +02:00
this . name = this . id ? ` ${ i18next . t ( ` ability: ${ i18nKey } .name ` ) as string } ${ this . nameAppend } ` : "" ;
this . description = this . id ? i18next . t ( ` ability: ${ i18nKey } .description ` ) as string : "" ;
2023-04-26 23:33:13 -04:00
}
2024-05-31 20:50:30 -04:00
/ * *
* Get all ability attributes that match ` attrType `
* @param attrType any attribute that extends { @linkcode AbAttr }
* @returns Array of attributes that match ` attrType ` , Empty Array if none match .
* /
2024-06-19 12:00:26 -04:00
getAttrs < T extends AbAttr > ( attrType : Constructor < T > ) : T [ ] {
2024-05-31 20:50:30 -04:00
return this . attrs . filter ( ( a ) : a is T = > a instanceof attrType ) ;
}
/ * *
* Check if an ability has an attribute that matches ` attrType `
* @param attrType any attribute that extends { @linkcode AbAttr }
* @returns true if the ability has attribute ` attrType `
* /
2024-06-19 12:00:26 -04:00
hasAttr < T extends AbAttr > ( attrType : Constructor < T > ) : boolean {
2024-05-31 20:50:30 -04:00
return this . attrs . some ( ( attr ) = > attr instanceof attrType ) ;
2023-04-26 23:33:13 -04:00
}
2024-06-19 12:00:26 -04:00
attr < T extends Constructor < AbAttr > > ( AttrType : T , . . . args : ConstructorParameters < T > ) : Ability {
2023-04-26 23:33:13 -04:00
const attr = new AttrType ( . . . args ) ;
this . attrs . push ( attr ) ;
return this ;
2023-04-15 20:36:19 -04:00
}
2023-04-27 14:30:03 -04:00
2024-06-19 12:00:26 -04:00
conditionalAttr < T extends Constructor < AbAttr > > ( condition : AbAttrCondition , AttrType : T , . . . args : ConstructorParameters < T > ) : Ability {
2023-12-23 01:21:01 -05:00
const attr = new AttrType ( . . . args ) ;
attr . addCondition ( condition ) ;
this . attrs . push ( attr ) ;
2024-05-24 01:45:04 +02:00
2023-12-23 01:21:01 -05:00
return this ;
}
2024-05-24 01:45:04 +02:00
2024-04-11 09:24:03 -04:00
bypassFaint ( ) : Ability {
this . isBypassFaint = true ;
2023-12-22 23:57:05 -05:00
return this ;
}
2024-03-14 00:40:57 -04:00
ignorable ( ) : Ability {
this . isIgnorable = true ;
return this ;
}
2023-04-27 14:30:03 -04:00
condition ( condition : AbAttrCondition ) : Ability {
this . conditions . push ( condition ) ;
return this ;
}
2024-04-25 03:10:09 +02:00
partial ( ) : this {
2024-05-23 17:03:10 +02:00
this . nameAppend += " (P)" ;
2024-04-25 03:10:09 +02:00
return this ;
}
unimplemented ( ) : this {
2024-05-23 17:03:10 +02:00
this . nameAppend += " (N)" ;
2024-04-25 03:10:09 +02:00
return this ;
}
2023-04-15 20:36:19 -04:00
}
2024-04-11 09:24:03 -04:00
type AbAttrApplyFunc < TAttr extends AbAttr > = ( attr : TAttr , passive : boolean ) = > boolean | Promise < boolean > ;
2023-04-27 14:30:03 -04:00
type AbAttrCondition = ( pokemon : Pokemon ) = > boolean ;
2023-12-23 01:21:01 -05:00
type PokemonAttackCondition = ( user : Pokemon , target : Pokemon , move : Move ) = > boolean ;
type PokemonDefendCondition = ( target : Pokemon , user : Pokemon , move : Move ) = > boolean ;
2024-04-14 14:20:00 -04:00
type PokemonStatChangeCondition = ( target : Pokemon , statsChanged : BattleStat [ ] , levels : integer ) = > boolean ;
2023-12-23 01:21:01 -05:00
2023-04-27 14:30:03 -04:00
export abstract class AbAttr {
2023-05-06 12:13:35 -04:00
public showAbility : boolean ;
2023-12-23 01:21:01 -05:00
private extraCondition : AbAttrCondition ;
2023-05-06 12:13:35 -04:00
2024-03-18 21:22:27 -04:00
constructor ( showAbility : boolean = true ) {
this . showAbility = showAbility ;
2023-05-06 12:13:35 -04:00
}
2024-05-24 01:45:04 +02:00
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean | Promise < boolean > {
2023-04-27 14:30:03 -04:00
return false ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2023-04-27 01:14:15 -04:00
return null ;
}
2023-04-27 14:30:03 -04:00
2024-05-22 08:52:45 -04:00
getCondition ( ) : AbAttrCondition | null {
2023-12-23 01:21:01 -05:00
return this . extraCondition || null ;
}
addCondition ( condition : AbAttrCondition ) : AbAttr {
this . extraCondition = condition ;
return this ;
2023-04-27 14:30:03 -04:00
}
}
export class BlockRecoilDamageAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-04-27 14:30:03 -04:00
cancelled . value = true ;
return true ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) {
2024-06-06 15:36:12 +02:00
return i18next . t ( "abilityTriggers:blockRecoilDamage" , { pokemonName : getPokemonNameWithAffix ( pokemon ) , abilityName : abilityName } ) ;
2023-04-27 14:30:03 -04:00
}
2023-04-27 01:14:15 -04:00
}
2023-04-26 23:33:13 -04:00
2023-05-18 11:11:06 -04:00
export class DoubleBattleChanceAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-05-18 11:11:06 -04:00
const doubleChance = ( args [ 0 ] as Utils . IntegerHolder ) ;
doubleChance . value = Math . max ( doubleChance . value / 2 , 1 ) ;
return true ;
}
}
2024-03-30 00:53:35 -04:00
export class PostBattleInitAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPostBattleInit ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2024-03-30 00:53:35 -04:00
return false ;
}
}
export class PostBattleInitFormChangeAbAttr extends PostBattleInitAbAttr {
private formFunc : ( p : Pokemon ) = > integer ;
constructor ( formFunc : ( ( p : Pokemon ) = > integer ) ) {
super ( true ) ;
this . formFunc = formFunc ;
}
2024-04-11 09:24:03 -04:00
applyPostBattleInit ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-03-30 00:53:35 -04:00
const formIndex = this . formFunc ( pokemon ) ;
2024-05-23 17:03:10 +02:00
if ( formIndex !== pokemon . formIndex ) {
2024-03-30 00:53:35 -04:00
return pokemon . scene . triggerPokemonFormChange ( pokemon , SpeciesFormChangeManualTrigger , false ) ;
2024-05-23 17:03:10 +02:00
}
2024-03-30 00:53:35 -04:00
return false ;
}
}
2024-04-02 18:03:49 -05:00
export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr {
private stats : BattleStat [ ] ;
private levels : integer ;
private selfTarget : boolean ;
constructor ( stats : BattleStat | BattleStat [ ] , levels : integer , selfTarget? : boolean ) {
super ( ) ;
2024-05-23 17:03:10 +02:00
this . stats = typeof ( stats ) === "number"
2024-04-02 18:03:49 -05:00
? [ stats as BattleStat ]
: stats as BattleStat [ ] ;
this . levels = levels ;
this . selfTarget = ! ! selfTarget ;
}
2024-04-11 09:24:03 -04:00
applyPostBattleInit ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-04-02 18:03:49 -05:00
const statChangePhases : StatChangePhase [ ] = [ ] ;
2024-05-23 17:03:10 +02:00
if ( this . selfTarget ) {
2024-04-02 18:03:49 -05:00
statChangePhases . push ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , this . stats , this . levels ) ) ;
2024-05-23 17:03:10 +02:00
} else {
for ( const opponent of pokemon . getOpponents ( ) ) {
2024-04-02 18:03:49 -05:00
statChangePhases . push ( new StatChangePhase ( pokemon . scene , opponent . getBattlerIndex ( ) , false , this . stats , this . levels ) ) ;
2024-05-23 17:03:10 +02:00
}
2024-04-02 18:03:49 -05:00
}
2024-05-23 17:03:10 +02:00
for ( const statChangePhase of statChangePhases ) {
if ( ! this . selfTarget && ! statChangePhase . getPokemon ( ) . summonData ) {
pokemon . scene . pushPhase ( statChangePhase ) ;
} else { // TODO: This causes the ability bar to be shown at the wrong time
2024-04-02 18:03:49 -05:00
pokemon . scene . unshiftPhase ( statChangePhase ) ;
2024-05-23 17:03:10 +02:00
}
2024-04-02 18:03:49 -05:00
}
2024-05-24 01:45:04 +02:00
2024-04-02 18:03:49 -05:00
return true ;
}
}
2024-06-07 16:57:57 -04:00
type PreDefendAbAttrCondition = ( pokemon : Pokemon , attacker : Pokemon , move : Move ) = > boolean ;
2023-12-22 01:16:56 -05:00
2023-04-27 14:30:03 -04:00
export class PreDefendAbAttr extends AbAttr {
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean | Promise < boolean > {
2023-04-26 23:33:13 -04:00
return false ;
}
}
2024-04-17 22:09:28 -06:00
export class PreDefendFormChangeAbAttr extends PreDefendAbAttr {
private formFunc : ( p : Pokemon ) = > integer ;
constructor ( formFunc : ( ( p : Pokemon ) = > integer ) ) {
super ( true ) ;
this . formFunc = formFunc ;
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-17 22:09:28 -06:00
const formIndex = this . formFunc ( pokemon ) ;
if ( formIndex !== pokemon . formIndex ) {
pokemon . scene . triggerPokemonFormChange ( pokemon , SpeciesFormChangeManualTrigger , false ) ;
return true ;
}
return false ;
}
}
2024-04-02 01:03:29 -04:00
export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr {
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-05-12 16:53:54 -03:00
if ( pokemon . hp === pokemon . getMaxHp ( ) &&
pokemon . getMaxHp ( ) > 1 && //Checks if pokemon has wonder_guard (which forces 1hp)
2024-05-24 02:19:20 +02:00
( args [ 0 ] as Utils . NumberHolder ) . value >= pokemon . hp ) { //Damage >= hp
2024-05-12 16:53:54 -03:00
return pokemon . addTag ( BattlerTagType . STURDY , 1 ) ;
}
2024-05-24 01:45:04 +02:00
2024-05-23 17:03:10 +02:00
return false ;
2024-03-09 23:49:00 +01:00
}
}
2023-05-04 14:06:31 -04:00
export class BlockItemTheftAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-10-26 20:02:30 -04:00
cancelled . value = true ;
2024-05-24 01:45:04 +02:00
2023-05-04 14:06:31 -04:00
return true ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) {
return getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nprevents item theft! ` ) ;
2023-05-04 14:06:31 -04:00
}
}
2023-10-26 20:02:30 -04:00
export class StabBoostAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-03-26 09:32:02 -04:00
if ( ( args [ 0 ] as Utils . NumberHolder ) . value > 1 ) {
2023-11-26 09:53:16 -05:00
( args [ 0 ] as Utils . NumberHolder ) . value += 0.5 ;
2024-03-26 09:32:02 -04:00
return true ;
}
2024-05-24 01:45:04 +02:00
2024-03-26 09:32:02 -04:00
return false ;
2023-10-26 20:02:30 -04:00
}
}
2023-12-23 01:21:01 -05:00
export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr {
2024-04-17 22:09:28 -06:00
protected condition : PokemonDefendCondition ;
2024-06-26 03:23:48 +10:00
private damageMultiplier : number ;
2023-05-02 15:56:41 -04:00
2024-06-26 03:23:48 +10:00
constructor ( condition : PokemonDefendCondition , damageMultiplier : number ) {
2023-05-02 15:56:41 -04:00
super ( ) ;
2023-12-23 01:21:01 -05:00
this . condition = condition ;
2024-06-26 03:23:48 +10:00
this . damageMultiplier = damageMultiplier ;
2023-05-02 15:56:41 -04:00
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , attacker , move ) ) {
2024-06-25 20:08:03 -04:00
( args [ 0 ] as Utils . NumberHolder ) . value = Math . floor ( ( args [ 0 ] as Utils . NumberHolder ) . value * this . damageMultiplier ) ;
2023-05-02 15:56:41 -04:00
return true ;
}
return false ;
}
}
2023-12-23 01:21:01 -05:00
export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
2024-06-26 03:23:48 +10:00
constructor ( moveType : Type , damageMultiplier : number ) {
super ( ( user , target , move ) = > move . type === moveType , damageMultiplier ) ;
2023-12-23 01:21:01 -05:00
}
}
2024-06-26 03:23:48 +10:00
export class PreDefendMoveDamageToOneAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
2024-04-17 22:09:28 -06:00
constructor ( condition : PokemonDefendCondition ) {
super ( condition , 1 ) ;
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , attacker , move ) ) {
2024-06-26 03:32:45 +08:00
( args [ 0 ] as Utils . NumberHolder ) . value = Math . floor ( pokemon . getMaxHp ( ) / 8 ) ;
2024-04-17 22:09:28 -06:00
return true ;
}
return false ;
}
}
2024-06-07 16:57:57 -04:00
/ * *
* Determines whether a Pokemon is immune to a move because of an ability .
* @extends PreDefendAbAttr
* @see { @linkcode applyPreDefend }
* @see { @linkcode getCondition }
* /
2023-04-27 14:30:03 -04:00
export class TypeImmunityAbAttr extends PreDefendAbAttr {
2023-04-26 23:33:13 -04:00
private immuneType : Type ;
2023-04-27 14:30:03 -04:00
private condition : AbAttrCondition ;
2023-04-26 23:33:13 -04:00
2023-04-27 14:30:03 -04:00
constructor ( immuneType : Type , condition? : AbAttrCondition ) {
2023-04-26 23:33:13 -04:00
super ( ) ;
this . immuneType = immuneType ;
2023-04-27 14:30:03 -04:00
this . condition = condition ;
2023-04-26 23:33:13 -04:00
}
2024-06-07 16:57:57 -04:00
/ * *
2024-06-12 14:46:45 -04:00
* Applies immunity if this ability grants immunity to the type of the given move .
2024-06-07 16:57:57 -04:00
* @param pokemon { @linkcode Pokemon } the defending Pokemon
* @param passive N / A
* @param attacker { @linkcode Pokemon } the attacking Pokemon
* @param move { @linkcode Move } the attacking move
* @param cancelled N / A
* @param args [ 0 ] { @linkcode Utils . NumberHolder } gets set to 0 if move is immuned by an ability .
* @param args [ 1 ] { @linkcode Utils . NumberHolder } type of move being defended against in case it has changed from default type
* /
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-06-12 14:46:45 -04:00
// Field moves should ignore immunity
if ( [ MoveTarget . BOTH_SIDES , MoveTarget . ENEMY_SIDE , MoveTarget . USER_SIDE ] . includes ( move . moveTarget ) ) {
return false ;
}
2024-06-13 09:49:40 -04:00
if ( attacker !== pokemon && move . type === this . immuneType ) {
2023-04-26 23:33:13 -04:00
( args [ 0 ] as Utils . NumberHolder ) . value = 0 ;
return true ;
}
return false ;
}
2023-04-27 14:30:03 -04:00
getCondition ( ) : AbAttrCondition {
return this . condition ;
}
2023-04-26 23:33:13 -04:00
}
2023-05-02 15:56:41 -04:00
export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr {
constructor ( immuneType : Type ) {
super ( immuneType ) ;
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-11 09:24:03 -04:00
const ret = super . applyPreDefend ( pokemon , passive , attacker , move , cancelled , args ) ;
2023-05-02 15:56:41 -04:00
2023-05-18 11:11:06 -04:00
if ( ret ) {
2024-02-28 11:34:55 -05:00
if ( pokemon . getHpRatio ( ) < 1 ) {
const simulated = args . length > 1 && args [ 1 ] ;
if ( ! simulated ) {
2024-04-11 09:24:03 -04:00
const abilityName = ( ! passive ? pokemon . getAbility ( ) : pokemon . getPassiveAbility ( ) ) . name ;
2024-02-28 11:34:55 -05:00
pokemon . scene . unshiftPhase ( new PokemonHealPhase ( pokemon . scene , pokemon . getBattlerIndex ( ) ,
2024-04-11 09:24:03 -04:00
Math . max ( Math . floor ( pokemon . getMaxHp ( ) / 4 ) , 1 ) , getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nrestored its HP a little! ` ) , true ) ) ;
2024-02-28 11:34:55 -05:00
}
}
2023-05-02 15:56:41 -04:00
return true ;
}
2024-05-24 01:45:04 +02:00
2023-05-02 15:56:41 -04:00
return false ;
}
}
2023-04-27 14:30:03 -04:00
class TypeImmunityStatChangeAbAttr extends TypeImmunityAbAttr {
2023-04-26 23:33:13 -04:00
private stat : BattleStat ;
private levels : integer ;
2023-04-27 14:30:03 -04:00
constructor ( immuneType : Type , stat : BattleStat , levels : integer , condition? : AbAttrCondition ) {
super ( immuneType , condition ) ;
2023-04-26 23:33:13 -04:00
this . stat = stat ;
this . levels = levels ;
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-11 09:24:03 -04:00
const ret = super . applyPreDefend ( pokemon , passive , attacker , move , cancelled , args ) ;
2023-04-26 23:33:13 -04:00
if ( ret ) {
cancelled . value = true ;
2024-02-28 11:34:55 -05:00
const simulated = args . length > 1 && args [ 1 ] ;
2024-05-23 17:03:10 +02:00
if ( ! simulated ) {
2024-02-28 11:34:55 -05:00
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , [ this . stat ] , this . levels ) ) ;
2024-05-23 17:03:10 +02:00
}
2023-04-26 23:33:13 -04:00
}
2024-05-24 01:45:04 +02:00
2023-04-26 23:33:13 -04:00
return ret ;
}
}
2023-04-27 14:30:03 -04:00
class TypeImmunityAddBattlerTagAbAttr extends TypeImmunityAbAttr {
private tagType : BattlerTagType ;
private turnCount : integer ;
constructor ( immuneType : Type , tagType : BattlerTagType , turnCount : integer , condition? : AbAttrCondition ) {
super ( immuneType , condition ) ;
this . tagType = tagType ;
this . turnCount = turnCount ;
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-11 09:24:03 -04:00
const ret = super . applyPreDefend ( pokemon , passive , attacker , move , cancelled , args ) ;
2023-04-27 14:30:03 -04:00
if ( ret ) {
cancelled . value = true ;
2024-02-28 11:34:55 -05:00
const simulated = args . length > 1 && args [ 1 ] ;
2024-05-23 17:03:10 +02:00
if ( ! simulated ) {
2024-02-28 11:34:55 -05:00
pokemon . addTag ( this . tagType , this . turnCount , undefined , pokemon . id ) ;
2024-05-23 17:03:10 +02:00
}
2023-04-27 14:30:03 -04:00
}
2024-05-24 01:45:04 +02:00
2023-04-27 14:30:03 -04:00
return ret ;
}
}
2023-04-27 14:56:30 -04:00
export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr {
constructor ( condition? : AbAttrCondition ) {
super ( null , condition ) ;
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
if ( move instanceof AttackMove && pokemon . getAttackTypeEffectiveness ( move . type , attacker ) < 2 ) {
2023-04-27 14:56:30 -04:00
cancelled . value = true ;
( args [ 0 ] as Utils . NumberHolder ) . value = 0 ;
return true ;
}
return false ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` avoided damage \ nwith ${ abilityName } ! ` ) ;
2023-04-27 14:56:30 -04:00
}
}
2023-05-04 12:57:55 -04:00
export class PostDefendAbAttr extends AbAttr {
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean | Promise < boolean > {
2023-05-04 12:57:55 -04:00
return false ;
}
}
2024-04-17 22:09:28 -06:00
export class PostDefendDisguiseAbAttr extends PostDefendAbAttr {
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( pokemon . formIndex === 0 && pokemon . battleData . hitCount !== 0 && ( move . category === MoveCategory . SPECIAL || move . category === MoveCategory . PHYSICAL ) ) {
2024-05-24 01:45:04 +02:00
2024-04-17 22:09:28 -06:00
const recoilDamage = Math . ceil ( ( pokemon . getMaxHp ( ) / 8 ) - attacker . turnData . damageDealt ) ;
2024-05-23 17:03:10 +02:00
if ( ! recoilDamage ) {
2024-04-17 22:09:28 -06:00
return false ;
2024-05-23 17:03:10 +02:00
}
2024-04-17 22:09:28 -06:00
pokemon . damageAndUpdate ( recoilDamage , HitResult . OTHER ) ;
2024-04-25 20:51:04 -04:00
pokemon . turnData . damageTaken += recoilDamage ;
2024-05-23 17:03:10 +02:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , "'s disguise was busted!" ) ) ;
2024-04-17 22:09:28 -06:00
return true ;
}
return false ;
}
}
export class PostDefendFormChangeAbAttr extends PostDefendAbAttr {
private formFunc : ( p : Pokemon ) = > integer ;
constructor ( formFunc : ( ( p : Pokemon ) = > integer ) ) {
super ( true ) ;
this . formFunc = formFunc ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-04-17 22:09:28 -06:00
const formIndex = this . formFunc ( pokemon ) ;
if ( formIndex !== pokemon . formIndex ) {
pokemon . scene . triggerPokemonFormChange ( pokemon , SpeciesFormChangeManualTrigger , false ) ;
return true ;
}
return false ;
}
}
2024-04-15 19:48:33 +03:00
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
const attackPriority = new Utils . IntegerHolder ( move . priority ) ;
applyMoveAttrs ( IncrementMovePriorityAttr , attacker , null , move , attackPriority ) ;
applyAbAttrs ( IncrementMovePriorityAbAttr , attacker , null , move , attackPriority ) ;
2024-05-24 01:45:04 +02:00
2024-06-07 16:57:57 -04:00
if ( move . moveTarget === MoveTarget . USER || move . moveTarget === MoveTarget . NEAR_ALLY ) {
2024-05-23 17:03:10 +02:00
return false ;
}
2024-05-20 07:52:51 +09:00
2024-06-07 16:57:57 -04:00
if ( attackPriority . value > 0 && ! move . isMultiTarget ( ) ) {
2024-05-23 17:03:10 +02:00
cancelled . value = true ;
return true ;
}
2024-05-24 01:45:04 +02:00
2024-04-15 19:48:33 +03:00
return false ;
}
}
2024-04-14 14:20:00 -04:00
export class PostStatChangeAbAttr extends AbAttr {
applyPostStatChange ( pokemon : Pokemon , statsChanged : BattleStat [ ] , levelChanged : integer , selfTarget : boolean , args : any [ ] ) : boolean | Promise < boolean > {
return false ;
}
}
2023-12-22 01:16:56 -05:00
export class MoveImmunityAbAttr extends PreDefendAbAttr {
private immuneCondition : PreDefendAbAttrCondition ;
constructor ( immuneCondition : PreDefendAbAttrCondition ) {
super ( true ) ;
this . immuneCondition = immuneCondition ;
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-12-22 01:16:56 -05:00
if ( this . immuneCondition ( pokemon , attacker , move ) ) {
cancelled . value = true ;
return true ;
}
return false ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2023-12-22 01:16:56 -05:00
return ` It doesn \ 't affect ${ pokemon . name } ! ` ;
}
}
2024-06-16 00:06:32 +08:00
/ * *
* Reduces the accuracy of status moves used against the Pokémon with this ability to 50 % .
* Used by Wonder Skin .
*
* @extends PreDefendAbAttr
* /
export class WonderSkinAbAttr extends PreDefendAbAttr {
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
const moveAccuracy = args [ 0 ] as Utils . NumberHolder ;
if ( move . category === MoveCategory . STATUS && moveAccuracy . value >= 50 ) {
moveAccuracy . value = 50 ;
return true ;
}
return false ;
}
}
2024-04-17 01:09:15 -04:00
export class MoveImmunityStatChangeAbAttr extends MoveImmunityAbAttr {
private stat : BattleStat ;
private levels : integer ;
constructor ( immuneCondition : PreDefendAbAttrCondition , stat : BattleStat , levels : integer ) {
super ( immuneCondition ) ;
this . stat = stat ;
this . levels = levels ;
}
2024-06-07 16:57:57 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
const ret = super . applyPreDefend ( pokemon , passive , attacker , move , cancelled , args ) ;
2024-04-17 01:09:15 -04:00
if ( ret ) {
2024-05-25 13:32:32 +03:00
const simulated = args . length > 1 && args [ 1 ] ;
if ( ! simulated ) {
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , [ this . stat ] , this . levels ) ) ;
}
2024-04-17 01:09:15 -04:00
}
return ret ;
}
}
2024-06-01 15:53:32 -04:00
/ * *
* Class for abilities that make drain moves deal damage to user instead of healing them .
* @extends PostDefendAbAttr
* @see { @linkcode applyPostDefend }
* /
2024-04-22 04:02:10 +01:00
export class ReverseDrainAbAttr extends PostDefendAbAttr {
2024-06-01 15:53:32 -04:00
/ * *
* Determines if a damage and draining move was used to check if this ability should stop the healing .
* Examples include : Absorb , Draining Kiss , Bitter Blade , etc .
* Also displays a message to show this ability was activated .
* @param pokemon { @linkcode Pokemon } with this ability
* @param passive N / A
* @param attacker { @linkcode Pokemon } that is attacking this Pokemon
* @param move { @linkcode PokemonMove } that is being used
* @param hitResult N / A
* @args N / A
* @returns true if healing should be reversed on a healing move , false otherwise .
* /
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( move . hasAttr ( HitHealAttr ) ) {
2024-05-23 17:03:10 +02:00
pokemon . scene . queueMessage ( getPokemonMessage ( attacker , " sucked up the liquid ooze!" ) ) ;
2024-04-22 04:02:10 +01:00
return true ;
}
return false ;
}
}
2024-04-05 00:24:43 +02:00
export class PostDefendStatChangeAbAttr extends PostDefendAbAttr {
private condition : PokemonDefendCondition ;
private stat : BattleStat ;
private levels : integer ;
2024-04-06 22:18:12 -05:00
private selfTarget : boolean ;
2024-05-08 18:25:15 -04:00
private allOthers : boolean ;
2024-04-05 00:24:43 +02:00
2024-05-08 18:25:15 -04:00
constructor ( condition : PokemonDefendCondition , stat : BattleStat , levels : integer , selfTarget : boolean = true , allOthers : boolean = false ) {
2024-04-05 00:24:43 +02:00
super ( true ) ;
this . condition = condition ;
this . stat = stat ;
this . levels = levels ;
2024-04-06 22:18:12 -05:00
this . selfTarget = selfTarget ;
2024-05-08 18:25:15 -04:00
this . allOthers = allOthers ;
2024-04-05 00:24:43 +02:00
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , attacker , move ) ) {
2024-05-08 18:25:15 -04:00
if ( this . allOthers ) {
2024-05-23 17:03:10 +02:00
const otherPokemon = pokemon . getAlly ( ) ? pokemon . getOpponents ( ) . concat ( [ pokemon . getAlly ( ) ] ) : pokemon . getOpponents ( ) ;
for ( const other of otherPokemon ) {
2024-05-08 18:25:15 -04:00
other . scene . unshiftPhase ( new StatChangePhase ( other . scene , ( other ) . getBattlerIndex ( ) , false , [ this . stat ] , this . levels ) ) ;
}
return true ;
}
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , ( this . selfTarget ? pokemon : attacker ) . getBattlerIndex ( ) , this . selfTarget , [ this . stat ] , this . levels ) ) ;
2024-04-05 00:24:43 +02:00
return true ;
}
return false ;
}
}
2024-05-03 13:55:46 -07:00
export class PostDefendHpGatedStatChangeAbAttr extends PostDefendAbAttr {
private condition : PokemonDefendCondition ;
private hpGate : number ;
private stats : BattleStat [ ] ;
private levels : integer ;
private selfTarget : boolean ;
constructor ( condition : PokemonDefendCondition , hpGate : number , stats : BattleStat [ ] , levels : integer , selfTarget : boolean = true ) {
super ( true ) ;
this . condition = condition ;
this . hpGate = hpGate ;
this . stats = stats ;
this . levels = levels ;
this . selfTarget = selfTarget ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
const hpGateFlat : integer = Math . ceil ( pokemon . getMaxHp ( ) * this . hpGate ) ;
const lastAttackReceived = pokemon . turnData . attacksReceived [ pokemon . turnData . attacksReceived . length - 1 ] ;
2024-06-13 23:37:15 +08:00
const damageReceived = lastAttackReceived ? . damage || 0 ;
if ( this . condition ( pokemon , attacker , move ) && ( pokemon . hp <= hpGateFlat && ( pokemon . hp + damageReceived ) > hpGateFlat ) ) {
2024-05-03 13:55:46 -07:00
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , ( this . selfTarget ? pokemon : attacker ) . getBattlerIndex ( ) , true , this . stats , this . levels ) ) ;
return true ;
}
return false ;
}
}
2024-04-19 20:08:09 +01:00
export class PostDefendApplyArenaTrapTagAbAttr extends PostDefendAbAttr {
private condition : PokemonDefendCondition ;
2024-04-21 23:05:36 -04:00
private tagType : ArenaTagType ;
2024-04-19 20:08:09 +01:00
constructor ( condition : PokemonDefendCondition , tagType : ArenaTagType ) {
super ( true ) ;
this . condition = condition ;
this . tagType = tagType ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , attacker , move ) ) {
2024-04-19 20:08:09 +01:00
const tag = pokemon . scene . arena . getTag ( this . tagType ) as ArenaTrapTag ;
if ( ! pokemon . scene . arena . getTag ( this . tagType ) || tag . layers < tag . maxLayers ) {
pokemon . scene . arena . addTag ( this . tagType , 0 , undefined , pokemon . id , pokemon . isPlayer ( ) ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER ) ;
return true ;
}
}
return false ;
}
}
2024-04-17 01:09:15 -04:00
export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr {
private condition : PokemonDefendCondition ;
private tagType : BattlerTagType ;
constructor ( condition : PokemonDefendCondition , tagType : BattlerTagType ) {
super ( true ) ;
this . condition = condition ;
this . tagType = tagType ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , attacker , move ) ) {
2024-05-31 05:42:46 +08:00
if ( ! pokemon . getTag ( this . tagType ) ) {
pokemon . addTag ( this . tagType , undefined , undefined , pokemon . id ) ;
2024-06-07 16:57:57 -04:00
pokemon . scene . queueMessage ( i18next . t ( "abilityTriggers:windPowerCharged" , { pokemonName : pokemon.name , moveName : move.name } ) ) ;
2024-05-31 05:42:46 +08:00
}
2024-04-17 01:09:15 -04:00
return true ;
}
return false ;
}
}
2023-05-06 00:42:01 -04:00
export class PostDefendTypeChangeAbAttr extends PostDefendAbAttr {
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2023-05-18 11:11:06 -04:00
if ( hitResult < HitResult . NO_EFFECT ) {
2024-06-07 16:57:57 -04:00
const type = move . type ;
2024-02-17 00:40:03 -05:00
const pokemonTypes = pokemon . getTypes ( true ) ;
2023-05-08 18:48:35 -04:00
if ( pokemonTypes . length !== 1 || pokemonTypes [ 0 ] !== type ) {
pokemon . summonData . types = [ type ] ;
2023-05-06 00:42:01 -04:00
return true ;
}
}
return false ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nmade it the ${ Utils . toReadableString ( Type [ pokemon . getTypes ( true ) [ 0 ] ] ) } type! ` ) ;
2023-05-06 00:42:01 -04:00
}
}
2024-03-14 00:40:57 -04:00
export class PostDefendTerrainChangeAbAttr extends PostDefendAbAttr {
private terrainType : TerrainType ;
constructor ( terrainType : TerrainType ) {
super ( ) ;
this . terrainType = terrainType ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
if ( hitResult < HitResult . NO_EFFECT ) {
2024-03-25 10:22:16 -04:00
return pokemon . scene . arena . trySetTerrain ( this . terrainType , true ) ;
2024-05-23 17:03:10 +02:00
}
2024-03-14 00:40:57 -04:00
return false ;
}
}
2023-05-04 12:57:55 -04:00
export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
private chance : integer ;
private effects : StatusEffect [ ] ;
constructor ( chance : integer , . . . effects : StatusEffect [ ] ) {
super ( ) ;
this . chance = chance ;
this . effects = effects ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) && ! attacker . status && ( this . chance === - 1 || pokemon . randSeedInt ( 100 ) < this . chance ) ) {
2024-01-02 21:31:59 -05:00
const effect = this . effects . length === 1 ? this . effects [ 0 ] : this . effects [ pokemon . randSeedInt ( this . effects . length ) ] ;
2024-05-14 14:00:37 -04:00
return attacker . trySetStatus ( effect , true , pokemon ) ;
2023-05-04 12:57:55 -04:00
}
return false ;
}
}
2024-05-01 17:47:32 -04:00
export class EffectSporeAbAttr extends PostDefendContactApplyStatusEffectAbAttr {
constructor ( ) {
super ( 10 , StatusEffect . POISON , StatusEffect . PARALYSIS , StatusEffect . SLEEP ) ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-05-01 17:47:32 -04:00
if ( attacker . hasAbility ( Abilities . OVERCOAT ) || attacker . isOfType ( Type . GRASS ) ) {
return false ;
}
return super . applyPostDefend ( pokemon , passive , attacker , move , hitResult , args ) ;
}
}
2023-05-04 12:57:55 -04:00
export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
private chance : integer ;
private tagType : BattlerTagType ;
private turnCount : integer ;
constructor ( chance : integer , tagType : BattlerTagType , turnCount? : integer ) {
super ( ) ;
this . tagType = tagType ;
this . chance = chance ;
this . turnCount = turnCount ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) && pokemon . randSeedInt ( 100 ) < this . chance ) {
return attacker . addTag ( this . tagType , this . turnCount , move . id , attacker . id ) ;
2024-05-23 17:03:10 +02:00
}
2023-05-04 12:57:55 -04:00
return false ;
}
}
2023-10-26 21:12:53 -07:00
export class PostDefendCritStatChangeAbAttr extends PostDefendAbAttr {
private stat : BattleStat ;
private levels : integer ;
constructor ( stat : BattleStat , levels : integer ) {
2024-04-06 21:04:40 -04:00
super ( ) ;
2023-10-26 21:12:53 -07:00
this . stat = stat ;
this . levels = levels ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2023-10-26 21:12:53 -07:00
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , [ this . stat ] , this . levels ) ) ;
2024-05-24 01:45:04 +02:00
2023-10-26 21:12:53 -07:00
return true ;
}
getCondition ( ) : AbAttrCondition {
return ( pokemon : Pokemon ) = > pokemon . turnData . attacksReceived . length && pokemon . turnData . attacksReceived [ pokemon . turnData . attacksReceived . length - 1 ] . critical ;
}
}
2024-04-06 21:04:40 -04:00
export class PostDefendContactDamageAbAttr extends PostDefendAbAttr {
private damageRatio : integer ;
constructor ( damageRatio : integer ) {
super ( ) ;
this . damageRatio = damageRatio ;
}
2024-05-24 01:45:04 +02:00
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-07-04 15:18:09 -07:00
if ( move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) && ! attacker . hasAbilityWithAttr ( BlockNonDirectDamageAbAttr ) ) {
2024-04-06 21:04:40 -04:00
attacker . damageAndUpdate ( Math . ceil ( attacker . getMaxHp ( ) * ( 1 / this . damageRatio ) ) , HitResult . OTHER ) ;
2024-04-25 20:51:04 -04:00
attacker . turnData . damageTaken += Math . ceil ( attacker . getMaxHp ( ) * ( 1 / this . damageRatio ) ) ;
2024-04-06 21:04:40 -04:00
return true ;
}
2024-05-24 01:45:04 +02:00
2024-04-06 21:04:40 -04:00
return false ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nhurt its attacker! ` ) ;
2024-04-06 21:04:40 -04:00
}
}
2024-05-30 08:36:12 -07:00
/ * *
* @description : This ability applies the Perish Song tag to the attacking pokemon
* and the defending pokemon if the move makes physical contact and neither pokemon
* already has the Perish Song tag .
* @class PostDefendPerishSongAbAttr
* @extends { PostDefendAbAttr }
* /
export class PostDefendPerishSongAbAttr extends PostDefendAbAttr {
private turns : integer ;
constructor ( turns : integer ) {
super ( ) ;
this . turns = turns ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) ) {
2024-05-30 08:36:12 -07:00
if ( pokemon . getTag ( BattlerTagType . PERISH_SONG ) || attacker . getTag ( BattlerTagType . PERISH_SONG ) ) {
return false ;
} else {
attacker . addTag ( BattlerTagType . PERISH_SONG , this . turns ) ;
pokemon . addTag ( BattlerTagType . PERISH_SONG , this . turns ) ;
return true ;
}
}
return false ;
}
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2024-06-06 15:36:12 +02:00
return i18next . t ( "abilityTriggers:perishBody" , { pokemonName : getPokemonNameWithAffix ( pokemon ) , abilityName : abilityName } ) ;
2024-05-30 08:36:12 -07:00
}
}
2024-04-06 21:04:40 -04:00
2024-04-07 14:01:48 -05:00
export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr {
private weatherType : WeatherType ;
constructor ( weatherType : WeatherType ) {
super ( ) ;
this . weatherType = weatherType ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
if ( ! pokemon . scene . arena . weather ? . isImmutable ( ) ) {
2024-04-07 14:01:48 -05:00
return pokemon . scene . arena . trySetWeather ( this . weatherType , true ) ;
2024-05-23 17:03:10 +02:00
}
2024-04-07 14:01:48 -05:00
return false ;
}
}
2024-04-14 13:21:34 +10:00
export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr {
constructor ( ) {
super ( ) ;
}
2024-05-24 01:45:04 +02:00
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) && ! attacker . getAbility ( ) . hasAttr ( UnswappableAbilityAbAttr ) ) {
2024-04-14 13:21:34 +10:00
const tempAbilityId = attacker . getAbility ( ) . id ;
attacker . summonData . ability = pokemon . getAbility ( ) . id ;
pokemon . summonData . ability = tempAbilityId ;
return true ;
}
2024-05-24 01:45:04 +02:00
2024-04-14 13:21:34 +10:00
return false ;
}
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2024-05-23 17:03:10 +02:00
return getPokemonMessage ( pokemon , " swapped\nabilities with its target!" ) ;
2024-04-14 13:21:34 +10:00
}
}
export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
2024-05-03 22:30:23 -04:00
private ability : Abilities ;
constructor ( ability : Abilities ) {
2024-04-14 13:21:34 +10:00
super ( ) ;
2024-05-03 22:30:23 -04:00
this . ability = ability ;
2024-04-14 13:21:34 +10:00
}
2024-05-24 01:45:04 +02:00
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) && ! attacker . getAbility ( ) . hasAttr ( UnsuppressableAbilityAbAttr ) && ! attacker . getAbility ( ) . hasAttr ( PostDefendAbilityGiveAbAttr ) ) {
2024-05-03 22:30:23 -04:00
attacker . summonData . ability = this . ability ;
2024-04-14 13:21:34 +10:00
return true ;
}
2024-05-24 01:45:04 +02:00
2024-04-14 13:21:34 +10:00
return false ;
}
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` gave its target \ n ${ abilityName } ! ` ) ;
}
}
2024-05-08 20:25:16 -04:00
export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr {
private chance : integer ;
private attacker : Pokemon ;
2024-06-07 16:57:57 -04:00
private move : Move ;
2024-05-08 20:25:16 -04:00
constructor ( chance : integer ) {
super ( ) ;
this . chance = chance ;
}
2024-05-24 01:45:04 +02:00
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-05-08 20:25:16 -04:00
if ( ! attacker . summonData . disabledMove ) {
2024-06-07 16:57:57 -04:00
if ( move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) && ( this . chance === - 1 || pokemon . randSeedInt ( 100 ) < this . chance ) && ! attacker . isMax ( ) ) {
2024-05-08 20:25:16 -04:00
this . attacker = attacker ;
this . move = move ;
2024-06-07 16:57:57 -04:00
attacker . summonData . disabledMove = move . id ;
2024-05-08 20:25:16 -04:00
attacker . summonData . disabledTurns = 4 ;
return true ;
}
}
return false ;
}
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2024-06-07 16:57:57 -04:00
return getPokemonMessage ( this . attacker , ` 's ${ this . move . name } \ nwas disabled! ` ) ;
2024-05-08 20:25:16 -04:00
}
}
2024-04-14 14:20:00 -04:00
export class PostStatChangeStatChangeAbAttr extends PostStatChangeAbAttr {
private condition : PokemonStatChangeCondition ;
private statsToChange : BattleStat [ ] ;
private levels : integer ;
constructor ( condition : PokemonStatChangeCondition , statsToChange : BattleStat [ ] , levels : integer ) {
super ( true ) ;
this . condition = condition ;
this . statsToChange = statsToChange ;
this . levels = levels ;
}
applyPostStatChange ( pokemon : Pokemon , statsChanged : BattleStat [ ] , levelsChanged : integer , selfTarget : boolean , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , statsChanged , levelsChanged ) && ! selfTarget ) {
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , ( pokemon ) . getBattlerIndex ( ) , true , this . statsToChange , this . levels ) ) ;
return true ;
}
return false ;
}
}
2023-04-27 14:30:03 -04:00
export class PreAttackAbAttr extends AbAttr {
2024-06-07 16:57:57 -04:00
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , args : any [ ] ) : boolean | Promise < boolean > {
2023-04-27 14:30:03 -04:00
return false ;
}
}
2024-06-17 18:30:42 -06:00
/ * *
* Modifies moves additional effects with multipliers , ie . Sheer Force , Serene Grace .
* @extends AbAttr
* @see { @linkcode apply }
* /
export class MoveEffectChanceMultiplierAbAttr extends AbAttr {
private chanceMultiplier : number ;
constructor ( chanceMultiplier? : number ) {
super ( true ) ;
this . chanceMultiplier = chanceMultiplier ;
}
/ * *
* @param args [ 0 ] : { @linkcode Utils . NumberHolder } Move additional effect chance . Has to be higher than or equal to 0 .
* [ 1 ] : { @linkcode Moves } Move used by the ability user .
* /
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
if ( ( args [ 0 ] as Utils . NumberHolder ) . value <= 0 || ( args [ 1 ] as Move ) . id === Moves . ORDER_UP ) {
return false ;
}
( args [ 0 ] as Utils . NumberHolder ) . value *= this . chanceMultiplier ;
( args [ 0 ] as Utils . NumberHolder ) . value = Math . min ( ( args [ 0 ] as Utils . NumberHolder ) . value , 100 ) ;
return true ;
}
}
/ * *
* Sets incoming moves additional effect chance to zero , ignoring all effects from moves . ie . Shield Dust .
* @extends PreDefendAbAttr
* @see { @linkcode applyPreDefend }
* /
export class IgnoreMoveEffectsAbAttr extends PreDefendAbAttr {
/ * *
* @param args [ 0 ] : { @linkcode Utils . NumberHolder } Move additional effect chance .
* /
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
if ( ( args [ 0 ] as Utils . NumberHolder ) . value <= 0 ) {
return false ;
}
( args [ 0 ] as Utils . NumberHolder ) . value = 0 ;
return true ;
}
}
2023-04-27 14:30:03 -04:00
export class VariableMovePowerAbAttr extends PreAttackAbAttr {
2024-06-07 16:57:57 -04:00
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , args : any [ ] ) : boolean {
2023-04-27 14:30:03 -04:00
//const power = args[0] as Utils.NumberHolder;
2024-04-07 22:27:07 -07:00
return false ;
}
}
2024-04-25 21:42:41 -04:00
export class FieldPreventExplosiveMovesAbAttr extends AbAttr {
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean | Promise < boolean > {
cancelled . value = true ;
return true ;
}
}
2024-06-11 06:37:10 -07:00
/ * *
* Multiplies a BattleStat if the checked Pokemon lacks this ability .
* If this ability cannot stack , a BooleanHolder can be used to prevent this from stacking .
* @see { @link applyFieldBattleStatMultiplierAbAttrs }
* @see { @link applyFieldBattleStat }
* @see { @link Utils . BooleanHolder }
* /
export class FieldMultiplyBattleStatAbAttr extends AbAttr {
private stat : Stat ;
private multiplier : number ;
private canStack : boolean ;
constructor ( stat : Stat , multiplier : number , canStack : boolean = false ) {
super ( false ) ;
this . stat = stat ;
this . multiplier = multiplier ;
this . canStack = canStack ;
}
/ * *
* applyFieldBattleStat : Tries to multiply a Pokemon ' s BattleStat
* @param pokemon { @linkcode Pokemon } the Pokemon using this ability
* @param passive { @linkcode boolean } unused
* @param stat { @linkcode Stat } the type of the checked stat
* @param statValue { @linkcode Utils . NumberHolder } the value of the checked stat
* @param checkedPokemon { @linkcode Pokemon } the Pokemon this ability is targeting
* @param hasApplied { @linkcode Utils . BooleanHolder } whether or not another multiplier has been applied to this stat
* @param args { any [ ] } unused
* @returns true if this changed the checked stat , false otherwise .
* /
applyFieldBattleStat ( pokemon : Pokemon , passive : boolean , stat : Stat , statValue : Utils.NumberHolder , checkedPokemon : Pokemon , hasApplied : Utils.BooleanHolder , args : any [ ] ) : boolean {
if ( ! this . canStack && hasApplied . value ) {
return false ;
}
if ( this . stat === stat && checkedPokemon . getAbilityAttrs ( FieldMultiplyBattleStatAbAttr ) . every ( attr = > ( attr as FieldMultiplyBattleStatAbAttr ) . stat !== stat ) ) {
statValue . value *= this . multiplier ;
hasApplied . value = true ;
return true ;
}
return false ;
}
}
2024-04-14 13:15:01 -04:00
export class MoveTypeChangeAttr extends PreAttackAbAttr {
2024-06-13 10:54:23 -04:00
constructor (
private newType : Type ,
private powerMultiplier : number ,
private condition? : PokemonAttackCondition
) {
2024-04-14 13:15:01 -04:00
super ( true ) ;
}
2024-06-07 16:57:57 -04:00
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , args : any [ ] ) : boolean {
2024-06-13 10:54:23 -04:00
if ( this . condition && this . condition ( pokemon , defender , move ) ) {
2024-06-07 16:57:57 -04:00
move . type = this . newType ;
2024-06-13 10:54:23 -04:00
if ( args [ 0 ] && args [ 0 ] instanceof Utils . NumberHolder ) {
args [ 0 ] . value *= this . powerMultiplier ;
}
2024-04-14 13:15:01 -04:00
return true ;
}
return false ;
}
}
2024-06-13 10:54:23 -04:00
/** Ability attribute for changing a pokemon's type before using a move */
export class PokemonTypeChangeAbAttr extends PreAttackAbAttr {
private moveType : Type ;
constructor ( ) {
super ( true ) ;
}
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , args : any [ ] ) : boolean {
if (
! pokemon . isTerastallized ( ) &&
move . id !== Moves . STRUGGLE &&
/ * *
* Skip moves that call other moves because these moves generate a following move that will trigger this ability attribute
* @see { @link https : //bulbapedia.bulbagarden.net/wiki/Category:Moves_that_call_other_moves}
* /
! move . findAttr ( ( attr ) = >
attr instanceof RandomMovesetMoveAttr ||
attr instanceof RandomMoveAttr ||
attr instanceof NaturePowerAttr ||
attr instanceof CopyMoveAttr
)
) {
// TODO remove this copy when phase order is changed so that damage, type, category, etc.
// TODO are all calculated prior to playing the move animation.
const moveCopy = new Move ( move . id , move . type , move . category , move . moveTarget , move . power , move . accuracy , move . pp , move . chance , move . priority , move . generation ) ;
moveCopy . attrs = move . attrs ;
// Moves like Weather Ball ignore effects of abilities like Normalize and Refrigerate
if ( move . findAttr ( attr = > attr instanceof VariableMoveTypeAttr ) ) {
applyMoveAttrs ( VariableMoveTypeAttr , pokemon , null , moveCopy ) ;
} else {
applyPreAttackAbAttrs ( MoveTypeChangeAttr , pokemon , null , moveCopy ) ;
}
if ( pokemon . getTypes ( ) . some ( ( t ) = > t !== moveCopy . type ) ) {
this . moveType = moveCopy . type ;
pokemon . summonData . types = [ moveCopy . type ] ;
pokemon . updateInfo ( ) ;
return true ;
}
}
return false ;
}
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` transformed into the ${ Type [ this . moveType ] } type! ` ) ;
}
}
2024-06-26 13:03:14 -07:00
/ * *
* Class for abilities that convert single - strike moves to two - strike moves ( i . e . Parental Bond ) .
* @param damageMultiplier the damage multiplier for the second strike , relative to the first .
* /
export class AddSecondStrikeAbAttr extends PreAttackAbAttr {
private damageMultiplier : number ;
constructor ( damageMultiplier : number ) {
super ( false ) ;
this . damageMultiplier = damageMultiplier ;
}
/ * *
* Determines whether this attribute can apply to a given move .
* @param { Move } move the move to which this attribute may apply
* @param numTargets the number of { @linkcode Pokemon } targeted by this move
* @returns true if the attribute can apply to the move , false otherwise
* /
canApplyPreAttack ( move : Move , numTargets : integer ) : boolean {
/ * *
* Parental Bond cannot apply to multi - hit moves , charging moves , or
* moves that cause the user to faint .
* /
const exceptAttrs : Constructor < MoveAttr > [ ] = [
MultiHitAttr ,
ChargeAttr ,
SacrificialAttr ,
SacrificialAttrOnHit
] ;
/** Parental Bond cannot apply to these specific moves */
const exceptMoves : Moves [ ] = [
Moves . FLING ,
Moves . UPROAR ,
Moves . ROLLOUT ,
Moves . ICE_BALL ,
Moves . ENDEAVOR
] ;
/** Also check if this move is an Attack move and if it's only targeting one Pokemon */
return numTargets === 1
&& ! exceptAttrs . some ( attr = > move . hasAttr ( attr ) )
&& ! exceptMoves . some ( id = > move . id === id )
&& move . category !== MoveCategory . STATUS ;
}
/ * *
* If conditions are met , this doubles the move ' s hit count ( via args [ 1 ] )
* or multiplies the damage of secondary strikes ( via args [ 2 ] )
* @param { Pokemon } pokemon the Pokemon using the move
* @param passive n / a
* @param defender n / a
* @param { Move } move the move used by the ability source
* @param args \ [ 0 \ ] the number of Pokemon this move is targeting
* @param { Utils . IntegerHolder } args \ [ 1 \ ] the number of strikes with this move
* @param { Utils . NumberHolder } args \ [ 2 \ ] the damage multiplier for the current strike
* @returns
* /
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , args : any [ ] ) : boolean {
const numTargets = args [ 0 ] as integer ;
const hitCount = args [ 1 ] as Utils . IntegerHolder ;
const multiplier = args [ 2 ] as Utils . NumberHolder ;
if ( this . canApplyPreAttack ( move , numTargets ) ) {
2024-07-05 15:52:58 -07:00
this . showAbility = ! ! hitCount ? . value ;
2024-06-26 13:03:14 -07:00
if ( ! ! hitCount ? . value ) {
hitCount . value *= 2 ;
}
2024-06-26 22:59:57 -07:00
if ( ! ! multiplier ? . value && pokemon . turnData . hitsLeft % 2 === 1 && pokemon . turnData . hitsLeft !== pokemon . turnData . hitCount ) {
2024-06-26 13:03:14 -07:00
multiplier . value *= this . damageMultiplier ;
}
return true ;
}
return false ;
}
}
2024-05-13 11:05:09 -07:00
/ * *
* Class for abilities that boost the damage of moves
* For abilities that boost the base power of moves , see VariableMovePowerAbAttr
2024-05-24 01:45:04 +02:00
* @param damageMultiplier the amount to multiply the damage by
* @param condition the condition for this ability to be applied
2024-05-13 11:05:09 -07:00
* /
export class DamageBoostAbAttr extends PreAttackAbAttr {
private damageMultiplier : number ;
private condition : PokemonAttackCondition ;
2024-05-24 02:19:20 +02:00
constructor ( damageMultiplier : number , condition : PokemonAttackCondition ) {
2024-05-13 11:05:09 -07:00
super ( true ) ;
this . damageMultiplier = damageMultiplier ;
this . condition = condition ;
}
/ * *
2024-05-24 01:45:04 +02:00
*
2024-05-13 11:05:09 -07:00
* @param pokemon the attacker pokemon
* @param passive N / A
* @param defender the target pokemon
* @param move the move used by the attacker pokemon
* @param args Utils . NumberHolder as damage
* @returns true if the function succeeds
* /
2024-06-07 16:57:57 -04:00
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , defender , move ) ) {
2024-05-13 11:05:09 -07:00
const power = args [ 0 ] as Utils . NumberHolder ;
power . value = Math . floor ( power . value * this . damageMultiplier ) ;
2024-05-23 17:03:10 +02:00
return true ;
}
2024-05-13 11:05:09 -07:00
2024-05-23 17:03:10 +02:00
return false ;
2024-05-13 11:05:09 -07:00
}
}
2023-12-23 01:21:01 -05:00
export class MovePowerBoostAbAttr extends VariableMovePowerAbAttr {
private condition : PokemonAttackCondition ;
private powerMultiplier : number ;
2023-12-14 11:48:59 -06:00
2024-05-01 18:17:12 -04:00
constructor ( condition : PokemonAttackCondition , powerMultiplier : number , showAbility : boolean = true ) {
super ( showAbility ) ;
2023-12-23 01:21:01 -05:00
this . condition = condition ;
this . powerMultiplier = powerMultiplier ;
2023-12-14 11:48:59 -06:00
}
2024-06-07 16:57:57 -04:00
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , defender , move ) ) {
2023-12-23 01:21:01 -05:00
( args [ 0 ] as Utils . NumberHolder ) . value *= this . powerMultiplier ;
2023-12-14 11:48:59 -06:00
return true ;
}
return false ;
}
}
2023-12-23 01:21:01 -05:00
export class MoveTypePowerBoostAbAttr extends MovePowerBoostAbAttr {
constructor ( boostedType : Type , powerMultiplier? : number ) {
super ( ( pokemon , defender , move ) = > move . type === boostedType , powerMultiplier || 1.5 ) ;
2023-04-27 14:30:03 -04:00
}
2023-12-23 01:21:01 -05:00
}
2023-04-27 14:30:03 -04:00
2023-12-23 01:21:01 -05:00
export class LowHpMoveTypePowerBoostAbAttr extends MoveTypePowerBoostAbAttr {
constructor ( boostedType : Type ) {
super ( boostedType ) ;
2023-04-27 14:30:03 -04:00
}
getCondition ( ) : AbAttrCondition {
return ( pokemon ) = > pokemon . getHpRatio ( ) <= 0.33 ;
}
}
2024-05-30 01:07:59 +10:00
/ * *
* Abilities which cause a variable amount of power increase .
* @extends VariableMovePowerAbAttr
* @see { @link applyPreAttack }
* /
export class VariableMovePowerBoostAbAttr extends VariableMovePowerAbAttr {
private mult : ( user : Pokemon , target : Pokemon , move : Move ) = > number ;
/ * *
* @param mult A function which takes the user , target , and move , and returns the power multiplier . 1 means no multiplier .
* @param { boolean } showAbility Whether to show the ability when it activates .
* /
constructor ( mult : ( user : Pokemon , target : Pokemon , move : Move ) = > number , showAbility : boolean = true ) {
super ( showAbility ) ;
this . mult = mult ;
}
/ * *
* @override
* /
2024-06-07 16:57:57 -04:00
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move , args : any [ ] ) : boolean {
const multiplier = this . mult ( pokemon , defender , move ) ;
2024-05-30 01:07:59 +10:00
if ( multiplier !== 1 ) {
( args [ 0 ] as Utils . NumberHolder ) . value *= multiplier ;
return true ;
}
return false ;
}
}
2024-06-18 04:12:11 +08:00
/ * *
* Boosts the power of a Pokémon ' s move under certain conditions .
* @extends AbAttr
* /
export class FieldMovePowerBoostAbAttr extends AbAttr {
2024-03-14 00:40:57 -04:00
private condition : PokemonAttackCondition ;
private powerMultiplier : number ;
2024-06-18 04:12:11 +08:00
/ * *
* @param condition - A function that determines whether the power boost condition is met .
* @param powerMultiplier - The multiplier to apply to the move ' s power when the condition is met .
* /
2024-03-14 00:40:57 -04:00
constructor ( condition : PokemonAttackCondition , powerMultiplier : number ) {
super ( false ) ;
this . condition = condition ;
this . powerMultiplier = powerMultiplier ;
}
2024-06-07 16:57:57 -04:00
applyPreAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , args : any [ ] ) : boolean {
if ( this . condition ( pokemon , defender , move ) ) {
2024-03-14 00:40:57 -04:00
( args [ 0 ] as Utils . NumberHolder ) . value *= this . powerMultiplier ;
return true ;
}
return false ;
}
}
2024-06-18 04:12:11 +08:00
/ * *
* Boosts the power of a specific type of move .
* @extends FieldMovePowerBoostAbAttr
* /
2024-07-04 00:55:39 +08:00
export class PreAttackFieldMoveTypePowerBoostAbAttr extends FieldMovePowerBoostAbAttr {
2024-06-18 04:12:11 +08:00
/ * *
* @param boostedType - The type of move that will receive the power boost .
* @param powerMultiplier - The multiplier to apply to the move ' s power , defaults to 1.5 if not provided .
* /
2024-03-14 00:40:57 -04:00
constructor ( boostedType : Type , powerMultiplier? : number ) {
super ( ( pokemon , defender , move ) = > move . type === boostedType , powerMultiplier || 1.5 ) ;
}
}
2024-07-04 00:55:39 +08:00
/ * *
* Boosts the power of a specific type of move for all Pokemon in the field .
* @extends PreAttackFieldMoveTypePowerBoostAbAttr
* /
export class FieldMoveTypePowerBoostAbAttr extends PreAttackFieldMoveTypePowerBoostAbAttr { }
/ * *
* Boosts the power of a specific type of move for the user and its allies .
* @extends PreAttackFieldMoveTypePowerBoostAbAttr
* /
export class UserFieldMoveTypePowerBoostAbAttr extends PreAttackFieldMoveTypePowerBoostAbAttr { }
2024-06-18 04:12:11 +08:00
/ * *
* Boosts the power of moves in specified categories .
* @extends FieldMovePowerBoostAbAttr
* /
export class AllyMoveCategoryPowerBoostAbAttr extends FieldMovePowerBoostAbAttr {
/ * *
* @param boostedCategories - The categories of moves that will receive the power boost .
* @param powerMultiplier - The multiplier to apply to the move ' s power .
* /
constructor ( boostedCategories : MoveCategory [ ] , powerMultiplier : number ) {
super ( ( pokemon , defender , move ) = > boostedCategories . includes ( move . category ) , powerMultiplier ) ;
}
}
2023-05-02 00:11:31 -04:00
export class BattleStatMultiplierAbAttr extends AbAttr {
private battleStat : BattleStat ;
private multiplier : number ;
2024-04-30 09:47:10 -06:00
private condition : PokemonAttackCondition ;
2023-05-02 00:11:31 -04:00
2024-04-30 09:47:10 -06:00
constructor ( battleStat : BattleStat , multiplier : number , condition? : PokemonAttackCondition ) {
2023-12-22 22:04:30 -05:00
super ( false ) ;
2023-05-02 00:11:31 -04:00
this . battleStat = battleStat ;
this . multiplier = multiplier ;
2024-04-30 09:47:10 -06:00
this . condition = condition ;
2023-05-02 00:11:31 -04:00
}
2024-04-11 09:24:03 -04:00
applyBattleStat ( pokemon : Pokemon , passive : boolean , battleStat : BattleStat , statValue : Utils.NumberHolder , args : any [ ] ) : boolean | Promise < boolean > {
2024-05-23 17:03:10 +02:00
const move = ( args [ 0 ] as Move ) ;
2024-04-30 09:47:10 -06:00
if ( battleStat === this . battleStat && ( ! this . condition || this . condition ( pokemon , null , move ) ) ) {
2023-05-02 00:11:31 -04:00
statValue . value *= this . multiplier ;
return true ;
}
return false ;
}
}
2023-12-22 01:16:56 -05:00
export class PostAttackAbAttr extends AbAttr {
2024-06-07 16:57:57 -04:00
applyPostAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean | Promise < boolean > {
2023-12-22 01:16:56 -05:00
return false ;
}
}
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
2023-12-23 01:21:01 -05:00
private condition : PokemonAttackCondition ;
constructor ( condition? : PokemonAttackCondition ) {
super ( ) ;
this . condition = condition ;
}
2024-06-07 16:57:57 -04:00
applyPostAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : Promise < boolean > {
2023-12-22 21:42:47 -05:00
return new Promise < boolean > ( resolve = > {
2024-06-07 16:57:57 -04:00
if ( hitResult < HitResult . NO_EFFECT && ( ! this . condition || this . condition ( pokemon , defender , move ) ) ) {
2023-12-22 21:42:47 -05:00
const heldItems = this . getTargetHeldItems ( defender ) . filter ( i = > i . getTransferrable ( false ) ) ;
if ( heldItems . length ) {
2024-01-02 21:31:59 -05:00
const stolenItem = heldItems [ pokemon . randSeedInt ( heldItems . length ) ] ;
2024-05-30 23:58:10 +02:00
pokemon . scene . tryTransferHeldItemModifier ( stolenItem , pokemon , false ) . then ( success = > {
2024-05-23 17:03:10 +02:00
if ( success ) {
2023-12-22 21:42:47 -05:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ` stole \ n ${ defender . name } 's ${ stolenItem . type . name } ! ` ) ) ;
2024-05-23 17:03:10 +02:00
}
2023-12-22 21:42:47 -05:00
resolve ( success ) ;
} ) ;
return ;
}
2023-12-22 01:16:56 -05:00
}
2023-12-22 21:42:47 -05:00
resolve ( false ) ;
} ) ;
2023-12-22 01:16:56 -05:00
}
getTargetHeldItems ( target : Pokemon ) : PokemonHeldItemModifier [ ] {
return target . scene . findModifiers ( m = > m instanceof PokemonHeldItemModifier
&& ( m as PokemonHeldItemModifier ) . pokemonId === target . id , target . isPlayer ( ) ) as PokemonHeldItemModifier [ ] ;
}
}
2024-04-14 11:13:17 -06:00
export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
private contactRequired : boolean ;
2024-03-27 23:02:49 -05:00
private chance : integer ;
private effects : StatusEffect [ ] ;
2024-04-14 11:13:17 -06:00
constructor ( contactRequired : boolean , chance : integer , . . . effects : StatusEffect [ ] ) {
2024-03-27 23:02:49 -05:00
super ( ) ;
2024-04-14 11:13:17 -06:00
this . contactRequired = contactRequired ;
2024-03-27 23:02:49 -05:00
this . chance = chance ;
this . effects = effects ;
}
2024-06-07 16:57:57 -04:00
applyPostAttack ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-06-17 18:30:42 -06:00
/**Status inflicted by abilities post attacking are also considered additional effects.*/
if ( ! attacker . hasAbilityWithAttr ( IgnoreMoveEffectsAbAttr ) && pokemon !== attacker && ( ! this . contactRequired || move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) ) && pokemon . randSeedInt ( 100 ) < this . chance && ! pokemon . status ) {
2024-03-27 23:02:49 -05:00
const effect = this . effects . length === 1 ? this . effects [ 0 ] : this . effects [ pokemon . randSeedInt ( this . effects . length ) ] ;
2024-05-14 14:00:37 -04:00
return attacker . trySetStatus ( effect , true , pokemon ) ;
2024-03-27 23:02:49 -05:00
}
return false ;
}
}
2024-04-14 11:13:17 -06:00
export class PostAttackContactApplyStatusEffectAbAttr extends PostAttackApplyStatusEffectAbAttr {
constructor ( chance : integer , . . . effects : StatusEffect [ ] ) {
super ( true , chance , . . . effects ) ;
}
}
2024-04-19 09:33:35 -04:00
export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr {
private contactRequired : boolean ;
2024-06-07 16:57:57 -04:00
private chance : ( user : Pokemon , target : Pokemon , move : Move ) = > integer ;
2024-04-19 09:33:35 -04:00
private effects : BattlerTagType [ ] ;
2024-05-24 01:45:04 +02:00
2024-06-07 16:57:57 -04:00
constructor ( contactRequired : boolean , chance : ( user : Pokemon , target : Pokemon , move : Move ) = > integer , . . . effects : BattlerTagType [ ] ) {
2024-04-19 09:33:35 -04:00
super ( ) ;
this . contactRequired = contactRequired ;
this . chance = chance ;
this . effects = effects ;
}
2024-06-07 16:57:57 -04:00
applyPostAttack ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-06-17 18:30:42 -06:00
/**Battler tags inflicted by abilities post attacking are also considered additional effects.*/
if ( ! attacker . hasAbilityWithAttr ( IgnoreMoveEffectsAbAttr ) && pokemon !== attacker && ( ! this . contactRequired || move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) ) && pokemon . randSeedInt ( 100 ) < this . chance ( attacker , pokemon , move ) && ! pokemon . status ) {
2024-04-19 09:33:35 -04:00
const effect = this . effects . length === 1 ? this . effects [ 0 ] : this . effects [ pokemon . randSeedInt ( this . effects . length ) ] ;
return attacker . addTag ( effect ) ;
}
return false ;
}
}
2023-12-23 01:21:01 -05:00
export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
private condition : PokemonDefendCondition ;
constructor ( condition? : PokemonDefendCondition ) {
super ( ) ;
this . condition = condition ;
}
2024-06-07 16:57:57 -04:00
applyPostDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : Promise < boolean > {
2023-12-23 01:21:01 -05:00
return new Promise < boolean > ( resolve = > {
2024-06-07 16:57:57 -04:00
if ( hitResult < HitResult . NO_EFFECT && ( ! this . condition || this . condition ( pokemon , attacker , move ) ) ) {
2023-12-23 01:21:01 -05:00
const heldItems = this . getTargetHeldItems ( attacker ) . filter ( i = > i . getTransferrable ( false ) ) ;
if ( heldItems . length ) {
2024-01-02 21:31:59 -05:00
const stolenItem = heldItems [ pokemon . randSeedInt ( heldItems . length ) ] ;
2024-05-30 23:58:10 +02:00
pokemon . scene . tryTransferHeldItemModifier ( stolenItem , pokemon , false ) . then ( success = > {
2024-05-23 17:03:10 +02:00
if ( success ) {
2023-12-23 01:21:01 -05:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ` stole \ n ${ attacker . name } 's ${ stolenItem . type . name } ! ` ) ) ;
2024-05-23 17:03:10 +02:00
}
2023-12-23 01:21:01 -05:00
resolve ( success ) ;
} ) ;
return ;
}
}
resolve ( false ) ;
} ) ;
}
getTargetHeldItems ( target : Pokemon ) : PokemonHeldItemModifier [ ] {
return target . scene . findModifiers ( m = > m instanceof PokemonHeldItemModifier
&& ( m as PokemonHeldItemModifier ) . pokemonId === target . id , target . isPlayer ( ) ) as PokemonHeldItemModifier [ ] ;
}
}
2024-03-29 22:08:27 -04:00
export class PostVictoryAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPostVictory ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2024-03-29 22:08:27 -04:00
return false ;
}
}
class PostVictoryStatChangeAbAttr extends PostVictoryAbAttr {
private stat : BattleStat | ( ( p : Pokemon ) = > BattleStat ) ;
private levels : integer ;
constructor ( stat : BattleStat | ( ( p : Pokemon ) = > BattleStat ) , levels : integer ) {
super ( ) ;
this . stat = stat ;
this . levels = levels ;
}
2024-04-11 09:24:03 -04:00
applyPostVictory ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2024-05-23 17:03:10 +02:00
const stat = typeof this . stat === "function"
2024-03-29 22:08:27 -04:00
? this . stat ( pokemon )
: this . stat ;
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , [ stat ] , this . levels ) ) ;
2024-05-24 01:45:04 +02:00
2024-03-29 22:08:27 -04:00
return true ;
}
}
2024-04-29 19:43:51 -05:00
export class PostVictoryFormChangeAbAttr extends PostVictoryAbAttr {
private formFunc : ( p : Pokemon ) = > integer ;
constructor ( formFunc : ( ( p : Pokemon ) = > integer ) ) {
super ( true ) ;
this . formFunc = formFunc ;
}
applyPostVictory ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
const formIndex = this . formFunc ( pokemon ) ;
if ( formIndex !== pokemon . formIndex ) {
pokemon . scene . triggerPokemonFormChange ( pokemon , SpeciesFormChangeManualTrigger , false ) ;
return true ;
}
return false ;
}
}
2024-04-08 00:20:24 +03:00
export class PostKnockOutAbAttr extends AbAttr {
2024-04-14 13:21:34 +10:00
applyPostKnockOut ( pokemon : Pokemon , passive : boolean , knockedOut : Pokemon , args : any [ ] ) : boolean | Promise < boolean > {
2024-04-08 00:20:24 +03:00
return false ;
}
}
export class PostKnockOutStatChangeAbAttr extends PostKnockOutAbAttr {
private stat : BattleStat | ( ( p : Pokemon ) = > BattleStat ) ;
private levels : integer ;
constructor ( stat : BattleStat | ( ( p : Pokemon ) = > BattleStat ) , levels : integer ) {
super ( ) ;
this . stat = stat ;
this . levels = levels ;
}
2024-04-14 13:21:34 +10:00
applyPostKnockOut ( pokemon : Pokemon , passive : boolean , knockedOut : Pokemon , args : any [ ] ) : boolean | Promise < boolean > {
2024-05-23 17:03:10 +02:00
const stat = typeof this . stat === "function"
2024-04-08 00:20:24 +03:00
? this . stat ( pokemon )
: this . stat ;
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , [ stat ] , this . levels ) ) ;
2024-05-24 01:45:04 +02:00
2024-04-08 00:20:24 +03:00
return true ;
}
}
2024-04-14 13:21:34 +10:00
export class CopyFaintedAllyAbilityAbAttr extends PostKnockOutAbAttr {
constructor ( ) {
super ( ) ;
}
applyPostKnockOut ( pokemon : Pokemon , passive : boolean , knockedOut : Pokemon , args : any [ ] ) : boolean | Promise < boolean > {
if ( pokemon . isPlayer ( ) === knockedOut . isPlayer ( ) && ! knockedOut . getAbility ( ) . hasAttr ( UncopiableAbilityAbAttr ) ) {
pokemon . summonData . ability = knockedOut . getAbility ( ) . id ;
pokemon . scene . queueMessage ( getPokemonMessage ( knockedOut , ` 's ${ allAbilities [ knockedOut . getAbility ( ) . id ] . name } was taken over! ` ) ) ;
return true ;
}
2024-05-24 01:45:04 +02:00
2024-04-14 13:21:34 +10:00
return false ;
}
}
2023-11-05 23:27:40 -05:00
export class IgnoreOpponentStatChangesAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) {
2023-11-05 23:27:40 -05:00
( args [ 0 ] as Utils . IntegerHolder ) . value = 0 ;
return true ;
}
}
2024-05-24 01:45:04 +02:00
/ * *
2024-05-21 23:11:42 -04:00
* Ignores opponent ' s evasion stat changes when determining if a move hits or not
* @extends AbAttr
* @see { @linkcode apply }
* /
export class IgnoreOpponentEvasionAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
/ * *
* Checks if enemy Pokemon is trapped by an Arena Trap - esque ability
* @param pokemon N / A
* @param passive N / A
* @param cancelled N / A
* @param args [ 0 ] { @linkcode Utils . IntegerHolder } of BattleStat . EVA
* @returns if evasion level was successfully considered as 0
2024-05-24 01:45:04 +02:00
* /
2024-05-21 23:11:42 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) {
( args [ 0 ] as Utils . IntegerHolder ) . value = 0 ;
return true ;
}
}
2023-11-05 23:27:40 -05:00
2024-05-24 01:45:04 +02:00
export class IntimidateImmunityAbAttr extends AbAttr {
2024-05-05 07:52:27 -07:00
constructor ( ) {
super ( false ) ;
}
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
cancelled . value = true ;
return true ;
}
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` 's ${ abilityName } prevented it from being Intimidated! ` ) ;
}
}
2024-05-24 01:45:04 +02:00
export class PostIntimidateStatChangeAbAttr extends AbAttr {
2024-05-05 07:52:27 -07:00
private stats : BattleStat [ ] ;
private levels : integer ;
private overwrites : boolean ;
constructor ( stats : BattleStat [ ] , levels : integer , overwrites? : boolean ) {
2024-05-23 17:03:10 +02:00
super ( true ) ;
this . stats = stats ;
this . levels = levels ;
this . overwrites = ! ! overwrites ;
2024-05-05 07:52:27 -07:00
}
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
pokemon . scene . pushPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , false , this . stats , this . levels ) ) ;
cancelled . value = this . overwrites ;
return true ;
}
}
2024-06-22 11:35:25 -04:00
/ * *
* Base class for defining all { @linkcode Ability } Attributes post summon
* @see { @linkcode applyPostSummon ( ) }
* /
2023-05-04 12:57:55 -04:00
export class PostSummonAbAttr extends AbAttr {
2024-06-22 11:35:25 -04:00
/ * *
* Applies ability post summon ( after switching in )
* @param pokemon { @linkcode Pokemon } with this ability
* @param passive Whether this ability is a passive
* @param args Set of unique arguments needed by this attribute
* @returns true if application of the ability succeeds
* /
2024-04-11 09:24:03 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2023-05-04 12:57:55 -04:00
return false ;
}
}
2024-06-18 03:37:11 +08:00
/ * *
* Removes specified arena tags when a Pokemon is summoned .
* /
export class PostSummonRemoveArenaTagAbAttr extends PostSummonAbAttr {
private arenaTags : ArenaTagType [ ] ;
/ * *
* @param arenaTags { @linkcode ArenaTagType [ ] } - the arena tags to be removed
* /
constructor ( arenaTags : ArenaTagType [ ] ) {
super ( true ) ;
this . arenaTags = arenaTags ;
}
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
for ( const arenaTag of this . arenaTags ) {
pokemon . scene . arena . removeTag ( arenaTag ) ;
}
return true ;
}
}
2023-05-04 12:57:55 -04:00
2023-10-30 00:16:23 -04:00
export class PostSummonMessageAbAttr extends PostSummonAbAttr {
private messageFunc : ( pokemon : Pokemon ) = > string ;
constructor ( messageFunc : ( pokemon : Pokemon ) = > string ) {
super ( true ) ;
this . messageFunc = messageFunc ;
}
2024-04-11 09:24:03 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2023-10-30 00:16:23 -04:00
pokemon . scene . queueMessage ( this . messageFunc ( pokemon ) ) ;
return true ;
}
}
2024-05-24 01:45:04 +02:00
export class PostSummonUnnamedMessageAbAttr extends PostSummonAbAttr {
2024-05-13 22:09:46 -03:00
//Attr doesn't force pokemon name on the message
private message : string ;
constructor ( message : string ) {
super ( true ) ;
this . message = message ;
}
2024-05-24 01:45:04 +02:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-05-13 22:09:46 -03:00
pokemon . scene . queueMessage ( this . message ) ;
return true ;
}
}
2023-05-06 12:13:35 -04:00
export class PostSummonAddBattlerTagAbAttr extends PostSummonAbAttr {
private tagType : BattlerTagType ;
private turnCount : integer ;
2023-12-22 22:46:05 -05:00
constructor ( tagType : BattlerTagType , turnCount : integer , showAbility? : boolean ) {
super ( showAbility ) ;
2023-05-06 12:13:35 -04:00
this . tagType = tagType ;
this . turnCount = turnCount ;
}
2024-04-11 09:24:03 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2023-05-06 12:13:35 -04:00
return pokemon . addTag ( this . tagType , this . turnCount ) ;
}
}
export class PostSummonStatChangeAbAttr extends PostSummonAbAttr {
private stats : BattleStat [ ] ;
private levels : integer ;
private selfTarget : boolean ;
2024-05-05 07:52:27 -07:00
private intimidate : boolean ;
2023-05-06 12:13:35 -04:00
2024-05-05 07:52:27 -07:00
constructor ( stats : BattleStat | BattleStat [ ] , levels : integer , selfTarget? : boolean , intimidate? : boolean ) {
super ( false ) ;
2023-05-06 12:13:35 -04:00
2024-05-23 17:03:10 +02:00
this . stats = typeof ( stats ) === "number"
2023-05-06 12:13:35 -04:00
? [ stats as BattleStat ]
: stats as BattleStat [ ] ;
this . levels = levels ;
this . selfTarget = ! ! selfTarget ;
2024-05-05 07:52:27 -07:00
this . intimidate = ! ! intimidate ;
2023-05-06 12:13:35 -04:00
}
2024-04-11 09:24:03 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-05-05 07:52:27 -07:00
queueShowAbility ( pokemon , passive ) ; // TODO: Better solution than manually showing the ability here
if ( this . selfTarget ) {
2024-06-11 16:12:46 +02:00
// we unshift the StatChangePhase to put it right after the showAbility and not at the end of the
// phase list (which could be after CommandPhase for example)
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , this . stats , this . levels ) ) ;
2024-05-05 07:52:27 -07:00
return true ;
2023-05-18 11:11:06 -04:00
}
2024-05-23 17:03:10 +02:00
for ( const opponent of pokemon . getOpponents ( ) ) {
const cancelled = new Utils . BooleanHolder ( false ) ;
2024-05-05 07:52:27 -07:00
if ( this . intimidate ) {
applyAbAttrs ( IntimidateImmunityAbAttr , opponent , cancelled ) ;
applyAbAttrs ( PostIntimidateStatChangeAbAttr , opponent , cancelled ) ;
}
if ( ! cancelled . value ) {
const statChangePhase = new StatChangePhase ( pokemon . scene , opponent . getBattlerIndex ( ) , false , this . stats , this . levels ) ;
2023-05-18 11:11:06 -04:00
pokemon . scene . unshiftPhase ( statChangePhase ) ;
2024-05-05 07:52:27 -07:00
}
2023-05-18 11:11:06 -04:00
}
2023-05-06 12:13:35 -04:00
return true ;
}
}
2024-04-23 09:43:35 -04:00
export class PostSummonAllyHealAbAttr extends PostSummonAbAttr {
private healRatio : number ;
private showAnim : boolean ;
constructor ( healRatio : number , showAnim : boolean = false ) {
super ( ) ;
this . healRatio = healRatio || 4 ;
this . showAnim = showAnim ;
}
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
const target = pokemon . getAlly ( ) ;
if ( target ? . isActive ( true ) ) {
target . scene . unshiftPhase ( new PokemonHealPhase ( target . scene , target . getBattlerIndex ( ) ,
Math . max ( Math . floor ( pokemon . getMaxHp ( ) / this . healRatio ) , 1 ) , getPokemonMessage ( target , ` drank down all the \ nmatcha that ${ pokemon . name } made! ` ) , true , ! this . showAnim ) ) ;
return true ;
}
2024-05-24 01:45:04 +02:00
2024-04-23 09:43:35 -04:00
return false ;
}
}
2024-05-13 05:57:17 -04:00
/ * *
* Resets an ally ' s temporary stat boots to zero with no regard to
* whether this is a positive or negative change
* @param pokemon The { @link Pokemon } with this { @link AbAttr }
* @param passive N / A
* @param args N / A
* @returns if the move was successful
* /
export class PostSummonClearAllyStatsAbAttr extends PostSummonAbAttr {
constructor ( ) {
super ( ) ;
}
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
const target = pokemon . getAlly ( ) ;
if ( target ? . isActive ( true ) ) {
2024-05-23 17:03:10 +02:00
for ( let s = 0 ; s < target . summonData . battleStats . length ; s ++ ) {
2024-05-13 05:57:17 -04:00
target . summonData . battleStats [ s ] = 0 ;
2024-05-23 17:03:10 +02:00
}
2024-05-13 05:57:17 -04:00
2024-05-23 17:03:10 +02:00
target . scene . queueMessage ( getPokemonMessage ( target , "'s stat changes\nwere removed!" ) ) ;
2024-05-13 05:57:17 -04:00
return true ;
}
2024-05-24 01:45:04 +02:00
2024-05-13 05:57:17 -04:00
return false ;
}
}
2024-05-28 15:32:52 -04:00
/ * *
* Download raises either the Attack stat or Special Attack stat by one stage depending on the foe ' s currently lowest defensive stat :
* it will raise Attack if the foe ' s current Defense is lower than its current Special Defense stat ;
* otherwise , it will raise Special Attack .
* @extends PostSummonAbAttr
* @see { applyPostSummon }
* /
2024-04-12 16:08:04 -04:00
export class DownloadAbAttr extends PostSummonAbAttr {
private enemyDef : integer ;
private enemySpDef : integer ;
2024-05-28 15:32:52 -04:00
private enemyCountTally : integer ;
2024-04-12 16:08:04 -04:00
private stats : BattleStat [ ] ;
2024-05-28 15:32:52 -04:00
// TODO: Implement the Substitute feature(s) once move is implemented.
/ * *
* Checks to see if it is the opening turn ( starting a new game ) , if so , Download won ' t work . This is because Download takes into account
* vitamins and items , so it needs to use the BattleStat and the stat alone .
* @param { Pokemon } pokemon Pokemon that is using the move , as well as seeing the opposing pokemon .
* @param { boolean } passive N / A
* @param { any [ ] } args N / A
* @returns Returns true if ability is used successful , false if not .
* /
2024-04-12 16:08:04 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
this . enemyDef = 0 ;
this . enemySpDef = 0 ;
2024-05-28 15:32:52 -04:00
this . enemyCountTally = 0 ;
2024-05-24 01:45:04 +02:00
2024-06-07 12:17:22 -06:00
for ( const opponent of pokemon . getOpponents ( ) ) {
this . enemyCountTally ++ ;
this . enemyDef += opponent . getBattleStat ( Stat . DEF ) ;
this . enemySpDef += opponent . getBattleStat ( Stat . SPDEF ) ;
2024-04-12 16:08:04 -04:00
}
2024-06-07 12:17:22 -06:00
this . enemyDef = Math . round ( this . enemyDef / this . enemyCountTally ) ;
this . enemySpDef = Math . round ( this . enemySpDef / this . enemyCountTally ) ;
2024-05-24 01:45:04 +02:00
2024-05-23 17:03:10 +02:00
if ( this . enemyDef < this . enemySpDef ) {
2024-04-12 16:08:04 -04:00
this . stats = [ BattleStat . ATK ] ;
2024-05-23 17:03:10 +02:00
} else {
2024-04-12 16:08:04 -04:00
this . stats = [ BattleStat . SPATK ] ;
2024-05-23 17:03:10 +02:00
}
2024-04-12 16:08:04 -04:00
if ( this . enemyDef > 0 && this . enemySpDef > 0 ) { // only activate if there's actually an enemy to download from
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , false , this . stats , 1 ) ) ;
return true ;
}
2024-05-24 01:45:04 +02:00
2024-04-12 16:08:04 -04:00
return false ;
}
}
2023-05-04 12:57:55 -04:00
export class PostSummonWeatherChangeAbAttr extends PostSummonAbAttr {
private weatherType : WeatherType ;
constructor ( weatherType : WeatherType ) {
super ( ) ;
this . weatherType = weatherType ;
}
2024-04-11 09:24:03 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-06-07 15:22:06 -04:00
if ( ( this . weatherType === WeatherType . HEAVY_RAIN ||
this . weatherType === WeatherType . HARSH_SUN ||
this . weatherType === WeatherType . STRONG_WINDS ) || ! pokemon . scene . arena . weather ? . isImmutable ( ) ) {
2024-03-25 10:22:16 -04:00
return pokemon . scene . arena . trySetWeather ( this . weatherType , true ) ;
2024-05-23 17:03:10 +02:00
}
2023-05-04 12:57:55 -04:00
return false ;
}
}
2024-03-13 12:23:31 -05:00
export class PostSummonTerrainChangeAbAttr extends PostSummonAbAttr {
private terrainType : TerrainType ;
constructor ( terrainType : TerrainType ) {
super ( ) ;
this . terrainType = terrainType ;
}
2024-04-11 09:24:03 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-03-25 10:22:16 -04:00
return pokemon . scene . arena . trySetTerrain ( this . terrainType , true ) ;
2024-03-13 12:23:31 -05:00
}
}
2024-03-30 00:53:35 -04:00
export class PostSummonFormChangeAbAttr extends PostSummonAbAttr {
private formFunc : ( p : Pokemon ) = > integer ;
constructor ( formFunc : ( ( p : Pokemon ) = > integer ) ) {
super ( true ) ;
this . formFunc = formFunc ;
}
2024-04-11 09:24:03 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-03-30 00:53:35 -04:00
const formIndex = this . formFunc ( pokemon ) ;
2024-05-23 17:03:10 +02:00
if ( formIndex !== pokemon . formIndex ) {
2024-03-30 00:53:35 -04:00
return pokemon . scene . triggerPokemonFormChange ( pokemon , SpeciesFormChangeManualTrigger , false ) ;
2024-05-23 17:03:10 +02:00
}
2024-03-30 00:53:35 -04:00
return false ;
}
}
2024-06-22 11:35:25 -04:00
/** Attempts to copy a pokemon's ability */
export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr {
2024-06-22 12:09:35 -04:00
private target : Pokemon ;
2024-06-22 11:35:25 -04:00
private targetAbilityName : string ;
2024-04-14 13:21:34 +10:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
const targets = pokemon . getOpponents ( ) ;
2024-05-23 17:03:10 +02:00
if ( ! targets . length ) {
2024-04-15 22:52:13 +03:00
return false ;
2024-05-23 17:03:10 +02:00
}
2024-05-24 01:45:04 +02:00
2024-04-14 13:21:34 +10:00
let target : Pokemon ;
2024-05-23 17:03:10 +02:00
if ( targets . length > 1 ) {
2024-04-14 13:21:34 +10:00
pokemon . scene . executeWithSeedOffset ( ( ) = > target = Utils . randSeedItem ( targets ) , pokemon . scene . currentBattle . waveIndex ) ;
2024-05-23 17:03:10 +02:00
} else {
2024-04-14 13:21:34 +10:00
target = targets [ 0 ] ;
2024-05-23 17:03:10 +02:00
}
2024-04-14 13:21:34 +10:00
2024-06-22 11:35:25 -04:00
if (
target . getAbility ( ) . hasAttr ( UncopiableAbilityAbAttr ) &&
// Wonder Guard is normally uncopiable so has the attribute, but Trace specifically can copy it
! ( pokemon . hasAbility ( Abilities . TRACE ) && target . getAbility ( ) . id === Abilities . WONDER_GUARD )
) {
2024-04-14 13:21:34 +10:00
return false ;
2024-05-23 17:03:10 +02:00
}
2024-04-14 13:21:34 +10:00
2024-06-22 12:09:35 -04:00
this . target = target ;
2024-06-22 11:35:25 -04:00
this . targetAbilityName = allAbilities [ target . getAbility ( ) . id ] . name ;
2024-04-14 13:21:34 +10:00
pokemon . summonData . ability = target . getAbility ( ) . id ;
2024-06-16 00:13:59 +08:00
setAbilityRevealed ( target ) ;
2024-06-22 11:35:25 -04:00
pokemon . updateInfo ( ) ;
return true ;
}
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2024-06-22 12:09:35 -04:00
return i18next . t ( "abilityTriggers:trace" , {
pokemonName : getPokemonNameWithAffix ( pokemon ) ,
targetName : getPokemonNameWithAffix ( this . target ) ,
abilityName : this.targetAbilityName ,
} ) ;
2024-06-22 11:35:25 -04:00
}
}
/** Attempt to copy the stat changes on an ally pokemon */
export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr {
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
if ( ! pokemon . scene . currentBattle . double ) {
return false ;
}
const ally = pokemon . getAlly ( ) ;
if ( ! ally || ally . summonData . battleStats . every ( ( change ) = > change === 0 ) ) {
return false ;
}
pokemon . summonData . battleStats = ally . summonData . battleStats ;
pokemon . updateInfo ( ) ;
2024-04-14 13:21:34 +10:00
return true ;
}
2024-06-22 11:35:25 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2024-06-22 12:09:35 -04:00
return i18next . t ( "abilityTriggers:costar" , {
pokemonName : getPokemonNameWithAffix ( pokemon ) ,
allyName : getPokemonNameWithAffix ( pokemon . getAlly ( ) ) ,
} ) ;
2024-06-22 11:35:25 -04:00
}
2024-04-14 13:21:34 +10:00
}
2023-10-29 01:28:56 -04:00
export class PostSummonTransformAbAttr extends PostSummonAbAttr {
constructor ( ) {
super ( true ) ;
}
2024-04-11 09:24:03 -04:00
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2023-10-29 01:28:56 -04:00
const targets = pokemon . getOpponents ( ) ;
2024-05-23 17:03:10 +02:00
if ( ! targets . length ) {
2024-04-30 09:47:10 -06:00
return false ;
2024-05-23 17:03:10 +02:00
}
2024-04-30 09:47:10 -06:00
2023-10-29 01:28:56 -04:00
let target : Pokemon ;
2024-05-23 17:03:10 +02:00
if ( targets . length > 1 ) {
2024-02-17 00:40:03 -05:00
pokemon . scene . executeWithSeedOffset ( ( ) = > target = Utils . randSeedItem ( targets ) , pokemon . scene . currentBattle . waveIndex ) ;
2024-05-23 17:03:10 +02:00
} else {
2023-10-29 01:28:56 -04:00
target = targets [ 0 ] ;
2024-05-23 17:03:10 +02:00
}
2023-10-29 01:28:56 -04:00
pokemon . summonData . speciesForm = target . getSpeciesForm ( ) ;
2023-11-24 15:12:26 -05:00
pokemon . summonData . fusionSpeciesForm = target . getFusionSpeciesForm ( ) ;
2024-04-14 12:23:49 -04:00
pokemon . summonData . ability = target . getAbility ( ) . id ;
2023-10-29 01:28:56 -04:00
pokemon . summonData . gender = target . getGender ( ) ;
2023-11-24 15:12:26 -05:00
pokemon . summonData . fusionGender = target . getFusionGender ( ) ;
2023-10-29 01:28:56 -04:00
pokemon . summonData . stats = [ pokemon . stats [ Stat . HP ] ] . concat ( target . stats . slice ( 1 ) ) ;
pokemon . summonData . battleStats = target . summonData . battleStats . slice ( 0 ) ;
pokemon . summonData . moveset = target . getMoveset ( ) . map ( m = > new PokemonMove ( m . moveId , m . ppUsed , m . ppUp ) ) ;
pokemon . summonData . types = target . getTypes ( ) ;
2024-05-24 01:45:04 +02:00
2024-05-23 17:03:10 +02:00
pokemon . scene . playSound ( "PRSFX- Transform" ) ;
2023-11-24 15:12:26 -05:00
2024-03-27 23:44:11 -04:00
pokemon . loadAssets ( false ) . then ( ( ) = > pokemon . playAnim ( ) ) ;
2023-10-29 01:28:56 -04:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ` transformed \ ninto ${ target . name } ! ` ) ) ;
return true ;
}
}
2024-01-16 00:28:03 -05:00
export class PreSwitchOutAbAttr extends AbAttr {
constructor ( ) {
super ( true ) ;
}
2024-04-11 09:24:03 -04:00
applyPreSwitchOut ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2024-01-16 00:28:03 -05:00
return false ;
}
}
export class PreSwitchOutResetStatusAbAttr extends PreSwitchOutAbAttr {
2024-04-11 09:24:03 -04:00
applyPreSwitchOut ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2024-01-16 00:28:03 -05:00
if ( pokemon . status ) {
pokemon . resetStatus ( ) ;
pokemon . updateInfo ( ) ;
return true ;
}
return false ;
}
}
2024-06-07 15:22:06 -04:00
/ * *
* Clears Desolate Land / Primordial Sea / Delta Stream upon the Pokemon switching out .
* /
export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr {
/ * *
* @param pokemon The { @linkcode Pokemon } with the ability
* @param passive N / A
* @param args N / A
* @returns { boolean } Returns true if the weather clears , otherwise false .
* /
applyPreSwitchOut ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
const weatherType = pokemon . scene . arena . weather . weatherType ;
let turnOffWeather = false ;
// Clear weather only if user's ability matches the weather and no other pokemon has the ability.
switch ( weatherType ) {
case ( WeatherType . HARSH_SUN ) :
if ( pokemon . hasAbility ( Abilities . DESOLATE_LAND )
&& pokemon . scene . getField ( true ) . filter ( p = > p !== pokemon ) . filter ( p = > p . hasAbility ( Abilities . DESOLATE_LAND ) ) . length === 0 ) {
turnOffWeather = true ;
}
break ;
case ( WeatherType . HEAVY_RAIN ) :
if ( pokemon . hasAbility ( Abilities . PRIMORDIAL_SEA )
&& pokemon . scene . getField ( true ) . filter ( p = > p !== pokemon ) . filter ( p = > p . hasAbility ( Abilities . PRIMORDIAL_SEA ) ) . length === 0 ) {
turnOffWeather = true ;
}
break ;
case ( WeatherType . STRONG_WINDS ) :
if ( pokemon . hasAbility ( Abilities . DELTA_STREAM )
&& pokemon . scene . getField ( true ) . filter ( p = > p !== pokemon ) . filter ( p = > p . hasAbility ( Abilities . DELTA_STREAM ) ) . length === 0 ) {
turnOffWeather = true ;
}
break ;
}
if ( turnOffWeather ) {
pokemon . scene . arena . trySetWeather ( WeatherType . NONE , false ) ;
return true ;
}
return false ;
}
}
2024-04-05 17:32:36 +03:00
export class PreSwitchOutHealAbAttr extends PreSwitchOutAbAttr {
2024-04-11 09:24:03 -04:00
applyPreSwitchOut ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2024-04-05 17:32:36 +03:00
if ( pokemon . getHpRatio ( ) < 1 ) {
const healAmount = Math . floor ( pokemon . getMaxHp ( ) * 0.33 ) ;
pokemon . heal ( healAmount ) ;
pokemon . updateInfo ( ) ;
return true ;
}
return false ;
}
}
2024-05-28 12:11:04 +01:00
/ * *
* Attribute for form changes that occur on switching out
* @extends PreSwitchOutAbAttr
* @see { @linkcode applyPreSwitchOut }
* /
export class PreSwitchOutFormChangeAbAttr extends PreSwitchOutAbAttr {
private formFunc : ( p : Pokemon ) = > integer ;
constructor ( formFunc : ( ( p : Pokemon ) = > integer ) ) {
super ( ) ;
this . formFunc = formFunc ;
}
/ * *
* On switch out , trigger the form change to the one defined in the ability
* @param pokemon The pokemon switching out and changing form { @linkcode Pokemon }
* @param passive N / A
* @param args N / A
* @returns true if the form change was successful
* /
applyPreSwitchOut ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
const formIndex = this . formFunc ( pokemon ) ;
if ( formIndex !== pokemon . formIndex ) {
pokemon . scene . triggerPokemonFormChange ( pokemon , SpeciesFormChangeManualTrigger , false ) ;
return true ;
}
return false ;
}
}
2023-04-27 14:30:03 -04:00
export class PreStatChangeAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPreStatChange ( pokemon : Pokemon , passive : boolean , stat : BattleStat , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean | Promise < boolean > {
2023-04-26 23:33:13 -04:00
return false ;
}
}
2023-05-06 12:13:35 -04:00
export class ProtectStatAbAttr extends PreStatChangeAbAttr {
2023-04-27 01:14:15 -04:00
private protectedStat : BattleStat ;
2023-04-26 23:33:13 -04:00
2023-04-27 01:14:15 -04:00
constructor ( protectedStat? : BattleStat ) {
2023-04-26 23:33:13 -04:00
super ( ) ;
2023-04-27 01:14:15 -04:00
this . protectedStat = protectedStat ;
2023-04-26 23:33:13 -04:00
}
2024-04-11 09:24:03 -04:00
applyPreStatChange ( pokemon : Pokemon , passive : boolean , stat : BattleStat , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-04-27 01:14:15 -04:00
if ( this . protectedStat === undefined || stat === this . protectedStat ) {
2023-04-26 23:33:13 -04:00
cancelled . value = true ;
return true ;
}
2024-05-24 01:45:04 +02:00
2023-04-26 23:33:13 -04:00
return false ;
}
2023-04-27 01:14:15 -04:00
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2024-05-23 17:03:10 +02:00
return getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nprevents lowering its ${ this . protectedStat !== undefined ? getBattleStatName ( this . protectedStat ) : "stats" } ! ` ) ;
2023-04-27 01:14:15 -04:00
}
2023-04-26 23:33:13 -04:00
}
2024-05-25 05:51:36 -04:00
/ * *
* This attribute applies confusion to the target whenever the user
* directly poisons them with a move , e . g . Poison Puppeteer .
* Called in { @linkcode StatusEffectAttr } .
* @extends PostAttackAbAttr
* @see { @linkcode applyPostAttack }
* /
export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr {
/** List of effects to apply confusion after */
private effects : StatusEffect [ ] ;
constructor ( . . . effects : StatusEffect [ ] ) {
super ( ) ;
this . effects = effects ;
}
/ * *
* Applies confusion to the target pokemon .
* @param pokemon { @link Pokemon } attacking
* @param passive N / A
* @param defender { @link Pokemon } defending
* @param move { @link Move } used to apply status effect and confusion
* @param hitResult N / A
* @param args [ 0 ] { @linkcode StatusEffect } applied by move
* @returns true if defender is confused
* /
2024-06-07 16:57:57 -04:00
applyPostAttack ( pokemon : Pokemon , passive : boolean , defender : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-05-25 05:51:36 -04:00
if ( this . effects . indexOf ( args [ 0 ] ) > - 1 && ! defender . isFainted ( ) ) {
2024-06-07 16:57:57 -04:00
return defender . addTag ( BattlerTagType . CONFUSED , pokemon . randSeedInt ( 3 , 2 ) , move . id , defender . id ) ;
2024-05-25 05:51:36 -04:00
}
return false ;
}
}
2023-05-04 12:57:55 -04:00
export class PreSetStatusAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPreSetStatus ( pokemon : Pokemon , passive : boolean , effect : StatusEffect , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean | Promise < boolean > {
2023-05-04 12:57:55 -04:00
return false ;
}
}
export class StatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
private immuneEffects : StatusEffect [ ] ;
constructor ( . . . immuneEffects : StatusEffect [ ] ) {
super ( ) ;
this . immuneEffects = immuneEffects ;
}
2023-05-01 22:07:00 -04:00
2024-04-11 09:24:03 -04:00
applyPreSetStatus ( pokemon : Pokemon , passive : boolean , effect : StatusEffect , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-05-04 12:57:55 -04:00
if ( ! this . immuneEffects . length || this . immuneEffects . indexOf ( effect ) > - 1 ) {
cancelled . value = true ;
return true ;
}
return false ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
2024-05-23 17:03:10 +02:00
return getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nprevents ${ this . immuneEffects . length ? getStatusEffectDescriptor ( args [ 0 ] as StatusEffect ) : "status problems" } ! ` ) ;
2023-05-04 12:57:55 -04:00
}
}
export class PreApplyBattlerTagAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPreApplyBattlerTag ( pokemon : Pokemon , passive : boolean , tag : BattlerTag , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean | Promise < boolean > {
2023-05-04 12:57:55 -04:00
return false ;
}
}
export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr {
private immuneTagType : BattlerTagType ;
constructor ( immuneTagType : BattlerTagType ) {
super ( ) ;
this . immuneTagType = immuneTagType ;
}
2024-04-11 09:24:03 -04:00
applyPreApplyBattlerTag ( pokemon : Pokemon , passive : boolean , tag : BattlerTag , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-05-04 12:57:55 -04:00
if ( tag . tagType === this . immuneTagType ) {
cancelled . value = true ;
return true ;
}
return false ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nprevents ${ ( args [ 0 ] as BattlerTag ) . getDescriptor ( ) } ! ` ) ;
2023-05-04 12:57:55 -04:00
}
}
2024-03-14 00:40:57 -04:00
export class BlockCritAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-03-14 00:40:57 -04:00
( args [ 0 ] as Utils . BooleanHolder ) . value = true ;
return true ;
}
}
2023-04-30 23:58:16 -04:00
2024-04-12 22:21:56 +01:00
export class BonusCritAbAttr extends AbAttr {
2024-04-12 19:31:08 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-12 22:21:56 +01:00
( args [ 0 ] as Utils . BooleanHolder ) . value = true ;
return true ;
}
}
2024-05-04 01:56:13 +10:00
export class MultCritAbAttr extends AbAttr {
public multAmount : number ;
constructor ( multAmount : number ) {
super ( true ) ;
this . multAmount = multAmount ;
}
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
const critMult = args [ 0 ] as Utils . NumberHolder ;
2024-05-24 02:19:20 +02:00
if ( critMult . value > 1 ) {
2024-05-04 01:56:13 +10:00
critMult . value *= this . multAmount ;
return true ;
}
return false ;
}
}
2024-05-19 08:06:58 -06:00
/ * *
* Guarantees a critical hit according to the given condition , except if target prevents critical hits . ie . Merciless
* @extends AbAttr
* @see { @linkcode apply }
* /
export class ConditionalCritAbAttr extends AbAttr {
private condition : PokemonAttackCondition ;
constructor ( condition : PokemonAttackCondition , checkUser? : Boolean ) {
super ( ) ;
this . condition = condition ;
}
/ * *
* @param pokemon { @linkcode Pokemon } user .
2024-05-24 01:45:04 +02:00
* @param args [ 0 ] { @linkcode Utils . BooleanHolder } If true critical hit is guaranteed .
2024-05-19 08:06:58 -06:00
* [ 1 ] { @linkcode Pokemon } Target .
* [ 2 ] { @linkcode Move } used by ability user .
* /
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
const target = ( args [ 1 ] as Pokemon ) ;
const move = ( args [ 2 ] as Move ) ;
2024-05-24 02:19:20 +02:00
if ( ! this . condition ( pokemon , target , move ) ) {
2024-05-19 08:06:58 -06:00
return false ;
2024-05-23 17:03:10 +02:00
}
2024-05-19 08:06:58 -06:00
( args [ 0 ] as Utils . BooleanHolder ) . value = true ;
return true ;
}
}
2024-05-04 01:56:13 +10:00
2024-04-02 15:14:07 -04:00
export class BlockNonDirectDamageAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-02 15:14:07 -04:00
cancelled . value = true ;
return true ;
}
}
2024-05-30 18:58:40 -04:00
/ * *
* This attribute will block any status damage that you put in the parameter .
* /
2024-06-20 12:07:27 -07:00
export class BlockStatusDamageAbAttr extends AbAttr {
2024-05-30 18:58:40 -04:00
private effects : StatusEffect [ ] ;
/ * *
* @param { StatusEffect [ ] } effects The status effect ( s ) that will be blocked from damaging the ability pokemon
* /
constructor ( . . . effects : StatusEffect [ ] ) {
super ( false ) ;
this . effects = effects ;
}
/ * *
* @param { Pokemon } pokemon The pokemon with the ability
* @param { boolean } passive N / A
* @param { Utils . BooleanHolder } cancelled Whether to cancel the status damage
* @param { any [ ] } args N / A
* @returns Returns true if status damage is blocked
* /
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-06-20 12:07:27 -07:00
if ( this . effects . includes ( pokemon . status ? . effect ) ) {
2024-05-30 18:58:40 -04:00
cancelled . value = true ;
return true ;
}
return false ;
}
}
2024-03-09 23:49:00 +01:00
export class BlockOneHitKOAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-02 15:14:07 -04:00
cancelled . value = true ;
2024-03-09 23:49:00 +01:00
return true ;
}
}
2024-03-28 16:24:11 -04:00
export class IncrementMovePriorityAbAttr extends AbAttr {
2024-04-08 17:10:07 +03:00
private moveIncrementFunc : ( pokemon : Pokemon , move : Move ) = > boolean ;
private increaseAmount : integer ;
2024-03-28 16:24:11 -04:00
2024-04-08 17:10:07 +03:00
constructor ( moveIncrementFunc : ( pokemon : Pokemon , move : Move ) = > boolean , increaseAmount = 1 ) {
2024-03-28 16:24:11 -04:00
super ( true ) ;
this . moveIncrementFunc = moveIncrementFunc ;
2024-04-08 17:10:07 +03:00
this . increaseAmount = increaseAmount ;
2024-03-28 16:24:11 -04:00
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
if ( ! this . moveIncrementFunc ( pokemon , args [ 0 ] as Move ) ) {
2024-03-28 16:24:11 -04:00
return false ;
2024-05-23 17:03:10 +02:00
}
2024-05-24 01:45:04 +02:00
2024-04-08 17:10:07 +03:00
( args [ 1 ] as Utils . IntegerHolder ) . value += this . increaseAmount ;
2024-03-28 16:24:11 -04:00
return true ;
}
}
2023-12-10 22:29:13 -05:00
export class IgnoreContactAbAttr extends AbAttr { }
2023-04-27 14:30:03 -04:00
export class PreWeatherEffectAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPreWeatherEffect ( pokemon : Pokemon , passive : boolean , weather : Weather , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean | Promise < boolean > {
2023-04-27 14:30:03 -04:00
return false ;
}
}
export class PreWeatherDamageAbAttr extends PreWeatherEffectAbAttr { }
export class BlockWeatherDamageAttr extends PreWeatherDamageAbAttr {
2023-05-02 15:56:41 -04:00
private weatherTypes : WeatherType [ ] ;
constructor ( . . . weatherTypes : WeatherType [ ] ) {
super ( ) ;
this . weatherTypes = weatherTypes ;
}
2024-04-11 09:24:03 -04:00
applyPreWeatherEffect ( pokemon : Pokemon , passive : boolean , weather : Weather , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
if ( ! this . weatherTypes . length || this . weatherTypes . indexOf ( weather ? . weatherType ) > - 1 ) {
2023-05-02 15:56:41 -04:00
cancelled . value = true ;
2024-05-23 17:03:10 +02:00
}
2023-04-27 14:30:03 -04:00
return true ;
}
}
export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr {
2023-05-02 22:27:04 -04:00
public affectsImmutable : boolean ;
2023-04-27 14:30:03 -04:00
constructor ( affectsImmutable? : boolean ) {
super ( ) ;
this . affectsImmutable = affectsImmutable ;
}
2024-04-11 09:24:03 -04:00
applyPreWeatherEffect ( pokemon : Pokemon , passive : boolean , weather : Weather , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-04-27 14:30:03 -04:00
if ( this . affectsImmutable || weather . isImmutable ( ) ) {
cancelled . value = true ;
return true ;
}
return false ;
}
}
2024-06-17 18:30:42 -06:00
/ * *
* Condition function to applied to abilities related to Sheer Force .
* Checks if last move used against target was affected by a Sheer Force user and :
* Disables : Color Change , Pickpocket , Wimp Out , Emergency Exit , Berserk , Anger Shell
* @returns { AbAttrCondition } If false disables the ability which the condition is applied to .
* /
function getSheerForceHitDisableAbCondition ( ) : AbAttrCondition {
return ( pokemon : Pokemon ) = > {
if ( ! pokemon . turnData ) {
return true ;
}
const lastReceivedAttack = pokemon . turnData . attacksReceived [ 0 ] ;
if ( ! lastReceivedAttack ) {
return true ;
}
const lastAttacker = pokemon . getOpponents ( ) . find ( p = > p . id === lastReceivedAttack . sourceId ) ;
if ( ! lastAttacker ) {
return true ;
}
/**if the last move chance is greater than or equal to cero, and the last attacker's ability is sheer force*/
const SheerForceAffected = allMoves [ lastReceivedAttack . move ] . chance >= 0 && lastAttacker . hasAbility ( Abilities . SHEER_FORCE ) ;
return ! SheerForceAffected ;
} ;
}
2023-05-02 15:56:41 -04:00
function getWeatherCondition ( . . . weatherTypes : WeatherType [ ] ) : AbAttrCondition {
return ( pokemon : Pokemon ) = > {
2024-06-19 17:36:23 -04:00
if ( ! pokemon . scene ? . arena ) {
return false ;
}
2024-05-23 17:03:10 +02:00
if ( pokemon . scene . arena . weather ? . isEffectSuppressed ( pokemon . scene ) ) {
2023-05-02 15:56:41 -04:00
return false ;
2024-05-23 17:03:10 +02:00
}
2023-05-02 15:56:41 -04:00
const weatherType = pokemon . scene . arena . weather ? . weatherType ;
return weatherType && weatherTypes . indexOf ( weatherType ) > - 1 ;
} ;
}
2024-04-21 23:01:11 -04:00
function getAnticipationCondition ( ) : AbAttrCondition {
return ( pokemon : Pokemon ) = > {
2024-05-23 17:03:10 +02:00
for ( const opponent of pokemon . getOpponents ( ) ) {
for ( const move of opponent . moveset ) {
// move is super effective
2024-06-08 05:15:24 +10:00
if ( move . getMove ( ) instanceof AttackMove && pokemon . getAttackTypeEffectiveness ( move . getMove ( ) . type , opponent , true ) >= 2 ) {
2024-05-23 17:03:10 +02:00
return true ;
}
// move is a OHKO
2024-05-31 20:50:30 -04:00
if ( move . getMove ( ) . hasAttr ( OneHitKOAttr ) ) {
2024-05-23 17:03:10 +02:00
return true ;
}
// edge case for hidden power, type is computed
if ( move . getMove ( ) . id === Moves . HIDDEN_POWER ) {
const iv_val = Math . floor ( ( ( opponent . ivs [ Stat . HP ] & 1 )
2024-04-21 23:01:11 -04:00
+ ( opponent . ivs [ Stat . ATK ] & 1 ) * 2
+ ( opponent . ivs [ Stat . DEF ] & 1 ) * 4
+ ( opponent . ivs [ Stat . SPD ] & 1 ) * 8
+ ( opponent . ivs [ Stat . SPATK ] & 1 ) * 16
+ ( opponent . ivs [ Stat . SPDEF ] & 1 ) * 32 ) * 15 / 63 ) ;
2024-05-24 01:45:04 +02:00
2024-05-23 17:03:10 +02:00
const type = [
Type . FIGHTING , Type . FLYING , Type . POISON , Type . GROUND ,
Type . ROCK , Type . BUG , Type . GHOST , Type . STEEL ,
Type . FIRE , Type . WATER , Type . GRASS , Type . ELECTRIC ,
Type . PSYCHIC , Type . ICE , Type . DRAGON , Type . DARK ] [ iv_val ] ;
if ( pokemon . getAttackTypeEffectiveness ( type , opponent ) >= 2 ) {
return true ;
2024-04-21 23:01:11 -04:00
}
}
2024-05-23 17:03:10 +02:00
}
2024-04-21 23:01:11 -04:00
}
return false ;
} ;
}
2024-05-07 14:35:15 +10:00
/ * *
* Creates an ability condition that causes the ability to fail if that ability
* has already been used by that pokemon that battle . It requires an ability to
* be specified due to current limitations in how conditions on abilities work .
* @param { Abilities } ability The ability to check if it ' s already been applied
* @returns { AbAttrCondition } The condition
* /
function getOncePerBattleCondition ( ability : Abilities ) : AbAttrCondition {
return ( pokemon : Pokemon ) = > {
return ! pokemon . battleData ? . abilitiesApplied . includes ( ability ) ;
2024-05-23 17:03:10 +02:00
} ;
2024-05-07 14:35:15 +10:00
}
2024-05-03 22:10:40 -04:00
export class ForewarnAbAttr extends PostSummonAbAttr {
constructor ( ) {
super ( true ) ;
}
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
let maxPowerSeen = 0 ;
let maxMove = "" ;
let movePower = 0 ;
2024-05-23 17:03:10 +02:00
for ( const opponent of pokemon . getOpponents ( ) ) {
for ( const move of opponent . moveset ) {
2024-05-03 22:10:40 -04:00
if ( move . getMove ( ) instanceof StatusMove ) {
movePower = 1 ;
2024-05-31 20:50:30 -04:00
} else if ( move . getMove ( ) . hasAttr ( OneHitKOAttr ) ) {
2024-05-03 22:10:40 -04:00
movePower = 150 ;
} else if ( move . getMove ( ) . id === Moves . COUNTER || move . getMove ( ) . id === Moves . MIRROR_COAT || move . getMove ( ) . id === Moves . METAL_BURST ) {
movePower = 120 ;
} else if ( move . getMove ( ) . power === - 1 ) {
movePower = 80 ;
} else {
movePower = move . getMove ( ) . power ;
}
2024-05-24 01:45:04 +02:00
2024-05-03 22:10:40 -04:00
if ( movePower > maxPowerSeen ) {
maxPowerSeen = movePower ;
2024-05-24 01:45:04 +02:00
maxMove = move . getName ( ) ;
2024-05-03 22:10:40 -04:00
}
}
}
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , " was forewarned about " + maxMove + "!" ) ) ;
return true ;
}
}
export class FriskAbAttr extends PostSummonAbAttr {
constructor ( ) {
super ( true ) ;
}
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
for ( const opponent of pokemon . getOpponents ( ) ) {
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , " frisked " + opponent . name + "'s " + opponent . getAbility ( ) . name + "!" ) ) ;
2024-06-16 00:13:59 +08:00
setAbilityRevealed ( opponent ) ;
2024-05-03 22:10:40 -04:00
}
return true ;
}
}
2024-03-18 21:22:27 -04:00
export class PostWeatherChangeAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPostWeatherChange ( pokemon : Pokemon , passive : boolean , weather : WeatherType , args : any [ ] ) : boolean {
2024-03-18 21:22:27 -04:00
return false ;
}
}
export class PostWeatherChangeAddBattlerTagAttr extends PostWeatherChangeAbAttr {
private tagType : BattlerTagType ;
private turnCount : integer ;
private weatherTypes : WeatherType [ ] ;
constructor ( tagType : BattlerTagType , turnCount : integer , . . . weatherTypes : WeatherType [ ] ) {
super ( ) ;
this . tagType = tagType ;
this . turnCount = turnCount ;
this . weatherTypes = weatherTypes ;
}
2024-04-11 09:24:03 -04:00
applyPostWeatherChange ( pokemon : Pokemon , passive : boolean , weather : WeatherType , args : any [ ] ) : boolean {
2024-03-18 21:22:27 -04:00
console . log ( this . weatherTypes . find ( w = > weather === w ) , WeatherType [ weather ] ) ;
2024-05-23 17:03:10 +02:00
if ( ! this . weatherTypes . find ( w = > weather === w ) ) {
2024-03-18 21:22:27 -04:00
return false ;
2024-05-23 17:03:10 +02:00
}
2024-03-18 21:22:27 -04:00
return pokemon . addTag ( this . tagType , this . turnCount ) ;
}
}
2023-05-02 15:56:41 -04:00
export class PostWeatherLapseAbAttr extends AbAttr {
protected weatherTypes : WeatherType [ ] ;
2023-04-27 14:30:03 -04:00
constructor ( . . . weatherTypes : WeatherType [ ] ) {
super ( ) ;
this . weatherTypes = weatherTypes ;
}
2024-04-11 09:24:03 -04:00
applyPostWeatherLapse ( pokemon : Pokemon , passive : boolean , weather : Weather , args : any [ ] ) : boolean | Promise < boolean > {
2023-05-02 15:56:41 -04:00
return false ;
}
getCondition ( ) : AbAttrCondition {
return getWeatherCondition ( . . . this . weatherTypes ) ;
}
}
export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr {
private healFactor : integer ;
constructor ( healFactor : integer , . . . weatherTypes : WeatherType [ ] ) {
super ( . . . weatherTypes ) ;
2024-05-24 01:45:04 +02:00
2023-05-02 15:56:41 -04:00
this . healFactor = healFactor ;
}
2024-04-11 09:24:03 -04:00
applyPostWeatherLapse ( pokemon : Pokemon , passive : boolean , weather : Weather , args : any [ ] ) : boolean {
2023-05-02 15:56:41 -04:00
if ( pokemon . getHpRatio ( ) < 1 ) {
2023-04-27 14:30:03 -04:00
const scene = pokemon . scene ;
2024-04-11 09:24:03 -04:00
const abilityName = ( ! passive ? pokemon . getAbility ( ) : pokemon . getPassiveAbility ( ) ) . name ;
2023-05-18 11:11:06 -04:00
scene . unshiftPhase ( new PokemonHealPhase ( scene , pokemon . getBattlerIndex ( ) ,
2024-04-11 09:24:03 -04:00
Math . max ( Math . floor ( pokemon . getMaxHp ( ) / ( 16 / this . healFactor ) ) , 1 ) , getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nrestored its HP a little! ` ) , true ) ) ;
2023-05-02 15:56:41 -04:00
return true ;
}
return false ;
}
}
export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr {
private damageFactor : integer ;
constructor ( damageFactor : integer , . . . weatherTypes : WeatherType [ ] ) {
super ( . . . weatherTypes ) ;
2024-05-24 01:45:04 +02:00
2023-05-02 15:56:41 -04:00
this . damageFactor = damageFactor ;
}
2024-04-11 09:24:03 -04:00
applyPostWeatherLapse ( pokemon : Pokemon , passive : boolean , weather : Weather , args : any [ ] ) : boolean {
2024-06-26 03:23:48 +10:00
const scene = pokemon . scene ;
const abilityName = ( ! passive ? pokemon . getAbility ( ) : pokemon . getPassiveAbility ( ) ) . name ;
scene . queueMessage ( getPokemonMessage ( pokemon , ` is hurt \ nby its ${ abilityName } ! ` ) ) ;
pokemon . damageAndUpdate ( Math . ceil ( pokemon . getMaxHp ( ) / ( 16 / this . damageFactor ) ) , HitResult . OTHER ) ;
return true ;
2023-04-27 14:30:03 -04:00
}
}
2024-03-18 21:22:27 -04:00
export class PostTerrainChangeAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPostTerrainChange ( pokemon : Pokemon , passive : boolean , terrain : TerrainType , args : any [ ] ) : boolean {
2024-03-18 21:22:27 -04:00
return false ;
}
}
export class PostTerrainChangeAddBattlerTagAttr extends PostTerrainChangeAbAttr {
private tagType : BattlerTagType ;
private turnCount : integer ;
private terrainTypes : TerrainType [ ] ;
constructor ( tagType : BattlerTagType , turnCount : integer , . . . terrainTypes : TerrainType [ ] ) {
super ( ) ;
this . tagType = tagType ;
this . turnCount = turnCount ;
this . terrainTypes = terrainTypes ;
}
2024-04-11 09:24:03 -04:00
applyPostTerrainChange ( pokemon : Pokemon , passive : boolean , terrain : TerrainType , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
if ( ! this . terrainTypes . find ( t = > t === terrain ) ) {
2024-03-18 21:22:27 -04:00
return false ;
2024-05-23 17:03:10 +02:00
}
2024-03-18 21:22:27 -04:00
return pokemon . addTag ( this . tagType , this . turnCount ) ;
}
}
2024-03-13 12:23:31 -05:00
function getTerrainCondition ( . . . terrainTypes : TerrainType [ ] ) : AbAttrCondition {
return ( pokemon : Pokemon ) = > {
const terrainType = pokemon . scene . arena . terrain ? . terrainType ;
return terrainType && terrainTypes . indexOf ( terrainType ) > - 1 ;
} ;
}
2023-12-10 22:29:13 -05:00
export class PostTurnAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2023-12-10 22:29:13 -05:00
return false ;
}
}
2024-05-30 18:58:40 -04:00
/ * *
* This attribute will heal 1 / 8 th HP if the ability pokemon has the correct status .
* /
export class PostTurnStatusHealAbAttr extends PostTurnAbAttr {
private effects : StatusEffect [ ] ;
/ * *
* @param { StatusEffect [ ] } effects The status effect ( s ) that will qualify healing the ability pokemon
* /
constructor ( . . . effects : StatusEffect [ ] ) {
super ( false ) ;
this . effects = effects ;
}
/ * *
* @param { Pokemon } pokemon The pokemon with the ability that will receive the healing
* @param { Boolean } passive N / A
* @param { any [ ] } args N / A
* @returns Returns true if healed from status , false if not
* /
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
2024-06-05 15:41:04 -04:00
if ( this . effects . includes ( pokemon . status ? . effect ) ) {
2024-05-30 18:58:40 -04:00
if ( pokemon . getMaxHp ( ) !== pokemon . hp ) {
const scene = pokemon . scene ;
const abilityName = ( ! passive ? pokemon . getAbility ( ) : pokemon . getPassiveAbility ( ) ) . name ;
scene . unshiftPhase ( new PokemonHealPhase ( scene , pokemon . getBattlerIndex ( ) ,
Math . max ( Math . floor ( pokemon . getMaxHp ( ) / 8 ) , 1 ) , i18next . t ( "abilityTriggers:poisonHeal" , { pokemonName : pokemon.name , abilityName : abilityName } ) , true ) ) ;
return true ;
}
}
return false ;
}
}
2024-05-08 21:21:55 -04:00
/ * *
* After the turn ends , resets the status of either the ability holder or their ally
* @param { boolean } allyTarget Whether to target ally , defaults to false ( self - target )
* /
2024-04-11 05:16:09 +01:00
export class PostTurnResetStatusAbAttr extends PostTurnAbAttr {
2024-05-08 21:21:55 -04:00
private allyTarget : boolean ;
private target : Pokemon ;
constructor ( allyTarget : boolean = false ) {
super ( true ) ;
this . allyTarget = allyTarget ;
}
2024-04-11 09:24:03 -04:00
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-05-08 21:21:55 -04:00
if ( this . allyTarget ) {
this . target = pokemon . getAlly ( ) ;
} else {
this . target = pokemon ;
}
if ( this . target ? . status ) {
2024-05-24 01:45:04 +02:00
2024-07-02 23:22:46 +09:00
this . target . scene . queueMessage ( getStatusEffectHealText ( this . target . status ? . effect , getPokemonNameWithAffix ( this . target ) ) ) ;
2024-05-08 21:21:55 -04:00
this . target . resetStatus ( false ) ;
this . target . updateInfo ( ) ;
2024-04-11 05:16:09 +01:00
return true ;
}
2024-05-24 01:45:04 +02:00
2024-04-11 05:16:09 +01:00
return false ;
}
}
2024-05-22 08:52:45 -04:00
/ * *
* After the turn ends , try to create an extra item
* /
export class PostTurnLootAbAttr extends PostTurnAbAttr {
/ * *
* @param itemType - The type of item to create
* @param procChance - Chance to create an item
* @see { @linkcode applyPostTurn ( ) }
* /
constructor (
/** Extend itemType to add more options */
private itemType : "EATEN_BERRIES" | "HELD_BERRIES" ,
private procChance : ( pokemon : Pokemon ) = > number
) {
super ( ) ;
}
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
const pass = Phaser . Math . RND . realInRange ( 0 , 1 ) ;
// Clamp procChance to [0, 1]. Skip if didn't proc (less than pass)
if ( Math . max ( Math . min ( this . procChance ( pokemon ) , 1 ) , 0 ) < pass ) {
return false ;
}
if ( this . itemType === "EATEN_BERRIES" ) {
return this . createEatenBerry ( pokemon ) ;
} else {
return false ;
}
}
/ * *
* Create a new berry chosen randomly from the berries the pokemon ate this battle
* @param pokemon The pokemon with this ability
* @returns whether a new berry was created
* /
createEatenBerry ( pokemon : Pokemon ) : boolean {
const berriesEaten = pokemon . battleData . berriesEaten ;
if ( ! berriesEaten . length ) {
return false ;
}
const randomIdx = Utils . randSeedInt ( berriesEaten . length ) ;
2024-05-23 17:03:10 +02:00
const chosenBerryType = berriesEaten [ randomIdx ] ;
2024-05-22 19:34:49 -04:00
const chosenBerry = new BerryModifierType ( chosenBerryType ) ;
2024-05-23 17:03:10 +02:00
berriesEaten . splice ( randomIdx ) ; // Remove berry from memory
2024-05-22 08:52:45 -04:00
const berryModifier = pokemon . scene . findModifier (
2024-05-22 19:34:49 -04:00
( m ) = > m instanceof BerryModifier && m . berryType === chosenBerryType ,
2024-05-22 08:52:45 -04:00
pokemon . isPlayer ( )
) as BerryModifier | undefined ;
if ( ! berryModifier ) {
2024-05-22 19:34:49 -04:00
pokemon . scene . addModifier ( new BerryModifier ( chosenBerry , pokemon . id , chosenBerryType , 1 ) ) ;
2024-06-07 17:42:48 -04:00
} else if ( berryModifier . stackCount < berryModifier . getMaxHeldItemCount ( pokemon ) ) {
2024-05-22 08:52:45 -04:00
berryModifier . stackCount ++ ;
}
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ` harvested one ${ chosenBerry . name } ! ` ) ) ;
pokemon . scene . updateModifiers ( pokemon . isPlayer ( ) ) ;
return true ;
}
}
2024-04-25 01:23:45 -04:00
export class MoodyAbAttr extends PostTurnAbAttr {
constructor ( ) {
super ( true ) ;
}
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
const selectableStats = [ BattleStat . ATK , BattleStat . DEF , BattleStat . SPATK , BattleStat . SPDEF , BattleStat . SPD ] ;
const increaseStatArray = selectableStats . filter ( s = > pokemon . summonData . battleStats [ s ] < 6 ) ;
2024-05-03 22:30:23 -04:00
let decreaseStatArray = selectableStats . filter ( s = > pokemon . summonData . battleStats [ s ] > - 6 ) ;
if ( increaseStatArray . length > 0 ) {
2024-05-23 17:03:10 +02:00
const increaseStat = increaseStatArray [ Utils . randInt ( increaseStatArray . length ) ] ;
2024-05-03 22:30:23 -04:00
decreaseStatArray = decreaseStatArray . filter ( s = > s !== increaseStat ) ;
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , [ increaseStat ] , 2 ) ) ;
}
if ( decreaseStatArray . length > 0 ) {
2024-05-23 17:03:10 +02:00
const decreaseStat = selectableStats [ Utils . randInt ( selectableStats . length ) ] ;
2024-05-03 22:30:23 -04:00
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , [ decreaseStat ] , - 1 ) ) ;
}
2024-04-25 01:23:45 -04:00
return true ;
}
}
2023-12-22 01:16:56 -05:00
export class PostTurnStatChangeAbAttr extends PostTurnAbAttr {
private stats : BattleStat [ ] ;
private levels : integer ;
constructor ( stats : BattleStat | BattleStat [ ] , levels : integer ) {
super ( true ) ;
this . stats = Array . isArray ( stats )
? stats
: [ stats ] ;
this . levels = levels ;
}
2024-04-11 09:24:03 -04:00
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2023-12-22 01:16:56 -05:00
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , this . stats , this . levels ) ) ;
2023-12-10 22:29:13 -05:00
return true ;
}
}
export class PostTurnHealAbAttr extends PostTurnAbAttr {
2024-04-11 09:24:03 -04:00
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2023-12-10 22:29:13 -05:00
if ( pokemon . getHpRatio ( ) < 1 ) {
const scene = pokemon . scene ;
2024-04-11 09:24:03 -04:00
const abilityName = ( ! passive ? pokemon . getAbility ( ) : pokemon . getPassiveAbility ( ) ) . name ;
2023-12-10 22:29:13 -05:00
scene . unshiftPhase ( new PokemonHealPhase ( scene , pokemon . getBattlerIndex ( ) ,
2024-04-11 09:24:03 -04:00
Math . max ( Math . floor ( pokemon . getMaxHp ( ) / 16 ) , 1 ) , getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nrestored its HP a little! ` ) , true ) ) ;
2023-12-10 22:29:13 -05:00
return true ;
}
return false ;
}
}
2024-03-30 00:53:35 -04:00
export class PostTurnFormChangeAbAttr extends PostTurnAbAttr {
private formFunc : ( p : Pokemon ) = > integer ;
constructor ( formFunc : ( ( p : Pokemon ) = > integer ) ) {
super ( true ) ;
this . formFunc = formFunc ;
}
2024-04-11 09:24:03 -04:00
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-03-30 00:53:35 -04:00
const formIndex = this . formFunc ( pokemon ) ;
if ( formIndex !== pokemon . formIndex ) {
pokemon . scene . triggerPokemonFormChange ( pokemon , SpeciesFormChangeManualTrigger , false ) ;
return true ;
}
return false ;
}
}
2024-05-21 09:26:01 +02:00
/ * *
* Attribute used for abilities ( Bad Dreams ) that damages the opponents for being asleep
* /
export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
/ * *
* Deals damage to all sleeping opponents equal to 1 / 8 of their max hp ( min 1 )
2024-05-24 01:45:04 +02:00
* @param { Pokemon } pokemon Pokemon that has this ability
2024-05-21 09:26:01 +02:00
* @param { boolean } passive N / A
* @param { any [ ] } args N / A
* @returns { boolean } true if any opponents are sleeping
* /
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean | Promise < boolean > {
let hadEffect : boolean = false ;
2024-05-24 02:19:20 +02:00
for ( const opp of pokemon . getOpponents ( ) ) {
2024-05-27 05:01:03 -06:00
if ( opp . status ? . effect === StatusEffect . SLEEP || opp . hasAbility ( Abilities . COMATOSE ) ) {
2024-05-21 09:26:01 +02:00
opp . damageAndUpdate ( Math . floor ( Math . max ( 1 , opp . getMaxHp ( ) / 8 ) ) , HitResult . OTHER ) ;
2024-06-06 15:36:12 +02:00
pokemon . scene . queueMessage ( i18next . t ( "abilityTriggers:badDreams" , { pokemonName : getPokemonNameWithAffix ( opp ) } ) ) ;
2024-05-21 09:26:01 +02:00
hadEffect = true ;
}
2024-05-24 01:45:04 +02:00
2024-05-21 09:26:01 +02:00
}
return hadEffect ;
}
}
2024-05-24 01:45:04 +02:00
/ * *
* Grabs the last failed Pokeball used
* @extends PostTurnAbAttr
2024-05-19 17:13:33 +01:00
* @see { @linkcode applyPostTurn } * /
export class FetchBallAbAttr extends PostTurnAbAttr {
constructor ( ) {
super ( ) ;
}
2024-05-24 01:45:04 +02:00
/ * *
* Adds the last used Pokeball back into the player ' s inventory
* @param pokemon { @linkcode Pokemon } with this ability
* @param passive N / A
* @param args N / A
* @returns true if player has used a pokeball and this pokemon is owned by the player
2024-05-19 17:13:33 +01:00
* /
applyPostTurn ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
const lastUsed = pokemon . scene . currentBattle . lastUsedPokeball ;
2024-05-24 02:19:20 +02:00
if ( lastUsed !== null && pokemon . isPlayer ) {
2024-05-19 17:13:33 +01:00
pokemon . scene . pokeballCounts [ lastUsed ] ++ ;
pokemon . scene . currentBattle . lastUsedPokeball = null ;
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ` found a \ n ${ getPokeballName ( lastUsed ) } ! ` ) ) ;
return true ;
}
return false ;
}
}
2024-04-08 09:31:30 -04:00
export class PostBiomeChangeAbAttr extends AbAttr { }
export class PostBiomeChangeWeatherChangeAbAttr extends PostBiomeChangeAbAttr {
private weatherType : WeatherType ;
constructor ( weatherType : WeatherType ) {
super ( ) ;
this . weatherType = weatherType ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-05-23 17:03:10 +02:00
if ( ! pokemon . scene . arena . weather ? . isImmutable ( ) ) {
2024-04-08 09:31:30 -04:00
return pokemon . scene . arena . trySetWeather ( this . weatherType , true ) ;
2024-05-23 17:03:10 +02:00
}
2024-04-08 09:31:30 -04:00
return false ;
}
}
export class PostBiomeChangeTerrainChangeAbAttr extends PostBiomeChangeAbAttr {
private terrainType : TerrainType ;
constructor ( terrainType : TerrainType ) {
super ( ) ;
this . terrainType = terrainType ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-08 09:31:30 -04:00
return pokemon . scene . arena . trySetTerrain ( this . terrainType , true ) ;
}
}
2024-05-25 06:00:58 +02:00
/ * *
* Triggers just after a move is used either by the opponent or the player
* @extends AbAttr
* /
export class PostMoveUsedAbAttr extends AbAttr {
applyPostMoveUsed ( pokemon : Pokemon , move : PokemonMove , source : Pokemon , targets : BattlerIndex [ ] , args : any [ ] ) : boolean | Promise < boolean > {
return false ;
}
}
/ * *
* Triggers after a dance move is used either by the opponent or the player
* @extends PostMoveUsedAbAttr
* /
export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
/ * *
* Resolves the Dancer ability by replicating the move used by the source of the dance
* either on the source itself or on the target of the dance
* @param dancer { @linkcode Pokemon } with Dancer ability
* @param move { @linkcode PokemonMove } Dancing move used by the source
* @param source { @linkcode Pokemon } that used the dancing move
* @param targets { @linkcode BattlerIndex } Targets of the dancing move
* @param args N / A
*
* @return true if the Dancer ability was resolved
* /
applyPostMoveUsed ( dancer : Pokemon , move : PokemonMove , source : Pokemon , targets : BattlerIndex [ ] , args : any [ ] ) : boolean | Promise < boolean > {
2024-06-05 19:10:24 +02:00
// List of tags that prevent the Dancer from replicating the move
const forbiddenTags = [ BattlerTagType . FLYING , BattlerTagType . UNDERWATER ,
BattlerTagType . UNDERGROUND , BattlerTagType . HIDDEN ] ;
2024-05-25 06:00:58 +02:00
// The move to replicate cannot come from the Dancer
2024-06-05 19:10:24 +02:00
if ( source . getBattlerIndex ( ) !== dancer . getBattlerIndex ( )
&& ! dancer . summonData . tags . some ( tag = > forbiddenTags . includes ( tag . tagType ) ) ) {
2024-05-25 06:00:58 +02:00
// If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance
if ( move . getMove ( ) instanceof AttackMove || move . getMove ( ) instanceof StatusMove ) {
const target = this . getTarget ( dancer , source , targets ) ;
dancer . scene . unshiftPhase ( new MovePhase ( dancer . scene , dancer , target , move , true ) ) ;
} else if ( move . getMove ( ) instanceof SelfStatusMove ) {
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself
dancer . scene . unshiftPhase ( new MovePhase ( dancer . scene , dancer , [ dancer . getBattlerIndex ( ) ] , move , true ) ) ;
}
2024-06-05 19:10:24 +02:00
return true ;
2024-05-25 06:00:58 +02:00
}
2024-06-05 19:10:24 +02:00
return false ;
2024-05-25 06:00:58 +02:00
}
/ * *
* Get the correct targets of Dancer ability
*
* @param dancer { @linkcode Pokemon } Pokemon with Dancer ability
* @param source { @linkcode Pokemon } Source of the dancing move
* @param targets { @linkcode BattlerIndex } Targets of the dancing move
* /
getTarget ( dancer : Pokemon , source : Pokemon , targets : BattlerIndex [ ] ) : BattlerIndex [ ] {
if ( dancer . isPlayer ( ) ) {
return source . isPlayer ( ) ? targets : [ source . getBattlerIndex ( ) ] ;
}
return source . isPlayer ( ) ? [ source . getBattlerIndex ( ) ] : targets ;
}
}
2023-11-06 16:11:38 +13:00
export class StatChangeMultiplierAbAttr extends AbAttr {
private multiplier : integer ;
constructor ( multiplier : integer ) {
super ( true ) ;
this . multiplier = multiplier ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-11-06 16:11:38 +13:00
( args [ 0 ] as Utils . IntegerHolder ) . value *= this . multiplier ;
return true ;
}
}
2024-05-04 16:38:53 -07:00
export class StatChangeCopyAbAttr extends AbAttr {
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean | Promise < boolean > {
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , ( args [ 0 ] as BattleStat [ ] ) , ( args [ 1 ] as integer ) , true , false , false ) ) ;
return true ;
}
}
2024-03-14 00:40:57 -04:00
export class BypassBurnDamageReductionAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-03-14 00:40:57 -04:00
cancelled . value = true ;
return true ;
}
}
2023-12-22 01:16:56 -05:00
export class DoubleBerryEffectAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-12-22 01:16:56 -05:00
( args [ 0 ] as Utils . NumberHolder ) . value *= 2 ;
return true ;
}
}
2023-12-23 01:21:01 -05:00
export class PreventBerryUseAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-12-23 01:21:01 -05:00
cancelled . value = true ;
return true ;
}
}
2024-05-28 13:19:03 -04:00
/ * *
* A Pokemon with this ability heals by a percentage of their maximum hp after eating a berry
* @param healPercent - Percent of Max HP to heal
* @see { @linkcode apply ( ) } for implementation
* /
export class HealFromBerryUseAbAttr extends AbAttr {
/** Percent of Max HP to heal */
private healPercent : number ;
constructor ( healPercent : number ) {
super ( ) ;
// Clamp healPercent so its between [0,1].
this . healPercent = Math . max ( Math . min ( healPercent , 1 ) , 0 ) ;
}
apply ( pokemon : Pokemon , passive : boolean , . . . args : [ Utils . BooleanHolder , any [ ] ] ) : boolean {
const { name : abilityName } = passive ? pokemon . getPassiveAbility ( ) : pokemon . getAbility ( ) ;
pokemon . scene . unshiftPhase (
new PokemonHealPhase (
pokemon . scene ,
pokemon . getBattlerIndex ( ) ,
Math . max ( Math . floor ( pokemon . getMaxHp ( ) * this . healPercent ) , 1 ) ,
getPokemonMessage ( pokemon , ` 's ${ abilityName } \ nrestored its HP! ` ) ,
true
)
) ;
return true ;
}
}
2023-12-22 18:08:37 -04:00
export class RunSuccessAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-12-22 18:08:37 -04:00
( args [ 0 ] as Utils . IntegerHolder ) . value = 256 ;
return true ;
}
}
2024-05-29 14:47:16 -04:00
type ArenaTrapCondition = ( user : Pokemon , target : Pokemon ) = > boolean ;
2024-05-19 13:05:46 -04:00
/ * *
* Base class for checking if a Pokemon is trapped by arena trap
* @extends AbAttr
2024-05-29 14:47:16 -04:00
* @field { @linkcode arenaTrapCondition } Conditional for trapping abilities .
* For example , Magnet Pull will only activate if opponent is Steel type .
2024-05-19 13:05:46 -04:00
* @see { @linkcode applyCheckTrapped }
* /
2023-05-04 12:57:55 -04:00
export class CheckTrappedAbAttr extends AbAttr {
2024-05-29 14:47:16 -04:00
protected arenaTrapCondition : ArenaTrapCondition ;
constructor ( condition : ArenaTrapCondition ) {
2023-12-22 22:04:30 -05:00
super ( false ) ;
2024-05-29 14:47:16 -04:00
this . arenaTrapCondition = condition ;
2023-12-22 22:04:30 -05:00
}
2024-05-19 13:05:46 -04:00
applyCheckTrapped ( pokemon : Pokemon , passive : boolean , trapped : Utils.BooleanHolder , otherPokemon : Pokemon , args : any [ ] ) : boolean | Promise < boolean > {
2023-05-04 12:57:55 -04:00
return false ;
}
}
2024-05-19 13:05:46 -04:00
/ * *
* Determines whether a Pokemon is blocked from switching / running away
* because of a trapping ability or move .
* @extends CheckTrappedAbAttr
* @see { @linkcode applyCheckTrapped }
* /
2023-05-04 12:57:55 -04:00
export class ArenaTrapAbAttr extends CheckTrappedAbAttr {
2024-05-19 13:05:46 -04:00
/ * *
* Checks if enemy Pokemon is trapped by an Arena Trap - esque ability
2024-05-29 14:47:16 -04:00
* If the enemy is a Ghost type , it is not trapped
2024-06-08 15:46:16 -04:00
* If the enemy has the ability Run Away , it is not trapped .
2024-05-29 14:47:16 -04:00
* If the user has Magnet Pull and the enemy is not a Steel type , it is not trapped .
* If the user has Arena Trap and the enemy is not grounded , it is not trapped .
2024-05-19 13:05:46 -04:00
* @param pokemon The { @link Pokemon } with this { @link AbAttr }
* @param passive N / A
* @param trapped { @link Utils . BooleanHolder } indicating whether the other Pokemon is trapped or not
* @param otherPokemon The { @link Pokemon } that is affected by an Arena Trap ability
* @param args N / A
* @returns if enemy Pokemon is trapped or not
* /
applyCheckTrapped ( pokemon : Pokemon , passive : boolean , trapped : Utils.BooleanHolder , otherPokemon : Pokemon , args : any [ ] ) : boolean {
2024-05-29 14:47:16 -04:00
if ( this . arenaTrapCondition ( pokemon , otherPokemon ) ) {
if ( otherPokemon . getTypes ( true ) . includes ( Type . GHOST ) || ( otherPokemon . getTypes ( true ) . includes ( Type . STELLAR ) && otherPokemon . getTypes ( ) . includes ( Type . GHOST ) ) ) {
trapped . value = false ;
return false ;
2024-06-08 15:46:16 -04:00
} else if ( otherPokemon . hasAbility ( Abilities . RUN_AWAY ) ) {
trapped . value = false ;
return false ;
2024-05-29 14:47:16 -04:00
}
trapped . value = true ;
return true ;
2024-05-19 13:05:46 -04:00
}
2024-05-29 14:47:16 -04:00
trapped . value = false ;
return false ;
2023-05-04 12:57:55 -04:00
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` \ 's ${ abilityName } \ nprevents switching! ` ) ;
2023-05-04 12:57:55 -04:00
}
}
2023-12-22 18:08:37 -04:00
export class MaxMultiHitAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-12-22 18:08:37 -04:00
( args [ 0 ] as Utils . IntegerHolder ) . value = 0 ;
return true ;
}
}
2024-03-06 21:05:23 -05:00
export class PostBattleAbAttr extends AbAttr {
constructor ( ) {
super ( true ) ;
}
2024-04-11 09:24:03 -04:00
applyPostBattle ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-03-06 21:05:23 -05:00
return false ;
}
}
export class PostBattleLootAbAttr extends PostBattleAbAttr {
2024-04-11 09:24:03 -04:00
applyPostBattle ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
2024-03-06 21:05:23 -05:00
const postBattleLoot = pokemon . scene . currentBattle . postBattleLoot ;
if ( postBattleLoot . length ) {
const randItem = Utils . randSeedItem ( postBattleLoot ) ;
2024-05-30 23:58:10 +02:00
if ( pokemon . scene . tryTransferHeldItemModifier ( randItem , pokemon , true , 1 , true ) ) {
2024-03-08 14:49:17 -05:00
postBattleLoot . splice ( postBattleLoot . indexOf ( randItem ) , 1 ) ;
2024-03-06 21:05:23 -05:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ` picked up \ n ${ randItem . type . name } ! ` ) ) ;
return true ;
}
}
return false ;
}
}
2024-04-09 18:05:15 -04:00
export class PostFaintAbAttr extends AbAttr {
2024-06-07 16:57:57 -04:00
applyPostFaint ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-04-09 18:05:15 -04:00
return false ;
}
}
2024-06-07 15:22:06 -04:00
/ * *
* Clears Desolate Land / Primordial Sea / Delta Stream upon the Pokemon fainting
* /
export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr {
/ * *
* @param pokemon The { @linkcode Pokemon } with the ability
* @param passive N / A
* @param attacker N / A
* @param move N / A
* @param hitResult N / A
* @param args N / A
* @returns { boolean } Returns true if the weather clears , otherwise false .
* /
2024-06-07 17:05:44 -04:00
applyPostFaint ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-06-07 15:22:06 -04:00
const weatherType = pokemon . scene . arena . weather . weatherType ;
let turnOffWeather = false ;
// Clear weather only if user's ability matches the weather and no other pokemon has the ability.
switch ( weatherType ) {
case ( WeatherType . HARSH_SUN ) :
if ( pokemon . hasAbility ( Abilities . DESOLATE_LAND )
&& pokemon . scene . getField ( true ) . filter ( p = > p . hasAbility ( Abilities . DESOLATE_LAND ) ) . length === 0 ) {
turnOffWeather = true ;
}
break ;
case ( WeatherType . HEAVY_RAIN ) :
if ( pokemon . hasAbility ( Abilities . PRIMORDIAL_SEA )
&& pokemon . scene . getField ( true ) . filter ( p = > p . hasAbility ( Abilities . PRIMORDIAL_SEA ) ) . length === 0 ) {
turnOffWeather = true ;
}
break ;
case ( WeatherType . STRONG_WINDS ) :
if ( pokemon . hasAbility ( Abilities . DELTA_STREAM )
&& pokemon . scene . getField ( true ) . filter ( p = > p . hasAbility ( Abilities . DELTA_STREAM ) ) . length === 0 ) {
turnOffWeather = true ;
}
break ;
}
if ( turnOffWeather ) {
pokemon . scene . arena . trySetWeather ( WeatherType . NONE , false ) ;
return true ;
}
return false ;
}
}
2024-04-09 18:05:15 -04:00
export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
private damageRatio : integer ;
2024-05-24 01:45:04 +02:00
2024-04-09 18:05:15 -04:00
constructor ( damageRatio : integer ) {
super ( ) ;
this . damageRatio = damageRatio ;
}
2024-06-07 16:57:57 -04:00
applyPostFaint ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
if ( move . checkFlag ( MoveFlags . MAKES_CONTACT , attacker , pokemon ) ) {
2024-04-25 21:42:41 -04:00
const cancelled = new Utils . BooleanHolder ( false ) ;
2024-05-23 17:03:10 +02:00
pokemon . scene . getField ( true ) . map ( p = > applyAbAttrs ( FieldPreventExplosiveMovesAbAttr , p , cancelled ) ) ;
2024-05-24 23:35:45 +03:00
if ( cancelled . value ) {
2024-04-25 21:42:41 -04:00
return false ;
}
2024-04-09 18:05:15 -04:00
attacker . damageAndUpdate ( Math . ceil ( attacker . getMaxHp ( ) * ( 1 / this . damageRatio ) ) , HitResult . OTHER ) ;
2024-04-25 20:51:04 -04:00
attacker . turnData . damageTaken += Math . ceil ( attacker . getMaxHp ( ) * ( 1 / this . damageRatio ) ) ;
2024-04-09 18:05:15 -04:00
return true ;
}
return false ;
}
2024-04-11 09:24:03 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` 's ${ abilityName } hurt \ nits attacker! ` ) ;
2024-04-09 18:05:15 -04:00
}
}
2024-05-24 01:45:04 +02:00
/ * *
2024-05-12 17:07:31 -04:00
* Attribute used for abilities ( Innards Out ) that damage the opponent based on how much HP the last attack used to knock out the owner of the ability .
* /
export class PostFaintHPDamageAbAttr extends PostFaintAbAttr {
constructor ( ) {
super ( ) ;
}
2024-06-07 16:57:57 -04:00
applyPostFaint ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , hitResult : HitResult , args : any [ ] ) : boolean {
2024-05-12 17:07:31 -04:00
const damage = pokemon . turnData . attacksReceived [ 0 ] . damage ;
attacker . damageAndUpdate ( ( damage ) , HitResult . OTHER ) ;
attacker . turnData . damageTaken += damage ;
return true ;
2024-05-24 01:45:04 +02:00
}
2024-05-12 17:07:31 -04:00
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return getPokemonMessage ( pokemon , ` 's ${ abilityName } hurt \ nits attacker! ` ) ;
}
}
2024-03-11 20:55:41 -04:00
export class RedirectMoveAbAttr extends AbAttr {
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-03-11 20:55:41 -04:00
if ( this . canRedirect ( args [ 0 ] as Moves ) ) {
const target = args [ 1 ] as Utils . IntegerHolder ;
const newTarget = pokemon . getBattlerIndex ( ) ;
if ( target . value !== newTarget ) {
target . value = newTarget ;
return true ;
}
}
return false ;
}
2024-05-24 01:45:04 +02:00
2024-03-11 20:55:41 -04:00
canRedirect ( moveId : Moves ) : boolean {
const move = allMoves [ moveId ] ;
return ! ! [ MoveTarget . NEAR_OTHER , MoveTarget . OTHER ] . find ( t = > move . moveTarget === t ) ;
}
}
export class RedirectTypeMoveAbAttr extends RedirectMoveAbAttr {
public type : Type ;
constructor ( type : Type ) {
super ( ) ;
this . type = type ;
}
canRedirect ( moveId : Moves ) : boolean {
return super . canRedirect ( moveId ) && allMoves [ moveId ] . type === this . type ;
}
}
2024-05-10 11:40:21 -04:00
export class BlockRedirectAbAttr extends AbAttr { }
2024-01-16 00:28:03 -05:00
export class ReduceStatusEffectDurationAbAttr extends AbAttr {
private statusEffect : StatusEffect ;
constructor ( statusEffect : StatusEffect ) {
super ( true ) ;
this . statusEffect = statusEffect ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-01-16 00:28:03 -05:00
if ( args [ 0 ] === this . statusEffect ) {
( args [ 1 ] as Utils . IntegerHolder ) . value = Math . floor ( ( args [ 1 ] as Utils . IntegerHolder ) . value / 2 ) ;
return true ;
}
return false ;
}
}
export class FlinchEffectAbAttr extends AbAttr {
constructor ( ) {
super ( true ) ;
}
}
export class FlinchStatChangeAbAttr extends FlinchEffectAbAttr {
private stats : BattleStat [ ] ;
private levels : integer ;
constructor ( stats : BattleStat | BattleStat [ ] , levels : integer ) {
super ( ) ;
this . stats = Array . isArray ( stats )
? stats
: [ stats ] ;
this . levels = levels ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-01-16 00:28:03 -05:00
pokemon . scene . unshiftPhase ( new StatChangePhase ( pokemon . scene , pokemon . getBattlerIndex ( ) , true , this . stats , this . levels ) ) ;
return true ;
}
}
2024-04-11 09:24:03 -04:00
export class IncreasePpAbAttr extends AbAttr { }
2024-05-05 07:52:27 -07:00
export class ForceSwitchOutImmunityAbAttr extends AbAttr {
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-05-05 10:54:22 -07:00
cancelled . value = true ;
2024-05-05 07:52:27 -07:00
return true ;
}
}
2024-01-16 00:28:03 -05:00
export class ReduceBerryUseThresholdAbAttr extends AbAttr {
constructor ( ) {
2024-04-11 09:24:03 -04:00
super ( ) ;
2024-01-16 00:28:03 -05:00
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-01-16 00:28:03 -05:00
const hpRatio = pokemon . getHpRatio ( ) ;
if ( args [ 0 ] . value < hpRatio ) {
args [ 0 ] . value *= 2 ;
return args [ 0 ] . value >= hpRatio ;
}
return false ;
}
}
2023-12-10 22:29:13 -05:00
export class WeightMultiplierAbAttr extends AbAttr {
private multiplier : integer ;
constructor ( multiplier : integer ) {
2024-04-11 09:24:03 -04:00
super ( ) ;
2023-12-10 22:29:13 -05:00
this . multiplier = multiplier ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2023-12-10 22:29:13 -05:00
( args [ 0 ] as Utils . NumberHolder ) . value *= this . multiplier ;
return true ;
}
}
2024-01-05 22:24:05 -05:00
export class SyncEncounterNatureAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-02 23:00:56 -04:00
( args [ 0 ] as Pokemon ) . setNature ( pokemon . getNature ( ) ) ;
2024-01-05 22:24:05 -05:00
return true ;
}
}
2024-03-14 00:40:57 -04:00
export class MoveAbilityBypassAbAttr extends AbAttr {
2024-04-18 15:44:03 +10:00
private moveIgnoreFunc : ( pokemon : Pokemon , move : Move ) = > boolean ;
constructor ( moveIgnoreFunc ? : ( pokemon : Pokemon , move : Move ) = > boolean ) {
super ( false ) ;
this . moveIgnoreFunc = moveIgnoreFunc || ( ( pokemon , move ) = > true ) ;
}
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
if ( this . moveIgnoreFunc ( pokemon , ( args [ 0 ] as Move ) ) ) {
cancelled . value = true ;
return true ;
}
return false ;
}
}
export class SuppressFieldAbilitiesAbAttr extends AbAttr {
2024-03-14 00:40:57 -04:00
constructor ( ) {
super ( false ) ;
}
2024-04-11 09:24:03 -04:00
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-04-18 15:44:03 +10:00
const ability = ( args [ 0 ] as Ability ) ;
if ( ! ability . hasAttr ( UnsuppressableAbilityAbAttr ) && ! ability . hasAttr ( SuppressFieldAbilitiesAbAttr ) ) {
cancelled . value = true ;
return true ;
}
return false ;
2024-03-14 00:40:57 -04:00
}
}
2024-04-21 15:26:30 +10:00
export class AlwaysHitAbAttr extends AbAttr { }
2024-06-15 19:14:49 -07:00
/** Attribute for abilities that allow moves that make contact to ignore protection (i.e. Unseen Fist) */
export class IgnoreProtectOnContactAbAttr extends AbAttr { }
2024-04-13 11:08:32 +10:00
export class UncopiableAbilityAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
}
export class UnsuppressableAbilityAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
}
export class UnswappableAbilityAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
}
export class NoTransformAbilityAbAttr extends AbAttr {
2024-03-04 21:32:11 -05:00
constructor ( ) {
super ( false ) ;
}
}
2024-04-19 04:27:34 +10:00
export class NoFusionAbilityAbAttr extends AbAttr {
constructor ( ) {
super ( false ) ;
}
}
2024-05-06 00:27:56 -05:00
export class IgnoreTypeImmunityAbAttr extends AbAttr {
2024-05-14 14:00:37 -04:00
private defenderType : Type ;
private allowedMoveTypes : Type [ ] ;
2024-05-06 00:27:56 -05:00
constructor ( defenderType : Type , allowedMoveTypes : Type [ ] ) {
super ( true ) ;
this . defenderType = defenderType ;
this . allowedMoveTypes = allowedMoveTypes ;
}
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-05-08 00:32:38 -05:00
if ( this . defenderType === ( args [ 1 ] as Type ) && this . allowedMoveTypes . includes ( args [ 0 ] as Type ) ) {
cancelled . value = true ;
return true ;
2024-05-06 00:27:56 -05:00
}
2024-05-08 00:32:38 -05:00
return false ;
2024-05-06 00:27:56 -05:00
}
}
2024-05-14 14:00:37 -04:00
/ * *
* Ignores the type immunity to Status Effects of the defender if the defender is of a certain type
* /
export class IgnoreTypeStatusEffectImmunityAbAttr extends AbAttr {
private statusEffect : StatusEffect [ ] ;
private defenderType : Type [ ] ;
constructor ( statusEffect : StatusEffect [ ] , defenderType : Type [ ] ) {
super ( true ) ;
this . statusEffect = statusEffect ;
this . defenderType = defenderType ;
}
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
if ( this . statusEffect . includes ( args [ 0 ] as StatusEffect ) && this . defenderType . includes ( args [ 1 ] as Type ) ) {
cancelled . value = true ;
return true ;
}
return false ;
}
}
2024-05-25 15:01:08 +02:00
/ * *
* Gives money to the user after the battle .
*
* @extends PostBattleAbAttr
* @see { @linkcode applyPostBattle }
* /
export class MoneyAbAttr extends PostBattleAbAttr {
constructor ( ) {
super ( ) ;
}
/ * *
* @param pokemon { @linkcode Pokemon } that is the user of this ability .
* @param passive N / A
* @param args N / A
* @returns true
* /
applyPostBattle ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
pokemon . scene . currentBattle . moneyScattered += pokemon . scene . getWaveMoneyAmount ( 0.2 ) ;
return true ;
}
}
2024-05-31 05:42:46 +08:00
/ * *
* Applies a stat change after a Pokémon is summoned ,
* conditioned on the presence of a specific arena tag .
*
* @extends { PostSummonStatChangeAbAttr }
* /
export class PostSummonStatChangeOnArenaAbAttr extends PostSummonStatChangeAbAttr {
/ * *
* The type of arena tag that conditions the stat change .
* @private
* @type { ArenaTagType }
* /
private tagType : ArenaTagType ;
/ * *
* Creates an instance of PostSummonStatChangeOnArenaAbAttr .
* Initializes the stat change to increase Attack by 1 stage if the specified arena tag is present .
*
* @param { ArenaTagType } tagType - The type of arena tag to check for .
* /
constructor ( tagType : ArenaTagType ) {
super ( [ BattleStat . ATK ] , 1 , true , false ) ;
this . tagType = tagType ;
}
/ * *
* Applies the post - summon stat change if the specified arena tag is present on pokemon ' s side .
* This is used in Wind Rider ability .
*
* @param { Pokemon } pokemon - The Pokémon being summoned .
* @param { boolean } passive - Whether the effect is passive .
* @param { any [ ] } args - Additional arguments .
* @returns { boolean } - Returns true if the stat change was applied , otherwise false .
* /
applyPostSummon ( pokemon : Pokemon , passive : boolean , args : any [ ] ) : boolean {
const side = pokemon . isPlayer ( ) ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY ;
if ( pokemon . scene . arena . getTagOnSide ( this . tagType , side ) ) {
return super . applyPostSummon ( pokemon , passive , args ) ;
}
return false ;
}
}
2024-06-06 23:49:50 +08:00
/ * *
2024-06-19 10:56:44 +08:00
* Takes no damage from the first hit of a physical move .
2024-06-06 23:49:50 +08:00
* This is used in Ice Face ability .
* /
2024-06-19 10:56:44 +08:00
export class IceFaceBlockPhysicalAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
private multiplier : number ;
constructor ( condition : PokemonDefendCondition , multiplier : number ) {
super ( condition , multiplier ) ;
this . multiplier = multiplier ;
}
2024-06-06 23:49:50 +08:00
/ * *
* Applies the Ice Face pre - defense ability to the Pokémon .
2024-06-19 10:56:44 +08:00
* Removes BattlerTagType . ICE_FACE when hit by physical attack and is in Ice Face form .
2024-06-06 23:49:50 +08:00
*
* @param { Pokemon } pokemon - The Pokémon with the Ice Face ability .
* @param { boolean } passive - Whether the ability is passive .
* @param { Pokemon } attacker - The attacking Pokémon .
* @param { PokemonMove } move - The move being used .
* @param { Utils . BooleanHolder } cancelled - A holder for whether the move was cancelled .
* @param { any [ ] } args - Additional arguments .
* @returns { boolean } - Whether the immunity was applied .
* /
2024-06-07 17:05:44 -04:00
applyPreDefend ( pokemon : Pokemon , passive : boolean , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
2024-06-19 10:56:44 +08:00
if ( this . condition ( pokemon , attacker , move ) ) {
( args [ 0 ] as Utils . NumberHolder ) . value = this . multiplier ;
pokemon . removeTag ( BattlerTagType . ICE_FACE ) ;
return true ;
2024-06-06 23:49:50 +08:00
}
2024-06-19 10:56:44 +08:00
return false ;
2024-06-06 23:49:50 +08:00
}
/ * *
* Gets the message triggered when the Pokémon avoids damage using the Ice Face ability .
* @param { Pokemon } pokemon - The Pokémon with the Ice Face ability .
* @param { string } abilityName - The name of the ability .
* @param { . . . any } args - Additional arguments .
* @returns { string } - The trigger message .
* /
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return i18next . t ( "abilityTriggers:iceFaceAvoidedDamage" , { pokemonName : pokemon.name , abilityName : abilityName } ) ;
}
}
2024-06-25 00:22:15 +09:00
/ * *
* If a Pokémon with this Ability selects a damaging move , it has a 30 % chance of going first in its priority bracket . If the Ability activates , this is announced at the start of the turn ( after move selection ) .
*
* @extends AbAttr
* /
export class BypassSpeedChanceAbAttr extends AbAttr {
public chance : integer ;
/ * *
* @param { integer } chance probability of ability being active .
* /
constructor ( chance : integer ) {
super ( true ) ;
this . chance = chance ;
}
/ * *
* bypass move order in their priority bracket when pokemon choose damaging move
* @param { Pokemon } pokemon { @linkcode Pokemon } the Pokemon applying this ability
* @param { boolean } passive N / A
* @param { Utils . BooleanHolder } cancelled N / A
* @param { any [ ] } args [ 0 ] { @linkcode Utils . BooleanHolder } set to true when the ability activated
* @returns { boolean } - whether the ability was activated .
* /
apply ( pokemon : Pokemon , passive : boolean , cancelled : Utils.BooleanHolder , args : any [ ] ) : boolean {
const bypassSpeed = args [ 0 ] as Utils . BooleanHolder ;
if ( ! bypassSpeed . value && pokemon . randSeedInt ( 100 ) < this . chance ) {
const turnCommand =
pokemon . scene . currentBattle . turnCommands [ pokemon . getBattlerIndex ( ) ] ;
const isCommandFight = turnCommand ? . command === Command . FIGHT ;
const move = allMoves [ turnCommand . move ? . move ] ;
const isDamageMove = move ? . category === MoveCategory . PHYSICAL || move ? . category === MoveCategory . SPECIAL ;
if ( isCommandFight && isDamageMove ) {
bypassSpeed . value = true ;
return true ;
}
}
return false ;
}
getTriggerMessage ( pokemon : Pokemon , abilityName : string , . . . args : any [ ] ) : string {
return i18next . t ( "abilityTriggers:quickDraw" , { pokemonName : getPokemonNameWithAffix ( pokemon ) } ) ;
}
}
2024-06-19 12:00:26 -04:00
function applyAbAttrsInternal < TAttr extends AbAttr > ( attrType : Constructor < TAttr > ,
2024-04-11 09:24:03 -04:00
pokemon : Pokemon , applyFunc : AbAttrApplyFunc < TAttr > , args : any [ ] , isAsync : boolean = false , showAbilityInstant : boolean = false , quiet : boolean = false , passive : boolean = false ) : Promise < void > {
2023-12-22 21:42:47 -05:00
return new Promise ( resolve = > {
2024-06-13 05:36:12 -04:00
if ( ! pokemon . canApplyAbility ( passive ) ) {
2024-05-23 17:03:10 +02:00
if ( ! passive ) {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal ( attrType , pokemon , applyFunc , args , isAsync , showAbilityInstant , quiet , true ) . then ( ( ) = > resolve ( ) ) ;
2024-05-23 17:03:10 +02:00
} else {
2024-04-11 09:24:03 -04:00
return resolve ( ) ;
2024-05-23 17:03:10 +02:00
}
2024-04-11 09:24:03 -04:00
}
2023-04-27 14:30:03 -04:00
2024-04-11 09:24:03 -04:00
const ability = ( ! passive ? pokemon . getAbility ( ) : pokemon . getPassiveAbility ( ) ) ;
2024-05-31 20:50:30 -04:00
const attrs = ability . getAttrs ( attrType ) ;
2023-04-27 14:30:03 -04:00
2023-12-22 21:42:47 -05:00
const clearSpliceQueueAndResolve = ( ) = > {
2024-06-19 21:51:50 +08:00
pokemon . scene ? . clearPhaseQueueSplice ( ) ;
2024-05-23 17:03:10 +02:00
if ( ! passive ) {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal ( attrType , pokemon , applyFunc , args , isAsync , showAbilityInstant , quiet , true ) . then ( ( ) = > resolve ( ) ) ;
2024-05-23 17:03:10 +02:00
} else {
2024-04-11 09:24:03 -04:00
return resolve ( ) ;
2024-05-23 17:03:10 +02:00
}
2023-12-22 21:42:47 -05:00
} ;
const applyNextAbAttr = ( ) = > {
2024-05-23 17:03:10 +02:00
if ( attrs . length ) {
2023-12-22 21:42:47 -05:00
applyAbAttr ( attrs . shift ( ) ) ;
2024-05-23 17:03:10 +02:00
} else {
2023-12-22 21:42:47 -05:00
clearSpliceQueueAndResolve ( ) ;
2024-05-23 17:03:10 +02:00
}
2023-12-22 21:42:47 -05:00
} ;
2023-12-22 22:04:30 -05:00
const applyAbAttr = ( attr : TAttr ) = > {
2024-05-23 17:03:10 +02:00
if ( ! canApplyAttr ( pokemon , attr ) ) {
2023-12-22 21:42:47 -05:00
return applyNextAbAttr ( ) ;
2024-05-23 17:03:10 +02:00
}
2023-12-22 21:42:47 -05:00
pokemon . scene . setPhaseQueueSplice ( ) ;
const onApplySuccess = ( ) = > {
2024-06-13 10:54:23 -04:00
if ( pokemon . summonData && ! pokemon . summonData . abilitiesApplied . includes ( ability . id ) ) {
pokemon . summonData . abilitiesApplied . push ( ability . id ) ;
}
2024-05-07 14:35:15 +10:00
if ( pokemon . battleData && ! pokemon . battleData . abilitiesApplied . includes ( ability . id ) ) {
pokemon . battleData . abilitiesApplied . push ( ability . id ) ;
}
2024-02-28 11:34:55 -05:00
if ( attr . showAbility && ! quiet ) {
2024-05-23 17:03:10 +02:00
if ( showAbilityInstant ) {
2024-04-11 09:24:03 -04:00
pokemon . scene . abilityBar . showAbility ( pokemon , passive ) ;
2024-05-23 17:03:10 +02:00
} else {
2024-04-11 09:24:03 -04:00
queueShowAbility ( pokemon , passive ) ;
2024-05-23 17:03:10 +02:00
}
2023-12-22 22:04:30 -05:00
}
2024-02-28 11:34:55 -05:00
if ( ! quiet ) {
2024-04-11 09:24:03 -04:00
const message = attr . getTriggerMessage ( pokemon , ( ! passive ? pokemon . getAbility ( ) : pokemon . getPassiveAbility ( ) ) . name , args ) ;
2024-02-28 11:34:55 -05:00
if ( message ) {
2024-05-23 17:03:10 +02:00
if ( isAsync ) {
2024-02-28 11:34:55 -05:00
pokemon . scene . ui . showText ( message , null , ( ) = > pokemon . scene . ui . showText ( null , 0 ) , null , true ) ;
2024-05-23 17:03:10 +02:00
} else {
2024-02-28 11:34:55 -05:00
pokemon . scene . queueMessage ( message ) ;
2024-05-23 17:03:10 +02:00
}
2024-02-28 11:34:55 -05:00
}
2023-12-22 22:04:30 -05:00
}
2023-12-22 21:42:47 -05:00
} ;
2024-04-11 09:24:03 -04:00
const result = applyFunc ( attr , passive ) ;
2023-12-22 21:42:47 -05:00
if ( result instanceof Promise ) {
result . then ( success = > {
2024-05-23 17:03:10 +02:00
if ( success ) {
2023-12-22 21:42:47 -05:00
onApplySuccess ( ) ;
2024-05-23 17:03:10 +02:00
}
2023-12-22 21:42:47 -05:00
applyNextAbAttr ( ) ;
} ) ;
} else {
2024-05-23 17:03:10 +02:00
if ( result ) {
2023-12-22 21:42:47 -05:00
onApplySuccess ( ) ;
2024-05-23 17:03:10 +02:00
}
2023-12-22 21:42:47 -05:00
applyNextAbAttr ( ) ;
}
} ;
applyNextAbAttr ( ) ;
} ) ;
2023-04-27 14:30:03 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyAbAttrs ( attrType : Constructor < AbAttr > , pokemon : Pokemon , cancelled : Utils.BooleanHolder , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < AbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . apply ( pokemon , passive , cancelled , args ) , args ) ;
2023-12-22 22:04:30 -05:00
}
2024-06-19 12:00:26 -04:00
export function applyPostBattleInitAbAttrs ( attrType : Constructor < PostBattleInitAbAttr > ,
2024-03-30 00:53:35 -04:00
pokemon : Pokemon , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostBattleInitAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostBattleInit ( pokemon , passive , args ) , args ) ;
2024-03-30 00:53:35 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPreDefendAbAttrs ( attrType : Constructor < PreDefendAbAttr > ,
2024-06-07 16:57:57 -04:00
pokemon : Pokemon , attacker : Pokemon , move : Move , cancelled : Utils.BooleanHolder , . . . args : any [ ] ) : Promise < void > {
2024-02-28 11:34:55 -05:00
const simulated = args . length > 1 && args [ 1 ] ;
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PreDefendAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPreDefend ( pokemon , passive , attacker , move , cancelled , args ) , args , false , false , simulated ) ;
2023-04-27 14:30:03 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostDefendAbAttrs ( attrType : Constructor < PostDefendAbAttr > ,
2024-06-07 16:57:57 -04:00
pokemon : Pokemon , attacker : Pokemon , move : Move , hitResult : HitResult , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostDefendAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostDefend ( pokemon , passive , attacker , move , hitResult , args ) , args ) ;
2023-12-22 21:42:47 -05:00
}
2023-05-02 00:11:31 -04:00
2024-06-19 12:00:26 -04:00
export function applyPostMoveUsedAbAttrs ( attrType : Constructor < PostMoveUsedAbAttr > ,
2024-05-25 06:00:58 +02:00
pokemon : Pokemon , move : PokemonMove , source : Pokemon , targets : BattlerIndex [ ] , . . . args : any [ ] ) : Promise < void > {
return applyAbAttrsInternal < PostMoveUsedAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostMoveUsed ( pokemon , move , source , targets , args ) , args ) ;
}
2024-06-19 12:00:26 -04:00
export function applyBattleStatMultiplierAbAttrs ( attrType : Constructor < BattleStatMultiplierAbAttr > ,
2023-12-22 21:42:47 -05:00
pokemon : Pokemon , battleStat : BattleStat , statValue : Utils.NumberHolder , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < BattleStatMultiplierAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyBattleStat ( pokemon , passive , battleStat , statValue , args ) , args ) ;
2023-05-02 00:11:31 -04:00
}
2024-06-11 06:37:10 -07:00
/ * *
* Applies a field Battle Stat multiplier attribute
* @param attrType { @linkcode FieldMultiplyBattleStatAbAttr } should always be FieldMultiplyBattleStatAbAttr for the time being
* @param pokemon { @linkcode Pokemon } the Pokemon applying this ability
* @param stat { @linkcode Stat } the type of the checked stat
* @param statValue { @linkcode Utils . NumberHolder } the value of the checked stat
* @param checkedPokemon { @linkcode Pokemon } the Pokemon with the checked stat
* @param hasApplied { @linkcode Utils . BooleanHolder } whether or not a FieldMultiplyBattleStatAbAttr has already affected this stat
* @param args unused
* /
2024-06-19 12:00:26 -04:00
export function applyFieldBattleStatMultiplierAbAttrs ( attrType : Constructor < FieldMultiplyBattleStatAbAttr > ,
2024-06-11 06:37:10 -07:00
pokemon : Pokemon , stat : Stat , statValue : Utils.NumberHolder , checkedPokemon : Pokemon , hasApplied : Utils.BooleanHolder , . . . args : any [ ] ) : Promise < void > {
return applyAbAttrsInternal < FieldMultiplyBattleStatAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyFieldBattleStat ( pokemon , passive , stat , statValue , checkedPokemon , hasApplied , args ) , args ) ;
}
2024-06-19 12:00:26 -04:00
export function applyPreAttackAbAttrs ( attrType : Constructor < PreAttackAbAttr > ,
2024-06-07 16:57:57 -04:00
pokemon : Pokemon , defender : Pokemon , move : Move , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PreAttackAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPreAttack ( pokemon , passive , defender , move , args ) , args ) ;
2023-04-27 14:30:03 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostAttackAbAttrs ( attrType : Constructor < PostAttackAbAttr > ,
2024-06-07 16:57:57 -04:00
pokemon : Pokemon , defender : Pokemon , move : Move , hitResult : HitResult , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostAttackAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostAttack ( pokemon , passive , defender , move , hitResult , args ) , args ) ;
2023-12-22 01:16:56 -05:00
}
2024-06-19 12:00:26 -04:00
export function applyPostKnockOutAbAttrs ( attrType : Constructor < PostKnockOutAbAttr > ,
2024-04-14 13:21:34 +10:00
pokemon : Pokemon , knockedOut : Pokemon , . . . args : any [ ] ) : Promise < void > {
return applyAbAttrsInternal < PostKnockOutAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostKnockOut ( pokemon , passive , knockedOut , args ) , args ) ;
2024-05-24 01:45:04 +02:00
}
2024-04-08 00:20:24 +03:00
2024-06-19 12:00:26 -04:00
export function applyPostVictoryAbAttrs ( attrType : Constructor < PostVictoryAbAttr > ,
2024-03-29 22:08:27 -04:00
pokemon : Pokemon , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostVictoryAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostVictory ( pokemon , passive , args ) , args ) ;
2024-03-29 22:08:27 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostSummonAbAttrs ( attrType : Constructor < PostSummonAbAttr > ,
2023-12-22 21:42:47 -05:00
pokemon : Pokemon , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostSummonAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostSummon ( pokemon , passive , args ) , args ) ;
2023-05-04 12:57:55 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPreSwitchOutAbAttrs ( attrType : Constructor < PreSwitchOutAbAttr > ,
2024-01-16 00:28:03 -05:00
pokemon : Pokemon , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PreSwitchOutAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPreSwitchOut ( pokemon , passive , args ) , args , false , true ) ;
2024-01-16 00:28:03 -05:00
}
2024-06-19 12:00:26 -04:00
export function applyPreStatChangeAbAttrs ( attrType : Constructor < PreStatChangeAbAttr > ,
2023-12-22 21:42:47 -05:00
pokemon : Pokemon , stat : BattleStat , cancelled : Utils.BooleanHolder , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PreStatChangeAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPreStatChange ( pokemon , passive , stat , cancelled , args ) , args ) ;
2023-04-26 23:33:13 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostStatChangeAbAttrs ( attrType : Constructor < PostStatChangeAbAttr > ,
2024-04-14 14:20:00 -04:00
pokemon : Pokemon , stats : BattleStat [ ] , levels : integer , selfTarget : boolean , . . . args : any [ ] ) : Promise < void > {
return applyAbAttrsInternal < PostStatChangeAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostStatChange ( pokemon , stats , levels , selfTarget , args ) , args ) ;
}
2024-06-19 12:00:26 -04:00
export function applyPreSetStatusAbAttrs ( attrType : Constructor < PreSetStatusAbAttr > ,
2023-12-22 21:42:47 -05:00
pokemon : Pokemon , effect : StatusEffect , cancelled : Utils.BooleanHolder , . . . args : any [ ] ) : Promise < void > {
2024-03-09 21:57:33 -05:00
const simulated = args . length > 1 && args [ 1 ] ;
2024-05-15 09:12:03 -04:00
return applyAbAttrsInternal < PreSetStatusAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPreSetStatus ( pokemon , passive , effect , cancelled , args ) , args , false , false , ! simulated ) ;
2023-05-04 12:57:55 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPreApplyBattlerTagAbAttrs ( attrType : Constructor < PreApplyBattlerTagAbAttr > ,
2023-12-22 21:42:47 -05:00
pokemon : Pokemon , tag : BattlerTag , cancelled : Utils.BooleanHolder , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PreApplyBattlerTagAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPreApplyBattlerTag ( pokemon , passive , tag , cancelled , args ) , args ) ;
2023-05-04 12:57:55 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPreWeatherEffectAbAttrs ( attrType : Constructor < PreWeatherEffectAbAttr > ,
2023-12-22 21:42:47 -05:00
pokemon : Pokemon , weather : Weather , cancelled : Utils.BooleanHolder , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PreWeatherDamageAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPreWeatherEffect ( pokemon , passive , weather , cancelled , args ) , args , false , true ) ;
2023-04-27 14:30:03 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostTurnAbAttrs ( attrType : Constructor < PostTurnAbAttr > ,
2023-12-22 21:42:47 -05:00
pokemon : Pokemon , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostTurnAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostTurn ( pokemon , passive , args ) , args ) ;
2023-05-02 15:56:41 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostWeatherChangeAbAttrs ( attrType : Constructor < PostWeatherChangeAbAttr > ,
2024-03-18 21:22:27 -04:00
pokemon : Pokemon , weather : WeatherType , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostWeatherChangeAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostWeatherChange ( pokemon , passive , weather , args ) , args ) ;
2024-03-18 21:22:27 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostWeatherLapseAbAttrs ( attrType : Constructor < PostWeatherLapseAbAttr > ,
2023-12-22 21:42:47 -05:00
pokemon : Pokemon , weather : Weather , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostWeatherLapseAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostWeatherLapse ( pokemon , passive , weather , args ) , args ) ;
2023-04-27 14:30:03 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostTerrainChangeAbAttrs ( attrType : Constructor < PostTerrainChangeAbAttr > ,
2024-03-18 21:22:27 -04:00
pokemon : Pokemon , terrain : TerrainType , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostTerrainChangeAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostTerrainChange ( pokemon , passive , terrain , args ) , args ) ;
2024-03-18 21:22:27 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyCheckTrappedAbAttrs ( attrType : Constructor < CheckTrappedAbAttr > ,
2024-05-19 13:05:46 -04:00
pokemon : Pokemon , trapped : Utils.BooleanHolder , otherPokemon : Pokemon , . . . args : any [ ] ) : Promise < void > {
return applyAbAttrsInternal < CheckTrappedAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyCheckTrapped ( pokemon , passive , trapped , otherPokemon , args ) , args , true ) ;
2023-05-04 12:57:55 -04:00
}
2024-06-19 12:00:26 -04:00
export function applyPostBattleAbAttrs ( attrType : Constructor < PostBattleAbAttr > ,
2024-03-06 21:05:23 -05:00
pokemon : Pokemon , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostBattleAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostBattle ( pokemon , passive , args ) , args ) ;
2024-03-06 21:05:23 -05:00
}
2024-06-19 12:00:26 -04:00
export function applyPostFaintAbAttrs ( attrType : Constructor < PostFaintAbAttr > ,
2024-06-07 16:57:57 -04:00
pokemon : Pokemon , attacker : Pokemon , move : Move , hitResult : HitResult , . . . args : any [ ] ) : Promise < void > {
2024-04-11 09:24:03 -04:00
return applyAbAttrsInternal < PostFaintAbAttr > ( attrType , pokemon , ( attr , passive ) = > attr . applyPostFaint ( pokemon , passive , attacker , move , hitResult , args ) , args ) ;
2024-04-09 18:05:15 -04:00
}
2023-04-27 14:30:03 -04:00
function canApplyAttr ( pokemon : Pokemon , attr : AbAttr ) : boolean {
const condition = attr . getCondition ( ) ;
return ! condition || condition ( pokemon ) ;
}
2024-04-11 09:24:03 -04:00
function queueShowAbility ( pokemon : Pokemon , passive : boolean ) : void {
pokemon . scene . unshiftPhase ( new ShowAbilityPhase ( pokemon . scene , pokemon . id , passive ) ) ;
2023-04-27 14:30:03 -04:00
pokemon . scene . clearPhaseQueueSplice ( ) ;
2023-04-26 23:33:13 -04:00
}
2024-06-16 00:13:59 +08:00
/ * *
* Sets the ability of a Pokémon as revealed .
*
* @param pokemon - The Pokémon whose ability is being revealed .
* /
function setAbilityRevealed ( pokemon : Pokemon ) : void {
if ( pokemon . battleData ) {
pokemon . battleData . abilityRevealed = true ;
}
}
2024-04-25 03:10:09 +02:00
export const allAbilities = [ new Ability ( Abilities . NONE , 3 ) ] ;
2023-04-27 14:30:03 -04:00
export function initAbilities() {
2023-12-05 17:12:39 -05:00
allAbilities . push (
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STENCH , 3 )
2024-06-07 16:57:57 -04:00
. attr ( PostAttackApplyBattlerTagAbAttr , false , ( user , target , move ) = > ( move . category !== MoveCategory . STATUS && ! move . hasAttr ( FlinchAttr ) ) ? 10 : 0 , BattlerTagType . FLINCHED ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DRIZZLE , 3 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonWeatherChangeAbAttr , WeatherType . RAIN )
. attr ( PostBiomeChangeWeatherChangeAbAttr , WeatherType . RAIN ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SPEED_BOOST , 3 )
2023-12-22 01:16:56 -05:00
. attr ( PostTurnStatChangeAbAttr , BattleStat . SPD , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BATTLE_ARMOR , 3 )
2024-03-14 00:40:57 -04:00
. attr ( BlockCritAbAttr )
. ignorable ( ) ,
2024-05-24 01:45:04 +02:00
new Ability ( Abilities . STURDY , 3 )
2024-04-02 01:03:29 -04:00
. attr ( PreDefendFullHpEndureAbAttr )
2024-03-14 00:40:57 -04:00
. attr ( BlockOneHitKOAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DAMP , 3 )
2024-04-25 21:42:41 -04:00
. attr ( FieldPreventExplosiveMovesAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LIMBER , 3 )
2024-03-14 00:40:57 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . PARALYSIS )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SAND_VEIL , 3 )
2023-12-05 17:12:39 -05:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . EVA , 1.2 )
. attr ( BlockWeatherDamageAttr , WeatherType . SANDSTORM )
2024-03-14 00:40:57 -04:00
. condition ( getWeatherCondition ( WeatherType . SANDSTORM ) )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STATIC , 3 )
2024-05-05 17:26:28 +03:00
. attr ( PostDefendContactApplyStatusEffectAbAttr , 30 , StatusEffect . PARALYSIS )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . VOLT_ABSORB , 3 )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityHealAbAttr , Type . ELECTRIC )
2024-05-28 13:19:03 -04:00
. partial ( ) // Healing not blocked by Heal Block
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WATER_ABSORB , 3 )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityHealAbAttr , Type . WATER )
2024-05-28 13:19:03 -04:00
. partial ( ) // Healing not blocked by Heal Block
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . OBLIVIOUS , 3 )
2024-03-14 00:40:57 -04:00
. attr ( BattlerTagImmunityAbAttr , BattlerTagType . INFATUATED )
2024-05-05 07:52:27 -07:00
. attr ( IntimidateImmunityAbAttr )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . CLOUD_NINE , 3 )
2024-04-19 13:03:19 -04:00
. attr ( SuppressWeatherEffectAbAttr , true ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . COMPOUND_EYES , 3 )
2023-05-02 15:56:41 -04:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . ACC , 1.3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . INSOMNIA , 3 )
2023-05-04 12:57:55 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . SLEEP )
2024-03-14 00:40:57 -04:00
. attr ( BattlerTagImmunityAbAttr , BattlerTagType . DROWSY )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . COLOR_CHANGE , 3 )
2024-06-17 18:30:42 -06:00
. attr ( PostDefendTypeChangeAbAttr )
. condition ( getSheerForceHitDisableAbCondition ( ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . IMMUNITY , 3 )
2024-04-08 13:21:06 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . POISON , StatusEffect . TOXIC )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FLASH_FIRE , 3 )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityAddBattlerTagAbAttr , Type . FIRE , BattlerTagType . FIRE_BOOST , 1 , ( pokemon : Pokemon ) = > ! pokemon . status || pokemon . status . effect !== StatusEffect . FREEZE )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SHIELD_DUST , 3 )
2024-06-17 18:30:42 -06:00
. attr ( IgnoreMoveEffectsAbAttr )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . OWN_TEMPO , 3 )
2024-04-13 11:08:32 +10:00
. attr ( BattlerTagImmunityAbAttr , BattlerTagType . CONFUSED )
2024-05-05 07:52:27 -07:00
. attr ( IntimidateImmunityAbAttr )
2024-04-13 11:08:32 +10:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SUCTION_CUPS , 3 )
2024-05-24 01:45:04 +02:00
. attr ( ForceSwitchOutImmunityAbAttr )
2024-05-05 07:52:27 -07:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . INTIMIDATE , 3 )
2024-05-05 07:52:27 -07:00
. attr ( PostSummonStatChangeAbAttr , BattleStat . ATK , - 1 , false , true ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SHADOW_TAG , 3 )
2024-05-29 14:47:16 -04:00
. attr ( ArenaTrapAbAttr , ( user , target ) = > {
if ( target . hasAbility ( Abilities . SHADOW_TAG ) ) {
return false ;
}
return true ;
} ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ROUGH_SKIN , 3 )
2024-04-06 21:04:40 -04:00
. attr ( PostDefendContactDamageAbAttr , 8 )
2024-04-11 09:24:03 -04:00
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WONDER_GUARD , 3 )
2024-03-04 21:32:11 -05:00
. attr ( NonSuperEffectiveImmunityAbAttr )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LEVITATE , 3 )
2024-06-23 09:48:49 -07:00
. attr ( TypeImmunityAbAttr , Type . GROUND , ( pokemon : Pokemon ) = > ! pokemon . getTag ( GroundedTag ) && ! pokemon . scene . arena . getTag ( ArenaTagType . GRAVITY ) )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . EFFECT_SPORE , 3 )
2024-05-01 17:47:32 -04:00
. attr ( EffectSporeAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SYNCHRONIZE , 3 )
. attr ( SyncEncounterNatureAbAttr )
. unimplemented ( ) ,
new Ability ( Abilities . CLEAR_BODY , 3 )
2024-03-14 00:40:57 -04:00
. attr ( ProtectStatAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . NATURAL_CURE , 3 )
2024-01-16 00:28:03 -05:00
. attr ( PreSwitchOutResetStatusAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LIGHTNING_ROD , 3 )
2024-03-11 20:55:41 -04:00
. attr ( RedirectTypeMoveAbAttr , Type . ELECTRIC )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityStatChangeAbAttr , Type . ELECTRIC , BattleStat . SPATK , 1 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SERENE_GRACE , 3 )
2024-06-17 18:30:42 -06:00
. attr ( MoveEffectChanceMultiplierAbAttr , 2 )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SWIFT_SWIM , 3 )
2023-12-05 17:12:39 -05:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . SPD , 2 )
. condition ( getWeatherCondition ( WeatherType . RAIN , WeatherType . HEAVY_RAIN ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . CHLOROPHYLL , 3 )
2023-12-05 17:12:39 -05:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . SPD , 2 )
. condition ( getWeatherCondition ( WeatherType . SUNNY , WeatherType . HARSH_SUN ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ILLUMINATE , 3 )
2024-03-14 00:40:57 -04:00
. attr ( ProtectStatAbAttr , BattleStat . ACC )
. attr ( DoubleBattleChanceAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TRACE , 3 )
2024-06-22 11:35:25 -04:00
. attr ( PostSummonCopyAbilityAbAttr )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HUGE_POWER , 3 )
2024-03-14 14:09:25 -05:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . ATK , 2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . POISON_POINT , 3 )
2024-05-05 17:26:28 +03:00
. attr ( PostDefendContactApplyStatusEffectAbAttr , 30 , StatusEffect . POISON )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . INNER_FOCUS , 3 )
2024-03-14 00:40:57 -04:00
. attr ( BattlerTagImmunityAbAttr , BattlerTagType . FLINCHED )
2024-05-05 07:52:27 -07:00
. attr ( IntimidateImmunityAbAttr )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MAGMA_ARMOR , 3 )
2024-03-14 00:40:57 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . FREEZE )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WATER_VEIL , 3 )
2024-03-14 00:40:57 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . BURN )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MAGNET_PULL , 3 )
2024-05-29 14:47:16 -04:00
. attr ( ArenaTrapAbAttr , ( user , target ) = > {
if ( target . getTypes ( true ) . includes ( Type . STEEL ) || ( target . getTypes ( true ) . includes ( Type . STELLAR ) && target . getTypes ( ) . includes ( Type . STEEL ) ) ) {
return true ;
}
return false ;
} ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SOUNDPROOF , 3 )
2024-06-07 16:57:57 -04:00
. attr ( MoveImmunityAbAttr , ( pokemon , attacker , move ) = > pokemon !== attacker && move . hasFlag ( MoveFlags . SOUND_BASED ) )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . RAIN_DISH , 3 )
2024-05-28 13:19:03 -04:00
. attr ( PostWeatherLapseHealAbAttr , 1 , WeatherType . RAIN , WeatherType . HEAVY_RAIN )
. partial ( ) , // Healing not blocked by Heal Block
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SAND_STREAM , 3 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonWeatherChangeAbAttr , WeatherType . SANDSTORM )
. attr ( PostBiomeChangeWeatherChangeAbAttr , WeatherType . SANDSTORM ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PRESSURE , 3 )
2024-04-20 23:09:59 -04:00
. attr ( IncreasePpAbAttr )
2024-05-23 17:03:10 +02:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " is exerting its Pressure!" ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . THICK_FAT , 3 )
2023-05-06 12:13:35 -04:00
. attr ( ReceivedTypeDamageMultiplierAbAttr , Type . FIRE , 0.5 )
2024-03-14 00:40:57 -04:00
. attr ( ReceivedTypeDamageMultiplierAbAttr , Type . ICE , 0.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . EARLY_BIRD , 3 )
2024-01-16 00:28:03 -05:00
. attr ( ReduceStatusEffectDurationAbAttr , StatusEffect . SLEEP ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FLAME_BODY , 3 )
2024-05-05 17:26:28 +03:00
. attr ( PostDefendContactApplyStatusEffectAbAttr , 30 , StatusEffect . BURN )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . RUN_AWAY , 3 )
2023-12-22 18:08:37 -04:00
. attr ( RunSuccessAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . KEEN_EYE , 3 )
2024-03-14 00:40:57 -04:00
. attr ( ProtectStatAbAttr , BattleStat . ACC )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HYPER_CUTTER , 3 )
2024-03-14 00:40:57 -04:00
. attr ( ProtectStatAbAttr , BattleStat . ATK )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PICKUP , 3 )
2024-03-06 21:05:23 -05:00
. attr ( PostBattleLootAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TRUANT , 3 )
2023-12-22 22:46:05 -05:00
. attr ( PostSummonAddBattlerTagAbAttr , BattlerTagType . TRUANT , 1 , false ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HUSTLE , 3 )
2024-05-23 17:03:10 +02:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . ATK , 1.5 , ( user , target , move ) = > move . category === MoveCategory . PHYSICAL )
. attr ( BattleStatMultiplierAbAttr , BattleStat . ACC , 0.8 , ( user , target , move ) = > move . category === MoveCategory . PHYSICAL ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . CUTE_CHARM , 3 )
2023-12-05 17:12:39 -05:00
. attr ( PostDefendContactApplyTagChanceAbAttr , 30 , BattlerTagType . INFATUATED ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PLUS , 3 )
2024-05-26 11:03:27 +02:00
. conditionalAttr ( p = > p . scene . currentBattle . double && [ Abilities . PLUS , Abilities . MINUS ] . some ( a = > p . getAlly ( ) . hasAbility ( a ) ) , BattleStatMultiplierAbAttr , BattleStat . SPATK , 1.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MINUS , 3 )
2024-05-26 11:03:27 +02:00
. conditionalAttr ( p = > p . scene . currentBattle . double && [ Abilities . PLUS , Abilities . MINUS ] . some ( a = > p . getAlly ( ) . hasAbility ( a ) ) , BattleStatMultiplierAbAttr , BattleStat . SPATK , 1.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FORECAST , 3 )
2024-04-19 04:27:34 +10:00
. attr ( UncopiableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( NoFusionAbilityAbAttr )
. unimplemented ( ) ,
new Ability ( Abilities . STICKY_HOLD , 3 )
2023-12-22 23:57:05 -05:00
. attr ( BlockItemTheftAbAttr )
2024-04-11 09:24:03 -04:00
. bypassFaint ( )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SHED_SKIN , 3 )
2024-04-12 19:02:24 -05:00
. conditionalAttr ( pokemon = > ! Utils . randSeedInt ( 3 ) , PostTurnResetStatusAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GUTS , 3 )
2024-03-14 00:40:57 -04:00
. attr ( BypassBurnDamageReductionAbAttr )
2024-05-31 23:50:03 +02:00
. conditionalAttr ( pokemon = > ! ! pokemon . status || pokemon . hasAbility ( Abilities . COMATOSE ) , BattleStatMultiplierAbAttr , BattleStat . ATK , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MARVEL_SCALE , 3 )
2024-05-31 23:50:03 +02:00
. conditionalAttr ( pokemon = > ! ! pokemon . status || pokemon . hasAbility ( Abilities . COMATOSE ) , BattleStatMultiplierAbAttr , BattleStat . DEF , 1.5 )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LIQUID_OOZE , 3 )
2024-04-22 04:02:10 +01:00
. attr ( ReverseDrainAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . OVERGROW , 3 )
2023-12-05 17:12:39 -05:00
. attr ( LowHpMoveTypePowerBoostAbAttr , Type . GRASS ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BLAZE , 3 )
2023-12-05 17:12:39 -05:00
. attr ( LowHpMoveTypePowerBoostAbAttr , Type . FIRE ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TORRENT , 3 )
2023-12-05 17:12:39 -05:00
. attr ( LowHpMoveTypePowerBoostAbAttr , Type . WATER ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SWARM , 3 )
2023-12-05 17:12:39 -05:00
. attr ( LowHpMoveTypePowerBoostAbAttr , Type . BUG ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ROCK_HEAD , 3 )
2023-12-05 17:12:39 -05:00
. attr ( BlockRecoilDamageAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DROUGHT , 3 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonWeatherChangeAbAttr , WeatherType . SUNNY )
. attr ( PostBiomeChangeWeatherChangeAbAttr , WeatherType . SUNNY ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ARENA_TRAP , 3 )
2024-05-29 14:47:16 -04:00
. attr ( ArenaTrapAbAttr , ( user , target ) = > {
if ( target . isGrounded ( ) ) {
return true ;
}
return false ;
} )
2024-04-26 12:58:57 -05:00
. attr ( DoubleBattleChanceAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . VITAL_SPIRIT , 3 )
2023-05-04 12:57:55 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . SLEEP )
2024-03-14 00:40:57 -04:00
. attr ( BattlerTagImmunityAbAttr , BattlerTagType . DROWSY )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WHITE_SMOKE , 3 )
2024-03-14 00:40:57 -04:00
. attr ( ProtectStatAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PURE_POWER , 3 )
2024-03-14 14:09:25 -05:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . ATK , 2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SHELL_ARMOR , 3 )
2024-03-14 00:40:57 -04:00
. attr ( BlockCritAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . AIR_LOCK , 3 )
2024-05-13 22:09:46 -03:00
. attr ( SuppressWeatherEffectAbAttr , true )
. attr ( PostSummonUnnamedMessageAbAttr , "The effects of the weather disappeared." ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TANGLED_FEET , 4 )
2024-03-14 00:40:57 -04:00
. conditionalAttr ( pokemon = > ! ! pokemon . getTag ( BattlerTagType . CONFUSED ) , BattleStatMultiplierAbAttr , BattleStat . EVA , 2 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MOTOR_DRIVE , 4 )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityStatChangeAbAttr , Type . ELECTRIC , BattleStat . SPD , 1 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . RIVALRY , 4 )
2024-05-01 18:17:12 -04:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > user . gender !== Gender . GENDERLESS && target . gender !== Gender . GENDERLESS && user . gender === target . gender , 1.25 , true )
2024-04-14 13:15:01 -04:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > user . gender !== Gender . GENDERLESS && target . gender !== Gender . GENDERLESS && user . gender !== target . gender , 0.75 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STEADFAST , 4 )
2024-01-16 00:28:03 -05:00
. attr ( FlinchStatChangeAbAttr , BattleStat . SPD , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SNOW_CLOAK , 4 )
2023-12-05 17:12:39 -05:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . EVA , 1.2 )
2024-03-14 00:40:57 -04:00
. attr ( BlockWeatherDamageAttr , WeatherType . HAIL )
2024-04-15 22:47:39 +02:00
. condition ( getWeatherCondition ( WeatherType . HAIL , WeatherType . SNOW ) )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GLUTTONY , 4 )
2024-01-16 00:28:03 -05:00
. attr ( ReduceBerryUseThresholdAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ANGER_POINT , 4 )
2023-10-26 21:12:53 -07:00
. attr ( PostDefendCritStatChangeAbAttr , BattleStat . ATK , 6 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . UNBURDEN , 4 )
. unimplemented ( ) ,
new Ability ( Abilities . HEATPROOF , 4 )
2024-03-14 00:40:57 -04:00
. attr ( ReceivedTypeDamageMultiplierAbAttr , Type . FIRE , 0.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SIMPLE , 4 )
2024-03-14 00:40:57 -04:00
. attr ( StatChangeMultiplierAbAttr , 2 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DRY_SKIN , 4 )
2023-05-02 15:56:41 -04:00
. attr ( PostWeatherLapseDamageAbAttr , 2 , WeatherType . SUNNY , WeatherType . HARSH_SUN )
. attr ( PostWeatherLapseHealAbAttr , 2 , WeatherType . RAIN , WeatherType . HEAVY_RAIN )
2023-05-06 12:13:35 -04:00
. attr ( ReceivedTypeDamageMultiplierAbAttr , Type . FIRE , 1.25 )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityHealAbAttr , Type . WATER )
2024-05-28 13:19:03 -04:00
. partial ( ) // Healing not blocked by Heal Block
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DOWNLOAD , 4 )
2024-04-12 16:08:04 -04:00
. attr ( DownloadAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . IRON_FIST , 4 )
2023-12-23 01:21:01 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . hasFlag ( MoveFlags . PUNCHING_MOVE ) , 1.2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . POISON_HEAL , 4 )
2024-05-30 18:58:40 -04:00
. attr ( PostTurnStatusHealAbAttr , StatusEffect . TOXIC , StatusEffect . POISON )
. attr ( BlockStatusDamageAbAttr , StatusEffect . TOXIC , StatusEffect . POISON ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ADAPTABILITY , 4 )
2023-12-05 17:12:39 -05:00
. attr ( StabBoostAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SKILL_LINK , 4 )
2023-12-22 18:08:37 -04:00
. attr ( MaxMultiHitAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HYDRATION , 4 )
2024-04-11 05:16:09 +01:00
. attr ( PostTurnResetStatusAbAttr )
. condition ( getWeatherCondition ( WeatherType . RAIN , WeatherType . HEAVY_RAIN ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SOLAR_POWER , 4 )
2023-11-28 22:20:10 +09:00
. attr ( PostWeatherLapseDamageAbAttr , 2 , WeatherType . SUNNY , WeatherType . HARSH_SUN )
. attr ( BattleStatMultiplierAbAttr , BattleStat . SPATK , 1.5 )
. condition ( getWeatherCondition ( WeatherType . SUNNY , WeatherType . HARSH_SUN ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . QUICK_FEET , 4 )
2024-04-17 22:09:28 -06:00
. conditionalAttr ( pokemon = > pokemon . status ? pokemon . status . effect === StatusEffect.PARALYSIS : false , BattleStatMultiplierAbAttr , BattleStat . SPD , 2 )
2024-05-31 23:50:03 +02:00
. conditionalAttr ( pokemon = > ! ! pokemon . status || pokemon . hasAbility ( Abilities . COMATOSE ) , BattleStatMultiplierAbAttr , BattleStat . SPD , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . NORMALIZE , 4 )
2024-06-13 10:54:23 -04:00
. attr ( MoveTypeChangeAttr , Type . NORMAL , 1.2 , ( user , target , move ) = > {
return ! [ Moves . HIDDEN_POWER , Moves . WEATHER_BALL , Moves . NATURAL_GIFT , Moves . JUDGMENT , Moves . TECHNO_BLAST ] . includes ( move . id ) ;
} ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SNIPER , 4 )
2024-05-04 01:56:13 +10:00
. attr ( MultCritAbAttr , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MAGIC_GUARD , 4 )
2024-04-02 15:14:07 -04:00
. attr ( BlockNonDirectDamageAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . NO_GUARD , 4 )
2024-04-21 15:26:30 +10:00
. attr ( AlwaysHitAbAttr )
. attr ( DoubleBattleChanceAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STALL , 4 )
. unimplemented ( ) ,
new Ability ( Abilities . TECHNICIAN , 4 )
2024-05-12 02:06:09 -07:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > {
const power = new Utils . NumberHolder ( move . power ) ;
applyMoveAttrs ( VariablePowerAttr , user , target , move , power ) ;
2024-05-23 17:03:10 +02:00
return power . value <= 60 ;
2024-05-12 02:06:09 -07:00
} , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LEAF_GUARD , 4 )
2023-12-05 17:12:39 -05:00
. attr ( StatusEffectImmunityAbAttr )
2024-03-14 00:40:57 -04:00
. condition ( getWeatherCondition ( WeatherType . SUNNY , WeatherType . HARSH_SUN ) )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . KLUTZ , 4 )
. unimplemented ( ) ,
new Ability ( Abilities . MOLD_BREAKER , 4 )
2024-05-23 17:03:10 +02:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " breaks the mold!" ) )
2024-03-14 00:40:57 -04:00
. attr ( MoveAbilityBypassAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SUPER_LUCK , 4 )
. attr ( BonusCritAbAttr )
. partial ( ) ,
new Ability ( Abilities . AFTERMATH , 4 )
2024-04-09 18:05:15 -04:00
. attr ( PostFaintContactDamageAbAttr , 4 )
2024-04-11 09:24:03 -04:00
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ANTICIPATION , 4 )
2024-05-23 17:03:10 +02:00
. conditionalAttr ( getAnticipationCondition ( ) , PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " shuddered!" ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FOREWARN , 4 )
2024-05-03 22:10:40 -04:00
. attr ( ForewarnAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . UNAWARE , 4 )
2024-03-14 00:40:57 -04:00
. attr ( IgnoreOpponentStatChangesAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TINTED_LENS , 4 )
2024-05-13 11:05:09 -07:00
. attr ( DamageBoostAbAttr , 2 , ( user , target , move ) = > target . getAttackTypeEffectiveness ( move . type , user ) <= 0.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FILTER , 4 )
2024-05-06 00:27:56 -05:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > target . getAttackTypeEffectiveness ( move . type , user ) >= 2 , 0.75 )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SLOW_START , 4 )
2023-12-22 22:46:05 -05:00
. attr ( PostSummonAddBattlerTagAbAttr , BattlerTagType . SLOW_START , 5 ) ,
2024-05-06 00:27:56 -05:00
new Ability ( Abilities . SCRAPPY , 4 )
. attr ( IgnoreTypeImmunityAbAttr , Type . GHOST , [ Type . NORMAL , Type . FIGHTING ] )
. attr ( IntimidateImmunityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STORM_DRAIN , 4 )
2024-03-11 20:55:41 -04:00
. attr ( RedirectTypeMoveAbAttr , Type . WATER )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityStatChangeAbAttr , Type . WATER , BattleStat . SPATK , 1 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ICE_BODY , 4 )
2024-04-15 22:47:39 +02:00
. attr ( BlockWeatherDamageAttr , WeatherType . HAIL )
2024-05-28 13:19:03 -04:00
. attr ( PostWeatherLapseHealAbAttr , 1 , WeatherType . HAIL , WeatherType . SNOW )
. partial ( ) , // Healing not blocked by Heal Block
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SOLID_ROCK , 4 )
2024-05-06 00:27:56 -05:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > target . getAttackTypeEffectiveness ( move . type , user ) >= 2 , 0.75 )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SNOW_WARNING , 4 )
2024-04-15 22:47:39 +02:00
. attr ( PostSummonWeatherChangeAbAttr , WeatherType . SNOW )
. attr ( PostBiomeChangeWeatherChangeAbAttr , WeatherType . SNOW ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HONEY_GATHER , 4 )
2024-05-25 15:01:08 +02:00
. attr ( MoneyAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FRISK , 4 )
2024-05-03 22:10:40 -04:00
. attr ( FriskAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . RECKLESS , 4 )
2024-05-07 23:28:35 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . hasFlag ( MoveFlags . RECKLESS_MOVE ) , 1.2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MULTITYPE , 4 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( UnsuppressableAbilityAbAttr )
2024-06-10 08:58:34 -05:00
. attr ( NoFusionAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FLOWER_GIFT , 4 )
2024-03-30 18:55:37 -05:00
. conditionalAttr ( getWeatherCondition ( WeatherType . SUNNY || WeatherType . HARSH_SUN ) , BattleStatMultiplierAbAttr , BattleStat . ATK , 1.5 )
. conditionalAttr ( getWeatherCondition ( WeatherType . SUNNY || WeatherType . HARSH_SUN ) , BattleStatMultiplierAbAttr , BattleStat . SPDEF , 1.5 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( NoFusionAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. ignorable ( )
. partial ( ) ,
new Ability ( Abilities . BAD_DREAMS , 4 )
2024-05-21 09:26:01 +02:00
. attr ( PostTurnHurtIfSleepingAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PICKPOCKET , 5 )
2024-06-17 18:30:42 -06:00
. attr ( PostDefendStealHeldItemAbAttr , ( target , user , move ) = > move . hasFlag ( MoveFlags . MAKES_CONTACT ) )
. condition ( getSheerForceHitDisableAbCondition ( ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SHEER_FORCE , 5 )
2024-06-17 18:30:42 -06:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . chance >= 1 , 5461 / 4096 )
. attr ( MoveEffectChanceMultiplierAbAttr , 0 )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . CONTRARY , 5 )
2024-03-14 00:40:57 -04:00
. attr ( StatChangeMultiplierAbAttr , - 1 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . UNNERVE , 5 )
2023-12-23 01:21:01 -05:00
. attr ( PreventBerryUseAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DEFIANT , 5 )
2024-04-14 14:20:00 -04:00
. attr ( PostStatChangeStatChangeAbAttr , ( target , statsChanged , levels ) = > levels < 0 , [ BattleStat . ATK ] , 2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DEFEATIST , 5 )
2024-03-13 13:54:15 +01:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . ATK , 0.5 )
. attr ( BattleStatMultiplierAbAttr , BattleStat . SPATK , 0.5 )
. condition ( ( pokemon ) = > pokemon . getHpRatio ( ) <= 0.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . CURSED_BODY , 5 )
2024-05-08 20:25:16 -04:00
. attr ( PostDefendMoveDisableAbAttr , 30 )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HEALER , 5 )
2024-05-08 21:21:55 -04:00
. conditionalAttr ( pokemon = > pokemon . getAlly ( ) && Utils . randSeedInt ( 10 ) < 3 , PostTurnResetStatusAbAttr , true ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FRIEND_GUARD , 5 )
. ignorable ( )
. unimplemented ( ) ,
new Ability ( Abilities . WEAK_ARMOR , 5 )
2024-04-05 00:24:43 +02:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . category === MoveCategory . PHYSICAL , BattleStat . DEF , - 1 )
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . category === MoveCategory . PHYSICAL , BattleStat . SPD , 2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HEAVY_METAL , 5 )
2024-03-14 00:40:57 -04:00
. attr ( WeightMultiplierAbAttr , 2 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LIGHT_METAL , 5 )
2024-03-14 00:40:57 -04:00
. attr ( WeightMultiplierAbAttr , 0.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MULTISCALE , 5 )
Implement Multiscale, Solid Rock, Filter, Justified, Water Compaction, Soul-Heart, Shadow Shield, Prism Armor (#46)
* Implement Multiscale, Solid Rock, Filter, Justified, Water Compaction, Soul-Heart, Shadow Shield, Prism Armor
fix
fix
* Update src/data/ability.ts
---------
Co-authored-by: Samuel H <flashfireex@gmail.com>
2024-04-06 22:39:55 +03:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > target . getHpRatio ( ) === 1 , 0.5 )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TOXIC_BOOST , 5 )
2023-12-23 01:21:01 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . category === MoveCategory . PHYSICAL && ( user . status ? . effect === StatusEffect . POISON || user . status ? . effect === StatusEffect . TOXIC ) , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FLARE_BOOST , 5 )
2023-12-23 01:21:01 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . category === MoveCategory . SPECIAL && user . status ? . effect === StatusEffect . BURN , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HARVEST , 5 )
2024-05-22 08:52:45 -04:00
. attr (
2024-05-24 01:45:04 +02:00
PostTurnLootAbAttr ,
"EATEN_BERRIES" ,
2024-05-22 08:52:45 -04:00
/** Rate is doubled when under sun {@link https://dex.pokemonshowdown.com/abilities/harvest} */
( pokemon ) = > 0.5 * ( getWeatherCondition ( WeatherType . SUNNY , WeatherType . HARSH_SUN ) ( pokemon ) ? 2 : 1 )
)
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TELEPATHY , 5 )
2024-06-07 16:57:57 -04:00
. attr ( MoveImmunityAbAttr , ( pokemon , attacker , move ) = > pokemon . getAlly ( ) === attacker && move instanceof AttackMove )
2024-05-13 06:59:39 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MOODY , 5 )
2024-04-25 01:23:45 -04:00
. attr ( MoodyAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . OVERCOAT , 5 )
2023-12-23 01:21:01 -05:00
. attr ( BlockWeatherDamageAttr )
2024-06-07 16:57:57 -04:00
. attr ( MoveImmunityAbAttr , ( pokemon , attacker , move ) = > pokemon !== attacker && move . hasFlag ( MoveFlags . POWDER_MOVE ) )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . POISON_TOUCH , 5 )
2024-03-27 23:02:49 -05:00
. attr ( PostAttackContactApplyStatusEffectAbAttr , 30 , StatusEffect . POISON ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . REGENERATOR , 5 )
2024-05-23 17:03:10 +02:00
. attr ( PreSwitchOutHealAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BIG_PECKS , 5 )
2024-03-14 00:40:57 -04:00
. attr ( ProtectStatAbAttr , BattleStat . DEF )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SAND_RUSH , 5 )
2023-11-28 12:34:19 +09:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . SPD , 2 )
. attr ( BlockWeatherDamageAttr , WeatherType . SANDSTORM )
. condition ( getWeatherCondition ( WeatherType . SANDSTORM ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WONDER_SKIN , 5 )
2024-06-16 00:06:32 +08:00
. attr ( WonderSkinAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ANALYTIC , 5 )
2024-04-25 14:29:05 -04:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > ! ! target . getLastXMoves ( 1 ) . find ( m = > m . turn === target . scene . currentBattle . turn ) || user . scene . currentBattle . turnCommands [ target . getBattlerIndex ( ) ] . command !== Command . FIGHT , 1.3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ILLUSION , 5 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( UnswappableAbilityAbAttr )
. unimplemented ( ) ,
new Ability ( Abilities . IMPOSTER , 5 )
2024-04-13 11:08:32 +10:00
. attr ( PostSummonTransformAbAttr )
. attr ( UncopiableAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . INFILTRATOR , 5 )
. unimplemented ( ) ,
new Ability ( Abilities . MUMMY , 5 )
2024-05-03 22:30:23 -04:00
. attr ( PostDefendAbilityGiveAbAttr , Abilities . MUMMY )
2024-04-14 13:21:34 +10:00
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MOXIE , 5 )
2024-03-29 22:08:27 -04:00
. attr ( PostVictoryStatChangeAbAttr , BattleStat . ATK , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . JUSTIFIED , 5 )
Implement Multiscale, Solid Rock, Filter, Justified, Water Compaction, Soul-Heart, Shadow Shield, Prism Armor (#46)
* Implement Multiscale, Solid Rock, Filter, Justified, Water Compaction, Soul-Heart, Shadow Shield, Prism Armor
fix
fix
* Update src/data/ability.ts
---------
Co-authored-by: Samuel H <flashfireex@gmail.com>
2024-04-06 22:39:55 +03:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . type === Type . DARK && move . category !== MoveCategory . STATUS , BattleStat . ATK , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . RATTLED , 5 )
2024-04-17 01:09:15 -04:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . category !== MoveCategory . STATUS && ( move . type === Type . DARK || move . type === Type . BUG ||
2024-04-25 03:10:09 +02:00
move . type === Type . GHOST ) , BattleStat . SPD , 1 )
2024-05-05 07:52:27 -07:00
. attr ( PostIntimidateStatChangeAbAttr , [ BattleStat . SPD ] , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MAGIC_BOUNCE , 5 )
. ignorable ( )
. unimplemented ( ) ,
new Ability ( Abilities . SAP_SIPPER , 5 )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityStatChangeAbAttr , Type . GRASS , BattleStat . ATK , 1 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PRANKSTER , 5 )
2024-04-08 17:10:07 +03:00
. attr ( IncrementMovePriorityAbAttr , ( pokemon , move : Move ) = > move . category === MoveCategory . STATUS ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SAND_FORCE , 5 )
2023-12-23 01:21:01 -05:00
. attr ( MoveTypePowerBoostAbAttr , Type . ROCK , 1.3 )
. attr ( MoveTypePowerBoostAbAttr , Type . GROUND , 1.3 )
. attr ( MoveTypePowerBoostAbAttr , Type . STEEL , 1.3 )
. attr ( BlockWeatherDamageAttr , WeatherType . SANDSTORM )
. condition ( getWeatherCondition ( WeatherType . SANDSTORM ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . IRON_BARBS , 5 )
2024-04-09 18:05:15 -04:00
. attr ( PostDefendContactDamageAbAttr , 8 )
2024-04-11 09:24:03 -04:00
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ZEN_MODE , 5 )
2024-05-28 12:11:04 +01:00
. attr ( PostBattleInitFormChangeAbAttr , ( ) = > 0 )
2024-04-14 20:30:54 -05:00
. attr ( PostSummonFormChangeAbAttr , p = > p . getHpRatio ( ) <= 0.5 ? 1 : 0 )
. attr ( PostTurnFormChangeAbAttr , p = > p . getHpRatio ( ) <= 0.5 ? 1 : 0 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( UnsuppressableAbilityAbAttr )
2024-06-13 05:36:12 -04:00
. attr ( NoFusionAbilityAbAttr )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . VICTORY_STAR , 5 )
. attr ( BattleStatMultiplierAbAttr , BattleStat . ACC , 1.1 )
. partial ( ) ,
new Ability ( Abilities . TURBOBLAZE , 5 )
2024-05-23 17:03:10 +02:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " is radiating a blazing aura!" ) )
2024-03-14 00:40:57 -04:00
. attr ( MoveAbilityBypassAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TERAVOLT , 5 )
2024-05-23 17:03:10 +02:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " is radiating a bursting aura!" ) )
2024-03-14 00:40:57 -04:00
. attr ( MoveAbilityBypassAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . AROMA_VEIL , 6 )
. ignorable ( )
. unimplemented ( ) ,
new Ability ( Abilities . FLOWER_VEIL , 6 )
. ignorable ( )
. unimplemented ( ) ,
new Ability ( Abilities . CHEEK_POUCH , 6 )
2024-05-28 13:19:03 -04:00
. attr ( HealFromBerryUseAbAttr , 1 / 3 )
. partial ( ) , // Healing not blocked by Heal Block
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PROTEAN , 6 )
2024-06-24 21:58:50 -04:00
. attr ( PokemonTypeChangeAbAttr ) ,
//.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.PROTEAN)), //Gen 9 Implementation
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FUR_COAT , 6 )
2024-03-14 00:40:57 -04:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > move . category === MoveCategory . PHYSICAL , 0.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MAGICIAN , 6 )
2023-12-22 01:16:56 -05:00
. attr ( PostAttackStealHeldItemAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BULLETPROOF , 6 )
2024-06-07 16:57:57 -04:00
. attr ( MoveImmunityAbAttr , ( pokemon , attacker , move ) = > pokemon !== attacker && move . hasFlag ( MoveFlags . BALLBOMB_MOVE ) )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . COMPETITIVE , 6 )
2024-04-14 21:50:26 +01:00
. attr ( PostStatChangeStatChangeAbAttr , ( target , statsChanged , levels ) = > levels < 0 , [ BattleStat . SPATK ] , 2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STRONG_JAW , 6 )
2024-02-22 23:24:44 -06:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . hasFlag ( MoveFlags . BITING_MOVE ) , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . REFRIGERATE , 6 )
2024-06-07 16:57:57 -04:00
. attr ( MoveTypeChangeAttr , Type . ICE , 1.2 , ( user , target , move ) = > move . type === Type . NORMAL ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SWEET_VEIL , 6 )
2024-04-17 01:09:15 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . SLEEP )
. attr ( BattlerTagImmunityAbAttr , BattlerTagType . DROWSY )
2024-04-25 03:10:09 +02:00
. ignorable ( )
. partial ( ) ,
new Ability ( Abilities . STANCE_CHANGE , 6 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( UnsuppressableAbilityAbAttr )
. attr ( NoFusionAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GALE_WINGS , 6 )
2024-04-08 17:10:07 +03:00
. attr ( IncrementMovePriorityAbAttr , ( pokemon , move ) = > pokemon . getHpRatio ( ) === 1 && move . type === Type . FLYING ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MEGA_LAUNCHER , 6 )
2023-12-23 01:21:01 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . hasFlag ( MoveFlags . PULSE_MOVE ) , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GRASS_PELT , 6 )
2024-04-13 11:08:32 +10:00
. conditionalAttr ( getTerrainCondition ( TerrainType . GRASSY ) , BattleStatMultiplierAbAttr , BattleStat . DEF , 1.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SYMBIOSIS , 6 )
. unimplemented ( ) ,
new Ability ( Abilities . TOUGH_CLAWS , 6 )
2023-12-23 01:21:01 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . hasFlag ( MoveFlags . MAKES_CONTACT ) , 1.3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PIXILATE , 6 )
2024-06-07 16:57:57 -04:00
. attr ( MoveTypeChangeAttr , Type . FAIRY , 1.2 , ( user , target , move ) = > move . type === Type . NORMAL ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GOOEY , 6 )
2024-04-06 22:18:12 -05:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . hasFlag ( MoveFlags . MAKES_CONTACT ) , BattleStat . SPD , - 1 , false ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . AERILATE , 6 )
2024-06-07 16:57:57 -04:00
. attr ( MoveTypeChangeAttr , Type . FLYING , 1.2 , ( user , target , move ) = > move . type === Type . NORMAL ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PARENTAL_BOND , 6 )
2024-06-26 13:03:14 -07:00
. attr ( AddSecondStrikeAbAttr , 0.25 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DARK_AURA , 6 )
2024-05-23 17:03:10 +02:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " is radiating a Dark Aura!" ) )
2024-03-14 00:40:57 -04:00
. attr ( FieldMoveTypePowerBoostAbAttr , Type . DARK , 4 / 3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FAIRY_AURA , 6 )
2024-05-23 17:03:10 +02:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " is radiating a Fairy Aura!" ) )
2024-03-14 00:40:57 -04:00
. attr ( FieldMoveTypePowerBoostAbAttr , Type . FAIRY , 4 / 3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . AURA_BREAK , 6 )
. ignorable ( )
2024-06-22 08:37:46 -07:00
. conditionalAttr ( target = > target . hasAbility ( Abilities . DARK_AURA ) , FieldMoveTypePowerBoostAbAttr , Type . DARK , 9 / 16 )
. conditionalAttr ( target = > target . hasAbility ( Abilities . FAIRY_AURA ) , FieldMoveTypePowerBoostAbAttr , Type . FAIRY , 9 / 16 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PRIMORDIAL_SEA , 6 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonWeatherChangeAbAttr , WeatherType . HEAVY_RAIN )
2024-06-07 15:22:06 -04:00
. attr ( PostBiomeChangeWeatherChangeAbAttr , WeatherType . HEAVY_RAIN )
. attr ( PreSwitchOutClearWeatherAbAttr )
. attr ( PostFaintClearWeatherAbAttr )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DESOLATE_LAND , 6 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonWeatherChangeAbAttr , WeatherType . HARSH_SUN )
2024-06-07 15:22:06 -04:00
. attr ( PostBiomeChangeWeatherChangeAbAttr , WeatherType . HARSH_SUN )
. attr ( PreSwitchOutClearWeatherAbAttr )
. attr ( PostFaintClearWeatherAbAttr )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DELTA_STREAM , 6 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonWeatherChangeAbAttr , WeatherType . STRONG_WINDS )
2024-06-07 15:22:06 -04:00
. attr ( PostBiomeChangeWeatherChangeAbAttr , WeatherType . STRONG_WINDS )
. attr ( PreSwitchOutClearWeatherAbAttr )
. attr ( PostFaintClearWeatherAbAttr )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STAMINA , 7 )
2024-04-06 21:50:17 -05:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . category !== MoveCategory . STATUS , BattleStat . DEF , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WIMP_OUT , 7 )
2024-06-17 18:30:42 -06:00
. condition ( getSheerForceHitDisableAbCondition ( ) )
2024-04-25 03:10:09 +02:00
. unimplemented ( ) ,
new Ability ( Abilities . EMERGENCY_EXIT , 7 )
2024-06-17 18:30:42 -06:00
. condition ( getSheerForceHitDisableAbCondition ( ) )
2024-04-25 03:10:09 +02:00
. unimplemented ( ) ,
new Ability ( Abilities . WATER_COMPACTION , 7 )
2024-05-09 01:40:23 -05:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . type === Type . WATER && move . category !== MoveCategory . STATUS , BattleStat . DEF , 2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MERCILESS , 7 )
2024-05-19 08:06:58 -06:00
. attr ( ConditionalCritAbAttr , ( user , target , move ) = > target . status ? . effect === StatusEffect . TOXIC || target . status ? . effect === StatusEffect . POISON ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SHIELDS_DOWN , 7 )
2024-05-28 12:11:04 +01:00
. attr ( PostBattleInitFormChangeAbAttr , ( ) = > 0 )
2024-04-14 20:30:54 -05:00
. attr ( PostSummonFormChangeAbAttr , p = > p . formIndex % 7 + ( p . getHpRatio ( ) <= 0.5 ? 7 : 0 ) )
. attr ( PostTurnFormChangeAbAttr , p = > p . formIndex % 7 + ( p . getHpRatio ( ) <= 0.5 ? 7 : 0 ) )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( UnsuppressableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( NoFusionAbilityAbAttr )
2024-06-13 05:36:12 -04:00
. bypassFaint ( )
2024-04-25 03:10:09 +02:00
. partial ( ) ,
new Ability ( Abilities . STAKEOUT , 7 )
2024-04-25 14:29:05 -04:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > user . scene . currentBattle . turnCommands [ target . getBattlerIndex ( ) ] . command === Command . POKEMON , 2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WATER_BUBBLE , 7 )
2023-12-23 01:21:01 -05:00
. attr ( ReceivedTypeDamageMultiplierAbAttr , Type . FIRE , 0.5 )
2024-05-15 09:21:52 -05:00
. attr ( MoveTypePowerBoostAbAttr , Type . WATER , 2 )
2024-03-14 00:40:57 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . BURN )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STEELWORKER , 7 )
2023-12-14 11:48:59 -06:00
. attr ( MoveTypePowerBoostAbAttr , Type . STEEL ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BERSERK , 7 )
2024-06-17 18:30:42 -06:00
. attr ( PostDefendHpGatedStatChangeAbAttr , ( target , user , move ) = > move . category !== MoveCategory . STATUS , 0.5 , [ BattleStat . SPATK ] , 1 )
. condition ( getSheerForceHitDisableAbCondition ( ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SLUSH_RUSH , 7 )
2023-11-24 14:45:58 +09:00
. attr ( BattleStatMultiplierAbAttr , BattleStat . SPD , 2 )
2024-04-15 22:47:39 +02:00
. condition ( getWeatherCondition ( WeatherType . HAIL , WeatherType . SNOW ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LONG_REACH , 7 )
2023-12-10 22:29:13 -05:00
. attr ( IgnoreContactAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LIQUID_VOICE , 7 )
2024-04-14 13:15:01 -04:00
. attr ( MoveTypeChangeAttr , Type . WATER , 1 , ( user , target , move ) = > move . hasFlag ( MoveFlags . SOUND_BASED ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TRIAGE , 7 )
2024-04-08 17:10:07 +03:00
. attr ( IncrementMovePriorityAbAttr , ( pokemon , move ) = > move . hasFlag ( MoveFlags . TRIAGE_MOVE ) , 3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GALVANIZE , 7 )
2024-06-07 16:57:57 -04:00
. attr ( MoveTypeChangeAttr , Type . ELECTRIC , 1.2 , ( user , target , move ) = > move . type === Type . NORMAL ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SURGE_SURFER , 7 )
2024-03-14 00:40:57 -04:00
. conditionalAttr ( getTerrainCondition ( TerrainType . ELECTRIC ) , BattleStatMultiplierAbAttr , BattleStat . SPD , 2 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SCHOOLING , 7 )
2024-05-28 12:11:04 +01:00
. attr ( PostBattleInitFormChangeAbAttr , ( ) = > 0 )
2024-03-30 09:06:57 -04:00
. attr ( PostSummonFormChangeAbAttr , p = > p . level < 20 || p . getHpRatio ( ) <= 0.25 ? 0 : 1 )
. attr ( PostTurnFormChangeAbAttr , p = > p . level < 20 || p . getHpRatio ( ) <= 0.25 ? 0 : 1 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( UnsuppressableAbilityAbAttr )
2024-06-13 05:36:12 -04:00
. attr ( NoFusionAbilityAbAttr )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DISGUISE , 7 )
2024-06-26 03:23:48 +10:00
. attr ( PreDefendMoveDamageToOneAbAttr , ( target , user , move ) = > target . formIndex === 0 && target . getAttackTypeEffectiveness ( move . type , user ) > 0 )
2024-04-17 22:09:28 -06:00
. attr ( PostSummonFormChangeAbAttr , p = > p . battleData . hitCount === 0 ? 0 : 1 )
2024-05-28 12:11:04 +01:00
. attr ( PostBattleInitFormChangeAbAttr , ( ) = > 0 )
2024-04-17 22:09:28 -06:00
. attr ( PostDefendFormChangeAbAttr , p = > p . battleData . hitCount === 0 ? 0 : 1 )
. attr ( PreDefendFormChangeAbAttr , p = > p . battleData . hitCount === 0 ? 0 : 1 )
. attr ( PostDefendDisguiseAbAttr )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
. attr ( UnsuppressableAbilityAbAttr )
. attr ( NoTransformAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( NoFusionAbilityAbAttr )
2024-06-13 05:36:12 -04:00
. bypassFaint ( )
2024-04-25 03:10:09 +02:00
. ignorable ( )
. partial ( ) ,
new Ability ( Abilities . BATTLE_BOND , 7 )
2024-05-28 12:11:04 +01:00
. attr ( PostVictoryFormChangeAbAttr , ( ) = > 2 )
. attr ( PostBattleInitFormChangeAbAttr , ( ) = > 1 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( UnsuppressableAbilityAbAttr )
2024-06-13 05:36:12 -04:00
. attr ( NoFusionAbilityAbAttr )
. bypassFaint ( ) ,
2024-04-29 19:43:51 -05:00
new Ability ( Abilities . POWER_CONSTRUCT , 7 ) // TODO: 10% Power Construct Zygarde isn't accounted for yet. If changed, update Zygarde's getSpeciesFormIndex entry accordingly
2024-05-28 12:11:04 +01:00
. attr ( PostBattleInitFormChangeAbAttr , ( ) = > 2 )
2024-05-23 17:03:10 +02:00
. attr ( PostSummonFormChangeAbAttr , p = > p . getHpRatio ( ) <= 0.5 || p . getFormKey ( ) === "complete" ? 4 : 2 )
. attr ( PostTurnFormChangeAbAttr , p = > p . getHpRatio ( ) <= 0.5 || p . getFormKey ( ) === "complete" ? 4 : 2 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( UnsuppressableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( NoFusionAbilityAbAttr )
2024-06-13 05:36:12 -04:00
. bypassFaint ( )
2024-04-29 19:43:51 -05:00
. partial ( ) ,
2024-05-14 14:00:37 -04:00
new Ability ( Abilities . CORROSION , 7 ) // TODO: Test Corrosion against Magic Bounce once it is implemented
. attr ( IgnoreTypeStatusEffectImmunityAbAttr , [ StatusEffect . POISON , StatusEffect . TOXIC ] , [ Type . STEEL , Type . POISON ] )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . COMATOSE , 7 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( UnsuppressableAbilityAbAttr )
2024-05-27 05:01:03 -06:00
. attr ( StatusEffectImmunityAbAttr , . . . getNonVolatileStatusEffects ( ) )
. attr ( BattlerTagImmunityAbAttr , BattlerTagType . DROWSY ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . QUEENLY_MAJESTY , 7 )
2024-04-15 19:48:33 +03:00
. attr ( FieldPriorityMoveImmunityAbAttr )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . INNARDS_OUT , 7 )
2024-05-12 17:07:31 -04:00
. attr ( PostFaintHPDamageAbAttr )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DANCER , 7 )
2024-05-25 06:00:58 +02:00
. attr ( PostDancingMoveAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BATTERY , 7 )
2024-06-18 04:12:11 +08:00
. attr ( AllyMoveCategoryPowerBoostAbAttr , [ MoveCategory . SPECIAL ] , 1.3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FLUFFY , 7 )
2023-12-23 01:21:01 -05:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > move . hasFlag ( MoveFlags . MAKES_CONTACT ) , 0.5 )
2024-03-14 00:40:57 -04:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > move . type === Type . FIRE , 2 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DAZZLING , 7 )
2024-04-15 19:48:33 +03:00
. attr ( FieldPriorityMoveImmunityAbAttr )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SOUL_HEART , 7 )
2024-04-08 00:20:24 +03:00
. attr ( PostKnockOutStatChangeAbAttr , BattleStat . SPATK , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TANGLING_HAIR , 7 )
2024-04-06 22:18:12 -05:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . hasFlag ( MoveFlags . MAKES_CONTACT ) , BattleStat . SPD , - 1 , false ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . RECEIVER , 7 )
2024-04-14 13:21:34 +10:00
. attr ( CopyFaintedAllyAbilityAbAttr )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . POWER_OF_ALCHEMY , 7 )
2024-04-14 13:21:34 +10:00
. attr ( CopyFaintedAllyAbilityAbAttr )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BEAST_BOOST , 7 )
2024-03-30 00:53:35 -04:00
. attr ( PostVictoryStatChangeAbAttr , p = > {
const battleStats = Utils . getEnumValues ( BattleStat ) . slice ( 0 , - 3 ) . map ( s = > s as BattleStat ) ;
let highestBattleStat = 0 ;
let highestBattleStatIndex = 0 ;
battleStats . map ( ( bs : BattleStat , i : integer ) = > {
const stat = p . getStat ( bs + 1 ) ;
if ( stat > highestBattleStat ) {
highestBattleStatIndex = i ;
highestBattleStat = stat ;
}
} ) ;
return highestBattleStatIndex ;
} , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . RKS_SYSTEM , 7 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( UnsuppressableAbilityAbAttr )
2024-06-10 08:58:34 -05:00
. attr ( NoFusionAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ELECTRIC_SURGE , 7 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonTerrainChangeAbAttr , TerrainType . ELECTRIC )
. attr ( PostBiomeChangeTerrainChangeAbAttr , TerrainType . ELECTRIC ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PSYCHIC_SURGE , 7 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonTerrainChangeAbAttr , TerrainType . PSYCHIC )
. attr ( PostBiomeChangeTerrainChangeAbAttr , TerrainType . PSYCHIC ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MISTY_SURGE , 7 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonTerrainChangeAbAttr , TerrainType . MISTY )
. attr ( PostBiomeChangeTerrainChangeAbAttr , TerrainType . MISTY ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GRASSY_SURGE , 7 )
2024-04-08 09:31:30 -04:00
. attr ( PostSummonTerrainChangeAbAttr , TerrainType . GRASSY )
. attr ( PostBiomeChangeTerrainChangeAbAttr , TerrainType . GRASSY ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . FULL_METAL_BODY , 7 )
2023-12-23 01:21:01 -05:00
. attr ( ProtectStatAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SHADOW_SHIELD , 7 )
Implement Multiscale, Solid Rock, Filter, Justified, Water Compaction, Soul-Heart, Shadow Shield, Prism Armor (#46)
* Implement Multiscale, Solid Rock, Filter, Justified, Water Compaction, Soul-Heart, Shadow Shield, Prism Armor
fix
fix
* Update src/data/ability.ts
---------
Co-authored-by: Samuel H <flashfireex@gmail.com>
2024-04-06 22:39:55 +03:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > target . getHpRatio ( ) === 1 , 0.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PRISM_ARMOR , 7 )
2024-05-06 00:27:56 -05:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > target . getAttackTypeEffectiveness ( move . type , user ) >= 2 , 0.75 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . NEUROFORCE , 7 )
2024-05-06 00:27:56 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > target . getAttackTypeEffectiveness ( move . type , user ) >= 2 , 1.25 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . INTREPID_SWORD , 8 )
2024-05-07 14:35:15 +10:00
. attr ( PostSummonStatChangeAbAttr , BattleStat . ATK , 1 , true )
. condition ( getOncePerBattleCondition ( Abilities . INTREPID_SWORD ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DAUNTLESS_SHIELD , 8 )
2024-05-07 14:35:15 +10:00
. attr ( PostSummonStatChangeAbAttr , BattleStat . DEF , 1 , true )
. condition ( getOncePerBattleCondition ( Abilities . DAUNTLESS_SHIELD ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LIBERO , 8 )
2024-06-24 21:58:50 -04:00
. attr ( PokemonTypeChangeAbAttr ) ,
//.condition((p) => !p.summonData?.abilitiesApplied.includes(Abilities.LIBERO)), //Gen 9 Implementation
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BALL_FETCH , 8 )
2024-05-19 17:13:33 +01:00
. attr ( FetchBallAbAttr )
. condition ( getOncePerBattleCondition ( Abilities . BALL_FETCH ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . COTTON_DOWN , 8 )
2024-05-08 18:25:15 -04:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . category !== MoveCategory . STATUS , BattleStat . SPD , - 1 , false , true )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PROPELLER_TAIL , 8 )
2024-05-10 11:40:21 -04:00
. attr ( BlockRedirectAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MIRROR_ARMOR , 8 )
. ignorable ( )
. unimplemented ( ) ,
new Ability ( Abilities . GULP_MISSILE , 8 )
2024-04-13 11:08:32 +10:00
. attr ( UnsuppressableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( NoTransformAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( NoFusionAbilityAbAttr )
. unimplemented ( ) ,
new Ability ( Abilities . STALWART , 8 )
2024-05-10 11:40:21 -04:00
. attr ( BlockRedirectAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STEAM_ENGINE , 8 )
2024-04-16 23:17:47 -04:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > ( move . type === Type . FIRE || move . type === Type . WATER ) && move . category !== MoveCategory . STATUS , BattleStat . SPD , 6 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PUNK_ROCK , 8 )
2023-12-23 01:21:01 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . hasFlag ( MoveFlags . SOUND_BASED ) , 1.3 )
2024-03-14 00:40:57 -04:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > move . hasFlag ( MoveFlags . SOUND_BASED ) , 0.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SAND_SPIT , 8 )
2024-04-07 14:01:48 -05:00
. attr ( PostDefendWeatherChangeAbAttr , WeatherType . SANDSTORM ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ICE_SCALES , 8 )
2024-04-07 19:36:56 +01:00
. attr ( ReceivedMoveDamageMultiplierAbAttr , ( target , user , move ) = > move . category === MoveCategory . SPECIAL , 0.5 )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . RIPEN , 8 )
2023-12-22 01:16:56 -05:00
. attr ( DoubleBerryEffectAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ICE_FACE , 8 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
. attr ( UnsuppressableAbilityAbAttr )
. attr ( NoTransformAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( NoFusionAbilityAbAttr )
2024-06-06 23:49:50 +08:00
// Add BattlerTagType.ICE_FACE if the pokemon is in ice face form
. conditionalAttr ( pokemon = > pokemon . formIndex === 0 , PostSummonAddBattlerTagAbAttr , BattlerTagType . ICE_FACE , 0 , false )
// When summoned with active HAIL or SNOW, add BattlerTagType.ICE_FACE
. conditionalAttr ( getWeatherCondition ( WeatherType . HAIL , WeatherType . SNOW ) , PostSummonAddBattlerTagAbAttr , BattlerTagType . ICE_FACE , 0 )
// When weather changes to HAIL or SNOW while pokemon is fielded, add BattlerTagType.ICE_FACE
. attr ( PostWeatherChangeAddBattlerTagAttr , BattlerTagType . ICE_FACE , 0 , WeatherType . HAIL , WeatherType . SNOW )
2024-06-19 10:56:44 +08:00
. attr ( IceFaceBlockPhysicalAbAttr , ( target , user , move ) = > move . category === MoveCategory . PHYSICAL && ! ! target . getTag ( BattlerTagType . ICE_FACE ) , 0 )
2024-06-06 23:49:50 +08:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . POWER_SPOT , 8 )
2024-06-18 04:12:11 +08:00
. attr ( AllyMoveCategoryPowerBoostAbAttr , [ MoveCategory . SPECIAL , MoveCategory . PHYSICAL ] , 1.3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MIMICRY , 8 )
. unimplemented ( ) ,
new Ability ( Abilities . SCREEN_CLEANER , 8 )
2024-06-18 03:37:11 +08:00
. attr ( PostSummonRemoveArenaTagAbAttr , [ ArenaTagType . AURORA_VEIL , ArenaTagType . LIGHT_SCREEN , ArenaTagType . REFLECT ] ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . STEELY_SPIRIT , 8 )
2024-07-04 00:55:39 +08:00
. attr ( UserFieldMoveTypePowerBoostAbAttr , Type . STEEL ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PERISH_BODY , 8 )
2024-05-30 08:36:12 -07:00
. attr ( PostDefendPerishSongAbAttr , 4 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WANDERING_SPIRIT , 8 )
2024-04-14 13:21:34 +10:00
. attr ( PostDefendAbilitySwapAbAttr )
2024-04-25 03:10:09 +02:00
. bypassFaint ( )
. partial ( ) ,
new Ability ( Abilities . GORILLA_TACTICS , 8 )
. unimplemented ( ) ,
new Ability ( Abilities . NEUTRALIZING_GAS , 8 )
2024-04-18 15:44:03 +10:00
. attr ( SuppressFieldAbilitiesAbAttr )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( NoTransformAbilityAbAttr )
2024-05-23 17:03:10 +02:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , "'s Neutralizing Gas filled the area!" ) )
2024-04-25 03:10:09 +02:00
. partial ( ) ,
new Ability ( Abilities . PASTEL_VEIL , 8 )
2024-04-08 13:21:06 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . POISON , StatusEffect . TOXIC )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HUNGER_SWITCH , 8 )
2024-03-30 12:01:49 -05:00
. attr ( PostTurnFormChangeAbAttr , p = > p . getFormKey ? 0 : 1 )
2024-04-13 11:08:32 +10:00
. attr ( PostTurnFormChangeAbAttr , p = > p . getFormKey ? 1 : 0 )
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( NoTransformAbilityAbAttr )
2024-05-05 22:12:10 -07:00
. attr ( NoFusionAbilityAbAttr )
. condition ( ( pokemon ) = > ! pokemon . isTerastallized ( ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . QUICK_DRAW , 8 )
2024-06-25 00:22:15 +09:00
. attr ( BypassSpeedChanceAbAttr , 30 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . UNSEEN_FIST , 8 )
2024-06-15 19:14:49 -07:00
. attr ( IgnoreProtectOnContactAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . CURIOUS_MEDICINE , 8 )
2024-05-13 05:57:17 -04:00
. attr ( PostSummonClearAllyStatsAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TRANSISTOR , 8 )
2023-12-14 11:48:59 -06:00
. attr ( MoveTypePowerBoostAbAttr , Type . ELECTRIC ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . DRAGONS_MAW , 8 )
2023-12-14 11:48:59 -06:00
. attr ( MoveTypePowerBoostAbAttr , Type . DRAGON ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . CHILLING_NEIGH , 8 )
2024-03-29 22:17:26 -05:00
. attr ( PostVictoryStatChangeAbAttr , BattleStat . ATK , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GRIM_NEIGH , 8 )
2024-03-29 22:17:26 -05:00
. attr ( PostVictoryStatChangeAbAttr , BattleStat . SPATK , 1 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . AS_ONE_GLASTRIER , 8 )
2024-05-27 23:54:56 -05:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " has two Abilities!" ) )
2024-03-29 22:17:26 -05:00
. attr ( PreventBerryUseAbAttr )
2024-04-13 11:08:32 +10:00
. attr ( PostVictoryStatChangeAbAttr , BattleStat . ATK , 1 )
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
. attr ( UnsuppressableAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . AS_ONE_SPECTRIER , 8 )
2024-05-27 23:54:56 -05:00
. attr ( PostSummonMessageAbAttr , ( pokemon : Pokemon ) = > getPokemonMessage ( pokemon , " has two Abilities!" ) )
2024-03-29 22:17:26 -05:00
. attr ( PreventBerryUseAbAttr )
2024-04-13 11:08:32 +10:00
. attr ( PostVictoryStatChangeAbAttr , BattleStat . SPATK , 1 )
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
. attr ( UnsuppressableAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . LINGERING_AROMA , 9 )
2024-05-03 22:30:23 -04:00
. attr ( PostDefendAbilityGiveAbAttr , Abilities . LINGERING_AROMA )
2024-04-14 13:21:34 +10:00
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SEED_SOWER , 9 )
2024-03-14 00:40:57 -04:00
. attr ( PostDefendTerrainChangeAbAttr , TerrainType . GRASSY ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . THERMAL_EXCHANGE , 9 )
2024-04-17 01:09:15 -04:00
. attr ( PostDefendStatChangeAbAttr , ( target , user , move ) = > move . type === Type . FIRE && move . category !== MoveCategory . STATUS , BattleStat . ATK , 1 )
2024-03-14 00:40:57 -04:00
. attr ( StatusEffectImmunityAbAttr , StatusEffect . BURN )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ANGER_SHELL , 9 )
2024-05-03 13:55:46 -07:00
. attr ( PostDefendHpGatedStatChangeAbAttr , ( target , user , move ) = > move . category !== MoveCategory . STATUS , 0.5 , [ BattleStat . ATK , BattleStat . SPATK , BattleStat . SPD ] , 1 )
2024-06-17 18:30:42 -06:00
. attr ( PostDefendHpGatedStatChangeAbAttr , ( target , user , move ) = > move . category !== MoveCategory . STATUS , 0.5 , [ BattleStat . DEF , BattleStat . SPDEF ] , - 1 )
. condition ( getSheerForceHitDisableAbCondition ( ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PURIFYING_SALT , 9 )
2023-12-23 01:21:01 -05:00
. attr ( StatusEffectImmunityAbAttr )
2024-03-14 00:40:57 -04:00
. attr ( ReceivedTypeDamageMultiplierAbAttr , Type . GHOST , 0.5 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WELL_BAKED_BODY , 9 )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityStatChangeAbAttr , Type . FIRE , BattleStat . DEF , 2 )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WIND_RIDER , 9 )
2024-06-07 16:57:57 -04:00
. attr ( MoveImmunityStatChangeAbAttr , ( pokemon , attacker , move ) = > pokemon !== attacker && move . hasFlag ( MoveFlags . WIND_MOVE ) && move . category !== MoveCategory . STATUS , BattleStat . ATK , 1 )
2024-05-31 05:42:46 +08:00
. attr ( PostSummonStatChangeOnArenaAbAttr , ArenaTagType . TAILWIND )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GUARD_DOG , 9 )
2024-05-05 07:52:27 -07:00
. attr ( PostIntimidateStatChangeAbAttr , [ BattleStat . ATK ] , 1 , true )
. attr ( ForceSwitchOutImmunityAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ROCKY_PAYLOAD , 9 )
2023-12-14 11:48:59 -06:00
. attr ( MoveTypePowerBoostAbAttr , Type . ROCK ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . WIND_POWER , 9 )
2024-05-31 05:42:46 +08:00
. attr ( PostDefendApplyBattlerTagAbAttr , ( target , user , move ) = > move . hasFlag ( MoveFlags . WIND_MOVE ) , BattlerTagType . CHARGED ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ZERO_TO_HERO , 9 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
. attr ( UnsuppressableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( NoTransformAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( NoFusionAbilityAbAttr )
2024-05-28 12:11:04 +01:00
. attr ( PostBattleInitFormChangeAbAttr , ( ) = > 0 )
2024-06-13 05:36:12 -04:00
. attr ( PreSwitchOutFormChangeAbAttr , ( ) = > 1 )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . COMMANDER , 9 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( UnswappableAbilityAbAttr )
. unimplemented ( ) ,
new Ability ( Abilities . ELECTROMORPHOSIS , 9 )
2024-04-17 01:09:15 -04:00
. attr ( PostDefendApplyBattlerTagAbAttr , ( target , user , move ) = > move . category !== MoveCategory . STATUS , BattlerTagType . CHARGED ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . PROTOSYNTHESIS , 9 )
2024-03-18 21:22:27 -04:00
. conditionalAttr ( getWeatherCondition ( WeatherType . SUNNY , WeatherType . HARSH_SUN ) , PostSummonAddBattlerTagAbAttr , BattlerTagType . PROTOSYNTHESIS , 0 , true )
. attr ( PostWeatherChangeAddBattlerTagAttr , BattlerTagType . PROTOSYNTHESIS , 0 , WeatherType . SUNNY , WeatherType . HARSH_SUN )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-05-06 03:26:11 +03:00
. attr ( NoTransformAbilityAbAttr )
. partial ( ) , // While setting the tag, the getbattlestat should ignore all modifiers to stats except stat stages
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . QUARK_DRIVE , 9 )
2024-03-18 21:22:27 -04:00
. conditionalAttr ( getTerrainCondition ( TerrainType . ELECTRIC ) , PostSummonAddBattlerTagAbAttr , BattlerTagType . QUARK_DRIVE , 0 , true )
. attr ( PostTerrainChangeAddBattlerTagAttr , BattlerTagType . QUARK_DRIVE , 0 , TerrainType . ELECTRIC )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-05-06 03:26:11 +03:00
. attr ( NoTransformAbilityAbAttr )
. partial ( ) , // While setting the tag, the getbattlestat should ignore all modifiers to stats except stat stages
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . GOOD_AS_GOLD , 9 )
2024-06-07 16:57:57 -04:00
. attr ( MoveImmunityAbAttr , ( pokemon , attacker , move ) = > pokemon !== attacker && move . category === MoveCategory . STATUS )
2024-04-25 03:10:09 +02:00
. ignorable ( )
. partial ( ) ,
new Ability ( Abilities . VESSEL_OF_RUIN , 9 )
2024-06-11 06:37:10 -07:00
. attr ( FieldMultiplyBattleStatAbAttr , Stat . SPATK , 0.75 )
. attr ( PostSummonMessageAbAttr , ( user ) = > getPokemonMessage ( user , ` 's Vessel of Ruin lowered the ${ getStatName ( Stat . SPATK ) } \ nof all surrounding Pokémon! ` ) )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SWORD_OF_RUIN , 9 )
2024-06-11 06:37:10 -07:00
. attr ( FieldMultiplyBattleStatAbAttr , Stat . DEF , 0.75 )
. attr ( PostSummonMessageAbAttr , ( user ) = > getPokemonMessage ( user , ` 's Sword of Ruin lowered the ${ getStatName ( Stat . DEF ) } \ nof all surrounding Pokémon! ` ) )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TABLETS_OF_RUIN , 9 )
2024-06-11 06:37:10 -07:00
. attr ( FieldMultiplyBattleStatAbAttr , Stat . ATK , 0.75 )
. attr ( PostSummonMessageAbAttr , ( user ) = > getPokemonMessage ( user , ` 's Tablets of Ruin lowered the ${ getStatName ( Stat . ATK ) } \ nof all surrounding Pokémon! ` ) )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . BEADS_OF_RUIN , 9 )
2024-06-11 06:37:10 -07:00
. attr ( FieldMultiplyBattleStatAbAttr , Stat . SPDEF , 0.75 )
. attr ( PostSummonMessageAbAttr , ( user ) = > getPokemonMessage ( user , ` 's Beads of Ruin lowered the ${ getStatName ( Stat . SPDEF ) } \ nof all surrounding Pokémon! ` ) )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ORICHALCUM_PULSE , 9 )
2023-12-23 01:21:01 -05:00
. attr ( PostSummonWeatherChangeAbAttr , WeatherType . SUNNY )
2024-04-08 09:31:30 -04:00
. attr ( PostBiomeChangeWeatherChangeAbAttr , WeatherType . SUNNY )
2024-04-13 11:08:32 +10:00
. conditionalAttr ( getWeatherCondition ( WeatherType . SUNNY , WeatherType . HARSH_SUN ) , BattleStatMultiplierAbAttr , BattleStat . ATK , 4 / 3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HADRON_ENGINE , 9 )
2024-03-13 12:23:31 -05:00
. attr ( PostSummonTerrainChangeAbAttr , TerrainType . ELECTRIC )
2024-04-08 09:31:30 -04:00
. attr ( PostBiomeChangeTerrainChangeAbAttr , TerrainType . ELECTRIC )
2024-04-13 11:08:32 +10:00
. conditionalAttr ( getTerrainCondition ( TerrainType . ELECTRIC ) , BattleStatMultiplierAbAttr , BattleStat . SPATK , 4 / 3 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . OPPORTUNIST , 9 )
2024-05-04 16:38:53 -07:00
. attr ( StatChangeCopyAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . CUD_CHEW , 9 )
. unimplemented ( ) ,
new Ability ( Abilities . SHARPNESS , 9 )
2023-12-23 01:21:01 -05:00
. attr ( MovePowerBoostAbAttr , ( user , target , move ) = > move . hasFlag ( MoveFlags . SLICING_MOVE ) , 1.5 ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SUPREME_OVERLORD , 9 )
2024-05-30 01:07:59 +10:00
. attr ( VariableMovePowerBoostAbAttr , ( user , target , move ) = > 1 + 0.1 * Math . min ( user . isPlayer ( ) ? user.scene.currentBattle.playerFaints : user.scene.currentBattle.enemyFaints , 5 ) )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . COSTAR , 9 )
2024-06-22 11:35:25 -04:00
. attr ( PostSummonCopyAllyStatsAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TOXIC_DEBRIS , 9 )
2024-04-19 20:08:09 +01:00
. attr ( PostDefendApplyArenaTrapTagAbAttr , ( target , user , move ) = > move . category === MoveCategory . PHYSICAL , ArenaTagType . TOXIC_SPIKES )
. bypassFaint ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . ARMOR_TAIL , 9 )
2024-05-24 01:45:04 +02:00
. attr ( FieldPriorityMoveImmunityAbAttr )
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . EARTH_EATER , 9 )
2024-03-14 00:40:57 -04:00
. attr ( TypeImmunityHealAbAttr , Type . GROUND )
2024-05-28 13:19:03 -04:00
. partial ( ) // Healing not blocked by Heal Block
2024-03-14 00:40:57 -04:00
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . MYCELIUM_MIGHT , 9 )
. attr ( MoveAbilityBypassAbAttr , ( pokemon , move : Move ) = > move . category === MoveCategory . STATUS )
. partial ( ) ,
new Ability ( Abilities . MINDS_EYE , 9 )
2024-05-06 00:27:56 -05:00
. attr ( IgnoreTypeImmunityAbAttr , Type . GHOST , [ Type . NORMAL , Type . FIGHTING ] )
2024-05-21 23:11:42 -04:00
. attr ( ProtectStatAbAttr , BattleStat . ACC )
. attr ( IgnoreOpponentEvasionAbAttr )
. ignorable ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . SUPERSWEET_SYRUP , 9 )
2024-05-06 23:47:20 -05:00
. attr ( PostSummonStatChangeAbAttr , BattleStat . EVA , - 1 )
. condition ( getOncePerBattleCondition ( Abilities . SUPERSWEET_SYRUP ) ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . HOSPITALITY , 9 )
2024-05-28 13:19:03 -04:00
. attr ( PostSummonAllyHealAbAttr , 4 , true )
. partial ( ) , // Healing not blocked by Heal Block
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TOXIC_CHAIN , 9 )
2024-04-14 11:13:17 -06:00
. attr ( PostAttackApplyStatusEffectAbAttr , false , 30 , StatusEffect . TOXIC ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . EMBODY_ASPECT_TEAL , 9 )
2024-04-13 11:08:32 +10:00
. attr ( PostBattleInitStatChangeAbAttr , BattleStat . SPD , 1 , true )
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-05-28 12:11:04 +01:00
. attr ( NoTransformAbilityAbAttr )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . EMBODY_ASPECT_WELLSPRING , 9 )
2024-04-13 11:08:32 +10:00
. attr ( PostBattleInitStatChangeAbAttr , BattleStat . SPDEF , 1 , true )
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-05-28 12:11:04 +01:00
. attr ( NoTransformAbilityAbAttr )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . EMBODY_ASPECT_HEARTHFLAME , 9 )
2024-04-13 11:08:32 +10:00
. attr ( PostBattleInitStatChangeAbAttr , BattleStat . ATK , 1 , true )
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-05-28 12:11:04 +01:00
. attr ( NoTransformAbilityAbAttr )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . EMBODY_ASPECT_CORNERSTONE , 9 )
2024-04-13 11:08:32 +10:00
. attr ( PostBattleInitStatChangeAbAttr , BattleStat . DEF , 1 , true )
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-05-28 12:11:04 +01:00
. attr ( NoTransformAbilityAbAttr )
. partial ( ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TERA_SHIFT , 9 )
2024-04-13 11:08:32 +10:00
. attr ( PostSummonFormChangeAbAttr , p = > p . getFormKey ( ) ? 0 : 1 )
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
. attr ( UnsuppressableAbilityAbAttr )
2024-04-19 04:27:34 +10:00
. attr ( NoTransformAbilityAbAttr )
. attr ( NoFusionAbilityAbAttr ) ,
2024-04-25 03:10:09 +02:00
new Ability ( Abilities . TERA_SHELL , 9 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. ignorable ( )
. unimplemented ( ) ,
new Ability ( Abilities . TERAFORM_ZERO , 9 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
2024-04-25 03:10:09 +02:00
. attr ( UnswappableAbilityAbAttr )
. unimplemented ( ) ,
new Ability ( Abilities . POISON_PUPPETEER , 9 )
2024-04-13 11:08:32 +10:00
. attr ( UncopiableAbilityAbAttr )
. attr ( UnswappableAbilityAbAttr )
2024-05-25 05:51:36 -04:00
. conditionalAttr ( pokemon = > pokemon . species . speciesId === Species . PECHARUNT , ConfusionOnStatusEffectAbAttr , StatusEffect . POISON , StatusEffect . TOXIC )
2023-04-27 14:30:03 -04:00
) ;
2024-04-07 19:36:56 +01:00
}