pokerogue/src/modifier/modifier.ts

923 lines
27 KiB
TypeScript
Raw Normal View History

2023-04-12 11:57:15 -04:00
import * as ModifierTypes from './modifier-type';
2023-04-20 19:44:56 -04:00
import { LearnMovePhase, LevelUpPhase, PokemonHealPhase } from "../battle-phases";
2023-04-20 15:46:05 -04:00
import BattleScene from "../battle-scene";
import { getLevelTotalExp } from "../data/exp";
import { PokeballType } from "../data/pokeball";
2023-04-20 19:44:56 -04:00
import Pokemon, { EnemyPokemon, PlayerPokemon } from "../pokemon";
2023-04-20 15:46:05 -04:00
import { Stat } from "../data/pokemon-stat";
import { addTextObject, TextStyle } from "../ui/text";
import { Type } from '../data/type';
import { EvolutionPhase } from '../evolution-phase';
import { pokemonEvolutions } from '../data/pokemon-evolutions';
import { getPokemonMessage } from '../messages';
import * as Utils from "../utils";
import { TempBattleStat } from '../data/temp-battle-stat';
import { BerryType, getBerryEffectFunc, getBerryPredicate } from '../data/berry';
2023-03-28 14:54:52 -04:00
2023-04-12 11:57:15 -04:00
type ModifierType = ModifierTypes.ModifierType;
2023-04-14 18:21:33 -04:00
export type ModifierPredicate = (modifier: Modifier) => boolean;
2023-04-12 11:57:15 -04:00
2023-03-28 14:54:52 -04:00
export class ModifierBar extends Phaser.GameObjects.Container {
2023-04-20 19:44:56 -04:00
private player: boolean;
2023-03-28 14:54:52 -04:00
2023-04-20 19:44:56 -04:00
constructor(scene: BattleScene, enemy?: boolean) {
super(scene, 1 + (enemy ? 302 : 0), 2);
this.player = !enemy;
2023-03-28 14:54:52 -04:00
this.setScale(0.5);
}
2023-04-09 19:15:21 -04:00
updateModifiers(modifiers: PersistentModifier[]) {
this.removeAll(true);
for (let modifier of modifiers) {
const icon = modifier.getIcon(this.scene as BattleScene);
this.add(icon);
this.setModifierIconPosition(icon, modifiers.length);
2023-03-28 14:54:52 -04:00
}
}
setModifierIconPosition(icon: Phaser.GameObjects.Container, modifierCount: integer) {
let rowIcons: integer = 12 + 6 * Math.max((Math.ceil(modifierCount / 12) - 2), 0);
const x = (this.getIndex(icon) % rowIcons) * 26 / (rowIcons / 12);
const y = Math.floor(this.getIndex(icon) / rowIcons) * 20;
2023-03-28 14:54:52 -04:00
2023-04-20 19:44:56 -04:00
icon.setPosition(this.player ? x : -x, y);
2023-03-28 14:54:52 -04:00
}
}
export abstract class Modifier {
public type: ModifierType;
constructor(type: ModifierType) {
this.type = type;
}
2023-04-09 19:15:21 -04:00
match(_modifier: Modifier): boolean {
return false;
2023-03-28 14:54:52 -04:00
}
shouldApply(_args: any[]): boolean {
return true;
}
abstract apply(args: any[]): boolean;
2023-04-09 19:15:21 -04:00
}
export abstract class PersistentModifier extends Modifier {
public stackCount: integer;
public virtualStackCount: integer;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, stackCount: integer) {
2023-04-09 19:15:21 -04:00
super(type);
2023-04-21 14:05:16 -04:00
this.stackCount = stackCount === undefined ? 1 : stackCount;
2023-04-09 19:15:21 -04:00
this.virtualStackCount = 0;
}
add(modifiers: PersistentModifier[], virtual: boolean): boolean {
for (let modifier of modifiers) {
if (this.match(modifier))
return modifier.incrementStack(this.stackCount, virtual);
2023-04-09 19:15:21 -04:00
}
if (virtual) {
this.virtualStackCount += this.stackCount;
this.stackCount = 0;
}
modifiers.push(this);
return true;
}
abstract clone(): PersistentModifier;
2023-04-21 14:05:16 -04:00
incrementStack(amount: integer, virtual: boolean): boolean {
if (this.getStackCount() + amount <= this.getMaxStackCount()) {
2023-04-09 19:15:21 -04:00
if (!virtual)
2023-04-21 14:05:16 -04:00
this.stackCount += amount;
2023-04-09 19:15:21 -04:00
else
2023-04-21 14:05:16 -04:00
this.virtualStackCount += amount;
return true;
2023-04-09 19:15:21 -04:00
}
return false;
2023-04-09 19:15:21 -04:00
}
2023-03-28 14:54:52 -04:00
2023-04-09 19:15:21 -04:00
getStackCount(): integer {
return this.stackCount + this.virtualStackCount;
2023-03-30 23:02:35 -04:00
}
getMaxStackCount(): integer {
return 99;
2023-03-28 14:54:52 -04:00
}
getIcon(scene: BattleScene): Phaser.GameObjects.Container {
const container = scene.add.container(0, 0);
const item = scene.add.sprite(0, 12, 'items');
item.setFrame(this.type.iconImage);
item.setOrigin(0, 0.5);
container.add(item);
const stackText = this.getIconStackText(scene);
if (stackText)
container.add(stackText);
2023-04-09 19:15:21 -04:00
const virtualStackText = this.getIconStackText(scene, true);
if (virtualStackText)
container.add(virtualStackText);
2023-03-28 14:54:52 -04:00
return container;
}
2023-04-09 19:15:21 -04:00
getIconStackText(scene: BattleScene, virtual?: boolean): Phaser.GameObjects.Text {
if (this.getMaxStackCount() === 1 || (virtual && !this.virtualStackCount))
2023-03-28 14:54:52 -04:00
return null;
2023-04-09 19:15:21 -04:00
const isStackMax = this.getStackCount() >= this.getMaxStackCount();
const maxColor = '#f89890';
const maxStrokeColor = '#984038';
if (virtual) {
const virtualText = addTextObject(scene, 27, 12, `+${this.virtualStackCount.toString()}`, TextStyle.PARTY, { fontSize: '66px', color: !isStackMax ? '#40c8f8' : maxColor });
2023-04-09 19:15:21 -04:00
virtualText.setShadow(0, 0, null);
virtualText.setStroke(!isStackMax ? '#006090' : maxStrokeColor, 16)
virtualText.setOrigin(1, 0);
return virtualText;
}
const text = addTextObject(scene, 8, 12, this.stackCount.toString(), TextStyle.PARTY, { fontSize: '66px', color: !isStackMax ? '#f8f8f8' : maxColor });
text.setShadow(0, 0, null);
2023-03-28 14:54:52 -04:00
text.setStroke('#424242', 16)
2023-04-09 19:15:21 -04:00
text.setOrigin(0, 0);
2023-03-28 14:54:52 -04:00
return text;
}
}
export abstract class ConsumableModifier extends Modifier {
constructor(type: ModifierType) {
super(type);
}
2023-04-09 19:15:21 -04:00
add(_modifiers: Modifier[]): boolean {
2023-03-28 14:54:52 -04:00
return true;
}
shouldApply(args: any[]): boolean {
2023-03-30 23:02:35 -04:00
return super.shouldApply(args) && args.length === 1 && args[0] instanceof BattleScene;
2023-03-28 14:54:52 -04:00
}
}
2023-04-12 11:57:15 -04:00
export class AddPokeballModifier extends ConsumableModifier {
2023-03-28 14:54:52 -04:00
private pokeballType: PokeballType;
private count: integer;
constructor(type: ModifierType, pokeballType: PokeballType, count: integer) {
super(type);
this.pokeballType = pokeballType;
this.count = count;
}
apply(args: any[]): boolean {
2023-04-01 22:59:07 -04:00
const pokeballCounts = (args[0] as BattleScene).pokeballCounts;
pokeballCounts[this.pokeballType] = Math.min(pokeballCounts[this.pokeballType] + this.count, 99);
2023-03-28 14:54:52 -04:00
return true;
}
}
export class TempBattleStatBoosterModifier extends PersistentModifier {
2023-04-20 15:46:05 -04:00
private tempBattleStat: TempBattleStat;
private battlesLeft: integer;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierTypes.TempBattleStatBoosterModifierType, tempBattleStat: TempBattleStat, stackCount?: integer) {
super(type, stackCount);
this.tempBattleStat = tempBattleStat;
this.battlesLeft = 5;
}
clone(): TempBattleStatBoosterModifier {
2023-04-21 14:05:16 -04:00
return new TempBattleStatBoosterModifier(this.type as ModifierTypes.TempBattleStatBoosterModifierType, this.tempBattleStat, this.stackCount);
}
apply(args: any[]): boolean {
2023-04-20 15:46:05 -04:00
const tempBattleStat = args[0] as TempBattleStat;
if (tempBattleStat === this.tempBattleStat) {
const statLevel = args[1] as Utils.IntegerHolder;
statLevel.value = Math.min(statLevel.value + 1, 6);
return true;
}
return false;
}
lapse(): boolean {
return !!--this.battlesLeft;
}
getIcon(scene: BattleScene): Phaser.GameObjects.Container {
const container = super.getIcon(scene);
const battleCountText = addTextObject(scene, 27, 0, this.battlesLeft.toString(), TextStyle.PARTY, { fontSize: '66px', color: '#f89890' });
battleCountText.setShadow(0, 0, null);
battleCountText.setStroke('#984038', 16)
battleCountText.setOrigin(1, 0);
container.add(battleCountText);
return container;
}
}
2023-04-09 19:15:21 -04:00
export abstract class PokemonHeldItemModifier extends PersistentModifier {
2023-03-28 14:54:52 -04:00
public pokemonId: integer;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, pokemonId: integer, stackCount: integer) {
super(type, stackCount);
2023-03-28 14:54:52 -04:00
this.pokemonId = pokemonId;
}
2023-04-21 14:05:16 -04:00
abstract matchType(_modifier: Modifier): boolean;
match(modifier: Modifier) {
return this.matchType(modifier) && (modifier as PokemonHeldItemModifier).pokemonId === this.pokemonId;
}
2023-03-28 14:54:52 -04:00
shouldApply(args: any[]): boolean {
2023-03-30 23:02:35 -04:00
return super.shouldApply(args) && args.length && args[0] instanceof Pokemon && (this.pokemonId === -1 || (args[0] as Pokemon).id === this.pokemonId);
2023-03-28 14:54:52 -04:00
}
getIcon(scene: BattleScene): Phaser.GameObjects.Container {
const container = scene.add.container(0, 0);
const pokemon = this.getPokemon(scene);
2023-04-09 19:15:21 -04:00
const pokemonIcon = scene.add.sprite(0, 8, pokemon.species.getIconAtlasKey());
pokemonIcon.play(pokemon.getIconKey()).stop();
2023-03-28 14:54:52 -04:00
pokemonIcon.setOrigin(0, 0.5);
container.add(pokemonIcon);
2023-04-14 01:08:44 -04:00
const item = scene.add.sprite(16, this.virtualStackCount ? 8 : 16, 'items');
item.setScale(0.5);
item.setOrigin(0, 0.5);
item.setTexture('items', this.type.iconImage);
container.add(item);
const stackText = this.getIconStackText(scene);
if (stackText)
container.add(stackText);
const virtualStackText = this.getIconStackText(scene, true);
if (virtualStackText)
container.add(virtualStackText);
2023-03-28 14:54:52 -04:00
return container;
}
2023-04-22 22:14:53 -04:00
getPokemon(scene: BattleScene): Pokemon {
return scene.getPokemonById(this.pokemonId);
2023-03-28 14:54:52 -04:00
}
}
2023-04-09 19:15:21 -04:00
export class PokemonBaseStatModifier extends PokemonHeldItemModifier {
2023-03-28 14:54:52 -04:00
protected stat: Stat;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierTypes.PokemonBaseStatBoosterModifierType, pokemonId: integer, stat: Stat, stackCount?: integer) {
super(type, pokemonId, stackCount);
2023-03-28 14:54:52 -04:00
this.stat = stat;
}
2023-04-21 14:05:16 -04:00
matchType(modifier: Modifier): boolean {
if (modifier instanceof PokemonBaseStatModifier)
return (modifier as PokemonBaseStatModifier).stat === this.stat;
2023-04-09 19:15:21 -04:00
return false;
}
2023-03-28 14:54:52 -04:00
2023-04-09 19:15:21 -04:00
clone(): PersistentModifier {
2023-04-21 14:05:16 -04:00
return new PokemonBaseStatModifier(this.type as ModifierTypes.PokemonBaseStatBoosterModifierType, this.pokemonId, this.stat, this.stackCount);
2023-03-28 14:54:52 -04:00
}
shouldApply(args: any[]): boolean {
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array<integer>;
}
apply(args: any[]): boolean {
2023-04-09 19:15:21 -04:00
args[1][this.stat] = Math.min(Math.floor(args[1][this.stat] * (1 + this.getStackCount() * 0.2)), 999999);
2023-03-28 14:54:52 -04:00
return true;
}
2023-04-14 01:08:44 -04:00
}
2023-03-28 14:54:52 -04:00
2023-04-14 18:21:33 -04:00
export class AttackTypeBoosterModifier extends PokemonHeldItemModifier {
private moveType: Type;
private boostMultiplier: number;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, pokemonId: integer, moveType: Type, boostPercent: integer, stackCount?: integer) {
super(type, pokemonId, stackCount);
2023-04-14 18:21:33 -04:00
this.moveType = moveType;
this.boostMultiplier = boostPercent * 0.01;
}
2023-04-21 14:05:16 -04:00
matchType(modifier: Modifier) {
if (modifier instanceof AttackTypeBoosterModifier) {
const attackTypeBoosterModifier = modifier as AttackTypeBoosterModifier;
return attackTypeBoosterModifier.moveType === this.moveType && attackTypeBoosterModifier.boostMultiplier === this.boostMultiplier;
}
2023-04-14 18:21:33 -04:00
}
clone() {
2023-04-21 14:05:16 -04:00
return new AttackTypeBoosterModifier(this.type, this.pokemonId, this.moveType, this.boostMultiplier * 100, this.stackCount);
2023-04-14 18:21:33 -04:00
}
shouldApply(args: any[]): boolean {
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Utils.NumberHolder;
}
apply(args: any[]): boolean {
(args[1] as Utils.NumberHolder).value = Math.floor((args[1] as Utils.NumberHolder).value * (1 + (this.getStackCount() * this.boostMultiplier)));
return true;
}
}
2023-04-20 20:15:16 -04:00
export class TurnHealModifier extends PokemonHeldItemModifier {
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) {
super(type, pokemonId, stackCount);
2023-04-20 20:15:16 -04:00
}
2023-04-21 14:05:16 -04:00
matchType(modifier: Modifier) {
2023-04-20 20:15:16 -04:00
return modifier instanceof TurnHealModifier;
}
clone() {
2023-04-21 14:05:16 -04:00
return new TurnHealModifier(this.type, this.pokemonId, this.stackCount);
2023-04-20 20:15:16 -04:00
}
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
if (pokemon.getHpRatio() < 1) {
const scene = pokemon.scene;
2023-04-23 10:24:22 -04:00
scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.isPlayer(), Math.max(Math.floor(pokemon.getMaxHp() / 16) * this.stackCount, 1), getPokemonMessage(pokemon, `'s ${this.type.name}\nrestored its HP a little!`), true));
2023-04-20 20:15:16 -04:00
}
return true;
}
getMaxStackCount(): number {
return 16;
}
}
2023-04-14 01:08:44 -04:00
export class HitHealModifier extends PokemonHeldItemModifier {
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) {
super(type, pokemonId, stackCount);
2023-04-14 01:08:44 -04:00
}
2023-03-28 14:54:52 -04:00
2023-04-21 14:05:16 -04:00
matchType(modifier: Modifier) {
2023-04-14 01:08:44 -04:00
return modifier instanceof HitHealModifier;
}
2023-03-28 14:54:52 -04:00
2023-04-14 01:08:44 -04:00
clone() {
2023-04-21 14:05:16 -04:00
return new HitHealModifier(this.type, this.pokemonId, this.stackCount);
2023-04-14 01:08:44 -04:00
}
2023-03-28 14:54:52 -04:00
2023-04-14 01:08:44 -04:00
apply(args: any[]): boolean {
2023-04-20 19:44:56 -04:00
const pokemon = args[0] as Pokemon;
2023-04-09 19:15:21 -04:00
2023-04-14 01:08:44 -04:00
if (pokemon.turnData.damageDealt && pokemon.getHpRatio() < 1) {
2023-04-14 18:21:33 -04:00
const scene = pokemon.scene;
2023-04-23 10:24:22 -04:00
scene.unshiftPhase(new PokemonHealPhase(scene, pokemon.isPlayer(), Math.max(Math.floor(pokemon.turnData.damageDealt / 8) * this.stackCount, 1), getPokemonMessage(pokemon, `'s ${this.type.name}\nrestored its HP a little!`), true));
2023-04-14 01:08:44 -04:00
}
return true;
2023-03-28 14:54:52 -04:00
}
2023-04-20 20:15:16 -04:00
getMaxStackCount(): number {
return 16;
}
2023-03-28 14:54:52 -04:00
}
2023-04-23 12:35:16 -04:00
export class LevelIncrementBoosterModifier extends PersistentModifier {
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
}
match(modifier: Modifier) {
return modifier instanceof LevelIncrementBoosterModifier;
}
clone() {
return new LevelIncrementBoosterModifier(this.type, this.stackCount);
}
shouldApply(args: any[]): boolean {
return super.shouldApply(args) && args[0] instanceof Utils.IntegerHolder;
}
apply(args: any[]): boolean {
(args[0] as Utils.IntegerHolder).value += this.getStackCount();
return true;
}
}
2023-04-20 15:46:05 -04:00
export class BerryModifier extends PokemonHeldItemModifier {
public berryType: BerryType;
public consumed: boolean;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, pokemonId: integer, berryType: BerryType, stackCount?: integer) {
super(type, pokemonId, stackCount);
2023-04-20 15:46:05 -04:00
this.berryType = berryType;
this.consumed = false;
}
2023-04-21 14:05:16 -04:00
matchType(modifier: Modifier) {
return modifier instanceof BerryModifier && (modifier as BerryModifier).berryType === this.berryType;
2023-04-20 15:46:05 -04:00
}
clone() {
2023-04-21 14:05:16 -04:00
return new BerryModifier(this.type, this.pokemonId, this.berryType, this.stackCount);
2023-04-20 15:46:05 -04:00
}
shouldApply(args: any[]): boolean {
return !this.consumed && super.shouldApply(args) && getBerryPredicate(this.berryType)(args[0] as Pokemon);
}
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
const preserve = new Utils.BooleanHolder(false);
2023-04-20 19:44:56 -04:00
pokemon.scene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), preserve);
2023-04-20 15:46:05 -04:00
getBerryEffectFunc(this.berryType)(pokemon);
if (!preserve.value)
this.consumed = true;
return true;
}
}
export class PreserveBerryModifier extends PersistentModifier {
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
2023-04-20 15:46:05 -04:00
}
match(modifier: Modifier) {
return modifier instanceof PreserveBerryModifier;
}
clone() {
2023-04-21 14:05:16 -04:00
return new PreserveBerryModifier(this.type, this.stackCount);
2023-04-20 15:46:05 -04:00
}
shouldApply(args: any[]): boolean {
return super.shouldApply(args) && args[0] instanceof Utils.BooleanHolder;
}
apply(args: any[]): boolean {
if (!(args[0] as Utils.BooleanHolder).value)
(args[0] as Utils.BooleanHolder).value = this.getStackCount() === this.getMaxStackCount() || Utils.randInt(this.getMaxStackCount()) < this.getStackCount();
return true;
}
getMaxStackCount(): number {
return 4;
}
}
2023-04-09 19:15:21 -04:00
export abstract class ConsumablePokemonModifier extends ConsumableModifier {
public pokemonId: integer;
2023-03-28 14:54:52 -04:00
constructor(type: ModifierType, pokemonId: integer) {
2023-04-09 19:15:21 -04:00
super(type);
this.pokemonId = pokemonId;
2023-03-28 14:54:52 -04:00
}
2023-04-09 19:15:21 -04:00
shouldApply(args: any[]): boolean {
2023-04-20 19:44:56 -04:00
return args.length && args[0] instanceof PlayerPokemon && (this.pokemonId === -1 || (args[0] as PlayerPokemon).id === this.pokemonId);
2023-04-09 19:15:21 -04:00
}
getPokemon(scene: BattleScene) {
return scene.getParty().find(p => p.id === this.pokemonId);
2023-03-28 14:54:52 -04:00
}
}
export class PokemonHpRestoreModifier extends ConsumablePokemonModifier {
2023-04-09 19:15:21 -04:00
private restorePoints: integer;
private percent: boolean;
2023-04-20 15:46:05 -04:00
public fainted: boolean;
2023-03-28 14:54:52 -04:00
2023-04-09 19:15:21 -04:00
constructor(type: ModifierType, pokemonId: integer, restorePoints: integer, percent: boolean, fainted?: boolean) {
2023-03-28 14:54:52 -04:00
super(type, pokemonId);
2023-04-09 19:15:21 -04:00
this.restorePoints = restorePoints;
this.percent = percent;
this.fainted = !!fainted;
2023-03-28 14:54:52 -04:00
}
2023-04-09 19:15:21 -04:00
shouldApply(args: any[]): boolean {
return super.shouldApply(args) && (this.fainted || (args.length > 1 && typeof(args[1]) === 'number'));
}
2023-03-28 14:54:52 -04:00
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
2023-04-09 19:15:21 -04:00
if (!pokemon.hp === this.fainted) {
let restorePoints = this.restorePoints;
if (!this.fainted)
restorePoints = Math.floor(restorePoints * (args[1] as number));
2023-04-16 18:40:32 -04:00
else
pokemon.resetStatus();
pokemon.hp = Math.min(pokemon.hp + Math.ceil((this.percent ? (restorePoints * 0.01) * pokemon.getMaxHp() : restorePoints)), pokemon.getMaxHp());
2023-04-09 19:15:21 -04:00
}
2023-03-28 14:54:52 -04:00
return true;
}
}
2023-04-18 22:23:06 -04:00
export class PokemonStatusHealModifier extends ConsumablePokemonModifier {
constructor(type: ModifierType, pokemonId: integer) {
super(type, pokemonId);
}
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
pokemon.resetStatus();
return true;
}
}
2023-04-11 11:04:39 -04:00
export abstract class ConsumablePokemonMoveModifier extends ConsumablePokemonModifier {
public moveIndex: integer;
2023-04-04 21:10:11 -04:00
2023-04-11 11:04:39 -04:00
constructor(type: ModifierType, pokemonId: integer, moveIndex: integer) {
2023-04-04 21:10:11 -04:00
super(type, pokemonId);
2023-04-11 11:04:39 -04:00
this.moveIndex = moveIndex;
}
}
export class PokemonPpRestoreModifier extends ConsumablePokemonMoveModifier {
private restorePoints: integer;
constructor(type: ModifierType, pokemonId: integer, moveIndex: integer, restorePoints: integer) {
super(type, pokemonId, moveIndex);
2023-04-04 21:10:11 -04:00
this.restorePoints = restorePoints;
}
2023-04-11 11:04:39 -04:00
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
const move = pokemon.moveset[this.moveIndex];
move.ppUsed = this.restorePoints >= -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0;
return true;
}
}
export class PokemonAllMovePpRestoreModifier extends ConsumablePokemonModifier {
private restorePoints: integer;
constructor(type: ModifierType, pokemonId: integer, restorePoints: integer) {
super(type, pokemonId);
this.restorePoints = restorePoints;
2023-04-04 21:10:11 -04:00
}
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
2023-04-11 11:04:39 -04:00
for (let move of pokemon.moveset)
move.ppUsed = this.restorePoints >= -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0;
2023-04-04 21:10:11 -04:00
return true;
}
}
2023-04-04 18:28:21 -04:00
export class PokemonLevelIncrementModifier extends ConsumablePokemonModifier {
constructor(type: ModifierType, pokemonId: integer) {
super(type, pokemonId);
}
apply(args: any[]): boolean {
const pokemon = args[0] as PlayerPokemon;
2023-04-23 12:35:16 -04:00
const levelCount = new Utils.IntegerHolder(1);
pokemon.scene.applyModifiers(LevelIncrementBoosterModifier, true, levelCount);
pokemon.level += levelCount.value;
if (pokemon.level <= 100) {
pokemon.exp = getLevelTotalExp(pokemon.level, pokemon.species.growthRate);
pokemon.levelExp = 0;
}
2023-04-04 18:28:21 -04:00
2023-04-14 18:21:33 -04:00
pokemon.scene.unshiftPhase(new LevelUpPhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), pokemon.level - 1, pokemon.level));
2023-04-04 18:28:21 -04:00
return true;
}
}
2023-04-08 00:21:44 -04:00
export class TmModifier extends ConsumablePokemonModifier {
2023-04-12 11:57:15 -04:00
constructor(type: ModifierTypes.TmModifierType, pokemonId: integer) {
2023-04-08 00:21:44 -04:00
super(type, pokemonId);
}
apply(args: any[]): boolean {
const pokemon = args[0] as PlayerPokemon;
2023-04-14 18:21:33 -04:00
pokemon.scene.unshiftPhase(new LearnMovePhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), (this.type as ModifierTypes.TmModifierType).moveId));
2023-04-08 00:21:44 -04:00
return true;
}
}
2023-04-14 18:21:33 -04:00
export class EvolutionItemModifier extends ConsumablePokemonModifier {
constructor(type: ModifierTypes.EvolutionItemModifierType, pokemonId: integer) {
super(type, pokemonId);
}
apply(args: any[]): boolean {
const pokemon = args[0] as PlayerPokemon;
const matchingEvolution = pokemonEvolutions[pokemon.species.speciesId].find(e => e.item === (this.type as ModifierTypes.EvolutionItemModifierType).evolutionItem
&& (!e.condition || e.condition.predicate(pokemon)));
if (matchingEvolution) {
pokemon.scene.unshiftPhase(new EvolutionPhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), matchingEvolution, pokemon.level - 1));
return true;
}
return false;
}
}
2023-04-09 19:15:21 -04:00
export class PartyShareModifier extends PersistentModifier {
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
2023-04-09 19:15:21 -04:00
}
match(modifier: Modifier) {
return modifier instanceof PartyShareModifier;
}
clone(): PartyShareModifier {
2023-04-21 14:05:16 -04:00
return new PartyShareModifier(this.type, this.stackCount);
2023-04-09 19:15:21 -04:00
}
shouldApply(args: any[]): boolean {
return super.shouldApply(args) && args.length === 2 && args[0] instanceof BattleScene && args[1] instanceof Array<Modifier>;
}
apply(args: any[]): boolean {
const scene = args[0] as BattleScene;
const modifiers = args[1] as Modifier[];
const party = scene.getParty();
for (let modifier of modifiers) {
if (modifier instanceof PokemonHeldItemModifier) {
const heldItemModifier = modifier as PokemonHeldItemModifier;
2023-04-23 10:42:00 -04:00
const extraStacks = Math.floor(modifier.stackCount / Math.max(party.length - (this.stackCount - 1), 1));
2023-04-09 19:15:21 -04:00
for (let s = 0; s < extraStacks; s++) {
for (let p of party) {
if (p.id === heldItemModifier.pokemonId)
continue;
const newHeldItemModifier = heldItemModifier.clone() as PokemonHeldItemModifier;
newHeldItemModifier.pokemonId = p.id;
2023-04-20 19:44:56 -04:00
scene.addModifier(newHeldItemModifier, false, true);
2023-04-09 19:15:21 -04:00
}
}
}
}
return true;
}
getMaxStackCount(): number {
return 6;
}
}
export class HealingBoosterModifier extends PersistentModifier {
private multiplier: number;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, multiplier: number, stackCount?: integer) {
super(type, stackCount);
2023-04-09 19:15:21 -04:00
this.multiplier = multiplier;
}
match(modifier: Modifier): boolean {
return modifier instanceof HealingBoosterModifier;
}
clone(): HealingBoosterModifier {
2023-04-21 14:05:16 -04:00
return new HealingBoosterModifier(this.type, this.multiplier, this.stackCount);
2023-04-09 19:15:21 -04:00
}
apply(args: any[]): boolean {
const healingMultiplier = args[0] as Utils.IntegerHolder;
for (let s = 0; s < this.getStackCount(); s++)
healingMultiplier.value *= this.multiplier;
healingMultiplier.value = Math.floor(healingMultiplier.value);
return true;
}
}
export class ExpBoosterModifier extends PersistentModifier {
private boostMultiplier: integer;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, boostPercent: integer, stackCount?: integer) {
super(type, stackCount);
this.boostMultiplier = boostPercent * 0.01;
2023-03-28 14:54:52 -04:00
}
2023-04-09 19:15:21 -04:00
match(modifier: Modifier): boolean {
if (modifier instanceof ExpBoosterModifier) {
const expModifier = modifier as ExpBoosterModifier;
return expModifier.boostMultiplier === this.boostMultiplier;
2023-03-28 14:54:52 -04:00
}
2023-04-09 19:15:21 -04:00
return false;
}
2023-03-28 14:54:52 -04:00
2023-04-09 19:15:21 -04:00
clone(): ExpBoosterModifier {
2023-04-21 14:05:16 -04:00
return new ExpBoosterModifier(this.type, this.boostMultiplier * 100, this.stackCount);
2023-03-28 14:54:52 -04:00
}
apply(args: any[]): boolean {
2023-04-09 19:15:21 -04:00
(args[0] as Utils.NumberHolder).value = Math.floor((args[0] as Utils.NumberHolder).value * (1 + (this.getStackCount() * this.boostMultiplier)));
2023-03-30 23:02:35 -04:00
return true;
}
}
export class PokemonExpBoosterModifier extends PokemonHeldItemModifier {
private boostMultiplier: integer;
2023-04-21 14:05:16 -04:00
constructor(type: ModifierTypes.PokemonExpBoosterModifierType, pokemonId: integer, boostPercent: integer, stackCount?: integer) {
super(type, pokemonId, stackCount);
this.boostMultiplier = boostPercent * 0.01;
}
2023-04-21 14:05:16 -04:00
matchType(modifier: Modifier): boolean {
if (modifier instanceof PokemonExpBoosterModifier) {
const pokemonExpModifier = modifier as PokemonExpBoosterModifier;
2023-04-21 14:05:16 -04:00
return pokemonExpModifier.boostMultiplier === this.boostMultiplier;
}
return false;
}
clone(): PersistentModifier {
2023-04-21 14:05:16 -04:00
return new PokemonExpBoosterModifier(this.type as ModifierTypes.PokemonExpBoosterModifierType, this.pokemonId, this.boostMultiplier * 100, this.stackCount);
}
shouldApply(args: any[]): boolean {
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Utils.NumberHolder;
}
apply(args: any[]): boolean {
(args[1] as Utils.NumberHolder).value = Math.floor((args[1] as Utils.NumberHolder).value * (1 + (this.getStackCount() * this.boostMultiplier)));
return true;
}
}
2023-04-09 19:15:21 -04:00
export class ExpShareModifier extends PersistentModifier {
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
2023-03-30 23:02:35 -04:00
}
2023-03-28 14:54:52 -04:00
match(modifier: Modifier): boolean {
return modifier instanceof ExpShareModifier;
}
2023-03-30 23:02:35 -04:00
apply(_args: any[]): boolean {
2023-03-28 14:54:52 -04:00
return true;
}
2023-03-30 23:02:35 -04:00
2023-04-09 19:15:21 -04:00
clone(): ExpShareModifier {
2023-04-21 14:05:16 -04:00
return new ExpShareModifier(this.type, this.stackCount);
2023-04-09 19:15:21 -04:00
}
2023-03-30 23:02:35 -04:00
getMaxStackCount(): integer {
return 5;
}
2023-03-28 14:54:52 -04:00
}
2023-04-19 22:51:46 -04:00
export class ExpBalanceModifier extends PersistentModifier {
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
2023-04-19 22:51:46 -04:00
}
match(modifier: Modifier): boolean {
return modifier instanceof ExpBalanceModifier;
}
apply(_args: any[]): boolean {
return true;
}
clone(): ExpBalanceModifier {
2023-04-21 14:05:16 -04:00
return new ExpBalanceModifier(this.type, this.stackCount);
2023-04-19 22:51:46 -04:00
}
getMaxStackCount(): integer {
return 1;
}
}
2023-04-09 19:15:21 -04:00
export class ShinyRateBoosterModifier extends PersistentModifier {
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
2023-03-28 14:54:52 -04:00
}
2023-04-09 19:15:21 -04:00
match(modifier: Modifier): boolean {
return modifier instanceof ShinyRateBoosterModifier;
}
2023-03-28 14:54:52 -04:00
2023-04-09 19:15:21 -04:00
clone(): ShinyRateBoosterModifier {
2023-04-21 14:05:16 -04:00
return new ShinyRateBoosterModifier(this.type, this.stackCount);
2023-03-28 14:54:52 -04:00
}
apply(args: any[]): boolean {
2023-04-09 19:15:21 -04:00
(args[0] as Utils.IntegerHolder).value = Math.pow((args[0] as Utils.IntegerHolder).value * 0.5, this.getStackCount() + 1);
2023-03-28 14:54:52 -04:00
return true;
}
2023-03-30 23:02:35 -04:00
getMaxStackCount(): integer {
2023-04-23 10:24:22 -04:00
return 4;
2023-03-30 23:02:35 -04:00
}
2023-03-28 14:54:52 -04:00
}
2023-04-23 10:24:22 -04:00
export class HeldItemTransferModifier extends PokemonHeldItemModifier {
constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) {
super(type, pokemonId, stackCount);
2023-04-21 15:45:48 -04:00
}
2023-04-23 10:24:22 -04:00
matchType(modifier: Modifier): boolean {
2023-04-21 15:45:48 -04:00
return modifier instanceof HeldItemTransferModifier;
}
clone(): HeldItemTransferModifier {
2023-04-23 10:24:22 -04:00
return new HeldItemTransferModifier(this.type, this.pokemonId, this.stackCount);
2023-04-21 15:45:48 -04:00
}
apply(args: any[]): boolean {
2023-04-23 10:24:22 -04:00
const pokemon = args[0] as Pokemon;
const targetPokemon = pokemon.isPlayer() ? pokemon.scene.getEnemyPokemon() : pokemon.scene.getPlayerPokemon();
const transferredModifierTypes: ModifierTypes.ModifierType[] = [];
const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& (m as PokemonHeldItemModifier).pokemonId === targetPokemon.id, targetPokemon.isPlayer()) as PokemonHeldItemModifier[];
for (let i = 0; i < this.getStackCount(); i++) {
if (!itemModifiers.length)
break;
const randItemIndex = Utils.randInt(itemModifiers.length);
const randItem = itemModifiers[randItemIndex];
if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false, false)) {
transferredModifierTypes.push(randItem.type);
itemModifiers.splice(randItemIndex, 1);
}
}
2023-04-21 15:45:48 -04:00
2023-04-23 10:24:22 -04:00
for (let mt of transferredModifierTypes)
pokemon.scene.queueMessage(getPokemonMessage(targetPokemon, `'s ${mt.name} was absorbed\nby ${pokemon.name}'s MINI BLACK HOLE!`));
2023-04-21 15:45:48 -04:00
2023-04-23 10:24:22 -04:00
return !!transferredModifierTypes.length;
2023-04-21 15:45:48 -04:00
}
}
2023-04-09 19:15:21 -04:00
export class ExtraModifierModifier extends PersistentModifier {
2023-04-21 14:05:16 -04:00
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
}
2023-04-20 01:07:39 -04:00
match(modifier: Modifier): boolean {
return modifier instanceof ExtraModifierModifier;
}
2023-04-09 19:15:21 -04:00
clone(): ExtraModifierModifier {
2023-04-21 14:05:16 -04:00
return new ExtraModifierModifier(this.type, this.stackCount);
2023-04-09 19:15:21 -04:00
}
apply(args: any[]): boolean {
2023-04-09 19:15:21 -04:00
(args[0] as Utils.IntegerHolder).value += this.getStackCount();
return true;
}
getMaxStackCount(): integer {
return 3;
}
2023-03-28 14:54:52 -04:00
}