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-23 18:40:21 -04:00
import Pokemon , { 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 ) ;
2023-04-19 14:07:38 -04:00
this . setModifierIconPosition ( icon , modifiers . length ) ;
2023-03-28 14:54:52 -04:00
}
}
2023-04-19 14:07:38 -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 ) {
2023-04-20 11:29:26 -04:00
if ( this . match ( modifier ) )
2023-04-21 22:59:09 -04:00
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 ;
2023-04-20 11:29:26 -04:00
return true ;
2023-04-09 19:15:21 -04:00
}
2023-04-20 11:29:26 -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
}
2023-04-23 18:40:21 -04:00
getIcon ( scene : BattleScene , forSummary? : boolean ) : Phaser . GameObjects . Container {
2023-03-28 14:54:52 -04:00
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 ) {
2023-04-18 22:09:37 -04:00
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 ;
}
}
2023-04-18 22:09:37 -04:00
export class TempBattleStatBoosterModifier extends PersistentModifier {
2023-04-20 15:46:05 -04:00
private tempBattleStat : TempBattleStat ;
2023-04-18 22:09:37 -04:00
private battlesLeft : integer ;
2023-04-21 14:05:16 -04:00
constructor ( type : ModifierTypes . TempBattleStatBoosterModifierType , tempBattleStat : TempBattleStat , stackCount? : integer ) {
super ( type , stackCount ) ;
2023-04-18 22:09:37 -04:00
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 ) ;
2023-04-18 22:09:37 -04:00
}
apply ( args : any [ ] ) : boolean {
2023-04-20 15:46:05 -04:00
const tempBattleStat = args [ 0 ] as TempBattleStat ;
2023-04-18 22:09:37 -04:00
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
}
2023-04-23 18:40:21 -04:00
getIcon ( scene : BattleScene , forSummary? : boolean ) : Phaser . GameObjects . Container {
const container = ! forSummary ? scene . add . container ( 0 , 0 ) : super . getIcon ( scene ) ;
2023-03-28 14:54:52 -04:00
2023-04-23 18:40:21 -04:00
if ( ! forSummary ) {
const pokemon = this . getPokemon ( scene ) ;
const pokemonIcon = scene . add . sprite ( 0 , 8 , pokemon . species . getIconAtlasKey ( ) ) ;
pokemonIcon . play ( pokemon . getIconKey ( ) ) . stop ( ) ;
pokemonIcon . setOrigin ( 0 , 0.5 ) ;
2023-03-28 14:54:52 -04:00
2023-04-23 18:40:21 -04:00
container . add ( pokemonIcon ) ;
2023-03-28 14:54:52 -04:00
2023-04-23 18:40:21 -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 ) ;
2023-04-14 01:08:44 -04:00
2023-04-23 18:40:21 -04:00
const stackText = this . getIconStackText ( scene ) ;
if ( stackText )
container . add ( stackText ) ;
2023-04-14 01:08:44 -04:00
2023-04-23 18:40:21 -04:00
const virtualStackText = this . getIconStackText ( scene , true ) ;
if ( virtualStackText )
container . add ( virtualStackText ) ;
} else
container . setScale ( 0.5 ) ;
2023-04-14 01:08:44 -04:00
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-23 21:31:06 -04:00
export class SurviveDamageModifier extends PokemonHeldItemModifier {
constructor ( type : ModifierType , pokemonId : integer , stackCount? : integer ) {
super ( type , pokemonId , stackCount ) ;
}
matchType ( modifier : Modifier ) {
return modifier instanceof SurviveDamageModifier ;
}
clone() {
return new SurviveDamageModifier ( this . type , this . pokemonId , this . stackCount ) ;
}
shouldApply ( args : any [ ] ) : boolean {
return super . shouldApply ( args ) && args . length === 2 && args [ 1 ] instanceof Utils . BooleanHolder ;
}
apply ( args : any [ ] ) : boolean {
const pokemon = args [ 0 ] as Pokemon ;
const surviveDamage = args [ 1 ] as Utils . BooleanHolder ;
2023-04-25 01:32:48 -04:00
if ( ! surviveDamage . value && Utils . randInt ( 10 ) < this . getStackCount ( ) ) {
2023-04-23 21:31:06 -04:00
surviveDamage . value = true ;
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ` hung on \ nusing its ${ this . type . name } ! ` ) ) ;
}
return true ;
}
getMaxStackCount ( ) : number {
return 5 ;
}
}
2023-04-25 01:32:48 -04:00
export class FlinchChanceModifier extends PokemonHeldItemModifier {
constructor ( type : ModifierType , pokemonId : integer , stackCount? : integer ) {
super ( type , pokemonId , stackCount ) ;
}
matchType ( modifier : Modifier ) {
return modifier instanceof FlinchChanceModifier ;
}
clone() {
return new FlinchChanceModifier ( this . type , this . pokemonId , this . stackCount ) ;
}
shouldApply ( args : any [ ] ) : boolean {
return super . shouldApply ( args ) && args . length === 2 && args [ 1 ] instanceof Utils . BooleanHolder ;
}
apply ( args : any [ ] ) : boolean {
const flinched = args [ 1 ] as Utils . BooleanHolder ;
if ( ! flinched . value && Utils . randInt ( 10 ) < this . getStackCount ( ) )
flinched . value = true ;
return true ;
}
getMaxStackCount ( ) : number {
return 3 ;
}
}
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 {
2023-04-23 21:31:06 -04:00
return 4 ;
2023-04-20 20:15:16 -04:00
}
}
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 {
2023-04-23 21:31:06 -04:00
return 4 ;
2023-04-20 20:15:16 -04:00
}
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 ;
2023-03-30 10:50:46 -04:00
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 ( ) ;
2023-04-19 00:35:06 -04:00
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 ;
2023-04-19 14:07:38 -04:00
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 ;
}
2023-04-23 21:31:06 -04:00
getMaxStackCount ( ) : number {
return 4 ;
}
2023-04-09 19:15:21 -04:00
}
export class ExpBoosterModifier extends PersistentModifier {
2023-03-30 00:13:56 -04:00
private boostMultiplier : integer ;
2023-04-21 14:05:16 -04:00
constructor ( type : ModifierType , boostPercent : integer , stackCount? : integer ) {
super ( type , stackCount ) ;
2023-03-30 00:13:56 -04:00
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 ;
}
}
2023-04-19 19:55:22 -04:00
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 ) ;
2023-04-19 19:55:22 -04:00
this . boostMultiplier = boostPercent * 0.01 ;
}
2023-04-21 14:05:16 -04:00
matchType ( modifier : Modifier ) : boolean {
2023-04-19 19:55:22 -04:00
if ( modifier instanceof PokemonExpBoosterModifier ) {
const pokemonExpModifier = modifier as PokemonExpBoosterModifier ;
2023-04-21 14:05:16 -04:00
return pokemonExpModifier . boostMultiplier === this . boostMultiplier ;
2023-04-19 19:55:22 -04:00
}
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 ) ;
2023-04-19 19:55:22 -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-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
2023-04-19 00:35:06 -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-03-30 10:50:46 -04:00
}
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
}
2023-03-30 10:50:46 -04:00
apply ( args : any [ ] ) : boolean {
2023-04-09 19:15:21 -04:00
( args [ 0 ] as Utils . IntegerHolder ) . value += this . getStackCount ( ) ;
2023-03-30 10:50:46 -04:00
return true ;
}
2023-04-23 01:37:58 -04:00
getMaxStackCount ( ) : integer {
return 3 ;
}
2023-03-28 14:54:52 -04:00
}