2023-10-03 17:50:31 +01:00
import BattleScene , { startingLevel , startingWave } from "./battle-scene" ;
2023-05-18 16:11:06 +01:00
import { default as Pokemon , PlayerPokemon , EnemyPokemon , PokemonMove , MoveResult , DamageResult , FieldPosition , HitResult } from "./pokemon" ;
2023-04-18 03:44:41 +01:00
import * as Utils from './utils' ;
2023-10-10 01:20:02 +01:00
import { allMoves , applyMoveAttrs , BypassSleepAttr , ChargeAttr , applyFilteredMoveAttrs , HitsTagAttr , MissEffectAttr , MoveAttr , MoveCategory , MoveEffectAttr , MoveFlags , Moves , MultiHitAttr , OverrideMoveEffectAttr , VariableAccuracyAttr , MoveTarget , OneHitKOAttr , getMoveTargets , MoveTargetSet , MoveEffectTrigger , CopyMoveAttr } from "./data/move" ;
2023-04-10 19:12:01 +01:00
import { Mode } from './ui/ui' ;
import { Command } from "./ui/command-ui-handler" ;
2023-04-20 20:46:05 +01:00
import { Stat } from "./data/pokemon-stat" ;
2023-06-06 13:16:07 +01:00
import { BerryModifier , ContactHeldItemTransferChanceModifier , ExpBalanceModifier , ExpBoosterModifier , ExpShareModifier , ExtraModifierModifier , FlinchChanceModifier , HealingBoosterModifier , HitHealModifier , LapsingPersistentModifier , MapModifier , MultipleParticipantExpBonusModifier , PokemonExpBoosterModifier , PokemonHeldItemModifier , PokemonInstantReviveModifier , SwitchEffectTransferModifier , TempBattleStatBoosterModifier , TurnHealModifier , TurnHeldItemTransferModifier } from "./modifier/modifier" ;
2023-04-11 16:04:39 +01:00
import PartyUiHandler , { PartyOption , PartyUiMode } from "./ui/party-ui-handler" ;
2023-07-04 22:50:51 +01:00
import { doPokeballBounceAnim , getPokeballAtlasKey , getPokeballCatchMultiplier , getPokeballTintColor , PokeballType } from "./data/pokeball" ;
2023-04-20 20:46:05 +01:00
import { CommonAnim , CommonBattleAnim , MoveAnim , initMoveAnim , loadMoveAnimAssets } from "./data/battle-anims" ;
2023-05-19 21:13:11 +01:00
import { StatusEffect , getStatusEffectActivationText , getStatusEffectCatchRateMultiplier , getStatusEffectHealText , getStatusEffectObtainText , getStatusEffectOverlapText } from "./data/status-effect" ;
2023-04-10 19:12:01 +01:00
import { SummaryUiMode } from "./ui/summary-ui-handler" ;
import EvolutionSceneHandler from "./ui/evolution-scene-handler" ;
import { EvolutionPhase } from "./evolution-phase" ;
import { BattlePhase } from "./battle-phase" ;
2023-04-20 20:46:05 +01:00
import { BattleStat , getBattleStatLevelChangeDescription , getBattleStatName } from "./data/battle-stat" ;
import { Biome , biomeLinks } from "./data/biome" ;
2023-10-25 19:15:44 +01:00
import { ModifierPoolType , ModifierType , ModifierTypeFunc , ModifierTypeOption , PokemonModifierType , PokemonMoveModifierType , TmModifierType , getPlayerModifierTypeOptionsForWave , modifierTypes , regenerateModifierPoolThresholds } from "./modifier/modifier-type" ;
2023-04-13 00:09:15 +01:00
import SoundFade from "phaser3-rex-plugins/plugins/soundfade" ;
2023-04-29 00:26:41 +01:00
import { BattlerTagLapseType , BattlerTagType , HideSpriteTag as HiddenTag , TrappedTag } from "./data/battler-tag" ;
2023-04-15 06:32:16 +01:00
import { getPokemonMessage } from "./messages" ;
2023-04-18 03:44:41 +01:00
import { Starter } from "./ui/starter-select-ui-handler" ;
2023-04-20 20:46:05 +01:00
import { Gender } from "./data/gender" ;
import { Weather , WeatherType , getRandomWeatherType , getWeatherDamageMessage , getWeatherLapseMessage } from "./data/weather" ;
import { TempBattleStat } from "./data/temp-battle-stat" ;
2023-05-08 23:48:35 +01:00
import { ArenaTagType , ArenaTrapTag , TrickRoomTag } from "./data/arena-tag" ;
2023-05-06 17:13:35 +01:00
import { CheckTrappedAbAttr , PostDefendAbAttr , PostSummonAbAttr , PostTurnAbAttr , PostWeatherLapseAbAttr , PreWeatherDamageAbAttr , ProtectStatAbAttr , SuppressWeatherEffectAbAttr , applyCheckTrappedAbAttrs , applyPostDefendAbAttrs , applyPostSummonAbAttrs , applyPostTurnAbAttrs , applyPostWeatherLapseAbAttrs , applyPreStatChangeAbAttrs , applyPreWeatherEffectAbAttrs } from "./data/ability" ;
2023-04-29 06:40:24 +01:00
import { Unlockables , getUnlockableName } from "./system/unlockables" ;
2023-05-09 17:43:28 +01:00
import { getBiomeKey } from "./arena" ;
2023-10-07 21:08:33 +01:00
import { BattleType , BattlerIndex , TurnCommand } from "./battle" ;
2023-06-01 00:54:57 +01:00
import { GameMode } from "./game-mode" ;
2023-10-24 04:20:05 +01:00
import { Species } from "./data/species" ;
2023-04-10 19:12:01 +01:00
2023-04-28 20:03:42 +01:00
export class CheckLoadPhase extends BattlePhase {
private loaded : boolean ;
constructor ( scene : BattleScene ) {
super ( scene ) ;
this . loaded = false ;
}
start ( ) : void {
if ( ! this . scene . gameData . hasSession ( ) ) {
this . end ( ) ;
return ;
}
this . scene . ui . showText ( 'You currently have a session in progress.\nWould you like to continue where you left off?' , null , ( ) = > {
this . scene . ui . setMode ( Mode . CONFIRM , ( ) = > {
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . scene . gameData . loadSession ( this . scene ) . then ( ( success : boolean ) = > {
if ( success ) {
this . loaded = true ;
this . scene . ui . showText ( 'Session loaded successfully.' , null , ( ) = > this . end ( ) ) ;
} else
this . end ( ) ;
} ) . catch ( err = > {
console . error ( err ) ;
this . scene . ui . showText ( 'Your session data could not be loaded.\nIt may be corrupted. Please reload the page.' , null ) ;
} ) ;
} , ( ) = > {
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . scene . ui . clearText ( ) ;
this . end ( ) ;
} )
} ) ;
}
end ( ) : void {
if ( ! this . loaded ) {
this . scene . arena . preloadBgm ( ) ;
this . scene . pushPhase ( new SelectStarterPhase ( this . scene ) ) ;
} else
2023-10-10 01:20:02 +01:00
this . scene . playBgm ( ) ;
2023-04-28 20:03:42 +01:00
2023-10-07 21:08:33 +01:00
const availablePartyMembers = this . scene . getParty ( ) . filter ( p = > ! p . isFainted ( ) ) . length ;
2023-04-28 20:03:42 +01:00
this . scene . pushPhase ( new EncounterPhase ( this . scene , this . loaded ) ) ;
2023-05-18 16:11:06 +01:00
this . scene . pushPhase ( new SummonPhase ( this . scene , 0 ) ) ;
2023-10-07 21:08:33 +01:00
if ( this . scene . currentBattle . double && availablePartyMembers > 1 )
2023-05-18 16:11:06 +01:00
this . scene . pushPhase ( new SummonPhase ( this . scene , 1 ) ) ;
2023-10-18 23:01:15 +01:00
if ( this . scene . currentBattle . waveIndex > 1 && this . scene . currentBattle . battleType !== BattleType . TRAINER ) {
2023-10-03 17:50:31 +01:00
this . scene . pushPhase ( new CheckSwitchPhase ( this . scene , 0 , this . scene . currentBattle . double ) ) ;
2023-10-07 21:08:33 +01:00
if ( this . scene . currentBattle . double && availablePartyMembers > 1 )
2023-10-03 17:50:31 +01:00
this . scene . pushPhase ( new CheckSwitchPhase ( this . scene , 1 , this . scene . currentBattle . double ) ) ;
}
2023-04-28 20:03:42 +01:00
super . end ( ) ;
}
}
2023-04-10 19:12:01 +01:00
export class SelectStarterPhase extends BattlePhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
start() {
super . start ( ) ;
2023-10-26 21:33:59 +01:00
this . scene . playBgm ( 'menu' ) ;
2023-04-13 00:09:15 +01:00
2023-04-18 03:44:41 +01:00
this . scene . ui . setMode ( Mode . STARTER_SELECT , ( starters : Starter [ ] ) = > {
2023-04-13 00:09:15 +01:00
const party = this . scene . getParty ( ) ;
const loadPokemonAssets : Promise < void > [ ] = [ ] ;
2023-04-18 03:44:41 +01:00
for ( let starter of starters ) {
const starterGender = starter . species . malePercent !== null
? ! starter . female ? Gender.MALE : Gender.FEMALE
: Gender . GENDERLESS ;
2023-04-26 17:50:21 +01:00
const starterPokemon = new PlayerPokemon ( this . scene , starter . species , startingLevel , starter . abilityIndex , starter . formIndex , starterGender , starter . shiny ) ;
2023-10-25 19:15:44 +01:00
if ( starter . pokerus )
starterPokemon . pokerus = true ;
2023-04-18 03:44:41 +01:00
starterPokemon . setVisible ( false ) ;
party . push ( starterPokemon ) ;
loadPokemonAssets . push ( starterPokemon . loadAssets ( ) ) ;
2023-04-13 00:09:15 +01:00
}
Promise . all ( loadPokemonAssets ) . then ( ( ) = > {
this . scene . ui . clearText ( ) ;
this . scene . ui . setMode ( Mode . MESSAGE ) . then ( ( ) = > {
SoundFade . fadeOut ( this . scene . sound . get ( 'menu' ) , 500 , true ) ;
2023-10-10 01:20:02 +01:00
this . scene . time . delayedCall ( 500 , ( ) = > this . scene . playBgm ( ) ) ;
2023-04-13 00:09:15 +01:00
this . end ( ) ;
} ) ;
} ) ;
} ) ;
2023-04-10 19:12:01 +01:00
}
}
2023-05-18 16:11:06 +01:00
type PokemonFunc = ( pokemon : Pokemon ) = > void ;
export abstract class FieldPhase extends BattlePhase {
getOrder ( ) : BattlerIndex [ ] {
const playerField = this . scene . getPlayerField ( ) . filter ( p = > p . isActive ( ) ) as Pokemon [ ] ;
const enemyField = this . scene . getEnemyField ( ) . filter ( p = > p . isActive ( ) ) as Pokemon [ ] ;
let orderedTargets : Pokemon [ ] = playerField . concat ( enemyField ) . sort ( ( a : Pokemon , b : Pokemon ) = > {
const aSpeed = a ? . getBattleStat ( Stat . SPD ) || 0 ;
const bSpeed = b ? . getBattleStat ( Stat . SPD ) || 0 ;
return aSpeed < bSpeed ? 1 : aSpeed > bSpeed ? - 1 : ! Utils . randInt ( 2 ) ? - 1 : 1 ;
} ) ;
const speedReversed = new Utils . BooleanHolder ( false ) ;
this . scene . arena . applyTags ( TrickRoomTag , speedReversed ) ;
if ( speedReversed . value )
orderedTargets = orderedTargets . reverse ( ) ;
return orderedTargets . map ( t = > t . getFieldIndex ( ) + ( ! t . isPlayer ( ) ? BattlerIndex.ENEMY : 0 ) ) ;
}
executeForAll ( func : PokemonFunc ) : void {
const field = this . scene . getField ( ) . filter ( p = > p ? . isActive ( ) ) ;
field . forEach ( pokemon = > func ( pokemon ) ) ;
}
}
export abstract class PokemonPhase extends FieldPhase {
protected battlerIndex : BattlerIndex ;
protected player : boolean ;
protected fieldIndex : integer ;
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene ) ;
if ( battlerIndex === undefined )
battlerIndex = scene . getField ( ) . find ( p = > p ? . isActive ( ) ) . getBattlerIndex ( ) ;
this . battlerIndex = battlerIndex ;
this . player = battlerIndex < 2 ;
this . fieldIndex = battlerIndex % 2 ;
}
getPokemon() {
return this . scene . getField ( ) [ this . battlerIndex ] ;
}
}
export abstract class PartyMemberPokemonPhase extends FieldPhase {
protected partyMemberIndex : integer ;
protected fieldIndex : integer ;
2023-10-07 21:08:33 +01:00
protected player : boolean ;
2023-05-18 16:11:06 +01:00
2023-10-07 21:08:33 +01:00
constructor ( scene : BattleScene , partyMemberIndex : integer , player : boolean ) {
2023-05-18 16:11:06 +01:00
super ( scene ) ;
this . partyMemberIndex = partyMemberIndex ;
this . fieldIndex = partyMemberIndex < this . scene . currentBattle . getBattlerCount ( )
? partyMemberIndex
: - 1 ;
2023-10-07 21:08:33 +01:00
this . player = player ;
2023-05-18 16:11:06 +01:00
}
2023-10-07 21:08:33 +01:00
getParty ( ) : Pokemon [ ] {
return this . player ? this . scene . getParty ( ) : this . scene . getEnemyParty ( ) ;
}
getPokemon ( ) : Pokemon {
return this . getParty ( ) [ this . partyMemberIndex ] ;
}
}
export abstract class PlayerPartyMemberPokemonPhase extends PartyMemberPokemonPhase {
constructor ( scene : BattleScene , partyMemberIndex : integer ) {
super ( scene , partyMemberIndex , true ) ;
}
getPlayerPokemon ( ) : PlayerPokemon {
return super . getPokemon ( ) as PlayerPokemon ;
}
}
export abstract class EnemyPartyMemberPokemonPhase extends PartyMemberPokemonPhase {
constructor ( scene : BattleScene , partyMemberIndex : integer ) {
super ( scene , partyMemberIndex , false ) ;
}
getEnemyPokemon ( ) : EnemyPokemon {
return super . getPokemon ( ) as EnemyPokemon ;
2023-05-18 16:11:06 +01:00
}
}
2023-04-10 19:12:01 +01:00
export class EncounterPhase extends BattlePhase {
2023-04-28 20:03:42 +01:00
private loaded : boolean ;
constructor ( scene : BattleScene , loaded? : boolean ) {
2023-04-10 19:12:01 +01:00
super ( scene ) ;
2023-04-28 20:03:42 +01:00
this . loaded = ! ! loaded ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
2023-04-21 00:44:56 +01:00
this . scene . updateWaveCountText ( ) ;
2023-10-22 01:23:43 +01:00
this . scene . updateMoneyText ( ) ;
2023-04-19 04:54:07 +01:00
2023-05-18 16:11:06 +01:00
const loadEnemyAssets = [ ] ;
2023-04-10 19:12:01 +01:00
const battle = this . scene . currentBattle ;
2023-05-18 16:11:06 +01:00
battle . enemyLevels . forEach ( ( level , e ) = > {
2023-10-18 23:01:15 +01:00
if ( ! this . loaded ) {
if ( battle . battleType === BattleType . TRAINER )
battle . enemyParty [ e ] = battle . trainer . genPartyMember ( e ) ;
else {
const enemySpecies = this . scene . randomSpecies ( battle . waveIndex , level , null , true ) ;
battle . enemyParty [ e ] = new EnemyPokemon ( this . scene , enemySpecies , level ) ;
}
}
2023-10-07 21:08:33 +01:00
const enemyPokemon = this . scene . getEnemyParty ( ) [ e ] ;
if ( e < ( battle . double ? 2 : 1 ) ) {
enemyPokemon . setX ( - 66 + enemyPokemon . getFieldPositionOffset ( ) [ 0 ] ) ;
enemyPokemon . resetSummonData ( ) ;
this . scene . gameData . setPokemonSeen ( enemyPokemon ) ;
}
2023-04-18 06:32:26 +01:00
2023-10-24 04:20:05 +01:00
if ( this . scene . gameMode === GameMode . CLASSIC && battle . waveIndex === 200 && enemyPokemon . species . speciesId === Species . ETERNATUS )
enemyPokemon . formIndex = 1 ;
2023-05-18 16:11:06 +01:00
loadEnemyAssets . push ( enemyPokemon . loadAssets ( ) ) ;
console . log ( enemyPokemon . species . name , enemyPokemon . species . speciesId , enemyPokemon . stats ) ;
} ) ;
2023-04-10 19:12:01 +01:00
2023-10-07 21:08:33 +01:00
if ( battle . battleType === BattleType . TRAINER )
2023-10-18 23:01:15 +01:00
loadEnemyAssets . push ( battle . trainer . loadAssets ( ) . then ( ( ) = > battle . trainer . initSprite ( ) ) ) ;
2023-10-07 21:08:33 +01:00
2023-05-18 16:11:06 +01:00
Promise . all ( loadEnemyAssets ) . then ( ( ) = > {
2023-10-07 21:08:33 +01:00
battle . enemyParty . forEach ( ( enemyPokemon , e ) = > {
if ( e < ( battle . double ? 2 : 1 ) ) {
if ( battle . battleType === BattleType . WILD ) {
this . scene . field . add ( enemyPokemon ) ;
2023-10-23 18:48:56 +01:00
battle . seenEnemyPartyMemberIds . add ( enemyPokemon . id ) ;
2023-10-07 21:08:33 +01:00
const playerPokemon = this . scene . getPlayerPokemon ( ) ;
if ( playerPokemon . visible )
this . scene . field . moveBelow ( enemyPokemon as Pokemon , playerPokemon ) ;
enemyPokemon . tint ( 0 , 0.5 ) ;
} else if ( battle . battleType === BattleType . TRAINER ) {
enemyPokemon . setVisible ( false ) ;
this . scene . currentBattle . trainer . tint ( 0 , 0.5 ) ;
}
if ( battle . double )
enemyPokemon . setFieldPosition ( e ? FieldPosition.RIGHT : FieldPosition.LEFT ) ;
}
2023-05-18 16:11:06 +01:00
} ) ;
2023-04-10 19:12:01 +01:00
2023-04-28 20:03:42 +01:00
if ( ! this . loaded ) {
2023-10-23 18:48:56 +01:00
regenerateModifierPoolThresholds ( this . scene . getEnemyField ( ) , battle . battleType === BattleType . TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD ) ;
2023-04-28 20:03:42 +01:00
this . scene . generateEnemyModifiers ( ) ;
}
2023-04-21 00:44:56 +01:00
2023-04-28 20:03:42 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) . then ( ( ) = > {
if ( ! this . loaded )
this . scene . gameData . saveSession ( this . scene ) ;
this . doEncounter ( ) ;
} ) ;
2023-04-10 19:12:01 +01:00
} ) ;
}
doEncounter() {
2023-10-10 01:20:02 +01:00
this . scene . playBgm ( undefined , true ) ;
2023-05-09 17:43:28 +01:00
if ( startingWave > 10 ) {
2023-05-30 14:46:42 +01:00
for ( let m = 0 ; m < Math . min ( Math . floor ( startingWave / 10 ) , 99 ) ; m ++ )
2023-04-21 00:44:56 +01:00
this . scene . addModifier ( getPlayerModifierTypeOptionsForWave ( ( m + 1 ) * 10 , 1 , this . scene . getParty ( ) ) [ 0 ] . type . newModifier ( ) ) ;
2023-04-19 19:07:38 +01:00
}
this . scene . arena . trySetWeather ( getRandomWeatherType ( this . scene . arena . biomeType ) , false ) ;
2023-05-18 16:11:06 +01:00
const enemyField = this . scene . getEnemyField ( ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
2023-10-07 21:08:33 +01:00
targets : [ this . scene . arenaEnemy , this . scene . currentBattle . trainer , enemyField , this . scene . arenaPlayer , this . scene . trainer ] . flat ( ) ,
x : ( _target , _key , value , fieldIndex : integer ) = > fieldIndex < 2 + ( enemyField . length ) ? value + 300 : value - 300 ,
2023-04-10 19:12:01 +01:00
duration : 2000 ,
2023-10-07 21:08:33 +01:00
onComplete : ( ) = > this . doEncounterCommon ( )
2023-04-10 19:12:01 +01:00
} ) ;
}
2023-10-07 21:08:33 +01:00
doEncounterCommon() {
const enemyField = this . scene . getEnemyField ( ) ;
if ( this . scene . currentBattle . battleType === BattleType . WILD ) {
enemyField . forEach ( enemyPokemon = > {
enemyPokemon . untint ( 100 , 'Sine.easeOut' ) ;
enemyPokemon . cry ( ) ;
enemyPokemon . showInfo ( ) ;
} ) ;
let text = enemyField . length === 1
? ` A wild ${ enemyField [ 0 ] . name } appeared! `
: ` A wild ${ enemyField [ 0 ] . name } \ nand ${ enemyField [ 1 ] . name } appeared! ` ;
this . scene . ui . showText ( text , null , ( ) = > this . end ( ) , 1500 ) ;
} else if ( this . scene . currentBattle . battleType === BattleType . TRAINER ) {
2023-10-18 23:01:15 +01:00
const trainer = this . scene . currentBattle . trainer ;
trainer . untint ( 100 , 'Sine.easeOut' ) ;
trainer . playAnim ( ) ;
const doSummon = ( ) = > {
this . scene . currentBattle . started = true ;
this . scene . playBgm ( undefined ) ;
this . scene . pbTray . showPbTray ( this . scene . getParty ( ) ) ;
this . scene . pbTrayEnemy . showPbTray ( this . scene . getEnemyParty ( ) ) ;
const text = ` ${ this . scene . currentBattle . trainer . getName ( ) } \ nwould like to battle! ` ;
this . scene . ui . showText ( text , null , ( ) = > {
this . scene . tweens . add ( {
targets : this.scene.currentBattle.trainer ,
x : '+=16' ,
y : '-=16' ,
alpha : 0 ,
ease : 'Sine.easeInOut' ,
duration : 750
} ) ;
this . scene . unshiftPhase ( new SummonPhase ( this . scene , 0 , false ) ) ;
if ( this . scene . currentBattle . double )
this . scene . unshiftPhase ( new SummonPhase ( this . scene , 1 , false ) ) ;
this . end ( ) ;
} , 1500 , true ) ;
} ;
if ( ! trainer . config . encounterMessages . length )
doSummon ( ) ;
else {
let message : string ;
this . scene . executeWithSeedOffset ( ( ) = > message = Phaser . Math . RND . pick ( this . scene . currentBattle . trainer . config . encounterMessages ) , this . scene . currentBattle . waveIndex ) ;
const messagePages = message . split ( /\$/g ) . map ( m = > m . trim ( ) ) ;
let showMessageAndSummon = ( ) = > doSummon ( ) ;
for ( let p = messagePages . length - 1 ; p >= 0 ; p -- ) {
const originalFunc = showMessageAndSummon ;
showMessageAndSummon = ( ) = > this . scene . ui . showDialogue ( messagePages [ p ] , trainer . getName ( ) , null , originalFunc , null , true ) ;
}
showMessageAndSummon ( ) ;
}
2023-10-07 21:08:33 +01:00
}
}
2023-04-10 19:12:01 +01:00
end() {
2023-05-18 16:11:06 +01:00
const enemyField = this . scene . getEnemyField ( ) ;
enemyField . forEach ( ( enemyPokemon , e ) = > {
if ( enemyPokemon . shiny )
this . scene . unshiftPhase ( new ShinySparklePhase ( this . scene , BattlerIndex . ENEMY + e ) ) ;
} ) ;
2023-04-24 19:30:21 +01:00
2023-07-04 23:27:07 +01:00
enemyField . map ( p = > this . scene . pushPhase ( new PostSummonPhase ( this . scene , p . getBattlerIndex ( ) ) ) ) ;
2023-04-19 03:09:37 +01:00
2023-04-21 19:05:16 +01:00
// TODO: Remove
2023-04-10 19:12:01 +01:00
//this.scene.unshiftPhase(new SelectModifierPhase(this.scene));
super . end ( ) ;
}
}
export class NextEncounterPhase extends EncounterPhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
doEncounter ( ) : void {
2023-10-10 01:20:02 +01:00
this . scene . playBgm ( undefined , true ) ;
2023-05-18 16:11:06 +01:00
const enemyField = this . scene . getEnemyField ( ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
2023-10-18 23:01:15 +01:00
targets : [ this . scene . arenaEnemy , this . scene . arenaNextEnemy , this . scene . currentBattle . trainer , enemyField , this . scene . lastEnemyTrainer ] . flat ( ) ,
2023-04-10 19:12:01 +01:00
x : '+=300' ,
duration : 2000 ,
onComplete : ( ) = > {
this . scene . arenaEnemy . setX ( this . scene . arenaNextEnemy . x ) ;
2023-05-07 22:05:19 +01:00
this . scene . arenaEnemy . setAlpha ( 1 ) ;
2023-04-10 19:12:01 +01:00
this . scene . arenaNextEnemy . setX ( this . scene . arenaNextEnemy . x - 300 ) ;
2023-10-23 03:45:48 +01:00
if ( this . scene . lastEnemyTrainer )
this . scene . lastEnemyTrainer . destroy ( ) ;
2023-10-07 21:08:33 +01:00
this . doEncounterCommon ( ) ;
2023-04-10 19:12:01 +01:00
}
} ) ;
}
}
export class NewBiomeEncounterPhase extends NextEncounterPhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
doEncounter ( ) : void {
2023-04-19 05:35:06 +01:00
this . scene . arena . trySetWeather ( getRandomWeatherType ( this . scene . arena . biomeType ) , false ) ;
2023-05-18 16:11:06 +01:00
const enemyField = this . scene . getEnemyField ( ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
2023-05-18 16:11:06 +01:00
targets : [ this . scene . arenaEnemy , enemyField ] . flat ( ) ,
2023-05-30 17:15:59 +01:00
x : '+=300' ,
2023-04-10 19:12:01 +01:00
duration : 2000 ,
2023-10-07 21:08:33 +01:00
onComplete : ( ) = > this . doEncounterCommon ( )
2023-04-10 19:12:01 +01:00
} ) ;
}
}
2023-07-04 22:50:51 +01:00
export class PostSummonPhase extends PokemonPhase {
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene , battlerIndex ) ;
}
start() {
super . start ( ) ;
const pokemon = this . getPokemon ( ) ;
this . scene . arena . applyTags ( ArenaTrapTag , pokemon ) ;
applyPostSummonAbAttrs ( PostSummonAbAttr , pokemon ) ;
this . end ( ) ;
}
}
2023-04-12 05:37:56 +01:00
export class SelectBiomePhase extends BattlePhase {
2023-04-10 19:12:01 +01:00
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
start() {
super . start ( ) ;
2023-04-12 05:37:56 +01:00
const currentBiome = this . scene . arena . biomeType ;
const setNextBiome = ( nextBiome : Biome ) = > {
2023-10-27 00:45:35 +01:00
if ( this . scene . currentBattle . waveIndex % 10 === 1 )
2023-10-27 00:07:41 +01:00
this . scene . unshiftPhase ( new PartyHealPhase ( this . scene , false ) ) ;
2023-04-12 05:37:56 +01:00
this . scene . unshiftPhase ( new SwitchBiomePhase ( this . scene , nextBiome ) ) ;
this . end ( ) ;
} ;
2023-06-01 00:54:57 +01:00
if ( this . scene . gameMode === GameMode . CLASSIC && this . scene . currentBattle . waveIndex === this . scene . finalWave - 9 )
2023-04-26 22:40:08 +01:00
setNextBiome ( Biome . END ) ;
2023-06-01 00:54:57 +01:00
else if ( this . scene . gameMode === GameMode . ENDLESS ) {
if ( this . scene . currentBattle . waveIndex % 50 === 0 )
setNextBiome ( Biome . END ) ;
else {
const allBiomes = Utils . getEnumValues ( Biome ) ;
2023-10-18 23:01:15 +01:00
setNextBiome ( allBiomes [ Utils . randSeedInt ( allBiomes . length - 2 , 1 ) ] ) ;
2023-06-01 00:54:57 +01:00
}
} else if ( Array . isArray ( biomeLinks [ currentBiome ] ) ) {
2023-04-27 00:19:39 +01:00
const biomes = biomeLinks [ currentBiome ] as Biome [ ] ;
if ( this . scene . findModifier ( m = > m instanceof MapModifier ) ) {
this . scene . ui . setMode ( Mode . BIOME_SELECT , currentBiome , ( biomeIndex : integer ) = > {
this . scene . ui . setMode ( Mode . MESSAGE ) ;
setNextBiome ( biomes [ biomeIndex ] ) ;
} ) ;
} else
2023-10-18 23:01:15 +01:00
setNextBiome ( biomes [ Utils . randSeedInt ( biomes . length ) ] ) ;
2023-04-27 00:19:39 +01:00
} else
setNextBiome ( biomeLinks [ currentBiome ] as Biome ) ;
2023-04-12 05:37:56 +01:00
}
}
export class SwitchBiomePhase extends BattlePhase {
private nextBiome : Biome ;
constructor ( scene : BattleScene , nextBiome : Biome ) {
super ( scene ) ;
this . nextBiome = nextBiome ;
}
start() {
super . start ( ) ;
2023-10-18 23:01:15 +01:00
if ( this . nextBiome === undefined )
return this . end ( ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
targets : this.scene.arenaEnemy ,
x : '+=300' ,
duration : 2000 ,
onComplete : ( ) = > {
this . scene . arenaEnemy . setX ( this . scene . arenaEnemy . x - 600 ) ;
2023-04-18 03:44:41 +01:00
this . scene . newArena ( this . nextBiome ) ;
2023-04-10 19:12:01 +01:00
2023-05-09 17:43:28 +01:00
const biomeKey = getBiomeKey ( this . nextBiome ) ;
2023-04-10 19:12:01 +01:00
const bgTexture = ` ${ biomeKey } _bg ` ;
this . scene . arenaBgTransition . setTexture ( bgTexture )
this . scene . arenaBgTransition . setAlpha ( 0 ) ;
this . scene . arenaBgTransition . setVisible ( true ) ;
2023-05-09 17:43:28 +01:00
this . scene . arenaPlayerTransition . setBiome ( this . nextBiome ) ;
2023-04-10 19:12:01 +01:00
this . scene . arenaPlayerTransition . setAlpha ( 0 ) ;
this . scene . arenaPlayerTransition . setVisible ( true ) ;
2023-10-10 01:20:02 +01:00
this . scene . time . delayedCall ( 1000 , ( ) = > this . scene . playBgm ( ) ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
2023-10-23 03:45:48 +01:00
targets : [ this . scene . arenaPlayer , this . scene . arenaBgTransition , this . scene . arenaPlayerTransition , this . scene . lastEnemyTrainer ] ,
2023-04-10 19:12:01 +01:00
duration : 1000 ,
delay : 1000 ,
ease : 'Sine.easeInOut' ,
2023-04-30 16:38:46 +01:00
alpha : ( target : any ) = > target === this . scene . arenaPlayer ? 0 : 1 ,
2023-04-10 19:12:01 +01:00
onComplete : ( ) = > {
this . scene . arenaBg . setTexture ( bgTexture ) ;
2023-05-09 17:43:28 +01:00
this . scene . arenaPlayer . setBiome ( this . nextBiome ) ;
2023-04-30 16:38:46 +01:00
this . scene . arenaPlayer . setAlpha ( 1 ) ;
2023-05-09 17:43:28 +01:00
this . scene . arenaEnemy . setBiome ( this . nextBiome ) ;
2023-05-07 22:05:19 +01:00
this . scene . arenaEnemy . setAlpha ( 1 ) ;
2023-05-09 17:43:28 +01:00
this . scene . arenaNextEnemy . setBiome ( this . nextBiome ) ;
2023-04-10 19:12:01 +01:00
this . scene . arenaBgTransition . setVisible ( false ) ;
this . scene . arenaPlayerTransition . setVisible ( false ) ;
2023-10-23 03:45:48 +01:00
if ( this . scene . lastEnemyTrainer )
this . scene . lastEnemyTrainer . destroy ( ) ;
2023-04-10 19:12:01 +01:00
this . end ( ) ;
}
2023-04-30 16:38:46 +01:00
} ) ;
2023-04-10 19:12:01 +01:00
}
} ) ;
}
}
2023-05-18 16:11:06 +01:00
export class SummonPhase extends PartyMemberPokemonPhase {
2023-10-07 21:08:33 +01:00
constructor ( scene : BattleScene , fieldIndex : integer , player? : boolean ) {
super ( scene , fieldIndex , player !== undefined ? player : true ) ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
this . preSummon ( ) ;
}
preSummon ( ) : void {
2023-05-31 17:38:55 +01:00
const partyMember = this . getPokemon ( ) ;
if ( partyMember . isFainted ( ) ) {
2023-10-07 21:08:33 +01:00
const party = this . getParty ( ) ;
2023-05-31 17:38:55 +01:00
const nonFaintedIndex = party . slice ( this . partyMemberIndex ) . findIndex ( p = > ! p . isFainted ( ) ) + this . partyMemberIndex ;
const nonFaintedPartyMember = party [ nonFaintedIndex ] ;
party [ nonFaintedIndex ] = partyMember ;
party [ this . partyMemberIndex ] = nonFaintedPartyMember ;
}
2023-10-07 21:08:33 +01:00
if ( this . player ) {
this . scene . ui . showText ( ` Go! ${ this . getPokemon ( ) . name } ! ` ) ;
2023-10-18 23:01:15 +01:00
if ( this . player )
this . scene . pbTray . hide ( ) ;
2023-10-07 21:08:33 +01:00
this . scene . trainer . play ( 'trainer_m_pb' ) ;
this . scene . tweens . add ( {
targets : this.scene.trainer ,
x : - 36 ,
duration : 1000
} ) ;
this . scene . time . delayedCall ( 750 , ( ) = > this . summon ( ) ) ;
2023-10-18 23:01:15 +01:00
} else {
this . scene . pbTrayEnemy . hide ( ) ;
2023-10-07 21:08:33 +01:00
this . scene . ui . showText ( ` ${ this . scene . currentBattle . trainer . getName ( ) } sent out \ n ${ this . getPokemon ( ) . name } ! ` , null , ( ) = > this . summon ( ) ) ;
2023-10-18 23:01:15 +01:00
}
2023-04-10 19:12:01 +01:00
}
summon ( ) : void {
2023-10-07 21:08:33 +01:00
const pokeball = this . scene . add . sprite ( this . player ? 36 : 248 , this . player ? 80 : 44 , 'pb' , 'pb' ) ;
2023-04-10 19:12:01 +01:00
pokeball . setVisible ( false ) ;
pokeball . setOrigin ( 0.5 , 0.625 ) ;
this . scene . field . add ( pokeball ) ;
2023-10-07 21:08:33 +01:00
const pokemon = this . getPokemon ( ) ;
2023-05-18 16:11:06 +01:00
if ( this . fieldIndex === 1 )
2023-10-07 21:08:33 +01:00
pokemon . setFieldPosition ( FieldPosition . RIGHT , 0 ) ;
else {
const availablePartyMembers = this . getParty ( ) . filter ( p = > ! p . isFainted ( ) ) . length ;
pokemon . setFieldPosition ( ! this . scene . currentBattle . double || availablePartyMembers === 1 ? FieldPosition.CENTER : FieldPosition.LEFT ) ;
}
2023-05-18 16:11:06 +01:00
2023-10-07 21:08:33 +01:00
const fpOffset = pokemon . getFieldPositionOffset ( ) ;
2023-05-18 16:11:06 +01:00
2023-04-10 19:12:01 +01:00
pokeball . setVisible ( true ) ;
2023-05-18 16:11:06 +01:00
this . scene . tweens . add ( {
targets : pokeball ,
duration : 650 ,
2023-10-07 21:08:33 +01:00
x : ( this . player ? 100 : 236 ) + fpOffset [ 0 ]
2023-05-18 16:11:06 +01:00
} ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
targets : pokeball ,
duration : 150 ,
2023-05-18 16:11:06 +01:00
ease : 'Cubic.easeOut' ,
2023-10-07 21:08:33 +01:00
y : ( this . player ? 70 : 34 ) + fpOffset [ 1 ] ,
2023-04-10 19:12:01 +01:00
onComplete : ( ) = > {
this . scene . tweens . add ( {
targets : pokeball ,
duration : 500 ,
ease : 'Cubic.easeIn' ,
2023-05-18 16:11:06 +01:00
angle : 1440 ,
2023-10-07 21:08:33 +01:00
y : ( this . player ? 132 : 86 ) + fpOffset [ 1 ] ,
2023-04-10 19:12:01 +01:00
onComplete : ( ) = > {
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'pb_rel' ) ;
2023-04-10 19:12:01 +01:00
pokeball . destroy ( ) ;
2023-10-07 21:08:33 +01:00
this . scene . add . existing ( pokemon ) ;
this . scene . field . add ( pokemon ) ;
if ( ! this . player ) {
const playerPokemon = this . scene . getPlayerPokemon ( ) as Pokemon ;
2023-10-27 21:20:51 +01:00
if ( playerPokemon ? . visible )
2023-10-07 21:08:33 +01:00
this . scene . field . moveBelow ( pokemon , playerPokemon ) ;
2023-10-23 18:48:56 +01:00
this . scene . currentBattle . seenEnemyPartyMemberIds . add ( pokemon . id ) ;
this . scene . updateModifiers ( false ) ;
2023-10-07 21:08:33 +01:00
}
pokemon . showInfo ( ) ;
pokemon . playAnim ( ) ;
pokemon . setVisible ( true ) ;
pokemon . setScale ( 0.5 ) ;
pokemon . tint ( getPokeballTintColor ( pokemon . pokeball ) ) ;
pokemon . untint ( 250 , 'Sine.easeIn' ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
2023-10-07 21:08:33 +01:00
targets : pokemon ,
2023-04-10 19:12:01 +01:00
duration : 250 ,
ease : 'Sine.easeIn' ,
scale : 1 ,
onComplete : ( ) = > {
2023-10-07 21:08:33 +01:00
pokemon . cry ( ) ;
pokemon . getSprite ( ) . clearTint ( ) ;
pokemon . resetSummonData ( ) ;
2023-04-10 19:12:01 +01:00
this . scene . time . delayedCall ( 1000 , ( ) = > this . end ( ) ) ;
}
} ) ;
}
} ) ;
}
} ) ;
}
2023-07-05 21:13:00 +01:00
onEnd ( ) : void {
2023-06-02 16:41:08 +01:00
const pokemon = this . getPokemon ( ) ;
2023-05-06 05:42:01 +01:00
2023-06-02 16:41:08 +01:00
if ( pokemon . shiny )
this . scene . unshiftPhase ( new ShinySparklePhase ( this . scene , pokemon . getBattlerIndex ( ) ) ) ;
2023-04-10 19:12:01 +01:00
2023-06-02 16:41:08 +01:00
pokemon . resetTurnData ( ) ;
2023-05-06 05:42:01 +01:00
2023-07-04 22:50:51 +01:00
this . queuePostSummon ( ) ;
2023-07-05 21:13:00 +01:00
}
queuePostSummon ( ) : void {
this . scene . pushPhase ( new PostSummonPhase ( this . scene , this . getPokemon ( ) . getBattlerIndex ( ) ) ) ;
}
end() {
this . onEnd ( ) ;
2023-05-04 15:25:11 +01:00
2023-04-10 19:12:01 +01:00
super . end ( ) ;
}
}
export class SwitchSummonPhase extends SummonPhase {
private slotIndex : integer ;
private doReturn : boolean ;
2023-04-29 00:26:41 +01:00
private batonPass : boolean ;
2023-04-10 19:12:01 +01:00
2023-10-07 21:08:33 +01:00
private lastPokemon : Pokemon ;
2023-04-29 00:26:41 +01:00
2023-10-07 21:08:33 +01:00
constructor ( scene : BattleScene , fieldIndex : integer , slotIndex : integer , doReturn : boolean , batonPass : boolean , player? : boolean ) {
super ( scene , fieldIndex , player !== undefined ? player : true ) ;
2023-04-10 19:12:01 +01:00
this . slotIndex = slotIndex ;
this . doReturn = doReturn ;
2023-04-29 00:26:41 +01:00
this . batonPass = batonPass ;
2023-04-10 19:12:01 +01:00
}
preSummon ( ) : void {
2023-05-31 20:04:03 +01:00
if ( ! this . doReturn || ( this . slotIndex !== - 1 && ! this . scene . getParty ( ) [ this . slotIndex ] ) ) {
2023-04-10 19:12:01 +01:00
this . switchAndSummon ( ) ;
return ;
}
2023-10-07 21:08:33 +01:00
const pokemon = this . getPokemon ( ) ;
2023-04-10 19:12:01 +01:00
2023-04-29 00:26:41 +01:00
if ( ! this . batonPass )
2023-10-07 21:08:33 +01:00
this . scene . getEnemyField ( ) . forEach ( enemyPokemon = > enemyPokemon . removeTagsBySourceId ( pokemon . id ) ) ;
2023-04-23 03:14:53 +01:00
2023-10-07 21:08:33 +01:00
this . scene . ui . showText ( this . player ? ` Come back, ${ pokemon . name } ! ` : ` ${ this . scene . currentBattle . trainer . getName ( ) } \ nwithdrew ${ pokemon . name } ! ` ) ;
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'pb_rel' ) ;
2023-10-07 21:08:33 +01:00
pokemon . hideInfo ( ) ;
pokemon . tint ( getPokeballTintColor ( pokemon . pokeball ) , 1 , 250 , 'Sine.easeIn' ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
2023-10-07 21:08:33 +01:00
targets : pokemon ,
2023-04-10 19:12:01 +01:00
duration : 250 ,
ease : 'Sine.easeIn' ,
scale : 0.5 ,
onComplete : ( ) = > {
2023-10-07 21:08:33 +01:00
pokemon . setVisible ( false ) ;
this . scene . field . remove ( pokemon ) ;
2023-04-10 19:12:01 +01:00
this . scene . time . delayedCall ( 750 , ( ) = > this . switchAndSummon ( ) ) ;
}
} ) ;
}
switchAndSummon() {
2023-10-07 21:08:33 +01:00
const party = this . getParty ( ) ;
2023-04-10 19:12:01 +01:00
const switchedPokemon = party [ this . slotIndex ] ;
2023-05-18 16:11:06 +01:00
this . lastPokemon = this . getPokemon ( ) ;
2023-05-31 17:38:55 +01:00
if ( this . batonPass && switchedPokemon ) {
2023-05-18 16:11:06 +01:00
this . scene . getEnemyField ( ) . forEach ( enemyPokemon = > enemyPokemon . transferTagsBySourceId ( this . lastPokemon . id , switchedPokemon . id ) ) ;
2023-04-29 00:26:41 +01:00
if ( ! this . scene . findModifier ( m = > m instanceof SwitchEffectTransferModifier && ( m as SwitchEffectTransferModifier ) . pokemonId === switchedPokemon . id ) ) {
const batonPassModifier = this . scene . findModifier ( m = > m instanceof SwitchEffectTransferModifier
&& ( m as SwitchEffectTransferModifier ) . pokemonId === this . lastPokemon . id ) as SwitchEffectTransferModifier ;
this . scene . tryTransferHeldItemModifier ( batonPassModifier , switchedPokemon , false , false ) ;
}
}
2023-05-31 17:38:55 +01:00
if ( switchedPokemon ) {
party [ this . slotIndex ] = this . lastPokemon ;
party [ this . fieldIndex ] = switchedPokemon ;
2023-10-07 21:08:33 +01:00
this . scene . ui . showText ( this . player ? ` Go! ${ switchedPokemon . name } ! ` : ` ${ this . scene . currentBattle . trainer . getName ( ) } sent out \ n ${ this . getPokemon ( ) . name } ! ` ) ;
2023-05-31 17:38:55 +01:00
this . summon ( ) ;
} else
this . end ( ) ;
2023-04-10 19:12:01 +01:00
}
2023-04-29 00:26:41 +01:00
2023-07-05 21:13:00 +01:00
onEnd ( ) : void {
super . onEnd ( ) ;
2023-07-04 22:50:51 +01:00
2023-05-31 17:38:55 +01:00
const pokemon = this . getPokemon ( ) ;
if ( this . batonPass && pokemon )
pokemon . transferSummon ( this . lastPokemon ) ;
2023-04-29 00:26:41 +01:00
2023-05-18 16:11:06 +01:00
this . lastPokemon ? . resetSummonData ( ) ;
2023-07-05 21:13:00 +01:00
}
2023-04-29 00:26:41 +01:00
2023-07-05 21:13:00 +01:00
queuePostSummon ( ) : void {
this . scene . unshiftPhase ( new PostSummonPhase ( this . scene , this . getPokemon ( ) . getBattlerIndex ( ) ) ) ;
2023-04-29 00:26:41 +01:00
}
2023-04-10 19:12:01 +01:00
}
2023-05-18 16:11:06 +01:00
export class ReturnPhase extends SwitchSummonPhase {
constructor ( scene : BattleScene , fieldIndex : integer ) {
super ( scene , fieldIndex , - 1 , true , false ) ;
}
switchAndSummon ( ) : void {
this . end ( ) ;
}
summon ( ) : void { }
2023-07-04 23:06:12 +01:00
2023-07-05 21:13:00 +01:00
onEnd ( ) : void {
const pokemon = this . getPokemon ( ) ;
pokemon . resetTurnData ( ) ;
pokemon . resetSummonData ( ) ;
}
2023-05-18 16:11:06 +01:00
}
2023-10-18 23:01:15 +01:00
export class ShowTrainerPhase extends BattlePhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
start() {
super . start ( ) ;
this . scene . trainer . setTexture ( 'trainer_m' ) ;
this . scene . tweens . add ( {
targets : this.scene.trainer ,
x : 106 ,
duration : 1000 ,
onComplete : ( ) = > this . end ( )
} ) ;
}
}
2023-05-18 16:11:06 +01:00
export class ToggleDoublePositionPhase extends BattlePhase {
private double : boolean ;
constructor ( scene : BattleScene , double : boolean ) {
super ( scene ) ;
this . double = double ;
}
start() {
super . start ( ) ;
2023-07-06 03:33:27 +01:00
const playerPokemon = this . scene . getPlayerField ( ) . find ( p = > p . isActive ( true ) ) ;
2023-05-18 16:11:06 +01:00
playerPokemon . setFieldPosition ( this . double ? FieldPosition.LEFT : FieldPosition.CENTER , 500 ) . then ( ( ) = > {
2023-07-06 03:33:27 +01:00
if ( playerPokemon . getFieldIndex ( ) === 1 ) {
2023-05-18 16:11:06 +01:00
const party = this . scene . getParty ( ) ;
party [ 1 ] = party [ 0 ] ;
party [ 0 ] = playerPokemon ;
}
this . end ( ) ;
} ) ;
}
}
2023-04-10 19:12:01 +01:00
export class CheckSwitchPhase extends BattlePhase {
2023-05-18 16:11:06 +01:00
protected fieldIndex : integer ;
protected useName : boolean ;
constructor ( scene : BattleScene , fieldIndex : integer , useName : boolean ) {
super ( scene ) ;
this . fieldIndex = fieldIndex ;
this . useName = useName ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
2023-05-18 16:11:06 +01:00
const pokemon = this . scene . getPlayerField ( ) [ this . fieldIndex ] ;
if ( this . scene . field . getAll ( ) . indexOf ( pokemon ) === - 1 ) {
this . scene . unshiftPhase ( new SummonMissingPhase ( this . scene , this . fieldIndex ) ) ;
2023-04-14 04:50:48 +01:00
super . end ( ) ;
return ;
}
2023-05-18 16:11:06 +01:00
if ( ! this . scene . getParty ( ) . slice ( 1 ) . filter ( p = > p . isActive ( ) ) . length ) {
2023-04-20 16:29:26 +01:00
super . end ( ) ;
return ;
}
2023-05-18 16:11:06 +01:00
if ( pokemon . getTag ( BattlerTagType . FRENZY ) ) {
2023-04-15 06:32:16 +01:00
super . end ( ) ;
return ;
}
2023-10-18 23:01:15 +01:00
this . scene . ui . showText ( ` Will you switch \ n ${ this . useName ? pokemon . name : 'Pokémon' } ? ` , null , ( ) = > {
2023-04-10 19:12:01 +01:00
this . scene . ui . setMode ( Mode . CONFIRM , ( ) = > {
2023-04-19 19:07:38 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) ;
2023-05-18 16:11:06 +01:00
this . scene . unshiftPhase ( new SwitchPhase ( this . scene , this . fieldIndex , false , true ) ) ;
2023-04-10 19:12:01 +01:00
this . end ( ) ;
2023-04-19 19:07:38 +01:00
} , ( ) = > {
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . end ( ) ;
} ) ;
2023-04-10 19:12:01 +01:00
} ) ;
}
}
2023-04-14 04:50:48 +01:00
export class SummonMissingPhase extends SummonPhase {
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , fieldIndex : integer ) {
super ( scene , fieldIndex ) ;
2023-04-14 04:50:48 +01:00
}
preSummon ( ) : void {
2023-05-18 16:11:06 +01:00
this . scene . ui . showText ( ` Go! ${ this . getPokemon ( ) . name } ! ` ) ;
2023-04-14 04:50:48 +01:00
this . scene . time . delayedCall ( 250 , ( ) = > this . summon ( ) ) ;
}
}
2023-10-03 17:50:31 +01:00
export class LevelCapPhase extends FieldPhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
start ( ) : void {
super . start ( ) ;
this . scene . ui . setMode ( Mode . MESSAGE ) . then ( ( ) = > {
this . scene . playSoundWithoutBgm ( 'level_up_fanfare' , 1500 ) ;
this . scene . ui . showText ( ` The level cap \ nhas increased to ${ this . scene . getMaxExpLevel ( ) } ! ` , null , ( ) = > this . end ( ) , null , true ) ;
this . executeForAll ( pokemon = > pokemon . updateInfo ( true ) ) ;
} ) ;
}
}
2023-05-18 16:11:06 +01:00
export class TurnInitPhase extends FieldPhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
2023-04-27 19:30:03 +01:00
2023-05-18 16:11:06 +01:00
start() {
super . start ( ) ;
2023-04-27 19:30:03 +01:00
2023-06-01 18:54:52 +01:00
this . scene . getField ( ) . forEach ( ( pokemon , i ) = > {
if ( pokemon ? . isActive ( ) ) {
if ( pokemon . isPlayer ( ) )
this . scene . currentBattle . addParticipant ( pokemon as PlayerPokemon ) ;
2023-04-27 19:30:03 +01:00
2023-06-01 18:54:52 +01:00
pokemon . resetTurnData ( ) ;
2023-04-27 19:30:03 +01:00
2023-06-01 18:54:52 +01:00
this . scene . pushPhase ( pokemon . isPlayer ( ) ? new CommandPhase ( this . scene , i ) : new EnemyCommandPhase ( this . scene , i - BattlerIndex . ENEMY ) ) ;
}
2023-05-18 16:11:06 +01:00
} ) ;
this . scene . pushPhase ( new TurnStartPhase ( this . scene ) ) ;
this . end ( ) ;
2023-04-27 19:30:03 +01:00
}
}
export class CommandPhase extends FieldPhase {
2023-05-18 16:11:06 +01:00
protected fieldIndex : integer ;
constructor ( scene : BattleScene , fieldIndex : integer ) {
super ( scene ) ;
this . fieldIndex = fieldIndex ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
2023-10-27 22:43:53 +01:00
if ( this . fieldIndex ) {
const allyCommand = this . scene . currentBattle . turnCommands [ this . fieldIndex - 1 ] ;
if ( allyCommand . command === Command . BALL || allyCommand . command === Command . RUN )
this . scene . currentBattle . turnCommands [ this . fieldIndex ] = { command : allyCommand.command , skip : true } ;
}
if ( this . scene . currentBattle . turnCommands [ this . fieldIndex ] ? . skip )
return this . end ( ) ;
2023-05-18 16:11:06 +01:00
const playerPokemon = this . scene . getPlayerField ( ) [ this . fieldIndex ] ;
2023-04-13 17:16:36 +01:00
2023-04-21 02:32:48 +01:00
const moveQueue = playerPokemon . getMoveQueue ( ) ;
while ( moveQueue . length && moveQueue [ 0 ]
2023-05-06 05:42:01 +01:00
&& moveQueue [ 0 ] . move && ( ! playerPokemon . getMoveset ( ) . find ( m = > m . moveId === moveQueue [ 0 ] . move )
2023-10-25 14:41:37 +01:00
|| ! playerPokemon . getMoveset ( ) [ playerPokemon . getMoveset ( ) . findIndex ( m = > m . moveId === moveQueue [ 0 ] . move ) ] . isUsable ( playerPokemon , moveQueue [ 0 ] . ignorePP ) ) )
2023-04-21 02:32:48 +01:00
moveQueue . shift ( ) ;
if ( moveQueue . length ) {
const queuedMove = moveQueue [ 0 ] ;
if ( ! queuedMove . move )
2023-05-01 04:58:16 +01:00
this . handleCommand ( Command . FIGHT , - 1 , false ) ;
2023-04-21 02:32:48 +01:00
else {
2023-05-06 05:42:01 +01:00
const moveIndex = playerPokemon . getMoveset ( ) . findIndex ( m = > m . moveId === queuedMove . move ) ;
2023-10-25 14:41:37 +01:00
if ( moveIndex > - 1 && playerPokemon . getMoveset ( ) [ moveIndex ] . isUsable ( playerPokemon , queuedMove . ignorePP ) ) {
2023-05-18 16:11:06 +01:00
this . handleCommand ( Command . FIGHT , moveIndex , queuedMove . ignorePP , { targets : queuedMove.targets , multiple : queuedMove.targets.length > 1 } ) ;
} else
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-04-21 02:32:48 +01:00
}
2023-04-19 23:19:55 +01:00
} else
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-04-10 19:12:01 +01:00
}
2023-04-29 00:26:41 +01:00
handleCommand ( command : Command , cursor : integer , . . . args : any [ ] ) : boolean {
2023-05-18 16:11:06 +01:00
const playerPokemon = this . scene . getPlayerField ( ) [ this . fieldIndex ] ;
const enemyField = this . scene . getEnemyField ( ) ;
2023-04-10 19:12:01 +01:00
let success : boolean ;
2023-04-12 00:08:03 +01:00
2023-04-10 19:12:01 +01:00
switch ( command ) {
case Command . FIGHT :
2023-10-27 13:45:47 +01:00
let useStruggle = false ;
if ( cursor === - 1 || playerPokemon . trySelectMove ( cursor , args [ 0 ] as boolean ) || ( useStruggle = cursor > - 1 && ! playerPokemon . getMoveset ( ) . filter ( m = > m . isUsable ( playerPokemon ) ) . length ) ) {
const moveId = ! useStruggle ? playerPokemon . moveset [ cursor ] . moveId : Moves.STRUGGLE ;
2023-05-18 16:11:06 +01:00
const turnCommand : TurnCommand = { command : Command.FIGHT , cursor : cursor ,
2023-10-27 13:45:47 +01:00
move : cursor > - 1 ? { move : moveId , targets : [ ] } : null , args : args } ;
const moveTargets : MoveTargetSet = args . length < 3 ? getMoveTargets ( playerPokemon , cursor > - 1 ? moveId : Moves.NONE ) : args [ 2 ] ;
2023-05-18 16:11:06 +01:00
console . log ( moveTargets , playerPokemon . name ) ;
if ( moveTargets . targets . length <= 1 || moveTargets . multiple )
turnCommand . move . targets = moveTargets . targets ;
else
this . scene . unshiftPhase ( new SelectTargetPhase ( this . scene , this . fieldIndex ) ) ;
this . scene . currentBattle . turnCommands [ this . fieldIndex ] = turnCommand ;
2023-04-10 19:12:01 +01:00
success = true ;
2023-05-06 05:42:01 +01:00
} else if ( cursor < playerPokemon . getMoveset ( ) . length ) {
const move = playerPokemon . getMoveset ( ) [ cursor ] ;
2023-10-25 14:41:37 +01:00
if ( playerPokemon . summonData . disabledMove === move . moveId ) {
2023-04-20 03:51:46 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . scene . ui . showText ( ` ${ move . getName ( ) } is disabled! ` , null , ( ) = > {
this . scene . ui . clearText ( ) ;
2023-10-19 04:16:38 +01:00
this . scene . ui . setMode ( Mode . FIGHT , this . fieldIndex ) ;
2023-04-20 03:51:46 +01:00
} , null , true ) ;
}
2023-04-10 19:12:01 +01:00
}
break ;
case Command . BALL :
2023-04-29 21:26:09 +01:00
if ( this . scene . arena . biomeType === Biome . END ) {
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-04-29 21:26:09 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) ;
2023-10-18 23:01:15 +01:00
this . scene . ui . showText ( ` A strange force \ nprevents using Poké Balls. ` , null , ( ) = > {
this . scene . ui . showText ( null , 0 ) ;
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-10-18 23:01:15 +01:00
} , null , true ) ;
} else if ( this . scene . currentBattle . battleType === BattleType . TRAINER ) {
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-10-18 23:01:15 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . scene . ui . showText ( ` You can't catch \ nanother trainer's Pokémon! ` , null , ( ) = > {
2023-04-30 05:51:33 +01:00
this . scene . ui . showText ( null , 0 ) ;
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-04-29 21:26:09 +01:00
} , null , true ) ;
2023-10-27 22:43:53 +01:00
} else {
2023-06-02 16:41:08 +01:00
const targets = this . scene . getEnemyField ( ) . filter ( p = > p . isActive ( true ) ) . map ( p = > p . getBattlerIndex ( ) ) ;
2023-10-27 22:43:53 +01:00
if ( targets . length > 1 ) {
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . scene . ui . showText ( ` You can only throw a Poké Ball \ nwhen there is one Pokémon remaining! ` , null , ( ) = > {
this . scene . ui . showText ( null , 0 ) ;
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
} , null , true ) ;
} else if ( cursor < 4 ) {
this . scene . currentBattle . turnCommands [ this . fieldIndex ] = { command : Command.BALL , cursor : cursor } ;
if ( targets . length > 1 )
this . scene . unshiftPhase ( new SelectTargetPhase ( this . scene , this . fieldIndex ) ) ;
else {
this . scene . currentBattle . turnCommands [ this . fieldIndex ] . targets = targets ;
if ( this . fieldIndex )
this . scene . currentBattle . turnCommands [ this . fieldIndex - 1 ] . skip = true ;
}
success = true ;
}
2023-04-10 19:12:01 +01:00
}
break ;
case Command . POKEMON :
2023-05-08 15:03:57 +01:00
case Command . RUN :
const isSwitch = command === Command . POKEMON ;
2023-10-18 23:01:15 +01:00
if ( ! isSwitch && this . scene . currentBattle . battleType === BattleType . TRAINER ) {
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-10-18 23:01:15 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . scene . ui . showText ( ` You can't run \ nfrom a trainer battle! ` , null , ( ) = > {
2023-04-23 03:14:53 +01:00
this . scene . ui . showText ( null , 0 ) ;
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-04-23 03:14:53 +01:00
} , null , true ) ;
2023-10-18 23:01:15 +01:00
} else {
const trapTag = playerPokemon . findTag ( t = > t instanceof TrappedTag ) as TrappedTag ;
const trapped = new Utils . BooleanHolder ( false ) ;
const batonPass = isSwitch && args [ 0 ] as boolean ;
if ( ! batonPass )
enemyField . forEach ( enemyPokemon = > applyCheckTrappedAbAttrs ( CheckTrappedAbAttr , enemyPokemon , trapped ) ) ;
if ( batonPass || ( ! trapTag && ! trapped . value ) ) {
this . scene . currentBattle . turnCommands [ this . fieldIndex ] = isSwitch
? { command : Command.POKEMON , cursor : cursor , args : args }
: { command : Command.RUN } ;
success = true ;
2023-10-27 22:43:53 +01:00
if ( this . fieldIndex )
this . scene . currentBattle . turnCommands [ this . fieldIndex - 1 ] . skip = true ;
2023-10-18 23:01:15 +01:00
} else if ( trapTag ) {
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-10-18 23:01:15 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . scene . ui . showText ( ` ${ this . scene . getPokemonById ( trapTag . sourceId ) . name } 's ${ trapTag . getMoveName ( ) } \ nprevents ${ isSwitch ? 'switching' : 'fleeing' } ! ` , null , ( ) = > {
this . scene . ui . showText ( null , 0 ) ;
2023-10-20 16:38:41 +01:00
this . scene . ui . setMode ( Mode . COMMAND , this . fieldIndex ) ;
2023-10-18 23:01:15 +01:00
} , null , true ) ;
}
}
2023-04-10 19:12:01 +01:00
break ;
}
2023-04-12 05:37:56 +01:00
2023-05-18 16:11:06 +01:00
if ( success )
2023-04-10 19:12:01 +01:00
this . end ( ) ;
return success ;
}
2023-10-19 04:16:38 +01:00
cancel() {
if ( this . fieldIndex ) {
this . scene . unshiftPhase ( new CommandPhase ( this . scene , 0 ) ) ;
this . scene . unshiftPhase ( new CommandPhase ( this . scene , 1 ) ) ;
this . end ( ) ;
}
}
getFieldIndex ( ) : integer {
return this . fieldIndex ;
}
2023-05-18 16:11:06 +01:00
getPokemon ( ) : PlayerPokemon {
return this . scene . getPlayerField ( ) [ this . fieldIndex ] ;
}
2023-04-10 19:12:01 +01:00
end() {
this . scene . ui . setMode ( Mode . MESSAGE ) . then ( ( ) = > super . end ( ) ) ;
}
}
2023-05-18 16:11:06 +01:00
export class EnemyCommandPhase extends FieldPhase {
protected fieldIndex : integer ;
constructor ( scene : BattleScene , fieldIndex : integer ) {
super ( scene ) ;
this . fieldIndex = fieldIndex ;
}
start() {
super . start ( ) ;
const enemyPokemon = this . scene . getEnemyField ( ) [ this . fieldIndex ] ;
const nextMove = enemyPokemon . getNextMove ( ) ;
this . scene . currentBattle . turnCommands [ this . fieldIndex + BattlerIndex . ENEMY ] =
{ command : Command.FIGHT , move : nextMove } ;
this . end ( ) ;
}
}
export class SelectTargetPhase extends PokemonPhase {
constructor ( scene : BattleScene , fieldIndex : integer ) {
super ( scene , fieldIndex ) ;
}
start() {
super . start ( ) ;
const turnCommand = this . scene . currentBattle . turnCommands [ this . fieldIndex ] ;
const move = turnCommand . move ? . move ;
this . scene . ui . setMode ( Mode . TARGET_SELECT , this . fieldIndex , move , ( cursor : integer ) = > {
this . scene . ui . setMode ( Mode . MESSAGE ) ;
if ( cursor === - 1 ) {
this . scene . currentBattle . turnCommands [ this . fieldIndex ] = null ;
this . scene . unshiftPhase ( new CommandPhase ( this . scene , this . fieldIndex ) ) ;
} else
turnCommand . targets = [ cursor ] ;
2023-10-28 00:34:55 +01:00
if ( turnCommand . command === Command . BALL && this . fieldIndex )
2023-10-27 22:43:53 +01:00
this . scene . currentBattle . turnCommands [ this . fieldIndex - 1 ] . skip = true ;
2023-05-18 16:11:06 +01:00
this . end ( ) ;
} ) ;
}
}
export class TurnStartPhase extends FieldPhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
start() {
super . start ( ) ;
const field = this . scene . getField ( ) ;
const order = this . getOrder ( ) ;
const moveOrder = order . slice ( 0 ) ;
moveOrder . sort ( ( a , b ) = > {
const aCommand = this . scene . currentBattle . turnCommands [ a ] ;
const bCommand = this . scene . currentBattle . turnCommands [ b ] ;
if ( aCommand . command !== bCommand . command ) {
if ( aCommand . command === Command . FIGHT )
return 1 ;
else if ( bCommand . command === Command . FIGHT )
return - 1 ;
} else if ( aCommand . command === Command . FIGHT ) {
const aPriority = allMoves [ aCommand . move . move ] . priority ;
const bPriority = allMoves [ bCommand . move . move ] . priority ;
if ( aPriority !== bPriority )
return aPriority < bPriority ? 1 : - 1 ;
}
const aIndex = order . indexOf ( a ) ;
const bIndex = order . indexOf ( b ) ;
return aIndex < bIndex ? - 1 : aIndex > bIndex ? 1 : 0 ;
} ) ;
for ( let o of moveOrder ) {
const pokemon = field [ o ] ;
const turnCommand = this . scene . currentBattle . turnCommands [ o ] ;
2023-10-27 22:43:53 +01:00
if ( turnCommand . skip )
continue ;
2023-05-18 16:11:06 +01:00
switch ( turnCommand . command ) {
case Command . FIGHT :
const queuedMove = turnCommand . move ;
if ( ! queuedMove )
continue ;
const move = pokemon . getMoveset ( ) . find ( m = > m . moveId === queuedMove . move ) || new PokemonMove ( queuedMove . move ) ;
if ( pokemon . isPlayer ( ) ) {
if ( turnCommand . cursor === - 1 )
this . scene . pushPhase ( new MovePhase ( this . scene , pokemon , turnCommand . targets || turnCommand . move . targets , move ) ) ;
else {
const playerPhase = new MovePhase ( this . scene , pokemon , turnCommand . targets || turnCommand . move . targets , move , false , queuedMove . ignorePP ) ;
this . scene . pushPhase ( playerPhase ) ;
}
} else
this . scene . pushPhase ( new MovePhase ( this . scene , pokemon , turnCommand . targets || turnCommand . move . targets , move , false , queuedMove . ignorePP ) ) ;
break ;
case Command . BALL :
this . scene . unshiftPhase ( new AttemptCapturePhase ( this . scene , turnCommand . targets [ 0 ] % 2 , turnCommand . cursor ) ) ;
break ;
case Command . POKEMON :
case Command . RUN :
const isSwitch = turnCommand . command === Command . POKEMON ;
if ( isSwitch )
this . scene . unshiftPhase ( new SwitchSummonPhase ( this . scene , pokemon . getFieldIndex ( ) , turnCommand . cursor , true , turnCommand . args [ 0 ] as boolean ) ) ;
else
this . scene . unshiftPhase ( new AttemptRunPhase ( this . scene , pokemon . getFieldIndex ( ) ) ) ;
break ;
}
}
2023-07-04 21:16:50 +01:00
if ( this . scene . arena . weather )
this . scene . pushPhase ( new WeatherEffectPhase ( this . scene , this . scene . arena . weather ) ) ;
2023-05-18 16:11:06 +01:00
for ( let o of order ) {
if ( field [ o ] . status && field [ o ] . status . isPostTurn ( ) )
this . scene . pushPhase ( new PostTurnStatusEffectPhase ( this . scene , o ) ) ;
}
this . scene . pushPhase ( new TurnEndPhase ( this . scene ) ) ;
this . end ( ) ;
}
}
2023-04-27 19:30:03 +01:00
export class TurnEndPhase extends FieldPhase {
2023-04-13 17:16:36 +01:00
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
start() {
2023-04-19 03:09:37 +01:00
super . start ( ) ;
2023-05-18 16:11:06 +01:00
this . scene . currentBattle . incrementTurn ( this . scene ) ;
2023-04-19 23:19:55 +01:00
const handlePokemon = ( pokemon : Pokemon ) = > {
2023-04-22 00:30:04 +01:00
pokemon . lapseTags ( BattlerTagLapseType . TURN_END ) ;
2023-04-19 23:19:55 +01:00
2023-10-25 14:41:37 +01:00
if ( pokemon . summonData . disabledMove && ! -- pokemon . summonData . disabledTurns ) {
pokemon . summonData . disabledMove = Moves . NONE ;
this . scene . pushPhase ( new MessagePhase ( this . scene , ` ${ allMoves [ pokemon . summonData . disabledMove ] . name } is disabled \ nno more! ` ) ) ;
2023-04-19 23:19:55 +01:00
}
2023-04-15 22:40:18 +01:00
2023-04-21 00:44:56 +01:00
const hasUsableBerry = ! ! this . scene . findModifier ( m = > m instanceof BerryModifier && m . shouldApply ( [ pokemon ] ) , pokemon . isPlayer ( ) ) ;
2023-04-20 20:46:05 +01:00
if ( hasUsableBerry )
2023-05-18 16:11:06 +01:00
this . scene . pushPhase ( new BerryPhase ( this . scene , pokemon . getBattlerIndex ( ) ) ) ;
2023-04-20 20:46:05 +01:00
2023-04-21 01:15:16 +01:00
this . scene . applyModifiers ( TurnHealModifier , pokemon . isPlayer ( ) , pokemon ) ;
2023-05-31 16:20:06 +01:00
applyPostTurnAbAttrs ( PostTurnAbAttr , pokemon ) ;
2023-05-02 20:56:41 +01:00
2023-05-05 21:55:46 +01:00
this . scene . applyModifiers ( TurnHeldItemTransferModifier , pokemon . isPlayer ( ) , pokemon ) ;
2023-04-23 15:24:22 +01:00
2023-04-19 23:19:55 +01:00
pokemon . battleSummonData . turnCount ++ ;
} ;
2023-05-18 16:11:06 +01:00
this . executeForAll ( handlePokemon ) ;
2023-04-22 00:30:04 +01:00
this . scene . arena . lapseTags ( ) ;
2023-04-13 17:16:36 +01:00
2023-04-19 19:07:38 +01:00
if ( this . scene . arena . weather && ! this . scene . arena . weather . lapse ( ) )
this . scene . arena . trySetWeather ( WeatherType . NONE , false ) ;
2023-04-13 17:16:36 +01:00
this . end ( ) ;
}
}
2023-04-19 03:09:37 +01:00
export class BattleEndPhase extends BattlePhase {
start() {
super . start ( ) ;
2023-05-18 16:11:06 +01:00
for ( let pokemon of this . scene . getField ( ) ) {
if ( pokemon )
pokemon . resetBattleSummonData ( ) ;
}
2023-04-21 00:44:56 +01:00
this . scene . clearEnemyModifiers ( ) ;
2023-06-01 16:22:34 +01:00
const lapsingModifiers = this . scene . findModifiers ( m = > m instanceof LapsingPersistentModifier ) as LapsingPersistentModifier [ ] ;
for ( let m of lapsingModifiers ) {
2023-04-19 03:09:37 +01:00
if ( ! m . lapse ( ) )
this . scene . removeModifier ( m ) ;
}
this . scene . updateModifiers ( ) . then ( ( ) = > this . end ( ) ) ;
}
}
2023-05-18 16:11:06 +01:00
export class NewBattlePhase extends BattlePhase {
start() {
super . start ( ) ;
2023-04-10 19:12:01 +01:00
2023-05-18 16:11:06 +01:00
this . scene . newBattle ( ) ;
2023-04-10 19:12:01 +01:00
2023-05-18 16:11:06 +01:00
this . end ( ) ;
2023-04-10 19:12:01 +01:00
}
}
2023-04-14 06:08:44 +01:00
export class CommonAnimPhase extends PokemonPhase {
private anim : CommonAnim ;
2023-05-18 16:11:06 +01:00
private targetIndex : integer ;
constructor ( scene : BattleScene , battlerIndex : BattlerIndex , targetIndex : BattlerIndex , anim : CommonAnim ) {
super ( scene , battlerIndex ) ;
2023-04-14 06:08:44 +01:00
this . anim = anim ;
2023-05-18 16:11:06 +01:00
this . targetIndex = targetIndex ;
2023-04-14 06:08:44 +01:00
}
start() {
2023-05-19 18:02:58 +01:00
new CommonBattleAnim ( this . anim , this . getPokemon ( ) , this . targetIndex !== undefined ? ( this . player ? this . scene . getEnemyField ( ) : this . scene . getPlayerField ( ) ) [ this . targetIndex ] : this . getPokemon ( ) ) . play ( this . scene , ( ) = > {
2023-04-14 06:08:44 +01:00
this . end ( ) ;
} ) ;
}
}
2023-05-18 16:11:06 +01:00
export class MovePhase extends BattlePhase {
2023-04-10 19:12:01 +01:00
protected pokemon : Pokemon ;
2023-05-18 16:11:06 +01:00
protected targets : BattlerIndex [ ] ;
2023-04-10 19:12:01 +01:00
protected move : PokemonMove ;
2023-04-16 23:40:32 +01:00
protected followUp : boolean ;
2023-05-01 04:58:16 +01:00
protected ignorePp : boolean ;
2023-04-12 00:08:03 +01:00
protected cancelled : boolean ;
2023-04-10 19:12:01 +01:00
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , pokemon : Pokemon , targets : BattlerIndex [ ] , move : PokemonMove , followUp? : boolean , ignorePp? : boolean ) {
2023-04-10 19:12:01 +01:00
super ( scene ) ;
this . pokemon = pokemon ;
2023-05-18 16:11:06 +01:00
this . targets = targets ;
2023-04-10 19:12:01 +01:00
this . move = move ;
2023-04-16 23:40:32 +01:00
this . followUp = ! ! followUp ;
2023-05-01 04:58:16 +01:00
this . ignorePp = ! ! ignorePp ;
2023-04-12 00:08:03 +01:00
this . cancelled = false ;
2023-04-10 19:12:01 +01:00
}
canMove ( ) : boolean {
2023-10-25 14:41:37 +01:00
return this . pokemon . isActive ( true ) && this . move . isUsable ( this . pokemon , this . ignorePp ) && ! ! this . targets . length ;
2023-04-10 19:12:01 +01:00
}
2023-04-15 06:32:16 +01:00
cancel ( ) : void {
this . cancelled = true ;
}
2023-04-10 19:12:01 +01:00
start() {
super . start ( ) ;
2023-04-19 23:19:55 +01:00
console . log ( Moves [ this . move . moveId ] ) ;
2023-05-04 21:38:56 +01:00
if ( ! this . canMove ( ) ) {
2023-10-25 14:41:37 +01:00
if ( this . pokemon . summonData . disabledMove === this . move . moveId )
2023-05-04 21:38:56 +01:00
this . scene . queueMessage ( ` ${ this . move . getName ( ) } is disabled! ` ) ;
this . end ( ) ;
return ;
}
2023-05-18 16:11:06 +01:00
console . log ( this . targets ) ;
const targets = this . scene . getField ( ) . filter ( p = > {
2023-06-02 16:41:08 +01:00
if ( p ? . isActive ( true ) && this . targets . indexOf ( p . getBattlerIndex ( ) ) > - 1 ) {
2023-05-18 16:11:06 +01:00
const hiddenTag = p . getTag ( HiddenTag ) ;
if ( hiddenTag && ! this . move . getMove ( ) . getAttrs ( HitsTagAttr ) . filter ( hta = > ( hta as HitsTagAttr ) . tagType === hiddenTag . tagType ) . length )
return false ;
return true ;
}
return false ;
} ) ;
2023-04-16 23:40:32 +01:00
2023-04-19 04:54:07 +01:00
if ( ! this . followUp && this . canMove ( ) )
2023-04-22 00:30:04 +01:00
this . pokemon . lapseTags ( BattlerTagLapseType . MOVE ) ;
2023-04-15 06:32:16 +01:00
2023-04-12 00:08:03 +01:00
const doMove = ( ) = > {
2023-04-21 02:32:48 +01:00
const moveQueue = this . pokemon . getMoveQueue ( ) ;
2023-05-18 16:11:06 +01:00
if ( ( moveQueue . length && moveQueue [ 0 ] . move === Moves . NONE ) || ! targets . length ) {
2023-04-21 02:32:48 +01:00
moveQueue . shift ( ) ;
this . cancel ( ) ;
}
2023-04-12 00:08:03 +01:00
if ( this . cancelled ) {
2023-05-18 16:11:06 +01:00
this . pokemon . pushMoveHistory ( { move : Moves.NONE , result : MoveResult.FAIL } ) ;
2023-04-12 00:08:03 +01:00
this . end ( ) ;
return ;
}
2023-04-16 23:40:32 +01:00
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( getPokemonMessage ( this . pokemon , ` used \ n ${ this . move . getName ( ) } ! ` ) , 500 ) ;
2023-04-21 02:32:48 +01:00
if ( ! moveQueue . length || ! moveQueue . shift ( ) . ignorePP )
2023-04-13 17:16:36 +01:00
this . move . ppUsed ++ ;
2023-04-16 23:40:32 +01:00
2023-10-10 01:20:02 +01:00
if ( ! allMoves [ this . move . moveId ] . getAttrs ( CopyMoveAttr ) . length )
this . scene . currentBattle . lastMove = this . move . moveId ;
2023-05-18 16:11:06 +01:00
// Assume conditions affecting targets only apply to moves with a single target
let success = this . move . getMove ( ) . applyConditions ( this . pokemon , targets [ 0 ] , this . move . getMove ( ) ) ;
2023-04-24 19:30:21 +01:00
if ( success && this . scene . arena . isMoveWeatherCancelled ( this . move . getMove ( ) ) )
success = false ;
if ( success )
this . scene . unshiftPhase ( this . getEffectPhase ( ) ) ;
else {
2023-05-18 16:11:06 +01:00
this . pokemon . pushMoveHistory ( { move : this.move.moveId , targets : this.targets , result : MoveResult.FAIL , virtual : this.move.virtual } ) ;
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( 'But it failed!' ) ;
2023-04-24 19:30:21 +01:00
}
2023-04-15 22:40:18 +01:00
2023-04-12 00:08:03 +01:00
this . end ( ) ;
} ;
2023-04-16 23:40:32 +01:00
if ( ! this . followUp && this . pokemon . status && ! this . pokemon . status . isPostTurn ( ) ) {
2023-04-12 00:08:03 +01:00
this . pokemon . status . incrementTurn ( ) ;
let activated = false ;
let healed = false ;
2023-04-16 23:40:32 +01:00
2023-04-12 00:08:03 +01:00
switch ( this . pokemon . status . effect ) {
case StatusEffect . PARALYSIS :
if ( Utils . randInt ( 4 ) === 0 ) {
activated = true ;
this . cancelled = true ;
}
break ;
case StatusEffect . SLEEP :
2023-05-18 16:11:06 +01:00
applyMoveAttrs ( BypassSleepAttr , this . pokemon , null , this . move . getMove ( ) ) ;
2023-04-12 00:08:03 +01:00
healed = this . pokemon . status . turnCount === this . pokemon . status . cureTurn ;
2023-04-22 00:30:04 +01:00
activated = ! healed && ! this . pokemon . getTag ( BattlerTagType . BYPASS_SLEEP ) ;
2023-04-12 00:08:03 +01:00
this . cancelled = activated ;
break ;
case StatusEffect . FREEZE :
healed = Utils . randInt ( 5 ) === 0 ;
activated = ! healed ;
this . cancelled = activated ;
break ;
}
if ( activated ) {
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( getPokemonMessage ( this . pokemon , getStatusEffectActivationText ( this . pokemon . status . effect ) ) ) ;
2023-05-18 16:11:06 +01:00
this . scene . unshiftPhase ( new CommonAnimPhase ( this . scene , this . pokemon . getBattlerIndex ( ) , undefined , CommonAnim . POISON + ( this . pokemon . status . effect - 1 ) ) ) ;
2023-04-15 06:32:16 +01:00
doMove ( ) ;
2023-04-12 00:08:03 +01:00
} else {
if ( healed ) {
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( getPokemonMessage ( this . pokemon , getStatusEffectHealText ( this . pokemon . status . effect ) ) ) ;
2023-04-12 00:08:03 +01:00
this . pokemon . resetStatus ( ) ;
2023-04-20 20:46:05 +01:00
this . pokemon . updateInfo ( ) ;
2023-04-12 00:08:03 +01:00
}
doMove ( ) ;
}
} else
doMove ( ) ;
2023-04-10 19:12:01 +01:00
}
2023-04-16 23:40:32 +01:00
2023-04-10 19:12:01 +01:00
getEffectPhase ( ) : MoveEffectPhase {
2023-05-18 16:11:06 +01:00
return new MoveEffectPhase ( this . scene , this . pokemon . getBattlerIndex ( ) , this . targets , this . move ) ;
2023-04-10 19:12:01 +01:00
}
2023-05-18 16:11:06 +01:00
end() {
if ( ! this . followUp && this . canMove ( ) )
this . scene . unshiftPhase ( new MoveEndPhase ( this . scene , this . pokemon . getBattlerIndex ( ) ) ) ;
2023-04-10 19:12:01 +01:00
2023-05-18 16:11:06 +01:00
super . end ( ) ;
2023-04-10 19:12:01 +01:00
}
}
2023-05-18 16:11:06 +01:00
class MoveEffectPhase extends PokemonPhase {
2023-04-10 19:12:01 +01:00
protected move : PokemonMove ;
2023-05-18 16:11:06 +01:00
protected targets : BattlerIndex [ ] ;
2023-04-10 19:12:01 +01:00
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex , targets : BattlerIndex [ ] , move : PokemonMove ) {
super ( scene , battlerIndex ) ;
2023-04-10 19:12:01 +01:00
this . move = move ;
2023-05-18 16:11:06 +01:00
this . targets = targets ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
const user = this . getUserPokemon ( ) ;
2023-05-18 16:11:06 +01:00
const targets = this . getTargets ( ) ;
2023-04-10 19:12:01 +01:00
2023-04-13 17:16:36 +01:00
const overridden = new Utils . BooleanHolder ( false ) ;
2023-04-10 21:17:25 +01:00
2023-05-18 16:11:06 +01:00
// Assume single target for override
applyMoveAttrs ( OverrideMoveEffectAttr , user , this . getTarget ( ) , this . move . getMove ( ) , overridden ) . then ( ( ) = > {
2023-04-10 21:17:25 +01:00
2023-04-13 17:16:36 +01:00
if ( overridden . value ) {
2023-04-10 21:17:25 +01:00
this . end ( ) ;
2023-04-13 17:16:36 +01:00
return ;
2023-04-10 19:12:01 +01:00
}
2023-04-13 17:16:36 +01:00
2023-04-22 00:30:04 +01:00
user . lapseTags ( BattlerTagLapseType . MOVE_EFFECT ) ;
2023-04-13 17:16:36 +01:00
if ( user . turnData . hitsLeft === undefined ) {
const hitCount = new Utils . IntegerHolder ( 1 ) ;
2023-05-18 16:11:06 +01:00
// Assume single target for multi hit
applyMoveAttrs ( MultiHitAttr , user , this . getTarget ( ) , this . move . getMove ( ) , hitCount ) ;
2023-04-13 17:16:36 +01:00
user . turnData . hitCount = 0 ;
2023-05-03 05:00:21 +01:00
user . turnData . hitsLeft = user . turnData . hitCount = hitCount . value ;
2023-04-13 17:16:36 +01:00
}
2023-05-18 16:11:06 +01:00
const moveHistoryEntry = { move : this.move.moveId , targets : this.targets , result : MoveResult.PENDING , virtual : this.move.virtual } ;
user . pushMoveHistory ( moveHistoryEntry ) ;
const targetHitChecks = Object . fromEntries ( targets . map ( p = > [ p . getBattlerIndex ( ) , this . hitCheck ( p ) ] ) ) ;
if ( targets . length === 1 && ! targetHitChecks [ this . targets [ 0 ] ] ) {
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( getPokemonMessage ( user , '\'s\nattack missed!' ) ) ;
2023-05-18 16:11:06 +01:00
moveHistoryEntry . result = MoveResult . MISS ;
applyMoveAttrs ( MissEffectAttr , user , null , this . move . getMove ( ) ) ;
2023-04-13 17:16:36 +01:00
this . end ( ) ;
return ;
2023-04-10 19:12:01 +01:00
}
2023-04-18 17:30:47 +01:00
2023-05-18 16:11:06 +01:00
// Move animation only needs one target
new MoveAnim ( this . move . getMove ( ) . id as Moves , user , this . getTarget ( ) ? . getBattlerIndex ( ) ) . play ( this . scene , ( ) = > {
for ( let target of targets ) {
if ( ! targetHitChecks [ target . getBattlerIndex ( ) ] ) {
this . scene . queueMessage ( getPokemonMessage ( user , '\'s\nattack missed!' ) ) ;
if ( moveHistoryEntry . result === MoveResult . PENDING )
moveHistoryEntry . result = MoveResult . MISS ;
applyMoveAttrs ( MissEffectAttr , user , null , this . move . getMove ( ) ) ;
continue ;
2023-04-25 06:32:48 +01:00
}
2023-05-18 16:11:06 +01:00
const isProtected = ! this . move . getMove ( ) . hasFlag ( MoveFlags . IGNORE_PROTECT ) && target . lapseTag ( BattlerTagType . PROTECTED ) ;
moveHistoryEntry . result = MoveResult . SUCCESS ;
2023-10-10 01:20:02 +01:00
const hitResult = ! isProtected ? target . apply ( user , this . move ) : HitResult . NO_EFFECT ;
2023-07-10 15:54:22 +01:00
applyFilteredMoveAttrs ( ( attr : MoveAttr ) = > attr instanceof MoveEffectAttr && ( attr as MoveEffectAttr ) . trigger === MoveEffectTrigger . PRE_APPLY ,
user , target , this . move . getMove ( ) ) ;
2023-05-18 16:11:06 +01:00
2023-07-06 03:23:50 +01:00
if ( hitResult !== HitResult . FAIL ) {
2023-05-18 16:11:06 +01:00
const chargeEffect = ! ! this . move . getMove ( ) . getAttrs ( ChargeAttr ) . find ( ca = > ( ca as ChargeAttr ) . chargeEffect ) ;
// Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present
if ( ! chargeEffect )
2023-07-10 15:54:22 +01:00
applyFilteredMoveAttrs ( ( attr : MoveAttr ) = > attr instanceof MoveEffectAttr && ( attr as MoveEffectAttr ) . trigger === MoveEffectTrigger . POST_APPLY
&& ( attr as MoveEffectAttr ) . selfTarget , user , target , this . move . getMove ( ) ) ;
2023-07-06 03:23:50 +01:00
if ( hitResult !== HitResult . NO_EFFECT ) {
2023-07-10 15:54:22 +01:00
applyFilteredMoveAttrs ( ( attr : MoveAttr ) = > attr instanceof MoveEffectAttr && ( attr as MoveEffectAttr ) . trigger === MoveEffectTrigger . POST_APPLY
&& ! ( attr as MoveEffectAttr ) . selfTarget , user , target , this . move . getMove ( ) ) ;
2023-07-06 03:23:50 +01:00
if ( hitResult < HitResult . NO_EFFECT ) {
const flinched = new Utils . BooleanHolder ( false ) ;
user . scene . applyModifiers ( FlinchChanceModifier , user . isPlayer ( ) , user , flinched ) ;
if ( flinched . value )
target . addTag ( BattlerTagType . FLINCHED , undefined , this . move . moveId , user . id ) ;
}
if ( ! isProtected && ! chargeEffect ) {
2023-07-10 15:54:22 +01:00
applyFilteredMoveAttrs ( ( attr : MoveAttr ) = > attr instanceof MoveEffectAttr && ( attr as MoveEffectAttr ) . trigger === MoveEffectTrigger . HIT ,
user , target , this . move . getMove ( ) ) ;
2023-07-06 03:23:50 +01:00
if ( ! target . isFainted ( ) )
applyPostDefendAbAttrs ( PostDefendAbAttr , target , user , this . move , hitResult ) ;
if ( this . move . getMove ( ) . hasFlag ( MoveFlags . MAKES_CONTACT ) )
this . scene . applyModifiers ( ContactHeldItemTransferChanceModifier , this . player , user , target . getFieldIndex ( ) ) ;
}
2023-05-18 16:11:06 +01:00
}
2023-05-04 17:57:55 +01:00
}
2023-04-23 15:24:22 +01:00
}
2023-04-24 05:38:28 +01:00
this . end ( ) ;
2023-04-13 17:16:36 +01:00
} ) ;
2023-04-10 19:12:01 +01:00
} ) ;
}
2023-04-10 21:17:25 +01:00
end() {
const user = this . getUserPokemon ( ) ;
2023-05-29 16:39:47 +01:00
if ( -- user . turnData . hitsLeft >= 1 && this . getTarget ( ) )
2023-04-10 21:17:25 +01:00
this . scene . unshiftPhase ( this . getNewHitPhase ( ) ) ;
2023-04-13 17:16:36 +01:00
else {
2023-05-03 05:00:21 +01:00
if ( user . turnData . hitCount > 1 )
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( ` Hit ${ user . turnData . hitCount } time(s)! ` ) ;
2023-04-21 00:44:56 +01:00
this . scene . applyModifiers ( HitHealModifier , this . player , user ) ;
2023-04-13 17:16:36 +01:00
}
2023-04-10 21:17:25 +01:00
super . end ( ) ;
}
2023-05-18 16:11:06 +01:00
hitCheck ( target : Pokemon ) : boolean {
2023-05-01 19:41:44 +01:00
if ( this . move . getMove ( ) . moveTarget === MoveTarget . USER )
2023-04-18 17:30:47 +01:00
return true ;
2023-04-13 17:16:36 +01:00
2023-05-18 16:11:06 +01:00
const hiddenTag = target . getTag ( HiddenTag ) ;
if ( hiddenTag && ! this . move . getMove ( ) . getAttrs ( HitsTagAttr ) . filter ( hta = > ( hta as HitsTagAttr ) . tagType === hiddenTag . tagType ) . length )
return false ;
2023-04-19 19:07:38 +01:00
2023-07-04 17:59:58 +01:00
if ( this . getUserPokemon ( ) . getTag ( BattlerTagType . IGNORE_ACCURACY ) && ( this . getUserPokemon ( ) . getLastXMoves ( ) . find ( ( ) = > true ) ? . targets || [ ] ) . indexOf ( target . getBattlerIndex ( ) ) > - 1 )
2023-04-28 01:12:25 +01:00
return true ;
2023-04-19 19:07:38 +01:00
const moveAccuracy = new Utils . NumberHolder ( this . move . getMove ( ) . accuracy ) ;
2023-07-05 17:10:23 +01:00
applyMoveAttrs ( VariableAccuracyAttr , this . getUserPokemon ( ) , target , this . move . getMove ( ) , moveAccuracy ) ;
2023-04-19 19:07:38 +01:00
if ( moveAccuracy . value === - 1 )
return true ;
2023-05-08 23:48:35 +01:00
if ( ! this . move . getMove ( ) . getAttrs ( OneHitKOAttr ) . length && this . scene . arena . getTag ( ArenaTagType . GRAVITY ) )
moveAccuracy . value = Math . floor ( moveAccuracy . value * 1.67 ) ;
2023-04-13 17:16:36 +01:00
2023-07-28 15:23:37 +01:00
const userAccuracyLevel = new Utils . IntegerHolder ( this . getUserPokemon ( ) . summonData . battleStats [ BattleStat . ACC ] ) ;
const targetEvasionLevel = new Utils . IntegerHolder ( target . summonData . battleStats [ BattleStat . EVA ] ) ;
this . scene . applyModifiers ( TempBattleStatBoosterModifier , this . player , TempBattleStat . ACC , userAccuracyLevel ) ;
const rand = Utils . randInt ( 100 , 1 ) ;
let accuracyMultiplier = 1 ;
if ( userAccuracyLevel . value !== targetEvasionLevel . value ) {
accuracyMultiplier = userAccuracyLevel . value > targetEvasionLevel . value
? ( 3 + Math . min ( userAccuracyLevel . value - targetEvasionLevel . value , 6 ) ) / 3
: 3 / ( 3 + Math . min ( targetEvasionLevel . value - userAccuracyLevel . value , 6 ) ) ;
2023-04-10 21:17:25 +01:00
}
2023-07-28 15:23:37 +01:00
return rand <= moveAccuracy . value * accuracyMultiplier ;
2023-04-10 21:17:25 +01:00
}
2023-04-10 19:12:01 +01:00
getUserPokemon ( ) : Pokemon {
2023-05-18 16:11:06 +01:00
return ( this . player ? this . scene . getPlayerField ( ) : this . scene . getEnemyField ( ) ) [ this . fieldIndex ] ;
2023-04-10 19:12:01 +01:00
}
2023-05-18 16:11:06 +01:00
getTargets ( ) : Pokemon [ ] {
2023-06-02 16:41:08 +01:00
return this . scene . getField ( ) . filter ( p = > p ? . isActive ( true ) && this . targets . indexOf ( p . getBattlerIndex ( ) ) > - 1 ) ;
2023-04-10 19:12:01 +01:00
}
2023-04-10 21:17:25 +01:00
2023-05-18 16:11:06 +01:00
getTarget ( ) : Pokemon {
return this . getTargets ( ) . find ( ( ) = > true ) ;
2023-04-10 19:12:01 +01:00
}
2023-04-10 21:17:25 +01:00
getNewHitPhase() {
2023-05-18 16:11:06 +01:00
return new MoveEffectPhase ( this . scene , this . battlerIndex , this . targets , this . move ) ;
2023-04-10 21:17:25 +01:00
}
2023-04-10 19:12:01 +01:00
}
2023-04-16 23:40:32 +01:00
export class MoveEndPhase extends PokemonPhase {
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene , battlerIndex ) ;
2023-04-16 23:40:32 +01:00
}
start() {
super . start ( ) ;
2023-04-22 00:30:04 +01:00
this . getPokemon ( ) . lapseTags ( BattlerTagLapseType . AFTER_MOVE ) ;
2023-04-16 23:40:32 +01:00
this . end ( ) ;
}
}
2023-04-14 04:04:51 +01:00
export class MoveAnimTestPhase extends BattlePhase {
private moveQueue : Moves [ ] ;
constructor ( scene : BattleScene , moveQueue? : Moves [ ] ) {
super ( scene ) ;
2023-04-21 02:32:48 +01:00
this . moveQueue = moveQueue || Utils . getEnumValues ( Moves ) . slice ( 1 ) ;
2023-04-14 04:04:51 +01:00
}
start() {
const moveQueue = this . moveQueue . slice ( 0 ) ;
this . playMoveAnim ( moveQueue , true ) ;
}
playMoveAnim ( moveQueue : Moves [ ] , player : boolean ) {
const moveId = player ? moveQueue [ 0 ] : moveQueue . shift ( ) ;
if ( moveId === undefined ) {
this . playMoveAnim ( this . moveQueue . slice ( 0 ) , true ) ;
return ;
2023-04-25 03:32:12 +01:00
} else if ( player )
console . log ( Moves [ moveId ] ) ;
2023-04-14 04:04:51 +01:00
initMoveAnim ( moveId ) . then ( ( ) = > {
loadMoveAnimAssets ( this . scene , [ moveId ] , true )
. then ( ( ) = > {
2023-05-18 16:11:06 +01:00
new MoveAnim ( moveId , player ? this . scene . getPlayerPokemon ( ) : this . scene . getEnemyPokemon ( ) , 0 ) . play ( this . scene , ( ) = > {
2023-04-14 04:04:51 +01:00
if ( player )
this . playMoveAnim ( moveQueue , false ) ;
else
this . playMoveAnim ( moveQueue , true ) ;
} ) ;
} ) ;
} ) ;
}
}
2023-04-27 19:30:03 +01:00
export class ShowAbilityPhase extends PokemonPhase {
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene , battlerIndex ) ;
2023-04-27 19:30:03 +01:00
}
start() {
this . scene . abilityBar . showAbility ( this . getPokemon ( ) ) ;
this . end ( ) ;
}
}
2023-04-11 04:15:06 +01:00
export class StatChangePhase extends PokemonPhase {
private stats : BattleStat [ ] ;
2023-04-27 04:33:13 +01:00
private selfTarget : boolean ;
2023-04-11 04:15:06 +01:00
private levels : integer ;
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex , selfTarget : boolean , stats : BattleStat [ ] , levels : integer ) {
super ( scene , battlerIndex ) ;
2023-04-11 04:15:06 +01:00
2023-04-15 06:32:16 +01:00
const allStats = Utils . getEnumValues ( BattleStat ) ;
2023-04-27 19:30:03 +01:00
this . selfTarget = selfTarget ;
2023-04-15 06:32:16 +01:00
this . stats = stats . map ( s = > s !== BattleStat . RAND ? s : allStats [ Utils . randInt ( BattleStat . SPD + 1 ) ] ) ;
2023-04-11 04:15:06 +01:00
this . levels = levels ;
}
start() {
const pokemon = this . getPokemon ( ) ;
2023-04-27 04:33:13 +01:00
const filteredStats = this . stats . filter ( stat = > {
const cancelled = new Utils . BooleanHolder ( false ) ;
if ( ! this . selfTarget && this . levels < 0 )
2023-05-06 17:13:35 +01:00
applyPreStatChangeAbAttrs ( ProtectStatAbAttr , this . getPokemon ( ) , stat , cancelled ) ;
2023-04-27 04:33:13 +01:00
return ! cancelled . value ;
} ) ;
2023-04-11 04:15:06 +01:00
const battleStats = this . getPokemon ( ) . summonData . battleStats ;
2023-04-27 04:33:13 +01:00
const relLevels = filteredStats . map ( stat = > ( this . levels >= 1 ? Math . min ( battleStats [ stat ] + this . levels , 6 ) : Math . max ( battleStats [ stat ] + this . levels , - 6 ) ) - battleStats [ stat ] ) ;
2023-04-11 04:15:06 +01:00
const end = ( ) = > {
2023-04-27 04:33:13 +01:00
const messages = this . getStatChangeMessages ( filteredStats , relLevels ) ;
2023-04-11 04:15:06 +01:00
for ( let message of messages )
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( message ) ;
2023-04-11 04:15:06 +01:00
2023-04-27 04:33:13 +01:00
for ( let stat of filteredStats )
2023-04-11 04:15:06 +01:00
pokemon . summonData . battleStats [ stat ] = Math . max ( Math . min ( pokemon . summonData . battleStats [ stat ] + this . levels , 6 ) , - 6 ) ;
this . end ( ) ;
} ;
if ( relLevels . filter ( l = > l ) . length ) {
pokemon . enableMask ( ) ;
const pokemonMaskSprite = pokemon . maskSprite ;
2023-04-27 04:33:13 +01:00
const statSprite = this . scene . add . tileSprite ( ( this . player ? 106 : 236 ) * 6 , ( ( this . player ? 148 : 84 ) + ( this . levels >= 1 ? 160 : 0 ) ) * 6 , 156 , 316 , 'battle_stats' , filteredStats . length > 1 ? 'mix' : BattleStat [ filteredStats [ 0 ] ] . toLowerCase ( ) ) ;
2023-04-11 04:15:06 +01:00
statSprite . setAlpha ( 0 ) ;
statSprite . setScale ( 6 ) ;
statSprite . setOrigin ( 0.5 , 1 ) ;
2023-10-21 13:58:39 +01:00
this . scene . playSound ( ` stat_ ${ this . levels >= 1 ? 'up' : 'down' } ` ) ;
2023-04-11 04:15:06 +01:00
statSprite . setMask ( new Phaser . Display . Masks . BitmapMask ( this . scene , pokemonMaskSprite ) ) ;
this . scene . tweens . add ( {
targets : statSprite ,
duration : 250 ,
alpha : 0.8375 ,
onComplete : ( ) = > {
this . scene . tweens . add ( {
targets : statSprite ,
delay : 1000 ,
duration : 250 ,
alpha : 0
} ) ;
}
} ) ;
2023-04-11 14:41:11 +01:00
2023-04-11 04:15:06 +01:00
this . scene . tweens . add ( {
targets : statSprite ,
duration : 1500 ,
y : ` ${ this . levels >= 1 ? '-' : '+' } = ${ 160 * 6 } `
} ) ;
this . scene . time . delayedCall ( 1750 , ( ) = > {
pokemon . disableMask ( ) ;
end ( ) ;
} ) ;
} else
end ( ) ;
}
2023-04-27 04:33:13 +01:00
getStatChangeMessages ( stats : BattleStat [ ] , relLevels : integer [ ] ) : string [ ] {
2023-04-11 04:15:06 +01:00
const messages : string [ ] = [ ] ;
2023-04-27 04:33:13 +01:00
for ( let s = 0 ; s < stats . length ; s ++ )
messages . push ( getPokemonMessage ( this . getPokemon ( ) , ` 's ${ getBattleStatName ( stats [ s ] ) } ${ getBattleStatLevelChangeDescription ( Math . abs ( relLevels [ s ] ) , this . levels >= 1 ) } ! ` ) ) ;
2023-04-11 04:15:06 +01:00
return messages ;
}
}
2023-04-19 19:07:38 +01:00
export class WeatherEffectPhase extends CommonAnimPhase {
private weather : Weather ;
2023-04-27 19:30:03 +01:00
constructor ( scene : BattleScene , weather : Weather ) {
2023-05-18 16:11:06 +01:00
super ( scene , undefined , undefined , CommonAnim . SUNNY + ( weather . weatherType - 1 ) ) ;
2023-04-19 19:07:38 +01:00
this . weather = weather ;
}
start() {
if ( this . weather . isDamaging ( ) ) {
2023-04-27 19:30:03 +01:00
const cancelled = new Utils . BooleanHolder ( false ) ;
2023-05-18 16:11:06 +01:00
this . executeForAll ( ( pokemon : Pokemon ) = > applyPreWeatherEffectAbAttrs ( SuppressWeatherEffectAbAttr , pokemon , this . weather , cancelled ) ) ;
2023-04-27 19:30:03 +01:00
if ( ! cancelled . value ) {
const inflictDamage = ( pokemon : Pokemon ) = > {
const cancelled = new Utils . BooleanHolder ( false ) ;
applyPreWeatherEffectAbAttrs ( PreWeatherDamageAbAttr , pokemon , this . weather , cancelled ) ;
if ( cancelled . value )
return ;
this . scene . queueMessage ( getWeatherDamageMessage ( this . weather . weatherType , pokemon ) ) ;
2023-05-18 16:11:06 +01:00
this . scene . unshiftPhase ( new DamagePhase ( this . scene , pokemon . getBattlerIndex ( ) ) ) ;
2023-04-27 19:30:03 +01:00
pokemon . damage ( Math . ceil ( pokemon . getMaxHp ( ) / 16 ) ) ;
} ;
2023-05-18 16:11:06 +01:00
this . executeForAll ( ( pokemon : Pokemon ) = > {
2023-04-27 19:30:03 +01:00
const immune = ! pokemon || ! ! pokemon . getTypes ( ) . filter ( t = > this . weather . isTypeDamageImmune ( t ) ) . length ;
if ( ! immune )
inflictDamage ( pokemon ) ;
} ) ;
}
2023-04-19 19:07:38 +01:00
}
2023-04-27 19:30:03 +01:00
this . scene . ui . showText ( getWeatherLapseMessage ( this . weather . weatherType ) , null , ( ) = > {
2023-05-18 16:11:06 +01:00
this . executeForAll ( ( pokemon : Pokemon ) = > applyPostWeatherLapseAbAttrs ( PostWeatherLapseAbAttr , pokemon , this . weather ) ) ;
2023-04-27 19:30:03 +01:00
super . start ( ) ;
} ) ;
2023-04-19 19:07:38 +01:00
}
}
2023-04-10 19:12:01 +01:00
export class ObtainStatusEffectPhase extends PokemonPhase {
private statusEffect : StatusEffect ;
2023-04-16 23:40:32 +01:00
private cureTurn : integer ;
2023-04-24 19:30:21 +01:00
private sourceText : string ;
2023-04-10 19:12:01 +01:00
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex , statusEffect : StatusEffect , cureTurn? : integer , sourceText? : string ) {
super ( scene , battlerIndex ) ;
2023-04-12 00:08:03 +01:00
this . statusEffect = statusEffect ;
2023-04-16 23:40:32 +01:00
this . cureTurn = cureTurn ;
2023-04-24 19:30:21 +01:00
this . sourceText = sourceText ;
2023-04-10 19:12:01 +01:00
}
start() {
const pokemon = this . getPokemon ( ) ;
2023-04-12 00:08:03 +01:00
if ( ! pokemon . status ) {
if ( pokemon . trySetStatus ( this . statusEffect ) ) {
2023-04-16 23:40:32 +01:00
if ( this . cureTurn )
pokemon . status . cureTurn = this . cureTurn ;
2023-04-12 00:08:03 +01:00
pokemon . updateInfo ( true ) ;
new CommonBattleAnim ( CommonAnim . POISON + ( this . statusEffect - 1 ) , pokemon ) . play ( this . scene , ( ) = > {
2023-04-24 19:30:21 +01:00
this . scene . queueMessage ( getPokemonMessage ( pokemon , getStatusEffectObtainText ( this . statusEffect , this . sourceText ) ) ) ;
2023-04-12 00:08:03 +01:00
if ( pokemon . status . isPostTurn ( ) )
2023-05-18 16:11:06 +01:00
this . scene . pushPhase ( new PostTurnStatusEffectPhase ( this . scene , this . battlerIndex ) ) ;
2023-04-12 00:08:03 +01:00
this . end ( ) ;
} ) ;
return ;
}
} else if ( pokemon . status . effect === this . statusEffect )
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( getPokemonMessage ( pokemon , getStatusEffectOverlapText ( this . statusEffect ) ) ) ;
2023-04-12 00:08:03 +01:00
this . end ( ) ;
}
}
export class PostTurnStatusEffectPhase extends PokemonPhase {
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene , battlerIndex ) ;
2023-04-12 00:08:03 +01:00
}
start() {
const pokemon = this . getPokemon ( ) ;
2023-06-02 16:41:08 +01:00
if ( pokemon ? . isActive ( true ) && pokemon . status && pokemon . status . isPostTurn ( ) ) {
2023-04-12 00:08:03 +01:00
pokemon . status . incrementTurn ( ) ;
new CommonBattleAnim ( CommonAnim . POISON + ( pokemon . status . effect - 1 ) , pokemon ) . play ( this . scene , ( ) = > {
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( getPokemonMessage ( pokemon , getStatusEffectActivationText ( pokemon . status . effect ) ) ) ;
2023-04-12 00:08:03 +01:00
switch ( pokemon . status . effect ) {
case StatusEffect . POISON :
case StatusEffect . BURN :
2023-04-16 23:40:32 +01:00
pokemon . damage ( Math . max ( pokemon . getMaxHp ( ) >> 3 , 1 ) ) ;
2023-04-12 00:08:03 +01:00
break ;
case StatusEffect . TOXIC :
2023-04-16 23:40:32 +01:00
pokemon . damage ( Math . max ( Math . floor ( ( pokemon . getMaxHp ( ) / 16 ) * pokemon . status . turnCount ) , 1 ) ) ;
2023-04-12 00:08:03 +01:00
break ;
}
pokemon . updateInfo ( ) . then ( ( ) = > this . end ( ) ) ;
} ) ;
2023-04-10 19:12:01 +01:00
} else
this . end ( ) ;
}
}
export class MessagePhase extends BattlePhase {
private text : string ;
2023-04-12 00:08:03 +01:00
private callbackDelay : integer ;
2023-04-10 19:12:01 +01:00
private prompt : boolean ;
2023-05-07 22:05:19 +01:00
private promptDelay : integer ;
2023-04-10 19:12:01 +01:00
2023-05-07 22:05:19 +01:00
constructor ( scene : BattleScene , text : string , callbackDelay? : integer , prompt? : boolean , promptDelay? : integer ) {
2023-04-10 19:12:01 +01:00
super ( scene ) ;
this . text = text ;
2023-04-12 00:08:03 +01:00
this . callbackDelay = callbackDelay ;
2023-04-10 19:12:01 +01:00
this . prompt = prompt ;
2023-05-07 22:05:19 +01:00
this . promptDelay = promptDelay ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
2023-10-18 23:01:15 +01:00
if ( this . text . indexOf ( '$' ) > - 1 ) {
const pageIndex = this . text . indexOf ( '$' ) ;
this . scene . unshiftPhase ( new MessagePhase ( this . scene , this . text . slice ( pageIndex + 1 ) , this . callbackDelay , this . prompt , this . promptDelay ) ) ;
this . text = this . text . slice ( 0 , pageIndex ) . trim ( ) ;
}
2023-05-07 22:05:19 +01:00
this . scene . ui . showText ( this . text , null , ( ) = > this . end ( ) , this . callbackDelay || ( this . prompt ? 0 : 1500 ) , this . prompt , this . promptDelay ) ;
2023-04-10 19:12:01 +01:00
}
2023-04-27 06:14:15 +01:00
end() {
if ( this . scene . abilityBar . shown )
this . scene . abilityBar . hide ( ) ;
super . end ( ) ;
}
2023-04-10 19:12:01 +01:00
}
2023-04-15 06:32:16 +01:00
export class DamagePhase extends PokemonPhase {
private damageResult : DamageResult ;
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex , damageResult? : DamageResult ) {
super ( scene , battlerIndex ) ;
2023-04-15 06:32:16 +01:00
2023-05-18 16:11:06 +01:00
this . damageResult = damageResult || HitResult . EFFECTIVE ;
2023-04-15 06:32:16 +01:00
}
start() {
super . start ( ) ;
switch ( this . damageResult ) {
2023-05-18 16:11:06 +01:00
case HitResult . EFFECTIVE :
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'hit' ) ;
2023-04-15 06:32:16 +01:00
break ;
2023-05-18 16:11:06 +01:00
case HitResult . SUPER_EFFECTIVE :
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'hit_strong' ) ;
2023-04-15 06:32:16 +01:00
break ;
2023-05-18 16:11:06 +01:00
case HitResult . NOT_VERY_EFFECTIVE :
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'hit_weak' ) ;
2023-04-15 06:32:16 +01:00
break ;
}
2023-05-18 16:11:06 +01:00
if ( this . damageResult !== HitResult . OTHER ) {
2023-04-18 17:30:47 +01:00
const flashTimer = this . scene . time . addEvent ( {
delay : 100 ,
repeat : 5 ,
startAt : 200 ,
callback : ( ) = > {
this . getPokemon ( ) . getSprite ( ) . setVisible ( flashTimer . repeatCount % 2 === 0 ) ;
if ( ! flashTimer . repeatCount )
this . getPokemon ( ) . updateInfo ( ) . then ( ( ) = > this . end ( ) ) ;
}
} ) ;
} else
this . getPokemon ( ) . updateInfo ( ) . then ( ( ) = > this . end ( ) ) ;
2023-04-15 06:32:16 +01:00
}
}
2023-04-10 19:12:01 +01:00
export class FaintPhase extends PokemonPhase {
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene , battlerIndex ) ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
2023-06-06 13:16:07 +01:00
const pokemon = this . getPokemon ( ) ;
const instantReviveModifier = this . scene . applyModifier ( PokemonInstantReviveModifier , this . player , this . getPokemon ( ) ) as PokemonInstantReviveModifier ;
if ( instantReviveModifier ) {
if ( ! -- instantReviveModifier . stackCount )
this . scene . removeModifier ( instantReviveModifier ) ;
this . scene . updateModifiers ( this . player ) ;
this . end ( ) ;
return ;
}
this . scene . queueMessage ( getPokemonMessage ( pokemon , ' fainted!' ) , null , true ) ;
2023-04-15 06:32:16 +01:00
2023-04-22 03:59:09 +01:00
if ( this . player ) {
2023-05-18 16:11:06 +01:00
const nonFaintedPartyMemberCount = this . scene . getParty ( ) . filter ( p = > ! p . isFainted ( ) ) . length ;
if ( ! nonFaintedPartyMemberCount )
this . scene . unshiftPhase ( new GameOverPhase ( this . scene ) ) ;
else if ( nonFaintedPartyMemberCount >= this . scene . currentBattle . getBattlerCount ( ) )
this . scene . unshiftPhase ( new SwitchPhase ( this . scene , this . fieldIndex , true , false ) ) ;
2023-07-04 17:51:28 +01:00
else if ( nonFaintedPartyMemberCount === 1 && this . scene . currentBattle . double )
2023-07-06 03:23:50 +01:00
this . scene . unshiftPhase ( new ToggleDoublePositionPhase ( this . scene , true ) ) ;
2023-10-07 21:08:33 +01:00
} else {
2023-05-29 17:24:38 +01:00
this . scene . unshiftPhase ( new VictoryPhase ( this . scene , this . battlerIndex ) ) ;
2023-10-07 21:08:33 +01:00
if ( this . scene . currentBattle . battleType === BattleType . TRAINER ) {
2023-10-23 13:44:04 +01:00
const nonFaintedPartyMemberCount = this . scene . getEnemyParty ( ) . filter ( p = > ! p . isFainted ( ) ) . length ;
2023-10-07 21:08:33 +01:00
if ( nonFaintedPartyMemberCount >= this . scene . currentBattle . getBattlerCount ( ) )
this . scene . unshiftPhase ( new SwitchSummonPhase ( this . scene , this . fieldIndex , this . scene . currentBattle . trainer . getNextSummonIndex ( ) , false , false , false ) ) ;
}
}
2023-04-14 04:04:51 +01:00
2023-04-22 00:30:04 +01:00
pokemon . lapseTags ( BattlerTagLapseType . FAINT ) ;
2023-07-04 23:27:07 +01:00
this . scene . getField ( ) . filter ( p = > p !== pokemon && p ? . isActive ( true ) ) . forEach ( p = > p . removeTagsBySourceId ( pokemon . id ) ) ;
2023-04-13 17:16:36 +01:00
2023-04-10 19:12:01 +01:00
pokemon . faintCry ( ( ) = > {
pokemon . hideInfo ( ) ;
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'faint' ) ;
2023-04-10 19:12:01 +01:00
this . scene . tweens . add ( {
targets : pokemon ,
duration : 500 ,
y : pokemon.y + 150 ,
ease : 'Sine.easeIn' ,
onComplete : ( ) = > {
pokemon . setVisible ( false ) ;
pokemon . y -= 150 ;
2023-04-16 23:40:32 +01:00
pokemon . trySetStatus ( StatusEffect . FAINT ) ;
2023-04-15 06:32:16 +01:00
if ( pokemon . isPlayer ( ) )
2023-04-10 19:12:01 +01:00
this . scene . currentBattle . removeFaintedParticipant ( pokemon as PlayerPokemon ) ;
this . scene . field . remove ( pokemon ) ;
this . end ( ) ;
}
} ) ;
} ) ;
}
}
export class VictoryPhase extends PokemonPhase {
2023-05-29 17:24:38 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene , battlerIndex ) ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
const participantIds = this . scene . currentBattle . playerParticipantIds ;
const party = this . scene . getParty ( ) ;
2023-04-19 03:09:37 +01:00
const expShareModifier = this . scene . findModifier ( m = > m instanceof ExpShareModifier ) as ExpShareModifier ;
2023-04-20 03:51:46 +01:00
const expBalanceModifier = this . scene . findModifier ( m = > m instanceof ExpBalanceModifier ) as ExpBalanceModifier ;
2023-04-28 21:35:03 +01:00
const multipleParticipantExpBonusModifier = this . scene . findModifier ( m = > m instanceof MultipleParticipantExpBonusModifier ) as MultipleParticipantExpBonusModifier ;
2023-10-03 17:50:31 +01:00
const expPartyMembers = party . filter ( p = > p . hp && p . level < this . scene . getMaxExpLevel ( ) ) ;
2023-04-20 03:51:46 +01:00
const partyMemberExp = [ ] ;
2023-10-20 03:54:19 +01:00
let expValue = this . getPokemon ( ) . getExpValue ( ) ;
if ( this . scene . currentBattle . battleType === BattleType . TRAINER )
expValue = Math . floor ( expValue * 1.5 ) ;
2023-04-20 03:51:46 +01:00
for ( let partyMember of expPartyMembers ) {
const pId = partyMember . id ;
2023-04-10 19:12:01 +01:00
const participated = participantIds . has ( pId ) ;
2023-04-21 03:26:38 +01:00
if ( participated )
partyMember . winCount ++ ;
else if ( ! expShareModifier ) {
2023-04-20 03:51:46 +01:00
partyMemberExp . push ( 0 ) ;
2023-04-10 19:12:01 +01:00
continue ;
2023-04-20 03:51:46 +01:00
}
let expMultiplier = 0 ;
2023-10-23 22:47:05 +01:00
if ( participated ) {
2023-04-20 03:51:46 +01:00
expMultiplier += ( 1 / participantIds . size ) ;
2023-10-23 22:47:05 +01:00
if ( participantIds . size > 1 && multipleParticipantExpBonusModifier )
expMultiplier += multipleParticipantExpBonusModifier . getStackCount ( ) * 0.2 ;
} else if ( expShareModifier )
expMultiplier += ( expShareModifier . getStackCount ( ) * 0.2 ) / participantIds . size ;
2023-10-25 19:15:44 +01:00
if ( partyMember . pokerus )
expMultiplier *= 1.5 ;
2023-04-20 03:51:46 +01:00
const pokemonExp = new Utils . NumberHolder ( expValue * expMultiplier ) ;
2023-04-21 00:44:56 +01:00
this . scene . applyModifiers ( PokemonExpBoosterModifier , true , partyMember , pokemonExp ) ;
2023-04-20 03:51:46 +01:00
partyMemberExp . push ( Math . floor ( pokemonExp . value ) ) ;
}
if ( expBalanceModifier ) {
let totalLevel = 0 ;
let totalExp = 0 ;
expPartyMembers . forEach ( ( expPartyMember , epm ) = > {
totalExp += partyMemberExp [ epm ] ;
totalLevel += expPartyMember . level ;
} ) ;
const medianLevel = Math . floor ( totalLevel / expPartyMembers . length ) ;
const recipientExpPartyMemberIndexes = [ ] ;
expPartyMembers . forEach ( ( expPartyMember , epm ) = > {
if ( expPartyMember . level <= medianLevel )
recipientExpPartyMemberIndexes . push ( epm ) ;
} ) ;
const splitExp = Math . floor ( totalExp / recipientExpPartyMemberIndexes . length ) ;
expPartyMembers . forEach ( ( _partyMember , pm ) = > {
partyMemberExp [ pm ] = recipientExpPartyMemberIndexes . indexOf ( pm ) > - 1 ? splitExp : 0 ;
} ) ;
}
for ( let pm = 0 ; pm < expPartyMembers . length ; pm ++ ) {
const exp = partyMemberExp [ pm ] ;
if ( exp ) {
const partyMemberIndex = party . indexOf ( expPartyMembers [ pm ] ) ;
2023-10-04 22:24:28 +01:00
this . scene . unshiftPhase ( expPartyMembers [ pm ] . isOnField ( ) ? new ExpPhase ( this . scene , partyMemberIndex , exp ) : new ShowPartyExpBarPhase ( this . scene , partyMemberIndex , exp ) ) ;
2023-04-10 19:12:01 +01:00
}
}
2023-05-18 16:11:06 +01:00
2023-10-07 21:08:33 +01:00
if ( ! this . scene . getEnemyParty ( ) . filter ( p = > ! p ? . isFainted ( true ) ) . length ) {
2023-05-18 16:11:06 +01:00
this . scene . pushPhase ( new BattleEndPhase ( this . scene ) ) ;
2023-10-18 23:01:15 +01:00
if ( this . scene . currentBattle . battleType === BattleType . TRAINER )
this . scene . pushPhase ( new TrainerVictoryPhase ( this . scene ) ) ;
2023-06-01 00:54:57 +01:00
if ( this . scene . gameMode === GameMode . ENDLESS || this . scene . currentBattle . waveIndex < this . scene . finalWave ) {
2023-10-25 19:15:44 +01:00
if ( this . scene . currentBattle . waveIndex > 30 || this . scene . currentBattle . waveIndex % 10 )
this . scene . pushPhase ( new SelectModifierPhase ( this . scene ) ) ;
else
this . scene . pushPhase ( new ModifierRewardPhase ( this . scene , modifierTypes . GOLDEN_EXP_CHARM ) )
2023-05-18 16:11:06 +01:00
this . scene . pushPhase ( new NewBattlePhase ( this . scene ) ) ;
} else
this . scene . pushPhase ( new GameOverPhase ( this . scene , true ) ) ;
}
2023-04-10 19:12:01 +01:00
this . end ( ) ;
}
}
2023-10-18 23:01:15 +01:00
export class TrainerVictoryPhase extends BattlePhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
start() {
2023-10-20 16:38:41 +01:00
this . scene . playBgm ( this . scene . currentBattle . trainer . config . victoryBgm ) ;
const modifierRewardFuncs = this . scene . currentBattle . trainer . config . modifierRewardFuncs ;
for ( let modifierRewardFunc of modifierRewardFuncs )
2023-10-25 19:15:44 +01:00
this . scene . unshiftPhase ( new ModifierRewardPhase ( this . scene , modifierRewardFunc ) ) ;
2023-10-18 23:01:15 +01:00
this . scene . ui . showText ( ` You defeated \ n ${ this . scene . currentBattle . trainer . getName ( ) } ! ` , null , ( ) = > {
2023-10-20 16:38:41 +01:00
const defeatMessages = this . scene . currentBattle . trainer . config . victoryMessages ;
2023-10-18 23:01:15 +01:00
let showMessageAndEnd = ( ) = > this . end ( ) ; //this.scene.ui.showText(`You got ₽0\nfor winning!`, null, () => this.end(), null, true);
if ( defeatMessages . length ) {
let message : string ;
2023-10-20 16:38:41 +01:00
this . scene . executeWithSeedOffset ( ( ) = > message = Phaser . Math . RND . pick ( this . scene . currentBattle . trainer . config . victoryMessages ) , this . scene . currentBattle . waveIndex ) ;
2023-10-18 23:01:15 +01:00
const messagePages = message . split ( /\$/g ) . map ( m = > m . trim ( ) ) ;
for ( let p = messagePages . length - 1 ; p >= 0 ; p -- ) {
const originalFunc = showMessageAndEnd ;
showMessageAndEnd = ( ) = > this . scene . ui . showDialogue ( messagePages [ p ] , this . scene . currentBattle . trainer . getName ( ) , null , originalFunc , null , true ) ;
}
}
showMessageAndEnd ( ) ;
} , null , true ) ;
this . scene . tweens . add ( {
targets : this.scene.currentBattle.trainer ,
x : '-=16' ,
y : '+=16' ,
alpha : 1 ,
ease : 'Sine.easeInOut' ,
duration : 750
} ) ;
}
}
2023-10-20 16:38:41 +01:00
export class ModifierRewardPhase extends BattlePhase {
private modifierType : ModifierType ;
2023-10-25 19:15:44 +01:00
constructor ( scene : BattleScene , modifierTypeFunc : ModifierTypeFunc ) {
2023-10-20 16:38:41 +01:00
super ( scene ) ;
2023-10-25 19:15:44 +01:00
this . modifierType = modifierTypeFunc ( ) ;
if ( ! this . modifierType . id )
this . modifierType . id = Object . keys ( modifierTypes ) . find ( k = > modifierTypes [ k ] === modifierTypeFunc ) ;
2023-10-20 16:38:41 +01:00
}
start() {
super . start ( ) ;
const newModifier = this . modifierType . newModifier ( ) ;
2023-10-26 04:15:54 +01:00
this . scene . addModifier ( newModifier ) . then ( ( ) = > {
this . scene . playSoundWithoutBgm ( 'item_fanfare' ) ;
this . scene . ui . showText ( ` You received \ n ${ newModifier . type . name } ! ` , null , ( ) = > this . end ( ) , null , true ) ;
} ) ;
2023-10-20 16:38:41 +01:00
}
}
2023-04-22 03:59:09 +01:00
export class GameOverPhase extends BattlePhase {
2023-04-26 22:40:08 +01:00
private victory : boolean ;
constructor ( scene : BattleScene , victory? : boolean ) {
2023-04-22 03:59:09 +01:00
super ( scene ) ;
2023-04-26 22:40:08 +01:00
this . victory = ! ! victory ;
2023-04-22 03:59:09 +01:00
}
start() {
super . start ( ) ;
2023-04-28 20:03:42 +01:00
this . scene . gameData . clearSession ( ) ;
2023-04-22 03:59:09 +01:00
this . scene . time . delayedCall ( 1000 , ( ) = > {
2023-04-26 22:40:08 +01:00
const fadeDuration = this . victory ? 10000 : 5000 ;
this . scene . fadeOutBgm ( fadeDuration , true ) ;
this . scene . ui . fadeOut ( fadeDuration ) . then ( ( ) = > {
2023-04-22 03:59:09 +01:00
this . scene . clearPhaseQueue ( ) ;
this . scene . ui . clearText ( ) ;
this . scene . reset ( ) ;
this . scene . newBattle ( ) ;
this . end ( ) ;
} ) ;
} ) ;
}
2023-04-29 06:40:24 +01:00
end ( ) : void {
2023-06-05 16:39:49 +01:00
if ( this . victory ) {
if ( ! this . scene . gameData . unlocks [ Unlockables . ENDLESS_MODE ] )
this . scene . unshiftPhase ( new UnlockPhase ( this . scene , Unlockables . ENDLESS_MODE ) ) ;
if ( ! this . scene . gameData . unlocks [ Unlockables . MINI_BLACK_HOLE ] )
this . scene . unshiftPhase ( new UnlockPhase ( this . scene , Unlockables . MINI_BLACK_HOLE ) ) ;
}
2023-04-29 06:40:24 +01:00
super . end ( ) ;
}
}
export class UnlockPhase extends BattlePhase {
private unlockable : Unlockables ;
constructor ( scene : BattleScene , unlockable : Unlockables ) {
super ( scene ) ;
this . unlockable = unlockable ;
}
start ( ) : void {
this . scene . time . delayedCall ( 2000 , ( ) = > {
this . scene . gameData . unlocks [ this . unlockable ] = true ;
this . scene . gameData . saveSystem ( ) ;
2023-10-26 21:33:59 +01:00
this . scene . playSoundWithoutBgm ( 'level_up_fanfare' ) ;
2023-04-29 06:40:24 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) ;
this . scene . arenaBg . setVisible ( false ) ;
this . scene . ui . fadeIn ( 250 ) . then ( ( ) = > {
this . scene . ui . showText ( ` ${ getUnlockableName ( this . unlockable ) } \ nhas been unlocked. ` , null , ( ) = > {
this . scene . time . delayedCall ( 1500 , ( ) = > this . scene . arenaBg . setVisible ( true ) ) ;
this . end ( ) ;
} , null , true , 1500 ) ;
} ) ;
} ) ;
}
2023-04-22 03:59:09 +01:00
}
2023-04-10 19:12:01 +01:00
export class SwitchPhase extends BattlePhase {
2023-05-18 16:11:06 +01:00
protected fieldIndex : integer ;
2023-04-10 19:12:01 +01:00
private isModal : boolean ;
private doReturn : boolean ;
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , fieldIndex : integer , isModal : boolean , doReturn : boolean ) {
2023-04-10 19:12:01 +01:00
super ( scene ) ;
2023-05-18 16:11:06 +01:00
this . fieldIndex = fieldIndex ;
2023-04-10 19:12:01 +01:00
this . isModal = isModal ;
this . doReturn = doReturn ;
}
start() {
super . start ( ) ;
2023-05-18 16:11:06 +01:00
this . scene . ui . setMode ( Mode . PARTY , this . isModal ? PartyUiMode.FAINT_SWITCH : PartyUiMode.POST_BATTLE_SWITCH , this . fieldIndex , ( slotIndex : integer , option : PartyOption ) = > {
if ( slotIndex >= this . scene . currentBattle . getBattlerCount ( ) && slotIndex < 6 )
this . scene . unshiftPhase ( new SwitchSummonPhase ( this . scene , this . fieldIndex , slotIndex , this . doReturn , option === PartyOption . PASS_BATON ) ) ;
2023-04-10 19:12:01 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) . then ( ( ) = > super . end ( ) ) ;
} , PartyUiHandler . FilterNonFainted ) ;
}
}
2023-10-07 21:08:33 +01:00
export class ExpPhase extends PlayerPartyMemberPokemonPhase {
2023-04-10 19:12:01 +01:00
private expValue : number ;
constructor ( scene : BattleScene , partyMemberIndex : integer , expValue : number ) {
super ( scene , partyMemberIndex ) ;
this . expValue = expValue ;
}
start() {
super . start ( ) ;
const pokemon = this . getPokemon ( ) ;
let exp = new Utils . NumberHolder ( this . expValue ) ;
2023-04-21 00:44:56 +01:00
this . scene . applyModifiers ( ExpBoosterModifier , true , exp ) ;
2023-04-10 19:12:01 +01:00
exp . value = Math . floor ( exp . value ) ;
this . scene . ui . showText ( ` ${ pokemon . name } gained \ n ${ exp . value } EXP. Points! ` , null , ( ) = > {
const lastLevel = pokemon . level ;
let newLevel : integer ;
pokemon . addExp ( exp . value ) ;
newLevel = pokemon . level ;
if ( newLevel > lastLevel )
this . scene . unshiftPhase ( new LevelUpPhase ( this . scene , this . partyMemberIndex , lastLevel , newLevel ) ) ;
pokemon . updateInfo ( ) . then ( ( ) = > this . end ( ) ) ;
} , null , true ) ;
}
2023-10-04 22:24:28 +01:00
}
2023-10-07 21:08:33 +01:00
export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase {
2023-10-04 22:24:28 +01:00
private expValue : number ;
constructor ( scene : BattleScene , partyMemberIndex : integer , expValue : number ) {
super ( scene , partyMemberIndex ) ;
this . expValue = expValue ;
}
start() {
super . start ( ) ;
const pokemon = this . getPokemon ( ) ;
let exp = new Utils . NumberHolder ( this . expValue ) ;
this . scene . applyModifiers ( ExpBoosterModifier , true , exp ) ;
exp . value = Math . floor ( exp . value ) ;
const lastLevel = pokemon . level ;
let newLevel : integer ;
pokemon . addExp ( exp . value ) ;
newLevel = pokemon . level ;
if ( newLevel > lastLevel )
this . scene . unshiftPhase ( new LevelUpPhase ( this . scene , this . partyMemberIndex , lastLevel , newLevel ) ) ;
this . scene . unshiftPhase ( new HidePartyExpBarPhase ( this . scene ) ) ;
pokemon . updateInfo ( ) ;
this . scene . partyExpBar . showPokemonExp ( pokemon , exp . value ) . then ( ( ) = > {
if ( newLevel > lastLevel )
this . end ( ) ;
else
setTimeout ( ( ) = > this . end ( ) , 500 ) ;
} ) ;
}
}
export class HidePartyExpBarPhase extends BattlePhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
2023-04-10 19:12:01 +01:00
2023-10-04 22:24:28 +01:00
start() {
super . start ( ) ;
2023-04-10 19:12:01 +01:00
2023-10-04 22:24:28 +01:00
this . scene . partyExpBar . hide ( ) . then ( ( ) = > this . end ( ) ) ;
}
2023-04-10 19:12:01 +01:00
}
2023-10-07 21:08:33 +01:00
export class LevelUpPhase extends PlayerPartyMemberPokemonPhase {
2023-04-10 19:12:01 +01:00
private lastLevel : integer ;
private level : integer ;
constructor ( scene : BattleScene , partyMemberIndex : integer , lastLevel : integer , level : integer ) {
super ( scene , partyMemberIndex ) ;
this . lastLevel = lastLevel ;
this . level = level ;
}
start() {
super . start ( ) ;
const pokemon = this . getPokemon ( ) ;
const prevStats = pokemon . stats . slice ( 0 ) ;
pokemon . calculateStats ( ) ;
pokemon . updateInfo ( ) ;
2023-04-18 06:32:26 +01:00
this . scene . playSoundWithoutBgm ( 'level_up_fanfare' , 1500 ) ;
2023-10-18 23:01:15 +01:00
this . scene . ui . showText ( ` ${ this . getPokemon ( ) . name } grew to \ nLv. ${ this . level } ! ` , null , ( ) = > this . scene . ui . getMessageHandler ( ) . promptLevelUpStats ( this . partyMemberIndex , prevStats , false , ( ) = > this . end ( ) ) , null , true ) ;
2023-04-19 19:07:38 +01:00
if ( this . level <= 100 ) {
const levelMoves = this . getPokemon ( ) . getLevelMoves ( this . lastLevel + 1 ) ;
for ( let lm of levelMoves )
this . scene . unshiftPhase ( new LearnMovePhase ( this . scene , this . partyMemberIndex , lm ) ) ;
}
2023-05-09 17:43:28 +01:00
const evolution = pokemon . getEvolution ( ) ;
if ( evolution )
this . scene . unshiftPhase ( new EvolutionPhase ( this . scene , this . partyMemberIndex , evolution , this . lastLevel ) ) ;
2023-04-10 19:12:01 +01:00
}
}
2023-10-07 21:08:33 +01:00
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
2023-04-10 19:12:01 +01:00
private moveId : Moves ;
constructor ( scene : BattleScene , partyMemberIndex : integer , moveId : Moves ) {
super ( scene , partyMemberIndex ) ;
this . moveId = moveId ;
}
start() {
super . start ( ) ;
const pokemon = this . getPokemon ( ) ;
2023-04-21 02:32:48 +01:00
const move = allMoves [ this . moveId ] ;
2023-04-10 19:12:01 +01:00
2023-05-06 05:42:01 +01:00
const existingMoveIndex = pokemon . getMoveset ( ) . findIndex ( m = > m ? . moveId === move . id ) ;
2023-04-10 19:12:01 +01:00
if ( existingMoveIndex > - 1 ) {
this . end ( ) ;
return ;
}
2023-05-06 05:42:01 +01:00
const emptyMoveIndex = pokemon . getMoveset ( ) . length < 4
? pokemon . getMoveset ( ) . length
: pokemon . getMoveset ( ) . findIndex ( m = > m === null ) ;
2023-04-10 19:12:01 +01:00
const messageMode = this . scene . ui . getHandler ( ) instanceof EvolutionSceneHandler
? Mode . EVOLUTION_SCENE
: Mode . MESSAGE ;
if ( emptyMoveIndex > - 1 ) {
2023-05-06 05:42:01 +01:00
pokemon . setMove ( emptyMoveIndex , this . moveId ) ;
2023-04-12 00:08:03 +01:00
initMoveAnim ( this . moveId ) . then ( ( ) = > {
2023-04-10 19:12:01 +01:00
loadMoveAnimAssets ( this . scene , [ this . moveId ] , true )
. then ( ( ) = > {
this . scene . ui . setMode ( messageMode ) . then ( ( ) = > {
2023-04-18 06:32:26 +01:00
this . scene . playSoundWithoutBgm ( 'level_up_fanfare' , 1500 ) ;
2023-10-18 23:01:15 +01:00
this . scene . ui . showText ( ` ${ pokemon . name } learned \ n ${ move . name } ! ` , null , ( ) = > this . end ( ) , messageMode === Mode . EVOLUTION_SCENE ? 1000 : null , true ) ;
2023-04-10 19:12:01 +01:00
} ) ;
} ) ;
} ) ;
} else {
this . scene . ui . setMode ( messageMode ) . then ( ( ) = > {
this . scene . ui . showText ( ` ${ pokemon . name } wants to learn the \ nmove ${ move . name } . ` , null , ( ) = > {
this . scene . ui . showText ( ` However, ${ pokemon . name } already \ nknows four moves. ` , null , ( ) = > {
this . scene . ui . showText ( ` Should a move be deleted and \ nreplaced with ${ move . name } ? ` , null , ( ) = > {
const noHandler = ( ) = > {
this . scene . ui . setMode ( messageMode ) . then ( ( ) = > {
this . scene . ui . showText ( ` Stop trying to teach \ n ${ move . name } ? ` , null , ( ) = > {
this . scene . ui . setModeWithoutClear ( Mode . CONFIRM , ( ) = > {
this . scene . ui . setMode ( messageMode ) ;
this . scene . ui . showText ( ` ${ pokemon . name } did not learn the \ nmove ${ move . name } . ` , null , ( ) = > this . end ( ) , null , true ) ;
} , ( ) = > {
this . scene . ui . setMode ( messageMode ) ;
this . scene . unshiftPhase ( new LearnMovePhase ( this . scene , this . partyMemberIndex , this . moveId ) ) ;
this . end ( ) ;
} ) ;
} ) ;
} ) ;
} ;
this . scene . ui . setModeWithoutClear ( Mode . CONFIRM , ( ) = > {
this . scene . ui . setMode ( messageMode ) ;
this . scene . ui . showText ( 'Which move should be forgotten?' , null , ( ) = > {
this . scene . ui . setModeWithoutClear ( Mode . SUMMARY , this . getPokemon ( ) , SummaryUiMode . LEARN_MOVE , move , ( moveIndex : integer ) = > {
if ( moveIndex === 4 ) {
noHandler ( ) ;
return ;
}
this . scene . ui . setMode ( messageMode ) . then ( ( ) = > {
this . scene . ui . showText ( '@d{32}1, @d{15}2, and@d{15}… @d{15}… @d{15}… @d{15}@s{pb_bounce_1}Poof!' , null , ( ) = > {
this . scene . ui . showText ( ` ${ pokemon . name } forgot how to \ nuse ${ pokemon . moveset [ moveIndex ] . getName ( ) } . ` , null , ( ) = > {
this . scene . ui . showText ( 'And…' , null , ( ) = > {
2023-05-06 05:42:01 +01:00
pokemon . setMove ( moveIndex , Moves . NONE ) ;
2023-04-10 19:12:01 +01:00
this . scene . unshiftPhase ( new LearnMovePhase ( this . scene , this . partyMemberIndex , this . moveId ) ) ;
this . end ( ) ;
} , null , true ) ;
} , null , true ) ;
} , null , true ) ;
} ) ;
} ) ;
} , null , true ) ;
} , noHandler ) ;
} ) ;
} , null , true ) ;
} , null , true ) ;
} ) ;
}
}
}
2023-04-20 20:46:05 +01:00
export class BerryPhase extends CommonAnimPhase {
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene , battlerIndex , undefined , CommonAnim . USE_ITEM ) ;
2023-04-20 20:46:05 +01:00
}
start() {
let berryModifier : BerryModifier ;
2023-04-21 00:44:56 +01:00
if ( ( berryModifier = this . scene . applyModifier ( BerryModifier , this . player , this . getPokemon ( ) ) as BerryModifier ) ) {
if ( berryModifier . consumed ) {
if ( ! -- berryModifier . stackCount )
this . scene . removeModifier ( berryModifier ) ;
else
berryModifier . consumed = false ;
this . scene . updateModifiers ( this . player ) ;
2023-04-20 20:46:05 +01:00
}
2023-04-21 00:44:56 +01:00
super . start ( ) ;
return ;
2023-04-20 20:46:05 +01:00
}
this . end ( ) ;
}
}
2023-04-14 06:08:44 +01:00
export class PokemonHealPhase extends CommonAnimPhase {
private hpHealed : integer ;
2023-04-16 05:29:55 +01:00
private message : string ;
private showFullHpMessage : boolean ;
private skipAnim : boolean ;
2023-06-06 15:14:53 +01:00
private revive : boolean ;
2023-04-14 06:08:44 +01:00
2023-06-06 15:14:53 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex , hpHealed : integer , message : string , showFullHpMessage : boolean , skipAnim? : boolean , revive? : boolean ) {
2023-05-18 16:11:06 +01:00
super ( scene , battlerIndex , undefined , CommonAnim . HEALTH_UP ) ;
2023-04-14 06:08:44 +01:00
this . hpHealed = hpHealed ;
2023-04-16 05:29:55 +01:00
this . message = message ;
this . showFullHpMessage = showFullHpMessage ;
this . skipAnim = ! ! skipAnim ;
2023-06-06 15:14:53 +01:00
this . revive = ! ! revive ;
2023-04-16 05:29:55 +01:00
}
start() {
2023-06-06 15:14:53 +01:00
if ( ! this . skipAnim && ( this . revive || this . getPokemon ( ) . hp ) && this . getPokemon ( ) . getHpRatio ( ) < 1 )
2023-04-16 05:29:55 +01:00
super . start ( ) ;
else
this . end ( ) ;
2023-04-14 06:08:44 +01:00
}
end() {
const pokemon = this . getPokemon ( ) ;
2023-04-23 06:03:09 +01:00
2023-06-06 15:14:53 +01:00
if ( ! pokemon . isOnField ( ) || ( ! this . revive && ! pokemon . isActive ( ) ) ) {
2023-04-23 06:03:09 +01:00
super . end ( ) ;
return ;
}
2023-04-14 06:08:44 +01:00
2023-04-16 05:29:55 +01:00
const fullHp = pokemon . getHpRatio ( ) >= 1 ;
if ( ! fullHp ) {
2023-04-20 20:46:05 +01:00
const hpRestoreMultiplier = new Utils . IntegerHolder ( 1 ) ;
2023-06-06 15:14:53 +01:00
if ( ! this . revive )
this . scene . applyModifiers ( HealingBoosterModifier , this . player , hpRestoreMultiplier ) ;
2023-10-22 01:52:19 +01:00
pokemon . heal ( this . hpHealed * hpRestoreMultiplier . value ) ;
2023-04-16 05:29:55 +01:00
pokemon . updateInfo ( ) . then ( ( ) = > super . end ( ) ) ;
} else if ( this . showFullHpMessage )
this . message = getPokemonMessage ( pokemon , ` 's \ nHP is full! ` ) ;
if ( this . message )
2023-04-22 00:30:04 +01:00
this . scene . queueMessage ( this . message ) ;
2023-04-16 05:29:55 +01:00
if ( fullHp )
super . end ( ) ;
2023-04-14 06:08:44 +01:00
}
}
2023-05-18 16:11:06 +01:00
export class AttemptCapturePhase extends PokemonPhase {
2023-04-10 19:12:01 +01:00
private pokeballType : PokeballType ;
private pokeball : Phaser.GameObjects.Sprite ;
private originalY : number ;
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , targetIndex : integer , pokeballType : PokeballType ) {
super ( scene , BattlerIndex . ENEMY + targetIndex ) ;
2023-04-10 19:12:01 +01:00
this . pokeballType = pokeballType ;
}
start() {
super . start ( ) ;
2023-05-18 16:11:06 +01:00
const pokemon = this . getPokemon ( ) ;
if ( ! pokemon ? . hp ) {
this . end ( ) ;
return ;
}
2023-04-10 19:12:01 +01:00
this . scene . pokeballCounts [ this . pokeballType ] -- ;
this . originalY = pokemon . y ;
const _3m = 3 * pokemon . getMaxHp ( ) ;
const _2h = 2 * pokemon . hp ;
const catchRate = pokemon . species . catchRate ;
const pokeballMultiplier = getPokeballCatchMultiplier ( this . pokeballType ) ;
2023-04-19 03:09:37 +01:00
const statusMultiplier = pokemon . status ? getStatusEffectCatchRateMultiplier ( pokemon . status . effect ) : 1 ;
2023-04-10 19:12:01 +01:00
const x = Math . round ( ( ( ( _3m - _2h ) * catchRate * pokeballMultiplier ) / _3m ) * statusMultiplier ) ;
const y = Math . round ( 65536 / Math . sqrt ( Math . sqrt ( 255 / x ) ) ) ;
2023-05-18 16:11:06 +01:00
const fpOffset = pokemon . getFieldPositionOffset ( ) ;
2023-04-10 19:12:01 +01:00
const pokeballAtlasKey = getPokeballAtlasKey ( this . pokeballType ) ;
this . pokeball = this . scene . add . sprite ( 16 , 80 , 'pb' , pokeballAtlasKey ) ;
this . pokeball . setOrigin ( 0.5 , 0.625 ) ;
this . scene . field . add ( this . pokeball ) ;
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'pb_throw' ) ;
2023-04-10 19:12:01 +01:00
this . scene . time . delayedCall ( 300 , ( ) = > {
2023-06-06 15:14:53 +01:00
this . scene . field . moveBelow ( this . pokeball as Phaser . GameObjects . GameObject , pokemon ) ;
2023-04-10 19:12:01 +01:00
} ) ;
this . scene . tweens . add ( {
targets : this.pokeball ,
2023-05-18 16:11:06 +01:00
x : { value : 236 + fpOffset [ 0 ] , ease : 'Linear' } ,
y : { value : 16 + fpOffset [ 1 ] , ease : 'Cubic.easeOut' } ,
2023-04-10 19:12:01 +01:00
duration : 500 ,
onComplete : ( ) = > {
this . pokeball . setTexture ( 'pb' , ` ${ pokeballAtlasKey } _opening ` ) ;
this . scene . time . delayedCall ( 17 , ( ) = > this . pokeball . setTexture ( 'pb' , ` ${ pokeballAtlasKey } _open ` ) ) ;
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'pb_rel' ) ;
2023-04-10 19:12:01 +01:00
pokemon . tint ( getPokeballTintColor ( this . pokeballType ) ) ;
this . scene . tweens . add ( {
targets : pokemon ,
duration : 250 ,
ease : 'Sine.easeIn' ,
scale : 0.25 ,
y : 20 ,
onComplete : ( ) = > {
this . pokeball . setTexture ( 'pb' , ` ${ pokeballAtlasKey } _opening ` ) ;
pokemon . setVisible ( false ) ;
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'pb_catch' ) ;
2023-04-10 19:12:01 +01:00
this . scene . time . delayedCall ( 17 , ( ) = > this . pokeball . setTexture ( 'pb' , ` ${ pokeballAtlasKey } ` ) ) ;
2023-04-23 15:24:22 +01:00
const doShake = pokeballMultiplier > - 1 ? ( ) = > {
2023-04-10 19:12:01 +01:00
let shakeCount = 0 ;
const pbX = this . pokeball . x ;
const shakeCounter = this . scene . tweens . addCounter ( {
from : 0 ,
to : 1 ,
repeat : 4 ,
yoyo : true ,
ease : 'Cubic.easeOut' ,
duration : 250 ,
repeatDelay : 500 ,
onUpdate : t = > {
if ( shakeCount && shakeCount < 4 ) {
const value = t . getValue ( ) ;
const directionMultiplier = shakeCount % 2 === 1 ? 1 : - 1 ;
this . pokeball . setX ( pbX + value * 4 * directionMultiplier ) ;
this . pokeball . setAngle ( value * 27.5 * directionMultiplier ) ;
}
} ,
onRepeat : ( ) = > {
2023-04-26 21:07:29 +01:00
if ( ! pokemon . species . isObtainable ( ) ) {
shakeCounter . stop ( ) ;
this . failCatch ( shakeCount ) ;
} else if ( shakeCount ++ < 3 ) {
2023-04-10 19:12:01 +01:00
if ( Utils . randInt ( 65536 ) < y )
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'pb_move' ) ;
2023-04-10 19:12:01 +01:00
else {
shakeCounter . stop ( ) ;
2023-04-11 06:31:18 +01:00
this . failCatch ( shakeCount ) ;
2023-04-10 19:12:01 +01:00
}
} else
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'pb_lock' )
2023-04-10 19:12:01 +01:00
} ,
2023-04-21 00:44:56 +01:00
onComplete : ( ) = > this . catch ( )
2023-04-10 19:12:01 +01:00
} ) ;
} : ( ) = > this . catch ( ) ;
this . scene . time . delayedCall ( 250 , ( ) = > doPokeballBounceAnim ( this . scene , this . pokeball , 16 , 72 , 350 , doShake ) ) ;
}
} ) ;
}
} ) ;
}
2023-04-11 06:31:18 +01:00
failCatch ( shakeCount : integer ) {
2023-05-18 16:11:06 +01:00
const pokemon = this . getPokemon ( ) ;
2023-04-10 19:12:01 +01:00
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'pb_rel' ) ;
2023-04-10 19:12:01 +01:00
pokemon . setY ( this . originalY ) ;
pokemon . cry ( ) ;
pokemon . tint ( getPokeballTintColor ( this . pokeballType ) ) ;
pokemon . setVisible ( true ) ;
pokemon . untint ( 250 , 'Sine.easeOut' ) ;
const pokeballAtlasKey = getPokeballAtlasKey ( this . pokeballType ) ;
this . pokeball . setTexture ( 'pb' , ` ${ pokeballAtlasKey } _opening ` ) ;
this . scene . time . delayedCall ( 17 , ( ) = > this . pokeball . setTexture ( 'pb' , ` ${ pokeballAtlasKey } _open ` ) ) ;
this . scene . tweens . add ( {
targets : pokemon ,
duration : 250 ,
ease : 'Sine.easeOut' ,
scale : 1
} ) ;
this . removePb ( ) ;
this . end ( ) ;
}
catch ( ) {
2023-05-18 16:11:06 +01:00
const pokemon = this . getPokemon ( ) as EnemyPokemon ;
2023-05-29 17:24:38 +01:00
this . scene . unshiftPhase ( new VictoryPhase ( this . scene , this . battlerIndex ) ) ;
2023-04-10 19:12:01 +01:00
this . scene . ui . showText ( ` ${ pokemon . name } was caught! ` , null , ( ) = > {
2023-04-10 21:52:27 +01:00
const end = ( ) = > {
2023-04-10 19:12:01 +01:00
this . removePb ( ) ;
this . end ( ) ;
2023-04-10 21:52:27 +01:00
} ;
2023-07-03 15:59:56 +01:00
const removePokemon = ( ) = > {
2023-07-05 16:54:36 +01:00
this . scene . getPlayerField ( ) . filter ( p = > p . isActive ( ) ) . forEach ( playerPokemon = > playerPokemon . removeTagsBySourceId ( pokemon . id ) ) ;
2023-07-03 15:59:56 +01:00
pokemon . hp = 0 ;
pokemon . trySetStatus ( StatusEffect . FAINT ) ;
this . scene . clearEnemyModifiers ( ) ;
this . scene . field . remove ( pokemon , true ) ;
} ;
2023-04-11 06:31:18 +01:00
const addToParty = ( ) = > {
const newPokemon = pokemon . addToParty ( ) ;
2023-04-21 00:44:56 +01:00
const modifiers = this . scene . findModifiers ( m = > m instanceof PokemonHeldItemModifier , false ) ;
Promise . all ( modifiers . map ( m = > this . scene . addModifier ( m ) ) ) . then ( ( ) = > {
2023-07-03 15:59:56 +01:00
removePokemon ( ) ;
2023-04-21 00:44:56 +01:00
if ( newPokemon )
newPokemon . loadAssets ( ) . then ( end ) ;
else
end ( ) ;
} ) ;
2023-04-11 06:31:18 +01:00
} ;
2023-04-18 18:36:11 +01:00
Promise . all ( [ pokemon . hideInfo ( ) , this . scene . gameData . setPokemonCaught ( pokemon ) ] ) . then ( ( ) = > {
2023-04-18 06:32:26 +01:00
if ( this . scene . getParty ( ) . length === 6 ) {
const promptRelease = ( ) = > {
2023-10-18 23:01:15 +01:00
this . scene . ui . showText ( ` Your party is full. \ nRelease a Pokémon to make room for ${ pokemon . name } ? ` , null , ( ) = > {
2023-04-18 06:32:26 +01:00
this . scene . ui . setMode ( Mode . CONFIRM , ( ) = > {
2023-05-18 16:11:06 +01:00
this . scene . ui . setMode ( Mode . PARTY , PartyUiMode . RELEASE , this . fieldIndex , ( slotIndex : integer , _option : PartyOption ) = > {
2023-04-18 06:32:26 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) . then ( ( ) = > {
if ( slotIndex < 6 )
addToParty ( ) ;
else
promptRelease ( ) ;
} ) ;
2023-04-11 06:31:18 +01:00
} ) ;
2023-04-18 06:32:26 +01:00
} , ( ) = > {
2023-07-03 15:59:56 +01:00
this . scene . ui . setMode ( Mode . MESSAGE ) . then ( ( ) = > {
removePokemon ( ) ;
end ( ) ;
} ) ;
2023-04-11 06:31:18 +01:00
} ) ;
} ) ;
2023-04-18 06:32:26 +01:00
} ;
promptRelease ( ) ;
} else
addToParty ( ) ;
} ) ;
2023-04-10 19:12:01 +01:00
} , 0 , true ) ;
}
removePb() {
this . scene . tweens . add ( {
targets : this.pokeball ,
duration : 250 ,
delay : 250 ,
ease : 'Sine.easeIn' ,
alpha : 0 ,
onComplete : ( ) = > this . pokeball . destroy ( )
} ) ;
}
}
2023-05-18 16:11:06 +01:00
export class AttemptRunPhase extends PokemonPhase {
constructor ( scene : BattleScene , fieldIndex : integer ) {
super ( scene , fieldIndex ) ;
2023-05-07 22:05:19 +01:00
}
start() {
super . start ( ) ;
2023-05-18 16:11:06 +01:00
const playerPokemon = this . getPokemon ( ) ;
const enemyField = this . scene . getEnemyField ( ) ;
const enemySpeed = enemyField . reduce ( ( total : integer , enemyPokemon : Pokemon ) = > total + enemyPokemon . stats [ Stat . SPD ] , 0 ) / enemyField . length ;
2023-05-07 22:05:19 +01:00
2023-05-18 16:11:06 +01:00
const escapeChance = ( ( ( playerPokemon . stats [ Stat . SPD ] * 128 ) / enemySpeed ) + ( 30 * this . scene . currentBattle . escapeAttempts ++ ) ) % 256 ;
2023-05-07 22:05:19 +01:00
if ( Utils . randInt ( 256 ) < escapeChance ) {
2023-10-21 13:58:39 +01:00
this . scene . playSound ( 'flee' ) ;
2023-05-07 22:05:19 +01:00
this . scene . queueMessage ( 'You got away safely!' , null , true , 500 ) ;
this . scene . tweens . add ( {
2023-05-18 16:11:06 +01:00
targets : [ this . scene . arenaEnemy , enemyField ] . flat ( ) ,
2023-05-07 22:05:19 +01:00
alpha : 0 ,
duration : 250 ,
ease : 'Sine.easeIn'
} ) ;
2023-06-01 18:54:52 +01:00
enemyField . forEach ( enemyPokemon = > {
enemyPokemon . hideInfo ( ) ;
enemyPokemon . hp = 0 ;
} ) ;
2023-05-07 22:05:19 +01:00
this . scene . pushPhase ( new BattleEndPhase ( this . scene ) ) ;
2023-05-18 16:11:06 +01:00
this . scene . pushPhase ( new NewBattlePhase ( this . scene ) ) ;
2023-05-07 22:05:19 +01:00
} else
this . scene . queueMessage ( 'You can\'t escape!' , null , true ) ;
this . end ( ) ;
}
}
2023-04-10 19:12:01 +01:00
export class SelectModifierPhase extends BattlePhase {
constructor ( scene : BattleScene ) {
super ( scene ) ;
}
start() {
super . start ( ) ;
2023-10-18 23:01:15 +01:00
this . scene . resetSeed ( ) ;
2023-04-10 19:12:01 +01:00
const party = this . scene . getParty ( ) ;
2023-10-23 18:48:56 +01:00
regenerateModifierPoolThresholds ( party , ModifierPoolType . PLAYER ) ;
2023-04-10 19:12:01 +01:00
const modifierCount = new Utils . IntegerHolder ( 3 ) ;
2023-04-21 00:44:56 +01:00
this . scene . applyModifiers ( ExtraModifierModifier , true , modifierCount ) ;
2023-05-18 16:11:06 +01:00
const typeOptions : Array < ModifierTypeOption > = getPlayerModifierTypeOptionsForWave ( this . scene . currentBattle . waveIndex , modifierCount . value , party ) ;
2023-04-10 19:12:01 +01:00
const modifierSelectCallback = ( cursor : integer ) = > {
if ( cursor < 0 ) {
this . scene . ui . setMode ( Mode . MESSAGE ) ;
super . end ( ) ;
return ;
2023-04-21 19:05:16 +01:00
} else if ( cursor >= typeOptions . length ) {
2023-05-18 16:11:06 +01:00
this . scene . ui . setModeWithoutClear ( Mode . PARTY , PartyUiMode . MODIFIER_TRANSFER , - 1 , ( fromSlotIndex : integer , itemIndex : integer , toSlotIndex : integer ) = > {
2023-04-21 19:05:16 +01:00
if ( toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > - 1 ) {
2023-04-22 16:46:52 +01:00
this . scene . ui . setMode ( Mode . MODIFIER_SELECT ) . then ( ( ) = > {
const itemModifiers = this . scene . findModifiers ( m = > m instanceof PokemonHeldItemModifier
2023-06-01 00:54:57 +01:00
&& ( m as PokemonHeldItemModifier ) . getTransferrable ( true ) && ( m as PokemonHeldItemModifier ) . pokemonId === party [ fromSlotIndex ] . id ) as PokemonHeldItemModifier [ ] ;
2023-04-22 16:46:52 +01:00
const itemModifier = itemModifiers [ itemIndex ] ;
2023-04-23 15:24:22 +01:00
this . scene . tryTransferHeldItemModifier ( itemModifier , party [ toSlotIndex ] , true , true ) . then ( success = > {
2023-04-22 16:46:52 +01:00
if ( success ) {
this . scene . ui . clearText ( ) ;
this . scene . ui . setMode ( Mode . MESSAGE ) ;
2023-04-23 15:24:22 +01:00
super . end ( ) ;
2023-04-22 16:46:52 +01:00
} else
this . scene . ui . setMode ( Mode . MODIFIER_SELECT , typeOptions , modifierSelectCallback ) ;
} ) ;
2023-04-21 20:45:48 +01:00
} ) ;
2023-04-22 00:30:04 +01:00
} else
this . scene . ui . setMode ( Mode . MODIFIER_SELECT , typeOptions , modifierSelectCallback ) ;
2023-04-21 19:05:16 +01:00
} , PartyUiHandler . FilterItemMaxStacks ) ;
return ;
2023-04-10 19:12:01 +01:00
}
2023-04-12 17:56:37 +01:00
const modifierType = typeOptions [ cursor ] . type ;
2023-04-10 19:12:01 +01:00
if ( modifierType instanceof PokemonModifierType ) {
const pokemonModifierType = modifierType as PokemonModifierType ;
2023-04-11 16:04:39 +01:00
const isMoveModifier = modifierType instanceof PokemonMoveModifierType ;
2023-07-05 04:11:31 +01:00
const isTmModifier = modifierType instanceof TmModifierType ;
const partyUiMode = isMoveModifier ? PartyUiMode . MOVE_MODIFIER
: isTmModifier ? PartyUiMode.TM_MODIFIER : PartyUiMode.MODIFIER ;
const tmMoveId = isTmModifier
? ( modifierType as TmModifierType ) . moveId
: undefined ;
this . scene . ui . setModeWithoutClear ( Mode . PARTY , partyUiMode , - 1 , ( slotIndex : integer , option : PartyOption ) = > {
2023-04-10 19:12:01 +01:00
if ( slotIndex < 6 ) {
2023-04-22 16:46:52 +01:00
this . scene . ui . setMode ( Mode . MODIFIER_SELECT ) . then ( ( ) = > {
const modifierType = typeOptions [ cursor ] . type ;
const modifier = ! isMoveModifier
? modifierType . newModifier ( party [ slotIndex ] )
: modifierType . newModifier ( party [ slotIndex ] , option - PartyOption . MOVE_1 ) ;
this . scene . ui . clearText ( ) ;
this . scene . ui . setMode ( Mode . MESSAGE ) ;
2023-04-23 15:24:22 +01:00
this . scene . addModifier ( modifier , true ) . then ( ( ) = > super . end ( ) ) ;
2023-04-22 16:46:52 +01:00
} ) ;
2023-04-10 19:12:01 +01:00
} else
2023-04-12 17:56:37 +01:00
this . scene . ui . setMode ( Mode . MODIFIER_SELECT , typeOptions , modifierSelectCallback ) ;
2023-07-05 04:11:31 +01:00
} , pokemonModifierType . selectFilter , modifierType instanceof PokemonMoveModifierType ? ( modifierType as PokemonMoveModifierType ) . moveSelectFilter : undefined , tmMoveId ) ;
2023-04-10 19:12:01 +01:00
} else {
2023-04-21 00:44:56 +01:00
this . scene . addModifier ( typeOptions [ cursor ] . type . newModifier ( ) , true ) . then ( ( ) = > super . end ( ) ) ;
2023-04-10 19:12:01 +01:00
this . scene . ui . clearText ( ) ;
this . scene . ui . setMode ( Mode . MESSAGE ) ;
}
} ;
2023-04-12 17:56:37 +01:00
this . scene . ui . setMode ( Mode . MODIFIER_SELECT , typeOptions , modifierSelectCallback ) ;
2023-04-10 19:12:01 +01:00
}
}
2023-10-18 23:01:15 +01:00
export class PartyHealPhase extends BattlePhase {
private resumeBgm : boolean ;
constructor ( scene : BattleScene , resumeBgm : boolean ) {
super ( scene ) ;
this . resumeBgm = resumeBgm ;
}
start() {
super . start ( ) ;
const bgmPlaying = this . scene . isBgmPlaying ( ) ;
if ( bgmPlaying )
this . scene . fadeOutBgm ( 1000 , false ) ;
this . scene . ui . fadeOut ( 1000 ) . then ( ( ) = > {
for ( let pokemon of this . scene . getParty ( ) ) {
pokemon . hp = pokemon . getMaxHp ( ) ;
pokemon . resetStatus ( ) ;
for ( let move of pokemon . moveset )
move . ppUsed = 0 ;
2023-10-20 16:38:41 +01:00
pokemon . updateInfo ( true ) ;
2023-10-18 23:01:15 +01:00
}
2023-10-26 21:33:59 +01:00
const healSong = this . scene . playSoundWithoutBgm ( 'heal' ) ;
2023-10-18 23:01:15 +01:00
this . scene . time . delayedCall ( healSong . totalDuration * 1000 , ( ) = > {
healSong . destroy ( ) ;
if ( this . resumeBgm && bgmPlaying )
this . scene . playBgm ( ) ;
this . scene . ui . fadeIn ( 500 ) . then ( ( ) = > this . end ( ) ) ;
} ) ;
} ) ;
}
}
2023-04-10 19:12:01 +01:00
export class ShinySparklePhase extends PokemonPhase {
2023-05-18 16:11:06 +01:00
constructor ( scene : BattleScene , battlerIndex : BattlerIndex ) {
super ( scene , battlerIndex ) ;
2023-04-10 19:12:01 +01:00
}
start() {
super . start ( ) ;
this . getPokemon ( ) . sparkle ( ) ;
this . scene . time . delayedCall ( 1000 , ( ) = > this . end ( ) ) ;
}
2023-10-18 23:01:15 +01:00
}
export class TestMessagePhase extends MessagePhase {
constructor ( scene : BattleScene , message : string ) {
super ( scene , message , null , true ) ;
}
2023-04-10 19:12:01 +01:00
}