2023-04-10 14:12:01 -04:00
import { LearnMovePhase , LevelUpPhase } from "./battle-phases" ;
2023-03-28 14:54:52 -04:00
import BattleScene from "./battle-scene" ;
2023-04-04 18:28:21 -04:00
import { getLevelTotalExp } from "./exp" ;
2023-04-08 00:21:44 -04:00
import { allMoves , Moves } from "./move" ;
2023-03-28 14:54:52 -04:00
import { getPokeballName , PokeballType } from "./pokeball" ;
import Pokemon , { PlayerPokemon } from "./pokemon" ;
import { Stat , getStatName } from "./pokemon-stat" ;
import { addTextObject , TextStyle } from "./text" ;
2023-04-08 00:21:44 -04:00
import { tmSpecies } from "./tms" ;
import { Type } from "./type" ;
2023-03-28 14:54:52 -04:00
import PartyUiHandler from "./ui/party-ui-handler" ;
import * as Utils from "./utils" ;
export class ModifierBar extends Phaser . GameObjects . Container {
constructor ( scene : BattleScene ) {
super ( scene , 1 , 2 ) ;
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 ) ;
2023-03-28 14:54:52 -04:00
}
}
setModifierIconPosition ( icon : Phaser.GameObjects.Container ) {
const x = ( this . getIndex ( icon ) % 12 ) * 26 ;
const y = Math . floor ( ( this . getIndex ( icon ) * 6 ) / ( this . scene . game . canvas . width / 6 ) ) * 20 ;
icon . setPosition ( x , y ) ;
}
}
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 ;
constructor ( type : ModifierType ) {
super ( type ) ;
this . stackCount = 1 ;
this . virtualStackCount = 0 ;
}
add ( modifiers : PersistentModifier [ ] , virtual : boolean ) : boolean {
for ( let modifier of modifiers ) {
if ( this . match ( modifier ) ) {
modifier . incrementStack ( virtual ) ;
return true ;
}
}
if ( virtual ) {
this . virtualStackCount += this . stackCount ;
this . stackCount = 0 ;
}
modifiers . push ( this ) ;
return true ;
}
abstract clone ( ) : PersistentModifier ;
incrementStack ( virtual : boolean ) : void {
if ( this . getStackCount ( ) < this . getMaxStackCount ( ) ) {
if ( ! virtual )
this . stackCount ++ ;
else
this . virtualStackCount ++ ;
}
}
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 , 1 * 11 + 16 , 12 , ` + ${ this . virtualStackCount . toString ( ) } ` , TextStyle . PARTY , { fontSize : '66px' , color : ! isStackMax ? '#40c8f8' : maxColor } ) ;
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
}
}
class AddPokeballModifier extends ConsumableModifier {
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-09 19:15:21 -04:00
export abstract class PokemonHeldItemModifier extends PersistentModifier {
2023-03-28 14:54:52 -04:00
public pokemonId : integer ;
constructor ( type : ModifierType , pokemonId : integer ) {
super ( type ) ;
this . pokemonId = pokemonId ;
}
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 . species . getIconKey ( ) ) . stop ( ) ;
2023-03-28 14:54:52 -04:00
pokemonIcon . setOrigin ( 0 , 0.5 ) ;
container . add ( pokemonIcon ) ;
return container ;
}
getPokemon ( scene : BattleScene ) {
return scene . getParty ( ) . find ( p = > p . id === this . pokemonId ) ;
}
}
2023-04-09 19:15:21 -04:00
export class PokemonBaseStatModifier extends PokemonHeldItemModifier {
2023-03-28 14:54:52 -04:00
protected stat : Stat ;
constructor ( type : PokemonBaseStatBoosterModifierType , pokemonId : integer , stat : Stat ) {
super ( type , pokemonId ) ;
this . stat = stat ;
}
2023-04-09 19:15:21 -04:00
match ( modifier : Modifier ) : boolean {
if ( modifier instanceof PokemonBaseStatModifier ) {
const pokemonStatModifier = modifier as PokemonBaseStatModifier ;
return pokemonStatModifier . pokemonId === this . pokemonId && pokemonStatModifier . stat === this . stat ;
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 ( ) : PersistentModifier {
return new PokemonBaseStatModifier ( this . type as PokemonBaseStatBoosterModifierType , this . pokemonId , this . stat ) ;
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 ;
}
getIcon ( scene : BattleScene ) : Phaser . GameObjects . Container {
const container = super . getIcon ( scene ) ;
2023-04-09 19:15:21 -04:00
const item = scene . add . sprite ( 16 , this . virtualStackCount ? 8 : 16 , 'items' ) ;
2023-03-28 14:54:52 -04:00
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 ) ;
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
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 {
return args . length && args [ 0 ] instanceof Pokemon && ( this . pokemonId === - 1 || ( args [ 0 ] as Pokemon ) . id === this . pokemonId ) ;
}
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-03-30 10:50:46 -04:00
private 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 ) ) ;
pokemon . hp = Math . min ( pokemon . hp + ( this . percent ? ( restorePoints * 0.01 ) * pokemon . getMaxHp ( ) : restorePoints ) , pokemon . getMaxHp ( ) ) ;
}
2023-03-28 14:54:52 -04:00
return true ;
}
}
2023-04-04 21:10:11 -04:00
export class PokemonPpRestoreModifier extends ConsumablePokemonModifier {
private restorePoints : integer ;
constructor ( type : ModifierType , pokemonId : integer , restorePoints : integer ) {
super ( type , pokemonId ) ;
this . restorePoints = restorePoints ;
}
shouldApply ( args : any [ ] ) : boolean {
return super . shouldApply ( args ) && args . length > 1 && typeof ( args [ 1 ] ) === 'number' ;
}
apply ( args : any [ ] ) : boolean {
const pokemon = args [ 0 ] as Pokemon ;
const moveIndex = args [ 1 ] as integer ;
const move = pokemon . moveset [ moveIndex ] ;
move . ppUsed = this . restorePoints >= 0 ? Math . max ( move . ppUsed - this . restorePoints , 0 ) : 0 ;
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 ;
pokemon . level ++ ;
pokemon . exp = getLevelTotalExp ( pokemon . level , pokemon . species . growthRate ) ;
pokemon . levelExp = 0 ;
const scene = pokemon . scene as BattleScene ;
2023-04-10 13:54:06 -04:00
scene . unshiftPhase ( new LevelUpPhase ( scene , 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 {
constructor ( type : TmModifierType , pokemonId : integer ) {
super ( type , pokemonId ) ;
}
apply ( args : any [ ] ) : boolean {
const pokemon = args [ 0 ] as PlayerPokemon ;
const scene = pokemon . scene as BattleScene ;
scene . unshiftPhase ( new LearnMovePhase ( scene , scene . getParty ( ) . indexOf ( pokemon ) , ( this . type as TmModifierType ) . moveId ) ) ;
return true ;
}
}
2023-04-09 19:15:21 -04:00
export class PartyShareModifier extends PersistentModifier {
constructor ( type : ModifierType ) {
super ( type ) ;
}
match ( modifier : Modifier ) {
return modifier instanceof PartyShareModifier ;
}
clone ( ) : PartyShareModifier {
return new PartyShareModifier ( this . type ) ;
}
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 ;
const extraStacks = Math . floor ( modifier . stackCount / Math . max ( party . length - ( this . getStackCount ( ) - 1 ) , 1 ) ) ;
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 ;
scene . addModifier ( newHeldItemModifier , true ) ;
}
}
}
}
return true ;
}
getMaxStackCount ( ) : number {
return 6 ;
}
}
export class HealingBoosterModifier extends PersistentModifier {
private multiplier : number ;
constructor ( type : ModifierType , multiplier : number ) {
super ( type ) ;
this . multiplier = multiplier ;
}
match ( modifier : Modifier ) : boolean {
return modifier instanceof HealingBoosterModifier ;
}
clone ( ) : HealingBoosterModifier {
return new HealingBoosterModifier ( this . type , this . multiplier ) ;
}
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 {
2023-03-30 00:13:56 -04:00
private boostMultiplier : integer ;
constructor ( type : ModifierType , boostPercent : integer ) {
2023-03-28 14:54:52 -04:00
super ( type ) ;
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 {
return new ExpBoosterModifier ( this . type , this . boostMultiplier * 100 ) ;
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-09 19:15:21 -04:00
export class ExpShareModifier extends PersistentModifier {
2023-03-30 23:02:35 -04:00
constructor ( type : ModifierType ) {
super ( type ) ;
}
2023-03-28 14:54:52 -04:00
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 {
return new ExpShareModifier ( this . type ) ;
}
2023-03-30 23:02:35 -04:00
getMaxStackCount ( ) : integer {
return 5 ;
}
2023-03-28 14:54:52 -04:00
}
2023-04-09 19:15:21 -04:00
export class ShinyRateBoosterModifier extends PersistentModifier {
2023-03-28 14:54:52 -04:00
constructor ( type : ModifierType ) {
super ( type ) ;
}
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 {
return new ShinyRateBoosterModifier ( this . type ) ;
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 {
return 5 ;
}
2023-03-28 14:54:52 -04:00
}
2023-04-09 19:15:21 -04:00
export class ExtraModifierModifier extends PersistentModifier {
2023-03-30 10:50:46 -04:00
constructor ( type : ModifierType ) {
super ( type ) ;
}
2023-04-09 19:15:21 -04:00
clone ( ) : ExtraModifierModifier {
return new ExtraModifierModifier ( this . type ) ;
}
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-03-28 14:54:52 -04:00
export enum ModifierTier {
COMMON ,
GREAT ,
ULTRA ,
2023-03-30 00:13:56 -04:00
MASTER ,
LUXURY
2023-03-28 14:54:52 -04:00
} ;
export class ModifierType {
public name : string ;
public description : string ;
public iconImage : string ;
public tier : ModifierTier ;
private newModifierFunc : Function ;
constructor ( name : string , description : string , newModifierFunc : Function , iconImage? : string ) {
this . name = name ;
this . description = description ;
2023-04-08 00:21:44 -04:00
this . iconImage = iconImage || name ? . replace ( /[ \-]/g , '_' ) ? . toLowerCase ( ) ;
2023-03-28 14:54:52 -04:00
this . newModifierFunc = newModifierFunc ;
}
setTier ( tier : ModifierTier ) {
this . tier = tier ;
}
newModifier ( . . . args : any [ ] ) {
return this . newModifierFunc ( this , args ) ;
}
}
class AddPokeballModifierType extends ModifierType {
constructor ( pokeballType : PokeballType , count : integer , iconImage? : string ) {
super ( ` ${ count } x ${ getPokeballName ( pokeballType ) } ` , ` Receive ${ getPokeballName ( pokeballType ) } x ${ count } ` , ( _type , _args ) = > new AddPokeballModifier ( this , pokeballType , count ) , iconImage ) ;
}
}
export abstract class PokemonModifierType extends ModifierType {
public selectFilter : Function ;
constructor ( name : string , description : string , newModifierFunc : Function , selectFilter? : Function , iconImage? : string ) {
super ( name , description , newModifierFunc , iconImage ) ;
this . selectFilter = selectFilter ;
}
}
2023-03-29 00:31:25 -04:00
export class PokemonHpRestoreModifierType extends PokemonModifierType {
2023-04-09 19:15:21 -04:00
protected restorePoints : integer ;
protected percent : boolean ;
2023-03-28 14:54:52 -04:00
2023-04-09 19:15:21 -04:00
constructor ( name : string , restorePoints : integer , percent? : boolean , newModifierFunc? : Function , selectFilter? : Function , iconImage? : string ) {
super ( name , ` Restore ${ restorePoints } ${ percent ? '%' : '' } HP for one POKéMON ` ,
newModifierFunc || ( ( _type , args ) = > new PokemonHpRestoreModifier ( this , ( args [ 0 ] as PlayerPokemon ) . id , this . restorePoints , this . percent , false ) ) ,
2023-04-04 18:28:21 -04:00
selectFilter || ( ( pokemon : PlayerPokemon ) = > {
if ( ! pokemon . hp || pokemon . hp >= pokemon . getMaxHp ( ) )
2023-03-28 14:54:52 -04:00
return PartyUiHandler . NoEffectMessage ;
return null ;
2023-04-04 18:28:21 -04:00
} ) , iconImage ) ;
2023-03-28 14:54:52 -04:00
2023-04-09 19:15:21 -04:00
this . restorePoints = restorePoints ;
this . percent = ! ! percent ;
2023-03-28 14:54:52 -04:00
}
}
2023-03-29 00:31:25 -04:00
export class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
2023-03-28 14:54:52 -04:00
constructor ( name : string , restorePercent : integer , iconImage? : string ) {
2023-04-09 19:15:21 -04:00
super ( name , restorePercent , true , ( _type , args ) = > new PokemonHpRestoreModifier ( this , ( args [ 0 ] as PlayerPokemon ) . id , this . restorePoints , true , true ) ,
2023-04-04 18:28:21 -04:00
( ( pokemon : PlayerPokemon ) = > {
if ( pokemon . hp )
return PartyUiHandler . NoEffectMessage ;
return null ;
} ) , iconImage ) ;
2023-03-28 14:54:52 -04:00
this . description = ` Revive one POKéMON and restore ${ restorePercent } % HP ` ;
this . selectFilter = ( pokemon : PlayerPokemon ) = > {
if ( pokemon . hp )
return PartyUiHandler . NoEffectMessage ;
return null ;
} ;
}
}
2023-04-04 21:10:11 -04:00
export class PokemonLevelIncrementModifierType extends PokemonModifierType {
constructor ( name : string , iconImage? : string ) {
super ( name , ` Increase a POKéMON \ 's level by 1 ` , ( _type , args ) = > new PokemonLevelIncrementModifier ( this , ( args [ 0 ] as PlayerPokemon ) . id ) ,
( _pokemon : PlayerPokemon ) = > null , iconImage ) ;
}
}
export class PokemonPpRestoreModifierType extends PokemonModifierType {
protected restorePoints : integer ;
constructor ( name : string , restorePoints : integer , iconImage? : string ) {
super ( name , ` Restore ${ restorePoints } PP for one POKéMON's move ` , ( _type , args ) = > new PokemonPpRestoreModifier ( this , ( args [ 0 ] as PlayerPokemon ) . id , this . restorePoints ) ,
( pokemon : PlayerPokemon ) = > {
return null ;
} , iconImage ) ;
this . restorePoints = this . restorePoints ;
}
}
2023-03-29 00:31:25 -04:00
export class PokemonBaseStatBoosterModifierType extends PokemonModifierType {
2023-03-28 14:54:52 -04:00
private stat : Stat ;
constructor ( name : string , stat : Stat , _iconImage? : string ) {
2023-03-30 23:02:35 -04:00
super ( name , ` Increases one POKéMON's base ${ getStatName ( stat ) } by 20% ` , ( _type , args ) = > new PokemonBaseStatModifier ( this , ( args [ 0 ] as PlayerPokemon ) . id , this . stat ) ) ;
2023-03-28 14:54:52 -04:00
this . stat = stat ;
}
}
2023-03-29 12:23:52 -04:00
class AllPokemonFullHpRestoreModifierType extends ModifierType {
2023-03-30 10:50:46 -04:00
constructor ( name : string , description? : string , newModifierFunc? : Function , iconImage? : string ) {
super ( name , description || ` Restore 100% HP for all POKéMON ` , newModifierFunc || ( ( _type , _args ) = > new PokemonHpRestoreModifier ( this , - 1 , 100 , false ) ) , iconImage ) ;
}
}
class AllPokemonFullReviveModifierType extends AllPokemonFullHpRestoreModifierType {
2023-03-29 12:23:52 -04:00
constructor ( name : string , iconImage? : string ) {
2023-03-30 10:50:46 -04:00
super ( name , ` Revives all fainted POKéMON, restoring 100% HP ` , ( _type , _args ) = > new PokemonHpRestoreModifier ( this , - 1 , 100 , true ) , iconImage ) ;
2023-03-28 14:54:52 -04:00
}
}
2023-03-31 20:19:57 -04:00
export class ExpBoosterModifierType extends ModifierType {
2023-03-30 00:13:56 -04:00
constructor ( name : string , boostPercent : integer , iconImage? : string ) {
super ( name , ` Increases gain of EXP. Points by ${ boostPercent } % ` , ( ) = > new ExpBoosterModifier ( this , boostPercent ) , iconImage ) ;
}
}
2023-04-08 00:21:44 -04:00
export class TmModifierType extends PokemonModifierType {
public moveId : Moves ;
constructor ( moveId : Moves ) {
super ( ` TM ${ Utils . padInt ( Object . keys ( tmSpecies ) . indexOf ( moveId . toString ( ) ) + 1 , 3 ) } - ${ allMoves [ moveId - 1 ] . name } ` , ` Teach ${ allMoves [ moveId - 1 ] . name } to a POKéMON ` , ( _type , args ) = > new TmModifier ( this , ( args [ 0 ] as PlayerPokemon ) . id ) ,
( pokemon : PlayerPokemon ) = > {
if ( pokemon . compatibleTms . indexOf ( moveId ) === - 1 || pokemon . moveset . filter ( m = > m ? . moveId === moveId ) . length )
return PartyUiHandler . NoEffectMessage ;
return null ;
} , ` tm_ ${ Type [ allMoves [ moveId - 1 ] . type ] . toLowerCase ( ) } ` ) ;
this . moveId = moveId ;
}
}
class ModifierTypeGenerator extends ModifierType {
private genTypeFunc : Function ;
constructor ( genTypeFunc : Function ) {
super ( null , null , null , null ) ;
this . genTypeFunc = genTypeFunc ;
}
generateType ( party : PlayerPokemon [ ] ) {
const ret = this . genTypeFunc ( party ) ;
ret . setTier ( this . tier ) ;
return ret ;
}
}
2023-03-28 14:54:52 -04:00
class WeightedModifierType {
public modifierType : ModifierType ;
2023-03-29 12:23:52 -04:00
public weight : integer | Function ;
2023-03-28 14:54:52 -04:00
2023-03-29 12:23:52 -04:00
constructor ( modifierType : ModifierType , weight : integer | Function ) {
2023-03-28 14:54:52 -04:00
this . modifierType = modifierType ;
this . weight = weight ;
}
setTier ( tier : ModifierTier ) {
this . modifierType . setTier ( tier ) ;
}
}
const modifierPool = {
[ ModifierTier . COMMON ] : [
new WeightedModifierType ( new AddPokeballModifierType ( PokeballType . POKEBALL , 5 , 'pb' ) , 2 ) ,
2023-04-08 00:21:44 -04:00
new WeightedModifierType ( new PokemonHpRestoreModifierType ( 'POTION' , 20 ) , ( party : PlayerPokemon [ ] ) = > {
2023-03-29 12:23:52 -04:00
const thresholdPartyMemberCount = party . filter ( p = > p . getHpRatio ( ) <= 0.9 ) . length ;
return thresholdPartyMemberCount ;
} ) ,
2023-04-08 00:21:44 -04:00
new WeightedModifierType ( new PokemonHpRestoreModifierType ( 'SUPER POTION' , 50 ) , ( party : PlayerPokemon [ ] ) = > {
2023-03-29 12:23:52 -04:00
const thresholdPartyMemberCount = party . filter ( p = > p . getHpRatio ( ) <= 0.75 ) . length ;
return Math . ceil ( thresholdPartyMemberCount / 3 ) ;
2023-04-08 00:21:44 -04:00
} )
2023-03-28 14:54:52 -04:00
] . map ( m = > { m . setTier ( ModifierTier . COMMON ) ; return m ; } ) ,
[ ModifierTier . GREAT ] : [
2023-03-30 23:02:35 -04:00
new WeightedModifierType ( new AddPokeballModifierType ( PokeballType . GREAT_BALL , 5 , 'gb' ) , 3 ) ,
2023-04-08 00:21:44 -04:00
new WeightedModifierType ( new PokemonReviveModifierType ( 'REVIVE' , 50 ) , ( party : PlayerPokemon [ ] ) = > {
2023-03-30 23:02:35 -04:00
const faintedPartyMemberCount = party . filter ( p = > ! p . hp ) . length ;
return faintedPartyMemberCount * 3 ;
} ) ,
2023-04-08 00:21:44 -04:00
new WeightedModifierType ( new PokemonReviveModifierType ( 'MAX REVIVE' , 100 ) , ( party : PlayerPokemon [ ] ) = > {
2023-03-29 12:23:52 -04:00
const faintedPartyMemberCount = party . filter ( p = > ! p . hp ) . length ;
return faintedPartyMemberCount ;
} ) ,
2023-04-09 19:15:21 -04:00
new WeightedModifierType ( new PokemonHpRestoreModifierType ( 'HYPER POTION' , 200 ) , ( party : PlayerPokemon [ ] ) = > {
2023-03-29 12:23:52 -04:00
const thresholdPartyMemberCount = party . filter ( p = > p . getHpRatio ( ) <= 0.6 ) . length ;
2023-03-30 23:02:35 -04:00
return thresholdPartyMemberCount ;
} ) ,
2023-04-08 00:21:44 -04:00
new WeightedModifierType ( new ModifierTypeGenerator ( ( party : PlayerPokemon [ ] ) = > {
const partyMemberCompatibleTms = party . map ( p = > p . compatibleTms ) ;
const uniqueCompatibleTms = partyMemberCompatibleTms . flat ( ) . filter ( ( tm , i , array ) = > array . indexOf ( tm ) === i ) ;
const randTmIndex = Utils . randInt ( uniqueCompatibleTms . length ) ;
return new TmModifierType ( uniqueCompatibleTms [ randTmIndex ] ) ;
} ) , 2 ) ,
2023-04-04 18:28:21 -04:00
new PokemonLevelIncrementModifierType ( 'RARE CANDY' ) ,
2023-03-30 23:02:35 -04:00
new PokemonBaseStatBoosterModifierType ( 'HP-UP' , Stat . HP ) ,
new PokemonBaseStatBoosterModifierType ( 'PROTEIN' , Stat . ATK ) ,
new PokemonBaseStatBoosterModifierType ( 'IRON' , Stat . DEF ) ,
new PokemonBaseStatBoosterModifierType ( 'CALCIUM' , Stat . SPATK ) ,
new PokemonBaseStatBoosterModifierType ( 'ZINC' , Stat . SPDEF ) ,
new PokemonBaseStatBoosterModifierType ( 'CARBOS' , Stat . SPD )
2023-03-28 14:54:52 -04:00
] . map ( m = > { m . setTier ( ModifierTier . GREAT ) ; return m ; } ) ,
[ ModifierTier . ULTRA ] : [
new AddPokeballModifierType ( PokeballType . ULTRA_BALL , 5 , 'ub' ) ,
2023-04-08 00:21:44 -04:00
new WeightedModifierType ( new AllPokemonFullHpRestoreModifierType ( 'MAX POTION' ) , ( party : PlayerPokemon [ ] ) = > {
2023-03-29 12:23:52 -04:00
const thresholdPartyMemberCount = party . filter ( p = > p . getHpRatio ( ) <= 0.5 ) . length ;
return Math . ceil ( thresholdPartyMemberCount / 3 ) ;
} ) ,
2023-04-08 00:21:44 -04:00
new WeightedModifierType ( new AllPokemonFullReviveModifierType ( 'SACRED ASH' ) , ( party : PlayerPokemon [ ] ) = > {
2023-03-30 10:50:46 -04:00
return party . filter ( p = > ! p . hp ) . length >= Math . ceil ( party . length / 2 ) ? 1 : 0 ;
} ) ,
2023-04-09 19:15:21 -04:00
new ModifierType ( 'OVAL CHARM' , 'For every X (no. of party members) items in a POKéMON\'s held item stack, give one to each other party member' ,
( type , _args ) = > new PartyShareModifier ( type ) , 'oval_charm' ) ,
new ModifierType ( 'HEALING CHARM' , 'Doubles the effectiveness of HP restoring items (excludes revives)' , ( type , _args ) = > new HealingBoosterModifier ( type , 2 ) , 'healing_charm' ) ,
2023-03-30 23:02:35 -04:00
new ExpBoosterModifierType ( 'LUCKY EGG' , 25 ) ,
new ModifierType ( 'EXP. SHARE' , 'All POKéMON in your party gain an additional 10% of a battle\'s EXP. Points' , ( type , _args ) = > new ExpShareModifier ( type ) , 'exp_share' )
] . map ( m = > { m . setTier ( ModifierTier . ULTRA ) ; return m ; } ) ,
[ ModifierTier . MASTER ] : [
new AddPokeballModifierType ( PokeballType . MASTER_BALL , 1 , 'mb' ) ,
2023-03-30 10:50:46 -04:00
new WeightedModifierType ( new ModifierType ( 'SHINY CHARM' , 'Dramatically increases the chance of a wild POKéMON being shiny' , ( type , _args ) = > new ShinyRateBoosterModifier ( type ) ) , 2 )
2023-03-30 00:13:56 -04:00
] . map ( m = > { m . setTier ( ModifierTier . MASTER ) ; return m ; } ) ,
[ ModifierTier . LUXURY ] : [
2023-03-30 10:50:46 -04:00
new ExpBoosterModifierType ( 'GOLDEN EGG' , 100 ) ,
new ModifierType ( ` GOLDEN ${ getPokeballName ( PokeballType . POKEBALL ) } ` , 'Adds 1 extra ITEM option at the end of every battle' , ( type , _args ) = > new ExtraModifierModifier ( type ) , 'pb_gold' )
2023-03-30 00:13:56 -04:00
] . map ( m = > { m . setTier ( ModifierTier . LUXURY ) ; return m ; } ) ,
2023-03-28 14:54:52 -04:00
} ;
2023-03-29 12:23:52 -04:00
let modifierPoolThresholds = { } ;
let ignoredPoolIndexes = { } ;
2023-04-08 00:21:44 -04:00
export function regenerateModifierPoolThresholds ( party : PlayerPokemon [ ] ) {
2023-03-29 12:23:52 -04:00
ignoredPoolIndexes = { } ;
modifierPoolThresholds = Object . fromEntries ( new Map ( Object . keys ( modifierPool ) . map ( t = > {
ignoredPoolIndexes [ t ] = [ ] ;
const thresholds = new Map ( ) ;
let i = 0 ;
modifierPool [ t ] . reduce ( ( total : integer , modifierType : ModifierType | WeightedModifierType ) = > {
if ( modifierType instanceof WeightedModifierType ) {
const weightedModifierType = modifierType as WeightedModifierType ;
const weight = weightedModifierType . weight instanceof Function
? ( weightedModifierType . weight as Function ) ( party )
: weightedModifierType . weight as integer ;
if ( weight )
total += weight ;
else {
ignoredPoolIndexes [ t ] . push ( i ++ ) ;
return total ;
}
} else
total ++ ;
thresholds . set ( total , i ++ ) ;
return total ;
} , 0 ) ;
return [ t , Object . fromEntries ( thresholds ) ]
} ) ) ) ;
console . log ( modifierPoolThresholds )
}
2023-03-28 14:54:52 -04:00
2023-04-08 00:21:44 -04:00
export function getModifierTypesForWave ( waveIndex : integer , count : integer , party : PlayerPokemon [ ] ) : Array < ModifierType > {
2023-03-30 00:13:56 -04:00
if ( waveIndex % 10 === 0 )
return modifierPool [ ModifierTier . LUXURY ] ;
const ret = [ ] ;
for ( let m = 0 ; m < count ; m ++ )
2023-04-08 00:21:44 -04:00
ret . push ( getNewModifierType ( party ) ) ;
2023-03-30 00:13:56 -04:00
return ret ;
}
2023-04-08 00:21:44 -04:00
function getNewModifierType ( party : PlayerPokemon [ ] ) {
2023-03-28 14:54:52 -04:00
const tierValue = Utils . randInt ( 256 ) ;
const tier = tierValue >= 52 ? ModifierTier.COMMON : tierValue >= 8 ? ModifierTier.GREAT : tierValue >= 1 ? ModifierTier.ULTRA : ModifierTier.MASTER ;
const thresholds = Object . keys ( modifierPoolThresholds [ tier ] ) ;
const totalWeight = parseInt ( thresholds [ thresholds . length - 1 ] ) ;
const value = Utils . randInt ( totalWeight ) ;
let index : integer ;
for ( let t of thresholds ) {
let threshold = parseInt ( t ) ;
if ( value < threshold ) {
index = modifierPoolThresholds [ tier ] [ threshold ] ;
break ;
}
}
2023-03-29 12:23:52 -04:00
console . log ( index , ignoredPoolIndexes [ tier ] . filter ( i = > i <= index ) . length , ignoredPoolIndexes [ tier ] )
2023-03-28 14:54:52 -04:00
let modifierType : ModifierType | WeightedModifierType = modifierPool [ tier ] [ index ] ;
if ( modifierType instanceof WeightedModifierType )
2023-04-08 00:21:44 -04:00
modifierType = ( modifierType as WeightedModifierType ) . modifierType ;
if ( modifierType instanceof ModifierTypeGenerator )
modifierType = ( modifierType as ModifierTypeGenerator ) . generateType ( party ) ;
2023-03-28 14:54:52 -04:00
return modifierType ;
}