From 54efd444975d9b42e52148eb2b32eef9a054b047 Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Thu, 3 Oct 2024 08:38:17 -0700 Subject: [PATCH] [Refactor] Modifiers type inference v2 (#4294) * refactor: apply Modifiers type inference (pattern) Mirror from #1747 Co-authored-by: Dmitriy * fix: PokemonBaseStatTotalModifier.apply having a `[1]` left * fix: HeldItemTransferModifier.apply missing `...args: unknown[]` * Replace relative imports with absolute imports in `modifier.ts` * chore: fix TS1016* error [*] A required parameter cannot follow an optional parameter. * chore: fix namings, types and docs suggested by @torranx * replace: `IntegerHolder` with `NumberHolder` & `integer` with `number` * chore: apply review suggestions by @torranx * chore: address review feedback from @torranx * update: imports in `modifier-types` * update `lapse` calls in modifier.ts * fix lapse call in `battle-end-phase` * minor adjustments in `modifier.ts` * fix `EnemyEndureChanceModifier.apply` types * fix `EnemyAttackStatusEffectChanceModifier.apply` types * fix `EnemyTurnHealModifier.apply` types * fix `EnemyStatusEffectHealChanceModifier.apply` types --------- Co-authored-by: Dmitriy Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/battle-scene.ts | 90 +- src/modifier/modifier-type.ts | 311 ++++--- src/modifier/modifier.ts | 1542 ++++++++++++++++++++------------ src/phases/battle-end-phase.ts | 2 +- src/phases/berry-phase.ts | 4 +- 5 files changed, 1200 insertions(+), 749 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index df852126bc2..1bb0d6bfc4b 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2445,7 +2445,10 @@ export default class BattleScene extends SceneBase { } if ((modifier as PersistentModifier).add(this.modifiers, !!virtual, this)) { if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { - success = modifier.apply([ this.getPokemonById(modifier.pokemonId), true ]); + const pokemon = this.getPokemonById(modifier.pokemonId); + if (pokemon) { + success = modifier.apply(pokemon, true); + } } if (playSound && !this.sound.get(soundName)) { this.playSound(soundName); @@ -2472,7 +2475,7 @@ export default class BattleScene extends SceneBase { for (const p in this.party) { const pokemon = this.party[p]; - const args: any[] = [ pokemon ]; + const args: unknown[] = []; if (modifier instanceof PokemonHpRestoreModifier) { if (!(modifier as PokemonHpRestoreModifier).fainted) { const hpRestoreMultiplier = new Utils.IntegerHolder(1); @@ -2485,8 +2488,8 @@ export default class BattleScene extends SceneBase { args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon); } - if (modifier.shouldApply(args)) { - const result = modifier.apply(args); + if (modifier.shouldApply(pokemon, ...args)) { + const result = modifier.apply(pokemon, ...args); if (result instanceof Promise) { modifierPromises.push(result.then(s => success ||= s)); } else { @@ -2498,8 +2501,8 @@ export default class BattleScene extends SceneBase { return Promise.allSettled([this.party.map(p => p.updateInfo(instant)), ...modifierPromises]).then(() => resolve(success)); } else { const args = [ this ]; - if (modifier.shouldApply(args)) { - const result = modifier.apply(args); + if (modifier.shouldApply(...args)) { + const result = modifier.apply(...args); if (result instanceof Promise) { return result.then(success => resolve(success)); } else { @@ -2521,7 +2524,10 @@ export default class BattleScene extends SceneBase { } if ((modifier as PersistentModifier).add(this.enemyModifiers, false, this)) { if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { - modifier.apply([ this.getPokemonById(modifier.pokemonId), true ]); + const pokemon = this.getPokemonById(modifier.pokemonId); + if (pokemon) { + modifier.apply(pokemon, true); + } } for (const rm of modifiersToRemove) { this.removeModifier(rm, true); @@ -2755,7 +2761,10 @@ export default class BattleScene extends SceneBase { if (modifierIndex > -1) { modifiers.splice(modifierIndex, 1); if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { - modifier.apply([ this.getPokemonById(modifier.pokemonId), false ]); + const pokemon = this.getPokemonById(modifier.pokemonId); + if (pokemon) { + modifier.apply(pokemon, false); + } } return true; } @@ -2773,16 +2782,36 @@ export default class BattleScene extends SceneBase { return (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType); } - findModifiers(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier[] { - return (player ? this.modifiers : this.enemyModifiers).filter(m => (modifierFilter as ModifierPredicate)(m)); + /** + * Get all of the modifiers that pass the `modifierFilter` function + * @param modifierFilter The function used to filter a target's modifiers + * @param isPlayer Whether to search the player (`true`) or the enemy (`false`); Defaults to `true` + * @returns the list of all modifiers that passed the `modifierFilter` function + */ + findModifiers(modifierFilter: ModifierPredicate, isPlayer: boolean = true): PersistentModifier[] { + return (isPlayer ? this.modifiers : this.enemyModifiers).filter(modifierFilter); } + /** + * Find the first modifier that pass the `modifierFilter` function + * @param modifierFilter The function used to filter a target's modifiers + * @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true` + * @returns the first modifier that passed the `modifierFilter` function; `undefined` if none passed + */ findModifier(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier | undefined { - return (player ? this.modifiers : this.enemyModifiers).find(m => (modifierFilter as ModifierPredicate)(m)); + return (player ? this.modifiers : this.enemyModifiers).find(modifierFilter); } - applyShuffledModifiers(scene: BattleScene, modifierType: Constructor, player: boolean = true, ...args: any[]): PersistentModifier[] { - let modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args)); + /** + * Apply all modifiers that match `modifierType` in a random order + * @param scene {@linkcode BattleScene} used to randomize the order of modifiers + * @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier} + * @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true` + * @param ...args The list of arguments needed to invoke `modifierType.apply` + * @returns the list of all modifiers that matched `modifierType` and were applied. + */ + applyShuffledModifiers(scene: BattleScene, modifierType: Constructor, player: boolean = true, ...args: Parameters): T[] { + let modifiers = (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType && m.shouldApply(...args)); scene.executeWithSeedOffset(() => { const shuffleModifiers = mods => { if (mods.length < 1) { @@ -2796,15 +2825,23 @@ export default class BattleScene extends SceneBase { return this.applyModifiersInternal(modifiers, player, args); } - applyModifiers(modifierType: Constructor, player: boolean = true, ...args: any[]): PersistentModifier[] { - const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args)); + /** + * Apply all modifiers that match `modifierType` + * @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier} + * @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true` + * @param ...args The list of arguments needed to invoke `modifierType.apply` + * @returns the list of all modifiers that matched `modifierType` and were applied. + */ + applyModifiers(modifierType: Constructor, player: boolean = true, ...args: Parameters): T[] { + const modifiers = (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType && m.shouldApply(...args)); return this.applyModifiersInternal(modifiers, player, args); } - applyModifiersInternal(modifiers: PersistentModifier[], player: boolean, args: any[]): PersistentModifier[] { - const appliedModifiers: PersistentModifier[] = []; + /** Helper function to apply all passed modifiers */ + applyModifiersInternal(modifiers: T[], player: boolean, args: Parameters): T[] { + const appliedModifiers: T[] = []; for (const modifier of modifiers) { - if (modifier.apply(args)) { + if (modifier.apply(...args)) { console.log("Applied", modifier.type.name, !player ? "(enemy)" : ""); appliedModifiers.push(modifier); } @@ -2813,10 +2850,17 @@ export default class BattleScene extends SceneBase { return appliedModifiers; } - applyModifier(modifierType: Constructor, player: boolean = true, ...args: any[]): PersistentModifier | null { - const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args)); + /** + * Apply the first modifier that matches `modifierType` + * @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier} + * @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true` + * @param ...args The list of arguments needed to invoke `modifierType.apply` + * @returns the first modifier that matches `modifierType` and was applied; return `null` if none matched + */ + applyModifier(modifierType: Constructor, player: boolean = true, ...args: Parameters): T | null { + const modifiers = (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType && m.shouldApply(...args)); for (const modifier of modifiers) { - if (modifier.apply(args)) { + if (modifier.apply(...args)) { console.log("Applied", modifier.type.name, !player ? "(enemy)" : ""); return modifier; } @@ -2882,7 +2926,7 @@ export default class BattleScene extends SceneBase { } } - validateAchv(achv: Achv, args?: any[]): boolean { + validateAchv(achv: Achv, args?: unknown[]): boolean { if (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) && achv.validate(this, args)) { this.gameData.achvUnlocks[achv.id] = new Date().getTime(); this.ui.achvBar.showAchv(achv); @@ -2895,7 +2939,7 @@ export default class BattleScene extends SceneBase { return false; } - validateVoucher(voucher: Voucher, args?: any[]): boolean { + validateVoucher(voucher: Voucher, args?: unknown[]): boolean { if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(this, args)) { this.gameData.voucherUnlocks[voucher.id] = new Date().getTime(); this.ui.achvBar.showAchv(voucher); diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 238d2f0debf..aac6a0ed572 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1,38 +1,35 @@ -import * as Modifiers from "#app/modifier/modifier"; -import { MoneyMultiplierModifier } from "#app/modifier/modifier"; -import { allMoves, AttackMove, selfStatLowerMoves } from "#app/data/move"; -import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "#app/data/pokeball"; -import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon"; +import BattleScene from "#app/battle-scene"; import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { tmPoolTiers, tmSpecies } from "#app/data/balance/tms"; -import { Type } from "#app/data/type"; -import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler"; -import * as Utils from "#app/utils"; import { getBerryEffectDescription, getBerryName } from "#app/data/berry"; -import { Unlockables } from "#app/system/unlockables"; -import { getStatusEffectDescriptor, StatusEffect } from "#app/data/status-effect"; -import BattleScene from "#app/battle-scene"; -import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system/voucher"; -import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; -import { ModifierTier } from "#app/modifier/modifier-tier"; +import { allMoves, AttackMove, selfStatLowerMoves } from "#app/data/move"; import { getNatureName, getNatureStatMultiplier, Nature } from "#app/data/nature"; -import i18next from "i18next"; -import { getModifierTierTextTint } from "#app/ui/text"; +import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "#app/data/pokeball"; +import { FormChangeItem, pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; +import { getStatusEffectDescriptor, StatusEffect } from "#app/data/status-effect"; +import { Type } from "#app/data/type"; +import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon"; +import { getPokemonNameWithAffix } from "#app/messages"; +import { AddPokeballModifier, AddVoucherModifier, AttackTypeBoosterModifier, BaseStatModifier, BerryModifier, BoostBugSpawnModifier, BypassSpeedChanceModifier, ContactHeldItemTransferChanceModifier, CritBoosterModifier, DamageMoneyRewardModifier, DoubleBattleChanceBoosterModifier, EnemyAttackStatusEffectChanceModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, EvolutionItemModifier, EvolutionStatBoosterModifier, EvoTrackerModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, GigantamaxAccessModifier, HealingBoosterModifier, HealShopCostModifier, HiddenAbilityRateBoosterModifier, HitHealModifier, IvScannerModifier, LevelIncrementBoosterModifier, LockModifierTiersModifier, MapModifier, MegaEvolutionAccessModifier, MoneyInterestModifier, MoneyMultiplierModifier, MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, PokemonBaseStatFlatModifier, PokemonBaseStatTotalModifier, PokemonExpBoosterModifier, PokemonFormChangeItemModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonIncrementingStatModifier, PokemonInstantReviveModifier, PokemonLevelIncrementModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PokemonNatureChangeModifier, PokemonNatureWeightModifier, PokemonPpRestoreModifier, PokemonPpUpModifier, PokemonStatusHealModifier, PreserveBerryModifier, RememberMoveModifier, ResetNegativeStatStageModifier, ShinyRateBoosterModifier, SpeciesCritBoosterModifier, SpeciesStatBoosterModifier, SurviveDamageModifier, SwitchEffectTransferModifier, TempCritBoosterModifier, TempStatStageBoosterModifier, TerastallizeAccessModifier, TerastallizeModifier, TmModifier, TurnHealModifier, TurnHeldItemTransferModifier, TurnStatusEffectModifier, type EnemyPersistentModifier, type Modifier, type PersistentModifier } from "#app/modifier/modifier"; +import { ModifierTier } from "#app/modifier/modifier-tier"; import Overrides from "#app/overrides"; +import { Unlockables } from "#app/system/unlockables"; +import { getVoucherTypeIcon, getVoucherTypeName, VoucherType } from "#app/system/voucher"; +import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "#app/ui/party-ui-handler"; +import { getModifierTierTextTint } from "#app/ui/text"; +import { formatMoney, getEnumKeys, getEnumValues, IntegerHolder, NumberHolder, padInt, randSeedInt, randSeedItem } from "#app/utils"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; -import { getPokemonNameWithAffix } from "#app/messages"; -import { PermanentStat, TEMP_BATTLE_STATS, TempBattleStat, Stat, getStatKey } from "#enums/stat"; import { SpeciesFormKey } from "#enums/species-form-key"; +import { getStatKey, PermanentStat, Stat, TEMP_BATTLE_STATS, TempBattleStat } from "#enums/stat"; +import i18next from "i18next"; const outputModifierData = false; const useMaxWeightForOutput = false; -type Modifier = Modifiers.Modifier; - export enum ModifierPoolType { PLAYER, WILD, @@ -97,7 +94,7 @@ export class ModifierType { // Try multiple pool types in case of stolen items for (const type of poolTypes) { const pool = getModifierPoolForType(type); - for (const tier of Utils.getEnumValues(ModifierTier)) { + for (const tier of getEnumValues(ModifierTier)) { if (!pool.hasOwnProperty(tier)) { continue; } @@ -171,7 +168,7 @@ class AddPokeballModifierType extends ModifierType { private count: integer; constructor(iconImage: string, pokeballType: PokeballType, count: integer) { - super("", iconImage, (_type, _args) => new Modifiers.AddPokeballModifier(this, pokeballType, count), "pb", "se/pb_bounce_1"); + super("", iconImage, (_type, _args) => new AddPokeballModifier(this, pokeballType, count), "pb", "se/pb_bounce_1"); this.pokeballType = pokeballType; this.count = count; } @@ -198,7 +195,7 @@ class AddVoucherModifierType extends ModifierType { private count: integer; constructor(voucherType: VoucherType, count: integer) { - super("", getVoucherTypeIcon(voucherType), (_type, _args) => new Modifiers.AddVoucherModifier(this, voucherType, count), "voucher"); + super("", getVoucherTypeIcon(voucherType), (_type, _args) => new AddVoucherModifier(this, voucherType, count), "voucher"); this.count = count; this.voucherType = voucherType; } @@ -232,7 +229,7 @@ export class PokemonHeldItemModifierType extends PokemonModifierType { constructor(localeKey: string, iconImage: string, newModifierFunc: NewModifierFunc, group?: string, soundName?: string) { super(localeKey, iconImage, newModifierFunc, (pokemon: PlayerPokemon) => { const dummyModifier = this.newModifier(pokemon); - const matchingModifier = pokemon.scene.findModifier(m => m instanceof Modifiers.PokemonHeldItemModifier && m.pokemonId === pokemon.id && m.matchType(dummyModifier)) as Modifiers.PokemonHeldItemModifier; + const matchingModifier = pokemon.scene.findModifier(m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id && m.matchType(dummyModifier)) as PokemonHeldItemModifier; const maxStackCount = dummyModifier.getMaxStackCount(pokemon.scene); if (!maxStackCount) { return i18next.t("modifierType:ModifierType.PokemonHeldItemModifierType.extra.inoperable", { "pokemonName": getPokemonNameWithAffix(pokemon) }); @@ -244,8 +241,8 @@ export class PokemonHeldItemModifierType extends PokemonModifierType { }, group, soundName); } - newModifier(...args: any[]): Modifiers.PokemonHeldItemModifier { - return super.newModifier(...args) as Modifiers.PokemonHeldItemModifier; + newModifier(...args: any[]): PokemonHeldItemModifier { + return super.newModifier(...args) as PokemonHeldItemModifier; } } @@ -255,7 +252,7 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType { protected healStatus: boolean; constructor(localeKey: string, iconImage: string, restorePoints: integer, restorePercent: integer, healStatus: boolean = false, newModifierFunc?: NewModifierFunc, selectFilter?: PokemonSelectFilter, group?: string) { - super(localeKey, iconImage, newModifierFunc || ((_type, args) => new Modifiers.PokemonHpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePoints, this.restorePercent, this.healStatus, false)), + super(localeKey, iconImage, newModifierFunc || ((_type, args) => new PokemonHpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePoints, this.restorePercent, this.healStatus, false)), selectFilter || ((pokemon: PlayerPokemon) => { if (!pokemon.hp || (pokemon.isFullHp() && (!this.healStatus || (!pokemon.status && !pokemon.getTag(BattlerTagType.CONFUSED))))) { return PartyUiHandler.NoEffectMessage; @@ -282,7 +279,7 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType { export class PokemonReviveModifierType extends PokemonHpRestoreModifierType { constructor(localeKey: string, iconImage: string, restorePercent: integer) { - super(localeKey, iconImage, 0, restorePercent, false, (_type, args) => new Modifiers.PokemonHpRestoreModifier(this, (args[0] as PlayerPokemon).id, 0, this.restorePercent, false, true), + super(localeKey, iconImage, 0, restorePercent, false, (_type, args) => new PokemonHpRestoreModifier(this, (args[0] as PlayerPokemon).id, 0, this.restorePercent, false, true), ((pokemon: PlayerPokemon) => { if (!pokemon.isFainted()) { return PartyUiHandler.NoEffectMessage; @@ -305,7 +302,7 @@ export class PokemonReviveModifierType extends PokemonHpRestoreModifierType { export class PokemonStatusHealModifierType extends PokemonModifierType { constructor(localeKey: string, iconImage: string) { - super(localeKey, iconImage, ((_type, args) => new Modifiers.PokemonStatusHealModifier(this, (args[0] as PlayerPokemon).id)), + super(localeKey, iconImage, ((_type, args) => new PokemonStatusHealModifier(this, (args[0] as PlayerPokemon).id)), ((pokemon: PlayerPokemon) => { if (!pokemon.hp || (!pokemon.status && !pokemon.getTag(BattlerTagType.CONFUSED))) { return PartyUiHandler.NoEffectMessage; @@ -333,7 +330,7 @@ export class PokemonPpRestoreModifierType extends PokemonMoveModifierType { protected restorePoints: integer; constructor(localeKey: string, iconImage: string, restorePoints: integer) { - super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonPpRestoreModifier(this, (args[0] as PlayerPokemon).id, (args[1] as integer), this.restorePoints), + super(localeKey, iconImage, (_type, args) => new PokemonPpRestoreModifier(this, (args[0] as PlayerPokemon).id, (args[1] as integer), this.restorePoints), (_pokemon: PlayerPokemon) => { return null; }, (pokemonMove: PokemonMove) => { @@ -358,7 +355,7 @@ export class PokemonAllMovePpRestoreModifierType extends PokemonModifierType { protected restorePoints: integer; constructor(localeKey: string, iconImage: string, restorePoints: integer) { - super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonAllMovePpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePoints), + super(localeKey, iconImage, (_type, args) => new PokemonAllMovePpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePoints), (pokemon: PlayerPokemon) => { if (!pokemon.getMoveset().filter(m => m?.ppUsed).length) { return PartyUiHandler.NoEffectMessage; @@ -381,7 +378,7 @@ export class PokemonPpUpModifierType extends PokemonMoveModifierType { protected upPoints: integer; constructor(localeKey: string, iconImage: string, upPoints: integer) { - super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonPpUpModifier(this, (args[0] as PlayerPokemon).id, (args[1] as integer), this.upPoints), + super(localeKey, iconImage, (_type, args) => new PokemonPpUpModifier(this, (args[0] as PlayerPokemon).id, (args[1] as integer), this.upPoints), (_pokemon: PlayerPokemon) => { return null; }, (pokemonMove: PokemonMove) => { @@ -403,7 +400,7 @@ export class PokemonNatureChangeModifierType extends PokemonModifierType { protected nature: Nature; constructor(nature: Nature) { - super("", `mint_${Utils.getEnumKeys(Stat).find(s => getNatureStatMultiplier(nature, Stat[s]) > 1)?.toLowerCase() || "neutral" }`, ((_type, args) => new Modifiers.PokemonNatureChangeModifier(this, (args[0] as PlayerPokemon).id, this.nature)), + super("", `mint_${getEnumKeys(Stat).find(s => getNatureStatMultiplier(nature, Stat[s]) > 1)?.toLowerCase() || "neutral" }`, ((_type, args) => new PokemonNatureChangeModifier(this, (args[0] as PlayerPokemon).id, this.nature)), ((pokemon: PlayerPokemon) => { if (pokemon.getNature() === this.nature) { return PartyUiHandler.NoEffectMessage; @@ -425,7 +422,7 @@ export class PokemonNatureChangeModifierType extends PokemonModifierType { export class RememberMoveModifierType extends PokemonModifierType { constructor(localeKey: string, iconImage: string, group?: string) { - super(localeKey, iconImage, (type, args) => new Modifiers.RememberMoveModifier(type, (args[0] as PlayerPokemon).id, (args[1] as integer)), + super(localeKey, iconImage, (type, args) => new RememberMoveModifier(type, (args[0] as PlayerPokemon).id, (args[1] as integer)), (pokemon: PlayerPokemon) => { if (!pokemon.getLearnableLevelMoves().length) { return PartyUiHandler.NoEffectMessage; @@ -439,7 +436,7 @@ export class DoubleBattleChanceBoosterModifierType extends ModifierType { private maxBattles: number; constructor(localeKey: string, iconImage: string, maxBattles: number) { - super(localeKey, iconImage, (_type, _args) => new Modifiers.DoubleBattleChanceBoosterModifier(this, maxBattles), "lure"); + super(localeKey, iconImage, (_type, _args) => new DoubleBattleChanceBoosterModifier(this, maxBattles), "lure"); this.maxBattles = maxBattles; } @@ -458,7 +455,7 @@ export class TempStatStageBoosterModifierType extends ModifierType implements Ge constructor(stat: TempBattleStat) { const nameKey = TempStatStageBoosterModifierTypeGenerator.items[stat]; - super("", nameKey, (_type, _args) => new Modifiers.TempStatStageBoosterModifier(this, this.stat, 5)); + super("", nameKey, (_type, _args) => new TempStatStageBoosterModifier(this, this.stat, 5)); this.stat = stat; this.nameKey = nameKey; @@ -485,7 +482,7 @@ export class BerryModifierType extends PokemonHeldItemModifierType implements Ge private berryType: BerryType; constructor(berryType: BerryType) { - super("", `${BerryType[berryType].toLowerCase()}_berry`, (type, args) => new Modifiers.BerryModifier(type, (args[0] as Pokemon).id, berryType), "berry"); + super("", `${BerryType[berryType].toLowerCase()}_berry`, (type, args) => new BerryModifier(type, (args[0] as Pokemon).id, berryType), "berry"); this.berryType = berryType; } @@ -550,7 +547,7 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i constructor(moveType: Type, boostPercent: integer) { super("", `${getAttackTypeBoosterItemName(moveType)?.replace(/[ \-]/g, "_").toLowerCase()}`, - (_type, args) => new Modifiers.AttackTypeBoosterModifier(this, (args[0] as Pokemon).id, moveType, boostPercent)); + (_type, args) => new AttackTypeBoosterModifier(this, (args[0] as Pokemon).id, moveType, boostPercent)); this.moveType = moveType; this.boostPercent = boostPercent; @@ -573,7 +570,7 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i export type SpeciesStatBoosterItem = keyof typeof SpeciesStatBoosterModifierTypeGenerator.items; /** - * Modifier type for {@linkcode Modifiers.SpeciesStatBoosterModifier} + * Modifier type for {@linkcode SpeciesStatBoosterModifier} * @extends PokemonHeldItemModifierType * @implements GeneratedPersistentModifierType */ @@ -582,7 +579,7 @@ export class SpeciesStatBoosterModifierType extends PokemonHeldItemModifierType constructor(key: SpeciesStatBoosterItem) { const item = SpeciesStatBoosterModifierTypeGenerator.items[key]; - super(`modifierType:SpeciesBoosterItem.${key}`, key.toLowerCase(), (type, args) => new Modifiers.SpeciesStatBoosterModifier(type, (args[0] as Pokemon).id, item.stats, item.multiplier, item.species)); + super(`modifierType:SpeciesBoosterItem.${key}`, key.toLowerCase(), (type, args) => new SpeciesStatBoosterModifier(type, (args[0] as Pokemon).id, item.stats, item.multiplier, item.species)); this.key = key; } @@ -594,12 +591,12 @@ export class SpeciesStatBoosterModifierType extends PokemonHeldItemModifierType export class PokemonLevelIncrementModifierType extends PokemonModifierType { constructor(localeKey: string, iconImage: string) { - super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonLevelIncrementModifier(this, (args[0] as PlayerPokemon).id), (_pokemon: PlayerPokemon) => null); + super(localeKey, iconImage, (_type, args) => new PokemonLevelIncrementModifier(this, (args[0] as PlayerPokemon).id), (_pokemon: PlayerPokemon) => null); } getDescription(scene: BattleScene): string { let levels = 1; - const hasCandyJar = scene.modifiers.find(modifier => modifier instanceof Modifiers.LevelIncrementBoosterModifier); + const hasCandyJar = scene.modifiers.find(modifier => modifier instanceof LevelIncrementBoosterModifier); if (hasCandyJar) { levels += hasCandyJar.stackCount; } @@ -609,12 +606,12 @@ export class PokemonLevelIncrementModifierType extends PokemonModifierType { export class AllPokemonLevelIncrementModifierType extends ModifierType { constructor(localeKey: string, iconImage: string) { - super(localeKey, iconImage, (_type, _args) => new Modifiers.PokemonLevelIncrementModifier(this, -1)); + super(localeKey, iconImage, (_type, _args) => new PokemonLevelIncrementModifier(this, -1)); } getDescription(scene: BattleScene): string { let levels = 1; - const hasCandyJar = scene.modifiers.find(modifier => modifier instanceof Modifiers.LevelIncrementBoosterModifier); + const hasCandyJar = scene.modifiers.find(modifier => modifier instanceof LevelIncrementBoosterModifier); if (hasCandyJar) { levels += hasCandyJar.stackCount; } @@ -628,7 +625,7 @@ export class BaseStatBoosterModifierType extends PokemonHeldItemModifierType imp constructor(stat: PermanentStat) { const key = BaseStatBoosterModifierTypeGenerator.items[stat]; - super("", key, (_type, args) => new Modifiers.BaseStatModifier(this, (args[0] as Pokemon).id, this.stat)); + super("", key, (_type, args) => new BaseStatModifier(this, (args[0] as Pokemon).id, this.stat)); this.stat = stat; this.key = key; @@ -654,7 +651,7 @@ export class PokemonBaseStatTotalModifierType extends PokemonHeldItemModifierTyp private readonly statModifier: integer; constructor(statModifier: integer) { - super("modifierType:ModifierType.MYSTERY_ENCOUNTER_SHUCKLE_JUICE", "berry_juice", (_type, args) => new Modifiers.PokemonBaseStatTotalModifier(this, (args[0] as Pokemon).id, this.statModifier)); + super("modifierType:ModifierType.MYSTERY_ENCOUNTER_SHUCKLE_JUICE", "berry_juice", (_type, args) => new PokemonBaseStatTotalModifier(this, (args[0] as Pokemon).id, this.statModifier)); this.statModifier = statModifier; } @@ -679,7 +676,7 @@ export class PokemonBaseStatFlatModifierType extends PokemonHeldItemModifierType private readonly stats: Stat[]; constructor(statModifier: integer, stats: Stat[]) { - super("modifierType:ModifierType.MYSTERY_ENCOUNTER_OLD_GATEAU", "old_gateau", (_type, args) => new Modifiers.PokemonBaseStatFlatModifier(this, (args[0] as Pokemon).id, this.statModifier, this.stats)); + super("modifierType:ModifierType.MYSTERY_ENCOUNTER_OLD_GATEAU", "old_gateau", (_type, args) => new PokemonBaseStatFlatModifier(this, (args[0] as Pokemon).id, this.statModifier, this.stats)); this.statModifier = statModifier; this.stats = stats; } @@ -700,7 +697,7 @@ class AllPokemonFullHpRestoreModifierType extends ModifierType { private descriptionKey: string; constructor(localeKey: string, iconImage: string, descriptionKey?: string, newModifierFunc?: NewModifierFunc) { - super(localeKey, iconImage, newModifierFunc || ((_type, _args) => new Modifiers.PokemonHpRestoreModifier(this, -1, 0, 100, false))); + super(localeKey, iconImage, newModifierFunc || ((_type, _args) => new PokemonHpRestoreModifier(this, -1, 0, 100, false))); this.descriptionKey = descriptionKey!; // TODO: is this bang correct? } @@ -712,7 +709,7 @@ class AllPokemonFullHpRestoreModifierType extends ModifierType { class AllPokemonFullReviveModifierType extends AllPokemonFullHpRestoreModifierType { constructor(localeKey: string, iconImage: string) { - super(localeKey, iconImage, "modifierType:ModifierType.AllPokemonFullReviveModifierType", (_type, _args) => new Modifiers.PokemonHpRestoreModifier(this, -1, 0, 100, false, true)); + super(localeKey, iconImage, "modifierType:ModifierType.AllPokemonFullReviveModifierType", (_type, _args) => new PokemonHpRestoreModifier(this, -1, 0, 100, false, true)); } } @@ -721,16 +718,16 @@ export class MoneyRewardModifierType extends ModifierType { private moneyMultiplierDescriptorKey: string; constructor(localeKey: string, iconImage: string, moneyMultiplier: number, moneyMultiplierDescriptorKey: string) { - super(localeKey, iconImage, (_type, _args) => new Modifiers.MoneyRewardModifier(this, moneyMultiplier), "money", "se/buy"); + super(localeKey, iconImage, (_type, _args) => new MoneyRewardModifier(this, moneyMultiplier), "money", "se/buy"); this.moneyMultiplier = moneyMultiplier; this.moneyMultiplierDescriptorKey = moneyMultiplierDescriptorKey; } getDescription(scene: BattleScene): string { - const moneyAmount = new Utils.IntegerHolder(scene.getWaveMoneyAmount(this.moneyMultiplier)); + const moneyAmount = new IntegerHolder(scene.getWaveMoneyAmount(this.moneyMultiplier)); scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); - const formattedMoney = Utils.formatMoney(scene.moneyFormat, moneyAmount.value); + const formattedMoney = formatMoney(scene.moneyFormat, moneyAmount.value); return i18next.t("modifierType:ModifierType.MoneyRewardModifierType.description", { moneyMultiplier: i18next.t(this.moneyMultiplierDescriptorKey as any), @@ -743,7 +740,7 @@ export class ExpBoosterModifierType extends ModifierType { private boostPercent: integer; constructor(localeKey: string, iconImage: string, boostPercent: integer) { - super(localeKey, iconImage, () => new Modifiers.ExpBoosterModifier(this, boostPercent)); + super(localeKey, iconImage, () => new ExpBoosterModifier(this, boostPercent)); this.boostPercent = boostPercent; } @@ -757,7 +754,7 @@ export class PokemonExpBoosterModifierType extends PokemonHeldItemModifierType { private boostPercent: integer; constructor(localeKey: string, iconImage: string, boostPercent: integer) { - super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonExpBoosterModifier(this, (args[0] as Pokemon).id, boostPercent)); + super(localeKey, iconImage, (_type, args) => new PokemonExpBoosterModifier(this, (args[0] as Pokemon).id, boostPercent)); this.boostPercent = boostPercent; } @@ -769,7 +766,7 @@ export class PokemonExpBoosterModifierType extends PokemonHeldItemModifierType { export class PokemonFriendshipBoosterModifierType extends PokemonHeldItemModifierType { constructor(localeKey: string, iconImage: string) { - super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonFriendshipBoosterModifier(this, (args[0] as Pokemon).id)); + super(localeKey, iconImage, (_type, args) => new PokemonFriendshipBoosterModifier(this, (args[0] as Pokemon).id)); } getDescription(scene: BattleScene): string { @@ -781,7 +778,7 @@ export class PokemonMoveAccuracyBoosterModifierType extends PokemonHeldItemModif private amount: integer; constructor(localeKey: string, iconImage: string, amount: integer, group?: string, soundName?: string) { - super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonMoveAccuracyBoosterModifier(this, (args[0] as Pokemon).id, amount), group, soundName); + super(localeKey, iconImage, (_type, args) => new PokemonMoveAccuracyBoosterModifier(this, (args[0] as Pokemon).id, amount), group, soundName); this.amount = amount; } @@ -793,7 +790,7 @@ export class PokemonMoveAccuracyBoosterModifierType extends PokemonHeldItemModif export class PokemonMultiHitModifierType extends PokemonHeldItemModifierType { constructor(localeKey: string, iconImage: string) { - super(localeKey, iconImage, (type, args) => new Modifiers.PokemonMultiHitModifier(type as PokemonMultiHitModifierType, (args[0] as Pokemon).id)); + super(localeKey, iconImage, (type, args) => new PokemonMultiHitModifier(type as PokemonMultiHitModifierType, (args[0] as Pokemon).id)); } getDescription(scene: BattleScene): string { @@ -805,7 +802,7 @@ export class TmModifierType extends PokemonModifierType { public moveId: Moves; constructor(moveId: Moves) { - super("", `tm_${Type[allMoves[moveId].type].toLowerCase()}`, (_type, args) => new Modifiers.TmModifier(this, (args[0] as PlayerPokemon).id), + super("", `tm_${Type[allMoves[moveId].type].toLowerCase()}`, (_type, args) => new TmModifier(this, (args[0] as PlayerPokemon).id), (pokemon: PlayerPokemon) => { if (pokemon.compatibleTms.indexOf(moveId) === -1 || pokemon.getMoveset().filter(m => m?.moveId === moveId).length) { return PartyUiHandler.NoEffectMessage; @@ -818,7 +815,7 @@ export class TmModifierType extends PokemonModifierType { get name(): string { return i18next.t("modifierType:ModifierType.TmModifierType.name", { - moveId: Utils.padInt(Object.keys(tmSpecies).indexOf(this.moveId.toString()) + 1, 3), + moveId: padInt(Object.keys(tmSpecies).indexOf(this.moveId.toString()) + 1, 3), moveName: allMoves[this.moveId].name, }); } @@ -832,7 +829,7 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge public evolutionItem: EvolutionItem; constructor(evolutionItem: EvolutionItem) { - super("", EvolutionItem[evolutionItem].toLowerCase(), (_type, args) => new Modifiers.EvolutionItemModifier(this, (args[0] as PlayerPokemon).id), + super("", EvolutionItem[evolutionItem].toLowerCase(), (_type, args) => new EvolutionItemModifier(this, (args[0] as PlayerPokemon).id), (pokemon: PlayerPokemon) => { if (pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.item === this.evolutionItem && (!e.condition || e.condition.predicate(pokemon)) && (e.preFormKey === null || e.preFormKey === pokemon.getFormKey())).length && (pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX)) { @@ -868,7 +865,7 @@ export class FormChangeItemModifierType extends PokemonModifierType implements G public formChangeItem: FormChangeItem; constructor(formChangeItem: FormChangeItem) { - super("", FormChangeItem[formChangeItem].toLowerCase(), (_type, args) => new Modifiers.PokemonFormChangeItemModifier(this, (args[0] as PlayerPokemon).id, formChangeItem, true), + super("", FormChangeItem[formChangeItem].toLowerCase(), (_type, args) => new PokemonFormChangeItemModifier(this, (args[0] as PlayerPokemon).id, formChangeItem, true), (pokemon: PlayerPokemon) => { // Make sure the Pokemon has alternate forms if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) @@ -902,7 +899,7 @@ export class FormChangeItemModifierType extends PokemonModifierType implements G export class FusePokemonModifierType extends PokemonModifierType { constructor(localeKey: string, iconImage: string) { - super(localeKey, iconImage, (_type, args) => new Modifiers.FusePokemonModifier(this, (args[0] as PlayerPokemon).id, (args[1] as PlayerPokemon).id), + super(localeKey, iconImage, (_type, args) => new FusePokemonModifier(this, (args[0] as PlayerPokemon).id, (args[1] as PlayerPokemon).id), (pokemon: PlayerPokemon) => { if (pokemon.isFusion()) { return PartyUiHandler.NoEffectMessage; @@ -949,7 +946,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { let type: Type; - const randInt = Utils.randSeedInt(totalWeight); + const randInt = randSeedInt(totalWeight); let weight = 0; for (const t of attackMoveTypeWeights.keys()) { @@ -981,7 +978,7 @@ class BaseStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { if (pregenArgs) { return new BaseStatBoosterModifierType(pregenArgs[0]); } - const randStat: PermanentStat = Utils.randSeedInt(Stat.SPD + 1); + const randStat: PermanentStat = randSeedInt(Stat.SPD + 1); return new BaseStatBoosterModifierType(randStat); }); } @@ -1002,7 +999,7 @@ class TempStatStageBoosterModifierTypeGenerator extends ModifierTypeGenerator { if (pregenArgs && (pregenArgs.length === 1) && TEMP_BATTLE_STATS.includes(pregenArgs[0])) { return new TempStatStageBoosterModifierType(pregenArgs[0]); } - const randStat: TempBattleStat = Utils.randSeedInt(Stat.ACC, Stat.ATK); + const randStat: TempBattleStat = randSeedInt(Stat.ACC, Stat.ATK); return new TempStatStageBoosterModifierType(randStat); }); } @@ -1044,8 +1041,8 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { const checkedStats = values[i].stats; // If party member already has the item being weighted currently, skip to the next item - const hasItem = p.getHeldItems().some(m => m instanceof Modifiers.SpeciesStatBoosterModifier - && (m as Modifiers.SpeciesStatBoosterModifier).contains(checkedSpecies[0], checkedStats[0])); + const hasItem = p.getHeldItems().some(m => m instanceof SpeciesStatBoosterModifier + && (m as SpeciesStatBoosterModifier).contains(checkedSpecies[0], checkedStats[0])); if (!hasItem) { if (checkedSpecies.includes(speciesId) || (!!fusionSpeciesId && checkedSpecies.includes(fusionSpeciesId))) { @@ -1065,7 +1062,7 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { } if (totalWeight !== 0) { - const randInt = Utils.randSeedInt(totalWeight, 1); + const randInt = randSeedInt(totalWeight, 1); let weight = 0; for (const i in weights) { @@ -1095,7 +1092,7 @@ class TmModifierTypeGenerator extends ModifierTypeGenerator { if (!tierUniqueCompatibleTms.length) { return null; } - const randTmIndex = Utils.randSeedInt(tierUniqueCompatibleTms.length); + const randTmIndex = randSeedInt(tierUniqueCompatibleTms.length); return new TmModifierType(tierUniqueCompatibleTms[randTmIndex]); }); } @@ -1123,7 +1120,7 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator { return null; } - return new EvolutionItemModifierType(evolutionItemPool[Utils.randSeedInt(evolutionItemPool.length)]!); // TODO: is the bang correct? + return new EvolutionItemModifierType(evolutionItemPool[randSeedInt(evolutionItemPool.length)]!); // TODO: is the bang correct? }); } } @@ -1137,12 +1134,12 @@ class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator { const formChangeItemPool = [...new Set(party.filter(p => pokemonFormChanges.hasOwnProperty(p.species.speciesId)).map(p => { const formChanges = pokemonFormChanges[p.species.speciesId]; - let formChangeItemTriggers = formChanges.filter(fc => ((fc.formKey.indexOf(SpeciesFormKey.MEGA) === -1 && fc.formKey.indexOf(SpeciesFormKey.PRIMAL) === -1) || party[0].scene.getModifiers(Modifiers.MegaEvolutionAccessModifier).length) - && ((fc.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) === -1 && fc.formKey.indexOf(SpeciesFormKey.ETERNAMAX) === -1) || party[0].scene.getModifiers(Modifiers.GigantamaxAccessModifier).length) + let formChangeItemTriggers = formChanges.filter(fc => ((fc.formKey.indexOf(SpeciesFormKey.MEGA) === -1 && fc.formKey.indexOf(SpeciesFormKey.PRIMAL) === -1) || party[0].scene.getModifiers(MegaEvolutionAccessModifier).length) + && ((fc.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) === -1 && fc.formKey.indexOf(SpeciesFormKey.ETERNAMAX) === -1) || party[0].scene.getModifiers(GigantamaxAccessModifier).length) && (!fc.conditions.length || fc.conditions.filter(cond => cond instanceof SpeciesFormChangeCondition && cond.predicate(p)).length) && (fc.preFormKey === p.getFormKey())) .map(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger) - .filter(t => t && t.active && !p.scene.findModifier(m => m instanceof Modifiers.PokemonFormChangeItemModifier && m.pokemonId === p.id && m.formChangeItem === t.item)); + .filter(t => t && t.active && !p.scene.findModifier(m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === p.id && m.formChangeItem === t.item)); if (p.species.speciesId === Species.NECROZMA) { // technically we could use a simplified version and check for formChanges.length > 3, but in case any code changes later, this might break... @@ -1177,7 +1174,7 @@ class FormChangeItemModifierTypeGenerator extends ModifierTypeGenerator { return null; } - return new FormChangeItemModifierType(formChangeItemPool[Utils.randSeedInt(formChangeItemPool.length)]); + return new FormChangeItemModifierType(formChangeItemPool[randSeedInt(formChangeItemPool.length)]); }); } } @@ -1186,7 +1183,7 @@ export class TerastallizeModifierType extends PokemonHeldItemModifierType implem private teraType: Type; constructor(teraType: Type) { - super("", `${Type[teraType].toLowerCase()}_tera_shard`, (type, args) => new Modifiers.TerastallizeModifier(type as TerastallizeModifierType, (args[0] as Pokemon).id, teraType), "tera_shard"); + super("", `${Type[teraType].toLowerCase()}_tera_shard`, (type, args) => new TerastallizeModifier(type as TerastallizeModifierType, (args[0] as Pokemon).id, teraType), "tera_shard"); this.teraType = teraType; } @@ -1208,7 +1205,7 @@ export class ContactHeldItemTransferChanceModifierType extends PokemonHeldItemMo private chancePercent: integer; constructor(localeKey: string, iconImage: string, chancePercent: integer, group?: string, soundName?: string) { - super(localeKey, iconImage, (type, args) => new Modifiers.ContactHeldItemTransferChanceModifier(type, (args[0] as Pokemon).id, chancePercent), group, soundName); + super(localeKey, iconImage, (type, args) => new ContactHeldItemTransferChanceModifier(type, (args[0] as Pokemon).id, chancePercent), group, soundName); this.chancePercent = chancePercent; } @@ -1220,7 +1217,7 @@ export class ContactHeldItemTransferChanceModifierType extends PokemonHeldItemMo export class TurnHeldItemTransferModifierType extends PokemonHeldItemModifierType { constructor(localeKey: string, iconImage: string, group?: string, soundName?: string) { - super(localeKey, iconImage, (type, args) => new Modifiers.TurnHeldItemTransferModifier(type, (args[0] as Pokemon).id), group, soundName); + super(localeKey, iconImage, (type, args) => new TurnHeldItemTransferModifier(type, (args[0] as Pokemon).id), group, soundName); } getDescription(scene: BattleScene): string { @@ -1233,7 +1230,7 @@ export class EnemyAttackStatusEffectChanceModifierType extends ModifierType { private effect: StatusEffect; constructor(localeKey: string, iconImage: string, chancePercent: integer, effect: StatusEffect, stackCount?: integer) { - super(localeKey, iconImage, (type, args) => new Modifiers.EnemyAttackStatusEffectChanceModifier(type, effect, chancePercent, stackCount), "enemy_status_chance"); + super(localeKey, iconImage, (type, args) => new EnemyAttackStatusEffectChanceModifier(type, effect, chancePercent, stackCount), "enemy_status_chance"); this.chancePercent = chancePercent; this.effect = effect; @@ -1251,7 +1248,7 @@ export class EnemyEndureChanceModifierType extends ModifierType { private chancePercent: number; constructor(localeKey: string, iconImage: string, chancePercent: number) { - super(localeKey, iconImage, (type, _args) => new Modifiers.EnemyEndureChanceModifier(type, chancePercent), "enemy_endure"); + super(localeKey, iconImage, (type, _args) => new EnemyEndureChanceModifier(type, chancePercent), "enemy_endure"); this.chancePercent = chancePercent; } @@ -1298,7 +1295,7 @@ function skipInLastClassicWaveOrDefault(defaultWeight: integer) : WeightedModifi */ function lureWeightFunc(maxBattles: number, weight: number): WeightedModifierTypeWeightFunc { return (party: Pokemon[]) => { - const lures = party[0].scene.getModifiers(Modifiers.DoubleBattleChanceBoosterModifier); + const lures = party[0].scene.getModifiers(DoubleBattleChanceBoosterModifier); return !(party[0].scene.gameMode.isClassic && party[0].scene.currentBattle.waveIndex === 199) && (lures.length === 0 || lures.filter(m => m.getMaxBattles() === maxBattles && m.getBattleCount() >= maxBattles * 0.6).length === 0) ? weight : 0; }; } @@ -1388,13 +1385,13 @@ export const modifierTypes = { RARE_FORM_CHANGE_ITEM: () => new FormChangeItemModifierTypeGenerator(true), EVOLUTION_TRACKER_GIMMIGHOUL: () => new PokemonHeldItemModifierType("modifierType:ModifierType.EVOLUTION_TRACKER_GIMMIGHOUL", "relic_gold", - (type, args) => new Modifiers.EvoTrackerModifier(type, (args[0] as Pokemon).id, Species.GIMMIGHOUL, 10)), + (type, args) => new EvoTrackerModifier(type, (args[0] as Pokemon).id, Species.GIMMIGHOUL, 10)), - MEGA_BRACELET: () => new ModifierType("modifierType:ModifierType.MEGA_BRACELET", "mega_bracelet", (type, _args) => new Modifiers.MegaEvolutionAccessModifier(type)), - DYNAMAX_BAND: () => new ModifierType("modifierType:ModifierType.DYNAMAX_BAND", "dynamax_band", (type, _args) => new Modifiers.GigantamaxAccessModifier(type)), - TERA_ORB: () => new ModifierType("modifierType:ModifierType.TERA_ORB", "tera_orb", (type, _args) => new Modifiers.TerastallizeAccessModifier(type)), + MEGA_BRACELET: () => new ModifierType("modifierType:ModifierType.MEGA_BRACELET", "mega_bracelet", (type, _args) => new MegaEvolutionAccessModifier(type)), + DYNAMAX_BAND: () => new ModifierType("modifierType:ModifierType.DYNAMAX_BAND", "dynamax_band", (type, _args) => new GigantamaxAccessModifier(type)), + TERA_ORB: () => new ModifierType("modifierType:ModifierType.TERA_ORB", "tera_orb", (type, _args) => new TerastallizeAccessModifier(type)), - MAP: () => new ModifierType("modifierType:ModifierType.MAP", "map", (type, _args) => new Modifiers.MapModifier(type)), + MAP: () => new ModifierType("modifierType:ModifierType.MAP", "map", (type, _args) => new MapModifier(type)), POTION: () => new PokemonHpRestoreModifierType("modifierType:ModifierType.POTION", "potion", 20, 10), SUPER_POTION: () => new PokemonHpRestoreModifierType("modifierType:ModifierType.SUPER_POTION", "super_potion", 50, 25), @@ -1409,8 +1406,8 @@ export const modifierTypes = { SACRED_ASH: () => new AllPokemonFullReviveModifierType("modifierType:ModifierType.SACRED_ASH", "sacred_ash"), - REVIVER_SEED: () => new PokemonHeldItemModifierType("modifierType:ModifierType.REVIVER_SEED", "reviver_seed", (type, args) => new Modifiers.PokemonInstantReviveModifier(type, (args[0] as Pokemon).id)), - WHITE_HERB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.WHITE_HERB", "white_herb", (type, args) => new Modifiers.ResetNegativeStatStageModifier(type, (args[0] as Pokemon).id)), + REVIVER_SEED: () => new PokemonHeldItemModifierType("modifierType:ModifierType.REVIVER_SEED", "reviver_seed", (type, args) => new PokemonInstantReviveModifier(type, (args[0] as Pokemon).id)), + WHITE_HERB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.WHITE_HERB", "white_herb", (type, args) => new ResetNegativeStatStageModifier(type, (args[0] as Pokemon).id)), ETHER: () => new PokemonPpRestoreModifierType("modifierType:ModifierType.ETHER", "ether", 10), MAX_ETHER: () => new PokemonPpRestoreModifierType("modifierType:ModifierType.MAX_ETHER", "max_ether", -1), @@ -1440,7 +1437,7 @@ export const modifierTypes = { amount: i18next.t("modifierType:ModifierType.TempStatStageBoosterModifierType.extra.stage") }); } - }("modifierType:ModifierType.DIRE_HIT", "dire_hit", (type, _args) => new Modifiers.TempCritBoosterModifier(type, 5)), + }("modifierType:ModifierType.DIRE_HIT", "dire_hit", (type, _args) => new TempCritBoosterModifier(type, 5)), BASE_STAT_BOOSTER: () => new BaseStatBoosterModifierTypeGenerator(), @@ -1450,22 +1447,22 @@ export const modifierTypes = { if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in Nature)) { return new PokemonNatureChangeModifierType(pregenArgs[0] as Nature); } - return new PokemonNatureChangeModifierType(Utils.randSeedInt(Utils.getEnumValues(Nature).length) as Nature); + return new PokemonNatureChangeModifierType(randSeedInt(getEnumValues(Nature).length) as Nature); }), TERA_SHARD: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in Type)) { return new TerastallizeModifierType(pregenArgs[0] as Type); } - if (!party[0].scene.getModifiers(Modifiers.TerastallizeAccessModifier).length) { + if (!party[0].scene.getModifiers(TerastallizeAccessModifier).length) { return null; } let type: Type; - if (!Utils.randSeedInt(3)) { + if (!randSeedInt(3)) { const partyMemberTypes = party.map(p => p.getTypes(false, false, true)).flat(); - type = Utils.randSeedItem(partyMemberTypes); + type = randSeedItem(partyMemberTypes); } else { - type = Utils.randSeedInt(64) ? Utils.randSeedInt(18) as Type : Type.STELLAR; + type = randSeedInt(64) ? randSeedInt(18) as Type : Type.STELLAR; } return new TerastallizeModifierType(type); }), @@ -1474,9 +1471,9 @@ export const modifierTypes = { if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in BerryType)) { return new BerryModifierType(pregenArgs[0] as BerryType); } - const berryTypes = Utils.getEnumValues(BerryType); + const berryTypes = getEnumValues(BerryType); let randBerryType: BerryType; - const rand = Utils.randSeedInt(12); + const rand = randSeedInt(12); if (rand < 2) { randBerryType = BerryType.SITRUS; } else if (rand < 4) { @@ -1484,7 +1481,7 @@ export const modifierTypes = { } else if (rand < 6) { randBerryType = BerryType.LEPPA; } else { - randBerryType = berryTypes[Utils.randSeedInt(berryTypes.length - 3) + 2]; + randBerryType = berryTypes[randSeedInt(berryTypes.length - 3) + 2]; } return new BerryModifierType(randBerryType); }), @@ -1495,10 +1492,10 @@ export const modifierTypes = { MEMORY_MUSHROOM: () => new RememberMoveModifierType("modifierType:ModifierType.MEMORY_MUSHROOM", "big_mushroom"), - EXP_SHARE: () => new ModifierType("modifierType:ModifierType.EXP_SHARE", "exp_share", (type, _args) => new Modifiers.ExpShareModifier(type)), - EXP_BALANCE: () => new ModifierType("modifierType:ModifierType.EXP_BALANCE", "exp_balance", (type, _args) => new Modifiers.ExpBalanceModifier(type)), + EXP_SHARE: () => new ModifierType("modifierType:ModifierType.EXP_SHARE", "exp_share", (type, _args) => new ExpShareModifier(type)), + EXP_BALANCE: () => new ModifierType("modifierType:ModifierType.EXP_BALANCE", "exp_balance", (type, _args) => new ExpBalanceModifier(type)), - OVAL_CHARM: () => new ModifierType("modifierType:ModifierType.OVAL_CHARM", "oval_charm", (type, _args) => new Modifiers.MultipleParticipantExpBonusModifier(type)), + OVAL_CHARM: () => new ModifierType("modifierType:ModifierType.OVAL_CHARM", "oval_charm", (type, _args) => new MultipleParticipantExpBonusModifier(type)), EXP_CHARM: () => new ExpBoosterModifierType("modifierType:ModifierType.EXP_CHARM", "exp_charm", 25), SUPER_EXP_CHARM: () => new ExpBoosterModifierType("modifierType:ModifierType.SUPER_EXP_CHARM", "super_exp_charm", 60), @@ -1509,51 +1506,51 @@ export const modifierTypes = { SOOTHE_BELL: () => new PokemonFriendshipBoosterModifierType("modifierType:ModifierType.SOOTHE_BELL", "soothe_bell"), - SCOPE_LENS: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SCOPE_LENS", "scope_lens", (type, args) => new Modifiers.CritBoosterModifier(type, (args[0] as Pokemon).id, 1)), - LEEK: () => new PokemonHeldItemModifierType("modifierType:ModifierType.LEEK", "leek", (type, args) => new Modifiers.SpeciesCritBoosterModifier(type, (args[0] as Pokemon).id, 2, [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD])), + SCOPE_LENS: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SCOPE_LENS", "scope_lens", (type, args) => new CritBoosterModifier(type, (args[0] as Pokemon).id, 1)), + LEEK: () => new PokemonHeldItemModifierType("modifierType:ModifierType.LEEK", "leek", (type, args) => new SpeciesCritBoosterModifier(type, (args[0] as Pokemon).id, 2, [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD])), - EVIOLITE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.EVIOLITE", "eviolite", (type, args) => new Modifiers.EvolutionStatBoosterModifier(type, (args[0] as Pokemon).id, [Stat.DEF, Stat.SPDEF], 1.5)), + EVIOLITE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.EVIOLITE", "eviolite", (type, args) => new EvolutionStatBoosterModifier(type, (args[0] as Pokemon).id, [Stat.DEF, Stat.SPDEF], 1.5)), - SOUL_DEW: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SOUL_DEW", "soul_dew", (type, args) => new Modifiers.PokemonNatureWeightModifier(type, (args[0] as Pokemon).id)), + SOUL_DEW: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SOUL_DEW", "soul_dew", (type, args) => new PokemonNatureWeightModifier(type, (args[0] as Pokemon).id)), NUGGET: () => new MoneyRewardModifierType("modifierType:ModifierType.NUGGET", "nugget", 1, "modifierType:ModifierType.MoneyRewardModifierType.extra.small"), BIG_NUGGET: () => new MoneyRewardModifierType("modifierType:ModifierType.BIG_NUGGET", "big_nugget", 2.5, "modifierType:ModifierType.MoneyRewardModifierType.extra.moderate"), RELIC_GOLD: () => new MoneyRewardModifierType("modifierType:ModifierType.RELIC_GOLD", "relic_gold", 10, "modifierType:ModifierType.MoneyRewardModifierType.extra.large"), - AMULET_COIN: () => new ModifierType("modifierType:ModifierType.AMULET_COIN", "amulet_coin", (type, _args) => new Modifiers.MoneyMultiplierModifier(type)), - GOLDEN_PUNCH: () => new PokemonHeldItemModifierType("modifierType:ModifierType.GOLDEN_PUNCH", "golden_punch", (type, args) => new Modifiers.DamageMoneyRewardModifier(type, (args[0] as Pokemon).id)), - COIN_CASE: () => new ModifierType("modifierType:ModifierType.COIN_CASE", "coin_case", (type, _args) => new Modifiers.MoneyInterestModifier(type)), + AMULET_COIN: () => new ModifierType("modifierType:ModifierType.AMULET_COIN", "amulet_coin", (type, _args) => new MoneyMultiplierModifier(type)), + GOLDEN_PUNCH: () => new PokemonHeldItemModifierType("modifierType:ModifierType.GOLDEN_PUNCH", "golden_punch", (type, args) => new DamageMoneyRewardModifier(type, (args[0] as Pokemon).id)), + COIN_CASE: () => new ModifierType("modifierType:ModifierType.COIN_CASE", "coin_case", (type, _args) => new MoneyInterestModifier(type)), - LOCK_CAPSULE: () => new ModifierType("modifierType:ModifierType.LOCK_CAPSULE", "lock_capsule", (type, _args) => new Modifiers.LockModifierTiersModifier(type)), + LOCK_CAPSULE: () => new ModifierType("modifierType:ModifierType.LOCK_CAPSULE", "lock_capsule", (type, _args) => new LockModifierTiersModifier(type)), GRIP_CLAW: () => new ContactHeldItemTransferChanceModifierType("modifierType:ModifierType.GRIP_CLAW", "grip_claw", 10), WIDE_LENS: () => new PokemonMoveAccuracyBoosterModifierType("modifierType:ModifierType.WIDE_LENS", "wide_lens", 5), MULTI_LENS: () => new PokemonMultiHitModifierType("modifierType:ModifierType.MULTI_LENS", "zoom_lens"), - HEALING_CHARM: () => new ModifierType("modifierType:ModifierType.HEALING_CHARM", "healing_charm", (type, _args) => new Modifiers.HealingBoosterModifier(type, 1.1)), - CANDY_JAR: () => new ModifierType("modifierType:ModifierType.CANDY_JAR", "candy_jar", (type, _args) => new Modifiers.LevelIncrementBoosterModifier(type)), + HEALING_CHARM: () => new ModifierType("modifierType:ModifierType.HEALING_CHARM", "healing_charm", (type, _args) => new HealingBoosterModifier(type, 1.1)), + CANDY_JAR: () => new ModifierType("modifierType:ModifierType.CANDY_JAR", "candy_jar", (type, _args) => new LevelIncrementBoosterModifier(type)), - BERRY_POUCH: () => new ModifierType("modifierType:ModifierType.BERRY_POUCH", "berry_pouch", (type, _args) => new Modifiers.PreserveBerryModifier(type)), + BERRY_POUCH: () => new ModifierType("modifierType:ModifierType.BERRY_POUCH", "berry_pouch", (type, _args) => new PreserveBerryModifier(type)), - FOCUS_BAND: () => new PokemonHeldItemModifierType("modifierType:ModifierType.FOCUS_BAND", "focus_band", (type, args) => new Modifiers.SurviveDamageModifier(type, (args[0] as Pokemon).id)), + FOCUS_BAND: () => new PokemonHeldItemModifierType("modifierType:ModifierType.FOCUS_BAND", "focus_band", (type, args) => new SurviveDamageModifier(type, (args[0] as Pokemon).id)), - QUICK_CLAW: () => new PokemonHeldItemModifierType("modifierType:ModifierType.QUICK_CLAW", "quick_claw", (type, args) => new Modifiers.BypassSpeedChanceModifier(type, (args[0] as Pokemon).id)), + QUICK_CLAW: () => new PokemonHeldItemModifierType("modifierType:ModifierType.QUICK_CLAW", "quick_claw", (type, args) => new BypassSpeedChanceModifier(type, (args[0] as Pokemon).id)), - KINGS_ROCK: () => new PokemonHeldItemModifierType("modifierType:ModifierType.KINGS_ROCK", "kings_rock", (type, args) => new Modifiers.FlinchChanceModifier(type, (args[0] as Pokemon).id)), + KINGS_ROCK: () => new PokemonHeldItemModifierType("modifierType:ModifierType.KINGS_ROCK", "kings_rock", (type, args) => new FlinchChanceModifier(type, (args[0] as Pokemon).id)), - LEFTOVERS: () => new PokemonHeldItemModifierType("modifierType:ModifierType.LEFTOVERS", "leftovers", (type, args) => new Modifiers.TurnHealModifier(type, (args[0] as Pokemon).id)), - SHELL_BELL: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SHELL_BELL", "shell_bell", (type, args) => new Modifiers.HitHealModifier(type, (args[0] as Pokemon).id)), + LEFTOVERS: () => new PokemonHeldItemModifierType("modifierType:ModifierType.LEFTOVERS", "leftovers", (type, args) => new TurnHealModifier(type, (args[0] as Pokemon).id)), + SHELL_BELL: () => new PokemonHeldItemModifierType("modifierType:ModifierType.SHELL_BELL", "shell_bell", (type, args) => new HitHealModifier(type, (args[0] as Pokemon).id)), - TOXIC_ORB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.TOXIC_ORB", "toxic_orb", (type, args) => new Modifiers.TurnStatusEffectModifier(type, (args[0] as Pokemon).id)), - FLAME_ORB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.FLAME_ORB", "flame_orb", (type, args) => new Modifiers.TurnStatusEffectModifier(type, (args[0] as Pokemon).id)), + TOXIC_ORB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.TOXIC_ORB", "toxic_orb", (type, args) => new TurnStatusEffectModifier(type, (args[0] as Pokemon).id)), + FLAME_ORB: () => new PokemonHeldItemModifierType("modifierType:ModifierType.FLAME_ORB", "flame_orb", (type, args) => new TurnStatusEffectModifier(type, (args[0] as Pokemon).id)), - BATON: () => new PokemonHeldItemModifierType("modifierType:ModifierType.BATON", "baton", (type, args) => new Modifiers.SwitchEffectTransferModifier(type, (args[0] as Pokemon).id)), + BATON: () => new PokemonHeldItemModifierType("modifierType:ModifierType.BATON", "baton", (type, args) => new SwitchEffectTransferModifier(type, (args[0] as Pokemon).id)), - SHINY_CHARM: () => new ModifierType("modifierType:ModifierType.SHINY_CHARM", "shiny_charm", (type, _args) => new Modifiers.ShinyRateBoosterModifier(type)), - ABILITY_CHARM: () => new ModifierType("modifierType:ModifierType.ABILITY_CHARM", "ability_charm", (type, _args) => new Modifiers.HiddenAbilityRateBoosterModifier(type)), + SHINY_CHARM: () => new ModifierType("modifierType:ModifierType.SHINY_CHARM", "shiny_charm", (type, _args) => new ShinyRateBoosterModifier(type)), + ABILITY_CHARM: () => new ModifierType("modifierType:ModifierType.ABILITY_CHARM", "ability_charm", (type, _args) => new HiddenAbilityRateBoosterModifier(type)), - IV_SCANNER: () => new ModifierType("modifierType:ModifierType.IV_SCANNER", "scanner", (type, _args) => new Modifiers.IvScannerModifier(type)), + IV_SCANNER: () => new ModifierType("modifierType:ModifierType.IV_SCANNER", "scanner", (type, _args) => new IvScannerModifier(type)), DNA_SPLICERS: () => new FusePokemonModifierType("modifierType:ModifierType.DNA_SPLICERS", "dna_splicers"), @@ -1563,39 +1560,39 @@ export const modifierTypes = { VOUCHER_PLUS: () => new AddVoucherModifierType(VoucherType.PLUS, 1), VOUCHER_PREMIUM: () => new AddVoucherModifierType(VoucherType.PREMIUM, 1), - GOLDEN_POKEBALL: () => new ModifierType("modifierType:ModifierType.GOLDEN_POKEBALL", "pb_gold", (type, _args) => new Modifiers.ExtraModifierModifier(type), undefined, "se/pb_bounce_1"), + GOLDEN_POKEBALL: () => new ModifierType("modifierType:ModifierType.GOLDEN_POKEBALL", "pb_gold", (type, _args) => new ExtraModifierModifier(type), undefined, "se/pb_bounce_1"), - ENEMY_DAMAGE_BOOSTER: () => new ModifierType("modifierType:ModifierType.ENEMY_DAMAGE_BOOSTER", "wl_item_drop", (type, _args) => new Modifiers.EnemyDamageBoosterModifier(type, 5)), - ENEMY_DAMAGE_REDUCTION: () => new ModifierType("modifierType:ModifierType.ENEMY_DAMAGE_REDUCTION", "wl_guard_spec", (type, _args) => new Modifiers.EnemyDamageReducerModifier(type, 2.5)), - //ENEMY_SUPER_EFFECT_BOOSTER: () => new ModifierType('Type Advantage Token', 'Increases damage of super effective attacks by 30%', (type, _args) => new Modifiers.EnemySuperEffectiveDamageBoosterModifier(type, 30), 'wl_custom_super_effective'), - ENEMY_HEAL: () => new ModifierType("modifierType:ModifierType.ENEMY_HEAL", "wl_potion", (type, _args) => new Modifiers.EnemyTurnHealModifier(type, 2, 10)), + ENEMY_DAMAGE_BOOSTER: () => new ModifierType("modifierType:ModifierType.ENEMY_DAMAGE_BOOSTER", "wl_item_drop", (type, _args) => new EnemyDamageBoosterModifier(type, 5)), + ENEMY_DAMAGE_REDUCTION: () => new ModifierType("modifierType:ModifierType.ENEMY_DAMAGE_REDUCTION", "wl_guard_spec", (type, _args) => new EnemyDamageReducerModifier(type, 2.5)), + //ENEMY_SUPER_EFFECT_BOOSTER: () => new ModifierType('Type Advantage Token', 'Increases damage of super effective attacks by 30%', (type, _args) => new EnemySuperEffectiveDamageBoosterModifier(type, 30), 'wl_custom_super_effective'), + ENEMY_HEAL: () => new ModifierType("modifierType:ModifierType.ENEMY_HEAL", "wl_potion", (type, _args) => new EnemyTurnHealModifier(type, 2, 10)), ENEMY_ATTACK_POISON_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType("modifierType:ModifierType.ENEMY_ATTACK_POISON_CHANCE", "wl_antidote", 5, StatusEffect.POISON, 10), ENEMY_ATTACK_PARALYZE_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType("modifierType:ModifierType.ENEMY_ATTACK_PARALYZE_CHANCE", "wl_paralyze_heal", 2.5, StatusEffect.PARALYSIS, 10), ENEMY_ATTACK_BURN_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType("modifierType:ModifierType.ENEMY_ATTACK_BURN_CHANCE", "wl_burn_heal", 5, StatusEffect.BURN, 10), - ENEMY_STATUS_EFFECT_HEAL_CHANCE: () => new ModifierType("modifierType:ModifierType.ENEMY_STATUS_EFFECT_HEAL_CHANCE", "wl_full_heal", (type, _args) => new Modifiers.EnemyStatusEffectHealChanceModifier(type, 2.5, 10)), + ENEMY_STATUS_EFFECT_HEAL_CHANCE: () => new ModifierType("modifierType:ModifierType.ENEMY_STATUS_EFFECT_HEAL_CHANCE", "wl_full_heal", (type, _args) => new EnemyStatusEffectHealChanceModifier(type, 2.5, 10)), ENEMY_ENDURE_CHANCE: () => new EnemyEndureChanceModifierType("modifierType:ModifierType.ENEMY_ENDURE_CHANCE", "wl_reset_urge", 2), - ENEMY_FUSED_CHANCE: () => new ModifierType("modifierType:ModifierType.ENEMY_FUSED_CHANCE", "wl_custom_spliced", (type, _args) => new Modifiers.EnemyFusionChanceModifier(type, 1)), + ENEMY_FUSED_CHANCE: () => new ModifierType("modifierType:ModifierType.ENEMY_FUSED_CHANCE", "wl_custom_spliced", (type, _args) => new EnemyFusionChanceModifier(type, 1)), MYSTERY_ENCOUNTER_SHUCKLE_JUICE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs) { return new PokemonBaseStatTotalModifierType(pregenArgs[0] as number); } - return new PokemonBaseStatTotalModifierType(Utils.randSeedInt(20)); + return new PokemonBaseStatTotalModifierType(randSeedInt(20)); }), MYSTERY_ENCOUNTER_OLD_GATEAU: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs) { return new PokemonBaseStatFlatModifierType(pregenArgs[0] as number, pregenArgs[1] as Stat[]); } - return new PokemonBaseStatFlatModifierType(Utils.randSeedInt(20), [Stat.HP, Stat.ATK, Stat.DEF]); + return new PokemonBaseStatFlatModifierType(randSeedInt(20), [Stat.HP, Stat.ATK, Stat.DEF]); }), MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { if (pregenArgs) { - return new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.HealShopCostModifier(type, pregenArgs[0] as number)); + return new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new HealShopCostModifier(type, pregenArgs[0] as number)); } - return new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new Modifiers.HealShopCostModifier(type, 2.5)); + return new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_BLACK_SLUDGE", "black_sludge", (type, _args) => new HealShopCostModifier(type, 2.5)); }), - MYSTERY_ENCOUNTER_MACHO_BRACE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_MACHO_BRACE", "macho_brace", (type, args) => new Modifiers.PokemonIncrementingStatModifier(type, (args[0] as Pokemon).id)), - MYSTERY_ENCOUNTER_GOLDEN_BUG_NET: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET", "golden_net", (type, _args) => new Modifiers.BoostBugSpawnModifier(type)), + MYSTERY_ENCOUNTER_MACHO_BRACE: () => new PokemonHeldItemModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_MACHO_BRACE", "macho_brace", (type, args) => new PokemonIncrementingStatModifier(type, (args[0] as Pokemon).id)), + MYSTERY_ENCOUNTER_GOLDEN_BUG_NET: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET", "golden_net", (type, _args) => new BoostBugSpawnModifier(type)), }; interface ModifierPool { @@ -1644,8 +1641,8 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.PP_UP, 2), new WeightedModifierType(modifierTypes.FULL_HEAL, (party: Pokemon[]) => { const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => { - if (i instanceof Modifiers.TurnStatusEffectModifier) { - return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status?.effect; + if (i instanceof TurnStatusEffectModifier) { + return (i as TurnStatusEffectModifier).getStatusEffect() === p.status?.effect; } return false; })).length, 3); @@ -1672,8 +1669,8 @@ const modifierPool: ModifierPool = { }, 3), new WeightedModifierType(modifierTypes.FULL_RESTORE, (party: Pokemon[]) => { const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => { - if (i instanceof Modifiers.TurnStatusEffectModifier) { - return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status?.effect; + if (i instanceof TurnStatusEffectModifier) { + return (i as TurnStatusEffectModifier).getStatusEffect() === p.status?.effect; } return false; })).length, 3); @@ -1723,7 +1720,7 @@ const modifierPool: ModifierPool = { const { gameMode, gameData } = party[0].scene; if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) { return party.some(p => ((p.getSpeciesForm(true).speciesId in pokemonEvolutions) || (p.isFusion() && (p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))) - && !p.getHeldItems().some(i => i instanceof Modifiers.EvolutionStatBoosterModifier) && !p.isMax()) ? 10 : 0; + && !p.getHeldItems().some(i => i instanceof EvolutionStatBoosterModifier) && !p.isMax()) ? 10 : 0; } return 0; }), @@ -1731,7 +1728,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.LEEK, (party: Pokemon[]) => { const checkedSpecies = [ Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD ]; // If a party member doesn't already have a Leek and is one of the relevant species, Leek can appear - return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.SpeciesCritBoosterModifier) + return party.some(p => !p.getHeldItems().some(i => i instanceof SpeciesCritBoosterModifier) && (checkedSpecies.includes(p.getSpeciesForm(true).speciesId) || (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId)))) ? 12 : 0; }, 12), @@ -1739,7 +1736,7 @@ const modifierPool: ModifierPool = { const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL, Abilities.MAGIC_GUARD]; const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT]; // If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear - return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) + return party.some(p => !p.getHeldItems().some(i => i instanceof TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0; }, 10), @@ -1747,13 +1744,13 @@ const modifierPool: ModifierPool = { const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.FLARE_BOOST, Abilities.MAGIC_GUARD]; const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT]; // If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear - return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) + return party.some(p => !p.getHeldItems().some(i => i instanceof TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0; }, 10), new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => { const checkedAbilities = [Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT]; const weightMultiplier = party.filter( - p => !p.getHeldItems().some(i => i instanceof Modifiers.ResetNegativeStatStageModifier && i.stackCount >= i.getMaxHeldItemCount(p)) && + p => !p.getHeldItems().some(i => i instanceof ResetNegativeStatStageModifier && i.stackCount >= i.getMaxHeldItemCount(p)) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && selfStatLowerMoves.includes(m.moveId)))).length; // If a party member has one of the above moves or abilities and doesn't have max herbs, the herb will appear more frequently return 0 * (weightMultiplier ? 2 : 1) + (weightMultiplier ? weightMultiplier * 0 : 0); @@ -2246,7 +2243,7 @@ export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, base return options.slice(0, Math.ceil(Math.max(waveIndex + 10, 0) / 30)).flat(); } -export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers: Modifiers.PersistentModifier[], scene: BattleScene): Modifiers.EnemyPersistentModifier { +export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers: PersistentModifier[], scene: BattleScene): EnemyPersistentModifier { let tierStackCount: number; switch (tier) { case ModifierTier.ULTRA: @@ -2263,30 +2260,30 @@ export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers: const retryCount = 50; let candidate = getNewModifierTypeOption([], ModifierPoolType.ENEMY_BUFF, tier); let r = 0; - let matchingModifier: Modifiers.PersistentModifier | undefined; + let matchingModifier: PersistentModifier | undefined; while (++r < retryCount && (matchingModifier = enemyModifiers.find(m => m.type.id === candidate?.type?.id)) && matchingModifier.getMaxStackCount(scene) < matchingModifier.stackCount + (r < 10 ? tierStackCount : 1)) { candidate = getNewModifierTypeOption([], ModifierPoolType.ENEMY_BUFF, tier); } - const modifier = candidate?.type?.newModifier() as Modifiers.EnemyPersistentModifier; + const modifier = candidate?.type?.newModifier() as EnemyPersistentModifier; modifier.stackCount = tierStackCount; return modifier; } export function getEnemyModifierTypesForWave(waveIndex: integer, count: integer, party: EnemyPokemon[], poolType: ModifierPoolType.WILD | ModifierPoolType.TRAINER, upgradeChance: integer = 0): PokemonHeldItemModifierType[] { - const ret = new Array(count).fill(0).map(() => getNewModifierTypeOption(party, poolType, undefined, upgradeChance && !Utils.randSeedInt(upgradeChance) ? 1 : 0)?.type as PokemonHeldItemModifierType); + const ret = new Array(count).fill(0).map(() => getNewModifierTypeOption(party, poolType, undefined, upgradeChance && !randSeedInt(upgradeChance) ? 1 : 0)?.type as PokemonHeldItemModifierType); if (!(waveIndex % 1000)) { ret.push(getModifierType(modifierTypes.MINI_BLACK_HOLE) as PokemonHeldItemModifierType); } return ret; } -export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.PokemonHeldItemModifier[] { - const ret: Modifiers.PokemonHeldItemModifier[] = []; +export function getDailyRunStarterModifiers(party: PlayerPokemon[]): PokemonHeldItemModifier[] { + const ret: PokemonHeldItemModifier[] = []; for (const p of party) { for (let m = 0; m < 3; m++) { - const tierValue = Utils.randSeedInt(64); + const tierValue = randSeedInt(64); let tier: ModifierTier; if (tierValue > 25) { @@ -2301,7 +2298,7 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.P tier = ModifierTier.MASTER; } - const modifier = getNewModifierTypeOption(party, ModifierPoolType.DAILY_STARTER, tier)?.type?.newModifier(p) as Modifiers.PokemonHeldItemModifier; + const modifier = getNewModifierTypeOption(party, ModifierPoolType.DAILY_STARTER, tier)?.type?.newModifier(p) as PokemonHeldItemModifier; ret.push(modifier); } } @@ -2340,7 +2337,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, break; } if (tier === undefined) { - const tierValue = Utils.randSeedInt(1024); + const tierValue = randSeedInt(1024); if (!upgradeCount) { upgradeCount = 0; } @@ -2349,7 +2346,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, const upgradeOdds = Math.floor(128 / ((partyLuckValue + 4) / 4)); let upgraded = false; do { - upgraded = Utils.randSeedInt(upgradeOdds) < 4; + upgraded = randSeedInt(upgradeOdds) < 4; if (upgraded) { upgradeCount++; } @@ -2381,7 +2378,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, const partyShinyCount = party.filter(p => p.isShiny() && !p.isFainted()).length; const upgradeOdds = Math.floor(32 / ((partyShinyCount + 2) / 2)); while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) { - if (!Utils.randSeedInt(upgradeOdds)) { + if (!randSeedInt(upgradeOdds)) { upgradeCount++; } else { break; @@ -2396,7 +2393,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, const tierThresholds = Object.keys(thresholds[tier]); const totalWeight = parseInt(tierThresholds[tierThresholds.length - 1]); - const value = Utils.randSeedInt(totalWeight); + const value = randSeedInt(totalWeight); let index: integer | undefined; for (const t of tierThresholds) { const threshold = parseInt(t); @@ -2456,9 +2453,9 @@ export class ModifierTypeOption { */ export function getPartyLuckValue(party: Pokemon[]): integer { if (party[0].scene.gameMode.isDaily) { - const DailyLuck = new Utils.NumberHolder(0); + const DailyLuck = new NumberHolder(0); party[0].scene.executeWithSeedOffset(() => { - DailyLuck.value = Utils.randSeedInt(15); // Random number between 0 and 14 + DailyLuck.value = randSeedInt(15); // Random number between 0 and 14 }, 0, party[0].scene.seed); return DailyLuck.value; } diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 4c20b454081..4f1f9833602 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1,33 +1,35 @@ -import * as ModifierTypes from "#app/modifier/modifier-type"; -import { getModifierType, ModifierType, modifierTypes } from "#app/modifier/modifier-type"; -import BattleScene from "#app/battle-scene"; -import { getLevelTotalExp } from "#app/data/exp"; -import { MAX_PER_TYPE_POKEBALLS, PokeballType } from "#app/data/pokeball"; -import Pokemon, { PlayerPokemon } from "#app/field/pokemon"; -import { addTextObject, TextStyle } from "#app/ui/text"; -import { Type } from "#app/data/type"; -import { EvolutionPhase } from "#app/phases/evolution-phase"; +import type BattleScene from "#app/battle-scene"; import { FusionSpeciesFormEvolution, pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions"; -import { getPokemonNameWithAffix } from "#app/messages"; -import * as Utils from "#app/utils"; import { getBerryEffectFunc, getBerryPredicate } from "#app/data/berry"; -import { BattlerTagType } from "#enums/battler-tag-type"; -import { BerryType } from "#enums/berry-type"; -import { getStatusEffectHealText, StatusEffect } from "#app/data/status-effect"; -import { achvs } from "#app/system/achv"; -import { VoucherType } from "#app/system/voucher"; -import { FormChangeItem, SpeciesFormChangeItemTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms"; -import { Nature } from "#app/data/nature"; -import Overrides from "#app/overrides"; -import { Command } from "#app/ui/command-ui-handler"; -import { Species } from "#enums/species"; -import { BATTLE_STATS, type PermanentStat, Stat, TEMP_BATTLE_STATS, type TempBattleStat } from "#enums/stat"; -import i18next from "i18next"; +import { getLevelTotalExp } from "#app/data/exp"; import { allMoves } from "#app/data/move"; -import { Abilities } from "#enums/abilities"; +import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; +import { type FormChangeItem, SpeciesFormChangeItemTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms"; +import { getStatusEffectHealText } from "#app/data/status-effect"; +import { Type } from "#app/data/type"; +import Pokemon, { type PlayerPokemon } from "#app/field/pokemon"; +import { getPokemonNameWithAffix } from "#app/messages"; +import Overrides from "#app/overrides"; +import { EvolutionPhase } from "#app/phases/evolution-phase"; import { LearnMovePhase } from "#app/phases/learn-move-phase"; import { LevelUpPhase } from "#app/phases/level-up-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; +import { achvs } from "#app/system/achv"; +import type { VoucherType } from "#app/system/voucher"; +import { Command } from "#app/ui/command-ui-handler"; +import { addTextObject, TextStyle } from "#app/ui/text"; +import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, toDmgValue } from "#app/utils"; +import { Abilities } from "#enums/abilities"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { BerryType } from "#enums/berry-type"; +import type { Nature } from "#enums/nature"; +import type { PokeballType } from "#enums/pokeball"; +import { Species } from "#enums/species"; +import { type PermanentStat, type TempBattleStat, BATTLE_STATS, Stat, TEMP_BATTLE_STATS } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; +import i18next from "i18next"; +import { type DoubleBattleChanceBoosterModifierType, type EvolutionItemModifierType, type FormChangeItemModifierType, type ModifierOverride, type ModifierType, type PokemonBaseStatTotalModifierType, type PokemonExpBoosterModifierType, type PokemonFriendshipBoosterModifierType, type PokemonMoveAccuracyBoosterModifierType, type PokemonMultiHitModifierType, type TerastallizeModifierType, type TmModifierType, getModifierType, ModifierPoolType, ModifierTypeGenerator, modifierTypes, PokemonHeldItemModifierType } from "./modifier-type"; +import { Color, ShadowColor } from "#enums/color"; export type ModifierPredicate = (modifier: Modifier) => boolean; @@ -84,7 +86,7 @@ export class ModifierBar extends Phaser.GameObjects.Container { const thisArg = this; - sortedVisibleIconModifiers.forEach((modifier: PersistentModifier, i: integer) => { + sortedVisibleIconModifiers.forEach((modifier: PersistentModifier, i: number) => { const icon = modifier.getIcon(this.scene as BattleScene); if (i >= iconOverflowIndex) { icon.setVisible(false); @@ -120,8 +122,8 @@ export class ModifierBar extends Phaser.GameObjects.Container { } } - setModifierIconPosition(icon: Phaser.GameObjects.Container, modifierCount: integer) { - const rowIcons: integer = 12 + 6 * Math.max((Math.ceil(Math.min(modifierCount, 24) / 12) - 2), 0); + setModifierIconPosition(icon: Phaser.GameObjects.Container, modifierCount: number) { + const rowIcons: number = 12 + 6 * Math.max((Math.ceil(Math.min(modifierCount, 24) / 12) - 2), 0); const x = (this.getIndex(icon) % rowIcons) * 26 / (rowIcons / 12); const y = Math.floor(this.getIndex(icon) / rowIcons) * 20; @@ -141,18 +143,27 @@ export abstract class Modifier { return false; } - shouldApply(_args: any[]): boolean { + /** + * Checks if {@linkcode Modifier} should be applied + * @param _args parameters passed to {@linkcode Modifier.apply} + * @returns always `true` by default + */ + shouldApply(..._args: Parameters): boolean { return true; } - abstract apply(args: any[]): boolean | Promise; + /** + * Handles applying of {@linkcode Modifier} + * @param args collection of all passed parameters + */ + abstract apply(...args: unknown[]): boolean | Promise; } export abstract class PersistentModifier extends Modifier { - public stackCount: integer; - public virtualStackCount: integer; + public stackCount: number; + public virtualStackCount: number; - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type); this.stackCount = stackCount === undefined ? 1 : stackCount; this.virtualStackCount = 0; @@ -179,7 +190,7 @@ export abstract class PersistentModifier extends Modifier { return []; } - incrementStack(scene: BattleScene, amount: integer, virtual: boolean): boolean { + incrementStack(scene: BattleScene, amount: number, virtual: boolean): boolean { if (this.getStackCount() + amount <= this.getMaxStackCount(scene)) { if (!virtual) { this.stackCount += amount; @@ -192,11 +203,11 @@ export abstract class PersistentModifier extends Modifier { return false; } - getStackCount(): integer { + getStackCount(): number { return this.stackCount + this.virtualStackCount; } - abstract getMaxStackCount(scene: BattleScene, forThreshold?: boolean): integer; + abstract getMaxStackCount(scene: BattleScene, forThreshold?: boolean): number; isIconVisible(scene: BattleScene): boolean { return true; @@ -247,25 +258,26 @@ export abstract class ConsumableModifier extends Modifier { add(_modifiers: Modifier[]): boolean { return true; } - - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 1 && args[0] instanceof BattleScene; - } } export class AddPokeballModifier extends ConsumableModifier { private pokeballType: PokeballType; - private count: integer; + private count: number; - constructor(type: ModifierType, pokeballType: PokeballType, count: integer) { + constructor(type: ModifierType, pokeballType: PokeballType, count: number) { super(type); this.pokeballType = pokeballType; this.count = count; } - apply(args: any[]): boolean { - const pokeballCounts = (args[0] as BattleScene).pokeballCounts; + /** + * Applies {@linkcode AddPokeballModifier} + * @param battleScene {@linkcode BattleScene} + * @returns always `true` + */ + override apply(battleScene: BattleScene): boolean { + const pokeballCounts = battleScene.pokeballCounts; pokeballCounts[this.pokeballType] = Math.min(pokeballCounts[this.pokeballType] + this.count, MAX_PER_TYPE_POKEBALLS); return true; @@ -274,17 +286,22 @@ export class AddPokeballModifier extends ConsumableModifier { export class AddVoucherModifier extends ConsumableModifier { private voucherType: VoucherType; - private count: integer; + private count: number; - constructor(type: ModifierType, voucherType: VoucherType, count: integer) { + constructor(type: ModifierType, voucherType: VoucherType, count: number) { super(type); this.voucherType = voucherType; this.count = count; } - apply(args: any[]): boolean { - const voucherCounts = (args[0] as BattleScene).gameData.voucherCounts; + /** + * Applies {@linkcode AddVoucherModifier} + * @param battleScene {@linkcode BattleScene} + * @returns always `true` + */ + override apply(battleScene: BattleScene): boolean { + const voucherCounts = battleScene.gameData.voucherCounts; voucherCounts[this.voucherType] += this.count; return true; @@ -308,7 +325,7 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { /** The current amount of battles the modifier will exist for */ private battleCount: number; - constructor(type: ModifierTypes.ModifierType, maxBattles: number, battleCount?: number, stackCount?: integer) { + constructor(type: ModifierType, maxBattles: number, battleCount?: number, stackCount?: number) { super(type, stackCount); this.maxBattles = maxBattles; @@ -322,7 +339,7 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { * @param modifiers {@linkcode PersistentModifier} array of the player's modifiers * @param _virtual N/A * @param _scene N/A - * @returns true if the modifier was successfully added or applied, false otherwise + * @returns `true` if the modifier was successfully added or applied, false otherwise */ add(modifiers: PersistentModifier[], _virtual: boolean, scene: BattleScene): boolean { for (const modifier of modifiers) { @@ -342,7 +359,12 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { return true; } - lapse(_args: any[]): boolean { + /** + * Lapses the {@linkcode battleCount} by 1. + * @param _args passed arguments (not in use here) + * @returns `true` if the {@linkcode battleCount} is greater than 0 + */ + public lapse(..._args: unknown[]): boolean { this.battleCount--; return this.battleCount > 0; } @@ -354,10 +376,13 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { const hue = Math.floor(120 * (this.battleCount / this.maxBattles) + 5); // Generates the color hex code with a constant saturation and lightness but varying hue - const typeHex = Utils.hslToHex(hue, 0.50, 0.90); - const strokeHex = Utils.hslToHex(hue, 0.70, 0.30); + const typeHex = hslToHex(hue, 0.5, 0.9); + const strokeHex = hslToHex(hue, 0.7, 0.3); - const battleCountText = addTextObject(scene, 27, 0, this.battleCount.toString(), TextStyle.PARTY, { fontSize: "66px", color: typeHex }); + const battleCountText = addTextObject(scene, 27, 0, this.battleCount.toString(), TextStyle.PARTY, { + fontSize: "66px", + color: typeHex, + }); battleCountText.setShadow(0, 0); battleCountText.setStroke(strokeHex, 16); battleCountText.setOrigin(1, 0); @@ -383,7 +408,7 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { } getArgs(): any[] { - return [ this.maxBattles, this.battleCount ]; + return [this.maxBattles, this.battleCount]; } getMaxStackCount(_scene: BattleScene, _forThreshold?: boolean): number { @@ -399,7 +424,9 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { * @see {@linkcode apply} */ export class DoubleBattleChanceBoosterModifier extends LapsingPersistentModifier { - constructor(type: ModifierType, maxBattles:number, battleCount?: number, stackCount?: integer) { + public override type: DoubleBattleChanceBoosterModifierType; + + constructor(type: ModifierType, maxBattles:number, battleCount?: number, stackCount?: number) { super(type, maxBattles, battleCount, stackCount); } @@ -408,17 +435,16 @@ export class DoubleBattleChanceBoosterModifier extends LapsingPersistentModifier } clone(): DoubleBattleChanceBoosterModifier { - return new DoubleBattleChanceBoosterModifier(this.type as ModifierTypes.DoubleBattleChanceBoosterModifierType, this.getMaxBattles(), this.getBattleCount(), this.stackCount); + return new DoubleBattleChanceBoosterModifier(this.type, this.getMaxBattles(), this.getBattleCount(), this.stackCount); } /** * Increases the chance of a double battle occurring - * @param args [0] {@linkcode Utils.NumberHolder} for double battle chance - * @returns true if the modifier was applied + * @param doubleBattleChance {@linkcode NumberHolder} for double battle chance + * @returns true */ - apply(args: any[]): boolean { - const doubleBattleChance = args[0] as Utils.NumberHolder; - // This is divided because the chance is generated as a number from 0 to doubleBattleChance.value using Utils.randSeedInt + override apply(doubleBattleChance: NumberHolder): boolean { + // This is divided because the chance is generated as a number from 0 to doubleBattleChance.value using randSeedInt // A double battle will initiate if the generated number is 0 doubleBattleChance.value = doubleBattleChance.value / 4; @@ -467,21 +493,21 @@ export class TempStatStageBoosterModifier extends LapsingPersistentModifier { /** * Checks if {@linkcode args} contains the necessary elements and if the * incoming stat is matches {@linkcode stat}. - * @param args [0] {@linkcode TempBattleStat} being checked at the time - * [1] {@linkcode Utils.NumberHolder} N/A - * @returns true if the modifier can be applied, false otherwise + * @param tempBattleStat {@linkcode TempBattleStat} being affected + * @param statLevel {@linkcode NumberHolder} that holds the resulting value of the stat stage multiplier + * @returns `true` if the modifier can be applied, false otherwise */ - shouldApply(args: any[]): boolean { - return args && (args.length === 2) && TEMP_BATTLE_STATS.includes(args[0]) && (args[0] === this.stat) && (args[1] instanceof Utils.NumberHolder); + override shouldApply(tempBattleStat?: TempBattleStat, statLevel?: NumberHolder): boolean { + return !!tempBattleStat && !!statLevel && TEMP_BATTLE_STATS.includes(tempBattleStat) && (tempBattleStat === this.stat); } /** * Increases the incoming stat stage matching {@linkcode stat} by {@linkcode boost}. - * @param args [0] {@linkcode TempBattleStat} N/A - * [1] {@linkcode Utils.NumberHolder} that holds the resulting value of the stat stage multiplier + * @param _tempBattleStat {@linkcode TempBattleStat} N/A + * @param statLevel {@linkcode NumberHolder} that holds the resulting value of the stat stage multiplier */ - apply(args: any[]): boolean { - (args[1] as Utils.NumberHolder).value += this.boost; + override apply(_tempBattleStat: TempBattleStat, statLevel: NumberHolder): boolean { + statLevel.value += this.boost; return true; } } @@ -507,26 +533,26 @@ export class TempCritBoosterModifier extends LapsingPersistentModifier { /** * Checks if {@linkcode args} contains the necessary elements. - * @param args [1] {@linkcode Utils.NumberHolder} N/A - * @returns true if the critical-hit stage boost applies successfully + * @param critLevel {@linkcode NumberHolder} that holds the resulting critical-hit level + * @returns `true` if the critical-hit stage boost applies successfully */ - shouldApply(args: any[]): boolean { - return args && (args.length === 1) && (args[0] instanceof Utils.NumberHolder); + override shouldApply(critLevel?: NumberHolder): boolean { + return !!critLevel; } /** * Increases the current critical-hit stage value by 1. - * @param args [0] {@linkcode Utils.IntegerHolder} that holds the resulting critical-hit level - * @returns true if the critical-hit stage boost applies successfully + * @param critLevel {@linkcode NumberHolder} that holds the resulting critical-hit level + * @returns `true` if the critical-hit stage boost applies successfully */ - apply(args: any[]): boolean { - (args[0] as Utils.NumberHolder).value++; + override apply(critLevel: NumberHolder): boolean { + critLevel.value++; return true; } } export class MapModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -534,17 +560,17 @@ export class MapModifier extends PersistentModifier { return new MapModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { + override apply(..._args: unknown[]): boolean { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 1; } } export class MegaEvolutionAccessModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -552,17 +578,17 @@ export class MegaEvolutionAccessModifier extends PersistentModifier { return new MegaEvolutionAccessModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { + override apply(..._args: unknown[]): boolean { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 1; } } export class GigantamaxAccessModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -570,17 +596,22 @@ export class GigantamaxAccessModifier extends PersistentModifier { return new GigantamaxAccessModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { + /** + * Applies {@linkcode GigantamaxAccessModifier} + * @param _args N/A + * @returns always `true` + */ + apply(..._args: unknown[]): boolean { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 1; } } export class TerastallizeAccessModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -588,20 +619,25 @@ export class TerastallizeAccessModifier extends PersistentModifier { return new TerastallizeAccessModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { + /** + * Applies {@linkcode TerastallizeAccessModifier} + * @param _args N/A + * @returns always `true` + */ + override apply(..._args: unknown[]): boolean { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 1; } } export abstract class PokemonHeldItemModifier extends PersistentModifier { - public pokemonId: integer; + public pokemonId: number; public isTransferable: boolean = true; - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, stackCount); this.pokemonId = pokemonId; @@ -617,8 +653,21 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { return [ this.pokemonId ]; } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length !== 0 && args[0] instanceof Pokemon && (this.pokemonId === -1 || (args[0] as Pokemon).id === this.pokemonId); + /** + * Applies the {@linkcode PokemonHeldItemModifier} to the given {@linkcode Pokemon}. + * @param pokemon The {@linkcode Pokemon} that holds the held item + * @param args additional parameters + */ + abstract override apply(pokemon: Pokemon, ...args: unknown[]): boolean; + + /** + * Checks if {@linkcode PokemonHeldItemModifier} should be applied. + * @param pokemon The {@linkcode Pokemon} that holds the item + * @param _args N/A + * @returns if {@linkcode PokemonHeldItemModifier} should be applied + */ + override shouldApply(pokemon?: Pokemon, ..._args: unknown[]): boolean { + return !!pokemon && (this.pokemonId === -1 || pokemon.id === this.pokemonId); } isIconVisible(scene: BattleScene): boolean { @@ -667,7 +716,7 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { } //Applies to items with chance of activating secondary effects ie Kings Rock - getSecondaryChanceMultiplier(pokemon: Pokemon): integer { + getSecondaryChanceMultiplier(pokemon: Pokemon): number { // Temporary quickfix to stop game from freezing when the opponet uses u-turn while holding on to king's rock if (!pokemon.getLastXMoves(0)[0]) { return 1; @@ -682,41 +731,52 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { return 1; } - getMaxStackCount(scene: BattleScene, forThreshold?: boolean): integer { + getMaxStackCount(scene: BattleScene, forThreshold?: boolean): number { const pokemon = this.getPokemon(scene); if (!pokemon) { return 0; } if (pokemon.isPlayer() && forThreshold) { - return scene.getParty().map(p => this.getMaxHeldItemCount(p)).reduce((stackCount: integer, maxStackCount: integer) => Math.max(stackCount, maxStackCount), 0); + return scene.getParty().map(p => this.getMaxHeldItemCount(p)).reduce((stackCount: number, maxStackCount: number) => Math.max(stackCount, maxStackCount), 0); } return this.getMaxHeldItemCount(pokemon); } - abstract getMaxHeldItemCount(pokemon?: Pokemon): integer; + abstract getMaxHeldItemCount(pokemon?: Pokemon): number; } export abstract class LapsingPokemonHeldItemModifier extends PokemonHeldItemModifier { - protected battlesLeft: integer; + protected battlesLeft: number; public isTransferable: boolean = false; - constructor(type: ModifierTypes.ModifierType, pokemonId: integer, battlesLeft?: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, battlesLeft?: number, stackCount?: number) { super(type, pokemonId, stackCount); this.battlesLeft = battlesLeft!; // TODO: is this bang correct? } - lapse(args: any[]): boolean { + /** + * Lapse the {@linkcode battlesLeft} counter (reduce it by 1) + * @param _args arguments passed (not used here) + * @returns `true` if {@linkcode battlesLeft} is not null + */ + public lapse(..._args: unknown[]): boolean { return !!--this.battlesLeft; } - getIcon(scene: BattleScene, forSummary?: boolean): Phaser.GameObjects.Container { + /** + * Retrieve the {@linkcode Modifier | Modifiers} icon as a {@linkcode Phaser.GameObjects.Container | Container} + * @param scene The {@linkcode BattleScene} + * @param forSummary `true` if the icon is for the summary screen + * @returns the icon as a {@linkcode Phaser.GameObjects.Container | Container} + */ + public getIcon(scene: BattleScene, forSummary?: boolean): Phaser.GameObjects.Container { const container = super.getIcon(scene, forSummary); if (this.getPokemon(scene)?.isPlayer()) { - const battleCountText = addTextObject(scene, 27, 0, this.battlesLeft.toString(), TextStyle.PARTY, { fontSize: "66px", color: "#f89890" }); + const battleCountText = addTextObject(scene, 27, 0, this.battlesLeft.toString(), TextStyle.PARTY, { fontSize: "66px", color: Color.PINK }); battleCountText.setShadow(0, 0); - battleCountText.setStroke("#984038", 16); + battleCountText.setStroke(ShadowColor.RED, 16); battleCountText.setOrigin(1, 0); container.add(battleCountText); } @@ -724,7 +784,7 @@ export abstract class LapsingPokemonHeldItemModifier extends PokemonHeldItemModi return container; } - getBattlesLeft(): integer { + getBattlesLeft(): number { return this.battlesLeft; } @@ -734,10 +794,11 @@ export abstract class LapsingPokemonHeldItemModifier extends PokemonHeldItemModi } export class TerastallizeModifier extends LapsingPokemonHeldItemModifier { + public override type: TerastallizeModifierType; public teraType: Type; public isTransferable: boolean = false; - constructor(type: ModifierTypes.TerastallizeModifierType, pokemonId: integer, teraType: Type, battlesLeft?: integer, stackCount?: integer) { + constructor(type: TerastallizeModifierType, pokemonId: number, teraType: Type, battlesLeft?: number, stackCount?: number) { super(type, pokemonId, battlesLeft || 10, stackCount); this.teraType = teraType; @@ -751,15 +812,19 @@ export class TerastallizeModifier extends LapsingPokemonHeldItemModifier { } clone(): TerastallizeModifier { - return new TerastallizeModifier(this.type as ModifierTypes.TerastallizeModifierType, this.pokemonId, this.teraType, this.battlesLeft, this.stackCount); + return new TerastallizeModifier(this.type, this.pokemonId, this.teraType, this.battlesLeft, this.stackCount); } getArgs(): any[] { return [ this.pokemonId, this.teraType, this.battlesLeft ]; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; + /** + * Applies the {@linkcode TerastallizeModifier} to the specified {@linkcode Pokemon}. + * @param pokemon the {@linkcode Pokemon} to be terastallized + * @returns always `true` + */ + override apply(pokemon: Pokemon): boolean { if (pokemon.isPlayer()) { pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeTeraTrigger); pokemon.scene.validateAchv(achvs.TERASTALLIZE); @@ -771,10 +836,14 @@ export class TerastallizeModifier extends LapsingPokemonHeldItemModifier { return true; } - lapse(args: any[]): boolean { - const ret = super.lapse(args); + /** + * Triggers {@linkcode LapsingPokemonHeldItemModifier.lapse} and if it returns `0` a form change is triggered. + * @param pokemon THe {@linkcode Pokemon} to be terastallized + * @returns the result of {@linkcode LapsingPokemonHeldItemModifier.lapse} + */ + public override lapse(pokemon: Pokemon): boolean { + const ret = super.lapse(pokemon); if (!ret) { - const pokemon = args[0] as Pokemon; pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeLapseTeraTrigger); pokemon.updateSpritePipelineData(); } @@ -785,7 +854,7 @@ export class TerastallizeModifier extends LapsingPokemonHeldItemModifier { return 1.25; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 1; } } @@ -800,7 +869,7 @@ export class BaseStatModifier extends PokemonHeldItemModifier { protected stat: PermanentStat; public isTransferable: boolean = false; - constructor(type: ModifierType, pokemonId: integer, stat: PermanentStat, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stat: PermanentStat, stackCount?: number) { super(type, pokemonId, stackCount); this.stat = stat; } @@ -820,12 +889,23 @@ export class BaseStatModifier extends PokemonHeldItemModifier { return super.getArgs().concat(this.stat); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && Array.isArray(args[1]); + /** + * Checks if {@linkcode BaseStatModifier} should be applied to the specified {@linkcode Pokemon}. + * @param _pokemon the {@linkcode Pokemon} to be modified + * @param baseStats the base stats of the {@linkcode Pokemon} + * @returns `true` if the {@linkcode Pokemon} should be modified + */ + override shouldApply(_pokemon?: Pokemon, baseStats?: number[]): boolean { + return super.shouldApply(_pokemon, baseStats) && Array.isArray(baseStats); } - apply(args: any[]): boolean { - const baseStats = args[1] as number[]; + /** + * Applies the {@linkcode BaseStatModifier} to the specified {@linkcode Pokemon}. + * @param _pokemon the {@linkcode Pokemon} to be modified + * @param baseStats the base stats of the {@linkcode Pokemon} + * @returns always `true` + */ + override apply(_pokemon: Pokemon, baseStats: number[]): boolean { baseStats[this.stat] = Math.floor(baseStats[this.stat] * (1 + this.getStackCount() * 0.1)); return true; } @@ -834,17 +914,17 @@ export class BaseStatModifier extends PokemonHeldItemModifier { return 1.1; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return pokemon.ivs[this.stat]; } } export class EvoTrackerModifier extends PokemonHeldItemModifier { protected species: Species; - protected required: integer; + protected required: number; public isTransferable: boolean = false; - constructor(type: ModifierType, pokemonId: integer, species: Species, required: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, species: Species, required: number, stackCount?: number) { super(type, pokemonId, stackCount); this.species = species; this.required = required; @@ -862,7 +942,11 @@ export class EvoTrackerModifier extends PokemonHeldItemModifier { return super.getArgs().concat([this.species, this.required]); } - apply(args: any[]): boolean { + /** + * Applies the {@linkcode EvoTrackerModifier} + * @returns always `true` + */ + override apply(): boolean { return true; } @@ -888,7 +972,7 @@ export class EvoTrackerModifier extends PokemonHeldItemModifier { return text; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { this.stackCount = pokemon.evoCounter + pokemon.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length + pokemon.scene.findModifiers(m => m instanceof MoneyMultiplierModifier || m instanceof ExtraModifierModifier).length; return 999; @@ -899,10 +983,12 @@ export class EvoTrackerModifier extends PokemonHeldItemModifier { * Currently used by Shuckle Juice item */ export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier { - private statModifier: integer; + public override type: PokemonBaseStatTotalModifierType; public isTransferable: boolean = false; - constructor(type: ModifierTypes.PokemonBaseStatTotalModifierType, pokemonId: number, statModifier: number, stackCount?: integer) { + private statModifier: number; + + constructor(type: PokemonBaseStatTotalModifierType, pokemonId: number, statModifier: number, stackCount?: number) { super(type, pokemonId, stackCount); this.statModifier = statModifier; } @@ -912,23 +998,35 @@ export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier { } override clone(): PersistentModifier { - return new PokemonBaseStatTotalModifier(this.type as ModifierTypes.PokemonBaseStatTotalModifierType, this.pokemonId, this.statModifier, this.stackCount); + return new PokemonBaseStatTotalModifier(this.type, this.pokemonId, this.statModifier, this.stackCount); } override getArgs(): any[] { return super.getArgs().concat(this.statModifier); } - override shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array; + /** + * Checks if {@linkcode PokemonBaseStatTotalModifier} should be applied to the specified {@linkcode Pokemon}. + * @param pokemon the {@linkcode Pokemon} to be modified + * @param baseStats the base stats of the {@linkcode Pokemon} + * @returns `true` if the {@linkcode Pokemon} should be modified + */ + override shouldApply(pokemon?: Pokemon, baseStats?: number[]): boolean { + return super.shouldApply(pokemon, baseStats) && Array.isArray(baseStats); } - override apply(args: any[]): boolean { + /** + * Applies the {@linkcode PokemonBaseStatTotalModifier} + * @param _pokemon the {@linkcode Pokemon} to be modified + * @param baseStats the base stats of the {@linkcode Pokemon} + * @returns always `true` + */ + override apply(_pokemon: Pokemon, baseStats: number[]): boolean { // Modifies the passed in baseStats[] array - args[1].forEach((v, i) => { + baseStats.forEach((v, i) => { // HP is affected by half as much as other stats const newVal = i === 0 ? Math.floor(v + this.statModifier / 2) : Math.floor(v + this.statModifier); - args[1][i] = Math.min(Math.max(newVal, 1), 999999); + baseStats[i] = Math.min(Math.max(newVal, 1), 999999); }); return true; @@ -938,7 +1036,7 @@ export class PokemonBaseStatTotalModifier extends PokemonHeldItemModifier { return 1.2; } - override getMaxHeldItemCount(pokemon: Pokemon): integer { + override getMaxHeldItemCount(pokemon: Pokemon): number { return 2; } } @@ -970,16 +1068,28 @@ export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier { return [ ...super.getArgs(), this.statModifier, this.stats ]; } - override shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array; + /** + * Checks if the {@linkcode PokemonBaseStatFlatModifier} should be applied to the {@linkcode Pokemon}. + * @param pokemon The {@linkcode Pokemon} that holds the item + * @param baseStats The base stats of the {@linkcode Pokemon} + * @returns `true` if the {@linkcode PokemonBaseStatFlatModifier} should be applied + */ + override shouldApply(pokemon?: Pokemon, baseStats?: number[]): boolean { + return super.shouldApply(pokemon, baseStats) && Array.isArray(baseStats); } - override apply(args: any[]): boolean { + /** + * Applies the {@linkcode PokemonBaseStatFlatModifier} + * @param _pokemon The {@linkcode Pokemon} that holds the item + * @param baseStats The base stats of the {@linkcode Pokemon} + * @returns always `true` + */ + override apply(_pokemon: Pokemon, baseStats: number[]): boolean { // Modifies the passed in baseStats[] array by a flat value, only if the stat is specified in this.stats - args[1].forEach((v, i) => { + baseStats.forEach((v, i) => { if (this.stats.includes(i)) { const newVal = Math.floor(v + this.statModifier); - args[1][i] = Math.min(Math.max(newVal, 1), 999999); + baseStats[i] = Math.min(Math.max(newVal, 1), 999999); } }); @@ -990,7 +1100,7 @@ export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier { return 1.1; } - override getMaxHeldItemCount(pokemon: Pokemon): integer { + override getMaxHeldItemCount(pokemon: Pokemon): number { return 1; } } @@ -1001,7 +1111,7 @@ export class PokemonBaseStatFlatModifier extends PokemonHeldItemModifier { export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { public isTransferable: boolean = false; - constructor (type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor (type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -1017,15 +1127,28 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { return super.getArgs(); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 3 && args[2] instanceof Utils.IntegerHolder; + /** + * Checks if the {@linkcode PokemonIncrementingStatModifier} should be applied to the {@linkcode Pokemon}. + * @param pokemon The {@linkcode Pokemon} that holds the item + * @param stat The affected {@linkcode Stat} + * @param statHolder The {@linkcode NumberHolder} that holds the stat + * @returns `true` if the {@linkcode PokemonBaseStatFlatModifier} should be applied + */ + override shouldApply(pokemon?: Pokemon, stat?: Stat, statHolder?: NumberHolder): boolean { + return super.shouldApply(pokemon, stat, statHolder) && !!statHolder; } - apply(args: any[]): boolean { - // Modifies the passed in stat integer holder by +1 per stack for HP, +2 per stack for other stats + /** + * Applies the {@linkcode PokemonIncrementingStatModifier} + * @param _pokemon The {@linkcode Pokemon} that holds the item + * @param stat The affected {@linkcode Stat} + * @param statHolder The {@linkcode NumberHolder} that holds the stat + * @returns always `true` + */ + override apply(_pokemon: Pokemon, stat: Stat, statHolder: NumberHolder): boolean { + // Modifies the passed in stat number holder by +1 per stack for HP, +2 per stack for other stats // If the Macho Brace is at max stacks (50), adds additional 5% to total HP and 10% to other stats - const isHp = args[1] === Stat.HP; - const statHolder = args[2] as Utils.IntegerHolder; + const isHp = stat === Stat.HP; if (isHp) { statHolder.value += this.stackCount; @@ -1046,13 +1169,13 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier { return 1.2; } - getMaxHeldItemCount(pokemon?: Pokemon): integer { + getMaxHeldItemCount(pokemon?: Pokemon): number { return 50; } } /** - * Modifier used for held items that apply {@linkcode Stat} boost(s) + * Modifier used for held items that Applies {@linkcode Stat} boost(s) * using a multiplier. * @extends PokemonHeldItemModifier * @see {@linkcode apply} @@ -1063,7 +1186,7 @@ export class StatBoosterModifier extends PokemonHeldItemModifier { /** The multiplier used to increase the relevant stat(s) */ protected multiplier: number; - constructor(type: ModifierType, pokemonId: integer, stats: Stat[], multiplier: number, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stats: Stat[], multiplier: number, stackCount?: number) { super(type, pokemonId, stackCount); this.stats = stats; @@ -1091,27 +1214,25 @@ export class StatBoosterModifier extends PokemonHeldItemModifier { /** * Checks if the incoming stat is listed in {@linkcode stats} - * @param args [0] {@linkcode Pokemon} N/A - * [1] {@linkcode Stat} being checked at the time - * [2] {@linkcode Utils.NumberHolder} N/A - * @returns true if the stat could be boosted, false otherwise + * @param _pokemon the {@linkcode Pokemon} that holds the item + * @param _stat the {@linkcode Stat} to be boosted + * @param statValue {@linkcode NumberHolder} that holds the resulting value of the stat + * @returns `true` if the stat could be boosted, false otherwise */ - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && this.stats.includes(args[1] as Stat); + override shouldApply(pokemon: Pokemon, stat: Stat, statValue: NumberHolder): boolean { + return super.shouldApply(pokemon, stat, statValue) && this.stats.includes(stat); } /** * Boosts the incoming stat by a {@linkcode multiplier} if the stat is listed * in {@linkcode stats}. - * @param args [0] {@linkcode Pokemon} N/A - * [1] {@linkcode Stat} N/A - * [2] {@linkcode Utils.NumberHolder} that holds the resulting value of the stat - * @returns true if the stat boost applies successfully, false otherwise + * @param _pokemon the {@linkcode Pokemon} that holds the item + * @param _stat the {@linkcode Stat} to be boosted + * @param statValue {@linkcode NumberHolder} that holds the resulting value of the stat + * @returns `true` if the stat boost applies successfully, false otherwise * @see shouldApply */ - apply(args: any[]): boolean { - const statValue = args[2] as Utils.NumberHolder; - + override apply(_pokemon: Pokemon, _stat: Stat, statValue: NumberHolder): boolean { statValue.value *= this.multiplier; return true; } @@ -1139,39 +1260,37 @@ export class EvolutionStatBoosterModifier extends StatBoosterModifier { /** * Checks if the stat boosts can apply and if the holder is not currently * Gigantamax'd. - * @param args [0] {@linkcode Pokemon} that holds the held item - * [1] {@linkcode Stat} N/A - * [2] {@linkcode Utils.NumberHolder} N/A - * @returns true if the stat boosts can be applied, false otherwise + * @param pokemon {@linkcode Pokemon} that holds the held item + * @param stat {@linkcode Stat} The {@linkcode Stat} to be boosted + * @param statValue {@linkcode NumberHolder} that holds the resulting value of the stat + * @returns `true` if the stat boosts can be applied, false otherwise */ - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && !(args[0] as Pokemon).isMax(); + override shouldApply(pokemon: Pokemon, stat: Stat, statValue: NumberHolder): boolean { + return super.shouldApply(pokemon, stat, statValue) && !pokemon.isMax(); } /** - * Boosts the incoming stat value by a {@linkcode multiplier} if the holder + * Boosts the incoming stat value by a {@linkcode EvolutionStatBoosterModifier.multiplier} if the holder * can evolve. Note that, if the holder is a fusion, they will receive * only half of the boost if either of the fused members are fully * evolved. However, if they are both unevolved, the full boost * will apply. - * @param args [0] {@linkcode Pokemon} that holds the held item - * [1] {@linkcode Stat} N/A - * [2] {@linkcode Utils.NumberHolder} that holds the resulting value of the stat - * @returns true if the stat boost applies successfully, false otherwise + * @param pokemon {@linkcode Pokemon} that holds the item + * @param _stat {@linkcode Stat} The {@linkcode Stat} to be boosted + * @param statValue{@linkcode NumberHolder} that holds the resulting value of the stat + * @returns `true` if the stat boost applies successfully, false otherwise * @see shouldApply */ - apply(args: any[]): boolean { - const holder = args[0] as Pokemon; - const statValue = args[2] as Utils.NumberHolder; - const isUnevolved = holder.getSpeciesForm(true).speciesId in pokemonEvolutions; + override apply(pokemon: Pokemon, stat: Stat, statValue: NumberHolder): boolean { + const isUnevolved = pokemon.getSpeciesForm(true).speciesId in pokemonEvolutions; - if (holder.isFusion() && (holder.getFusionSpeciesForm(true).speciesId in pokemonEvolutions) !== isUnevolved) { - // Half boost applied if holder is fused and either part of fusion is fully evolved + if (pokemon.isFusion() && (pokemon.getFusionSpeciesForm(true).speciesId in pokemonEvolutions) !== isUnevolved) { + // Half boost applied if pokemon is fused and either part of fusion is fully evolved statValue.value *= 1 + (this.multiplier - 1) / 2; return true; } else if (isUnevolved) { // Full boost applied if holder is unfused and unevolved or, if fused, both parts of fusion are unevolved - return super.apply(args); + return super.apply(pokemon, stat, statValue); } return false; @@ -1179,7 +1298,7 @@ export class EvolutionStatBoosterModifier extends StatBoosterModifier { } /** - * Modifier used for held items that apply {@linkcode Stat} boost(s) using a + * Modifier used for held items that Applies {@linkcode Stat} boost(s) using a * multiplier if the holder is of a specific {@linkcode Species}. * @extends StatBoosterModifier * @see {@linkcode apply} @@ -1188,7 +1307,7 @@ export class SpeciesStatBoosterModifier extends StatBoosterModifier { /** The species that the held item's stat boost(s) apply to */ private species: Species[]; - constructor(type: ModifierType, pokemonId: integer, stats: Stat[], multiplier: number, species: Species[], stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stats: Stat[], multiplier: number, species: Species[], stackCount?: number) { super(type, pokemonId, stats, multiplier, stackCount); this.species = species; @@ -1216,21 +1335,20 @@ export class SpeciesStatBoosterModifier extends StatBoosterModifier { /** * Checks if the incoming stat is listed in {@linkcode stats} and if the holder's {@linkcode Species} * (or its fused species) is listed in {@linkcode species}. - * @param args [0] {@linkcode Pokemon} that holds the held item - * [1] {@linkcode Stat} being checked at the time - * [2] {@linkcode Utils.NumberHolder} N/A - * @returns true if the stat could be boosted, false otherwise + * @param pokemon {@linkcode Pokemon} that holds the item + * @param stat {@linkcode Stat} being checked at the time + * @param statValue {@linkcode NumberHolder} that holds the resulting value of the stat + * @returns `true` if the stat could be boosted, false otherwise */ - shouldApply(args: any[]): boolean { - const holder = args[0] as Pokemon; - return super.shouldApply(args) && (this.species.includes(holder.getSpeciesForm(true).speciesId) || (holder.isFusion() && this.species.includes(holder.getFusionSpeciesForm(true).speciesId))); + override shouldApply(pokemon: Pokemon, stat: Stat, statValue: NumberHolder): boolean { + return super.shouldApply(pokemon, stat, statValue) && (this.species.includes(pokemon.getSpeciesForm(true).speciesId) || (pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId))); } /** * Checks if either parameter is included in the corresponding lists * @param speciesId {@linkcode Species} being checked * @param stat {@linkcode Stat} being checked - * @returns true if both parameters are in {@linkcode species} and {@linkcode stats} respectively, false otherwise + * @returns `true` if both parameters are in {@linkcode species} and {@linkcode stats} respectively, false otherwise */ contains(speciesId: Species, stat: Stat): boolean { return this.species.includes(speciesId) && this.stats.includes(stat); @@ -1246,7 +1364,7 @@ export class CritBoosterModifier extends PokemonHeldItemModifier { /** The amount of stages by which the held item increases the current critical-hit stage value */ protected stageIncrement: number; - constructor(type: ModifierType, pokemonId: integer, stageIncrement: number, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stageIncrement: number, stackCount?: number) { super(type, pokemonId, stackCount); this.stageIncrement = stageIncrement; @@ -1270,13 +1388,11 @@ export class CritBoosterModifier extends PokemonHeldItemModifier { /** * Increases the current critical-hit stage value by {@linkcode stageIncrement}. - * @param args [0] {@linkcode Pokemon} N/A - * [1] {@linkcode Utils.IntegerHolder} that holds the resulting critical-hit level - * @returns true if the critical-hit stage boost applies successfully, false otherwise + * @param _pokemon {@linkcode Pokemon} N/A + * @param critStage {@linkcode NumberHolder} that holds the resulting critical-hit level + * @returns always `true` */ - apply(args: any[]): boolean { - const critStage = args[1] as Utils.NumberHolder; - + override apply(_pokemon: Pokemon, critStage: NumberHolder): boolean { critStage.value += this.stageIncrement; return true; } @@ -1296,7 +1412,7 @@ export class SpeciesCritBoosterModifier extends CritBoosterModifier { /** The species that the held item's critical-hit stage boost applies to */ private species: Species[]; - constructor(type: ModifierType, pokemonId: integer, stageIncrement: number, species: Species[], stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stageIncrement: number, species: Species[], stackCount?: number) { super(type, pokemonId, stageIncrement, stackCount); this.species = species; @@ -1317,14 +1433,12 @@ export class SpeciesCritBoosterModifier extends CritBoosterModifier { /** * Checks if the holder's {@linkcode Species} (or its fused species) is listed * in {@linkcode species}. - * @param args [0] {@linkcode Pokemon} that holds the held item - * [1] {@linkcode Utils.IntegerHolder} N/A - * @returns true if the critical-hit level can be incremented, false otherwise + * @param pokemon {@linkcode Pokemon} that holds the held item + * @param critStage {@linkcode NumberHolder} that holds the resulting critical-hit level + * @returns `true` if the critical-hit level can be incremented, false otherwise */ - shouldApply(args: any[]) { - const holder = args[0] as Pokemon; - - return super.shouldApply(args) && (this.species.includes(holder.getSpeciesForm(true).speciesId) || (holder.isFusion() && this.species.includes(holder.getFusionSpeciesForm(true).speciesId))); + override shouldApply(pokemon: Pokemon, critStage: NumberHolder): boolean { + return super.shouldApply(pokemon, critStage) && (this.species.includes(pokemon.getSpeciesForm(true).speciesId) || (pokemon.isFusion() && this.species.includes(pokemon.getFusionSpeciesForm(true).speciesId))); } } @@ -1335,7 +1449,7 @@ export class AttackTypeBoosterModifier extends PokemonHeldItemModifier { public moveType: Type; private boostMultiplier: number; - constructor(type: ModifierType, pokemonId: integer, moveType: Type, boostPercent: number, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, moveType: Type, boostPercent: number, stackCount?: number) { super(type, pokemonId, stackCount); this.moveType = moveType; @@ -1359,20 +1473,27 @@ export class AttackTypeBoosterModifier extends PokemonHeldItemModifier { return super.getArgs().concat([ this.moveType, this.boostMultiplier * 100 ]); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 3 && typeof args[1] === "number" && args[2] instanceof Utils.NumberHolder; + /** + * Checks if {@linkcode AttackTypeBoosterModifier} should be applied + * @param pokemon the {@linkcode Pokemon} that holds the held item + * @param moveType the {@linkcode Type} of the move being used + * @param movePower the {@linkcode NumberHolder} that holds the power of the move + * @returns `true` if boosts should be applied to the move. + */ + override shouldApply(pokemon?: Pokemon, moveType?: Type, movePower?: NumberHolder): boolean { + return super.shouldApply(pokemon, moveType, movePower) && typeof moveType === "number" && movePower instanceof NumberHolder; } /** - * @param {Array} args Array - * - Index 0: {Pokemon} Pokemon - * - Index 1: {number} Move type - * - Index 2: {Utils.NumberHolder} Move power - * @returns {boolean} Returns true if boosts have been applied to the move. - */ - apply(args: any[]): boolean { - if (args[1] === this.moveType && (args[2] as Utils.NumberHolder).value >= 1) { - (args[2] as Utils.NumberHolder).value = Math.floor((args[2] as Utils.NumberHolder).value * (1 + (this.getStackCount() * this.boostMultiplier))); + * Applies {@linkcode AttackTypeBoosterModifier} + * @param pokemon {@linkcode Pokemon} that holds the held item + * @param moveType {@linkcode Type} of the move being used + * @param movePower {@linkcode NumberHolder} that holds the power of the move + * @returns `true` if boosts have been applied to the move. + */ + override apply(_pokemon: Pokemon, moveType: Type, movePower: NumberHolder): boolean { + if (moveType === this.moveType && movePower.value >= 1) { + (movePower as NumberHolder).value = Math.floor((movePower as NumberHolder).value * (1 + (this.getStackCount() * this.boostMultiplier))); return true; } @@ -1383,13 +1504,13 @@ export class AttackTypeBoosterModifier extends PokemonHeldItemModifier { return 1.2; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 99; } } export class SurviveDamageModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -1401,14 +1522,23 @@ export class SurviveDamageModifier extends PokemonHeldItemModifier { return new SurviveDamageModifier(this.type, this.pokemonId, this.stackCount); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && args[1] instanceof Utils.BooleanHolder; + /** + * Checks if the {@linkcode SurviveDamageModifier} should be applied + * @param pokemon the {@linkcode Pokemon} that holds the item + * @param surviveDamage {@linkcode BooleanHolder} that holds the survive damage + * @returns `true` if the {@linkcode SurviveDamageModifier} should be applied + */ + override shouldApply(pokemon?: Pokemon, surviveDamage?: BooleanHolder): boolean { + return super.shouldApply(pokemon, surviveDamage) && !!surviveDamage; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - const surviveDamage = args[1] as Utils.BooleanHolder; - + /** + * Applies {@linkcode SurviveDamageModifier} + * @param pokemon the {@linkcode Pokemon} that holds the item + * @param surviveDamage {@linkcode BooleanHolder} that holds the survive damage + * @returns `true` if the survive damage has been applied + */ + override apply(pokemon: Pokemon, surviveDamage: BooleanHolder): boolean { if (!surviveDamage.value && pokemon.randSeedInt(10) < this.getStackCount()) { surviveDamage.value = true; @@ -1419,13 +1549,13 @@ export class SurviveDamageModifier extends PokemonHeldItemModifier { return false; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 5; } } export class BypassSpeedChanceModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -1437,18 +1567,27 @@ export class BypassSpeedChanceModifier extends PokemonHeldItemModifier { return new BypassSpeedChanceModifier(this.type, this.pokemonId, this.stackCount); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && args[1] instanceof Utils.BooleanHolder; + /** + * Checks if {@linkcode BypassSpeedChanceModifier} should be applied + * @param pokemon the {@linkcode Pokemon} that holds the item + * @param doBypassSpeed {@linkcode BooleanHolder} that is `true` if speed should be bypassed + * @returns `true` if {@linkcode BypassSpeedChanceModifier} should be applied + */ + override shouldApply(pokemon?: Pokemon, doBypassSpeed?: BooleanHolder): boolean { + return super.shouldApply(pokemon, doBypassSpeed) && !!doBypassSpeed; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - const bypassSpeed = args[1] as Utils.BooleanHolder; - - if (!bypassSpeed.value && pokemon.randSeedInt(10) < this.getStackCount()) { - bypassSpeed.value = true; + /** + * Applies {@linkcode BypassSpeedChanceModifier} + * @param pokemon the {@linkcode Pokemon} that holds the item + * @param doBypassSpeed {@linkcode BooleanHolder} that is `true` if speed should be bypassed + * @returns `true` if {@linkcode BypassSpeedChanceModifier} has been applied + */ + override apply(pokemon: Pokemon, doBypassSpeed: BooleanHolder): boolean { + if (!doBypassSpeed.value && pokemon.randSeedInt(10) < this.getStackCount()) { + doBypassSpeed.value = true; const isCommandFight = pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()]?.command === Command.FIGHT; - const hasQuickClaw = this.type instanceof ModifierTypes.PokemonHeldItemModifierType && this.type.id === "QUICK_CLAW"; + const hasQuickClaw = this.type instanceof PokemonHeldItemModifierType && this.type.id === "QUICK_CLAW"; if (isCommandFight && hasQuickClaw) { pokemon.scene.queueMessage(i18next.t("modifier:bypassSpeedChanceApply", { pokemonName: getPokemonNameWithAffix(pokemon), itemName: i18next.t("modifierType:ModifierType.QUICK_CLAW.name") })); @@ -1459,13 +1598,13 @@ export class BypassSpeedChanceModifier extends PokemonHeldItemModifier { return false; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 3; } } export class FlinchChanceModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -1477,14 +1616,23 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier { return new FlinchChanceModifier(this.type, this.pokemonId, this.stackCount); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && args[1] instanceof Utils.BooleanHolder; + /** + * Checks if {@linkcode FlinchChanceModifier} should be applied + * @param pokemon the {@linkcode Pokemon} that holds the item + * @param flinched {@linkcode BooleanHolder} that is `true` if the pokemon flinched + * @returns `true` if {@linkcode FlinchChanceModifier} should be applied + */ + override shouldApply(pokemon?: Pokemon, flinched?: BooleanHolder): boolean { + return super.shouldApply(pokemon, flinched) && !!flinched; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - const flinched = args[1] as Utils.BooleanHolder; - + /** + * Applies {@linkcode FlinchChanceModifier} + * @param pokemon the {@linkcode Pokemon} that holds the item + * @param flinched {@linkcode BooleanHolder} that is `true` if the pokemon flinched + * @returns `true` if {@linkcode FlinchChanceModifier} has been applied + */ + override apply(pokemon: Pokemon, flinched: BooleanHolder): boolean { if (!flinched.value && pokemon.randSeedInt(10) < (this.getStackCount() * this.getSecondaryChanceMultiplier(pokemon))) { flinched.value = true; return true; @@ -1493,13 +1641,13 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier { return false; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 3; } } export class TurnHealModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -1511,20 +1659,23 @@ export class TurnHealModifier extends PokemonHeldItemModifier { return new TurnHealModifier(this.type, this.pokemonId, this.stackCount); } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - + /** + * Applies {@linkcode TurnHealModifier} + * @param pokemon The {@linkcode Pokemon} that holds the item + * @returns `true` if the {@linkcode Pokemon} was healed + */ + override apply(pokemon: Pokemon): boolean { if (!pokemon.isFullHp()) { const scene = pokemon.scene; scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Utils.toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount, i18next.t("modifier:turnHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); + toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount, i18next.t("modifier:turnHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); return true; } return false; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 4; } } @@ -1539,7 +1690,7 @@ export class TurnStatusEffectModifier extends PokemonHeldItemModifier { /** The status effect to be applied by the held item */ private effect: StatusEffect; - constructor (type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor (type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); switch (type.id) { @@ -1559,7 +1710,7 @@ export class TurnStatusEffectModifier extends PokemonHeldItemModifier { * would be the only item able to {@linkcode apply} successfully. * @override * @param modifier {@linkcode Modifier} being type tested - * @return true if {@linkcode modifier} is an instance of + * @return `true` if {@linkcode modifier} is an instance of * TurnStatusEffectModifier, false otherwise */ matchType(modifier: Modifier): boolean { @@ -1572,15 +1723,14 @@ export class TurnStatusEffectModifier extends PokemonHeldItemModifier { /** * Tries to inflicts the holder with the associated {@linkcode StatusEffect}. - * @param args [0] {@linkcode Pokemon} that holds the held item - * @returns true if the status effect was applied successfully, false if - * otherwise + * @param pokemon {@linkcode Pokemon} that holds the held item + * @returns `true` if the status effect was applied successfully */ - apply(args: any[]): boolean { - return (args[0] as Pokemon).trySetStatus(this.effect, true, undefined, undefined, this.type.name); + override apply(pokemon: Pokemon): boolean { + return pokemon.trySetStatus(this.effect, true, undefined, undefined, this.type.name); } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 1; } @@ -1590,7 +1740,7 @@ export class TurnStatusEffectModifier extends PokemonHeldItemModifier { } export class HitHealModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -1602,25 +1752,28 @@ export class HitHealModifier extends PokemonHeldItemModifier { return new HitHealModifier(this.type, this.pokemonId, this.stackCount); } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - + /** + * Applies {@linkcode HitHealModifier} + * @param pokemon The {@linkcode Pokemon} that holds the item + * @returns `true` if the {@linkcode Pokemon} was healed + */ + override apply(pokemon: Pokemon): boolean { if (pokemon.turnData.damageDealt && !pokemon.isFullHp()) { const scene = pokemon.scene; scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Utils.toDmgValue(pokemon.turnData.damageDealt / 8) * this.stackCount, i18next.t("modifier:hitHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); + toDmgValue(pokemon.turnData.damageDealt / 8) * this.stackCount, i18next.t("modifier:hitHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), true)); } return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 4; } } export class LevelIncrementBoosterModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -1632,12 +1785,22 @@ export class LevelIncrementBoosterModifier extends PersistentModifier { return new LevelIncrementBoosterModifier(this.type, this.stackCount); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args[0] instanceof Utils.IntegerHolder; + /** + * Checks if {@linkcode LevelIncrementBoosterModifier} should be applied + * @param count {@linkcode NumberHolder} holding the level increment count + * @returns `true` if {@linkcode LevelIncrementBoosterModifier} should be applied + */ + override shouldApply(count: NumberHolder): boolean { + return !!count; } - apply(args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value += this.getStackCount(); + /** + * Applies {@linkcode LevelIncrementBoosterModifier} + * @param count {@linkcode NumberHolder} holding the level increment count + * @returns always `true` + */ + override apply(count: NumberHolder): boolean { + count.value += this.getStackCount(); return true; } @@ -1651,7 +1814,7 @@ export class BerryModifier extends PokemonHeldItemModifier { public berryType: BerryType; public consumed: boolean; - constructor(type: ModifierType, pokemonId: integer, berryType: BerryType, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, berryType: BerryType, stackCount?: number) { super(type, pokemonId, stackCount); this.berryType = berryType; @@ -1670,14 +1833,22 @@ export class BerryModifier extends PokemonHeldItemModifier { return super.getArgs().concat(this.berryType); } - shouldApply(args: any[]): boolean { - return !this.consumed && super.shouldApply(args) && getBerryPredicate(this.berryType)(args[0] as Pokemon); + /** + * Checks if {@linkcode BerryModifier} should be applied + * @param pokemon The {@linkcode Pokemon} that holds the berry + * @returns `true` if {@linkcode BerryModifier} should be applied + */ + override shouldApply(pokemon: Pokemon): boolean { + return !this.consumed && super.shouldApply(pokemon) && getBerryPredicate(this.berryType)(pokemon); } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - - const preserve = new Utils.BooleanHolder(false); + /** + * Applies {@linkcode BerryModifier} + * @param pokemon The {@linkcode Pokemon} that holds the berry + * @returns always `true` + */ + override apply(pokemon: Pokemon): boolean { + const preserve = new BooleanHolder(false); pokemon.scene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), pokemon, preserve); getBerryEffectFunc(this.berryType)(pokemon); @@ -1688,7 +1859,7 @@ export class BerryModifier extends PokemonHeldItemModifier { return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { if ([BerryType.LUM, BerryType.LEPPA, BerryType.SITRUS, BerryType.ENIGMA].includes(this.berryType)) { return 2; } @@ -1697,7 +1868,7 @@ export class BerryModifier extends PokemonHeldItemModifier { } export class PreserveBerryModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -1709,25 +1880,37 @@ export class PreserveBerryModifier extends PersistentModifier { return new PreserveBerryModifier(this.type, this.stackCount); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args[0] instanceof Pokemon && args[1] instanceof Utils.BooleanHolder; + /** + * Checks if all prequired conditions are met to apply {@linkcode PreserveBerryModifier} + * @param pokemon {@linkcode Pokemon} that holds the berry + * @param doPreserve {@linkcode BooleanHolder} that is `true` if the berry should be preserved + * @returns `true` if {@linkcode PreserveBerryModifier} should be applied + */ + override shouldApply(pokemon?: Pokemon, doPreserve?: BooleanHolder): boolean { + return !!pokemon && !!doPreserve; } - apply(args: any[]): boolean { - if (!(args[1] as Utils.BooleanHolder).value) { - (args[1] as Utils.BooleanHolder).value = (args[0] as Pokemon).randSeedInt(10) < this.getStackCount() * 3; + /** + * Applies {@linkcode PreserveBerryModifier} + * @param pokemon The {@linkcode Pokemon} that holds the berry + * @param doPreserve {@linkcode BooleanHolder} that is `true` if the berry should be preserved + * @returns always `true` + */ + override apply(pokemon: Pokemon, doPreserve: BooleanHolder): boolean { + if (!doPreserve.value) { + doPreserve.value = pokemon.randSeedInt(10) < this.getStackCount() * 3; } return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 3; } } export class PokemonInstantReviveModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -1739,17 +1922,20 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier { return new PokemonInstantReviveModifier(this.type, this.pokemonId, this.stackCount); } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - + /** + * Applies {@linkcode PokemonInstantReviveModifier} + * @param pokemon The {@linkcode Pokemon} that holds the item + * @returns always `true` + */ + override apply(pokemon: Pokemon): boolean { pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), - Utils.toDmgValue(pokemon.getMaxHp() / 2), i18next.t("modifier:pokemonInstantReviveApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), false, false, true)); + toDmgValue(pokemon.getMaxHp() / 2), i18next.t("modifier:pokemonInstantReviveApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), typeName: this.type.name }), false, false, true)); pokemon.resetStatus(true, false, true); return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 1; } } @@ -1761,7 +1947,7 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier { * @see {@linkcode apply} */ export class ResetNegativeStatStageModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -1776,11 +1962,10 @@ export class ResetNegativeStatStageModifier extends PokemonHeldItemModifier { /** * Goes through the holder's stat stages and, if any are negative, resets that * stat stage back to 0. - * @param args [0] {@linkcode Pokemon} that holds the held item - * @returns true if any stat stages were reset, false otherwise + * @param pokemon {@linkcode Pokemon} that holds the item + * @returns `true` if any stat stages were reset, false otherwise */ - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; + override apply(pokemon: Pokemon): boolean { let statRestored = false; for (const s of BATTLE_STATS) { @@ -1796,36 +1981,49 @@ export class ResetNegativeStatStageModifier extends PokemonHeldItemModifier { return statRestored; } - getMaxHeldItemCount(_pokemon: Pokemon): integer { + getMaxHeldItemCount(_pokemon: Pokemon): number { return 2; } } export abstract class ConsumablePokemonModifier extends ConsumableModifier { - public pokemonId: integer; + public pokemonId: number; - constructor(type: ModifierType, pokemonId: integer) { + constructor(type: ModifierType, pokemonId: number) { super(type); this.pokemonId = pokemonId; } - shouldApply(args: any[]): boolean { - return args.length !== 0 && args[0] instanceof PlayerPokemon && (this.pokemonId === -1 || (args[0] as PlayerPokemon).id === this.pokemonId); + /** + * Checks if {@linkcode ConsumablePokemonModifier} should be applied + * @param playerPokemon The {@linkcode PlayerPokemon} that consumes the item + * @param _args N/A + * @returns `true` if {@linkcode ConsumablePokemonModifier} should be applied + */ + override shouldApply(playerPokemon?: PlayerPokemon, ..._args: unknown[]): boolean { + return !!playerPokemon && (this.pokemonId === -1 || playerPokemon.id === this.pokemonId); } + /** + * Applies {@linkcode ConsumablePokemonModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that consumes the item + * @param args Additional arguments passed to {@linkcode ConsumablePokemonModifier.apply} + */ + abstract override apply(playerPokemon: PlayerPokemon, ...args: unknown[]): boolean | Promise; + getPokemon(scene: BattleScene) { return scene.getParty().find(p => p.id === this.pokemonId); } } export class PokemonHpRestoreModifier extends ConsumablePokemonModifier { - private restorePoints: integer; + private restorePoints: number; private restorePercent: number; private healStatus: boolean; public fainted: boolean; - constructor(type: ModifierType, pokemonId: integer, restorePoints: integer, restorePercent: number, healStatus: boolean, fainted?: boolean) { + constructor(type: ModifierType, pokemonId: number, restorePoints: number, restorePercent: number, healStatus: boolean, fainted?: boolean) { super(type, pokemonId); this.restorePoints = restorePoints; @@ -1834,16 +2032,27 @@ export class PokemonHpRestoreModifier extends ConsumablePokemonModifier { this.fainted = !!fainted; } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && (this.fainted || (args.length > 1 && typeof(args[1]) === "number")); + /** + * Checks if {@linkcode PokemonHpRestoreModifier} should be applied + * @param playerPokemon The {@linkcode PlayerPokemon} that consumes the item + * @param multiplier The multiplier of the hp restore + * @returns `true` if the {@linkcode PokemonHpRestoreModifier} should be applied + */ + override shouldApply(playerPokemon?: PlayerPokemon, multiplier?: number): boolean { + return super.shouldApply(playerPokemon) && (this.fainted || (!isNullOrUndefined(multiplier) && typeof(multiplier) === "number")); } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; + /** + * Applies {@linkcode PokemonHpRestoreModifier} + * @param pokemon The {@linkcode PlayerPokemon} that consumes the item + * @param multiplier The multiplier of the hp restore + * @returns `true` if hp was restored + */ + override apply(pokemon: Pokemon, multiplier: number): boolean { if (!pokemon.hp === this.fainted) { let restorePoints = this.restorePoints; if (!this.fainted) { - restorePoints = Math.floor(restorePoints * (args[1] as number)); + restorePoints = Math.floor(restorePoints * multiplier); } if (this.fainted || this.healStatus) { pokemon.resetStatus(true, true); @@ -1856,21 +2065,25 @@ export class PokemonHpRestoreModifier extends ConsumablePokemonModifier { } export class PokemonStatusHealModifier extends ConsumablePokemonModifier { - constructor(type: ModifierType, pokemonId: integer) { + constructor(type: ModifierType, pokemonId: number) { super(type, pokemonId); } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - pokemon.resetStatus(true, true); + /** + * Applies {@linkcode PokemonStatusHealModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that gets healed from the status + * @returns always `true` + */ + override apply(playerPokemon: PlayerPokemon): boolean { + playerPokemon.resetStatus(true, true); return true; } } export abstract class ConsumablePokemonMoveModifier extends ConsumablePokemonModifier { - public moveIndex: integer; + public moveIndex: number; - constructor(type: ModifierType, pokemonId: integer, moveIndex: integer) { + constructor(type: ModifierType, pokemonId: number, moveIndex: number) { super(type, pokemonId); this.moveIndex = moveIndex; @@ -1878,36 +2091,49 @@ export abstract class ConsumablePokemonMoveModifier extends ConsumablePokemonMod } export class PokemonPpRestoreModifier extends ConsumablePokemonMoveModifier { - private restorePoints: integer; + private restorePoints: number; - constructor(type: ModifierType, pokemonId: integer, moveIndex: integer, restorePoints: integer) { + constructor(type: ModifierType, pokemonId: number, moveIndex: number, restorePoints: number) { super(type, pokemonId, moveIndex); this.restorePoints = restorePoints; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - const move = pokemon.getMoveset()[this.moveIndex]!; //TODO: is the bang correct? - move.ppUsed = this.restorePoints > -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0; + /** + * Applies {@linkcode PokemonPpRestoreModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that should get move pp restored + * @returns always `true` + */ + override apply(playerPokemon: PlayerPokemon): boolean { + const move = playerPokemon.getMoveset()[this.moveIndex]; + + if (move) { + move.ppUsed = this.restorePoints > -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0; + } return true; } } export class PokemonAllMovePpRestoreModifier extends ConsumablePokemonModifier { - private restorePoints: integer; + private restorePoints: number; - constructor(type: ModifierType, pokemonId: integer, restorePoints: integer) { + constructor(type: ModifierType, pokemonId: number, restorePoints: number) { super(type, pokemonId); this.restorePoints = restorePoints; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - for (const move of pokemon.getMoveset()) { - move!.ppUsed = this.restorePoints > -1 ? Math.max(move!.ppUsed - this.restorePoints, 0) : 0; // TODO: are those bangs correct? + /** + * Applies {@linkcode PokemonAllMovePpRestoreModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that should get all move pp restored + * @returns always `true` + */ + override apply(playerPokemon: PlayerPokemon): boolean { + for (const move of playerPokemon.getMoveset()) { + if (move) { + move.ppUsed = this.restorePoints > -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0; + } } return true; @@ -1915,18 +2141,25 @@ export class PokemonAllMovePpRestoreModifier extends ConsumablePokemonModifier { } export class PokemonPpUpModifier extends ConsumablePokemonMoveModifier { - private upPoints: integer; + private upPoints: number; - constructor(type: ModifierType, pokemonId: integer, moveIndex: integer, upPoints: integer) { + constructor(type: ModifierType, pokemonId: number, moveIndex: number, upPoints: number) { super(type, pokemonId, moveIndex); this.upPoints = upPoints; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - const move = pokemon.getMoveset()[this.moveIndex]!; // TODO: is the bang correct? - move.ppUp = Math.min(move.ppUp + this.upPoints, 3); + /** + * Applies {@linkcode PokemonPpUpModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that gets a pp up on move-slot {@linkcode moveIndex} + * @returns + */ + override apply(playerPokemon: PlayerPokemon): boolean { + const move = playerPokemon.getMoveset()[this.moveIndex]; + + if (move) { + move.ppUp = Math.min(move.ppUp + this.upPoints, 3); + } return true; } @@ -1935,21 +2168,25 @@ export class PokemonPpUpModifier extends ConsumablePokemonMoveModifier { export class PokemonNatureChangeModifier extends ConsumablePokemonModifier { public nature: Nature; - constructor(type: ModifierType, pokemonId: integer, nature: Nature) { + constructor(type: ModifierType, pokemonId: number, nature: Nature) { super(type, pokemonId); this.nature = nature; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - pokemon.natureOverride = this.nature; - let speciesId = pokemon.species.speciesId; - pokemon.scene.gameData.dexData[speciesId].natureAttr |= 1 << (this.nature + 1); + /** + * Applies {@linkcode PokemonNatureChangeModifier} + * @param playerPokemon {@linkcode PlayerPokemon} to apply the {@linkcode Nature} change to + * @returns + */ + override apply(playerPokemon: PlayerPokemon): boolean { + playerPokemon.natureOverride = this.nature; + let speciesId = playerPokemon.species.speciesId; + playerPokemon.scene.gameData.dexData[speciesId].natureAttr |= 1 << (this.nature + 1); while (pokemonPrevolutions.hasOwnProperty(speciesId)) { speciesId = pokemonPrevolutions[speciesId]; - pokemon.scene.gameData.dexData[speciesId].natureAttr |= 1 << (this.nature + 1); + playerPokemon.scene.gameData.dexData[speciesId].natureAttr |= 1 << (this.nature + 1); } return true; @@ -1957,86 +2194,104 @@ export class PokemonNatureChangeModifier extends ConsumablePokemonModifier { } export class PokemonLevelIncrementModifier extends ConsumablePokemonModifier { - constructor(type: ModifierType, pokemonId: integer) { + constructor(type: ModifierType, pokemonId: number) { super(type, pokemonId); } - apply(args: any[]): boolean { - const pokemon = args[0] as PlayerPokemon; - const levelCount = new Utils.IntegerHolder(1); - pokemon.scene.applyModifiers(LevelIncrementBoosterModifier, true, levelCount); + /** + * Applies {@linkcode PokemonLevelIncrementModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that should get levels incremented + * @param levelCount The amount of levels to increment + * @returns always `true` + */ + override apply(playerPokemon: PlayerPokemon, levelCount: NumberHolder): boolean { + playerPokemon.scene.applyModifiers(LevelIncrementBoosterModifier, true, levelCount); - pokemon.level += levelCount.value; - if (pokemon.level <= pokemon.scene.getMaxExpLevel(true)) { - pokemon.exp = getLevelTotalExp(pokemon.level, pokemon.species.growthRate); - pokemon.levelExp = 0; + playerPokemon.level += levelCount.value; + if (playerPokemon.level <= playerPokemon.scene.getMaxExpLevel(true)) { + playerPokemon.exp = getLevelTotalExp(playerPokemon.level, playerPokemon.species.growthRate); + playerPokemon.levelExp = 0; } - pokemon.addFriendship(5); + playerPokemon.addFriendship(5); - pokemon.scene.unshiftPhase(new LevelUpPhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), pokemon.level - levelCount.value, pokemon.level)); + playerPokemon.scene.unshiftPhase(new LevelUpPhase(playerPokemon.scene, playerPokemon.scene.getParty().indexOf(playerPokemon), playerPokemon.level - levelCount.value, playerPokemon.level)); return true; } } export class TmModifier extends ConsumablePokemonModifier { - constructor(type: ModifierTypes.TmModifierType, pokemonId: integer) { + public override type: TmModifierType; + + constructor(type: TmModifierType, pokemonId: number) { super(type, pokemonId); } - apply(args: any[]): boolean { - const pokemon = args[0] as PlayerPokemon; + /** + * Applies {@linkcode TmModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that should learn the TM + * @returns always `true` + */ + override apply(playerPokemon: PlayerPokemon): boolean { - pokemon.scene.unshiftPhase(new LearnMovePhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), (this.type as ModifierTypes.TmModifierType).moveId, true)); + playerPokemon.scene.unshiftPhase(new LearnMovePhase(playerPokemon.scene, playerPokemon.scene.getParty().indexOf(playerPokemon), this.type.moveId, true)); return true; } } export class RememberMoveModifier extends ConsumablePokemonModifier { - public levelMoveIndex: integer; + public levelMoveIndex: number; - constructor(type: ModifierTypes.ModifierType, pokemonId: integer, levelMoveIndex: integer) { + constructor(type: ModifierType, pokemonId: number, levelMoveIndex: number) { super(type, pokemonId); this.levelMoveIndex = levelMoveIndex; } - apply(args: any[]): boolean { - const pokemon = args[0] as PlayerPokemon; - - pokemon.scene.unshiftPhase(new LearnMovePhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), pokemon.getLearnableLevelMoves()[this.levelMoveIndex])); + /** + * Applies {@linkcode RememberMoveModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that should remember the move + * @returns always `true` + */ + override apply(playerPokemon: PlayerPokemon): boolean { + playerPokemon.scene.unshiftPhase(new LearnMovePhase(playerPokemon.scene, playerPokemon.scene.getParty().indexOf(playerPokemon), playerPokemon.getLearnableLevelMoves()[this.levelMoveIndex])); return true; } } export class EvolutionItemModifier extends ConsumablePokemonModifier { - constructor(type: ModifierTypes.EvolutionItemModifierType, pokemonId: integer) { + public override type: EvolutionItemModifierType; + + constructor(type: EvolutionItemModifierType, pokemonId: number) { super(type, pokemonId); } - apply(args: any[]): boolean { - const pokemon = args[0] as PlayerPokemon; - - let matchingEvolution = pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) - ? pokemonEvolutions[pokemon.species.speciesId].find(e => e.item === (this.type as ModifierTypes.EvolutionItemModifierType).evolutionItem - && (e.evoFormKey === null || (e.preFormKey || "") === pokemon.getFormKey()) - && (!e.condition || e.condition.predicate(pokemon))) + /** + * Applies {@linkcode EvolutionItemModifier} + * @param playerPokemon The {@linkcode PlayerPokemon} that should evolve via item + * @returns `true` if the evolution was successful + */ + override apply(playerPokemon: PlayerPokemon): boolean { + let matchingEvolution = pokemonEvolutions.hasOwnProperty(playerPokemon.species.speciesId) + ? pokemonEvolutions[playerPokemon.species.speciesId].find(e => e.item === this.type.evolutionItem + && (e.evoFormKey === null || (e.preFormKey || "") === playerPokemon.getFormKey()) + && (!e.condition || e.condition.predicate(playerPokemon))) : null; - if (!matchingEvolution && pokemon.isFusion()) { - matchingEvolution = pokemonEvolutions[pokemon.fusionSpecies!.speciesId].find(e => e.item === (this.type as ModifierTypes.EvolutionItemModifierType).evolutionItem // TODO: is the bang correct? - && (e.evoFormKey === null || (e.preFormKey || "") === pokemon.getFusionFormKey()) - && (!e.condition || e.condition.predicate(pokemon))); + if (!matchingEvolution && playerPokemon.isFusion()) { + matchingEvolution = pokemonEvolutions[playerPokemon.fusionSpecies!.speciesId].find(e => e.item === this.type.evolutionItem // TODO: is the bang correct? + && (e.evoFormKey === null || (e.preFormKey || "") === playerPokemon.getFusionFormKey()) + && (!e.condition || e.condition.predicate(playerPokemon))); if (matchingEvolution) { - matchingEvolution = new FusionSpeciesFormEvolution(pokemon.species.speciesId, matchingEvolution); + matchingEvolution = new FusionSpeciesFormEvolution(playerPokemon.species.speciesId, matchingEvolution); } } if (matchingEvolution) { - pokemon.scene.unshiftPhase(new EvolutionPhase(pokemon.scene, pokemon, matchingEvolution, pokemon.level - 1)); + playerPokemon.scene.unshiftPhase(new EvolutionPhase(playerPokemon.scene, playerPokemon, matchingEvolution, playerPokemon.level - 1)); return true; } @@ -2045,27 +2300,38 @@ export class EvolutionItemModifier extends ConsumablePokemonModifier { } export class FusePokemonModifier extends ConsumablePokemonModifier { - public fusePokemonId: integer; + public fusePokemonId: number; - constructor(type: ModifierType, pokemonId: integer, fusePokemonId: integer) { + constructor(type: ModifierType, pokemonId: number, fusePokemonId: number) { super(type, pokemonId); this.fusePokemonId = fusePokemonId; } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args[1] instanceof PlayerPokemon && this.fusePokemonId === (args[1] as PlayerPokemon).id; + /** + * Checks if {@linkcode FusePokemonModifier} should be applied + * @param playerPokemon {@linkcode PlayerPokemon} that should be fused + * @param playerPokemon2 {@linkcode PlayerPokemon} that should be fused with {@linkcode playerPokemon} + * @returns `true` if {@linkcode FusePokemonModifier} should be applied + */ + override shouldApply(playerPokemon?: PlayerPokemon, playerPokemon2?: PlayerPokemon): boolean { + return super.shouldApply(playerPokemon, playerPokemon2) && !!playerPokemon2 && this.fusePokemonId === playerPokemon2.id; } - apply(args: any[]): Promise { - return new Promise(resolve => { - (args[0] as PlayerPokemon).fuse(args[1] as PlayerPokemon).then(() => resolve(true)); - }); + /** + * Applies {@linkcode FusePokemonModifier} + * @param playerPokemon {@linkcode PlayerPokemon} that should be fused + * @param playerPokemon2 {@linkcode PlayerPokemon} that should be fused with {@linkcode playerPokemon} + * @returns always Promise + */ + override async apply(playerPokemon: PlayerPokemon, playerPokemon2: PlayerPokemon): Promise { + await playerPokemon.fuse(playerPokemon2); + return true; } } export class MultipleParticipantExpBonusModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2073,7 +2339,11 @@ export class MultipleParticipantExpBonusModifier extends PersistentModifier { return modifier instanceof MultipleParticipantExpBonusModifier; } - apply(_args: any[]): boolean { + /** + * Applies {@linkcode MultipleParticipantExpBonusModifier} + * @returns always `true` + */ + apply(): boolean { return true; } @@ -2081,7 +2351,7 @@ export class MultipleParticipantExpBonusModifier extends PersistentModifier { return new MultipleParticipantExpBonusModifier(this.type, this.stackCount); } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 5; } } @@ -2089,7 +2359,7 @@ export class MultipleParticipantExpBonusModifier extends PersistentModifier { export class HealingBoosterModifier extends PersistentModifier { private multiplier: number; - constructor(type: ModifierType, multiplier: number, stackCount?: integer) { + constructor(type: ModifierType, multiplier: number, stackCount?: number) { super(type, stackCount); this.multiplier = multiplier; @@ -2107,22 +2377,26 @@ export class HealingBoosterModifier extends PersistentModifier { return [ this.multiplier ]; } - apply(args: any[]): boolean { - const healingMultiplier = args[0] as Utils.IntegerHolder; + /** + * Applies {@linkcode HealingBoosterModifier} + * @param healingMultiplier the multiplier to apply to the healing + * @returns always `true` + */ + override apply(healingMultiplier: NumberHolder): boolean { healingMultiplier.value *= 1 + ((this.multiplier - 1) * this.getStackCount()); return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 5; } } export class ExpBoosterModifier extends PersistentModifier { - private boostMultiplier: integer; + private boostMultiplier: number; - constructor(type: ModifierType, boostPercent: number, stackCount?: integer) { + constructor(type: ModifierType, boostPercent: number, stackCount?: number) { super(type, stackCount); this.boostMultiplier = boostPercent * 0.01; @@ -2144,21 +2418,28 @@ export class ExpBoosterModifier extends PersistentModifier { return [ this.boostMultiplier * 100 ]; } - apply(args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = Math.floor((args[0] as Utils.NumberHolder).value * (1 + (this.getStackCount() * this.boostMultiplier))); + /** + * Applies {@linkcode ExpBoosterModifier} + * @param boost {@linkcode NumberHolder} holding the boost value + * @returns always `true` + */ + override apply(boost: NumberHolder): boolean { + boost.value = Math.floor(boost.value * (1 + (this.getStackCount() * this.boostMultiplier))); return true; } - getMaxStackCount(scene: BattleScene, forThreshold?: boolean): integer { + getMaxStackCount(scene: BattleScene, forThreshold?: boolean): number { return this.boostMultiplier < 1 ? this.boostMultiplier < 0.6 ? 99 : 30 : 10; } } export class PokemonExpBoosterModifier extends PokemonHeldItemModifier { - private boostMultiplier: integer; + public override type: PokemonExpBoosterModifierType; - constructor(type: ModifierTypes.PokemonExpBoosterModifierType, pokemonId: integer, boostPercent: number, stackCount?: integer) { + private boostMultiplier: number; + + constructor(type: PokemonExpBoosterModifierType, pokemonId: number, boostPercent: number, stackCount?: number) { super(type, pokemonId, stackCount); this.boostMultiplier = boostPercent * 0.01; } @@ -2172,30 +2453,42 @@ export class PokemonExpBoosterModifier extends PokemonHeldItemModifier { } clone(): PersistentModifier { - return new PokemonExpBoosterModifier(this.type as ModifierTypes.PokemonExpBoosterModifierType, this.pokemonId, this.boostMultiplier * 100, this.stackCount); + return new PokemonExpBoosterModifier(this.type, this.pokemonId, this.boostMultiplier * 100, this.stackCount); } getArgs(): any[] { return super.getArgs().concat(this.boostMultiplier * 100); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && args[1] instanceof Utils.NumberHolder; + /** + * Checks if {@linkcode PokemonExpBoosterModifier} should be applied + * @param pokemon The {@linkcode Pokemon} to apply the exp boost to + * @param boost {@linkcode NumberHolder} holding the exp boost value + * @returns `true` if {@linkcode PokemonExpBoosterModifier} should be applied + */ + override shouldApply(pokemon: Pokemon, boost: NumberHolder): boolean { + return super.shouldApply(pokemon, boost) && !!boost; } - apply(args: any[]): boolean { - (args[1] as Utils.NumberHolder).value = Math.floor((args[1] as Utils.NumberHolder).value * (1 + (this.getStackCount() * this.boostMultiplier))); + /** + * Applies {@linkcode PokemonExpBoosterModifier} + * @param _pokemon The {@linkcode Pokemon} to apply the exp boost to + * @param boost {@linkcode NumberHolder} holding the exp boost value + * @returns always `true` + */ + override apply(_pokemon: Pokemon, boost: NumberHolder): boolean { + boost.value = Math.floor(boost.value * (1 + (this.getStackCount() * this.boostMultiplier))); return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 99; } } export class ExpShareModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2207,17 +2500,21 @@ export class ExpShareModifier extends PersistentModifier { return new ExpShareModifier(this.type, this.stackCount); } - apply(_args: any[]): boolean { + /** + * Applies {@linkcode ExpShareModifier} + * @returns always `true` + */ + override apply(): boolean { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 5; } } export class ExpBalanceModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2229,17 +2526,23 @@ export class ExpBalanceModifier extends PersistentModifier { return new ExpBalanceModifier(this.type, this.stackCount); } - apply(_args: any[]): boolean { + /** + * Applies {@linkcode ExpBalanceModifier} + * @returns always `true` + */ + override apply(): boolean { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 4; } } export class PokemonFriendshipBoosterModifier extends PokemonHeldItemModifier { - constructor(type: ModifierTypes.PokemonFriendshipBoosterModifierType, pokemonId: integer, stackCount?: integer) { + public override type: PokemonFriendshipBoosterModifierType; + + constructor(type: PokemonFriendshipBoosterModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -2248,23 +2551,28 @@ export class PokemonFriendshipBoosterModifier extends PokemonHeldItemModifier { } clone(): PersistentModifier { - return new PokemonFriendshipBoosterModifier(this.type as ModifierTypes.PokemonFriendshipBoosterModifierType, this.pokemonId, this.stackCount); + return new PokemonFriendshipBoosterModifier(this.type, this.pokemonId, this.stackCount); } - apply(args: any[]): boolean { - const friendship = args[1] as Utils.IntegerHolder; + /** + * Applies {@linkcode PokemonFriendshipBoosterModifier} + * @param _pokemon The {@linkcode Pokemon} to apply the friendship boost to + * @param friendship {@linkcode NumberHolder} holding the friendship boost value + * @returns always `true` + */ + override apply(_pokemon: Pokemon, friendship: NumberHolder): boolean { friendship.value = Math.floor(friendship.value * (1 + 0.5 * this.getStackCount())); return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 3; } } export class PokemonNatureWeightModifier extends PokemonHeldItemModifier { - constructor(type: ModifierTypes.ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -2276,8 +2584,13 @@ export class PokemonNatureWeightModifier extends PokemonHeldItemModifier { return new PokemonNatureWeightModifier(this.type, this.pokemonId, this.stackCount); } - apply(args: any[]): boolean { - const multiplier = args[1] as Utils.IntegerHolder; + /** + * Applies {@linkcode PokemonNatureWeightModifier} + * @param _pokemon The {@linkcode Pokemon} to apply the nature weight to + * @param multiplier {@linkcode NumberHolder} holding the nature weight + * @returns `true` if multiplier was applied + */ + override apply(_pokemon: Pokemon, multiplier: NumberHolder): boolean { if (multiplier.value !== 1) { multiplier.value += 0.1 * this.getStackCount() * (multiplier.value > 1 ? 1 : -1); return true; @@ -2286,15 +2599,16 @@ export class PokemonNatureWeightModifier extends PokemonHeldItemModifier { return false; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 10; } } export class PokemonMoveAccuracyBoosterModifier extends PokemonHeldItemModifier { - private accuracyAmount: integer; + public override type: PokemonMoveAccuracyBoosterModifierType; + private accuracyAmount: number; - constructor(type: ModifierTypes.PokemonMoveAccuracyBoosterModifierType, pokemonId: integer, accuracy: integer, stackCount?: integer) { + constructor(type: PokemonMoveAccuracyBoosterModifierType, pokemonId: number, accuracy: number, stackCount?: number) { super(type, pokemonId, stackCount); this.accuracyAmount = accuracy; } @@ -2308,31 +2622,44 @@ export class PokemonMoveAccuracyBoosterModifier extends PokemonHeldItemModifier } clone(): PersistentModifier { - return new PokemonMoveAccuracyBoosterModifier(this.type as ModifierTypes.PokemonMoveAccuracyBoosterModifierType, this.pokemonId, this.accuracyAmount, this.stackCount); + return new PokemonMoveAccuracyBoosterModifier(this.type, this.pokemonId, this.accuracyAmount, this.stackCount); } getArgs(): any[] { return super.getArgs().concat(this.accuracyAmount); } - shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && args[1] instanceof Utils.NumberHolder; + /** + * Checks if {@linkcode PokemonMoveAccuracyBoosterModifier} should be applied + * @param pokemon The {@linkcode Pokemon} to apply the move accuracy boost to + * @param moveAccuracy {@linkcode NumberHolder} holding the move accuracy boost + * @returns `true` if {@linkcode PokemonMoveAccuracyBoosterModifier} should be applied + */ + override shouldApply(pokemon?: Pokemon, moveAccuracy?: NumberHolder): boolean { + return super.shouldApply(pokemon, moveAccuracy) && !!moveAccuracy; } - apply(args: any[]): boolean { - const moveAccuracy = (args[1] as Utils.IntegerHolder); + /** + * Applies {@linkcode PokemonMoveAccuracyBoosterModifier} + * @param _pokemon The {@linkcode Pokemon} to apply the move accuracy boost to + * @param moveAccuracy {@linkcode NumberHolder} holding the move accuracy boost + * @returns always `true` + */ + override apply(_pokemon: Pokemon, moveAccuracy: NumberHolder): boolean { moveAccuracy.value = Math.min(moveAccuracy.value + this.accuracyAmount * this.getStackCount(), 100); return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 3; } } export class PokemonMultiHitModifier extends PokemonHeldItemModifier { - constructor(type: ModifierTypes.PokemonMultiHitModifierType, pokemonId: integer, stackCount?: integer) { + public override type: PokemonMultiHitModifierType; + + constructor(type: PokemonMultiHitModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -2341,13 +2668,19 @@ export class PokemonMultiHitModifier extends PokemonHeldItemModifier { } clone(): PersistentModifier { - return new PokemonMultiHitModifier(this.type as ModifierTypes.PokemonMultiHitModifierType, this.pokemonId, this.stackCount); + return new PokemonMultiHitModifier(this.type, this.pokemonId, this.stackCount); } - apply(args: any[]): boolean { - (args[1] as Utils.IntegerHolder).value *= (this.getStackCount() + 1); + /** + * Applies {@linkcode PokemonMultiHitModifier} + * @param _pokemon The {@linkcode Pokemon} using the move + * @param count {@linkcode NumberHolder} holding the number of items + * @param power {@linkcode NumberHolder} holding the power of the move + * @returns always `true` + */ + override apply(_pokemon: Pokemon, count: NumberHolder, power: NumberHolder): boolean { + count.value *= (this.getStackCount() + 1); - const power = args[2] as Utils.NumberHolder; switch (this.getStackCount()) { case 1: power.value *= 0.4; @@ -2363,17 +2696,18 @@ export class PokemonMultiHitModifier extends PokemonHeldItemModifier { return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 3; } } export class PokemonFormChangeItemModifier extends PokemonHeldItemModifier { + public override type: FormChangeItemModifierType; public formChangeItem: FormChangeItem; public active: boolean; public isTransferable: boolean = false; - constructor(type: ModifierTypes.FormChangeItemModifierType, pokemonId: integer, formChangeItem: FormChangeItem, active: boolean, stackCount?: integer) { + constructor(type: FormChangeItemModifierType, pokemonId: number, formChangeItem: FormChangeItem, active: boolean, stackCount?: number) { super(type, pokemonId, stackCount); this.formChangeItem = formChangeItem; this.active = active; @@ -2384,17 +2718,20 @@ export class PokemonFormChangeItemModifier extends PokemonHeldItemModifier { } clone(): PersistentModifier { - return new PokemonFormChangeItemModifier(this.type as ModifierTypes.FormChangeItemModifierType, this.pokemonId, this.formChangeItem, this.active, this.stackCount); + return new PokemonFormChangeItemModifier(this.type, this.pokemonId, this.formChangeItem, this.active, this.stackCount); } getArgs(): any[] { return super.getArgs().concat(this.formChangeItem, this.active); } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - const active = args[1] as boolean; - + /** + * Applies {@linkcode PokemonFormChangeItemModifier} + * @param pokemon The {@linkcode Pokemon} to apply the form change item to + * @param active `true` if the form change item is active + * @returns `true` if the form change item was applied + */ + override apply(pokemon: Pokemon, active: boolean): boolean { const switchActive = this.active && !active; if (switchActive) { @@ -2410,7 +2747,7 @@ export class PokemonFormChangeItemModifier extends PokemonHeldItemModifier { return ret; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 1; } } @@ -2424,19 +2761,23 @@ export class MoneyRewardModifier extends ConsumableModifier { this.moneyMultiplier = moneyMultiplier; } - apply(args: any[]): boolean { - const scene = args[0] as BattleScene; - const moneyAmount = new Utils.IntegerHolder(scene.getWaveMoneyAmount(this.moneyMultiplier)); + /** + * Applies {@linkcode MoneyRewardModifier} + * @param battleScene The current {@linkcode BattleScene} + * @returns always `true` + */ + override apply(battleScene: BattleScene): boolean { + const moneyAmount = new NumberHolder(battleScene.getWaveMoneyAmount(this.moneyMultiplier)); - scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); + battleScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); - scene.addMoney(moneyAmount.value); + battleScene.addMoney(moneyAmount.value); - scene.getParty().map(p => { + battleScene.getParty().map(p => { if (p.species?.speciesId === Species.GIMMIGHOUL || p.fusionSpecies?.speciesId === Species.GIMMIGHOUL) { p.evoCounter ? p.evoCounter++ : p.evoCounter = 1; const modifier = getModifierType(modifierTypes.EVOLUTION_TRACKER_GIMMIGHOUL).newModifier(p) as EvoTrackerModifier; - scene.addModifier(modifier); + battleScene.addModifier(modifier); } }); @@ -2445,7 +2786,7 @@ export class MoneyRewardModifier extends ConsumableModifier { } export class MoneyMultiplierModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2457,19 +2798,24 @@ export class MoneyMultiplierModifier extends PersistentModifier { return new MoneyMultiplierModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value += Math.floor((args[0] as Utils.IntegerHolder).value * 0.2 * this.getStackCount()); + /** + * Applies {@linkcode MoneyMultiplierModifier} + * @param multiplier {@linkcode NumberHolder} holding the money multiplier value + * @returns always `true` + */ + override apply(multiplier: NumberHolder): boolean { + multiplier.value += Math.floor(multiplier.value * 0.2 * this.getStackCount()); return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 5; } } export class DamageMoneyRewardModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -2481,22 +2827,28 @@ export class DamageMoneyRewardModifier extends PokemonHeldItemModifier { return new DamageMoneyRewardModifier(this.type, this.pokemonId, this.stackCount); } - apply(args: any[]): boolean { - const scene = (args[0] as Pokemon).scene; - const moneyAmount = new Utils.IntegerHolder(Math.floor((args[1] as Utils.IntegerHolder).value * (0.5 * this.getStackCount()))); - scene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); - scene.addMoney(moneyAmount.value); + /** + * Applies {@linkcode DamageMoneyRewardModifier} + * @param pokemon The {@linkcode Pokemon} attacking + * @param multiplier {@linkcode NumberHolder} holding the multiplier value + * @returns always `true` + */ + override apply(pokemon: Pokemon, multiplier: NumberHolder): boolean { + const battleScene = pokemon.scene; + const moneyAmount = new NumberHolder(Math.floor(multiplier.value * (0.5 * this.getStackCount()))); + battleScene.applyModifiers(MoneyMultiplierModifier, true, moneyAmount); + battleScene.addMoney(moneyAmount.value); return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 5; } } export class MoneyInterestModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2504,15 +2856,19 @@ export class MoneyInterestModifier extends PersistentModifier { return modifier instanceof MoneyInterestModifier; } - apply(args: any[]): boolean { - const scene = args[0] as BattleScene; - const interestAmount = Math.floor(scene.money * 0.1 * this.getStackCount()); - scene.addMoney(interestAmount); + /** + * Applies {@linkcode MoneyInterestModifier} + * @param battleScene The current {@linkcode BattleScene} + * @returns always `true` + */ + override apply(battleScene: BattleScene): boolean { + const interestAmount = Math.floor(battleScene.money * 0.1 * this.getStackCount()); + battleScene.addMoney(interestAmount); const userLocale = navigator.language || "en-US"; const formattedMoneyAmount = interestAmount.toLocaleString(userLocale); const message = i18next.t("modifier:moneyInterestApply", { moneyAmount: formattedMoneyAmount, typeName: this.type.name }); - scene.queueMessage(message, undefined, true); + battleScene.queueMessage(message, undefined, true); return true; } @@ -2521,13 +2877,13 @@ export class MoneyInterestModifier extends PersistentModifier { return new MoneyInterestModifier(this.type, this.stackCount); } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 5; } } export class HiddenAbilityRateBoosterModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2539,19 +2895,24 @@ export class HiddenAbilityRateBoosterModifier extends PersistentModifier { return new HiddenAbilityRateBoosterModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value *= Math.pow(2, -1 - this.getStackCount()); + /** + * Applies {@linkcode HiddenAbilityRateBoosterModifier} + * @param boost {@linkcode NumberHolder} holding the boost value + * @returns always `true` + */ + override apply(boost: NumberHolder): boolean { + boost.value *= Math.pow(2, -1 - this.getStackCount()); return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 4; } } export class ShinyRateBoosterModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2563,19 +2924,24 @@ export class ShinyRateBoosterModifier extends PersistentModifier { return new ShinyRateBoosterModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value *= Math.pow(2, 1 + this.getStackCount()); + /** + * Applies {@linkcode ShinyRateBoosterModifier} + * @param boost {@linkcode NumberHolder} holding the boost value + * @returns always `true` + */ + override apply(boost: NumberHolder): boolean { + boost.value *= Math.pow(2, 1 + this.getStackCount()); return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 4; } } export class LockModifierTiersModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2583,7 +2949,11 @@ export class LockModifierTiersModifier extends PersistentModifier { return modifier instanceof LockModifierTiersModifier; } - apply(args: any[]): boolean { + /** + * Applies {@linkcode LockModifierTiersModifier} + * @returns always `true` + */ + override apply(): boolean { return true; } @@ -2591,7 +2961,7 @@ export class LockModifierTiersModifier extends PersistentModifier { return new LockModifierTiersModifier(this.type, this.stackCount); } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 1; } } @@ -2602,7 +2972,7 @@ export class LockModifierTiersModifier extends PersistentModifier { export class HealShopCostModifier extends PersistentModifier { public readonly shopMultiplier: number; - constructor(type: ModifierType, shopMultiplier: number, stackCount?: integer) { + constructor(type: ModifierType, shopMultiplier: number, stackCount?: number) { super(type, stackCount); this.shopMultiplier = shopMultiplier ?? 2.5; @@ -2616,8 +2986,12 @@ export class HealShopCostModifier extends PersistentModifier { return new HealShopCostModifier(this.type, this.shopMultiplier, this.stackCount); } - apply(args: any[]): boolean { - const moneyCost = args[0] as Utils.NumberHolder; + /** + * Applies {@linkcode HealShopCostModifier} + * @param cost {@linkcode NumberHolder} holding the heal shop cost + * @returns always `true` + */ + apply(moneyCost: NumberHolder): boolean { moneyCost.value = Math.floor(moneyCost.value * this.shopMultiplier); return true; @@ -2627,13 +3001,13 @@ export class HealShopCostModifier extends PersistentModifier { return super.getArgs().concat(this.shopMultiplier); } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 1; } } export class BoostBugSpawnModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2645,17 +3019,21 @@ export class BoostBugSpawnModifier extends PersistentModifier { return new BoostBugSpawnModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { + /** + * Applies {@linkcode BoostBugSpawnModifier} + * @returns always `true` + */ + override apply(): boolean { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 1; } } export class SwitchEffectTransferModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -2667,11 +3045,15 @@ export class SwitchEffectTransferModifier extends PokemonHeldItemModifier { return new SwitchEffectTransferModifier(this.type, this.pokemonId, this.stackCount); } - apply(args: any[]): boolean { + /** + * Applies {@linkcode SwitchEffectTransferModifier} + * @returns always `true` + */ + override apply(): boolean { return true; } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 1; } } @@ -2682,18 +3064,17 @@ export class SwitchEffectTransferModifier extends PokemonHeldItemModifier { * @see {@linkcode ContactHeldItemTransferChanceModifier} */ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } /** * Determines the targets to transfer items from when this applies. - * @param args\[0\] the {@linkcode Pokemon} holding this item + * @param pokemon the {@linkcode Pokemon} holding this item + * @param _args N/A * @returns the opponents of the source {@linkcode Pokemon} */ - getTargets(args: any[]): Pokemon[] { - const pokemon = args[0]; - + getTargets(pokemon?: Pokemon, ..._args: unknown[]): Pokemon[] { return pokemon instanceof Pokemon ? pokemon.getOpponents() : []; @@ -2702,12 +3083,12 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { /** * Steals an item from a set of target Pokemon. * This prioritizes high-tier held items when selecting the item to steal. - * @param args \[0\] The {@linkcode Pokemon} holding this item - * @returns true if an item was stolen; false otherwise. + * @param pokemon The {@linkcode Pokemon} holding this item + * @param _args N/A + * @returns `true` if an item was stolen; false otherwise. */ - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - const opponents = this.getTargets(args); + override apply(pokemon: Pokemon, ..._args: unknown[]): boolean { + const opponents = this.getTargets(pokemon); if (!opponents.length) { return false; @@ -2720,9 +3101,9 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { return false; } - const poolType = pokemon.isPlayer() ? ModifierTypes.ModifierPoolType.PLAYER : pokemon.hasTrainer() ? ModifierTypes.ModifierPoolType.TRAINER : ModifierTypes.ModifierPoolType.WILD; + const poolType = pokemon.isPlayer() ? ModifierPoolType.PLAYER : pokemon.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD; - const transferredModifierTypes: ModifierTypes.ModifierType[] = []; + const transferredModifierTypes: ModifierType[] = []; const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === targetPokemon.id && m.isTransferable, targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; let highestItemTier = itemModifiers.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is this bang correct? @@ -2758,9 +3139,9 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { return !!transferredModifierTypes.length; } - abstract getTransferredItemCount(): integer; + abstract getTransferredItemCount(): number; - abstract getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierTypes.ModifierType): string; + abstract getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierType): string; } /** @@ -2770,7 +3151,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { */ export class TurnHeldItemTransferModifier extends HeldItemTransferModifier { isTransferable: boolean = true; - constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); } @@ -2782,15 +3163,15 @@ export class TurnHeldItemTransferModifier extends HeldItemTransferModifier { return new TurnHeldItemTransferModifier(this.type, this.pokemonId, this.stackCount); } - getTransferredItemCount(): integer { + getTransferredItemCount(): number { return this.getStackCount(); } - getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierTypes.ModifierType): string { + getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierType): string { return i18next.t("modifier:turnHeldItemTransferApply", { pokemonNameWithAffix: getPokemonNameWithAffix(targetPokemon), itemName: item.name, pokemonName: pokemon.getNameToRender(), typeName: this.type.name }); } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 1; } @@ -2808,7 +3189,7 @@ export class TurnHeldItemTransferModifier extends HeldItemTransferModifier { export class ContactHeldItemTransferChanceModifier extends HeldItemTransferModifier { private chance: number; - constructor(type: ModifierType, pokemonId: integer, chancePercent: number, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: number, chancePercent: number, stackCount?: number) { super(type, pokemonId, stackCount); this.chance = chancePercent / 100; @@ -2816,16 +3197,12 @@ export class ContactHeldItemTransferChanceModifier extends HeldItemTransferModif /** * Determines the target to steal items from when this applies. - * @param args\[0\] The {@linkcode Pokemon} holding this item - * @param args\[1\] The {@linkcode Pokemon} the holder is targeting with an attack - * @returns The target (args[1]) stored in array format for use in {@linkcode HeldItemTransferModifier.apply} + * @param _holderPokemon The {@linkcode Pokemon} holding this item + * @param targetPokemon The {@linkcode Pokemon} the holder is targeting with an attack + * @returns The target {@linkcode Pokemon} as array for further use in `apply` implementations */ - getTargets(args: any[]): Pokemon[] { - const target = args[1]; - - return target instanceof Pokemon - ? [ target ] - : []; + override getTargets(_holderPokemon: Pokemon, targetPokemon: Pokemon): Pokemon[] { + return !!targetPokemon ? [ targetPokemon ] : []; } matchType(modifier: Modifier): boolean { @@ -2840,21 +3217,21 @@ export class ContactHeldItemTransferChanceModifier extends HeldItemTransferModif return super.getArgs().concat(this.chance * 100); } - getTransferredItemCount(): integer { + getTransferredItemCount(): number { return Phaser.Math.RND.realInRange(0, 1) < (this.chance * this.getStackCount()) ? 1 : 0; } - getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierTypes.ModifierType): string { + getTransferMessage(pokemon: Pokemon, targetPokemon: Pokemon, item: ModifierType): string { return i18next.t("modifier:contactHeldItemTransferApply", { pokemonNameWithAffix: getPokemonNameWithAffix(targetPokemon), itemName: item.name, pokemonName: getPokemonNameWithAffix(pokemon), typeName: this.type.name }); } - getMaxHeldItemCount(pokemon: Pokemon): integer { + getMaxHeldItemCount(pokemon: Pokemon): number { return 5; } } export class IvScannerModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2866,17 +3243,21 @@ export class IvScannerModifier extends PersistentModifier { return new IvScannerModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { + /** + * Applies {@linkcode IvScannerModifier} + * @returns always `true` + */ + override apply(): boolean { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 3; } } export class ExtraModifierModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } @@ -2888,23 +3269,28 @@ export class ExtraModifierModifier extends PersistentModifier { return new ExtraModifierModifier(this.type, this.stackCount); } - apply(args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value += this.getStackCount(); + /** + * Applies {@linkcode ExtraModifierModifier} + * @param count {NumberHolder} holding the count value + * @returns always `true` + */ + override apply(count: NumberHolder): boolean { + count.value += this.getStackCount(); return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 3; } } export abstract class EnemyPersistentModifier extends PersistentModifier { - constructor(type: ModifierType, stackCount?: integer) { + constructor(type: ModifierType, stackCount?: number) { super(type, stackCount); } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 5; } } @@ -2912,25 +3298,30 @@ export abstract class EnemyPersistentModifier extends PersistentModifier { abstract class EnemyDamageMultiplierModifier extends EnemyPersistentModifier { protected damageMultiplier: number; - constructor(type: ModifierType, damageMultiplier: number, stackCount?: integer) { + constructor(type: ModifierType, damageMultiplier: number, stackCount?: number) { super(type, stackCount); this.damageMultiplier = damageMultiplier; } - apply(args: any[]): boolean { - (args[0] as Utils.NumberHolder).value = Math.floor((args[0] as Utils.NumberHolder).value * Math.pow(this.damageMultiplier, this.getStackCount())); + /** + * Applies {@linkcode EnemyDamageMultiplierModifier} + * @param multiplier {NumberHolder} holding the multiplier value + * @returns always `true` + */ + override apply(multiplier: NumberHolder): boolean { + multiplier.value = Math.floor(multiplier.value * Math.pow(this.damageMultiplier, this.getStackCount())); return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 99; } } export class EnemyDamageBoosterModifier extends EnemyDamageMultiplierModifier { - constructor(type: ModifierType, boostPercent: number, stackCount?: integer) { + constructor(type: ModifierType, boostPercent: number, stackCount?: number) { //super(type, 1 + ((boostPercent || 10) * 0.01), stackCount); super(type, 1.05, stackCount); // Hardcode multiplier temporarily } @@ -2947,13 +3338,13 @@ export class EnemyDamageBoosterModifier extends EnemyDamageMultiplierModifier { return [ (this.damageMultiplier - 1) * 100 ]; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 999; } } export class EnemyDamageReducerModifier extends EnemyDamageMultiplierModifier { - constructor(type: ModifierType, reductionPercent: number, stackCount?: integer) { + constructor(type: ModifierType, reductionPercent: number, stackCount?: number) { //super(type, 1 - ((reductionPercent || 5) * 0.01), stackCount); super(type, 0.975, stackCount); // Hardcode multiplier temporarily } @@ -2970,7 +3361,7 @@ export class EnemyDamageReducerModifier extends EnemyDamageMultiplierModifier { return [ (1 - this.damageMultiplier) * 100 ]; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return scene.currentBattle.waveIndex < 2000 ? super.getMaxStackCount(scene) : 999; } } @@ -2978,7 +3369,7 @@ export class EnemyDamageReducerModifier extends EnemyDamageMultiplierModifier { export class EnemyTurnHealModifier extends EnemyPersistentModifier { public healPercent: number; - constructor(type: ModifierType, healPercent: number, stackCount?: integer) { + constructor(type: ModifierType, healPercent: number, stackCount?: number) { super(type, stackCount); // Hardcode temporarily @@ -2997,20 +3388,23 @@ export class EnemyTurnHealModifier extends EnemyPersistentModifier { return [ this.healPercent ]; } - apply(args: any[]): boolean { - const pokemon = args[0] as Pokemon; - - if (!pokemon.isFullHp()) { - const scene = pokemon.scene; - scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.getBattlerIndex(), - Math.max(Math.floor(pokemon.getMaxHp() / (100 / this.healPercent)) * this.stackCount, 1), i18next.t("modifier:enemyTurnHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), true, false, false, false, true)); + /** + * Applies {@linkcode EnemyTurnHealModifier} + * @param enemyPokemon The {@linkcode Pokemon} to heal + * @returns `true` if the {@linkcode Pokemon} was healed + */ + override apply(enemyPokemon: Pokemon): boolean { + if (!enemyPokemon.isFullHp()) { + const scene = enemyPokemon.scene; + scene.unshiftPhase(new PokemonHealPhase(scene, enemyPokemon.getBattlerIndex(), + Math.max(Math.floor(enemyPokemon.getMaxHp() / (100 / this.healPercent)) * this.stackCount, 1), i18next.t("modifier:enemyTurnHealApply", { pokemonNameWithAffix: getPokemonNameWithAffix(enemyPokemon) }), true, false, false, false, true)); return true; } return false; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 10; } } @@ -3019,7 +3413,7 @@ export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModifi public effect: StatusEffect; public chance: number; - constructor(type: ModifierType, effect: StatusEffect, chancePercent: number, stackCount?: integer) { + constructor(type: ModifierType, effect: StatusEffect, chancePercent: number, stackCount?: number) { super(type, stackCount); this.effect = effect; @@ -3039,16 +3433,20 @@ export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModifi return [ this.effect, this.chance * 100 ]; } - apply(args: any[]): boolean { - const target = (args[0] as Pokemon); + /** + * Applies {@linkcode EnemyAttackStatusEffectChanceModifier} + * @param enemyPokemon {@linkcode Pokemon} to apply the status effect to + * @returns `true` if the {@linkcode Pokemon} was affected + */ + override apply(enemyPokemon: Pokemon): boolean { if (Phaser.Math.RND.realInRange(0, 1) < (this.chance * this.getStackCount())) { - return target.trySetStatus(this.effect, true); + return enemyPokemon.trySetStatus(this.effect, true); } return false; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 10; } } @@ -3056,7 +3454,7 @@ export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModifi export class EnemyStatusEffectHealChanceModifier extends EnemyPersistentModifier { public chance: number; - constructor(type: ModifierType, chancePercent: number, stackCount?: integer) { + constructor(type: ModifierType, chancePercent: number, stackCount?: number) { super(type, stackCount); //Hardcode temporarily @@ -3075,19 +3473,23 @@ export class EnemyStatusEffectHealChanceModifier extends EnemyPersistentModifier return [ this.chance * 100 ]; } - apply(args: any[]): boolean { - const target = (args[0] as Pokemon); - if (target.status && Phaser.Math.RND.realInRange(0, 1) < (this.chance * this.getStackCount())) { - target.scene.queueMessage(getStatusEffectHealText(target.status.effect, getPokemonNameWithAffix(target))); - target.resetStatus(); - target.updateInfo(); + /** + * Applies {@linkcode EnemyStatusEffectHealChanceModifier} + * @param enemyPokemon The {@linkcode Pokemon} to heal + * @returns `true` if the {@linkcode Pokemon} was healed + */ + override apply(enemyPokemon: Pokemon): boolean { + if (enemyPokemon.status && Phaser.Math.RND.realInRange(0, 1) < (this.chance * this.getStackCount())) { + enemyPokemon.scene.queueMessage(getStatusEffectHealText(enemyPokemon.status.effect, getPokemonNameWithAffix(enemyPokemon))); + enemyPokemon.resetStatus(); + enemyPokemon.updateInfo(); return true; } return false; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 10; } } @@ -3095,7 +3497,7 @@ export class EnemyStatusEffectHealChanceModifier extends EnemyPersistentModifier export class EnemyEndureChanceModifier extends EnemyPersistentModifier { public chance: number; - constructor(type: ModifierType, chancePercent?: number, stackCount?: integer) { + constructor(type: ModifierType, chancePercent?: number, stackCount?: number) { super(type, stackCount || 10); //Hardcode temporarily @@ -3114,9 +3516,12 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { return [ this.chance * 100 ]; } - apply(args: any[]): boolean { - const target = (args[0] as Pokemon); - + /** + * Applies {@linkcode EnemyEndureChanceModifier} + * @param target {@linkcode Pokemon} to apply the {@linkcode BattlerTagType.ENDURING} chance to + * @returns `true` if {@linkcode Pokemon} endured + */ + override apply(target: Pokemon): boolean { if (target.battleData.endured || Phaser.Math.RND.realInRange(0, 1) >= (this.chance * this.getStackCount())) { return false; } @@ -3128,7 +3533,7 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 10; } } @@ -3136,7 +3541,7 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier { export class EnemyFusionChanceModifier extends EnemyPersistentModifier { private chance: number; - constructor(type: ModifierType, chancePercent: number, stackCount?: integer) { + constructor(type: ModifierType, chancePercent: number, stackCount?: number) { super(type, stackCount); this.chance = chancePercent / 100; @@ -3154,17 +3559,22 @@ export class EnemyFusionChanceModifier extends EnemyPersistentModifier { return [ this.chance * 100 ]; } - apply(args: any[]): boolean { + /** + * Applies {@linkcode EnemyFusionChanceModifier} + * @param isFusion {@linkcode BooleanHolder} that will be set to `true` if the {@linkcode EnemyPokemon} is a fusion + * @returns `true` if the {@linkcode EnemyPokemon} is a fusion + */ + override apply(isFusion: BooleanHolder): boolean { if (Phaser.Math.RND.realInRange(0, 1) >= (this.chance * this.getStackCount())) { return false; } - (args[0] as Utils.BooleanHolder).value = true; + isFusion.value = true; return true; } - getMaxStackCount(scene: BattleScene): integer { + getMaxStackCount(scene: BattleScene): number { return 10; } } @@ -3177,7 +3587,7 @@ export class EnemyFusionChanceModifier extends EnemyPersistentModifier { * @param isPlayer {@linkcode boolean} for whether the player (`true`) or enemy (`false`) is being overridden */ export function overrideModifiers(scene: BattleScene, isPlayer: boolean = true): void { - const modifiersOverride: ModifierTypes.ModifierOverride[] = isPlayer ? Overrides.STARTING_MODIFIER_OVERRIDE : Overrides.OPP_MODIFIER_OVERRIDE; + const modifiersOverride: ModifierOverride[] = isPlayer ? Overrides.STARTING_MODIFIER_OVERRIDE : Overrides.OPP_MODIFIER_OVERRIDE; if (!modifiersOverride || modifiersOverride.length === 0 || !scene) { return; } @@ -3191,7 +3601,7 @@ export function overrideModifiers(scene: BattleScene, isPlayer: boolean = true): const modifierFunc = modifierTypes[item.name]; let modifierType: ModifierType | null = modifierFunc(); - if (modifierType instanceof ModifierTypes.ModifierTypeGenerator) { + if (modifierType instanceof ModifierTypeGenerator) { const pregenArgs = ("type" in item) && (item.type !== null) ? [item.type] : undefined; modifierType = modifierType.generateType([], pregenArgs); } @@ -3218,7 +3628,7 @@ export function overrideModifiers(scene: BattleScene, isPlayer: boolean = true): * @param isPlayer {@linkcode boolean} for whether the {@linkcode pokemon} is the player's (`true`) or an enemy (`false`) */ export function overrideHeldItems(scene: BattleScene, pokemon: Pokemon, isPlayer: boolean = true): void { - const heldItemsOverride: ModifierTypes.ModifierOverride[] = isPlayer ? Overrides.STARTING_HELD_ITEMS_OVERRIDE : Overrides.OPP_HELD_ITEMS_OVERRIDE; + const heldItemsOverride: ModifierOverride[] = isPlayer ? Overrides.STARTING_HELD_ITEMS_OVERRIDE : Overrides.OPP_HELD_ITEMS_OVERRIDE; if (!heldItemsOverride || heldItemsOverride.length === 0 || !scene) { return; } @@ -3232,7 +3642,7 @@ export function overrideHeldItems(scene: BattleScene, pokemon: Pokemon, isPlayer let modifierType: ModifierType | null = modifierFunc(); const qty = item.count || 1; - if (modifierType instanceof ModifierTypes.ModifierTypeGenerator) { + if (modifierType instanceof ModifierTypeGenerator) { const pregenArgs = ("type" in item) && (item.type !== null) ? [item.type] : undefined; modifierType = modifierType.generateType([], pregenArgs); } diff --git a/src/phases/battle-end-phase.ts b/src/phases/battle-end-phase.ts index eaa458af904..bae61aa2288 100644 --- a/src/phases/battle-end-phase.ts +++ b/src/phases/battle-end-phase.ts @@ -57,7 +57,7 @@ export class BattleEndPhase extends BattlePhase { if (m instanceof LapsingPokemonHeldItemModifier) { args.push(this.scene.getPokemonById(m.pokemonId)); } - if (!m.lapse(args)) { + if (!m.lapse(...args)) { this.scene.removeModifier(m); } } diff --git a/src/phases/berry-phase.ts b/src/phases/berry-phase.ts index 66ecaa6c7f8..e419aa6692d 100644 --- a/src/phases/berry-phase.ts +++ b/src/phases/berry-phase.ts @@ -15,7 +15,7 @@ export class BerryPhase extends FieldPhase { this.executeForAll((pokemon) => { const hasUsableBerry = !!this.scene.findModifier((m) => { - return m instanceof BerryModifier && m.shouldApply([pokemon]); + return m instanceof BerryModifier && m.shouldApply(pokemon); }, pokemon.isPlayer()); if (hasUsableBerry) { @@ -29,7 +29,7 @@ export class BerryPhase extends FieldPhase { new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM) ); - for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon) as BerryModifier[]) { + for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon)) { if (berryModifier.consumed) { if (!--berryModifier.stackCount) { this.scene.removeModifier(berryModifier);