[Refactor] Modifiers type inference v2 (#4294)

* refactor: apply Modifiers type inference (pattern)

Mirror from #1747

Co-authored-by: Dmitriy <kagno.dmitriy@gmail.com>

* 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 <kagno.dmitriy@gmail.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
flx-sta 2024-10-03 08:38:17 -07:00 committed by GitHub
parent ea9e0c7909
commit 54efd44497
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 1200 additions and 749 deletions

View File

@ -2445,7 +2445,10 @@ export default class BattleScene extends SceneBase {
} }
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual, this)) { if ((modifier as PersistentModifier).add(this.modifiers, !!virtual, this)) {
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { 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)) { if (playSound && !this.sound.get(soundName)) {
this.playSound(soundName); this.playSound(soundName);
@ -2472,7 +2475,7 @@ export default class BattleScene extends SceneBase {
for (const p in this.party) { for (const p in this.party) {
const pokemon = this.party[p]; const pokemon = this.party[p];
const args: any[] = [ pokemon ]; const args: unknown[] = [];
if (modifier instanceof PokemonHpRestoreModifier) { if (modifier instanceof PokemonHpRestoreModifier) {
if (!(modifier as PokemonHpRestoreModifier).fainted) { if (!(modifier as PokemonHpRestoreModifier).fainted) {
const hpRestoreMultiplier = new Utils.IntegerHolder(1); const hpRestoreMultiplier = new Utils.IntegerHolder(1);
@ -2485,8 +2488,8 @@ export default class BattleScene extends SceneBase {
args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon); args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon);
} }
if (modifier.shouldApply(args)) { if (modifier.shouldApply(pokemon, ...args)) {
const result = modifier.apply(args); const result = modifier.apply(pokemon, ...args);
if (result instanceof Promise) { if (result instanceof Promise) {
modifierPromises.push(result.then(s => success ||= s)); modifierPromises.push(result.then(s => success ||= s));
} else { } 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)); return Promise.allSettled([this.party.map(p => p.updateInfo(instant)), ...modifierPromises]).then(() => resolve(success));
} else { } else {
const args = [ this ]; const args = [ this ];
if (modifier.shouldApply(args)) { if (modifier.shouldApply(...args)) {
const result = modifier.apply(args); const result = modifier.apply(...args);
if (result instanceof Promise) { if (result instanceof Promise) {
return result.then(success => resolve(success)); return result.then(success => resolve(success));
} else { } else {
@ -2521,7 +2524,10 @@ export default class BattleScene extends SceneBase {
} }
if ((modifier as PersistentModifier).add(this.enemyModifiers, false, this)) { if ((modifier as PersistentModifier).add(this.enemyModifiers, false, this)) {
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { 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) { for (const rm of modifiersToRemove) {
this.removeModifier(rm, true); this.removeModifier(rm, true);
@ -2755,7 +2761,10 @@ export default class BattleScene extends SceneBase {
if (modifierIndex > -1) { if (modifierIndex > -1) {
modifiers.splice(modifierIndex, 1); modifiers.splice(modifierIndex, 1);
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier) { 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; 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); 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 { 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<Modifier>, 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<T extends PersistentModifier>(scene: BattleScene, modifierType: Constructor<T>, player: boolean = true, ...args: Parameters<T["apply"]>): T[] {
let modifiers = (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType && m.shouldApply(...args));
scene.executeWithSeedOffset(() => { scene.executeWithSeedOffset(() => {
const shuffleModifiers = mods => { const shuffleModifiers = mods => {
if (mods.length < 1) { if (mods.length < 1) {
@ -2796,15 +2825,23 @@ export default class BattleScene extends SceneBase {
return this.applyModifiersInternal(modifiers, player, args); return this.applyModifiersInternal(modifiers, player, args);
} }
applyModifiers(modifierType: Constructor<Modifier>, 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<T extends PersistentModifier>(modifierType: Constructor<T>, player: boolean = true, ...args: Parameters<T["apply"]>): 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); return this.applyModifiersInternal(modifiers, player, args);
} }
applyModifiersInternal(modifiers: PersistentModifier[], player: boolean, args: any[]): PersistentModifier[] { /** Helper function to apply all passed modifiers */
const appliedModifiers: PersistentModifier[] = []; applyModifiersInternal<T extends PersistentModifier>(modifiers: T[], player: boolean, args: Parameters<T["apply"]>): T[] {
const appliedModifiers: T[] = [];
for (const modifier of modifiers) { for (const modifier of modifiers) {
if (modifier.apply(args)) { if (modifier.apply(...args)) {
console.log("Applied", modifier.type.name, !player ? "(enemy)" : ""); console.log("Applied", modifier.type.name, !player ? "(enemy)" : "");
appliedModifiers.push(modifier); appliedModifiers.push(modifier);
} }
@ -2813,10 +2850,17 @@ export default class BattleScene extends SceneBase {
return appliedModifiers; return appliedModifiers;
} }
applyModifier(modifierType: Constructor<Modifier>, 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<T extends PersistentModifier>(modifierType: Constructor<T>, player: boolean = true, ...args: Parameters<T["apply"]>): 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) { for (const modifier of modifiers) {
if (modifier.apply(args)) { if (modifier.apply(...args)) {
console.log("Applied", modifier.type.name, !player ? "(enemy)" : ""); console.log("Applied", modifier.type.name, !player ? "(enemy)" : "");
return modifier; 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)) { if (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) && achv.validate(this, args)) {
this.gameData.achvUnlocks[achv.id] = new Date().getTime(); this.gameData.achvUnlocks[achv.id] = new Date().getTime();
this.ui.achvBar.showAchv(achv); this.ui.achvBar.showAchv(achv);
@ -2895,7 +2939,7 @@ export default class BattleScene extends SceneBase {
return false; 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)) { if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(this, args)) {
this.gameData.voucherUnlocks[voucher.id] = new Date().getTime(); this.gameData.voucherUnlocks[voucher.id] = new Date().getTime();
this.ui.achvBar.showAchv(voucher); this.ui.achvBar.showAchv(voucher);

View File

@ -1,38 +1,35 @@
import * as Modifiers from "#app/modifier/modifier"; import BattleScene from "#app/battle-scene";
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 { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import { tmPoolTiers, tmSpecies } from "#app/data/balance/tms"; 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 { getBerryEffectDescription, getBerryName } from "#app/data/berry";
import { Unlockables } from "#app/system/unlockables"; import { allMoves, AttackMove, selfStatLowerMoves } from "#app/data/move";
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 { getNatureName, getNatureStatMultiplier, Nature } from "#app/data/nature"; import { getNatureName, getNatureStatMultiplier, Nature } from "#app/data/nature";
import i18next from "i18next"; import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS, PokeballType } from "#app/data/pokeball";
import { getModifierTierTextTint } from "#app/ui/text"; 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 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 { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; 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 { 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 outputModifierData = false;
const useMaxWeightForOutput = false; const useMaxWeightForOutput = false;
type Modifier = Modifiers.Modifier;
export enum ModifierPoolType { export enum ModifierPoolType {
PLAYER, PLAYER,
WILD, WILD,
@ -97,7 +94,7 @@ export class ModifierType {
// Try multiple pool types in case of stolen items // Try multiple pool types in case of stolen items
for (const type of poolTypes) { for (const type of poolTypes) {
const pool = getModifierPoolForType(type); const pool = getModifierPoolForType(type);
for (const tier of Utils.getEnumValues(ModifierTier)) { for (const tier of getEnumValues(ModifierTier)) {
if (!pool.hasOwnProperty(tier)) { if (!pool.hasOwnProperty(tier)) {
continue; continue;
} }
@ -171,7 +168,7 @@ class AddPokeballModifierType extends ModifierType {
private count: integer; private count: integer;
constructor(iconImage: string, pokeballType: PokeballType, 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.pokeballType = pokeballType;
this.count = count; this.count = count;
} }
@ -198,7 +195,7 @@ class AddVoucherModifierType extends ModifierType {
private count: integer; private count: integer;
constructor(voucherType: VoucherType, 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.count = count;
this.voucherType = voucherType; this.voucherType = voucherType;
} }
@ -232,7 +229,7 @@ export class PokemonHeldItemModifierType extends PokemonModifierType {
constructor(localeKey: string, iconImage: string, newModifierFunc: NewModifierFunc, group?: string, soundName?: string) { constructor(localeKey: string, iconImage: string, newModifierFunc: NewModifierFunc, group?: string, soundName?: string) {
super(localeKey, iconImage, newModifierFunc, (pokemon: PlayerPokemon) => { super(localeKey, iconImage, newModifierFunc, (pokemon: PlayerPokemon) => {
const dummyModifier = this.newModifier(pokemon); 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); const maxStackCount = dummyModifier.getMaxStackCount(pokemon.scene);
if (!maxStackCount) { if (!maxStackCount) {
return i18next.t("modifierType:ModifierType.PokemonHeldItemModifierType.extra.inoperable", { "pokemonName": getPokemonNameWithAffix(pokemon) }); return i18next.t("modifierType:ModifierType.PokemonHeldItemModifierType.extra.inoperable", { "pokemonName": getPokemonNameWithAffix(pokemon) });
@ -244,8 +241,8 @@ export class PokemonHeldItemModifierType extends PokemonModifierType {
}, group, soundName); }, group, soundName);
} }
newModifier(...args: any[]): Modifiers.PokemonHeldItemModifier { newModifier(...args: any[]): PokemonHeldItemModifier {
return super.newModifier(...args) as Modifiers.PokemonHeldItemModifier; return super.newModifier(...args) as PokemonHeldItemModifier;
} }
} }
@ -255,7 +252,7 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType {
protected healStatus: boolean; protected healStatus: boolean;
constructor(localeKey: string, iconImage: string, restorePoints: integer, restorePercent: integer, healStatus: boolean = false, newModifierFunc?: NewModifierFunc, selectFilter?: PokemonSelectFilter, group?: string) { 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) => { selectFilter || ((pokemon: PlayerPokemon) => {
if (!pokemon.hp || (pokemon.isFullHp() && (!this.healStatus || (!pokemon.status && !pokemon.getTag(BattlerTagType.CONFUSED))))) { if (!pokemon.hp || (pokemon.isFullHp() && (!this.healStatus || (!pokemon.status && !pokemon.getTag(BattlerTagType.CONFUSED))))) {
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -282,7 +279,7 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType {
export class PokemonReviveModifierType extends PokemonHpRestoreModifierType { export class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
constructor(localeKey: string, iconImage: string, restorePercent: integer) { 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) => { ((pokemon: PlayerPokemon) => {
if (!pokemon.isFainted()) { if (!pokemon.isFainted()) {
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -305,7 +302,7 @@ export class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
export class PokemonStatusHealModifierType extends PokemonModifierType { export class PokemonStatusHealModifierType extends PokemonModifierType {
constructor(localeKey: string, iconImage: string) { 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) => { ((pokemon: PlayerPokemon) => {
if (!pokemon.hp || (!pokemon.status && !pokemon.getTag(BattlerTagType.CONFUSED))) { if (!pokemon.hp || (!pokemon.status && !pokemon.getTag(BattlerTagType.CONFUSED))) {
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -333,7 +330,7 @@ export class PokemonPpRestoreModifierType extends PokemonMoveModifierType {
protected restorePoints: integer; protected restorePoints: integer;
constructor(localeKey: string, iconImage: string, 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) => { (_pokemon: PlayerPokemon) => {
return null; return null;
}, (pokemonMove: PokemonMove) => { }, (pokemonMove: PokemonMove) => {
@ -358,7 +355,7 @@ export class PokemonAllMovePpRestoreModifierType extends PokemonModifierType {
protected restorePoints: integer; protected restorePoints: integer;
constructor(localeKey: string, iconImage: string, 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) => { (pokemon: PlayerPokemon) => {
if (!pokemon.getMoveset().filter(m => m?.ppUsed).length) { if (!pokemon.getMoveset().filter(m => m?.ppUsed).length) {
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -381,7 +378,7 @@ export class PokemonPpUpModifierType extends PokemonMoveModifierType {
protected upPoints: integer; protected upPoints: integer;
constructor(localeKey: string, iconImage: string, 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) => { (_pokemon: PlayerPokemon) => {
return null; return null;
}, (pokemonMove: PokemonMove) => { }, (pokemonMove: PokemonMove) => {
@ -403,7 +400,7 @@ export class PokemonNatureChangeModifierType extends PokemonModifierType {
protected nature: Nature; protected nature: Nature;
constructor(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) => { ((pokemon: PlayerPokemon) => {
if (pokemon.getNature() === this.nature) { if (pokemon.getNature() === this.nature) {
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -425,7 +422,7 @@ export class PokemonNatureChangeModifierType extends PokemonModifierType {
export class RememberMoveModifierType extends PokemonModifierType { export class RememberMoveModifierType extends PokemonModifierType {
constructor(localeKey: string, iconImage: string, group?: string) { 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) => { (pokemon: PlayerPokemon) => {
if (!pokemon.getLearnableLevelMoves().length) { if (!pokemon.getLearnableLevelMoves().length) {
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -439,7 +436,7 @@ export class DoubleBattleChanceBoosterModifierType extends ModifierType {
private maxBattles: number; private maxBattles: number;
constructor(localeKey: string, iconImage: string, 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; this.maxBattles = maxBattles;
} }
@ -458,7 +455,7 @@ export class TempStatStageBoosterModifierType extends ModifierType implements Ge
constructor(stat: TempBattleStat) { constructor(stat: TempBattleStat) {
const nameKey = TempStatStageBoosterModifierTypeGenerator.items[stat]; 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.stat = stat;
this.nameKey = nameKey; this.nameKey = nameKey;
@ -485,7 +482,7 @@ export class BerryModifierType extends PokemonHeldItemModifierType implements Ge
private berryType: BerryType; private berryType: BerryType;
constructor(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; this.berryType = berryType;
} }
@ -550,7 +547,7 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i
constructor(moveType: Type, boostPercent: integer) { constructor(moveType: Type, boostPercent: integer) {
super("", `${getAttackTypeBoosterItemName(moveType)?.replace(/[ \-]/g, "_").toLowerCase()}`, 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.moveType = moveType;
this.boostPercent = boostPercent; this.boostPercent = boostPercent;
@ -573,7 +570,7 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i
export type SpeciesStatBoosterItem = keyof typeof SpeciesStatBoosterModifierTypeGenerator.items; export type SpeciesStatBoosterItem = keyof typeof SpeciesStatBoosterModifierTypeGenerator.items;
/** /**
* Modifier type for {@linkcode Modifiers.SpeciesStatBoosterModifier} * Modifier type for {@linkcode SpeciesStatBoosterModifier}
* @extends PokemonHeldItemModifierType * @extends PokemonHeldItemModifierType
* @implements GeneratedPersistentModifierType * @implements GeneratedPersistentModifierType
*/ */
@ -582,7 +579,7 @@ export class SpeciesStatBoosterModifierType extends PokemonHeldItemModifierType
constructor(key: SpeciesStatBoosterItem) { constructor(key: SpeciesStatBoosterItem) {
const item = SpeciesStatBoosterModifierTypeGenerator.items[key]; 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; this.key = key;
} }
@ -594,12 +591,12 @@ export class SpeciesStatBoosterModifierType extends PokemonHeldItemModifierType
export class PokemonLevelIncrementModifierType extends PokemonModifierType { export class PokemonLevelIncrementModifierType extends PokemonModifierType {
constructor(localeKey: string, iconImage: string) { 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 { getDescription(scene: BattleScene): string {
let levels = 1; let levels = 1;
const hasCandyJar = scene.modifiers.find(modifier => modifier instanceof Modifiers.LevelIncrementBoosterModifier); const hasCandyJar = scene.modifiers.find(modifier => modifier instanceof LevelIncrementBoosterModifier);
if (hasCandyJar) { if (hasCandyJar) {
levels += hasCandyJar.stackCount; levels += hasCandyJar.stackCount;
} }
@ -609,12 +606,12 @@ export class PokemonLevelIncrementModifierType extends PokemonModifierType {
export class AllPokemonLevelIncrementModifierType extends ModifierType { export class AllPokemonLevelIncrementModifierType extends ModifierType {
constructor(localeKey: string, iconImage: string) { 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 { getDescription(scene: BattleScene): string {
let levels = 1; let levels = 1;
const hasCandyJar = scene.modifiers.find(modifier => modifier instanceof Modifiers.LevelIncrementBoosterModifier); const hasCandyJar = scene.modifiers.find(modifier => modifier instanceof LevelIncrementBoosterModifier);
if (hasCandyJar) { if (hasCandyJar) {
levels += hasCandyJar.stackCount; levels += hasCandyJar.stackCount;
} }
@ -628,7 +625,7 @@ export class BaseStatBoosterModifierType extends PokemonHeldItemModifierType imp
constructor(stat: PermanentStat) { constructor(stat: PermanentStat) {
const key = BaseStatBoosterModifierTypeGenerator.items[stat]; 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.stat = stat;
this.key = key; this.key = key;
@ -654,7 +651,7 @@ export class PokemonBaseStatTotalModifierType extends PokemonHeldItemModifierTyp
private readonly statModifier: integer; private readonly statModifier: integer;
constructor(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; this.statModifier = statModifier;
} }
@ -679,7 +676,7 @@ export class PokemonBaseStatFlatModifierType extends PokemonHeldItemModifierType
private readonly stats: Stat[]; private readonly stats: Stat[];
constructor(statModifier: integer, 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.statModifier = statModifier;
this.stats = stats; this.stats = stats;
} }
@ -700,7 +697,7 @@ class AllPokemonFullHpRestoreModifierType extends ModifierType {
private descriptionKey: string; private descriptionKey: string;
constructor(localeKey: string, iconImage: string, descriptionKey?: string, newModifierFunc?: NewModifierFunc) { 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? this.descriptionKey = descriptionKey!; // TODO: is this bang correct?
} }
@ -712,7 +709,7 @@ class AllPokemonFullHpRestoreModifierType extends ModifierType {
class AllPokemonFullReviveModifierType extends AllPokemonFullHpRestoreModifierType { class AllPokemonFullReviveModifierType extends AllPokemonFullHpRestoreModifierType {
constructor(localeKey: string, iconImage: string) { 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; private moneyMultiplierDescriptorKey: string;
constructor(localeKey: string, iconImage: string, moneyMultiplier: number, 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.moneyMultiplier = moneyMultiplier;
this.moneyMultiplierDescriptorKey = moneyMultiplierDescriptorKey; this.moneyMultiplierDescriptorKey = moneyMultiplierDescriptorKey;
} }
getDescription(scene: BattleScene): string { 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); 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", { return i18next.t("modifierType:ModifierType.MoneyRewardModifierType.description", {
moneyMultiplier: i18next.t(this.moneyMultiplierDescriptorKey as any), moneyMultiplier: i18next.t(this.moneyMultiplierDescriptorKey as any),
@ -743,7 +740,7 @@ export class ExpBoosterModifierType extends ModifierType {
private boostPercent: integer; private boostPercent: integer;
constructor(localeKey: string, iconImage: string, 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; this.boostPercent = boostPercent;
} }
@ -757,7 +754,7 @@ export class PokemonExpBoosterModifierType extends PokemonHeldItemModifierType {
private boostPercent: integer; private boostPercent: integer;
constructor(localeKey: string, iconImage: string, 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; this.boostPercent = boostPercent;
} }
@ -769,7 +766,7 @@ export class PokemonExpBoosterModifierType extends PokemonHeldItemModifierType {
export class PokemonFriendshipBoosterModifierType extends PokemonHeldItemModifierType { export class PokemonFriendshipBoosterModifierType extends PokemonHeldItemModifierType {
constructor(localeKey: string, iconImage: string) { 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 { getDescription(scene: BattleScene): string {
@ -781,7 +778,7 @@ export class PokemonMoveAccuracyBoosterModifierType extends PokemonHeldItemModif
private amount: integer; private amount: integer;
constructor(localeKey: string, iconImage: string, amount: integer, group?: string, soundName?: string) { 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; this.amount = amount;
} }
@ -793,7 +790,7 @@ export class PokemonMoveAccuracyBoosterModifierType extends PokemonHeldItemModif
export class PokemonMultiHitModifierType extends PokemonHeldItemModifierType { export class PokemonMultiHitModifierType extends PokemonHeldItemModifierType {
constructor(localeKey: string, iconImage: string) { 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 { getDescription(scene: BattleScene): string {
@ -805,7 +802,7 @@ export class TmModifierType extends PokemonModifierType {
public moveId: Moves; public moveId: Moves;
constructor(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) => { (pokemon: PlayerPokemon) => {
if (pokemon.compatibleTms.indexOf(moveId) === -1 || pokemon.getMoveset().filter(m => m?.moveId === moveId).length) { if (pokemon.compatibleTms.indexOf(moveId) === -1 || pokemon.getMoveset().filter(m => m?.moveId === moveId).length) {
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -818,7 +815,7 @@ export class TmModifierType extends PokemonModifierType {
get name(): string { get name(): string {
return i18next.t("modifierType:ModifierType.TmModifierType.name", { 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, moveName: allMoves[this.moveId].name,
}); });
} }
@ -832,7 +829,7 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge
public evolutionItem: EvolutionItem; public evolutionItem: EvolutionItem;
constructor(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) => { (pokemon: PlayerPokemon) => {
if (pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.item === this.evolutionItem 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)) { && (!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; public formChangeItem: FormChangeItem;
constructor(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) => { (pokemon: PlayerPokemon) => {
// Make sure the Pokemon has alternate forms // Make sure the Pokemon has alternate forms
if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) if (pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId)
@ -902,7 +899,7 @@ export class FormChangeItemModifierType extends PokemonModifierType implements G
export class FusePokemonModifierType extends PokemonModifierType { export class FusePokemonModifierType extends PokemonModifierType {
constructor(localeKey: string, iconImage: string) { 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) => { (pokemon: PlayerPokemon) => {
if (pokemon.isFusion()) { if (pokemon.isFusion()) {
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -949,7 +946,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator {
let type: Type; let type: Type;
const randInt = Utils.randSeedInt(totalWeight); const randInt = randSeedInt(totalWeight);
let weight = 0; let weight = 0;
for (const t of attackMoveTypeWeights.keys()) { for (const t of attackMoveTypeWeights.keys()) {
@ -981,7 +978,7 @@ class BaseStatBoosterModifierTypeGenerator extends ModifierTypeGenerator {
if (pregenArgs) { if (pregenArgs) {
return new BaseStatBoosterModifierType(pregenArgs[0]); return new BaseStatBoosterModifierType(pregenArgs[0]);
} }
const randStat: PermanentStat = Utils.randSeedInt(Stat.SPD + 1); const randStat: PermanentStat = randSeedInt(Stat.SPD + 1);
return new BaseStatBoosterModifierType(randStat); return new BaseStatBoosterModifierType(randStat);
}); });
} }
@ -1002,7 +999,7 @@ class TempStatStageBoosterModifierTypeGenerator extends ModifierTypeGenerator {
if (pregenArgs && (pregenArgs.length === 1) && TEMP_BATTLE_STATS.includes(pregenArgs[0])) { if (pregenArgs && (pregenArgs.length === 1) && TEMP_BATTLE_STATS.includes(pregenArgs[0])) {
return new TempStatStageBoosterModifierType(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); return new TempStatStageBoosterModifierType(randStat);
}); });
} }
@ -1044,8 +1041,8 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator {
const checkedStats = values[i].stats; const checkedStats = values[i].stats;
// If party member already has the item being weighted currently, skip to the next item // 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 const hasItem = p.getHeldItems().some(m => m instanceof SpeciesStatBoosterModifier
&& (m as Modifiers.SpeciesStatBoosterModifier).contains(checkedSpecies[0], checkedStats[0])); && (m as SpeciesStatBoosterModifier).contains(checkedSpecies[0], checkedStats[0]));
if (!hasItem) { if (!hasItem) {
if (checkedSpecies.includes(speciesId) || (!!fusionSpeciesId && checkedSpecies.includes(fusionSpeciesId))) { if (checkedSpecies.includes(speciesId) || (!!fusionSpeciesId && checkedSpecies.includes(fusionSpeciesId))) {
@ -1065,7 +1062,7 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator {
} }
if (totalWeight !== 0) { if (totalWeight !== 0) {
const randInt = Utils.randSeedInt(totalWeight, 1); const randInt = randSeedInt(totalWeight, 1);
let weight = 0; let weight = 0;
for (const i in weights) { for (const i in weights) {
@ -1095,7 +1092,7 @@ class TmModifierTypeGenerator extends ModifierTypeGenerator {
if (!tierUniqueCompatibleTms.length) { if (!tierUniqueCompatibleTms.length) {
return null; return null;
} }
const randTmIndex = Utils.randSeedInt(tierUniqueCompatibleTms.length); const randTmIndex = randSeedInt(tierUniqueCompatibleTms.length);
return new TmModifierType(tierUniqueCompatibleTms[randTmIndex]); return new TmModifierType(tierUniqueCompatibleTms[randTmIndex]);
}); });
} }
@ -1123,7 +1120,7 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator {
return null; 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 formChangeItemPool = [...new Set(party.filter(p => pokemonFormChanges.hasOwnProperty(p.species.speciesId)).map(p => {
const formChanges = pokemonFormChanges[p.species.speciesId]; 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) 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(Modifiers.GigantamaxAccessModifier).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.conditions.length || fc.conditions.filter(cond => cond instanceof SpeciesFormChangeCondition && cond.predicate(p)).length)
&& (fc.preFormKey === p.getFormKey())) && (fc.preFormKey === p.getFormKey()))
.map(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger) .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) { 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... // 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 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; private teraType: Type;
constructor(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; this.teraType = teraType;
} }
@ -1208,7 +1205,7 @@ export class ContactHeldItemTransferChanceModifierType extends PokemonHeldItemMo
private chancePercent: integer; private chancePercent: integer;
constructor(localeKey: string, iconImage: string, chancePercent: integer, group?: string, soundName?: string) { 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; this.chancePercent = chancePercent;
} }
@ -1220,7 +1217,7 @@ export class ContactHeldItemTransferChanceModifierType extends PokemonHeldItemMo
export class TurnHeldItemTransferModifierType extends PokemonHeldItemModifierType { export class TurnHeldItemTransferModifierType extends PokemonHeldItemModifierType {
constructor(localeKey: string, iconImage: string, group?: string, soundName?: string) { 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 { getDescription(scene: BattleScene): string {
@ -1233,7 +1230,7 @@ export class EnemyAttackStatusEffectChanceModifierType extends ModifierType {
private effect: StatusEffect; private effect: StatusEffect;
constructor(localeKey: string, iconImage: string, chancePercent: integer, effect: StatusEffect, stackCount?: integer) { 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.chancePercent = chancePercent;
this.effect = effect; this.effect = effect;
@ -1251,7 +1248,7 @@ export class EnemyEndureChanceModifierType extends ModifierType {
private chancePercent: number; private chancePercent: number;
constructor(localeKey: string, iconImage: string, 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; this.chancePercent = chancePercent;
} }
@ -1298,7 +1295,7 @@ function skipInLastClassicWaveOrDefault(defaultWeight: integer) : WeightedModifi
*/ */
function lureWeightFunc(maxBattles: number, weight: number): WeightedModifierTypeWeightFunc { function lureWeightFunc(maxBattles: number, weight: number): WeightedModifierTypeWeightFunc {
return (party: Pokemon[]) => { 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; 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), RARE_FORM_CHANGE_ITEM: () => new FormChangeItemModifierTypeGenerator(true),
EVOLUTION_TRACKER_GIMMIGHOUL: () => new PokemonHeldItemModifierType("modifierType:ModifierType.EVOLUTION_TRACKER_GIMMIGHOUL", "relic_gold", 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)), 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 Modifiers.GigantamaxAccessModifier(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 Modifiers.TerastallizeAccessModifier(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), POTION: () => new PokemonHpRestoreModifierType("modifierType:ModifierType.POTION", "potion", 20, 10),
SUPER_POTION: () => new PokemonHpRestoreModifierType("modifierType:ModifierType.SUPER_POTION", "super_potion", 50, 25), 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"), 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)), 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 Modifiers.ResetNegativeStatStageModifier(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), ETHER: () => new PokemonPpRestoreModifierType("modifierType:ModifierType.ETHER", "ether", 10),
MAX_ETHER: () => new PokemonPpRestoreModifierType("modifierType:ModifierType.MAX_ETHER", "max_ether", -1), 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") 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(), BASE_STAT_BOOSTER: () => new BaseStatBoosterModifierTypeGenerator(),
@ -1450,22 +1447,22 @@ export const modifierTypes = {
if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in Nature)) { if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in Nature)) {
return new PokemonNatureChangeModifierType(pregenArgs[0] as 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[]) => { TERA_SHARD: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in Type)) { if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in Type)) {
return new TerastallizeModifierType(pregenArgs[0] as 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; return null;
} }
let type: Type; let type: Type;
if (!Utils.randSeedInt(3)) { if (!randSeedInt(3)) {
const partyMemberTypes = party.map(p => p.getTypes(false, false, true)).flat(); const partyMemberTypes = party.map(p => p.getTypes(false, false, true)).flat();
type = Utils.randSeedItem(partyMemberTypes); type = randSeedItem(partyMemberTypes);
} else { } 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); return new TerastallizeModifierType(type);
}), }),
@ -1474,9 +1471,9 @@ export const modifierTypes = {
if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in BerryType)) { if (pregenArgs && (pregenArgs.length === 1) && (pregenArgs[0] in BerryType)) {
return new BerryModifierType(pregenArgs[0] as BerryType); return new BerryModifierType(pregenArgs[0] as BerryType);
} }
const berryTypes = Utils.getEnumValues(BerryType); const berryTypes = getEnumValues(BerryType);
let randBerryType: BerryType; let randBerryType: BerryType;
const rand = Utils.randSeedInt(12); const rand = randSeedInt(12);
if (rand < 2) { if (rand < 2) {
randBerryType = BerryType.SITRUS; randBerryType = BerryType.SITRUS;
} else if (rand < 4) { } else if (rand < 4) {
@ -1484,7 +1481,7 @@ export const modifierTypes = {
} else if (rand < 6) { } else if (rand < 6) {
randBerryType = BerryType.LEPPA; randBerryType = BerryType.LEPPA;
} else { } else {
randBerryType = berryTypes[Utils.randSeedInt(berryTypes.length - 3) + 2]; randBerryType = berryTypes[randSeedInt(berryTypes.length - 3) + 2];
} }
return new BerryModifierType(randBerryType); return new BerryModifierType(randBerryType);
}), }),
@ -1495,10 +1492,10 @@ export const modifierTypes = {
MEMORY_MUSHROOM: () => new RememberMoveModifierType("modifierType:ModifierType.MEMORY_MUSHROOM", "big_mushroom"), 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_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 Modifiers.ExpBalanceModifier(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), 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), 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"), 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)), 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 Modifiers.SpeciesCritBoosterModifier(type, (args[0] as Pokemon).id, 2, [Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD])), 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"), 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"), 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"), 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)), 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 Modifiers.DamageMoneyRewardModifier(type, (args[0] as Pokemon).id)), 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 Modifiers.MoneyInterestModifier(type)), 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), GRIP_CLAW: () => new ContactHeldItemTransferChanceModifierType("modifierType:ModifierType.GRIP_CLAW", "grip_claw", 10),
WIDE_LENS: () => new PokemonMoveAccuracyBoosterModifierType("modifierType:ModifierType.WIDE_LENS", "wide_lens", 5), WIDE_LENS: () => new PokemonMoveAccuracyBoosterModifierType("modifierType:ModifierType.WIDE_LENS", "wide_lens", 5),
MULTI_LENS: () => new PokemonMultiHitModifierType("modifierType:ModifierType.MULTI_LENS", "zoom_lens"), 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)), 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 Modifiers.LevelIncrementBoosterModifier(type)), 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)), 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 Modifiers.HitHealModifier(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)), 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 Modifiers.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)), 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 Modifiers.HiddenAbilityRateBoosterModifier(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"), 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_PLUS: () => new AddVoucherModifierType(VoucherType.PLUS, 1),
VOUCHER_PREMIUM: () => new AddVoucherModifierType(VoucherType.PREMIUM, 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_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 Modifiers.EnemyDamageReducerModifier(type, 2.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 Modifiers.EnemySuperEffectiveDamageBoosterModifier(type, 30), 'wl_custom_super_effective'), //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 Modifiers.EnemyTurnHealModifier(type, 2, 10)), 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_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_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_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_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[]) => { MYSTERY_ENCOUNTER_SHUCKLE_JUICE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
if (pregenArgs) { if (pregenArgs) {
return new PokemonBaseStatTotalModifierType(pregenArgs[0] as number); 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[]) => { MYSTERY_ENCOUNTER_OLD_GATEAU: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
if (pregenArgs) { if (pregenArgs) {
return new PokemonBaseStatFlatModifierType(pregenArgs[0] as number, pregenArgs[1] as Stat[]); 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[]) => { MYSTERY_ENCOUNTER_BLACK_SLUDGE: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => {
if (pregenArgs) { 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_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 Modifiers.BoostBugSpawnModifier(type)), MYSTERY_ENCOUNTER_GOLDEN_BUG_NET: () => new ModifierType("modifierType:ModifierType.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET", "golden_net", (type, _args) => new BoostBugSpawnModifier(type)),
}; };
interface ModifierPool { interface ModifierPool {
@ -1644,8 +1641,8 @@ const modifierPool: ModifierPool = {
new WeightedModifierType(modifierTypes.PP_UP, 2), new WeightedModifierType(modifierTypes.PP_UP, 2),
new WeightedModifierType(modifierTypes.FULL_HEAL, (party: Pokemon[]) => { new WeightedModifierType(modifierTypes.FULL_HEAL, (party: Pokemon[]) => {
const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => { const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => {
if (i instanceof Modifiers.TurnStatusEffectModifier) { if (i instanceof TurnStatusEffectModifier) {
return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status?.effect; return (i as TurnStatusEffectModifier).getStatusEffect() === p.status?.effect;
} }
return false; return false;
})).length, 3); })).length, 3);
@ -1672,8 +1669,8 @@ const modifierPool: ModifierPool = {
}, 3), }, 3),
new WeightedModifierType(modifierTypes.FULL_RESTORE, (party: Pokemon[]) => { new WeightedModifierType(modifierTypes.FULL_RESTORE, (party: Pokemon[]) => {
const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => { const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => {
if (i instanceof Modifiers.TurnStatusEffectModifier) { if (i instanceof TurnStatusEffectModifier) {
return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status?.effect; return (i as TurnStatusEffectModifier).getStatusEffect() === p.status?.effect;
} }
return false; return false;
})).length, 3); })).length, 3);
@ -1723,7 +1720,7 @@ const modifierPool: ModifierPool = {
const { gameMode, gameData } = party[0].scene; const { gameMode, gameData } = party[0].scene;
if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) { 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))) 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; return 0;
}), }),
@ -1731,7 +1728,7 @@ const modifierPool: ModifierPool = {
new WeightedModifierType(modifierTypes.LEEK, (party: Pokemon[]) => { new WeightedModifierType(modifierTypes.LEEK, (party: Pokemon[]) => {
const checkedSpecies = [ Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD ]; 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 // 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) && (checkedSpecies.includes(p.getSpeciesForm(true).speciesId)
|| (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId)))) ? 12 : 0; || (p.isFusion() && checkedSpecies.includes(p.getFusionSpeciesForm(true).speciesId)))) ? 12 : 0;
}, 12), }, 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 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]; 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 // 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)) && (checkedAbilities.some(a => p.hasAbility(a, false, true))
|| p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0; || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0;
}, 10), }, 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 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]; 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 // 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; && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0;
}, 10), }, 10),
new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => { new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => {
const checkedAbilities = [Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT]; const checkedAbilities = [Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT];
const weightMultiplier = party.filter( 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; (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 // 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); 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(); 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; let tierStackCount: number;
switch (tier) { switch (tier) {
case ModifierTier.ULTRA: case ModifierTier.ULTRA:
@ -2263,30 +2260,30 @@ export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers:
const retryCount = 50; const retryCount = 50;
let candidate = getNewModifierTypeOption([], ModifierPoolType.ENEMY_BUFF, tier); let candidate = getNewModifierTypeOption([], ModifierPoolType.ENEMY_BUFF, tier);
let r = 0; 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)) { 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); candidate = getNewModifierTypeOption([], ModifierPoolType.ENEMY_BUFF, tier);
} }
const modifier = candidate?.type?.newModifier() as Modifiers.EnemyPersistentModifier; const modifier = candidate?.type?.newModifier() as EnemyPersistentModifier;
modifier.stackCount = tierStackCount; modifier.stackCount = tierStackCount;
return modifier; return modifier;
} }
export function getEnemyModifierTypesForWave(waveIndex: integer, count: integer, party: EnemyPokemon[], poolType: ModifierPoolType.WILD | ModifierPoolType.TRAINER, upgradeChance: integer = 0): PokemonHeldItemModifierType[] { 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)) { if (!(waveIndex % 1000)) {
ret.push(getModifierType(modifierTypes.MINI_BLACK_HOLE) as PokemonHeldItemModifierType); ret.push(getModifierType(modifierTypes.MINI_BLACK_HOLE) as PokemonHeldItemModifierType);
} }
return ret; return ret;
} }
export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.PokemonHeldItemModifier[] { export function getDailyRunStarterModifiers(party: PlayerPokemon[]): PokemonHeldItemModifier[] {
const ret: Modifiers.PokemonHeldItemModifier[] = []; const ret: PokemonHeldItemModifier[] = [];
for (const p of party) { for (const p of party) {
for (let m = 0; m < 3; m++) { for (let m = 0; m < 3; m++) {
const tierValue = Utils.randSeedInt(64); const tierValue = randSeedInt(64);
let tier: ModifierTier; let tier: ModifierTier;
if (tierValue > 25) { if (tierValue > 25) {
@ -2301,7 +2298,7 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.P
tier = ModifierTier.MASTER; 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); ret.push(modifier);
} }
} }
@ -2340,7 +2337,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
break; break;
} }
if (tier === undefined) { if (tier === undefined) {
const tierValue = Utils.randSeedInt(1024); const tierValue = randSeedInt(1024);
if (!upgradeCount) { if (!upgradeCount) {
upgradeCount = 0; upgradeCount = 0;
} }
@ -2349,7 +2346,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
const upgradeOdds = Math.floor(128 / ((partyLuckValue + 4) / 4)); const upgradeOdds = Math.floor(128 / ((partyLuckValue + 4) / 4));
let upgraded = false; let upgraded = false;
do { do {
upgraded = Utils.randSeedInt(upgradeOdds) < 4; upgraded = randSeedInt(upgradeOdds) < 4;
if (upgraded) { if (upgraded) {
upgradeCount++; upgradeCount++;
} }
@ -2381,7 +2378,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
const partyShinyCount = party.filter(p => p.isShiny() && !p.isFainted()).length; const partyShinyCount = party.filter(p => p.isShiny() && !p.isFainted()).length;
const upgradeOdds = Math.floor(32 / ((partyShinyCount + 2) / 2)); const upgradeOdds = Math.floor(32 / ((partyShinyCount + 2) / 2));
while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) { while (modifierPool.hasOwnProperty(tier + upgradeCount + 1) && modifierPool[tier + upgradeCount + 1].length) {
if (!Utils.randSeedInt(upgradeOdds)) { if (!randSeedInt(upgradeOdds)) {
upgradeCount++; upgradeCount++;
} else { } else {
break; break;
@ -2396,7 +2393,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
const tierThresholds = Object.keys(thresholds[tier]); const tierThresholds = Object.keys(thresholds[tier]);
const totalWeight = parseInt(tierThresholds[tierThresholds.length - 1]); const totalWeight = parseInt(tierThresholds[tierThresholds.length - 1]);
const value = Utils.randSeedInt(totalWeight); const value = randSeedInt(totalWeight);
let index: integer | undefined; let index: integer | undefined;
for (const t of tierThresholds) { for (const t of tierThresholds) {
const threshold = parseInt(t); const threshold = parseInt(t);
@ -2456,9 +2453,9 @@ export class ModifierTypeOption {
*/ */
export function getPartyLuckValue(party: Pokemon[]): integer { export function getPartyLuckValue(party: Pokemon[]): integer {
if (party[0].scene.gameMode.isDaily) { if (party[0].scene.gameMode.isDaily) {
const DailyLuck = new Utils.NumberHolder(0); const DailyLuck = new NumberHolder(0);
party[0].scene.executeWithSeedOffset(() => { 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); }, 0, party[0].scene.seed);
return DailyLuck.value; return DailyLuck.value;
} }

File diff suppressed because it is too large Load Diff

View File

@ -57,7 +57,7 @@ export class BattleEndPhase extends BattlePhase {
if (m instanceof LapsingPokemonHeldItemModifier) { if (m instanceof LapsingPokemonHeldItemModifier) {
args.push(this.scene.getPokemonById(m.pokemonId)); args.push(this.scene.getPokemonById(m.pokemonId));
} }
if (!m.lapse(args)) { if (!m.lapse(...args)) {
this.scene.removeModifier(m); this.scene.removeModifier(m);
} }
} }

View File

@ -15,7 +15,7 @@ export class BerryPhase extends FieldPhase {
this.executeForAll((pokemon) => { this.executeForAll((pokemon) => {
const hasUsableBerry = !!this.scene.findModifier((m) => { const hasUsableBerry = !!this.scene.findModifier((m) => {
return m instanceof BerryModifier && m.shouldApply([pokemon]); return m instanceof BerryModifier && m.shouldApply(pokemon);
}, pokemon.isPlayer()); }, pokemon.isPlayer());
if (hasUsableBerry) { if (hasUsableBerry) {
@ -29,7 +29,7 @@ export class BerryPhase extends FieldPhase {
new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM) 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.consumed) {
if (!--berryModifier.stackCount) { if (!--berryModifier.stackCount) {
this.scene.removeModifier(berryModifier); this.scene.removeModifier(berryModifier);