Refactor move attribute logic and add arena trap moves
parent
77b3f136dd
commit
92c8583129
|
@ -8,7 +8,7 @@ import { Weather, WeatherType, getWeatherClearMessage, getWeatherStartMessage }
|
|||
import { CommonAnimPhase } from "./battle-phases";
|
||||
import { CommonAnim } from "./data/battle-anims";
|
||||
import { Type } from "./data/type";
|
||||
import Move from "./data/move";
|
||||
import Move, { Moves } from "./data/move";
|
||||
import { ArenaTag, ArenaTagType, getArenaTag } from "./data/arena-tag";
|
||||
|
||||
export class Arena {
|
||||
|
@ -224,14 +224,14 @@ export class Arena {
|
|||
tags.forEach(t => t.apply(args));
|
||||
}
|
||||
|
||||
addTag(tagType: ArenaTagType, turnCount: integer): boolean {
|
||||
addTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): boolean {
|
||||
const existingTag = this.getTag(tagType);
|
||||
if (existingTag) {
|
||||
existingTag.onOverlap(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
const newTag = getArenaTag(tagType, turnCount || 0);
|
||||
const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId);
|
||||
this.tags.push(newTag);
|
||||
newTag.onAdd(this);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import BattleScene, { startingLevel, startingWave } from "./battle-scene";
|
||||
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult } from "./pokemon";
|
||||
import * as Utils from './utils';
|
||||
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, ConditionalMoveAttr, HitsTagAttr, MissEffectAttr, MoveCategory, MoveEffectAttr, MoveFlags, MoveHitEffectAttr, Moves, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr } from "./data/move";
|
||||
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, HitsTagAttr, MissEffectAttr, MoveCategory, MoveEffectAttr, MoveFlags, MoveHitEffectAttr, Moves, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr } from "./data/move";
|
||||
import { Mode } from './ui/ui';
|
||||
import { Command } from "./ui/command-ui-handler";
|
||||
import { Stat } from "./data/pokemon-stat";
|
||||
|
@ -24,6 +24,7 @@ import { Starter } from "./ui/starter-select-ui-handler";
|
|||
import { Gender } from "./data/gender";
|
||||
import { Weather, WeatherType, getRandomWeatherType, getWeatherDamageMessage, getWeatherLapseMessage } from "./data/weather";
|
||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||
import { ArenaTrapTag, TrickRoomTag } from "./data/arena-tag";
|
||||
|
||||
export class SelectStarterPhase extends BattlePhase {
|
||||
constructor(scene: BattleScene) {
|
||||
|
@ -118,6 +119,8 @@ export class EncounterPhase extends BattlePhase {
|
|||
if (this.scene.getEnemyPokemon().shiny)
|
||||
this.scene.unshiftPhase(new ShinySparklePhase(this.scene, false));
|
||||
|
||||
this.scene.arena.applyTags(ArenaTrapTag, this.scene.getEnemyPokemon());
|
||||
|
||||
// TODO: Remove
|
||||
//this.scene.unshiftPhase(new SelectModifierPhase(this.scene));
|
||||
|
||||
|
@ -329,6 +332,7 @@ export class SummonPhase extends BattlePhase {
|
|||
playerPokemon.getSprite().clearTint();
|
||||
playerPokemon.resetSummonData();
|
||||
this.scene.time.delayedCall(1000, () => this.end());
|
||||
this.scene.arena.applyTags(ArenaTrapTag, playerPokemon);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -505,7 +509,10 @@ export class CommandPhase extends BattlePhase {
|
|||
return true;
|
||||
}
|
||||
|
||||
return playerSpeed < enemySpeed || (playerSpeed === enemySpeed && Utils.randInt(2) === 1);
|
||||
const speedDelayed = new Utils.BooleanHolder(playerSpeed < enemySpeed);
|
||||
this.scene.arena.applyTags(TrickRoomTag, speedDelayed);
|
||||
|
||||
return speedDelayed.value || (playerSpeed === enemySpeed && Utils.randInt(2) === 1);
|
||||
};
|
||||
|
||||
let playerMove: PokemonMove;
|
||||
|
@ -633,7 +640,10 @@ export class TurnEndPhase extends BattlePhase {
|
|||
const playerSpeed = playerPokemon?.getBattleStat(Stat.SPD) || 0;
|
||||
const enemySpeed = enemyPokemon?.getBattleStat(Stat.SPD) || 0;
|
||||
|
||||
const isDelayed = playerSpeed < enemySpeed || (playerSpeed === enemySpeed && Utils.randInt(2) === 1);
|
||||
const speedDelayed = new Utils.BooleanHolder(playerSpeed < enemySpeed);
|
||||
this.scene.arena.applyTags(TrickRoomTag, speedDelayed);
|
||||
|
||||
const isDelayed = speedDelayed.value || (playerSpeed === enemySpeed && Utils.randInt(2) === 1);
|
||||
|
||||
if (!isDelayed)
|
||||
handlePokemon(playerPokemon);
|
||||
|
@ -767,15 +777,15 @@ export abstract class MovePhase extends BattlePhase {
|
|||
if (!moveQueue.length || !moveQueue.shift().ignorePP)
|
||||
this.move.ppUsed++;
|
||||
|
||||
const failed = new Utils.BooleanHolder(false);
|
||||
applyMoveAttrs(ConditionalMoveAttr, this.pokemon, target, this.move.getMove(), failed);
|
||||
if (!failed.value && this.scene.arena.isMoveWeatherCancelled(this.move.getMove()))
|
||||
failed.value = true;
|
||||
if (failed.value) {
|
||||
let success = this.move.getMove().applyConditions(this.pokemon, target, this.move.getMove());
|
||||
if (success && this.scene.arena.isMoveWeatherCancelled(this.move.getMove()))
|
||||
success = false;
|
||||
if (success)
|
||||
this.scene.unshiftPhase(this.getEffectPhase());
|
||||
else {
|
||||
this.pokemon.getMoveHistory().push({ move: this.move.moveId, result: MoveResult.FAILED, virtual: this.move.virtual });
|
||||
this.scene.queueMessage('But it failed!');
|
||||
} else
|
||||
this.scene.unshiftPhase(this.getEffectPhase());
|
||||
}
|
||||
|
||||
this.end();
|
||||
};
|
||||
|
@ -1175,12 +1185,14 @@ export class WeatherEffectPhase extends CommonAnimPhase {
|
|||
export class ObtainStatusEffectPhase extends PokemonPhase {
|
||||
private statusEffect: StatusEffect;
|
||||
private cureTurn: integer;
|
||||
private sourceText: string;
|
||||
|
||||
constructor(scene: BattleScene, player: boolean, statusEffect: StatusEffect, cureTurn?: integer) {
|
||||
constructor(scene: BattleScene, player: boolean, statusEffect: StatusEffect, cureTurn?: integer, sourceText?: string) {
|
||||
super(scene, player);
|
||||
|
||||
this.statusEffect = statusEffect;
|
||||
this.cureTurn = cureTurn;
|
||||
this.sourceText = sourceText;
|
||||
}
|
||||
|
||||
start() {
|
||||
|
@ -1191,7 +1203,7 @@ export class ObtainStatusEffectPhase extends PokemonPhase {
|
|||
pokemon.status.cureTurn = this.cureTurn;
|
||||
pokemon.updateInfo(true);
|
||||
new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect - 1), pokemon).play(this.scene, () => {
|
||||
this.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectObtainText(this.statusEffect)));
|
||||
this.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectObtainText(this.statusEffect, this.sourceText)));
|
||||
if (pokemon.status.isPostTurn())
|
||||
this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, this.player));
|
||||
this.end();
|
||||
|
|
|
@ -1,20 +1,34 @@
|
|||
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, MoveResult } from "../pokemon";
|
||||
import { DamagePhase, ObtainStatusEffectPhase } from "../battle-phases";
|
||||
import { StatusEffect } from "./status-effect";
|
||||
import { BattlerTagType } from "./battler-tag";
|
||||
|
||||
export enum ArenaTagType {
|
||||
NONE,
|
||||
MUD_SPORT,
|
||||
WATER_SPORT
|
||||
WATER_SPORT,
|
||||
SPIKES,
|
||||
TOXIC_SPIKES,
|
||||
STEALTH_ROCK,
|
||||
TRICK_ROOM
|
||||
}
|
||||
|
||||
export class ArenaTag {
|
||||
export abstract class ArenaTag {
|
||||
public tagType: ArenaTagType;
|
||||
public turnCount: integer;
|
||||
public sourceMove: Moves;
|
||||
public sourceId: integer;
|
||||
|
||||
constructor(tagType: ArenaTagType, turnCount: integer) {
|
||||
constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer) {
|
||||
this.tagType = tagType;
|
||||
this.turnCount = turnCount;
|
||||
this.sourceMove = sourceMove;
|
||||
this.sourceId = sourceId;
|
||||
}
|
||||
|
||||
apply(args: any[]): boolean {
|
||||
|
@ -23,20 +37,28 @@ export class ArenaTag {
|
|||
|
||||
onAdd(arena: Arena): void { }
|
||||
|
||||
onRemove(arena: Arena): void { }
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage(`${this.getMoveName()}\'s effect wore off.`);
|
||||
}
|
||||
|
||||
onOverlap(arena: Arena): void { }
|
||||
|
||||
lapse(arena: Arena): boolean {
|
||||
return --this.turnCount > 0;
|
||||
return this.turnCount < 1 || !!(--this.turnCount);
|
||||
}
|
||||
|
||||
getMoveName(): string {
|
||||
return this.sourceMove
|
||||
? allMoves[this.sourceMove].name
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
export class WeakenTypeTag extends ArenaTag {
|
||||
export class WeakenMoveTypeTag extends ArenaTag {
|
||||
private weakenedType: Type;
|
||||
|
||||
constructor(tagType: ArenaTagType, turnCount: integer, type: Type) {
|
||||
super(tagType, turnCount);
|
||||
constructor(tagType: ArenaTagType, turnCount: integer, type: Type, sourceMove: Moves, sourceId: integer) {
|
||||
super(tagType, turnCount, sourceMove, sourceId);
|
||||
|
||||
this.weakenedType = type;
|
||||
}
|
||||
|
@ -51,39 +73,189 @@ export class WeakenTypeTag extends ArenaTag {
|
|||
}
|
||||
}
|
||||
|
||||
class MudSportTag extends WeakenTypeTag {
|
||||
constructor(turnCount: integer) {
|
||||
super(ArenaTagType.MUD_SPORT, turnCount, Type.ELECTRIC);
|
||||
class MudSportTag extends WeakenMoveTypeTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(ArenaTagType.MUD_SPORT, turnCount, Type.ELECTRIC, Moves.MUD_SPORT, sourceId);
|
||||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage('Electricity\'s power was weakened!');
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage('MUD SPORT\'s effect wore off.');
|
||||
}
|
||||
}
|
||||
|
||||
class WaterSportTag extends WeakenTypeTag {
|
||||
constructor(turnCount: integer) {
|
||||
super(ArenaTagType.WATER_SPORT, turnCount, Type.FIRE);
|
||||
class WaterSportTag extends WeakenMoveTypeTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(ArenaTagType.WATER_SPORT, turnCount, Type.FIRE, Moves.WATER_SPORT, sourceId);
|
||||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage('Fire\'s power was weakened!');
|
||||
}
|
||||
}
|
||||
|
||||
onRemove(arena: Arena): void {
|
||||
arena.scene.queueMessage('WATER SPORT\'s effect wore off.');
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
export function getArenaTag(tagType: ArenaTagType, turnCount: integer): ArenaTag {
|
||||
class SpikesTag extends ArenaTrapTag {
|
||||
constructor(sourceId: integer) {
|
||||
super(ArenaTagType.SPIKES, Moves.SPIKES, sourceId, 3);
|
||||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
super.onAdd(arena);
|
||||
|
||||
const source = arena.scene.getPokemonById(this.sourceId);
|
||||
const target = source.isPlayer() ? source.scene.getEnemyPokemon() : source.scene.getPlayerPokemon();
|
||||
arena.scene.queueMessage(`${this.getMoveName()} were scattered\nall around ${target.name}'s feet!`);
|
||||
}
|
||||
|
||||
activateTrap(pokemon: Pokemon): boolean {
|
||||
if ((!pokemon.isOfType(Type.FLYING) || pokemon.getTag(BattlerTagType.IGNORE_FLYING))) {
|
||||
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.isPlayer(), MoveResult.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);
|
||||
const target = source.isPlayer() ? source.scene.getEnemyPokemon() : source.scene.getPlayerPokemon();
|
||||
arena.scene.queueMessage(`${this.getMoveName()} were scattered\nall around ${target.name}'s feet!`);
|
||||
}
|
||||
|
||||
activateTrap(pokemon: Pokemon): boolean {
|
||||
if (!pokemon.status && (!pokemon.isOfType(Type.FLYING) || pokemon.getTag(BattlerTagType.IGNORE_FLYING))) {
|
||||
const toxic = this.layers > 1;
|
||||
|
||||
pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, pokemon.isPlayer(),
|
||||
!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);
|
||||
const target = source.isPlayer() ? source.scene.getEnemyPokemon() : source.scene.getPlayerPokemon();
|
||||
arena.scene.queueMessage(`Pointed stones float in the air\naround ${target.name}!`);
|
||||
}
|
||||
|
||||
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.isPlayer(), MoveResult.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 speedDelayed = args[0] as Utils.BooleanHolder;
|
||||
speedDelayed.value = !speedDelayed.value;
|
||||
return true;
|
||||
}
|
||||
|
||||
onAdd(arena: Arena): void {
|
||||
arena.scene.queueMessage(getPokemonMessage(arena.scene.getPokemonById(this.sourceId), ' twisted\nthe dimensions!'));
|
||||
}
|
||||
}
|
||||
|
||||
export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): ArenaTag {
|
||||
switch (tagType) {
|
||||
case ArenaTagType.MUD_SPORT:
|
||||
return new MudSportTag(turnCount);
|
||||
return new MudSportTag(turnCount, sourceId);
|
||||
case ArenaTagType.WATER_SPORT:
|
||||
return new WaterSportTag(turnCount);
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -48,15 +48,15 @@ export class BattlerTag {
|
|||
public tagType: BattlerTagType;
|
||||
public lapseType: BattlerTagLapseType;
|
||||
public turnCount: integer;
|
||||
public sourceId: integer;
|
||||
public sourceMove: Moves;
|
||||
public sourceId?: integer;
|
||||
|
||||
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: integer, sourceId?: integer, sourceMove?: Moves) {
|
||||
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: integer, sourceMove: Moves, sourceId?: integer) {
|
||||
this.tagType = tagType;
|
||||
this.lapseType = lapseType;
|
||||
this.turnCount = turnCount;
|
||||
this.sourceId = sourceId;
|
||||
this.sourceMove = sourceMove;
|
||||
this.sourceId = sourceId;
|
||||
}
|
||||
|
||||
canAdd(pokemon: Pokemon): boolean {
|
||||
|
@ -73,6 +73,10 @@ export class BattlerTag {
|
|||
return --this.turnCount > 0;
|
||||
}
|
||||
|
||||
isSourceLinked(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getMoveName(): string {
|
||||
return this.sourceMove
|
||||
? allMoves[this.sourceMove].name
|
||||
|
@ -81,8 +85,8 @@ export class BattlerTag {
|
|||
}
|
||||
|
||||
export class RechargingTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.RECHARGING, BattlerTagLapseType.MOVE, 1);
|
||||
constructor(sourceMove: Moves) {
|
||||
super(BattlerTagType.RECHARGING, BattlerTagLapseType.MOVE, 1, sourceMove);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
|
@ -102,8 +106,8 @@ export class RechargingTag extends BattlerTag {
|
|||
}
|
||||
|
||||
export class TrappedTag extends BattlerTag {
|
||||
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: integer, sourceId: integer, sourceMove: Moves) {
|
||||
super(tagType, lapseType, turnCount, sourceId, sourceMove);
|
||||
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: integer, sourceMove: Moves, sourceId: integer) {
|
||||
super(tagType, lapseType, turnCount, sourceMove, sourceId);
|
||||
}
|
||||
|
||||
canAdd(pokemon: Pokemon): boolean {
|
||||
|
@ -122,14 +126,18 @@ export class TrappedTag extends BattlerTag {
|
|||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` was freed\nfrom ${this.getMoveName()}!`));
|
||||
}
|
||||
|
||||
isSourceLinked(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
getTrapMessage(pokemon: Pokemon): string {
|
||||
return getPokemonMessage(pokemon, ' can no\nlonger escape!');
|
||||
}
|
||||
}
|
||||
|
||||
export class FlinchedTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.FLINCHED, BattlerTagLapseType.MOVE, 0);
|
||||
constructor(sourceMove: Moves) {
|
||||
super(BattlerTagType.FLINCHED, BattlerTagLapseType.MOVE, 0, sourceMove);
|
||||
}
|
||||
|
||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||
|
@ -143,8 +151,8 @@ export class FlinchedTag extends BattlerTag {
|
|||
}
|
||||
|
||||
export class ConfusedTag extends BattlerTag {
|
||||
constructor(turnCount: integer) {
|
||||
super(BattlerTagType.CONFUSED, BattlerTagLapseType.MOVE, turnCount);
|
||||
constructor(turnCount: integer, sourceMove: Moves) {
|
||||
super(BattlerTagType.CONFUSED, BattlerTagLapseType.MOVE, turnCount, sourceMove);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
|
@ -190,7 +198,7 @@ export class ConfusedTag extends BattlerTag {
|
|||
|
||||
export class SeedTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.SEEDED, BattlerTagLapseType.AFTER_MOVE, 1);
|
||||
super(BattlerTagType.SEEDED, BattlerTagLapseType.AFTER_MOVE, 1, Moves.LEECH_SEED);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
|
@ -217,7 +225,7 @@ export class SeedTag extends BattlerTag {
|
|||
|
||||
export class NightmareTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.NIGHTMARE, BattlerTagLapseType.AFTER_MOVE, 1);
|
||||
super(BattlerTagType.NIGHTMARE, BattlerTagLapseType.AFTER_MOVE, 1, Moves.NIGHTMARE);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
|
@ -250,7 +258,7 @@ export class NightmareTag extends BattlerTag {
|
|||
|
||||
export class IngrainTag extends TrappedTag {
|
||||
constructor(sourceId: integer) {
|
||||
super(BattlerTagType.INGRAIN, BattlerTagLapseType.TURN_END, 1, sourceId, Moves.INGRAIN);
|
||||
super(BattlerTagType.INGRAIN, BattlerTagLapseType.TURN_END, 1, Moves.INGRAIN, sourceId);
|
||||
}
|
||||
|
||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||
|
@ -270,7 +278,7 @@ export class IngrainTag extends TrappedTag {
|
|||
|
||||
export class AquaRingTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.AQUA_RING, BattlerTagLapseType.TURN_END, 1, undefined, Moves.AQUA_RING);
|
||||
super(BattlerTagType.AQUA_RING, BattlerTagLapseType.TURN_END, 1, Moves.AQUA_RING, undefined);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
|
@ -291,7 +299,7 @@ export class AquaRingTag extends BattlerTag {
|
|||
|
||||
export class DrowsyTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.DROWSY, BattlerTagLapseType.TURN_END, 2);
|
||||
super(BattlerTagType.DROWSY, BattlerTagLapseType.TURN_END, 2, Moves.YAWN);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
|
@ -313,8 +321,8 @@ export class DrowsyTag extends BattlerTag {
|
|||
export abstract class DamagingTrapTag extends TrappedTag {
|
||||
private commonAnim: CommonAnim;
|
||||
|
||||
constructor(tagType: BattlerTagType, commonAnim: CommonAnim, turnCount: integer, sourceId: integer, sourceMove: Moves) {
|
||||
super(tagType, BattlerTagLapseType.TURN_END, turnCount, sourceId, sourceMove);
|
||||
constructor(tagType: BattlerTagType, commonAnim: CommonAnim, turnCount: integer, sourceMove: Moves, sourceId: integer) {
|
||||
super(tagType, BattlerTagLapseType.TURN_END, turnCount, sourceMove, sourceId);
|
||||
|
||||
this.commonAnim = commonAnim;
|
||||
}
|
||||
|
@ -341,7 +349,7 @@ export abstract class DamagingTrapTag extends TrappedTag {
|
|||
|
||||
export class BindTag extends DamagingTrapTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(BattlerTagType.BIND, CommonAnim.BIND, turnCount, sourceId, Moves.BIND);
|
||||
super(BattlerTagType.BIND, CommonAnim.BIND, turnCount, Moves.BIND, sourceId);
|
||||
}
|
||||
|
||||
getTrapMessage(pokemon: Pokemon): string {
|
||||
|
@ -351,7 +359,7 @@ export class BindTag extends DamagingTrapTag {
|
|||
|
||||
export class WrapTag extends DamagingTrapTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(BattlerTagType.WRAP, CommonAnim.WRAP, turnCount, sourceId, Moves.WRAP);
|
||||
super(BattlerTagType.WRAP, CommonAnim.WRAP, turnCount, Moves.WRAP, sourceId);
|
||||
}
|
||||
|
||||
getTrapMessage(pokemon: Pokemon): string {
|
||||
|
@ -360,8 +368,8 @@ export class WrapTag extends DamagingTrapTag {
|
|||
}
|
||||
|
||||
export abstract class VortexTrapTag extends DamagingTrapTag {
|
||||
constructor(tagType: BattlerTagType, commonAnim: CommonAnim, turnCount: integer, sourceId: integer, sourceMove: Moves) {
|
||||
super(tagType, commonAnim, turnCount, sourceId, sourceMove);
|
||||
constructor(tagType: BattlerTagType, commonAnim: CommonAnim, turnCount: integer, sourceMove: Moves, sourceId: integer) {
|
||||
super(tagType, commonAnim, turnCount, sourceMove, sourceId);
|
||||
}
|
||||
|
||||
getTrapMessage(pokemon: Pokemon): string {
|
||||
|
@ -371,19 +379,19 @@ export abstract class VortexTrapTag extends DamagingTrapTag {
|
|||
|
||||
export class FireSpinTag extends VortexTrapTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(BattlerTagType.FIRE_SPIN, CommonAnim.FIRE_SPIN, turnCount, sourceId, Moves.FIRE_SPIN);
|
||||
super(BattlerTagType.FIRE_SPIN, CommonAnim.FIRE_SPIN, turnCount, Moves.FIRE_SPIN, sourceId);
|
||||
}
|
||||
}
|
||||
|
||||
export class WhirlpoolTag extends VortexTrapTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(BattlerTagType.WHIRLPOOL, CommonAnim.WHIRLPOOL, turnCount, sourceId, Moves.WHIRLPOOL);
|
||||
super(BattlerTagType.WHIRLPOOL, CommonAnim.WHIRLPOOL, turnCount, Moves.WHIRLPOOL, sourceId);
|
||||
}
|
||||
}
|
||||
|
||||
export class ClampTag extends DamagingTrapTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(BattlerTagType.CLAMP, CommonAnim.CLAMP, turnCount, sourceId, Moves.CLAMP);
|
||||
super(BattlerTagType.CLAMP, CommonAnim.CLAMP, turnCount, Moves.CLAMP, sourceId);
|
||||
}
|
||||
|
||||
getTrapMessage(pokemon: Pokemon): string {
|
||||
|
@ -393,7 +401,7 @@ export class ClampTag extends DamagingTrapTag {
|
|||
|
||||
export class SandTombTag extends DamagingTrapTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(BattlerTagType.SAND_TOMB, CommonAnim.SAND_TOMB, turnCount, sourceId, Moves.SAND_TOMB);
|
||||
super(BattlerTagType.SAND_TOMB, CommonAnim.SAND_TOMB, turnCount, Moves.SAND_TOMB, sourceId);
|
||||
}
|
||||
|
||||
getTrapMessage(pokemon: Pokemon): string {
|
||||
|
@ -403,7 +411,7 @@ export class SandTombTag extends DamagingTrapTag {
|
|||
|
||||
export class MagmaStormTag extends DamagingTrapTag {
|
||||
constructor(turnCount: integer, sourceId: integer) {
|
||||
super(BattlerTagType.MAGMA_STORM, CommonAnim.MAGMA_STORM, turnCount, sourceId, Moves.MAGMA_STORM);
|
||||
super(BattlerTagType.MAGMA_STORM, CommonAnim.MAGMA_STORM, turnCount, Moves.MAGMA_STORM, sourceId);
|
||||
}
|
||||
|
||||
getTrapMessage(pokemon: Pokemon): string {
|
||||
|
@ -412,8 +420,8 @@ export class MagmaStormTag extends DamagingTrapTag {
|
|||
}
|
||||
|
||||
export class ProtectedTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.PROTECTED, BattlerTagLapseType.CUSTOM, 0);
|
||||
constructor(sourceMove: Moves) {
|
||||
super(BattlerTagType.PROTECTED, BattlerTagLapseType.CUSTOM, 0, sourceMove);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
|
@ -434,8 +442,8 @@ export class ProtectedTag extends BattlerTag {
|
|||
}
|
||||
|
||||
export class HideSpriteTag extends BattlerTag {
|
||||
constructor(tagType: BattlerTagType, turnCount: integer) {
|
||||
super(tagType, BattlerTagLapseType.MOVE_EFFECT, turnCount);
|
||||
constructor(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves) {
|
||||
super(tagType, BattlerTagLapseType.MOVE_EFFECT, turnCount, sourceMove);
|
||||
}
|
||||
|
||||
onAdd(pokemon: Pokemon): void {
|
||||
|
@ -454,14 +462,14 @@ export class HideSpriteTag extends BattlerTag {
|
|||
}
|
||||
}
|
||||
|
||||
export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourceId: integer, sourceMove: Moves): BattlerTag {
|
||||
export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): BattlerTag {
|
||||
switch (tagType) {
|
||||
case BattlerTagType.RECHARGING:
|
||||
return new RechargingTag();
|
||||
return new RechargingTag(sourceMove);
|
||||
case BattlerTagType.FLINCHED:
|
||||
return new FlinchedTag();
|
||||
return new FlinchedTag(sourceMove);
|
||||
case BattlerTagType.CONFUSED:
|
||||
return new ConfusedTag(turnCount);
|
||||
return new ConfusedTag(turnCount, sourceMove);
|
||||
case BattlerTagType.SEEDED:
|
||||
return new SeedTag();
|
||||
case BattlerTagType.NIGHTMARE:
|
||||
|
@ -473,7 +481,7 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
|
|||
case BattlerTagType.DROWSY:
|
||||
return new DrowsyTag();
|
||||
case BattlerTagType.TRAPPED:
|
||||
return new TrappedTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceId, sourceMove);
|
||||
return new TrappedTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||
case BattlerTagType.BIND:
|
||||
return new BindTag(turnCount, sourceId);
|
||||
case BattlerTagType.WRAP:
|
||||
|
@ -489,17 +497,17 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
|
|||
case BattlerTagType.MAGMA_STORM:
|
||||
return new MagmaStormTag(turnCount, sourceId);
|
||||
case BattlerTagType.PROTECTED:
|
||||
return new ProtectedTag();
|
||||
return new ProtectedTag(sourceMove);
|
||||
case BattlerTagType.FLYING:
|
||||
case BattlerTagType.UNDERGROUND:
|
||||
return new HideSpriteTag(tagType, turnCount);
|
||||
return new HideSpriteTag(tagType, turnCount, sourceMove);
|
||||
case BattlerTagType.NO_CRIT:
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.AFTER_MOVE, turnCount);
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.AFTER_MOVE, turnCount, sourceMove);
|
||||
case BattlerTagType.BYPASS_SLEEP:
|
||||
return new BattlerTag(BattlerTagType.BYPASS_SLEEP, BattlerTagLapseType.TURN_END, turnCount);
|
||||
return new BattlerTag(BattlerTagType.BYPASS_SLEEP, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
|
||||
case BattlerTagType.IGNORE_FLYING:
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount);
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
|
||||
default:
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount);
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||
}
|
||||
}
|
1443
src/data/move.ts
1443
src/data/move.ts
File diff suppressed because it is too large
Load Diff
|
@ -32,20 +32,21 @@ export class Status {
|
|||
}
|
||||
}
|
||||
|
||||
export function getStatusEffectObtainText(statusEffect: StatusEffect): string {
|
||||
export function getStatusEffectObtainText(statusEffect: StatusEffect, sourceText?: string): string {
|
||||
const sourceClause = sourceText ? ` ${statusEffect !== StatusEffect.SLEEP ? 'by' : 'from'} ${sourceText}` : '';
|
||||
switch (statusEffect) {
|
||||
case StatusEffect.POISON:
|
||||
return '\nwas poisoned!';
|
||||
return `\nwas poisoned${sourceClause}!`;
|
||||
case StatusEffect.TOXIC:
|
||||
return '\nwas badly poisoned!';
|
||||
return `\nwas badly poisoned${sourceClause}!`;
|
||||
case StatusEffect.PARALYSIS:
|
||||
return ' is paralyzed!\nIt may be unable to move!';
|
||||
return ` was paralyzed${sourceClause}!\nIt may be unable to move!`;
|
||||
case StatusEffect.SLEEP:
|
||||
return '\nfell asleep!';
|
||||
return `\nfell asleep${sourceClause}!`;
|
||||
case StatusEffect.FREEZE:
|
||||
return '\nwas frozen solid!';
|
||||
return `\nwas frozen solid${sourceClause}!`;
|
||||
case StatusEffect.BURN:
|
||||
return '\nwas burned!';
|
||||
return `\nwas burned${sourceClause}!`;
|
||||
}
|
||||
|
||||
return '';
|
||||
|
|
|
@ -19,7 +19,9 @@ export enum Type {
|
|||
FAIRY
|
||||
};
|
||||
|
||||
export function getTypeDamageMultiplier(attackType: integer, defType: integer) {
|
||||
export type TypeDamageMultiplier = 0 | 0.25 | 0.5 | 1 | 2 | 4;
|
||||
|
||||
export function getTypeDamageMultiplier(attackType: integer, defType: integer): TypeDamageMultiplier {
|
||||
switch (defType) {
|
||||
case Type.NORMAL:
|
||||
switch (attackType) {
|
||||
|
|
|
@ -5,7 +5,7 @@ import Move, { StatChangeAttr, HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedD
|
|||
import { pokemonLevelMoves } from './data/pokemon-level-moves';
|
||||
import { default as PokemonSpecies, PokemonSpeciesForm, getPokemonSpecies } from './data/pokemon-species';
|
||||
import * as Utils from './utils';
|
||||
import { Type, getTypeDamageMultiplier } from './data/type';
|
||||
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier } from './data/type';
|
||||
import { getLevelTotalExp } from './data/exp';
|
||||
import { Stat } from './data/pokemon-stat';
|
||||
import { AttackTypeBoosterModifier, PokemonBaseStatModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier } from './modifier/modifier';
|
||||
|
@ -21,7 +21,7 @@ import { BattlerTag, BattlerTagLapseType, BattlerTagType, getBattlerTag } from '
|
|||
import { Species } from './data/species';
|
||||
import { WeatherType } from './data/weather';
|
||||
import { TempBattleStat } from './data/temp-battle-stat';
|
||||
import { WeakenTypeTag as WeakenMoveTypeTag } from './data/arena-tag';
|
||||
import { WeakenMoveTypeTag } from './data/arena-tag';
|
||||
import { Biome } from './data/biome';
|
||||
|
||||
export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
@ -348,6 +348,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
return this.getTypes().indexOf(type) > -1;
|
||||
}
|
||||
|
||||
getAttackMoveEffectiveness(moveType: Type): TypeDamageMultiplier {
|
||||
const types = this.getTypes();
|
||||
return getTypeDamageMultiplier(moveType, types[0]) * (types.length ? getTypeDamageMultiplier(moveType, types[1]) : 1) as TypeDamageMultiplier;
|
||||
}
|
||||
|
||||
getEvolution(): SpeciesEvolution {
|
||||
if (!pokemonEvolutions.hasOwnProperty(this.species.speciesId))
|
||||
return null;
|
||||
|
@ -568,14 +573,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
}
|
||||
}
|
||||
|
||||
addTag(tagType: BattlerTagType, turnCount?: integer, sourceId?: integer, sourceMove?: Moves): boolean {
|
||||
addTag(tagType: BattlerTagType, turnCount?: integer, sourceMove?: Moves, sourceId?: integer): boolean {
|
||||
const existingTag = this.getTag(tagType);
|
||||
if (existingTag) {
|
||||
existingTag.onOverlap(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
const newTag = getBattlerTag(tagType, turnCount || 0, sourceId, sourceMove);
|
||||
const newTag = getBattlerTag(tagType, turnCount || 0, sourceMove, sourceId);
|
||||
|
||||
if (newTag.canAdd(this)) {
|
||||
this.summonData.tags.push(newTag);
|
||||
|
@ -951,8 +956,7 @@ export class EnemyPokemon extends Pokemon {
|
|||
if (move.category === MoveCategory.STATUS)
|
||||
moveScore++;
|
||||
else {
|
||||
const targetTypes = target.getTypes();
|
||||
const effectiveness = getTypeDamageMultiplier(move.type, targetTypes[0]) * (targetTypes.length > 1 ? getTypeDamageMultiplier(move.type, targetTypes[1]) : 1);
|
||||
const effectiveness = this.getAttackMoveEffectiveness(move.type);
|
||||
moveScore = Math.pow(effectiveness - 1, 2) * effectiveness < 1 ? -2 : 2;
|
||||
if (moveScore) {
|
||||
if (move.category === MoveCategory.PHYSICAL) {
|
||||
|
|
|
@ -65,10 +65,7 @@ export function initAutoPlay() {
|
|||
let maxEffectiveness = 0.5;
|
||||
for (let m of attacker.moveset) {
|
||||
const moveType = m.getMove().type;
|
||||
const defenderTypes = defender.getTypes();
|
||||
let effectiveness = getTypeDamageMultiplier(moveType, defenderTypes[0]);
|
||||
if (defenderTypes.length > 1)
|
||||
effectiveness *= getTypeDamageMultiplier(moveType, defenderTypes[1]);
|
||||
const effectiveness = defender.getAttackMoveEffectiveness(moveType);
|
||||
if (effectiveness > maxEffectiveness)
|
||||
maxEffectiveness = effectiveness;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue