pokerogue/src/battle-tag.ts

247 lines
7.8 KiB
TypeScript
Raw Normal View History

2023-04-18 09:30:47 -07:00
import { CommonAnim, CommonBattleAnim } from "./battle-anims";
import { CommonAnimPhase, DamagePhase, MessagePhase, MovePhase, PokemonHealPhase } from "./battle-phases";
2023-04-14 22:32:16 -07:00
import { getPokemonMessage } from "./messages";
import Pokemon from "./pokemon";
import { Stat } from "./pokemon-stat";
import * as Utils from "./utils";
2023-04-13 09:16:36 -07:00
export enum BattleTagType {
NONE,
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-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-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
}
export enum BattleTagLapseType {
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
}
export class BattleTag {
public tagType: BattleTagType;
public lapseType: BattleTagLapseType;
public turnCount: integer;
constructor(tagType: BattleTagType, lapseType: BattleTagLapseType, turnCount: integer) {
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-16 15:40:32 -07:00
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
return --this.turnCount > 0;
}
}
export class FlinchedTag extends BattleTag {
constructor() {
2023-04-18 09:30:47 -07:00
super(BattleTagType.FLINCHED, BattleTagLapseType.MOVE, 0);
}
2023-04-16 15:40:32 -07:00
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
super.lapse(pokemon, lapseType);
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' flinched!')));
return true;
2023-04-14 22:32:16 -07:00
}
}
export class PseudoStatusTag extends BattleTag {
2023-04-16 15:40:32 -07:00
constructor(tagType: BattleTagType, lapseType: BattleTagLapseType, turnCount: integer) {
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) {
super(BattleTagType.CONFUSED, BattleTagLapseType.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));
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' became\nconfused!')));
}
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' snapped\nout of confusion!')));
}
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' is\nalready confused!')));
}
2023-04-16 15:40:32 -07:00
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
const ret = super.lapse(pokemon, lapseType);
2023-04-14 22:32:16 -07:00
if (ret) {
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' is\nconfused!')));
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));
pokemon.damage(damage);
2023-04-14 22:32:16 -07:00
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, '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() {
super(BattleTagType.SEEDED, BattleTagLapseType.AFTER_MOVE, 1);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' was seeded!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
console.trace(lapseType);
const ret = lapseType !== BattleTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, !pokemon.isPlayer(), CommonAnim.LEECH_SEED));
const damage = Math.max(Math.floor(pokemon.getMaxHp() / 8), 1);
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() {
super(BattleTagType.NIGHTMARE, BattleTagLapseType.AFTER_MOVE, 1);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
2023-04-18 09:30:47 -07:00
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' began\nhaving a NIGHTMARE!')));
2023-04-16 15:40:32 -07:00
}
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
2023-04-18 09:30:47 -07:00
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' is\nalready locked in a NIGHTMARE!')));
2023-04-16 15:40:32 -07:00
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
const ret = lapseType !== BattleTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
2023-04-18 09:30:47 -07:00
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, 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);
pokemon.damage(damage);
2023-04-16 15:40:32 -07:00
pokemon.scene.unshiftPhase(new DamagePhase(pokemon.scene, pokemon.isPlayer()));
}
return ret;
}
}
2023-04-18 09:30:47 -07:00
export class ProtectedTag extends BattleTag {
constructor() {
super(BattleTagType.PROTECTED, BattleTagLapseType.CUSTOM, 0);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, '\nprotected itself!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
console.log(pokemon, BattleTagLapseType[lapseType]);
if (lapseType === BattleTagLapseType.CUSTOM) {
new CommonBattleAnim(CommonAnim.PROTECT, pokemon).play(pokemon.scene);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, '\nprotected itself!')));
return true;
}
return super.lapse(pokemon, lapseType);
}
}
2023-04-14 22:32:16 -07:00
export class HideSpriteTag extends BattleTag {
constructor(tagType: BattleTagType, turnCount: integer) {
super(tagType, BattleTagLapseType.MOVE_EFFECT, turnCount);
}
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-14 22:32:16 -07:00
export function getBattleTag(tagType: BattleTagType, turnCount: integer): BattleTag {
switch (tagType) {
case BattleTagType.FLINCHED:
return new FlinchedTag();
2023-04-14 22:32:16 -07:00
case BattleTagType.CONFUSED:
2023-04-16 15:40:32 -07:00
return new ConfusedTag(turnCount);
2023-04-18 09:30:47 -07:00
case BattleTagType.SEEDED:
return new SeedTag();
2023-04-16 15:40:32 -07:00
case BattleTagType.NIGHTMARE:
return new NightmareTag();
2023-04-18 09:30:47 -07:00
case BattleTagType.PROTECTED:
return new ProtectedTag();
2023-04-14 22:32:16 -07:00
case BattleTagType.FLYING:
case BattleTagType.UNDERGROUND:
return new HideSpriteTag(tagType, turnCount);
2023-04-16 15:40:32 -07:00
case BattleTagType.BYPASS_SLEEP:
return new BattleTag(BattleTagType.BYPASS_SLEEP, BattleTagLapseType.TURN_END, turnCount);
2023-04-15 21:29:55 -07:00
case BattleTagType.IGNORE_FLYING:
return new BattleTag(tagType, BattleTagLapseType.TURN_END, turnCount);
2023-04-14 22:32:16 -07:00
default:
return new BattleTag(tagType, BattleTagLapseType.CUSTOM, turnCount);
2023-04-13 09:16:36 -07:00
}
}