pokerogue/src/data/arena-tag.ts

287 lines
8.0 KiB
TypeScript
Raw Normal View History

2023-04-21 16:30:04 -07:00
import { Arena } from "../arena";
import { Type } from "./type";
import * as Utils from "../utils";
import { Moves, allMoves } from "./move";
import { getPokemonMessage } from "../messages";
import Pokemon, { DamageResult, HitResult, MoveResult } from "../pokemon";
import { DamagePhase, ObtainStatusEffectPhase } from "../battle-phases";
import { StatusEffect } from "./status-effect";
import { BattlerTagType } from "./battler-tag";
2023-04-21 16:30:04 -07:00
export enum ArenaTagType {
NONE,
MUD_SPORT,
WATER_SPORT,
SPIKES,
TOXIC_SPIKES,
STEALTH_ROCK,
2023-05-08 15:48:35 -07:00
TRICK_ROOM,
GRAVITY
2023-04-21 16:30:04 -07:00
}
export abstract class ArenaTag {
2023-04-21 16:30:04 -07:00
public tagType: ArenaTagType;
public turnCount: integer;
public sourceMove: Moves;
public sourceId: integer;
2023-04-21 16:30:04 -07:00
2023-05-08 15:48:35 -07:00
constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId?: integer) {
2023-04-21 16:30:04 -07:00
this.tagType = tagType;
this.turnCount = turnCount;
this.sourceMove = sourceMove;
this.sourceId = sourceId;
2023-04-21 16:30:04 -07:00
}
apply(args: any[]): boolean {
return true;
}
onAdd(arena: Arena): void { }
onRemove(arena: Arena): void {
arena.scene.queueMessage(`${this.getMoveName()}\'s effect wore off.`);
}
2023-04-21 16:30:04 -07:00
onOverlap(arena: Arena): void { }
lapse(arena: Arena): boolean {
return this.turnCount < 1 || !!(--this.turnCount);
}
getMoveName(): string {
return this.sourceMove
? allMoves[this.sourceMove].name
: null;
2023-04-21 16:30:04 -07:00
}
}
export class WeakenMoveTypeTag extends ArenaTag {
2023-04-21 16:30:04 -07:00
private weakenedType: Type;
constructor(tagType: ArenaTagType, turnCount: integer, type: Type, sourceMove: Moves, sourceId: integer) {
super(tagType, turnCount, sourceMove, sourceId);
2023-04-21 16:30:04 -07:00
this.weakenedType = type;
}
apply(args: any[]): boolean {
if ((args[0] as Type) === this.weakenedType) {
(args[1] as Utils.NumberHolder).value *= 0.33;
return true;
}
return false;
}
}
class MudSportTag extends WeakenMoveTypeTag {
constructor(turnCount: integer, sourceId: integer) {
super(ArenaTagType.MUD_SPORT, turnCount, Type.ELECTRIC, Moves.MUD_SPORT, sourceId);
2023-04-21 16:30:04 -07:00
}
onAdd(arena: Arena): void {
arena.scene.queueMessage('Electricity\'s power was weakened!');
}
2023-05-08 15:48:35 -07:00
onRemove(arena: Arena): void {
arena.scene.queueMessage('The effects of MUD SPORT\nhave faded.');
}
}
class WaterSportTag extends WeakenMoveTypeTag {
constructor(turnCount: integer, sourceId: integer) {
super(ArenaTagType.WATER_SPORT, turnCount, Type.FIRE, Moves.WATER_SPORT, sourceId);
}
2023-04-21 16:30:04 -07:00
onAdd(arena: Arena): void {
arena.scene.queueMessage('Fire\'s power was weakened!');
2023-04-21 16:30:04 -07:00
}
2023-05-08 15:48:35 -07:00
onRemove(arena: Arena): void {
arena.scene.queueMessage('The effects of WATER SPORT\nhave faded.');
}
2023-04-21 16:30:04 -07:00
}
export class ArenaTrapTag extends ArenaTag {
public layers: integer;
public maxLayers: integer;
constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: integer, maxLayers: integer) {
super(tagType, 0, sourceMove, sourceId);
this.layers = 1;
this.maxLayers = maxLayers;
}
onOverlap(arena: Arena): void {
if (this.layers < this.maxLayers) {
this.layers++;
this.onAdd(arena);
}
}
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
if (this.sourceId === pokemon.id || pokemon.scene.getPokemonById(this.sourceId).isPlayer() === pokemon.isPlayer())
return false;
return this.activateTrap(pokemon);
}
activateTrap(pokemon: Pokemon): boolean {
return false;
}
}
class SpikesTag extends ArenaTrapTag {
constructor(sourceId: integer) {
super(ArenaTagType.SPIKES, Moves.SPIKES, sourceId, 3);
2023-04-21 16:30:04 -07:00
}
onAdd(arena: Arena): void {
super.onAdd(arena);
const source = arena.scene.getPokemonById(this.sourceId);
arena.scene.queueMessage(`${this.getMoveName()} were scattered\nall around ${source.getOpponentDescriptor()}'s feet!`);
2023-04-21 16:30:04 -07:00
}
activateTrap(pokemon: Pokemon): boolean {
2023-05-08 15:48:35 -07:00
if ((!pokemon.isOfType(Type.FLYING) || pokemon.getTag(BattlerTagType.IGNORE_FLYING) || pokemon.scene.arena.getTag(ArenaTagType.GRAVITY))) {
const damageHpRatio = 1 / (10 - 2 * this.layers);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' is hurt\nby the spikes!'));
pokemon.scene.unshiftPhase(new DamagePhase(pokemon.scene, pokemon.getBattlerIndex(), HitResult.OTHER));
pokemon.damage(Math.ceil(pokemon.getMaxHp() * damageHpRatio));
return true;
}
return false;
}
}
class ToxicSpikesTag extends ArenaTrapTag {
constructor(sourceId: integer) {
super(ArenaTagType.TOXIC_SPIKES, Moves.TOXIC_SPIKES, sourceId, 2);
}
onAdd(arena: Arena): void {
super.onAdd(arena);
const source = arena.scene.getPokemonById(this.sourceId);
arena.scene.queueMessage(`${this.getMoveName()} were scattered\nall around ${source.getOpponentDescriptor()}'s feet!`);
}
activateTrap(pokemon: Pokemon): boolean {
2023-05-08 15:48:35 -07:00
if (!pokemon.status && (!pokemon.isOfType(Type.FLYING) || pokemon.getTag(BattlerTagType.IGNORE_FLYING) || pokemon.scene.arena.getTag(ArenaTagType.GRAVITY))) {
const toxic = this.layers > 1;
pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, pokemon.getBattlerIndex(),
!toxic ? StatusEffect.POISON : StatusEffect.TOXIC, null, `the ${this.getMoveName()}`));
return true;
}
return false;
}
}
class StealthRockTag extends ArenaTrapTag {
constructor(sourceId: integer) {
super(ArenaTagType.STEALTH_ROCK, Moves.STEALTH_ROCK, sourceId, 1);
}
onAdd(arena: Arena): void {
super.onAdd(arena);
const source = arena.scene.getPokemonById(this.sourceId);
arena.scene.queueMessage(`Pointed stones float in the air\naround ${source.getOpponentDescriptor()}!`);
}
activateTrap(pokemon: Pokemon): boolean {
const effectiveness = pokemon.getAttackMoveEffectiveness(Type.ROCK);
let damageHpRatio: number;
switch (effectiveness) {
case 0:
damageHpRatio = 0;
break;
case 0.25:
damageHpRatio = 0.03125;
break;
case 0.5:
damageHpRatio = 0.0625;
break;
case 1:
damageHpRatio = 0.125;
break;
case 2:
damageHpRatio = 0.25;
break;
case 4:
damageHpRatio = 0.5;
break;
}
if (damageHpRatio) {
pokemon.scene.queueMessage(`Pointed stones dug into\n${pokemon.name}!`);
pokemon.scene.unshiftPhase(new DamagePhase(pokemon.scene, pokemon.getBattlerIndex(), HitResult.OTHER));
pokemon.damage(Math.ceil(pokemon.getMaxHp() * damageHpRatio));
}
return false;
}
}
export class TrickRoomTag extends ArenaTag {
constructor(turnCount: integer, sourceId: integer) {
super(ArenaTagType.TRICK_ROOM, turnCount, Moves.TRICK_ROOM, sourceId);
}
apply(args: any[]): boolean {
const speedReversed = args[0] as Utils.BooleanHolder;
speedReversed.value = !speedReversed.value;
return true;
}
onAdd(arena: Arena): void {
arena.scene.queueMessage(getPokemonMessage(arena.scene.getPokemonById(this.sourceId), ' twisted\nthe dimensions!'));
2023-04-21 16:30:04 -07:00
}
2023-05-08 15:48:35 -07:00
onRemove(arena: Arena): void {
arena.scene.queueMessage('The twisted dimensions\nreturned to normal!');
}
}
export class GravityTag extends ArenaTag {
constructor(turnCount: integer) {
super(ArenaTagType.GRAVITY, turnCount, Moves.GRAVITY);
}
onAdd(arena: Arena): void {
arena.scene.queueMessage('Gravity intensified!');
}
onRemove(arena: Arena): void {
arena.scene.queueMessage('Gravity returned to normal!');
}
2023-04-21 16:30:04 -07:00
}
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): ArenaTag {
2023-04-21 16:30:04 -07:00
switch (tagType) {
case ArenaTagType.MUD_SPORT:
return new MudSportTag(turnCount, sourceId);
2023-04-21 16:30:04 -07:00
case ArenaTagType.WATER_SPORT:
return new WaterSportTag(turnCount, sourceId);
case ArenaTagType.SPIKES:
return new SpikesTag(sourceId);
case ArenaTagType.TOXIC_SPIKES:
return new ToxicSpikesTag(sourceId);
case ArenaTagType.STEALTH_ROCK:
return new StealthRockTag(sourceId);
case ArenaTagType.TRICK_ROOM:
return new TrickRoomTag(turnCount, sourceId);
2023-05-08 15:48:35 -07:00
case ArenaTagType.GRAVITY:
return new GravityTag(turnCount);
2023-04-21 16:30:04 -07:00
}
}