diff --git a/src/account.ts b/src/account.ts index 104ad15704c..a2ff71a6ed3 100644 --- a/src/account.ts +++ b/src/account.ts @@ -22,7 +22,6 @@ export function updateUserInfo(): Promise<[boolean, integer]> { return resolve([ true, 200 ]); } Utils.apiFetch('account/info').then(response => { - console.log(response.status); if (!response.ok) { resolve([ false, response.status ]); return; diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 3090bbe1c8b..27166347039 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -19,7 +19,8 @@ import { } from "./data/move"; import { initMoves } from './data/move'; import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type'; import AbilityBar from './ui/ability-bar'; -import { Abilities, BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, applyAbAttrs, initAbilities } from './data/ability'; +import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, applyAbAttrs, initAbilities } from './data/ability'; +import { Abilities } from "./data/enums/abilities"; import Battle, { BattleType, FixedBattleConfig, fixedBattles } from './battle'; import { GameMode, GameModes, gameModes } from './game-mode'; import FieldSpritePipeline from './pipelines/field-sprite'; diff --git a/src/data/ability.ts b/src/data/ability.ts index 6c00f86d5ad..1d5dcb7581f 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -7,7 +7,7 @@ import { getPokemonMessage } from "../messages"; import { Weather, WeatherType } from "./weather"; import { BattlerTag } from "./battler-tags"; import { BattlerTagType } from "./enums/battler-tag-type"; -import { StatusEffect, getStatusEffectDescriptor } from "./status-effect"; +import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, allMoves } from "./move"; import { ArenaTagType } from "./enums/arena-tag-type"; import { Stat } from "./pokemon-stat"; @@ -15,13 +15,14 @@ import { PokemonHeldItemModifier } from "../modifier/modifier"; import { Moves } from "./enums/moves"; import { TerrainType } from "./terrain"; import { SpeciesFormChangeManualTrigger } from "./pokemon-forms"; +import { Abilities } from "./enums/abilities"; export class Ability { public id: Abilities; public name: string; public description: string; public generation: integer; - public isPassive: boolean; + public isBypassFaint: boolean; public isIgnorable: boolean; public attrs: AbAttr[]; public conditions: AbAttrCondition[]; @@ -58,8 +59,8 @@ export class Ability { return !!this.getAttrs(attrType).length; } - passive(): Ability { - this.isPassive = true; + bypassFaint(): Ability { + this.isBypassFaint = true; return this; } @@ -75,7 +76,7 @@ export class Ability { } } -type AbAttrApplyFunc = (attr: TAttr) => boolean | Promise; +type AbAttrApplyFunc = (attr: TAttr, passive: boolean) => boolean | Promise; type AbAttrCondition = (pokemon: Pokemon) => boolean; type PokemonAttackCondition = (user: Pokemon, target: Pokemon, move: Move) => boolean; @@ -89,11 +90,11 @@ export abstract class AbAttr { this.showAbility = showAbility; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { return null; } @@ -108,14 +109,14 @@ export abstract class AbAttr { } export class BlockRecoilDamageAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]) { - return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nprotected it from recoil!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) { + return getPokemonMessage(pokemon, `'s ${abilityName}\nprotected it from recoil!`); } } @@ -124,7 +125,7 @@ export class DoubleBattleChanceAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const doubleChance = (args[0] as Utils.IntegerHolder); doubleChance.value = Math.max(doubleChance.value / 2, 1); return true; @@ -132,7 +133,7 @@ export class DoubleBattleChanceAbAttr extends AbAttr { } export class PostBattleInitAbAttr extends AbAttr { - applyPostBattleInit(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPostBattleInit(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { return false; } } @@ -146,7 +147,7 @@ export class PostBattleInitFormChangeAbAttr extends PostBattleInitAbAttr { this.formFunc = formFunc; } - applyPostBattleInit(pokemon: Pokemon, args: any[]): boolean { + applyPostBattleInit(pokemon: Pokemon, passive: boolean, args: any[]): boolean { const formIndex = this.formFunc(pokemon); if (formIndex !== pokemon.formIndex) return pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); @@ -170,7 +171,7 @@ export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr { this.selfTarget = !!selfTarget; } - applyPostBattleInit(pokemon: Pokemon, args: any[]): boolean { + applyPostBattleInit(pokemon: Pokemon, passive: boolean, args: any[]): boolean { const statChangePhases: StatChangePhase[] = []; if (this.selfTarget) @@ -194,13 +195,13 @@ export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr { type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: PokemonMove) => boolean; export class PreDefendAbAttr extends AbAttr { - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr { - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (pokemon.getHpRatio() < 1 || (args[0] as Utils.NumberHolder).value < pokemon.hp) return false; @@ -209,19 +210,19 @@ export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr { } export class BlockItemTheftAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]) { - return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nprevents item theft!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) { + return getPokemonMessage(pokemon, `'s ${abilityName}\nprevents item theft!`); } } export class StabBoostAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if ((args[0] as Utils.NumberHolder).value > 1) { (args[0] as Utils.NumberHolder).value += 0.5; return true; @@ -242,7 +243,7 @@ export class ReceivedMoveDamageMultiplierAbAttr extends PreDefendAbAttr { this.powerMultiplier = powerMultiplier; } - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.condition(pokemon, attacker, move.getMove())) { (args[0] as Utils.NumberHolder).value *= this.powerMultiplier; return true; @@ -269,7 +270,7 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr { this.condition = condition; } - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { if ((move.getMove() instanceof AttackMove || move.getMove().getAttrs(StatusMoveTypeImmunityAttr).find(attr => (attr as StatusMoveTypeImmunityAttr).immuneType === this.immuneType)) && move.getMove().type === this.immuneType) { (args[0] as Utils.NumberHolder).value = 0; return true; @@ -288,15 +289,16 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr { super(immuneType); } - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const ret = super.applyPreDefend(pokemon, attacker, move, cancelled, args); + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); if (ret) { if (pokemon.getHpRatio() < 1) { const simulated = args.length > 1 && args[1]; if (!simulated) { + const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / 4), 1), getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nrestored its HP a little!`), true)); + Math.max(Math.floor(pokemon.getMaxHp() / 4), 1), getPokemonMessage(pokemon, `'s ${abilityName}\nrestored its HP a little!`), true)); } } return true; @@ -317,8 +319,8 @@ class TypeImmunityStatChangeAbAttr extends TypeImmunityAbAttr { this.levels = levels; } - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const ret = super.applyPreDefend(pokemon, attacker, move, cancelled, args); + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); if (ret) { cancelled.value = true; @@ -342,8 +344,8 @@ class TypeImmunityAddBattlerTagAbAttr extends TypeImmunityAbAttr { this.turnCount = turnCount; } - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const ret = super.applyPreDefend(pokemon, attacker, move, cancelled, args); + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const ret = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); if (ret) { cancelled.value = true; @@ -361,7 +363,7 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { super(null, condition); } - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type) < 2) { cancelled.value = true; (args[0] as Utils.NumberHolder).value = 0; @@ -371,13 +373,13 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { - return getPokemonMessage(pokemon, ` avoided damage\nwith ${pokemon.getAbility().name}!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, ` avoided damage\nwith ${abilityName}!`); } } export class PostDefendAbAttr extends AbAttr { - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean | Promise { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean | Promise { return false; } } @@ -391,7 +393,7 @@ export class MoveImmunityAbAttr extends PreDefendAbAttr { this.immuneCondition = immuneCondition; } - applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.immuneCondition(pokemon, attacker, move)) { cancelled.value = true; return true; @@ -400,7 +402,7 @@ export class MoveImmunityAbAttr extends PreDefendAbAttr { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { return `It doesn\'t affect ${pokemon.name}!`; } } @@ -420,7 +422,7 @@ export class PostDefendStatChangeAbAttr extends PostDefendAbAttr { this.selfTarget = selfTarget; } - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (this.condition(pokemon, attacker, move.getMove())) { pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, (this.selfTarget ? pokemon : attacker).getBattlerIndex(), true, [ this.stat ], this.levels)); return true; @@ -431,7 +433,7 @@ export class PostDefendStatChangeAbAttr extends PostDefendAbAttr { } export class PostDefendTypeChangeAbAttr extends PostDefendAbAttr { - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (hitResult < HitResult.NO_EFFECT) { const type = move.getMove().type; const pokemonTypes = pokemon.getTypes(true); @@ -444,8 +446,8 @@ export class PostDefendTypeChangeAbAttr extends PostDefendAbAttr { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { - return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nmade it the ${Utils.toReadableString(Type[pokemon.getTypes(true)[0]])} type!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, `'s ${abilityName}\nmade it the ${Utils.toReadableString(Type[pokemon.getTypes(true)[0]])} type!`); } } @@ -458,7 +460,7 @@ export class PostDefendTerrainChangeAbAttr extends PostDefendAbAttr { this.terrainType = terrainType; } - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (hitResult < HitResult.NO_EFFECT) return pokemon.scene.arena.trySetTerrain(this.terrainType, true); @@ -477,7 +479,7 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr { this.effects = effects; } - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.status && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance)) { const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; return attacker.trySetStatus(effect, true); @@ -500,7 +502,7 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr { this.turnCount = turnCount; } - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance) return attacker.addTag(this.tagType, this.turnCount, move.moveId, attacker.id); @@ -519,7 +521,7 @@ export class PostDefendCritStatChangeAbAttr extends PostDefendAbAttr { this.levels = levels; } - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels)); return true; @@ -539,7 +541,7 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr { this.damageRatio = damageRatio; } - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); return true; @@ -548,8 +550,8 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { - return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nhurt its attacker!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, `'s ${abilityName}\nhurt its attacker!`); } } @@ -562,7 +564,7 @@ export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr { this.weatherType = weatherType; } - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (!pokemon.scene.arena.weather?.isImmutable()) return pokemon.scene.arena.trySetWeather(this.weatherType, true); @@ -571,20 +573,20 @@ export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr { } export class PreAttackAbAttr extends AbAttr { - applyPreAttack(pokemon: Pokemon, defender: Pokemon, move: PokemonMove, args: any[]): boolean | Promise { + applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean | Promise { return false; } } export class VariableMovePowerAbAttr extends PreAttackAbAttr { - applyPreAttack(pokemon: Pokemon, defender: Pokemon, move: PokemonMove, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean { //const power = args[0] as Utils.NumberHolder; return false; } } export class VariableMoveTypeAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { //const power = args[0] as Utils.IntegerHolder; return false; } @@ -602,7 +604,7 @@ export class MoveTypeChangePowerMultiplierAbAttr extends VariableMoveTypeAbAttr this.powerMultiplier = powerMultiplier; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const type = (args[0] as Utils.IntegerHolder); if (type.value == this.matchType) { type.value = this.newType; @@ -624,7 +626,7 @@ export class MovePowerBoostAbAttr extends VariableMovePowerAbAttr { this.powerMultiplier = powerMultiplier; } - applyPreAttack(pokemon: Pokemon, defender: Pokemon, move: PokemonMove, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean { if (this.condition(pokemon, defender, move.getMove())) { (args[0] as Utils.NumberHolder).value *= this.powerMultiplier; @@ -652,7 +654,7 @@ export class LowHpMoveTypePowerBoostAbAttr extends MoveTypePowerBoostAbAttr { } export class FieldVariableMovePowerAbAttr extends AbAttr { - applyPreAttack(pokemon: Pokemon, defender: Pokemon, move: PokemonMove, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean { //const power = args[0] as Utils.NumberHolder; return false; } @@ -668,7 +670,7 @@ export class FieldMovePowerBoostAbAttr extends FieldVariableMovePowerAbAttr { this.powerMultiplier = powerMultiplier; } - applyPreAttack(pokemon: Pokemon, defender: Pokemon, move: PokemonMove, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, args: any[]): boolean { if (this.condition(pokemon, defender, move.getMove())) { (args[0] as Utils.NumberHolder).value *= this.powerMultiplier; @@ -696,7 +698,7 @@ export class BattleStatMultiplierAbAttr extends AbAttr { this.multiplier = multiplier; } - applyBattleStat(pokemon: Pokemon, battleStat: BattleStat, statValue: Utils.NumberHolder, args: any[]): boolean | Promise { + applyBattleStat(pokemon: Pokemon, passive: boolean, battleStat: BattleStat, statValue: Utils.NumberHolder, args: any[]): boolean | Promise { if (battleStat === this.battleStat) { statValue.value *= this.multiplier; return true; @@ -707,7 +709,7 @@ export class BattleStatMultiplierAbAttr extends AbAttr { } export class PostAttackAbAttr extends AbAttr { - applyPostAttack(pokemon: Pokemon, defender: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean | Promise { + applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean | Promise { return false; } } @@ -721,7 +723,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { this.condition = condition; } - applyPostAttack(pokemon: Pokemon, defender: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): Promise { + applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): Promise { return new Promise(resolve => { if (hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, defender, move.getMove()))) { const heldItems = this.getTargetHeldItems(defender).filter(i => i.getTransferrable(false)); @@ -756,7 +758,7 @@ export class PostAttackContactApplyStatusEffectAbAttr extends PostAttackAbAttr { this.effects = effects; } - applyPostAttack(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostAttack(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) { const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)]; return attacker.trySetStatus(effect, true); @@ -775,7 +777,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { this.condition = condition; } - applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): Promise { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): Promise { return new Promise(resolve => { if (hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, attacker, move.getMove()))) { const heldItems = this.getTargetHeldItems(attacker).filter(i => i.getTransferrable(false)); @@ -800,7 +802,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { } export class PostVictoryAbAttr extends AbAttr { - applyPostVictory(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPostVictory(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { return false; } } @@ -816,7 +818,7 @@ class PostVictoryStatChangeAbAttr extends PostVictoryAbAttr { this.levels = levels; } - applyPostVictory(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPostVictory(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { const stat = typeof this.stat === 'function' ? this.stat(pokemon) : this.stat; @@ -827,7 +829,7 @@ class PostVictoryStatChangeAbAttr extends PostVictoryAbAttr { } export class PostKnockOutAbAttr extends AbAttr { - applyPostKnockOut(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPostKnockOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { return false; } } @@ -843,7 +845,7 @@ export class PostKnockOutStatChangeAbAttr extends PostKnockOutAbAttr { this.levels = levels; } - applyPostKnockOut(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPostKnockOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { const stat = typeof this.stat === 'function' ? this.stat(pokemon) : this.stat; @@ -858,7 +860,7 @@ export class IgnoreOpponentStatChangesAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]) { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]) { (args[0] as Utils.IntegerHolder).value = 0; return true; @@ -866,7 +868,7 @@ export class IgnoreOpponentStatChangesAbAttr extends AbAttr { } export class PostSummonAbAttr extends AbAttr { - applyPostSummon(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { return false; } } @@ -880,7 +882,7 @@ export class PostSummonMessageAbAttr extends PostSummonAbAttr { this.messageFunc = messageFunc; } - applyPostSummon(pokemon: Pokemon, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { pokemon.scene.queueMessage(this.messageFunc(pokemon)); return true; @@ -898,7 +900,7 @@ export class PostSummonAddBattlerTagAbAttr extends PostSummonAbAttr { this.turnCount = turnCount; } - applyPostSummon(pokemon: Pokemon, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { return pokemon.addTag(this.tagType, this.turnCount); } } @@ -918,7 +920,7 @@ export class PostSummonStatChangeAbAttr extends PostSummonAbAttr { this.selfTarget = !!selfTarget; } - applyPostSummon(pokemon: Pokemon, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { const statChangePhases: StatChangePhase[] = []; if (this.selfTarget) @@ -948,7 +950,7 @@ export class PostSummonWeatherChangeAbAttr extends PostSummonAbAttr { this.weatherType = weatherType; } - applyPostSummon(pokemon: Pokemon, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { if (!pokemon.scene.arena.weather?.isImmutable()) return pokemon.scene.arena.trySetWeather(this.weatherType, true); @@ -965,7 +967,7 @@ export class PostSummonTerrainChangeAbAttr extends PostSummonAbAttr { this.terrainType = terrainType; } - applyPostSummon(pokemon: Pokemon, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { return pokemon.scene.arena.trySetTerrain(this.terrainType, true); } } @@ -979,7 +981,7 @@ export class PostSummonFormChangeAbAttr extends PostSummonAbAttr { this.formFunc = formFunc; } - applyPostSummon(pokemon: Pokemon, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { const formIndex = this.formFunc(pokemon); if (formIndex !== pokemon.formIndex) return pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); @@ -993,7 +995,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { super(true); } - applyPostSummon(pokemon: Pokemon, args: any[]): boolean { + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { const targets = pokemon.getOpponents(); let target: Pokemon; if (targets.length > 1) @@ -1025,13 +1027,13 @@ export class PreSwitchOutAbAttr extends AbAttr { super(true); } - applyPreSwitchOut(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { return false; } } export class PreSwitchOutResetStatusAbAttr extends PreSwitchOutAbAttr { - applyPreSwitchOut(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { if (pokemon.status) { pokemon.resetStatus(); pokemon.updateInfo(); @@ -1043,7 +1045,7 @@ export class PreSwitchOutResetStatusAbAttr extends PreSwitchOutAbAttr { } export class PreSwitchOutHealAbAttr extends PreSwitchOutAbAttr { - applyPreSwitchOut(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { if (pokemon.getHpRatio() < 1 ) { const healAmount = Math.floor(pokemon.getMaxHp() * 0.33); pokemon.heal(healAmount); @@ -1056,7 +1058,7 @@ export class PreSwitchOutHealAbAttr extends PreSwitchOutAbAttr { } export class PreStatChangeAbAttr extends AbAttr { - applyPreStatChange(pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -1070,7 +1072,7 @@ export class ProtectStatAbAttr extends PreStatChangeAbAttr { this.protectedStat = protectedStat; } - applyPreStatChange(pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.protectedStat === undefined || stat === this.protectedStat) { cancelled.value = true; return true; @@ -1079,13 +1081,13 @@ export class ProtectStatAbAttr extends PreStatChangeAbAttr { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { - return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nprevents lowering its ${this.protectedStat !== undefined ? getBattleStatName(this.protectedStat) : 'stats'}!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, `'s ${abilityName}\nprevents lowering its ${this.protectedStat !== undefined ? getBattleStatName(this.protectedStat) : 'stats'}!`); } } export class PreSetStatusAbAttr extends AbAttr { - applyPreSetStatus(pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -1099,7 +1101,7 @@ export class StatusEffectImmunityAbAttr extends PreSetStatusAbAttr { this.immuneEffects = immuneEffects; } - applyPreSetStatus(pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (!this.immuneEffects.length || this.immuneEffects.indexOf(effect) > -1) { cancelled.value = true; return true; @@ -1108,13 +1110,13 @@ export class StatusEffectImmunityAbAttr extends PreSetStatusAbAttr { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { - return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nprevents ${this.immuneEffects.length ? getStatusEffectDescriptor(args[0] as StatusEffect) : 'status problems'}!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, `'s ${abilityName}\nprevents ${this.immuneEffects.length ? getStatusEffectDescriptor(args[0] as StatusEffect) : 'status problems'}!`); } } export class PreApplyBattlerTagAbAttr extends AbAttr { - applyPreApplyBattlerTag(pokemon: Pokemon, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -1128,7 +1130,7 @@ export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr { this.immuneTagType = immuneTagType; } - applyPreApplyBattlerTag(pokemon: Pokemon, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreApplyBattlerTag(pokemon: Pokemon, passive: boolean, tag: BattlerTag, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (tag.tagType === this.immuneTagType) { cancelled.value = true; return true; @@ -1137,27 +1139,27 @@ export class BattlerTagImmunityAbAttr extends PreApplyBattlerTagAbAttr { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { - return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nprevents ${(args[0] as BattlerTag).getDescriptor()}!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, `'s ${abilityName}\nprevents ${(args[0] as BattlerTag).getDescriptor()}!`); } } export class BlockCritAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.BooleanHolder).value = true; return true; } } export class BlockNonDirectDamageAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } } export class BlockOneHitKOAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } @@ -1174,7 +1176,7 @@ export class IncrementMovePriorityAbAttr extends AbAttr { this.increaseAmount = increaseAmount; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (!this.moveIncrementFunc(pokemon, args[0] as Move)) return false; @@ -1186,7 +1188,7 @@ export class IncrementMovePriorityAbAttr extends AbAttr { export class IgnoreContactAbAttr extends AbAttr { } export class PreWeatherEffectAbAttr extends AbAttr { - applyPreWeatherEffect(pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -1202,7 +1204,7 @@ export class BlockWeatherDamageAttr extends PreWeatherDamageAbAttr { this.weatherTypes = weatherTypes; } - applyPreWeatherEffect(pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (!this.weatherTypes.length || this.weatherTypes.indexOf(weather?.weatherType) > -1) cancelled.value = true; @@ -1219,7 +1221,7 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr { this.affectsImmutable = affectsImmutable; } - applyPreWeatherEffect(pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { + applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.affectsImmutable || weather.isImmutable()) { cancelled.value = true; return true; @@ -1239,7 +1241,7 @@ function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition { } export class PostWeatherChangeAbAttr extends AbAttr { - applyPostWeatherChange(pokemon: Pokemon, weather: WeatherType, args: any[]): boolean { + applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean { return false; } } @@ -1257,7 +1259,7 @@ export class PostWeatherChangeAddBattlerTagAttr extends PostWeatherChangeAbAttr this.weatherTypes = weatherTypes; } - applyPostWeatherChange(pokemon: Pokemon, weather: WeatherType, args: any[]): boolean { + applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean { console.log(this.weatherTypes.find(w => weather === w), WeatherType[weather]); if (!this.weatherTypes.find(w => weather === w)) return false; @@ -1275,7 +1277,7 @@ export class PostWeatherLapseAbAttr extends AbAttr { this.weatherTypes = weatherTypes; } - applyPostWeatherLapse(pokemon: Pokemon, weather: Weather, args: any[]): boolean | Promise { + applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean | Promise { return false; } @@ -1293,11 +1295,12 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr { this.healFactor = healFactor; } - applyPostWeatherLapse(pokemon: Pokemon, weather: Weather, args: any[]): boolean { + applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean { if (pokemon.getHpRatio() < 1) { 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() / (16 / this.healFactor)), 1), getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nrestored its HP a little!`), true)); + Math.max(Math.floor(pokemon.getMaxHp() / (16 / this.healFactor)), 1), getPokemonMessage(pokemon, `'s ${abilityName}\nrestored its HP a little!`), true)); return true; } @@ -1314,10 +1317,11 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr { this.damageFactor = damageFactor; } - applyPostWeatherLapse(pokemon: Pokemon, weather: Weather, args: any[]): boolean { + applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean { if (pokemon.getHpRatio() < 1) { const scene = pokemon.scene; - scene.queueMessage(getPokemonMessage(pokemon, ` is hurt\nby its ${pokemon.getAbility().name}!`)); + 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; } @@ -1327,7 +1331,7 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr { } export class PostTerrainChangeAbAttr extends AbAttr { - applyPostTerrainChange(pokemon: Pokemon, terrain: TerrainType, args: any[]): boolean { + applyPostTerrainChange(pokemon: Pokemon, passive: boolean, terrain: TerrainType, args: any[]): boolean { return false; } } @@ -1345,7 +1349,7 @@ export class PostTerrainChangeAddBattlerTagAttr extends PostTerrainChangeAbAttr this.terrainTypes = terrainTypes; } - applyPostTerrainChange(pokemon: Pokemon, terrain: TerrainType, args: any[]): boolean { + applyPostTerrainChange(pokemon: Pokemon, passive: boolean, terrain: TerrainType, args: any[]): boolean { if (!this.terrainTypes.find(t => terrain === terrain)) return false; @@ -1361,7 +1365,21 @@ function getTerrainCondition(...terrainTypes: TerrainType[]): AbAttrCondition { } export class PostTurnAbAttr extends AbAttr { - applyPostTurn(pokemon: Pokemon, args: any[]): boolean | Promise { + applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + return false; + } +} + +export class PostTurnResetStatusAbAttr extends PostTurnAbAttr { + applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + if (pokemon.status) { + + pokemon.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectHealText(pokemon.status?.effect))); + pokemon.resetStatus(); + pokemon.updateInfo(); + return true; + } + return false; } } @@ -1379,18 +1397,19 @@ export class PostTurnStatChangeAbAttr extends PostTurnAbAttr { this.levels = levels; } - applyPostTurn(pokemon: Pokemon, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); return true; } } export class PostTurnHealAbAttr extends PostTurnAbAttr { - applyPostTurn(pokemon: Pokemon, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { if (pokemon.getHpRatio() < 1) { 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() / 16), 1), getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nrestored its HP a little!`), true)); + Math.max(Math.floor(pokemon.getMaxHp() / 16), 1), getPokemonMessage(pokemon, `'s ${abilityName}\nrestored its HP a little!`), true)); return true; } @@ -1407,7 +1426,7 @@ export class PostTurnFormChangeAbAttr extends PostTurnAbAttr { this.formFunc = formFunc; } - applyPostTurn(pokemon: Pokemon, args: any[]): boolean { + applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { const formIndex = this.formFunc(pokemon); if (formIndex !== pokemon.formIndex) { pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false); @@ -1429,7 +1448,7 @@ export class PostBiomeChangeWeatherChangeAbAttr extends PostBiomeChangeAbAttr { this.weatherType = weatherType; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (!pokemon.scene.arena.weather?.isImmutable()) return pokemon.scene.arena.trySetWeather(this.weatherType, true); @@ -1446,7 +1465,7 @@ export class PostBiomeChangeTerrainChangeAbAttr extends PostBiomeChangeAbAttr { this.terrainType = terrainType; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { return pokemon.scene.arena.trySetTerrain(this.terrainType, true); } } @@ -1460,7 +1479,7 @@ export class StatChangeMultiplierAbAttr extends AbAttr { this.multiplier = multiplier; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.IntegerHolder).value *= this.multiplier; return true; @@ -1472,7 +1491,7 @@ export class BypassBurnDamageReductionAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; @@ -1480,7 +1499,7 @@ export class BypassBurnDamageReductionAbAttr extends AbAttr { } export class DoubleBerryEffectAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.NumberHolder).value *= 2; return true; @@ -1488,7 +1507,7 @@ export class DoubleBerryEffectAbAttr extends AbAttr { } export class PreventBerryUseAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; @@ -1496,7 +1515,7 @@ export class PreventBerryUseAbAttr extends AbAttr { } export class RunSuccessAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.IntegerHolder).value = 256; return true; @@ -1508,24 +1527,24 @@ export class CheckTrappedAbAttr extends AbAttr { super(false); } - applyCheckTrapped(pokemon: Pokemon, trapped: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyCheckTrapped(pokemon: Pokemon, passive: boolean, trapped: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } export class ArenaTrapAbAttr extends CheckTrappedAbAttr { - applyCheckTrapped(pokemon: Pokemon, trapped: Utils.BooleanHolder, args: any[]): boolean { + applyCheckTrapped(pokemon: Pokemon, passive: boolean, trapped: Utils.BooleanHolder, args: any[]): boolean { trapped.value = true; return true; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { - return getPokemonMessage(pokemon, `\'s ${pokemon.getAbility().name}\nprevents switching!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, `\'s ${abilityName}\nprevents switching!`); } } export class MaxMultiHitAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.IntegerHolder).value = 0; return true; @@ -1537,13 +1556,13 @@ export class PostBattleAbAttr extends AbAttr { super(true); } - applyPostBattle(pokemon: Pokemon, args: any[]): boolean { + applyPostBattle(pokemon: Pokemon, passive: boolean, args: any[]): boolean { return false; } } export class PostBattleLootAbAttr extends PostBattleAbAttr { - applyPostBattle(pokemon: Pokemon, args: any[]): boolean { + applyPostBattle(pokemon: Pokemon, passive: boolean, args: any[]): boolean { const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot; if (postBattleLoot.length) { const randItem = Utils.randSeedItem(postBattleLoot); @@ -1559,7 +1578,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr { } export class PostFaintAbAttr extends AbAttr { - applyPostFaint(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { return false; } } @@ -1573,7 +1592,7 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr { this.damageRatio = damageRatio; } - applyPostFaint(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); return true; @@ -1582,13 +1601,13 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr { return false; } - getTriggerMessage(pokemon: Pokemon, ...args: any[]): string { - return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name} hurt\nits attacker!`); + getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + return getPokemonMessage(pokemon, `'s ${abilityName} hurt\nits attacker!`); } } export class RedirectMoveAbAttr extends AbAttr { - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (this.canRedirect(args[0] as Moves)) { const target = args[1] as Utils.IntegerHolder; const newTarget = pokemon.getBattlerIndex(); @@ -1629,7 +1648,7 @@ export class ReduceStatusEffectDurationAbAttr extends AbAttr { this.statusEffect = statusEffect; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { if (args[0] === this.statusEffect) { (args[1] as Utils.IntegerHolder).value = Math.floor((args[1] as Utils.IntegerHolder).value / 2); return true; @@ -1658,18 +1677,20 @@ export class FlinchStatChangeAbAttr extends FlinchEffectAbAttr { this.levels = levels; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.levels)); return true; } } +export class IncreasePpAbAttr extends AbAttr { } + export class ReduceBerryUseThresholdAbAttr extends AbAttr { constructor() { - super(true); + super(); } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { const hpRatio = pokemon.getHpRatio(); if (args[0].value < hpRatio) { @@ -1685,12 +1706,12 @@ export class WeightMultiplierAbAttr extends AbAttr { private multiplier: integer; constructor(multiplier: integer) { - super(true); + super(); this.multiplier = multiplier; } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Utils.NumberHolder).value *= this.multiplier; return true; @@ -1702,7 +1723,7 @@ export class SyncEncounterNatureAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { (args[0] as Pokemon).setNature(pokemon.getNature()); return true; @@ -1714,7 +1735,7 @@ export class MoveAbilityBypassAbAttr extends AbAttr { super(false); } - apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; return true; } @@ -1727,17 +1748,24 @@ export class ProtectAbilityAbAttr extends AbAttr { } function applyAbAttrsInternal(attrType: { new(...args: any[]): TAttr }, - pokemon: Pokemon, applyFunc: AbAttrApplyFunc, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false): Promise { + pokemon: Pokemon, applyFunc: AbAttrApplyFunc, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise { return new Promise(resolve => { - if (!pokemon.canApplyAbility()) - return resolve(); + if (!pokemon.canApplyAbility(passive)) { + if (!passive) + return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve()); + else + return resolve(); + } - const ability = pokemon.getAbility(); + const ability = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()); const attrs = ability.getAttrs(attrType) as TAttr[]; const clearSpliceQueueAndResolve = () => { pokemon.scene.clearPhaseQueueSplice(); - resolve(); + if (!passive) + return applyAbAttrsInternal(attrType, pokemon, applyFunc, args, isAsync, showAbilityInstant, quiet, true).then(() => resolve()); + else + return resolve(); }; const applyNextAbAttr = () => { if (attrs.length) @@ -1752,12 +1780,12 @@ function applyAbAttrsInternal(attrType: { new(...args: any const onApplySuccess = () => { if (attr.showAbility && !quiet) { if (showAbilityInstant) - pokemon.scene.abilityBar.showAbility(pokemon); + pokemon.scene.abilityBar.showAbility(pokemon, passive); else - queueShowAbility(pokemon); + queueShowAbility(pokemon, passive); } if (!quiet) { - const message = attr.getTriggerMessage(pokemon, args); + const message = attr.getTriggerMessage(pokemon, (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name, args); if (message) { if (isAsync) pokemon.scene.ui.showText(message, null, () => pokemon.scene.ui.showText(null, 0), null, true); @@ -1766,7 +1794,7 @@ function applyAbAttrsInternal(attrType: { new(...args: any } } }; - const result = applyFunc(attr); + const result = applyFunc(attr, passive); if (result instanceof Promise) { result.then(success => { if (success) @@ -1784,114 +1812,114 @@ function applyAbAttrsInternal(attrType: { new(...args: any } export function applyAbAttrs(attrType: { new(...args: any[]): AbAttr }, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.apply(pokemon, cancelled, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, cancelled, args), args); } export function applyPostBattleInitAbAttrs(attrType: { new(...args: any[]): PostBattleInitAbAttr }, pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostBattleInit(pokemon, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostBattleInit(pokemon, passive, args), args); } export function applyPreDefendAbAttrs(attrType: { new(...args: any[]): PreDefendAbAttr }, pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { const simulated = args.length > 1 && args[1]; - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPreDefend(pokemon, attacker, move, cancelled, args), args, false, false, simulated); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, false, simulated); } export function applyPostDefendAbAttrs(attrType: { new(...args: any[]): PostDefendAbAttr }, pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostDefend(pokemon, attacker, move, hitResult, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args); } export function applyBattleStatMultiplierAbAttrs(attrType: { new(...args: any[]): BattleStatMultiplierAbAttr }, pokemon: Pokemon, battleStat: BattleStat, statValue: Utils.NumberHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyBattleStat(pokemon, battleStat, statValue, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyBattleStat(pokemon, passive, battleStat, statValue, args), args); } export function applyPreAttackAbAttrs(attrType: { new(...args: any[]): PreAttackAbAttr }, pokemon: Pokemon, defender: Pokemon, move: PokemonMove, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPreAttack(pokemon, defender, move, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args); } export function applyPostAttackAbAttrs(attrType: { new(...args: any[]): PostAttackAbAttr }, pokemon: Pokemon, defender: Pokemon, move: PokemonMove, hitResult: HitResult, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostAttack(pokemon, defender, move, hitResult, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, defender, move, hitResult, args), args); } export function applyPostKnockOutAbAttrs(attrType: { new(...args: any[]): PostKnockOutAbAttr }, pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostKnockOut(pokemon, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostKnockOut(pokemon, passive, args), args); } export function applyPostVictoryAbAttrs(attrType: { new(...args: any[]): PostVictoryAbAttr }, pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostVictory(pokemon, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostVictory(pokemon, passive, args), args); } export function applyPostSummonAbAttrs(attrType: { new(...args: any[]): PostSummonAbAttr }, pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostSummon(pokemon, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostSummon(pokemon, passive, args), args); } export function applyPreSwitchOutAbAttrs(attrType: { new(...args: any[]): PreSwitchOutAbAttr }, pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPreSwitchOut(pokemon, args), args, false, true); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSwitchOut(pokemon, passive, args), args, false, true); } export function applyPreStatChangeAbAttrs(attrType: { new(...args: any[]): PreStatChangeAbAttr }, pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPreStatChange(pokemon, stat, cancelled, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args); } export function applyPreSetStatusAbAttrs(attrType: { new(...args: any[]): PreSetStatusAbAttr }, pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { const simulated = args.length > 1 && args[1]; - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPreSetStatus(pokemon, effect, cancelled, args), args, false, false, !simulated); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, false, !simulated); } export function applyPreApplyBattlerTagAbAttrs(attrType: { new(...args: any[]): PreApplyBattlerTagAbAttr }, pokemon: Pokemon, tag: BattlerTag, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPreApplyBattlerTag(pokemon, tag, cancelled, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreApplyBattlerTag(pokemon, passive, tag, cancelled, args), args); } export function applyPreWeatherEffectAbAttrs(attrType: { new(...args: any[]): PreWeatherEffectAbAttr }, pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPreWeatherEffect(pokemon, weather, cancelled, args), args, false, true); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, false, true); } export function applyPostTurnAbAttrs(attrType: { new(...args: any[]): PostTurnAbAttr }, pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostTurn(pokemon, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostTurn(pokemon, passive, args), args); } export function applyPostWeatherChangeAbAttrs(attrType: { new(...args: any[]): PostWeatherChangeAbAttr }, pokemon: Pokemon, weather: WeatherType, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostWeatherChange(pokemon, weather, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherChange(pokemon, passive, weather, args), args); } export function applyPostWeatherLapseAbAttrs(attrType: { new(...args: any[]): PostWeatherLapseAbAttr }, pokemon: Pokemon, weather: Weather, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostWeatherLapse(pokemon, weather, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, weather, args), args); } export function applyPostTerrainChangeAbAttrs(attrType: { new(...args: any[]): PostTerrainChangeAbAttr }, pokemon: Pokemon, terrain: TerrainType, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostTerrainChange(pokemon, terrain, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostTerrainChange(pokemon, passive, terrain, args), args); } export function applyCheckTrappedAbAttrs(attrType: { new(...args: any[]): CheckTrappedAbAttr }, pokemon: Pokemon, trapped: Utils.BooleanHolder, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyCheckTrapped(pokemon, trapped, args), args, true); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyCheckTrapped(pokemon, passive, trapped, args), args, true); } export function applyPostBattleAbAttrs(attrType: { new(...args: any[]): PostBattleAbAttr }, pokemon: Pokemon, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostBattle(pokemon, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostBattle(pokemon, passive, args), args); } export function applyPostFaintAbAttrs(attrType: { new(...args: any[]): PostFaintAbAttr }, pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, ...args: any[]): Promise { - return applyAbAttrsInternal(attrType, pokemon, attr => attr.applyPostFaint(pokemon, attacker, move, hitResult, args), args); + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, attacker, move, hitResult, args), args); } function canApplyAttr(pokemon: Pokemon, attr: AbAttr): boolean { @@ -1899,325 +1927,11 @@ function canApplyAttr(pokemon: Pokemon, attr: AbAttr): boolean { return !condition || condition(pokemon); } -function queueShowAbility(pokemon: Pokemon): void { - pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id)); +function queueShowAbility(pokemon: Pokemon, passive: boolean): void { + pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, passive)); pokemon.scene.clearPhaseQueueSplice(); } -export enum Abilities { - NONE, - STENCH, - DRIZZLE, - SPEED_BOOST, - BATTLE_ARMOR, - STURDY, - DAMP, - LIMBER, - SAND_VEIL, - STATIC, - VOLT_ABSORB, - WATER_ABSORB, - OBLIVIOUS, - CLOUD_NINE, - COMPOUND_EYES, - INSOMNIA, - COLOR_CHANGE, - IMMUNITY, - FLASH_FIRE, - SHIELD_DUST, - OWN_TEMPO, - SUCTION_CUPS, - INTIMIDATE, - SHADOW_TAG, - ROUGH_SKIN, - WONDER_GUARD, - LEVITATE, - EFFECT_SPORE, - SYNCHRONIZE, - CLEAR_BODY, - NATURAL_CURE, - LIGHTNING_ROD, - SERENE_GRACE, - SWIFT_SWIM, - CHLOROPHYLL, - ILLUMINATE, - TRACE, - HUGE_POWER, - POISON_POINT, - INNER_FOCUS, - MAGMA_ARMOR, - WATER_VEIL, - MAGNET_PULL, - SOUNDPROOF, - RAIN_DISH, - SAND_STREAM, - PRESSURE, - THICK_FAT, - EARLY_BIRD, - FLAME_BODY, - RUN_AWAY, - KEEN_EYE, - HYPER_CUTTER, - PICKUP, - TRUANT, - HUSTLE, - CUTE_CHARM, - PLUS, - MINUS, - FORECAST, - STICKY_HOLD, - SHED_SKIN, - GUTS, - MARVEL_SCALE, - LIQUID_OOZE, - OVERGROW, - BLAZE, - TORRENT, - SWARM, - ROCK_HEAD, - DROUGHT, - ARENA_TRAP, - VITAL_SPIRIT, - WHITE_SMOKE, - PURE_POWER, - SHELL_ARMOR, - AIR_LOCK, - TANGLED_FEET, - MOTOR_DRIVE, - RIVALRY, - STEADFAST, - SNOW_CLOAK, - GLUTTONY, - ANGER_POINT, - UNBURDEN, - HEATPROOF, - SIMPLE, - DRY_SKIN, - DOWNLOAD, - IRON_FIST, - POISON_HEAL, - ADAPTABILITY, - SKILL_LINK, - HYDRATION, - SOLAR_POWER, - QUICK_FEET, - NORMALIZE, - SNIPER, - MAGIC_GUARD, - NO_GUARD, - STALL, - TECHNICIAN, - LEAF_GUARD, - KLUTZ, - MOLD_BREAKER, - SUPER_LUCK, - AFTERMATH, - ANTICIPATION, - FOREWARN, - UNAWARE, - TINTED_LENS, - FILTER, - SLOW_START, - SCRAPPY, - STORM_DRAIN, - ICE_BODY, - SOLID_ROCK, - SNOW_WARNING, - HONEY_GATHER, - FRISK, - RECKLESS, - MULTITYPE, - FLOWER_GIFT, - BAD_DREAMS, - PICKPOCKET, - SHEER_FORCE, - CONTRARY, - UNNERVE, - DEFIANT, - DEFEATIST, - CURSED_BODY, - HEALER, - FRIEND_GUARD, - WEAK_ARMOR, - HEAVY_METAL, - LIGHT_METAL, - MULTISCALE, - TOXIC_BOOST, - FLARE_BOOST, - HARVEST, - TELEPATHY, - MOODY, - OVERCOAT, - POISON_TOUCH, - REGENERATOR, - BIG_PECKS, - SAND_RUSH, - WONDER_SKIN, - ANALYTIC, - ILLUSION, - IMPOSTER, - INFILTRATOR, - MUMMY, - MOXIE, - JUSTIFIED, - RATTLED, - MAGIC_BOUNCE, - SAP_SIPPER, - PRANKSTER, - SAND_FORCE, - IRON_BARBS, - ZEN_MODE, - VICTORY_STAR, - TURBOBLAZE, - TERAVOLT, - AROMA_VEIL, - FLOWER_VEIL, - CHEEK_POUCH, - PROTEAN, - FUR_COAT, - MAGICIAN, - BULLETPROOF, - COMPETITIVE, - STRONG_JAW, - REFRIGERATE, - SWEET_VEIL, - STANCE_CHANGE, - GALE_WINGS, - MEGA_LAUNCHER, - GRASS_PELT, - SYMBIOSIS, - TOUGH_CLAWS, - PIXILATE, - GOOEY, - AERILATE, - PARENTAL_BOND, - DARK_AURA, - FAIRY_AURA, - AURA_BREAK, - PRIMORDIAL_SEA, - DESOLATE_LAND, - DELTA_STREAM, - STAMINA, - WIMP_OUT, - EMERGENCY_EXIT, - WATER_COMPACTION, - MERCILESS, - SHIELDS_DOWN, - STAKEOUT, - WATER_BUBBLE, - STEELWORKER, - BERSERK, - SLUSH_RUSH, - LONG_REACH, - LIQUID_VOICE, - TRIAGE, - GALVANIZE, - SURGE_SURFER, - SCHOOLING, - DISGUISE, - BATTLE_BOND, - POWER_CONSTRUCT, - CORROSION, - COMATOSE, - QUEENLY_MAJESTY, - INNARDS_OUT, - DANCER, - BATTERY, - FLUFFY, - DAZZLING, - SOUL_HEART, - TANGLING_HAIR, - RECEIVER, - POWER_OF_ALCHEMY, - BEAST_BOOST, - RKS_SYSTEM, - ELECTRIC_SURGE, - PSYCHIC_SURGE, - MISTY_SURGE, - GRASSY_SURGE, - FULL_METAL_BODY, - SHADOW_SHIELD, - PRISM_ARMOR, - NEUROFORCE, - INTREPID_SWORD, - DAUNTLESS_SHIELD, - LIBERO, - BALL_FETCH, - COTTON_DOWN, - PROPELLER_TAIL, - MIRROR_ARMOR, - GULP_MISSILE, - STALWART, - STEAM_ENGINE, - PUNK_ROCK, - SAND_SPIT, - ICE_SCALES, - RIPEN, - ICE_FACE, - POWER_SPOT, - MIMICRY, - SCREEN_CLEANER, - STEELY_SPIRIT, - PERISH_BODY, - WANDERING_SPIRIT, - GORILLA_TACTICS, - NEUTRALIZING_GAS, - PASTEL_VEIL, - HUNGER_SWITCH, - QUICK_DRAW, - UNSEEN_FIST, - CURIOUS_MEDICINE, - TRANSISTOR, - DRAGONS_MAW, - CHILLING_NEIGH, - GRIM_NEIGH, - AS_ONE_GLASTRIER, - AS_ONE_SPECTRIER, - LINGERING_AROMA, - SEED_SOWER, - THERMAL_EXCHANGE, - ANGER_SHELL, - PURIFYING_SALT, - WELL_BAKED_BODY, - WIND_RIDER, - GUARD_DOG, - ROCKY_PAYLOAD, - WIND_POWER, - ZERO_TO_HERO, - COMMANDER, - ELECTROMORPHOSIS, - PROTOSYNTHESIS, - QUARK_DRIVE, - GOOD_AS_GOLD, - VESSEL_OF_RUIN, - SWORD_OF_RUIN, - TABLETS_OF_RUIN, - BEADS_OF_RUIN, - ORICHALCUM_PULSE, - HADRON_ENGINE, - OPPORTUNIST, - CUD_CHEW, - SHARPNESS, - SUPREME_OVERLORD, - COSTAR, - TOXIC_DEBRIS, - ARMOR_TAIL, - EARTH_EATER, - MYCELIUM_MIGHT, - MINDS_EYE, - SUPERSWEET_SYRUP, - HOSPITALITY, - TOXIC_CHAIN, - EMBODY_ASPECT_TEAL, - EMBODY_ASPECT_WELLSPRING, - EMBODY_ASPECT_HEARTHFLAME, - EMBODY_ASPECT_CORNERSTONE, - TERA_SHIFT, - TERA_SHELL, - TERAFORM_ZERO, - POISON_PUPPETEER -}; - export const allAbilities = [ new Ability(Abilities.NONE, "-", "", 3) ]; export function initAbilities() { @@ -2285,7 +1999,7 @@ export function initAbilities() { new Ability(Abilities.ROUGH_SKIN, "Rough Skin", "This Pokémon inflicts damage with its rough skin to the attacker on contact.", 3) .attr(PostDefendContactDamageAbAttr, 8) .ignorable() - .passive(), + .bypassFaint(), new Ability(Abilities.WONDER_GUARD, "Wonder Guard", "Its mysterious power only lets supereffective moves hit the Pokémon.", 3) .attr(NonSuperEffectiveImmunityAbAttr) .attr(ProtectAbilityAbAttr) @@ -2374,9 +2088,10 @@ export function initAbilities() { new Ability(Abilities.FORECAST, "Forecast (N)", "The Pokémon transforms with the weather to change its type to Water, Fire, or Ice.", 3), new Ability(Abilities.STICKY_HOLD, "Sticky Hold", "Items held by the Pokémon are stuck fast and cannot be removed by other Pokémon.", 3) .attr(BlockItemTheftAbAttr) - .passive() + .bypassFaint() .ignorable(), - new Ability(Abilities.SHED_SKIN, "Shed Skin (N)", "The Pokémon may heal its own status conditions by shedding its skin.", 3), + new Ability(Abilities.SHED_SKIN, "Shed Skin", "The Pokémon may heal its own status conditions by shedding its skin.", 3) + .conditionalAttr(pokemon => !Utils.randSeedInt(3), PostTurnResetStatusAbAttr), new Ability(Abilities.GUTS, "Guts", "It's so gutsy that having a status condition boosts the Pokémon's Attack stat.", 3) .attr(BypassBurnDamageReductionAbAttr) .conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.ATK, 1.5), @@ -2451,7 +2166,9 @@ export function initAbilities() { .attr(StabBoostAbAttr), new Ability(Abilities.SKILL_LINK, "Skill Link", "Maximizes the number of times multistrike moves hit.", 4) .attr(MaxMultiHitAbAttr), - new Ability(Abilities.HYDRATION, "Hydration (N)", "Heals status conditions if it's raining.", 4), + new Ability(Abilities.HYDRATION, "Hydration", "Heals status conditions if it's raining.", 4) + .attr(PostTurnResetStatusAbAttr) + .condition(getWeatherCondition(WeatherType.RAIN, WeatherType.HEAVY_RAIN)), new Ability(Abilities.SOLAR_POWER, "Solar Power", "Boosts the Sp. Atk stat in harsh sunlight, but HP decreases every turn.", 4) .attr(PostWeatherLapseDamageAbAttr, 2, WeatherType.SUNNY, WeatherType.HARSH_SUN) .attr(BattleStatMultiplierAbAttr, BattleStat.SPATK, 1.5) @@ -2476,7 +2193,7 @@ export function initAbilities() { new Ability(Abilities.SUPER_LUCK, "Super Luck (N)", "The Pokémon is so lucky that the critical-hit ratios of its moves are boosted.", 4), new Ability(Abilities.AFTERMATH, "Aftermath", "Damages the attacker if it contacts the Pokémon with a finishing hit.", 4) .attr(PostFaintContactDamageAbAttr,4) - .passive(), + .bypassFaint(), new Ability(Abilities.ANTICIPATION, "Anticipation (N)", "The Pokémon can sense an opposing Pokémon's dangerous moves.", 4), new Ability(Abilities.FOREWARN, "Forewarn (N)", "When it enters a battle, the Pokémon can tell one of the moves an opposing Pokémon has.", 4), new Ability(Abilities.UNAWARE, "Unaware", "When attacking, the Pokémon ignores the target Pokémon's stat changes.", 4) @@ -2596,7 +2313,7 @@ export function initAbilities() { .condition(getWeatherCondition(WeatherType.SANDSTORM)), new Ability(Abilities.IRON_BARBS, "Iron Barbs", "Inflicts damage on the attacker upon contact with iron barbs.", 5) .attr(PostDefendContactDamageAbAttr, 8) - .passive(), + .bypassFaint(), new Ability(Abilities.ZEN_MODE, "Zen Mode", "Changes the Pokémon's shape when HP is half or less.", 5) .attr(PostBattleInitFormChangeAbAttr, p => p.getHpRatio() >= 0.5 ? 0 : 1) .attr(PostSummonFormChangeAbAttr, p => p.getHpRatio() >= 0.5 ? 0 : 1) diff --git a/src/data/api.ts b/src/data/api.ts index aee0ece9581..9d342dab288 100644 --- a/src/data/api.ts +++ b/src/data/api.ts @@ -5,7 +5,8 @@ import fs from 'vite-plugin-fs/browser'; import PokemonSpecies, { PokemonForm, SpeciesFormKey, allSpecies } from './pokemon-species'; import { GrowthRate } from './exp'; import { Type } from './type'; -import { Abilities, allAbilities } from './ability'; +import { allAbilities } from './ability'; +import { Abilities } from "./enums/abilities"; import { Species } from './enums/species'; import { pokemonFormLevelMoves } from './pokemon-level-moves'; import { tmSpecies } from './tms'; diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index f50ad87d61b..1244d8697e6 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -8,11 +8,13 @@ import * as Utils from "../utils"; import { Moves } from "./enums/moves"; import { ChargeAttr, MoveFlags, allMoves } from "./move"; import { Type } from "./type"; -import { Abilities, BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, applyAbAttrs } from "./ability"; +import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, applyAbAttrs } from "./ability"; +import { Abilities } from "./enums/abilities"; import { BattlerTagType } from "./enums/battler-tag-type"; import { TerrainType } from "./terrain"; import { WeatherType } from "./weather"; import { BattleStat } from "./battle-stat"; +import { allAbilities } from "./ability" export enum BattlerTagLapseType { FAINT, @@ -797,14 +799,15 @@ export class TruantTag extends AbilityBattlerTag { } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if (pokemon.getAbility().id !== Abilities.TRUANT) + if ((!pokemon.canApplyAbility() || pokemon.getAbility().id !== Abilities.TRUANT) && (!pokemon.canApplyAbility(true) || pokemon.getPassiveAbility().id !== Abilities.TRUANT)) return super.lapse(pokemon, lapseType); + const passive = pokemon.getAbility().id !== Abilities.TRUANT; const lastMove = pokemon.getLastXMoves().find(() => true); if (lastMove && lastMove.move !== Moves.NONE) { (pokemon.scene.getCurrentPhase() as MovePhase).cancel(); - pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id)); + pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, passive)); pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' is\nloafing around!')); } @@ -824,7 +827,7 @@ export class SlowStartTag extends AbilityBattlerTag { } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if (pokemon.getAbility().id !== this.ability) + if ((!pokemon.canApplyAbility() || pokemon.getAbility().id !== this.ability) && (!pokemon.canApplyAbility(true) || pokemon.getPassiveAbility().id !== this.ability)) this.turnCount = 1; return super.lapse(pokemon, lapseType); @@ -875,7 +878,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag { onRemove(pokemon: Pokemon): void { super.onRemove(pokemon); - pokemon.scene.queueMessage(`The effects of ${getPokemonMessage(pokemon, `'s\n${pokemon.getAbility().name} wore off!`)}`); + pokemon.scene.queueMessage(`The effects of ${getPokemonMessage(pokemon, `'s\n${allAbilities[this.ability].name} wore off!`)}`); } } diff --git a/src/data/enums/abilities.ts b/src/data/enums/abilities.ts new file mode 100644 index 00000000000..4be87d8181b --- /dev/null +++ b/src/data/enums/abilities.ts @@ -0,0 +1,313 @@ +export enum Abilities { + NONE, + STENCH, + DRIZZLE, + SPEED_BOOST, + BATTLE_ARMOR, + STURDY, + DAMP, + LIMBER, + SAND_VEIL, + STATIC, + VOLT_ABSORB, + WATER_ABSORB, + OBLIVIOUS, + CLOUD_NINE, + COMPOUND_EYES, + INSOMNIA, + COLOR_CHANGE, + IMMUNITY, + FLASH_FIRE, + SHIELD_DUST, + OWN_TEMPO, + SUCTION_CUPS, + INTIMIDATE, + SHADOW_TAG, + ROUGH_SKIN, + WONDER_GUARD, + LEVITATE, + EFFECT_SPORE, + SYNCHRONIZE, + CLEAR_BODY, + NATURAL_CURE, + LIGHTNING_ROD, + SERENE_GRACE, + SWIFT_SWIM, + CHLOROPHYLL, + ILLUMINATE, + TRACE, + HUGE_POWER, + POISON_POINT, + INNER_FOCUS, + MAGMA_ARMOR, + WATER_VEIL, + MAGNET_PULL, + SOUNDPROOF, + RAIN_DISH, + SAND_STREAM, + PRESSURE, + THICK_FAT, + EARLY_BIRD, + FLAME_BODY, + RUN_AWAY, + KEEN_EYE, + HYPER_CUTTER, + PICKUP, + TRUANT, + HUSTLE, + CUTE_CHARM, + PLUS, + MINUS, + FORECAST, + STICKY_HOLD, + SHED_SKIN, + GUTS, + MARVEL_SCALE, + LIQUID_OOZE, + OVERGROW, + BLAZE, + TORRENT, + SWARM, + ROCK_HEAD, + DROUGHT, + ARENA_TRAP, + VITAL_SPIRIT, + WHITE_SMOKE, + PURE_POWER, + SHELL_ARMOR, + AIR_LOCK, + TANGLED_FEET, + MOTOR_DRIVE, + RIVALRY, + STEADFAST, + SNOW_CLOAK, + GLUTTONY, + ANGER_POINT, + UNBURDEN, + HEATPROOF, + SIMPLE, + DRY_SKIN, + DOWNLOAD, + IRON_FIST, + POISON_HEAL, + ADAPTABILITY, + SKILL_LINK, + HYDRATION, + SOLAR_POWER, + QUICK_FEET, + NORMALIZE, + SNIPER, + MAGIC_GUARD, + NO_GUARD, + STALL, + TECHNICIAN, + LEAF_GUARD, + KLUTZ, + MOLD_BREAKER, + SUPER_LUCK, + AFTERMATH, + ANTICIPATION, + FOREWARN, + UNAWARE, + TINTED_LENS, + FILTER, + SLOW_START, + SCRAPPY, + STORM_DRAIN, + ICE_BODY, + SOLID_ROCK, + SNOW_WARNING, + HONEY_GATHER, + FRISK, + RECKLESS, + MULTITYPE, + FLOWER_GIFT, + BAD_DREAMS, + PICKPOCKET, + SHEER_FORCE, + CONTRARY, + UNNERVE, + DEFIANT, + DEFEATIST, + CURSED_BODY, + HEALER, + FRIEND_GUARD, + WEAK_ARMOR, + HEAVY_METAL, + LIGHT_METAL, + MULTISCALE, + TOXIC_BOOST, + FLARE_BOOST, + HARVEST, + TELEPATHY, + MOODY, + OVERCOAT, + POISON_TOUCH, + REGENERATOR, + BIG_PECKS, + SAND_RUSH, + WONDER_SKIN, + ANALYTIC, + ILLUSION, + IMPOSTER, + INFILTRATOR, + MUMMY, + MOXIE, + JUSTIFIED, + RATTLED, + MAGIC_BOUNCE, + SAP_SIPPER, + PRANKSTER, + SAND_FORCE, + IRON_BARBS, + ZEN_MODE, + VICTORY_STAR, + TURBOBLAZE, + TERAVOLT, + AROMA_VEIL, + FLOWER_VEIL, + CHEEK_POUCH, + PROTEAN, + FUR_COAT, + MAGICIAN, + BULLETPROOF, + COMPETITIVE, + STRONG_JAW, + REFRIGERATE, + SWEET_VEIL, + STANCE_CHANGE, + GALE_WINGS, + MEGA_LAUNCHER, + GRASS_PELT, + SYMBIOSIS, + TOUGH_CLAWS, + PIXILATE, + GOOEY, + AERILATE, + PARENTAL_BOND, + DARK_AURA, + FAIRY_AURA, + AURA_BREAK, + PRIMORDIAL_SEA, + DESOLATE_LAND, + DELTA_STREAM, + STAMINA, + WIMP_OUT, + EMERGENCY_EXIT, + WATER_COMPACTION, + MERCILESS, + SHIELDS_DOWN, + STAKEOUT, + WATER_BUBBLE, + STEELWORKER, + BERSERK, + SLUSH_RUSH, + LONG_REACH, + LIQUID_VOICE, + TRIAGE, + GALVANIZE, + SURGE_SURFER, + SCHOOLING, + DISGUISE, + BATTLE_BOND, + POWER_CONSTRUCT, + CORROSION, + COMATOSE, + QUEENLY_MAJESTY, + INNARDS_OUT, + DANCER, + BATTERY, + FLUFFY, + DAZZLING, + SOUL_HEART, + TANGLING_HAIR, + RECEIVER, + POWER_OF_ALCHEMY, + BEAST_BOOST, + RKS_SYSTEM, + ELECTRIC_SURGE, + PSYCHIC_SURGE, + MISTY_SURGE, + GRASSY_SURGE, + FULL_METAL_BODY, + SHADOW_SHIELD, + PRISM_ARMOR, + NEUROFORCE, + INTREPID_SWORD, + DAUNTLESS_SHIELD, + LIBERO, + BALL_FETCH, + COTTON_DOWN, + PROPELLER_TAIL, + MIRROR_ARMOR, + GULP_MISSILE, + STALWART, + STEAM_ENGINE, + PUNK_ROCK, + SAND_SPIT, + ICE_SCALES, + RIPEN, + ICE_FACE, + POWER_SPOT, + MIMICRY, + SCREEN_CLEANER, + STEELY_SPIRIT, + PERISH_BODY, + WANDERING_SPIRIT, + GORILLA_TACTICS, + NEUTRALIZING_GAS, + PASTEL_VEIL, + HUNGER_SWITCH, + QUICK_DRAW, + UNSEEN_FIST, + CURIOUS_MEDICINE, + TRANSISTOR, + DRAGONS_MAW, + CHILLING_NEIGH, + GRIM_NEIGH, + AS_ONE_GLASTRIER, + AS_ONE_SPECTRIER, + LINGERING_AROMA, + SEED_SOWER, + THERMAL_EXCHANGE, + ANGER_SHELL, + PURIFYING_SALT, + WELL_BAKED_BODY, + WIND_RIDER, + GUARD_DOG, + ROCKY_PAYLOAD, + WIND_POWER, + ZERO_TO_HERO, + COMMANDER, + ELECTROMORPHOSIS, + PROTOSYNTHESIS, + QUARK_DRIVE, + GOOD_AS_GOLD, + VESSEL_OF_RUIN, + SWORD_OF_RUIN, + TABLETS_OF_RUIN, + BEADS_OF_RUIN, + ORICHALCUM_PULSE, + HADRON_ENGINE, + OPPORTUNIST, + CUD_CHEW, + SHARPNESS, + SUPREME_OVERLORD, + COSTAR, + TOXIC_DEBRIS, + ARMOR_TAIL, + EARTH_EATER, + MYCELIUM_MIGHT, + MINDS_EYE, + SUPERSWEET_SYRUP, + HOSPITALITY, + TOXIC_CHAIN, + EMBODY_ASPECT_TEAL, + EMBODY_ASPECT_WELLSPRING, + EMBODY_ASPECT_HEARTHFLAME, + EMBODY_ASPECT_CORNERSTONE, + TERA_SHIFT, + TERA_SHELL, + TERAFORM_ZERO, + POISON_PUPPETEER +} diff --git a/src/data/move.ts b/src/data/move.ts index a296e3b4884..2ba34d488fd 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -12,7 +12,8 @@ import * as Utils from "../utils"; import { WeatherType } from "./weather"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagType } from "./enums/arena-tag-type"; -import { Abilities, ProtectAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr } from "./ability"; +import { ProtectAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr } from "./ability"; +import { Abilities } from "./enums/abilities"; import { PokemonHeldItemModifier } from "../modifier/modifier"; import { BattlerIndex } from "../battle"; import { Stat } from "./pokemon-stat"; @@ -271,7 +272,7 @@ export default class Move { checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean { switch (flag) { case MoveFlags.MAKES_CONTACT: - if (user.getAbility().hasAttr(IgnoreContactAbAttr)) + if ((user.canApplyAbility() && user.getAbility().hasAttr(IgnoreContactAbAttr)) || (user.canApplyAbility(true) && user.getPassiveAbility().hasAttr(IgnoreContactAbAttr))) return false; break; } @@ -1898,6 +1899,57 @@ export class BlizzardAccuracyAttr extends VariableAccuracyAttr { } } +export class VariableMoveCategoryAttr extends MoveAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + return false; + } +} + +export class PhotonGeyserCategoryAttr extends VariableMoveCategoryAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const category = (args[0] as Utils.IntegerHolder); + + if (user.getBattleStat(Stat.ATK, target, move) > user.getBattleStat(Stat.SPATK, target, move)) { + category.value = MoveCategory.PHYSICAL; + return true; + } + + return false; + } +} + +export class TeraBlastCategoryAttr extends VariableMoveCategoryAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const category = (args[0] as Utils.IntegerHolder); + + if (user.isTerastallized() && user.getBattleStat(Stat.ATK, target, move) > user.getBattleStat(Stat.SPATK, target, move)) { + category.value = MoveCategory.PHYSICAL; + return true; + } + + return false; + } +} + +export class ShellSideArmCategoryAttr extends VariableMoveCategoryAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const category = (args[0] as Utils.IntegerHolder); + const atkRatio = user.getBattleStat(Stat.ATK, target, move) / target.getBattleStat(Stat.DEF, user, move); + const specialRatio = user.getBattleStat(Stat.SPATK, target, move) / target.getBattleStat(Stat.SPDEF, user, move); + + // Shell Side Arm is much more complicated than it looks, this is a partial implementation to try to achieve something similar to the games + if (atkRatio > specialRatio) { + category.value = MoveCategory.PHYSICAL; + return true; + } else if (atkRatio === specialRatio && user.randSeedInt(2) === 0) { + category.value = MoveCategory.PHYSICAL; + return true; + } + + return false; + } +} + export class VariableMoveTypeAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { return false; @@ -4453,9 +4505,9 @@ export function initMoves() { .attr(StatChangeAttr, [ BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true) .ignoresVirtual(), new StatusMove(Moves.MAGNETIC_FLUX, "Magnetic Flux", Type.ELECTRIC, -1, 20, "The user manipulates magnetic fields, which raises the Defense and Sp. Def stats of ally Pokémon with the Plus or Minus Ability.", -1, 0, 6) - .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, false, (user, target, move) => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === user.getAbility().id)) + .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, false, (user, target, move) => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === user.getAbility().id || (user.canApplyPassive() && a === user.getPassiveAbility().id))) .target(MoveTarget.USER_AND_ALLIES) - .condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === p.getAbility().id))), + .condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === p.getAbility().id || (user.canApplyPassive() && a === user.getPassiveAbility().id)))), new StatusMove(Moves.HAPPY_HOUR, "Happy Hour (N)", Type.NORMAL, -1, 30, "Using Happy Hour doubles the amount of prize money received after battle.", -1, 0, 6) // No animation .target(MoveTarget.USER_SIDE), new StatusMove(Moves.ELECTRIC_TERRAIN, "Electric Terrain", Type.ELECTRIC, -1, 10, "The user electrifies the ground for five turns, powering up Electric-type moves. Pokémon on the ground no longer fall asleep.", -1, 0, 6) @@ -4580,9 +4632,9 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.SPD, -1), new SelfStatusMove(Moves.LASER_FOCUS, "Laser Focus (N)", Type.NORMAL, -1, 30, "The user concentrates intensely. The attack on the next turn always results in a critical hit.", -1, 0, 7), new StatusMove(Moves.GEAR_UP, "Gear Up", Type.STEEL, -1, 20, "The user engages its gears to raise the Attack and Sp. Atk stats of ally Pokémon with the Plus or Minus Ability.", -1, 0, 7) - .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, false, (user, target, move) => [ Abilities.PLUS, Abilities.MINUS ].indexOf(target.getAbility().id) > -1) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, false, (user, target, move) => [ Abilities.PLUS, Abilities.MINUS ].includes(target.getAbility().id) || (target.canApplyPassive() && [ Abilities.PLUS, Abilities.MINUS ].includes(target.getPassiveAbility().id))) .target(MoveTarget.USER_AND_ALLIES) - .condition((user, target, move) => !![ user, user.getAlly() ].find(p => p && [ Abilities.PLUS, Abilities.MINUS ].indexOf(p.getAbility().id) > -1)), + .condition((user, target, move) => !![ user, user.getAlly() ].find(p => p && [ Abilities.PLUS, Abilities.MINUS ].includes(p.getAbility().id) || (target.canApplyPassive() && [ Abilities.PLUS, Abilities.MINUS ].includes(target.getPassiveAbility().id)))), new AttackMove(Moves.THROAT_CHOP, "Throat Chop (P)", Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, "The user attacks the target's throat, and the resultant suffering prevents the target from using moves that emit sound for two turns.", 100, 0, 7), new AttackMove(Moves.POLLEN_PUFF, "Pollen Puff (P)", Type.BUG, MoveCategory.SPECIAL, 90, 100, 15, "The user attacks the enemy with a pollen puff that explodes. If the target is an ally, it gives the ally a pollen puff that restores its HP instead.", -1, 0, 7) .ballBombMove(), @@ -4672,9 +4724,11 @@ export function initMoves() { .target(MoveTarget.ALL_NEAR_OTHERS), new AttackMove(Moves.PLASMA_FISTS, "Plasma Fists (P)", Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 100, 15, "The user attacks with electrically charged fists. This move changes Normal-type moves to Electric-type moves.", -1, 0, 7) .punchingMove(), - new AttackMove(Moves.PHOTON_GEYSER, "Photon Geyser (P)", Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, "The user attacks a target with a pillar of light. This move inflicts Attack or Sp. Atk damage—whichever stat is higher for the user.", -1, 0, 7), + new AttackMove(Moves.PHOTON_GEYSER, "Photon Geyser (P)", Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, "The user attacks a target with a pillar of light. This move inflicts Attack or Sp. Atk damage—whichever stat is higher for the user.", -1, 0, 7) + .attr(PhotonGeyserCategoryAttr), /* Unused */ - new AttackMove(Moves.LIGHT_THAT_BURNS_THE_SKY, "Light That Burns the Sky (P)", Type.PSYCHIC, MoveCategory.SPECIAL, 200, -1, 1, "This attack inflicts Attack or Sp. Atk damage—whichever stat is higher for the user, Necrozma. This move ignores the target's Ability.", -1, 0, 7), + new AttackMove(Moves.LIGHT_THAT_BURNS_THE_SKY, "Light That Burns the Sky (P)", Type.PSYCHIC, MoveCategory.SPECIAL, 200, -1, 1, "This attack inflicts Attack or Sp. Atk damage—whichever stat is higher for the user, Necrozma. This move ignores the target's Ability.", -1, 0, 7) + .attr(PhotonGeyserCategoryAttr), new AttackMove(Moves.SEARING_SUNRAZE_SMASH, "Searing Sunraze Smash (P)", Type.STEEL, MoveCategory.PHYSICAL, 200, -1, 1, "After obtaining Z-Power, the user, Solgaleo, attacks the target with full force. This move can ignore the effect of the target's Ability.", -1, 0, 7), new AttackMove(Moves.MENACING_MOONRAZE_MAELSTROM, "Menacing Moonraze Maelstrom (P)", Type.GHOST, MoveCategory.SPECIAL, 200, -1, 1, "After obtaining Z-Power, the user, Lunala, attacks the target with full force. This move can ignore the effect of the target's Ability.", -1, 0, 7), new AttackMove(Moves.LETS_SNUGGLE_FOREVER, "Let's Snuggle Forever (P)", Type.FAIRY, MoveCategory.PHYSICAL, 190, -1, 1, "After obtaining Z-Power, the user, Mimikyu, punches the target with full force.", -1, 0, 7), @@ -4855,7 +4909,9 @@ export function initMoves() { .attr(ChargeAttr, ChargeAnim.METEOR_BEAM_CHARGING, 'is overflowing\nwith space power!', null, true) .attr(StatChangeAttr, BattleStat.SPATK, 1, true) .ignoresVirtual(), - new AttackMove(Moves.SHELL_SIDE_ARM, "Shell Side Arm (P)", Type.POISON, MoveCategory.SPECIAL, 90, 100, 10, "This move inflicts physical or special damage, whichever will be more effective. This may also poison the target.", 20, 0, 8), + new AttackMove(Moves.SHELL_SIDE_ARM, "Shell Side Arm (P)", Type.POISON, MoveCategory.SPECIAL, 90, 100, 10, "This move inflicts physical or special damage, whichever will be more effective. This may also poison the target.", 20, 0, 8) + .attr(ShellSideArmCategoryAttr) + .attr(StatusEffectAttr, StatusEffect.POISON), new AttackMove(Moves.MISTY_EXPLOSION, "Misty Explosion (P)", Type.FAIRY, MoveCategory.SPECIAL, 100, 100, 5, "The user attacks everything around it and faints upon using this move. This move's power is increased on Misty Terrain.", -1, 0, 8) .target(MoveTarget.ALL_NEAR_OTHERS), new AttackMove(Moves.GRASSY_GLIDE, "Grassy Glide (P)", Type.GRASS, MoveCategory.PHYSICAL, 55, 100, 20, "Gliding on the ground, the user attacks the target. This move always goes first on Grassy Terrain.", -1, 0, 8), @@ -5057,7 +5113,8 @@ export function initMoves() { new AttackMove(Moves.G_MAX_RAPID_FLOW, "G-Max Rapid Flow (N)", Type.WATER, MoveCategory.PHYSICAL, 10, -1, 10, "A Water-type attack that Gigantamax Urshifu use. This rapid-strike move can ignore Max Guard.", -1, 0, 8) .target(MoveTarget.ALL_NEAR_ENEMIES), End Unused */ - new AttackMove(Moves.TERA_BLAST, "Tera Blast (P)", Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, "If the user has Terastallized, it unleashes energy of its Tera Type. This move inflicts damage using the Attack or Sp. Atk stat-whichever is higher for the user.", -1, 0, 9), + new AttackMove(Moves.TERA_BLAST, "Tera Blast (P)", Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, "If the user has Terastallized, it unleashes energy of its Tera Type. This move inflicts damage using the Attack or Sp. Atk stat-whichever is higher for the user.", -1, 0, 9) + .attr(TeraBlastCategoryAttr), new SelfStatusMove(Moves.SILK_TRAP, "Silk Trap", Type.BUG, -1, 10, "The user spins a silken trap, protecting itself from damage while lowering the Speed stat of any attacker that makes direct contact.", -1, 4, 9) .attr(ProtectAttr, BattlerTagType.SILK_TRAP), new AttackMove(Moves.AXE_KICK, "Axe Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 120, 90, 10, "The user attacks by kicking up into the air and slamming its heel down upon the target. This may also confuse the target. If it misses, the user takes damage instead.", 30, 0, 9) @@ -5193,7 +5250,8 @@ export function initMoves() { .attr(ElectroShotChargeAttr) .attr(StatChangeAttr, BattleStat.SPATK, 1, true) .ignoresVirtual(), - new AttackMove(Moves.TERA_STARSTORM, "Tera Starstorm (P)", Type.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, "With the power of its crystals, the user bombards and eliminates the target. When used by Terapagos in its Stellar Form, this move damages all opposing Pokémon.", -1, 0, 9), + new AttackMove(Moves.TERA_STARSTORM, "Tera Starstorm (P)", Type.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, "With the power of its crystals, the user bombards and eliminates the target. When used by Terapagos in its Stellar Form, this move damages all opposing Pokémon.", -1, 0, 9) + .attr(TeraBlastCategoryAttr), new AttackMove(Moves.FICKLE_BEAM, "Fickle Beam", Type.DRAGON, MoveCategory.SPECIAL, 80, 100, 5, "The user shoots a beam of light to inflict damage. Sometimes all the user's heads shoot beams in unison, doubling the move's power.", 30, 0, 9) .attr(PreMoveMessageAttr, doublePowerChanceMessageFunc) .attr(DoublePowerChanceAttr), diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 63f85ae42d8..e5bcf25a4fe 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -6,7 +6,7 @@ import { SpeciesFormKey } from "./pokemon-species"; import { Species } from "./enums/species"; import { StatusEffect } from "./status-effect"; import { MoveCategory, allMoves } from "./move"; -import { Abilities } from "./ability"; +import { Abilities } from "./enums/abilities"; export enum FormChangeItem { NONE, diff --git a/src/data/pokemon-level-moves.ts b/src/data/pokemon-level-moves.ts index bc72a3bd0f5..81fb79660fe 100644 --- a/src/data/pokemon-level-moves.ts +++ b/src/data/pokemon-level-moves.ts @@ -10888,6 +10888,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 91, Moves.SELF_DESTRUCT ], ], [Species.CHESPIN]: [ + [ 1, Moves.TACKLE ], [ 1, Moves.VINE_WHIP ], [ 1, Moves.GROWL ], [ 8, Moves.ROLLOUT ], @@ -10902,6 +10903,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 48, Moves.WOOD_HAMMER ], ], [Species.QUILLADIN]: [ + [ 1, Moves.TACKLE ], [ 1, Moves.VINE_WHIP ], [ 1, Moves.GROWL ], [ 8, Moves.ROLLOUT ], diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 02c259d5075..7f52315cfa7 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -1,4 +1,4 @@ -import { Abilities } from './ability'; +import { Abilities } from "./enums/abilities"; import BattleScene, { AnySound } from '../battle-scene'; import { GrowthRate } from './exp'; import { SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } from './pokemon-evolutions'; @@ -1835,7 +1835,7 @@ export function initSpecies() { new PokemonForm("10% Forme Power Construct", "10-pc", Type.DRAGON, Type.GROUND, 1.2, 33.5, Abilities.POWER_CONSTRUCT, Abilities.NONE, Abilities.NONE, 486, 54, 100, 71, 61, 85, 115, 3, 0, 300, false, "10"), new PokemonForm("Complete Forme", "complete", Type.DRAGON, Type.GROUND, 4.5, 610, Abilities.POWER_CONSTRUCT, Abilities.NONE, Abilities.NONE, 708, 216, 100, 121, 91, 95, 85, 3, 0, 300), ), - new PokemonSpecies(Species.DIANCIE, "Diancie", 6, false, false, true, "Jewel Pokémon", Type.ROCK, Type.FAIRY, 0.7, 8.8, Abilities.CLEAR_BODY, Abilities.NONE, Abilities.NONE, 600, 50, 100, 150, 100, 150, 50, 3, 50, 300, GrowthRate.SLOW, 0, false, true, + new PokemonSpecies(Species.DIANCIE, "Diancie", 6, false, false, true, "Jewel Pokémon", Type.ROCK, Type.FAIRY, 0.7, 8.8, Abilities.CLEAR_BODY, Abilities.NONE, Abilities.NONE, 600, 50, 100, 150, 100, 150, 50, 3, 50, 300, GrowthRate.SLOW, null, false, true, new PokemonForm("Normal", "", Type.ROCK, Type.FAIRY, 0.7, 8.8, Abilities.CLEAR_BODY, Abilities.NONE, Abilities.NONE, 600, 50, 100, 150, 100, 150, 50, 3, 50, 300), new PokemonForm("Mega", SpeciesFormKey.MEGA, Type.ROCK, Type.FAIRY, 1.1, 27.8, Abilities.MAGIC_BOUNCE, Abilities.NONE, Abilities.NONE, 700, 50, 160, 110, 160, 110, 110, 3, 50, 300), ), @@ -3053,6 +3053,578 @@ export const noStarterFormKeys: string[] = [ SpeciesFormKey.ETERNAMAX ].map(k => k.toString()); +export const starterPassiveAbilities = { + [Species.BULBASAUR]: Abilities.SOLAR_POWER, + [Species.CHARMANDER]: Abilities.INTIMIDATE, + [Species.SQUIRTLE]: Abilities.DAUNTLESS_SHIELD, + [Species.CATERPIE]: Abilities.MAGICIAN, + [Species.WEEDLE]: Abilities.POISON_TOUCH, + [Species.PIDGEY]: Abilities.TECHNICIAN, + [Species.RATTATA]: Abilities.STRONG_JAW, + [Species.SPEAROW]: Abilities.MOXIE, + [Species.EKANS]: Abilities.ROUGH_SKIN, + [Species.SANDSHREW]: Abilities.IRON_BARBS, + [Species.NIDORAN_F]: Abilities.QUEENLY_MAJESTY, + [Species.NIDORAN_M]: Abilities.SUPREME_OVERLORD, + [Species.VULPIX]: Abilities.CURSED_BODY, + [Species.ZUBAT]: Abilities.WIND_RIDER, + [Species.ODDISH]: Abilities.LINGERING_AROMA, + [Species.PARAS]: Abilities.POISON_HEAL, + [Species.VENONAT]: Abilities.TECHNICIAN, + [Species.DIGLETT]: Abilities.STURDY, + [Species.MEOWTH]: Abilities.NORMALIZE, + [Species.PSYDUCK]: Abilities.SIMPLE, + [Species.MANKEY]: Abilities.STAMINA, + [Species.GROWLITHE]: Abilities.BALL_FETCH, + [Species.POLIWAG]: Abilities.WATER_BUBBLE, + [Species.ABRA]: Abilities.TECHNICIAN, + [Species.MACHOP]: Abilities.IRON_FIST, + [Species.BELLSPROUT]: Abilities.CORROSION, + [Species.TENTACOOL]: Abilities.INNARDS_OUT, + [Species.GEODUDE]: Abilities.ROCKY_PAYLOAD, + [Species.PONYTA]: Abilities.PIXILATE, + [Species.SLOWPOKE]: Abilities.UNAWARE, + [Species.MAGNEMITE]: Abilities.MOTOR_DRIVE, + [Species.FARFETCHD]: Abilities.PURE_POWER, + [Species.DODUO]: Abilities.RECKLESS, + [Species.SEEL]: Abilities.REGENERATOR, + [Species.GRIMER]: Abilities.GOOEY, + [Species.SHELLDER]: Abilities.MOXIE, + [Species.GASTLY]: Abilities.PERISH_BODY, + [Species.ONIX]: Abilities.ROCKY_PAYLOAD, + [Species.DROWZEE]: Abilities.BAD_DREAMS, + [Species.KRABBY]: Abilities.ANGER_SHELL, + [Species.VOLTORB]: Abilities.GALVANIZE, + [Species.EXEGGCUTE]: Abilities.PARENTAL_BOND, + [Species.CUBONE]: Abilities.MOODY, + [Species.LICKITUNG]: Abilities.EARTH_EATER, + [Species.KOFFING]: Abilities.FLARE_BOOST, + [Species.RHYHORN]: Abilities.FILTER, + [Species.TANGELA]: Abilities.TANGLING_HAIR, + [Species.KANGASKHAN]: Abilities.IRON_FIST, + [Species.HORSEA]: Abilities.DRIZZLE, + [Species.GOLDEEN]: Abilities.VOLT_ABSORB, + [Species.STARYU]: Abilities.REGENERATOR, + [Species.SCYTHER]: Abilities.SPEED_BOOST, + [Species.PINSIR]: Abilities.SAP_SIPPER, + [Species.TAUROS]: Abilities.ROCK_HEAD, + [Species.MAGIKARP]: Abilities.BERSERK, + [Species.LAPRAS]: Abilities.LIQUID_VOICE, + [Species.DITTO]: Abilities.GOOEY, + [Species.EEVEE]: Abilities.PROTEAN, + [Species.PORYGON]: Abilities.QUARK_DRIVE, + [Species.OMANYTE]: Abilities.ANGER_SHELL, + [Species.KABUTO]: Abilities.SHARPNESS, + [Species.AERODACTYL]: Abilities.PROTOSYNTHESIS, + [Species.ARTICUNO]: Abilities.SNOW_WARNING, + [Species.ZAPDOS]: Abilities.DRIZZLE, + [Species.MOLTRES]: Abilities.DROUGHT, + [Species.DRATINI]: Abilities.DELTA_STREAM, + [Species.MEWTWO]: Abilities.BERSERK, + [Species.MEW]: Abilities.PROTEAN, + [Species.CHIKORITA]: Abilities.TRIAGE, + [Species.CYNDAQUIL]: Abilities.TURBOBLAZE, + [Species.TOTODILE]: Abilities.STRONG_JAW, + [Species.SENTRET]: Abilities.FLUFFY, + [Species.HOOTHOOT]: Abilities.CURSED_BODY, + [Species.LEDYBA]: Abilities.SCREEN_CLEANER, + [Species.SPINARAK]: Abilities.PRANKSTER, + [Species.CHINCHOU]: Abilities.REGENERATOR, + [Species.PICHU]: Abilities.TRANSISTOR, + [Species.CLEFFA]: Abilities.TRIAGE, + [Species.IGGLYBUFF]: Abilities.SERENE_GRACE, + [Species.TOGEPI]: Abilities.OPPORTUNIST, + [Species.NATU]: Abilities.TINTED_LENS, + [Species.MAREEP]: Abilities.FLUFFY, + [Species.HOPPIP]: Abilities.PRANKSTER, + [Species.AIPOM]: Abilities.SCRAPPY, + [Species.SUNKERN]: Abilities.DROUGHT, + [Species.YANMA]: Abilities.TECHNICIAN, + [Species.WOOPER]: Abilities.SIMPLE, + [Species.MURKROW]: Abilities.DEFIANT, + [Species.MISDREAVUS]: Abilities.DAZZLING, + [Species.UNOWN]: Abilities.PICKUP, + [Species.GIRAFARIG]: Abilities.PARENTAL_BOND, + [Species.PINECO]: Abilities.IRON_BARBS, + [Species.DUNSPARCE]: Abilities.MARVEL_SCALE, + [Species.GLIGAR]: Abilities.MERCILESS, + [Species.SNUBBULL]: Abilities.BALL_FETCH, + [Species.QWILFISH]: Abilities.LIQUID_OOZE, + [Species.SHUCKLE]: Abilities.WELL_BAKED_BODY, + [Species.HERACROSS]: Abilities.QUICK_FEET, + [Species.SNEASEL]: Abilities.MOXIE, + [Species.TEDDIURSA]: Abilities.GLUTTONY, + [Species.SLUGMA]: Abilities.DESOLATE_LAND, + [Species.SWINUB]: Abilities.SLUSH_RUSH, + [Species.CORSOLA]: Abilities.STORM_DRAIN, + [Species.REMORAID]: Abilities.SKILL_LINK, + [Species.DELIBIRD]: Abilities.PRANKSTER, + [Species.SKARMORY]: Abilities.OBLIVIOUS, + [Species.HOUNDOUR]: Abilities.INTIMIDATE, + [Species.PHANPY]: Abilities.ROCK_HEAD, + [Species.STANTLER]: Abilities.MAGIC_GUARD, + [Species.SMEARGLE]: Abilities.TRACE, + [Species.TYROGUE]: Abilities.STAMINA, + [Species.SMOOCHUM]: Abilities.CUTE_CHARM, + [Species.ELEKID]: Abilities.ADAPTABILITY, + [Species.MAGBY]: Abilities.CONTRARY, + [Species.MILTANK]: Abilities.GLUTTONY, + [Species.RAIKOU]: Abilities.FLARE_BOOST, + [Species.ENTEI]: Abilities.TOXIC_BOOST, + [Species.SUICUNE]: Abilities.SPEED_BOOST, + [Species.LARVITAR]: Abilities.SAND_FORCE, + [Species.LUGIA]: Abilities.STORM_DRAIN, + [Species.HO_OH]: Abilities.FLASH_FIRE, + [Species.CELEBI]: Abilities.TRIAGE, + [Species.TREECKO]: Abilities.GRASSY_SURGE, + [Species.TORCHIC]: Abilities.RECKLESS, + [Species.MUDKIP]: Abilities.REGENERATOR, + [Species.POOCHYENA]: Abilities.STRONG_JAW, + [Species.ZIGZAGOON]: Abilities.PICKPOCKET, + [Species.WURMPLE]: Abilities.TINTED_LENS, + [Species.LOTAD]: Abilities.DRIZZLE, + [Species.SEEDOT]: Abilities.DISGUISE, + [Species.TAILLOW]: Abilities.KEEN_EYE, + [Species.WINGULL]: Abilities.HYDRATION, + [Species.RALTS]: Abilities.PSYCHIC_SURGE, + [Species.SURSKIT]: Abilities.WATER_ABSORB, + [Species.SHROOMISH]: Abilities.GUTS, + [Species.SLAKOTH]: Abilities.GUTS, + [Species.NINCADA]: Abilities.OVERCOAT, + [Species.WHISMUR]: Abilities.PUNK_ROCK, + [Species.MAKUHITA]: Abilities.CONTRARY, + [Species.AZURILL]: Abilities.UNNERVE, + [Species.NOSEPASS]: Abilities.LEVITATE, + [Species.SKITTY]: Abilities.SCRAPPY, + [Species.SABLEYE]: Abilities.UNNERVE, + [Species.MAWILE]: Abilities.MOLD_BREAKER, + [Species.ARON]: Abilities.SOLID_ROCK, + [Species.MEDITITE]: Abilities.OWN_TEMPO, + [Species.ELECTRIKE]: Abilities.SPEED_BOOST, + [Species.PLUSLE]: Abilities.MINUS, + [Species.MINUN]: Abilities.PLUS, + [Species.VOLBEAT]: Abilities.TINTED_LENS, + [Species.ILLUMISE]: Abilities.SWARM, + [Species.GULPIN]: Abilities.POISON_TOUCH, + [Species.CARVANHA]: Abilities.STAKEOUT, + [Species.WAILMER]: Abilities.LEVITATE, + [Species.NUMEL]: Abilities.TURBOBLAZE, + [Species.TORKOAL]: Abilities.PROTOSYNTHESIS, + [Species.SPOINK]: Abilities.PSYCHIC_SURGE, + [Species.SPINDA]: Abilities.SIMPLE, + [Species.TRAPINCH]: Abilities.ADAPTABILITY, + [Species.CACNEA]: Abilities.SAND_RUSH, + [Species.SWABLU]: Abilities.WHITE_SMOKE, + [Species.ZANGOOSE]: Abilities.SUPER_LUCK, + [Species.SEVIPER]: Abilities.MOLD_BREAKER, + [Species.LUNATONE]: Abilities.SHADOW_SHIELD, + [Species.SOLROCK]: Abilities.FULL_METAL_BODY, + [Species.BARBOACH]: Abilities.BALL_FETCH, + [Species.CORPHISH]: Abilities.WATER_BUBBLE, + [Species.BALTOY]: Abilities.OWN_TEMPO, + [Species.LILEEP]: Abilities.WATER_ABSORB, + [Species.ANORITH]: Abilities.WATER_ABSORB, + [Species.FEEBAS]: Abilities.PASTEL_VEIL, + [Species.CASTFORM]: Abilities.ADAPTABILITY, + [Species.KECLEON]: Abilities.ADAPTABILITY, + [Species.SHUPPET]: Abilities.MUMMY, + [Species.DUSKULL]: Abilities.UNNERVE, + [Species.TROPIUS]: Abilities.CUD_CHEW, + [Species.ABSOL]: Abilities.DARK_AURA, + [Species.WYNAUT]: Abilities.STAMINA, + [Species.SNORUNT]: Abilities.SNOW_WARNING, + [Species.SPHEAL]: Abilities.SLUSH_RUSH, + [Species.CLAMPERL]: Abilities.SIMPLE, + [Species.RELICANTH]: Abilities.SOLID_ROCK, + [Species.LUVDISC]: Abilities.PICKUP, + [Species.BAGON]: Abilities.GALE_WINGS, + [Species.BELDUM]: Abilities.IRON_FIST, + [Species.REGIROCK]: Abilities.REGENERATOR, + [Species.REGICE]: Abilities.ICE_SCALES, + [Species.REGISTEEL]: Abilities.STEELY_SPIRIT, + [Species.LATIAS]: Abilities.SERENE_GRACE, + [Species.LATIOS]: Abilities.SERENE_GRACE, + [Species.KYOGRE]: Abilities.HYDRATION, + [Species.GROUDON]: Abilities.LEAF_GUARD, + [Species.RAYQUAZA]: Abilities.STEADFAST, + [Species.JIRACHI]: Abilities.COMATOSE, + [Species.DEOXYS]: Abilities.STICKY_HOLD, + [Species.TURTWIG]: Abilities.HARVEST, + [Species.CHIMCHAR]: Abilities.DEFIANT, + [Species.PIPLUP]: Abilities.BATTLE_ARMOR, + [Species.STARLY]: Abilities.ROCK_HEAD, + [Species.BIDOOF]: Abilities.NEUROFORCE, + [Species.KRICKETOT]: Abilities.SOUNDPROOF, + [Species.SHINX]: Abilities.VOLT_ABSORB, + [Species.BUDEW]: Abilities.CUTE_CHARM, + [Species.CRANIDOS]: Abilities.ROCK_HEAD, + [Species.SHIELDON]: Abilities.SOLID_ROCK, + [Species.BURMY]: Abilities.STURDY, + [Species.COMBEE]: Abilities.QUEENLY_MAJESTY, + [Species.PACHIRISU]: Abilities.BALL_FETCH, + [Species.BUIZEL]: Abilities.HYDRATION, + [Species.CHERUBI]: Abilities.DROUGHT, + [Species.SHELLOS]: Abilities.SHELL_ARMOR, + [Species.DRIFLOON]: Abilities.PICKPOCKET, + [Species.BUNEARY]: Abilities.OBLIVIOUS, + [Species.GLAMEOW]: Abilities.PICKUP, + [Species.CHINGLING]: Abilities.VICTORY_STAR, + [Species.STUNKY]: Abilities.MERCILESS, + [Species.BRONZOR]: Abilities.SOUNDPROOF, + [Species.BONSLY]: Abilities.SAP_SIPPER, + [Species.MIME_JR]: Abilities.MAGIC_BOUNCE, + [Species.HAPPINY]: Abilities.TRIAGE, + [Species.CHATOT]: Abilities.PUNK_ROCK, + [Species.SPIRITOMB]: Abilities.REGENERATOR, + [Species.GIBLE]: Abilities.SAND_STREAM, + [Species.MUNCHLAX]: Abilities.CUD_CHEW, + [Species.RIOLU]: Abilities.MEGA_LAUNCHER, + [Species.HIPPOPOTAS]: Abilities.SAND_VEIL, + [Species.SKORUPI]: Abilities.SUPER_LUCK, + [Species.CROAGUNK]: Abilities.PICKPOCKET, + [Species.CARNIVINE]: Abilities.EFFECT_SPORE, + [Species.FINNEON]: Abilities.DRIZZLE, + [Species.MANTYKE]: Abilities.STORM_DRAIN, + [Species.SNOVER]: Abilities.SNOW_CLOAK, + [Species.ROTOM]: Abilities.ELECTRIC_SURGE, + [Species.UXIE]: Abilities.ILLUSION, + [Species.MESPRIT]: Abilities.MOODY, + [Species.AZELF]: Abilities.NEUROFORCE, + [Species.DIALGA]: Abilities.SPEED_BOOST, + [Species.PALKIA]: Abilities.MAGIC_BOUNCE, + [Species.HEATRAN]: Abilities.ROUGH_SKIN, + [Species.REGIGIGAS]: Abilities.IRON_FIST, + [Species.GIRATINA]: Abilities.SHADOW_TAG, + [Species.CRESSELIA]: Abilities.MAGIC_BOUNCE, + [Species.PHIONE]: Abilities.SWIFT_SWIM, + [Species.MANAPHY]: Abilities.SIMPLE, + [Species.DARKRAI]: Abilities.UNNERVE, + [Species.SHAYMIN]: Abilities.FLOWER_VEIL, + [Species.ARCEUS]: Abilities.ADAPTABILITY, + [Species.VICTINI]: Abilities.SUPER_LUCK, + [Species.SNIVY]: Abilities.MULTISCALE, + [Species.TEPIG]: Abilities.SAND_RUSH, + [Species.OSHAWOTT]: Abilities.LIGHTNING_ROD, + [Species.PATRAT]: Abilities.STAKEOUT, + [Species.LILLIPUP]: Abilities.BALL_FETCH, + [Species.PURRLOIN]: Abilities.DEFIANT, + [Species.PANSAGE]: Abilities.SAP_SIPPER, + [Species.PANSEAR]: Abilities.FLASH_FIRE, + [Species.PANPOUR]: Abilities.STORM_DRAIN, + [Species.MUNNA]: Abilities.NEUTRALIZING_GAS, + [Species.PIDOVE]: Abilities.OPPORTUNIST, + [Species.BLITZLE]: Abilities.FLARE_BOOST, + [Species.ROGGENROLA]: Abilities.SOLID_ROCK, + [Species.WOOBAT]: Abilities.SOUL_HEART, + [Species.DRILBUR]: Abilities.SAND_STREAM, + [Species.AUDINO]: Abilities.SERENE_GRACE, + [Species.TIMBURR]: Abilities.STAMINA, + [Species.TYMPOLE]: Abilities.MOODY, + [Species.THROH]: Abilities.SIMPLE, + [Species.SAWK]: Abilities.DEFIANT, + [Species.SEWADDLE]: Abilities.SHARPNESS, + [Species.VENIPEDE]: Abilities.INTIMIDATE, + [Species.COTTONEE]: Abilities.MISTY_SURGE, + [Species.PETILIL]: Abilities.ORICHALCUM_PULSE, + [Species.BASCULIN]: Abilities.ROCK_HEAD, + [Species.SANDILE]: Abilities.STRONG_JAW, + [Species.DARUMAKA]: Abilities.IRON_FIST, + [Species.MARACTUS]: Abilities.IRON_BARBS, + [Species.DWEBBLE]: Abilities.STAMINA, + [Species.SCRAGGY]: Abilities.ROCK_HEAD, + [Species.SIGILYPH]: Abilities.MAGICIAN, + [Species.YAMASK]: Abilities.GOOD_AS_GOLD, + [Species.TIRTOUGA]: Abilities.SHELL_ARMOR, + [Species.ARCHEN]: Abilities.ROCKY_PAYLOAD, + [Species.TRUBBISH]: Abilities.GOOEY, + [Species.ZORUA]: Abilities.ADAPTABILITY, + [Species.MINCCINO]: Abilities.SCRAPPY, + [Species.GOTHITA]: Abilities.PRESSURE, + [Species.SOLOSIS]: Abilities.GOOEY, + [Species.DUCKLETT]: Abilities.GALE_WINGS, + [Species.VANILLITE]: Abilities.REFRIGERATE, + [Species.DEERLING]: Abilities.JUSTIFIED, + [Species.EMOLGA]: Abilities.WIND_POWER, + [Species.KARRABLAST]: Abilities.NO_GUARD, + [Species.FOONGUS]: Abilities.ADAPTABILITY, + [Species.FRILLISH]: Abilities.MUMMY, + [Species.ALOMOMOLA]: Abilities.MULTISCALE, + [Species.JOLTIK]: Abilities.VOLT_ABSORB, + [Species.FERROSEED]: Abilities.SKILL_LINK, + [Species.KLINK]: Abilities.STEELWORKER, + [Species.TYNAMO]: Abilities.SWIFT_SWIM, + [Species.ELGYEM]: Abilities.COMMANDER, + [Species.LITWICK]: Abilities.SOUL_HEART, + [Species.AXEW]: Abilities.SHEER_FORCE, + [Species.CUBCHOO]: Abilities.INTIMIDATE, + [Species.CRYOGONAL]: Abilities.DAZZLING, + [Species.SHELMET]: Abilities.DISGUISE, + [Species.STUNFISK]: Abilities.STORM_DRAIN, + [Species.MIENFOO]: Abilities.NO_GUARD, + [Species.DRUDDIGON]: Abilities.INTIMIDATE, + [Species.GOLETT]: Abilities.JUSTIFIED, + [Species.PAWNIARD]: Abilities.SHARPNESS, + [Species.BOUFFALANT]: Abilities.THICK_FAT, + [Species.RUFFLET]: Abilities.RECKLESS, + [Species.VULLABY]: Abilities.THICK_FAT, + [Species.HEATMOR]: Abilities.CONTRARY, + [Species.DURANT]: Abilities.TOUGH_CLAWS, + [Species.DEINO]: Abilities.BERSERK, + [Species.LARVESTA]: Abilities.DROUGHT, + [Species.COBALION]: Abilities.INTREPID_SWORD, + [Species.TERRAKION]: Abilities.ROCKY_PAYLOAD, + [Species.VIRIZION]: Abilities.SYMBIOSIS, + [Species.TORNADUS]: Abilities.DELTA_STREAM, + [Species.THUNDURUS]: Abilities.DRIZZLE, + [Species.RESHIRAM]: Abilities.ORICHALCUM_PULSE, + [Species.ZEKROM]: Abilities.HADRON_ENGINE, + [Species.LANDORUS]: Abilities.PRANKSTER, + [Species.KYUREM]: Abilities.SNOW_WARNING, + [Species.KELDEO]: Abilities.HUGE_POWER, + [Species.MELOETTA]: Abilities.PUNK_ROCK, + [Species.GENESECT]: Abilities.MEGA_LAUNCHER, + [Species.CHESPIN]: Abilities.IRON_BARBS, + [Species.FENNEKIN]: Abilities.MAGIC_GUARD, + [Species.FROAKIE]: Abilities.MERCILESS, + [Species.BUNNELBY]: Abilities.GUTS, + [Species.FLETCHLING]: Abilities.RECKLESS, + [Species.SCATTERBUG]: Abilities.PRANKSTER, + [Species.LITLEO]: Abilities.INTIMIDATE, + [Species.FLABEBE]: Abilities.GRASSY_SURGE, + [Species.SKIDDO]: Abilities.FUR_COAT, + [Species.PANCHAM]: Abilities.FLUFFY, + [Species.FURFROU]: Abilities.BALL_FETCH, + [Species.ESPURR]: Abilities.PSYCHIC_SURGE, + [Species.HONEDGE]: Abilities.SHARPNESS, + [Species.SPRITZEE]: Abilities.UNAWARE, + [Species.SWIRLIX]: Abilities.PIXILATE, + [Species.INKAY]: Abilities.SUPREME_OVERLORD, + [Species.BINACLE]: Abilities.SOLID_ROCK, + [Species.SKRELP]: Abilities.CORROSION, + [Species.CLAUNCHER]: Abilities.SWIFT_SWIM, + [Species.HELIOPTILE]: Abilities.NO_GUARD, + [Species.TYRUNT]: Abilities.SHEER_FORCE, + [Species.AMAURA]: Abilities.SERENE_GRACE, + [Species.HAWLUCHA]: Abilities.RECKLESS, + [Species.DEDENNE]: Abilities.SIMPLE, + [Species.CARBINK]: Abilities.OBLIVIOUS, + [Species.GOOMY]: Abilities.POISON_HEAL, + [Species.KLEFKI]: Abilities.TRIAGE, + [Species.PHANTUMP]: Abilities.UNNERVE, + [Species.PUMPKABOO]: Abilities.FLARE_BOOST, + [Species.BERGMITE]: Abilities.MIRROR_ARMOR, + [Species.NOIBAT]: Abilities.PUNK_ROCK, + [Species.XERNEAS]: Abilities.COMPETITIVE, + [Species.YVELTAL]: Abilities.DEFIANT, + [Species.ZYGARDE]: Abilities.REGENERATOR, + [Species.DIANCIE]: Abilities.QUEENLY_MAJESTY, + [Species.HOOPA]: Abilities.TRACE, + [Species.VOLCANION]: Abilities.FILTER, + [Species.ROWLET]: Abilities.SNIPER, + [Species.LITTEN]: Abilities.PRANKSTER, + [Species.POPPLIO]: Abilities.PUNK_ROCK, + [Species.PIKIPEK]: Abilities.ANGER_POINT, + [Species.YUNGOOS]: Abilities.HUGE_POWER, + [Species.GRUBBIN]: Abilities.GALVANIZE, + [Species.CRABRAWLER]: Abilities.REFRIGERATE, + [Species.ORICORIO]: Abilities.ADAPTABILITY, + [Species.CUTIEFLY]: Abilities.FRIEND_GUARD, + [Species.ROCKRUFF]: Abilities.ROCKY_PAYLOAD, + [Species.WISHIWASHI]: Abilities.PARENTAL_BOND, + [Species.MAREANIE]: Abilities.TOXIC_DEBRIS, + [Species.MUDBRAY]: Abilities.CUD_CHEW, + [Species.DEWPIDER]: Abilities.STRONG_JAW, + [Species.FOMANTIS]: Abilities.MIMICRY, + [Species.MORELULL]: Abilities.PERISH_BODY, + [Species.SALANDIT]: Abilities.DAZZLING, + [Species.STUFFUL]: Abilities.HOSPITALITY, + [Species.BOUNSWEET]: Abilities.RIPEN, + [Species.COMFEY]: Abilities.FRIEND_GUARD, + [Species.ORANGURU]: Abilities.HOSPITALITY, + [Species.PASSIMIAN]: Abilities.COSTAR, + [Species.WIMPOD]: Abilities.BATTLE_ARMOR, + [Species.SANDYGAST]: Abilities.DAUNTLESS_SHIELD, + [Species.PYUKUMUKU]: Abilities.IRON_BARBS, + [Species.TYPE_NULL]: Abilities.ADAPTABILITY, + [Species.MINIOR]: Abilities.ANGER_SHELL, + [Species.KOMALA]: Abilities.GUTS, + [Species.TURTONATOR]: Abilities.ANGER_SHELL, + [Species.TOGEDEMARU]: Abilities.STATIC, + [Species.MIMIKYU]: Abilities.MIMICRY, + [Species.BRUXISH]: Abilities.MULTISCALE, + [Species.DRAMPA]: Abilities.FLASH_FIRE, + [Species.DHELMISE]: Abilities.INFILTRATOR, + [Species.JANGMO_O]: Abilities.DANCER, + [Species.TAPU_KOKO]: Abilities.GALVANIZE, + [Species.TAPU_LELE]: Abilities.BERSERK, + [Species.TAPU_BULU]: Abilities.FLOWER_VEIL, + [Species.TAPU_FINI]: Abilities.FAIRY_AURA, + [Species.COSMOG]: Abilities.BEAST_BOOST, + [Species.NIHILEGO]: Abilities.POISON_PUPPETEER, + [Species.BUZZWOLE]: Abilities.MOXIE, + [Species.PHEROMOSA]: Abilities.MOXIE, + [Species.XURKITREE]: Abilities.LIGHTNING_ROD, + [Species.CELESTEELA]: Abilities.CHLOROPHYLL, + [Species.KARTANA]: Abilities.INTREPID_SWORD, + [Species.GUZZLORD]: Abilities.GLUTTONY, + [Species.NECROZMA]: Abilities.BEAST_BOOST, + [Species.MAGEARNA]: Abilities.STEELY_SPIRIT, + [Species.MARSHADOW]: Abilities.IRON_FIST, + [Species.POIPOLE]: Abilities.MERCILESS, + [Species.STAKATAKA]: Abilities.DAUNTLESS_SHIELD, + [Species.BLACEPHALON]: Abilities.REGENERATOR, + [Species.ZERAORA]: Abilities.MOTOR_DRIVE, + [Species.MELTAN]: Abilities.FULL_METAL_BODY, + [Species.GROOKEY]: Abilities.SOLID_ROCK, + [Species.SCORBUNNY]: Abilities.RECKLESS, + [Species.SOBBLE]: Abilities.MIMICRY, + [Species.SKWOVET]: Abilities.HONEY_GATHER, + [Species.ROOKIDEE]: Abilities.JUSTIFIED, + [Species.BLIPBUG]: Abilities.TINTED_LENS, + [Species.NICKIT]: Abilities.INTIMIDATE, + [Species.GOSSIFLEUR]: Abilities.STORM_DRAIN, + [Species.WOOLOO]: Abilities.ROCK_HEAD, + [Species.CHEWTLE]: Abilities.ROCK_HEAD, + [Species.YAMPER]: Abilities.SPEED_BOOST, + [Species.ROLYCOLY]: Abilities.EARTH_EATER, + [Species.APPLIN]: Abilities.DRAGONS_MAW, + [Species.SILICOBRA]: Abilities.SAND_RUSH, + [Species.CRAMORANT]: Abilities.STORM_DRAIN, + [Species.ARROKUDA]: Abilities.STRONG_JAW, + [Species.TOXEL]: Abilities.GALVANIZE, + [Species.SIZZLIPEDE]: Abilities.DEFIANT, + [Species.CLOBBOPUS]: Abilities.SWIFT_SWIM, + [Species.SINISTEA]: Abilities.WATER_ABSORB, + [Species.HATENNA]: Abilities.MAGIC_GUARD, + [Species.IMPIDIMP]: Abilities.TANGLING_HAIR, + [Species.MILCERY]: Abilities.WELL_BAKED_BODY, + [Species.FALINKS]: Abilities.MOXIE, + [Species.PINCURCHIN]: Abilities.IRON_BARBS, + [Species.SNOM]: Abilities.SNOW_WARNING, + [Species.STONJOURNER]: Abilities.SOLID_ROCK, + [Species.EISCUE]: Abilities.SLUSH_RUSH, + [Species.INDEEDEE]: Abilities.MAGIC_BOUNCE, + [Species.MORPEKO]: Abilities.GLUTTONY, + [Species.CUFANT]: Abilities.HEATPROOF, + [Species.DRACOZOLT]: Abilities.SLUSH_RUSH, + [Species.ARCTOZOLT]: Abilities.SAND_RUSH, + [Species.DRACOVISH]: Abilities.HUSTLE, + [Species.ARCTOVISH]: Abilities.STRONG_JAW, + [Species.DURALUDON]: Abilities.MEGA_LAUNCHER, + [Species.DREEPY]: Abilities.PARENTAL_BOND, + [Species.ZACIAN]: Abilities.SHARPNESS, + [Species.ZAMAZENTA]: Abilities.GUARD_DOG, + [Species.ETERNATUS]: Abilities.SUPREME_OVERLORD, + [Species.KUBFU]: Abilities.IRON_FIST, + [Species.ZARUDE]: Abilities.PRANKSTER, + [Species.REGIELEKI]: Abilities.LEVITATE, + [Species.REGIDRAGO]: Abilities.INTIMIDATE, + [Species.GLASTRIER]: Abilities.FILTER, + [Species.SPECTRIER]: Abilities.PERISH_BODY, + [Species.CALYREX]: Abilities.HARVEST, + [Species.ENAMORUS]: Abilities.MISTY_SURGE, + [Species.SPRIGATITO]: Abilities.MAGICIAN, + [Species.FUECOCO]: Abilities.EARTH_EATER, + [Species.QUAXLY]: Abilities.DANCER, + [Species.LECHONK]: Abilities.SIMPLE, + [Species.TAROUNTULA]: Abilities.PICKUP, + [Species.NYMBLE]: Abilities.TECHNICIAN, + [Species.PAWMI]: Abilities.FLUFFY, + [Species.TANDEMAUS]: Abilities.PARENTAL_BOND, + [Species.FIDOUGH]: Abilities.WATER_ABSORB, + [Species.SMOLIV]: Abilities.RIPEN, + [Species.SQUAWKABILLY]: Abilities.GALE_WINGS, + [Species.NACLI]: Abilities.EARTH_EATER, + [Species.CHARCADET]: Abilities.CONTRARY, + [Species.TADBULB]: Abilities.TRANSISTOR, + [Species.WATTREL]: Abilities.GALE_WINGS, + [Species.MASCHIFF]: Abilities.STRONG_JAW, + [Species.SHROODLE]: Abilities.CORROSION, + [Species.BRAMBLIN]: Abilities.WANDERING_SPIRIT, + [Species.TOEDSCOOL]: Abilities.PRANKSTER, + [Species.KLAWF]: Abilities.WATER_ABSORB, + [Species.CAPSAKID]: Abilities.PARENTAL_BOND, + [Species.RELLOR]: Abilities.MAGIC_GUARD, + [Species.FLITTLE]: Abilities.COMPETITIVE, + [Species.TINKATINK]: Abilities.HUGE_POWER, + [Species.WIGLETT]: Abilities.STORM_DRAIN, + [Species.BOMBIRDIER]: Abilities.UNAWARE, + [Species.FINIZEN]: Abilities.LIQUID_VOICE, + [Species.VAROOM]: Abilities.SPEED_BOOST, + [Species.CYCLIZAR]: Abilities.PROTEAN, + [Species.ORTHWORM]: Abilities.HEATPROOF, + [Species.GLIMMET]: Abilities.SYMBIOSIS, + [Species.GREAVARD]: Abilities.FUR_COAT, + [Species.FLAMIGO]: Abilities.MOXIE, + [Species.CETODDLE]: Abilities.GLUTTONY, + [Species.VELUZA]: Abilities.SIMPLE, + [Species.DONDOZO]: Abilities.GLUTTONY, + [Species.TATSUGIRI]: Abilities.WATER_BUBBLE, + [Species.GREAT_TUSK]: Abilities.INTIMIDATE, + [Species.SCREAM_TAIL]: Abilities.PIXILATE, + [Species.BRUTE_BONNET]: Abilities.ADAPTABILITY, + [Species.FLUTTER_MANE]: Abilities.DAZZLING, + [Species.SLITHER_WING]: Abilities.SCRAPPY, + [Species.SANDY_SHOCKS]: Abilities.EARTH_EATER, + [Species.IRON_TREADS]: Abilities.STEAM_ENGINE, + [Species.IRON_BUNDLE]: Abilities.SNOW_WARNING, + [Species.IRON_HANDS]: Abilities.IRON_FIST, + [Species.IRON_JUGULIS]: Abilities.NO_GUARD, + [Species.IRON_MOTH]: Abilities.TINTED_LENS, + [Species.IRON_THORNS]: Abilities.SAND_STREAM, + [Species.FRIGIBAX]: Abilities.THICK_FAT, + [Species.GIMMIGHOUL]: Abilities.SUPER_LUCK, + [Species.WO_CHIEN]: Abilities.TRIAGE, + [Species.CHIEN_PAO]: Abilities.REFRIGERATE, + [Species.TING_LU]: Abilities.STAMINA, + [Species.CHI_YU]: Abilities.BLAZE, + [Species.ROARING_MOON]: Abilities.AERILATE, + [Species.IRON_VALIANT]: Abilities.DOWNLOAD, + [Species.KORAIDON]: Abilities.PROTOSYNTHESIS, + [Species.MIRAIDON]: Abilities.QUARK_DRIVE, + [Species.WALKING_WAKE]: Abilities.BEAST_BOOST, + [Species.IRON_LEAVES]: Abilities.SHARPNESS, + [Species.POLTCHAGEIST]: Abilities.FLAME_BODY, + [Species.OKIDOGI]: Abilities.STICKY_HOLD, + [Species.MUNKIDORI]: Abilities.PRANKSTER, + [Species.FEZANDIPITI]: Abilities.DAZZLING, + [Species.OGERPON]: Abilities.DISGUISE, + [Species.GOUGING_FIRE]: Abilities.BEAST_BOOST, + [Species.RAGING_BOLT]: Abilities.BEAST_BOOST, + [Species.IRON_BOULDER]: Abilities.SHARPNESS, + [Species.IRON_CROWN]: Abilities.SHARPNESS, + [Species.TERAPAGOS]: Abilities.PROTEAN, + [Species.PECHARUNT]: Abilities.CORROSION, + [Species.ALOLA_RATTATA]: Abilities.CHEEK_POUCH, + [Species.ALOLA_SANDSHREW]: Abilities.ICE_BODY, + [Species.ALOLA_VULPIX]: Abilities.ICE_BODY, + [Species.ALOLA_DIGLETT]: Abilities.CUTE_CHARM, + [Species.ALOLA_MEOWTH]: Abilities.UNNERVE, + [Species.ALOLA_GEODUDE]: Abilities.ELECTROMORPHOSIS, + [Species.ALOLA_GRIMER]: Abilities.MERCILESS, + [Species.ETERNAL_FLOETTE]: Abilities.MAGIC_GUARD, + [Species.GALAR_MEOWTH]: Abilities.SUPER_LUCK, + [Species.GALAR_PONYTA]: Abilities.MAGIC_GUARD, + [Species.GALAR_SLOWPOKE]: Abilities.POISON_TOUCH, + [Species.GALAR_FARFETCHD]: Abilities.SUPER_LUCK, + [Species.GALAR_ARTICUNO]: Abilities.SERENE_GRACE, + [Species.GALAR_ZAPDOS]: Abilities.TOUGH_CLAWS, + [Species.GALAR_MOLTRES]: Abilities.REGENERATOR, + [Species.GALAR_CORSOLA]: Abilities.SHADOW_TAG, + [Species.GALAR_ZIGZAGOON]: Abilities.PICKPOCKET, + [Species.GALAR_DARUMAKA]: Abilities.FLASH_FIRE, + [Species.GALAR_YAMASK]: Abilities.SOLID_ROCK, + [Species.GALAR_STUNFISK]: Abilities.IRON_BARBS, + [Species.HISUI_GROWLITHE]: Abilities.STRONG_JAW, + [Species.HISUI_VOLTORB]: Abilities.HADRON_ENGINE, + [Species.HISUI_QWILFISH]: Abilities.MERCILESS, + [Species.HISUI_SNEASEL]: Abilities.SCRAPPY, + [Species.HISUI_ZORUA]: Abilities.DARK_AURA, + [Species.PALDEA_TAUROS]: Abilities.RATTLED, + [Species.PALDEA_WOOPER]: Abilities.THICK_FAT, + [Species.BLOODMOON_URSALUNA]: Abilities.BERSERK +}; + // TODO: Remove { //setTimeout(() => { @@ -3071,4 +3643,4 @@ export const noStarterFormKeys: string[] = [ return s; }))].map(s => s.name));*/ //}, 1000); -} \ No newline at end of file +} diff --git a/src/data/weather.ts b/src/data/weather.ts index a198990fd61..b3a59f34b98 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -106,7 +106,9 @@ export class Weather { const field = scene.getField(true); for (let pokemon of field) { - const suppressWeatherEffectAbAttr = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr; + let suppressWeatherEffectAbAttr = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr; + if (!suppressWeatherEffectAbAttr) + suppressWeatherEffectAbAttr = pokemon.canApplyPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr : null; if (suppressWeatherEffectAbAttr && (!this.isImmutable() || suppressWeatherEffectAbAttr.affectsImmutable)) return true; } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 6f4d09ea7a2..1cc4378ead5 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2,8 +2,8 @@ import Phaser from 'phaser'; import BattleScene, { ABILITY_OVERRIDE, AnySound, MOVE_OVERRIDE, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE } from '../battle-scene'; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info'; import { Moves } from "../data/enums/moves"; -import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr } from "../data/move"; -import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm } from '../data/pokemon-species'; +import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr } from "../data/move"; +import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, starterPassiveAbilities } from '../data/pokemon-species'; import * as Utils from '../utils'; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type'; import { getLevelTotalExp } from '../data/exp'; @@ -25,7 +25,8 @@ import { TempBattleStat } from '../data/temp-battle-stat'; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag'; import { ArenaTagType } from "../data/enums/arena-tag-type"; import { Biome } from "../data/enums/biome"; -import { Abilities, Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability'; +import { Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability'; +import { Abilities } from "#app/data/enums/abilities"; import PokemonData from '../system/pokemon-data'; import { BattlerIndex } from '../battle'; import { BattleSpec } from "../enums/battle-spec"; @@ -556,7 +557,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let value = Math.floor(((2 * baseStat + this.ivs[s]) * this.level) * 0.01); if (isHp) { value = value + this.level + 10; - if (this.getAbility().hasAttr(NonSuperEffectiveImmunityAbAttr)) + if ((this.canApplyAbility() && this.getAbility().hasAttr(NonSuperEffectiveImmunityAbAttr)) || (this.canApplyAbility(true) && this.getPassiveAbility().hasAttr(NonSuperEffectiveImmunityAbAttr))) value = 1; if (this.hp > value || this.hp === undefined) this.hp = value; @@ -716,11 +717,24 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return allAbilities[abilityId]; } - canApplyAbility(): boolean { - const ability = this.getAbility(); + getPassiveAbility(): Ability { + let starterSpeciesId = this.species.speciesId; + while (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) + starterSpeciesId = pokemonPrevolutions[starterSpeciesId]; + return allAbilities[starterPassiveAbilities[starterSpeciesId]]; + } + + canApplyPassive(): boolean { + return this.isBoss(); + } + + canApplyAbility(passive: boolean = false): boolean { + if (passive && !this.canApplyPassive()) + return false; + const ability = (!passive ? this.getAbility() : this.getPassiveAbility()); if (ability.isIgnorable && this.scene.arena.ignoreAbilities) return false; - return (this.hp || ability.isPassive) && !this.getAbility().conditions.find(condition => !condition(this)); + return (this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this)); } getWeight(): number { @@ -1093,9 +1107,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { apply(source: Pokemon, battlerMove: PokemonMove): HitResult { let result: HitResult; const move = battlerMove.getMove(); - const moveCategory = move.category; let damage = new Utils.NumberHolder(0); + const variableCategory = new Utils.IntegerHolder(move.category); + applyMoveAttrs(VariableMoveCategoryAttr, source, this, move, variableCategory); + const moveCategory = variableCategory.value as MoveCategory; + const variableType = new Utils.IntegerHolder(move.type); const typeChangeMovePowerMultiplier = new Utils.NumberHolder(1); applyMoveAttrs(VariableMoveTypeAttr, source, this, move, variableType); diff --git a/src/phases.ts b/src/phases.ts index 8c983317239..26a0651d647 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -30,7 +30,8 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get import { TempBattleStat } from "./data/temp-battle-stat"; import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag"; import { ArenaTagType } from "./data/enums/arena-tag-type"; -import { Abilities, CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr } from "./data/ability"; +import { CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr } from "./data/ability"; +import { Abilities } from "./data/enums/abilities"; import { Unlockables, getUnlockableName } from "./system/unlockables"; import { getBiomeKey } from "./field/arena"; import { BattleType, BattlerIndex, TurnCommand } from "./battle"; @@ -1207,7 +1208,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { pokemon.resetTurnData(); - if (!this.loaded) { + if (!this.loaded || this.scene.currentBattle.battleType === BattleType.TRAINER || (this.scene.currentBattle.waveIndex % 10) === 1) { this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); this.queuePostSummon(); @@ -2131,7 +2132,7 @@ export class MovePhase extends BattlePhase { for (let opponent of targetedOpponents) { if (this.move.ppUsed === this.move.getMove().pp) break; - if (opponent.getAbility().id === Abilities.PRESSURE) + if ((opponent.canApplyAbility() && opponent.getAbility().hasAttr(IncreasePpAbAttr)) || (opponent.canApplyAbility(true) && opponent.getPassiveAbility().hasAttr(IncreasePpAbAttr))) this.move.ppUsed = Math.min(this.move.ppUsed + 1, this.move.getMovePp()); } } @@ -2502,14 +2503,18 @@ export class MoveAnimTestPhase extends BattlePhase { } export class ShowAbilityPhase extends PokemonPhase { - constructor(scene: BattleScene, battlerIndex: BattlerIndex) { + private passive: boolean; + + constructor(scene: BattleScene, battlerIndex: BattlerIndex, passive: boolean = false) { super(scene, battlerIndex); + + this.passive = passive; } start() { super.start(); - this.scene.abilityBar.showAbility(this.getPokemon()); + this.scene.abilityBar.showAbility(this.getPokemon(), this.passive); this.end(); } @@ -2904,11 +2909,9 @@ export class FaintPhase extends PokemonPhase { this.scene.queueMessage(getPokemonMessage(pokemon, ' fainted!'), null, true); - if (pokemon.getAbility().hasAttr(PostFaintAbAttr)) { - if (pokemon.turnData?.attacksReceived?.length) { - const lastAttack = pokemon.turnData.attacksReceived[0]; - applyPostFaintAbAttrs(PostFaintAbAttr,pokemon, this.scene.getPokemonById(lastAttack.sourceId), new PokemonMove(lastAttack.move), lastAttack.result); - } + if (pokemon.turnData?.attacksReceived?.length) { + const lastAttack = pokemon.turnData.attacksReceived[0]; + applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId), new PokemonMove(lastAttack.move), lastAttack.result); } const alivePlayField = this.scene.getField(true); diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 248a3705122..1bf3852740a 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -360,7 +360,7 @@ export class GameData { .then(response => response.text()) .then(response => { if (!response.length || response[0] !== '{') { - if (response.startsWith('failed to read save file')) { + if (response.startsWith('failed to open save file')) { this.scene.queueMessage('Save data could not be found. If this is a new account, you can safely ignore this message.', null, true); return resolve(true); } diff --git a/src/ui/ability-bar.ts b/src/ui/ability-bar.ts index 1985844e919..155123b8553 100644 --- a/src/ui/ability-bar.ts +++ b/src/ui/ability-bar.ts @@ -38,9 +38,9 @@ export default class AbilityBar extends Phaser.GameObjects.Container { this.shown = false; } - showAbility(pokemon: Pokemon): void { - this.pokemonNameText.setText(`${pokemon.name}'s`); - this.abilityNameText.setText(pokemon.getAbility().name); + showAbility(pokemon: Pokemon, passive: boolean = false): void { + this.pokemonNameText.setText(`${pokemon.name}'s${passive ? ' Passive' : ''}`); + this.abilityNameText.setText((!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name); if (this.shown) return;