2023-04-18 09:30:47 -07:00
import { CommonAnim , CommonBattleAnim } from "./battle-anims" ;
2023-04-20 12:46:05 -07:00
import { CommonAnimPhase , DamagePhase , MessagePhase , MovePhase , ObtainStatusEffectPhase , PokemonHealPhase } from "../battle-phases" ;
import { getPokemonMessage } from "../messages" ;
import Pokemon from "../pokemon" ;
2023-04-14 22:32:16 -07:00
import { Stat } from "./pokemon-stat" ;
2023-04-19 13:52:14 -07:00
import { StatusEffect } from "./status-effect" ;
2023-04-20 12:46:05 -07:00
import * as Utils from "../utils" ;
2023-04-20 18:32:48 -07:00
import { Moves } from "./move" ;
2023-04-14 22:32:16 -07:00
2023-04-21 16:30:04 -07:00
export enum BattlerTagType {
2023-04-13 09:16:36 -07:00
NONE ,
2023-04-20 18:32:48 -07:00
RECHARGING ,
2023-04-15 14:40:18 -07:00
FLINCHED ,
2023-04-14 22:32:16 -07:00
CONFUSED ,
2023-04-18 09:30:47 -07:00
SEEDED ,
2023-04-16 15:40:32 -07:00
NIGHTMARE ,
2023-04-14 22:32:16 -07:00
FRENZY ,
2023-04-19 13:52:14 -07:00
INGRAIN ,
AQUA_RING ,
DROWSY ,
2023-04-18 09:30:47 -07:00
PROTECTED ,
2023-04-13 09:16:36 -07:00
FLYING ,
2023-04-15 21:29:55 -07:00
UNDERGROUND ,
2023-04-19 13:52:14 -07:00
NO_CRIT ,
2023-04-16 15:40:32 -07:00
BYPASS_SLEEP ,
2023-04-15 21:29:55 -07:00
IGNORE_FLYING
2023-04-13 09:16:36 -07:00
}
2023-04-21 16:30:04 -07:00
export enum BattlerTagLapseType {
2023-04-13 09:16:36 -07:00
FAINT ,
MOVE ,
2023-04-16 15:40:32 -07:00
AFTER_MOVE ,
2023-04-14 22:32:16 -07:00
MOVE_EFFECT ,
TURN_END ,
CUSTOM
2023-04-13 09:16:36 -07:00
}
2023-04-21 16:30:04 -07:00
export class BattlerTag {
public tagType : BattlerTagType ;
public lapseType : BattlerTagLapseType ;
2023-04-13 09:16:36 -07:00
public turnCount : integer ;
2023-04-21 16:30:04 -07:00
constructor ( tagType : BattlerTagType , lapseType : BattlerTagLapseType , turnCount : integer ) {
2023-04-13 09:16:36 -07:00
this . tagType = tagType ;
this . lapseType = lapseType ;
this . turnCount = turnCount ;
}
2023-04-14 22:32:16 -07:00
onAdd ( pokemon : Pokemon ) : void { }
onRemove ( pokemon : Pokemon ) : void { }
onOverlap ( pokemon : Pokemon ) : void { }
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
2023-04-15 14:40:18 -07:00
return -- this . turnCount > 0 ;
}
}
2023-04-21 16:30:04 -07:00
export class RechargingTag extends BattlerTag {
2023-04-20 18:32:48 -07:00
constructor ( ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . RECHARGING , BattlerTagLapseType . MOVE , 1 ) ;
2023-04-20 18:32:48 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
pokemon . getMoveQueue ( ) . push ( { move : Moves.NONE } )
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
2023-04-20 18:32:48 -07:00
super . lapse ( pokemon , lapseType ) ;
( pokemon . scene . getCurrentPhase ( ) as MovePhase ) . cancel ( ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' must\nrecharge!' ) ) ;
2023-04-20 18:32:48 -07:00
return true ;
}
}
2023-04-21 16:30:04 -07:00
export class FlinchedTag extends BattlerTag {
2023-04-15 14:40:18 -07:00
constructor ( ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . FLINCHED , BattlerTagLapseType . MOVE , 0 ) ;
2023-04-15 14:40:18 -07:00
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
2023-04-16 15:40:32 -07:00
super . lapse ( pokemon , lapseType ) ;
2023-04-15 14:40:18 -07:00
( pokemon . scene . getCurrentPhase ( ) as MovePhase ) . cancel ( ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' flinched!' ) ) ;
2023-04-15 14:40:18 -07:00
return true ;
2023-04-14 22:32:16 -07:00
}
}
2023-04-21 16:30:04 -07:00
export class PseudoStatusTag extends BattlerTag {
constructor ( tagType : BattlerTagType , lapseType : BattlerTagLapseType , turnCount : integer ) {
2023-04-16 15:40:32 -07:00
super ( tagType , lapseType , turnCount ) ;
2023-04-14 22:32:16 -07:00
}
}
export class ConfusedTag extends PseudoStatusTag {
2023-04-16 15:40:32 -07:00
constructor ( turnCount : integer ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . CONFUSED , BattlerTagLapseType . MOVE , turnCount ) ;
2023-04-14 22:32:16 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
pokemon . scene . unshiftPhase ( new CommonAnimPhase ( pokemon . scene , pokemon . isPlayer ( ) , CommonAnim . CONFUSION ) ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' became\nconfused!' ) ) ;
2023-04-14 22:32:16 -07:00
}
onRemove ( pokemon : Pokemon ) : void {
super . onRemove ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' snapped\nout of confusion!' ) ) ;
2023-04-14 22:32:16 -07:00
}
onOverlap ( pokemon : Pokemon ) : void {
super . onOverlap ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' is\nalready confused!' ) ) ;
2023-04-14 22:32:16 -07:00
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
const ret = lapseType !== BattlerTagLapseType . CUSTOM && super . lapse ( pokemon , lapseType ) ;
2023-04-14 22:32:16 -07:00
if ( ret ) {
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' is\nconfused!' ) ) ;
2023-04-14 22:32:16 -07:00
pokemon . scene . unshiftPhase ( new CommonAnimPhase ( pokemon . scene , pokemon . isPlayer ( ) , CommonAnim . CONFUSION ) ) ;
if ( Utils . randInt ( 2 ) ) {
const atk = pokemon . getBattleStat ( Stat . ATK ) ;
const def = pokemon . getBattleStat ( Stat . DEF ) ;
const damage = Math . ceil ( ( ( ( ( 2 * pokemon . level / 5 + 2 ) * 40 * atk / def ) / 50 ) + 2 ) * ( ( Utils . randInt ( 15 ) + 85 ) / 100 ) ) ;
2023-04-18 13:47:29 -07:00
pokemon . damage ( damage ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( 'It hurt itself in its\nconfusion!' ) ;
2023-04-16 15:40:32 -07:00
pokemon . scene . unshiftPhase ( new DamagePhase ( pokemon . scene , pokemon . isPlayer ( ) ) ) ;
2023-04-14 22:32:16 -07:00
( pokemon . scene . getCurrentPhase ( ) as MovePhase ) . cancel ( ) ;
}
2023-04-13 09:16:36 -07:00
}
2023-04-14 22:32:16 -07:00
return ret ;
}
}
2023-04-18 09:30:47 -07:00
export class SeedTag extends PseudoStatusTag {
constructor ( ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . SEEDED , BattlerTagLapseType . AFTER_MOVE , 1 ) ;
2023-04-18 09:30:47 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' was seeded!' ) ) ;
2023-04-18 09:30:47 -07:00
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
const ret = lapseType !== BattlerTagLapseType . CUSTOM || super . lapse ( pokemon , lapseType ) ;
2023-04-18 09:30:47 -07:00
if ( ret ) {
pokemon . scene . unshiftPhase ( new CommonAnimPhase ( pokemon . scene , ! pokemon . isPlayer ( ) , CommonAnim . LEECH_SEED ) ) ;
const damage = Math . max ( Math . floor ( pokemon . getMaxHp ( ) / 8 ) , 1 ) ;
2023-04-18 13:47:29 -07:00
pokemon . damage ( damage ) ;
2023-04-18 09:30:47 -07:00
pokemon . scene . unshiftPhase ( new DamagePhase ( pokemon . scene , pokemon . isPlayer ( ) ) ) ;
pokemon . scene . unshiftPhase ( new PokemonHealPhase ( pokemon . scene , ! pokemon . isPlayer ( ) , damage , getPokemonMessage ( pokemon , '\'s health is\nsapped by LEECH SEED!' ) , false , true ) ) ;
}
return ret ;
}
}
2023-04-16 15:40:32 -07:00
export class NightmareTag extends PseudoStatusTag {
constructor ( ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . NIGHTMARE , BattlerTagLapseType . AFTER_MOVE , 1 ) ;
2023-04-16 15:40:32 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' began\nhaving a NIGHTMARE!' ) ) ;
2023-04-16 15:40:32 -07:00
}
onOverlap ( pokemon : Pokemon ) : void {
super . onOverlap ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' is\nalready locked in a NIGHTMARE!' ) ) ;
2023-04-16 15:40:32 -07:00
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
const ret = lapseType !== BattlerTagLapseType . CUSTOM || super . lapse ( pokemon , lapseType ) ;
2023-04-16 15:40:32 -07:00
if ( ret ) {
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' is locked\nin a NIGHTMARE!' ) ) ;
2023-04-16 15:40:32 -07:00
pokemon . scene . unshiftPhase ( new CommonAnimPhase ( pokemon . scene , pokemon . isPlayer ( ) , CommonAnim . CURSE ) ) ; // TODO: Update animation type
const damage = Math . ceil ( pokemon . getMaxHp ( ) / 4 ) ;
2023-04-18 13:47:29 -07:00
pokemon . damage ( damage ) ;
2023-04-16 15:40:32 -07:00
pokemon . scene . unshiftPhase ( new DamagePhase ( pokemon . scene , pokemon . isPlayer ( ) ) ) ;
}
return ret ;
}
}
2023-04-19 13:52:14 -07:00
export class IngrainTag extends PseudoStatusTag {
constructor ( ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . INGRAIN , BattlerTagLapseType . TURN_END , 1 ) ;
2023-04-19 13:52:14 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' planted its roots!' ) ) ;
2023-04-19 13:52:14 -07:00
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
const ret = lapseType !== BattlerTagLapseType . CUSTOM || super . lapse ( pokemon , lapseType ) ;
2023-04-19 13:52:14 -07:00
if ( ret )
pokemon . scene . unshiftPhase ( new PokemonHealPhase ( pokemon . scene , pokemon . isPlayer ( ) , Math . floor ( pokemon . getMaxHp ( ) / 16 ) ,
getPokemonMessage ( pokemon , ` absorbed \ nnutrients with its roots! ` ) , true ) ) ;
return ret ;
}
}
export class AquaRingTag extends PseudoStatusTag {
constructor ( ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . AQUA_RING , BattlerTagLapseType . TURN_END , 1 ) ;
2023-04-19 13:52:14 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' surrounded\nitself with a veil of water!' ) ) ;
2023-04-19 13:52:14 -07:00
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
const ret = lapseType !== BattlerTagLapseType . CUSTOM || super . lapse ( pokemon , lapseType ) ;
2023-04-19 13:52:14 -07:00
if ( ret )
pokemon . scene . unshiftPhase ( new PokemonHealPhase ( pokemon . scene , pokemon . isPlayer ( ) , Math . floor ( pokemon . getMaxHp ( ) / 16 ) , ` AQUA RING restored \ n ${ pokemon . name } \ 's HP! ` , true ) ) ;
return ret ;
}
}
2023-04-21 16:30:04 -07:00
export class DrowsyTag extends BattlerTag {
2023-04-19 13:52:14 -07:00
constructor ( ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . DROWSY , BattlerTagLapseType . TURN_END , 2 ) ;
2023-04-19 13:52:14 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , ' grew drowsy!' ) ) ;
2023-04-19 13:52:14 -07:00
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
2023-04-19 13:52:14 -07:00
if ( ! super . lapse ( pokemon , lapseType ) ) {
pokemon . scene . unshiftPhase ( new ObtainStatusEffectPhase ( pokemon . scene , pokemon . isPlayer ( ) , StatusEffect . SLEEP ) ) ;
return false ;
}
return true ;
}
}
2023-04-21 16:30:04 -07:00
export class ProtectedTag extends BattlerTag {
2023-04-18 09:30:47 -07:00
constructor ( ) {
2023-04-21 16:30:04 -07:00
super ( BattlerTagType . PROTECTED , BattlerTagLapseType . CUSTOM , 0 ) ;
2023-04-18 09:30:47 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , '\nprotected itself!' ) ) ;
2023-04-18 09:30:47 -07:00
}
2023-04-21 16:30:04 -07:00
lapse ( pokemon : Pokemon , lapseType : BattlerTagLapseType ) : boolean {
if ( lapseType === BattlerTagLapseType . CUSTOM ) {
2023-04-18 09:30:47 -07:00
new CommonBattleAnim ( CommonAnim . PROTECT , pokemon ) . play ( pokemon . scene ) ;
2023-04-21 16:30:04 -07:00
pokemon . scene . queueMessage ( getPokemonMessage ( pokemon , '\nprotected itself!' ) ) ;
2023-04-18 09:30:47 -07:00
return true ;
}
return super . lapse ( pokemon , lapseType ) ;
}
}
2023-04-21 16:30:04 -07:00
export class HideSpriteTag extends BattlerTag {
constructor ( tagType : BattlerTagType , turnCount : integer ) {
super ( tagType , BattlerTagLapseType . MOVE_EFFECT , turnCount ) ;
2023-04-14 22:32:16 -07:00
}
onAdd ( pokemon : Pokemon ) : void {
super . onAdd ( pokemon ) ;
pokemon . setVisible ( false ) ;
}
onRemove ( pokemon : Pokemon ) : void {
// Wait 2 frames before setting visible for battle animations that don't immediately show the sprite invisible
pokemon . scene . tweens . addCounter ( {
duration : 2 ,
useFrames : true ,
onComplete : ( ) = > pokemon . setVisible ( true )
} ) ;
}
}
2023-04-13 09:16:36 -07:00
2023-04-21 16:30:04 -07:00
export function getBattlerTag ( tagType : BattlerTagType , turnCount : integer ) : BattlerTag {
2023-04-14 22:32:16 -07:00
switch ( tagType ) {
2023-04-21 16:30:04 -07:00
case BattlerTagType . RECHARGING :
2023-04-20 18:32:48 -07:00
return new RechargingTag ( ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . FLINCHED :
2023-04-15 14:40:18 -07:00
return new FlinchedTag ( ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . CONFUSED :
2023-04-16 15:40:32 -07:00
return new ConfusedTag ( turnCount ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . SEEDED :
2023-04-18 09:30:47 -07:00
return new SeedTag ( ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . NIGHTMARE :
2023-04-16 15:40:32 -07:00
return new NightmareTag ( ) ;
2023-04-22 10:16:45 -07:00
case BattlerTagType . INGRAIN :
return new IngrainTag ( ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . AQUA_RING :
2023-04-19 13:52:14 -07:00
return new AquaRingTag ( ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . DROWSY :
2023-04-19 13:52:14 -07:00
return new DrowsyTag ( ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . PROTECTED :
2023-04-18 09:30:47 -07:00
return new ProtectedTag ( ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . FLYING :
case BattlerTagType . UNDERGROUND :
2023-04-14 22:32:16 -07:00
return new HideSpriteTag ( tagType , turnCount ) ;
2023-04-21 16:30:04 -07:00
case BattlerTagType . NO_CRIT :
return new BattlerTag ( tagType , BattlerTagLapseType . AFTER_MOVE , turnCount ) ;
case BattlerTagType . BYPASS_SLEEP :
return new BattlerTag ( BattlerTagType . BYPASS_SLEEP , BattlerTagLapseType . TURN_END , turnCount ) ;
case BattlerTagType . IGNORE_FLYING :
return new BattlerTag ( tagType , BattlerTagLapseType . TURN_END , turnCount ) ;
2023-04-14 22:32:16 -07:00
default :
2023-04-21 16:30:04 -07:00
return new BattlerTag ( tagType , BattlerTagLapseType . CUSTOM , turnCount ) ;
2023-04-13 09:16:36 -07:00
}
}