Add move targets for proper animation target

pull/1/head
Flashfyre 2023-05-01 14:41:44 -04:00
parent f9c895c0cd
commit bfc26970f0
3 changed files with 277 additions and 132 deletions

View File

@ -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, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveCategory, MoveEffectAttr, MoveFlags, MoveHitEffectAttr, Moves, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr } from "./data/move";
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveCategory, MoveEffectAttr, MoveFlags, MoveHitEffectAttr, Moves, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget } from "./data/move";
import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./data/pokemon-stat";
@ -1024,7 +1024,7 @@ abstract class MoveEffectPhase extends PokemonPhase {
const isProtected = !this.move.getMove().hasFlag(MoveFlags.IGNORE_PROTECT) && target.lapseTag(BattlerTagType.PROTECTED);
new MoveAnim(this.move.getMove().id as Moves, user, target).play(this.scene, () => {
new MoveAnim(this.move.getMove().id as Moves, user).play(this.scene, () => {
const result = !isProtected ? target.apply(user, this.move) : MoveResult.NO_EFFECT;
++user.turnData.hitCount;
user.pushMoveHistory({ move: this.move.moveId, result: result, virtual: this.move.virtual });
@ -1059,7 +1059,7 @@ abstract class MoveEffectPhase extends PokemonPhase {
}
hitCheck(): boolean {
if (this.move.getMove().selfTarget)
if (this.move.getMove().moveTarget === MoveTarget.USER)
return true;
const hiddenTag = this.getTargetPokemon().getTag(HiddenTag);
@ -1180,8 +1180,7 @@ export class MoveAnimTestPhase extends BattlePhase {
initMoveAnim(moveId).then(() => {
loadMoveAnimAssets(this.scene, [ moveId ], true)
.then(() => {
new MoveAnim(moveId, player ? this.scene.getPlayerPokemon() : this.scene.getEnemyPokemon(),
player ? this.scene.getEnemyPokemon() : this.scene.getPlayerPokemon()).play(this.scene, () => {
new MoveAnim(moveId, player ? this.scene.getPlayerPokemon() : this.scene.getEnemyPokemon()).play(this.scene, () => {
if (player)
this.playMoveAnim(moveQueue, false);
else

View File

@ -1,6 +1,6 @@
//import { battleAnimRawData } from "./battle-anim-raw-data";
import BattleScene from "../battle-scene";
import { ChargeAttr, Moves, allMoves } from "./move";
import { ChargeAttr, Moves, allMoves, getMoveTarget } from "./move";
import Pokemon from "../pokemon";
import * as Utils from "../utils";
//import fs from 'vite-plugin-fs/browser';
@ -658,6 +658,8 @@ export abstract class BattleAnim {
for (let frame of spriteFrames) {
if (frame.target !== AnimFrameTarget.GRAPHIC) {
const isUser = frame.target === AnimFrameTarget.USER;
if (isUser && target === user)
continue;
const sprites = spriteCache[isUser ? AnimFrameTarget.USER : AnimFrameTarget.TARGET];
if ((isUser ? u : t) === sprites.length) {
const spriteSource = isUser ? userSprite : targetSprite;
@ -829,8 +831,8 @@ export class CommonBattleAnim extends BattleAnim {
export class MoveAnim extends BattleAnim {
public move: Moves;
constructor(move: Moves, user: Pokemon, target: Pokemon) {
super(user, target);
constructor(move: Moves, user: Pokemon) {
super(user, getMoveTarget(user, move));
this.move = move;
}
@ -849,8 +851,8 @@ export class MoveAnim extends BattleAnim {
export class MoveChargeAnim extends MoveAnim {
private chargeAnim: ChargeAnim;
constructor(chargeAnim: ChargeAnim, move: Moves, user: Pokemon, target: Pokemon) {
super(move, user, target);
constructor(chargeAnim: ChargeAnim, move: Moves, user: Pokemon) {
super(move, user);
this.chargeAnim = chargeAnim;
}

View File

@ -1,7 +1,7 @@
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
import { DamagePhase, EnemyMovePhase, MessagePhase, ObtainStatusEffectPhase, PlayerMovePhase, PokemonHealPhase, StatChangePhase } from "../battle-phases";
import { DamagePhase, EnemyMovePhase, ObtainStatusEffectPhase, PlayerMovePhase, PokemonHealPhase, StatChangePhase } from "../battle-phases";
import { BattleStat } from "./battle-stat";
import { BattlerTagType, IgnoreAccuracyTag } from "./battler-tag";
import { BattlerTagType } from "./battler-tag";
import { getPokemonMessage } from "../messages";
import Pokemon, { EnemyPokemon, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../pokemon";
import { StatusEffect, getStatusEffectDescriptor } from "./status-effect";
@ -18,6 +18,28 @@ export enum MoveCategory {
STATUS
}
export enum MoveTarget {
USER,
OTHER,
ALL_OTHERS,
NEAR_OTHER,
ALL_NEAR_OTHERS,
ENEMY,
NEAR_ENEMY,
ALL_NEAR_ENEMIES,
RANDOM_NEAR_ENEMY,
ALL_ENEMIES,
ATTACKER,
ALLY,
NEAR_ALLY,
USER_OR_NEAR_ALLY,
USER_AND_ALLIES,
ALL,
USER_SIDE,
ENEMY_SIDE,
BOTH_SIDES
}
export enum MoveFlags {
MAKES_CONTACT = 1,
IGNORE_PROTECT = 2,
@ -31,7 +53,7 @@ export default class Move {
public name: string;
public type: Type;
public category: MoveCategory;
public selfTarget: boolean;
public moveTarget: MoveTarget;
public power: integer;
public accuracy: integer;
public pp: integer;
@ -44,12 +66,12 @@ export default class Move {
private conditions: MoveCondition[];
private flags: integer;
constructor(id: Moves, name: string, type: Type, category: MoveCategory, selfTarget: boolean, power: integer, accuracy: integer, pp: integer, tm: integer, effect: string, chance: integer, priority: integer, generation: integer) {
constructor(id: Moves, name: string, type: Type, category: MoveCategory, defaultMoveTarget: MoveTarget, power: integer, accuracy: integer, pp: integer, tm: integer, effect: string, chance: integer, priority: integer, generation: integer) {
this.id = id;
this.name = name.toUpperCase();
this.type = type;
this.category = category;
this.selfTarget = selfTarget;
this.moveTarget = defaultMoveTarget;
this.power = power;
this.accuracy = accuracy;
this.pp = pp;
@ -63,7 +85,7 @@ export default class Move {
this.conditions = [];
this.flags = 0;
if (selfTarget)
if (defaultMoveTarget === MoveTarget.USER)
this.setFlag(MoveFlags.IGNORE_PROTECT, true);
if (category === MoveCategory.PHYSICAL)
this.setFlag(MoveFlags.MAKES_CONTACT, true);
@ -92,6 +114,11 @@ export default class Move {
return this;
}
target(moveTarget: MoveTarget): Move {
this.moveTarget = moveTarget;
return this;
}
hasFlag(flag: MoveFlags): boolean {
return !!(this.flags & flag);
}
@ -136,19 +163,19 @@ export default class Move {
export class AttackMove extends Move {
constructor(id: Moves, name: string, type: Type, category: MoveCategory, power: integer, accuracy: integer, pp: integer, tm: integer, effect: string, chance: integer, priority: integer, generation: integer) {
super(id, name, type, category, false, power, accuracy, pp, tm, effect, chance, priority, generation);
super(id, name, type, category, MoveTarget.NEAR_OTHER, power, accuracy, pp, tm, effect, chance, priority, generation);
}
}
export class StatusMove extends Move {
constructor(id: Moves, name: string, type: Type, accuracy: integer, pp: integer, tm: integer, effect: string, chance: integer, priority: integer, generation: integer) {
super(id, name, type, MoveCategory.STATUS, false, -1, accuracy, pp, tm, effect, chance, priority, generation);
super(id, name, type, MoveCategory.STATUS, MoveTarget.NEAR_OTHER, -1, accuracy, pp, tm, effect, chance, priority, generation);
}
}
export class SelfStatusMove extends Move {
constructor(id: Moves, name: string, type: Type, accuracy: integer, pp: integer, tm: integer, effect: string, chance: integer, priority: integer, generation: integer) {
super(id, name, type, MoveCategory.STATUS, true, -1, accuracy, pp, tm, effect, chance, priority, generation);
super(id, name, type, MoveCategory.STATUS, MoveTarget.USER, -1, accuracy, pp, tm, effect, chance, priority, generation);
}
}
@ -1106,7 +1133,7 @@ export class ChargeAttr extends OverrideMoveEffectAttr {
const lastMove = user.getLastXMoves(1) as TurnMove[];
if (!lastMove.length || lastMove[0].move !== move.id || lastMove[0].result !== MoveResult.OTHER) {
(args[0] as Utils.BooleanHolder).value = true;
new MoveChargeAnim(this.chargeAnim, move.id, user, target).play(user.scene, () => {
new MoveChargeAnim(this.chargeAnim, move.id, user).play(user.scene, () => {
user.scene.queueMessage(getPokemonMessage(user, ` ${this.chargeText.replace('{TARGET}', target.name)}`));
if (this.tagType)
user.addTag(this.tagType, 1, move.id, user.id);
@ -1838,6 +1865,22 @@ export function applyFilteredMoveAttrs(attrFilter: MoveAttrFilter, user: Pokemon
return applyMoveAttrsInternal(attrFilter, user, target, move, args);
}
export function getMoveTarget(user: Pokemon, move: Moves): Pokemon {
const moveTarget = allMoves[move].moveTarget;
const other = user.isPlayer() ? user.scene.getEnemyPokemon() : user.scene.getPlayerPokemon();
switch (moveTarget) {
case MoveTarget.USER:
case MoveTarget.USER_OR_NEAR_ALLY:
case MoveTarget.USER_AND_ALLIES:
case MoveTarget.USER_SIDE:
return user;
default:
return other;
}
}
export const allMoves = [
new StatusMove(Moves.NONE, "-", Type.NORMAL, MoveCategory.STATUS, -1, -1, "", -1, 0, 1),
];
@ -1865,18 +1908,21 @@ export function initMoves() {
new AttackMove(Moves.GUILLOTINE, "Guillotine", Type.NORMAL, MoveCategory.PHYSICAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 1)
.attr(OneHitKOAttr),
new AttackMove(Moves.RAZOR_WIND, "Razor Wind", Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, "Charges on first turn, attacks on second. High critical hit ratio.", -1, 0, 1)
.attr(ChargeAttr, ChargeAnim.RAZOR_WIND_CHARGING, 'whipped\nup a whirlwind!')
.attr(ChargeAttr, ChargeAnim.RAZOR_WIND_CHARGING, 'whipped$$$up a whirlwind!')
.attr(HighCritAttr)
.ignoresVirtual(),
.ignoresVirtual()
.target(MoveTarget.ALL_NEAR_ENEMIES),
new SelfStatusMove(Moves.SWORDS_DANCE, "Swords Dance", Type.NORMAL, -1, 20, 88, "Sharply raises user's Attack.", -1, 0, 1)
.attr(StatChangeAttr, BattleStat.ATK, 2, true),
new AttackMove(Moves.CUT, "Cut", Type.NORMAL, MoveCategory.PHYSICAL, 50, 95, 30, -1, "", -1, 0, 1),
new AttackMove(Moves.GUST, "Gust", Type.FLYING, MoveCategory.SPECIAL, 40, 100, 35, -1, "Hits Pokémon using FLY/BOUNCE/SKY DROP with double power.", -1, 0, 1)
.attr(HitsTagAttr, BattlerTagType.FLYING, true),
new AttackMove(Moves.WING_ATTACK, "Wing Attack", Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 35, -1, "", -1, 0, 1),
.attr(HitsTagAttr, BattlerTagType.FLYING, true)
.target(MoveTarget.OTHER),
new AttackMove(Moves.WING_ATTACK, "Wing Attack", Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 35, -1, "", -1, 0, 1)
.target(MoveTarget.OTHER),
new StatusMove(Moves.WHIRLWIND, "Whirlwind (N)", Type.NORMAL, -1, 20, -1, "In battles, the opponent switches. In the wild, the Pokémon runs.", -1, -6, 1), // TODO
new AttackMove(Moves.FLY, "Fly", Type.FLYING, MoveCategory.PHYSICAL, 90, 95, 15, 97, "Flies up on first turn, attacks on second turn.", -1, 0, 1)
.attr(ChargeAttr, ChargeAnim.FLY_CHARGING, 'flew\nup high!', BattlerTagType.FLYING)
.attr(ChargeAttr, ChargeAnim.FLY_CHARGING, 'flew$$$up high!', BattlerTagType.FLYING)
.ignoresVirtual(),
new AttackMove(Moves.BIND, "Bind", Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 1)
.attr(TrapAttr, BattlerTagType.BIND),
@ -1912,9 +1958,11 @@ export function initMoves() {
.attr(MissEffectAttr, frenzyMissFunc)
.attr(ConfuseAttr, true), // TODO: Update to still confuse if last hit misses
new AttackMove(Moves.DOUBLE_EDGE, "Double-Edge", Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 15, -1, "User receives recoil damage.", -1, 0, 1)
.attr(RecoilAttr),
.attr(RecoilAttr)
.target(MoveTarget.RANDOM_NEAR_ENEMY),
new StatusMove(Moves.TAIL_WHIP, "Tail Whip", Type.NORMAL, 100, 30, -1, "Lowers opponent's Defense.", -1, 0, 1)
.attr(StatChangeAttr, BattleStat.DEF, -1),
.attr(StatChangeAttr, BattleStat.DEF, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.POISON_STING, "Poison Sting", Type.POISON, MoveCategory.PHYSICAL, 15, 100, 35, -1, "May poison the opponent.", 30, 0, 1)
.attr(StatusEffectAttr, StatusEffect.POISON)
.makesContact(false),
@ -1926,11 +1974,13 @@ export function initMoves() {
.attr(MultiHitAttr)
.makesContact(false),
new StatusMove(Moves.LEER, "Leer", Type.NORMAL, 100, 30, -1, "Lowers opponent's Defense.", 100, 0, 1)
.attr(StatChangeAttr, BattleStat.DEF, -1),
.attr(StatChangeAttr, BattleStat.DEF, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BITE, "Bite", Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, -1, "May cause flinching.", 30, 0, 1)
.attr(FlinchAttr),
new StatusMove(Moves.GROWL, "Growl", Type.NORMAL, 100, 40, -1, "Lowers opponent's Attack.", -1, 0, 1)
.attr(StatChangeAttr, BattleStat.ATK, -1),
.attr(StatChangeAttr, BattleStat.ATK, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new StatusMove(Moves.ROAR, "Roar (N)", Type.NORMAL, -1, 20, -1, "In battles, the opponent switches. In the wild, the Pokémon runs.", -1, -6, 1),
new StatusMove(Moves.SING, "Sing", Type.NORMAL, 55, 15, -1, "Puts opponent to sleep.", -1, 0, 1)
.attr(StatusEffectAttr, StatusEffect.SLEEP),
@ -1941,35 +1991,42 @@ export function initMoves() {
new StatusMove(Moves.DISABLE, "Disable", Type.NORMAL, 100, 20, -1, "Opponent can't use its last attack for a few turns.", -1, 0, 1)
.attr(DisableMoveAttr),
new AttackMove(Moves.ACID, "Acid", Type.POISON, MoveCategory.SPECIAL, 40, 100, 30, -1, "May lower opponent's Special Defense.", 10, 0, 1)
.attr(StatChangeAttr, BattleStat.SPDEF, -1),
.attr(StatChangeAttr, BattleStat.SPDEF, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.EMBER, "Ember", Type.FIRE, MoveCategory.SPECIAL, 40, 100, 25, -1, "May burn opponent.", 10, 0, 1)
.attr(StatusEffectAttr, StatusEffect.BURN),
new AttackMove(Moves.FLAMETHROWER, "Flamethrower", Type.FIRE, MoveCategory.SPECIAL, 90, 100, 15, 125, "May burn opponent.", 10, 0, 1)
.attr(StatusEffectAttr, StatusEffect.BURN),
new SelfStatusMove(Moves.MIST, "Mist (N)", Type.ICE, -1, 30, -1, "User's stats cannot be changed for a period of time.", -1, 0, 1),
new SelfStatusMove(Moves.MIST, "Mist (N)", Type.ICE, -1, 30, -1, "User's stats cannot be changed for a period of time.", -1, 0, 1)
.target(MoveTarget.USER_SIDE),
new AttackMove(Moves.WATER_GUN, "Water Gun", Type.WATER, MoveCategory.SPECIAL, 40, 100, 25, -1, "", -1, 0, 1),
new AttackMove(Moves.HYDRO_PUMP, "Hydro Pump", Type.WATER, MoveCategory.SPECIAL, 110, 80, 5, 142, "", -1, 0, 1),
new AttackMove(Moves.SURF, "Surf", Type.WATER, MoveCategory.SPECIAL, 90, 100, 15, 123, "Hits all adjacent Pokémon.", -1, 0, 1), // TODO
new AttackMove(Moves.ICE_BEAM, "Ice Beam", Type.ICE, MoveCategory.SPECIAL, 90, 100, 10, 135, "May freeze opponent.", 10, 0, 1)
.attr(StatusEffectAttr, StatusEffect.FREEZE),
.attr(StatusEffectAttr, StatusEffect.FREEZE)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.BLIZZARD, "Blizzard", Type.ICE, MoveCategory.SPECIAL, 110, 70, 5, 143, "May freeze opponent.", 10, 0, 1)
.attr(BlizzardAccuracyAttr)
.attr(StatusEffectAttr, StatusEffect.FREEZE), // TODO: 30% chance to hit protect/detect in hail
new AttackMove(Moves.PSYBEAM, "Psybeam", Type.PSYCHIC, MoveCategory.SPECIAL, 65, 100, 20, 16, "May confuse opponent.", 10, 0, 1)
.attr(ConfuseAttr),
.attr(ConfuseAttr)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BUBBLE_BEAM, "Bubble Beam", Type.WATER, MoveCategory.SPECIAL, 65, 100, 20, -1, "May lower opponent's Speed.", 10, 0, 1)
.attr(StatChangeAttr, BattleStat.SPD, -1),
new AttackMove(Moves.AURORA_BEAM, "Aurora Beam", Type.ICE, MoveCategory.SPECIAL, 65, 100, 20, -1, "May lower opponent's Attack.", 10, 0, 1)
.attr(StatChangeAttr, BattleStat.ATK, -1),
new AttackMove(Moves.HYPER_BEAM, "Hyper Beam", Type.NORMAL, MoveCategory.SPECIAL, 150, 90, 5, 163, "User must recharge next turn.", -1, 0, 1)
.attr(AddBattlerTagAttr, BattlerTagType.RECHARGING, true),
new AttackMove(Moves.PECK, "Peck", Type.FLYING, MoveCategory.PHYSICAL, 35, 100, 35, -1, "", -1, 0, 1),
new AttackMove(Moves.DRILL_PECK, "Drill Peck", Type.FLYING, MoveCategory.PHYSICAL, 80, 100, 20, -1, "", -1, 0, 1),
new AttackMove(Moves.PECK, "Peck", Type.FLYING, MoveCategory.PHYSICAL, 35, 100, 35, -1, "", -1, 0, 1)
.target(MoveTarget.OTHER),
new AttackMove(Moves.DRILL_PECK, "Drill Peck", Type.FLYING, MoveCategory.PHYSICAL, 80, 100, 20, -1, "", -1, 0, 1)
.target(MoveTarget.OTHER),
new AttackMove(Moves.SUBMISSION, "Submission", Type.FIGHTING, MoveCategory.PHYSICAL, 80, 80, 20, -1, "User receives recoil damage.", -1, 0, 1)
.attr(RecoilAttr),
new AttackMove(Moves.LOW_KICK, "Low Kick", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, 12, "The heavier the opponent, the stronger the attack.", -1, 0, 1)
.attr(WeightPowerAttr),
new AttackMove(Moves.COUNTER, "Counter (N)", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, -1, "When hit by a Physical Attack, user strikes back with 2x power.", -1, -5, 1),
new AttackMove(Moves.COUNTER, "Counter (N)", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, -1, "When hit by a Physical Attack, user strikes back with 2x power.", -1, -5, 1)
.target(MoveTarget.ATTACKER),
new AttackMove(Moves.SEISMIC_TOSS, "Seismic Toss", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, -1, "Inflicts damage equal to user's level (maximum 150).", -1, 0, 1)
.attr(LevelPowerAttr),
new AttackMove(Moves.STRENGTH, "Strength", Type.NORMAL, MoveCategory.PHYSICAL, 80, 100, 15, -1, "", -1, 0, 1),
@ -1984,7 +2041,8 @@ export function initMoves() {
.attr(GrowthStatChangeAttr),
new AttackMove(Moves.RAZOR_LEAF, "Razor Leaf", Type.GRASS, MoveCategory.PHYSICAL, 55, 95, 25, -1, "High critical hit ratio.", -1, 0, 1)
.attr(HighCritAttr)
.makesContact(false),
.makesContact(false)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.SOLAR_BEAM, "Solar Beam", Type.GRASS, MoveCategory.SPECIAL, 120, 100, 10, 168, "Charges on first turn, attacks on second.", -1, 0, 1)
.attr(SolarBeamChargeAttr)
.attr(SolarBeamPowerAttr)
@ -1999,9 +2057,11 @@ export function initMoves() {
.attr(FrenzyAttr)
.attr(MissEffectAttr, frenzyMissFunc)
.attr(ConfuseAttr, true) // TODO: Update to still confuse if last hit misses
.makesContact(),
.makesContact()
.target(MoveTarget.RANDOM_NEAR_ENEMY),
new StatusMove(Moves.STRING_SHOT, "String Shot", Type.BUG, 95, 40, -1, "Sharply lowers opponent's Speed.", -1, 0, 1)
.attr(StatChangeAttr, BattleStat.SPD, -2),
.attr(StatChangeAttr, BattleStat.SPD, -2)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.DRAGON_RAGE, "Dragon Rage", Type.DRAGON, MoveCategory.SPECIAL, -1, 100, 10, -1, "Always inflicts 40 HP.", -1, 0, 1)
.attr(FixedDamageAttr, 40),
new AttackMove(Moves.FIRE_SPIN, "Fire Spin", Type.FIRE, MoveCategory.SPECIAL, 35, 85, 15, 24, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 1)
@ -2019,7 +2079,8 @@ export function initMoves() {
.makesContact(false),
new AttackMove(Moves.EARTHQUAKE, "Earthquake", Type.GROUND, MoveCategory.PHYSICAL, 100, 100, 10, 149, "Power is doubled if opponent is underground from using DIG.", -1, 0, 1)
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, true)
.makesContact(false),
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FISSURE, "Fissure", Type.GROUND, MoveCategory.PHYSICAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 1)
.attr(OneHitKOAttr)
.makesContact(false),
@ -2066,13 +2127,17 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.DEF, 1, true),
new SelfStatusMove(Moves.BARRIER, "Barrier", Type.PSYCHIC, -1, 20, -1, "Sharply raises user's Defense.", -1, 0, 1)
.attr(StatChangeAttr, BattleStat.DEF, 2, true),
new SelfStatusMove(Moves.LIGHT_SCREEN, "Light Screen (N)", Type.PSYCHIC, -1, 30, 75, "Halves damage from Special attacks for 5 turns.", -1, 0, 1),
new SelfStatusMove(Moves.HAZE, "Haze (N)", Type.ICE, -1, 30, -1, "Resets all stat changes.", -1, 0, 1),
new SelfStatusMove(Moves.REFLECT, "Reflect (N)", Type.PSYCHIC, -1, 20, 74, "Halves damage from Physical attacks for 5 turns.", -1, 0, 1),
new SelfStatusMove(Moves.LIGHT_SCREEN, "Light Screen (N)", Type.PSYCHIC, -1, 30, 75, "Halves damage from Special attacks for 5 turns.", -1, 0, 1)
.target(MoveTarget.USER_SIDE),
new SelfStatusMove(Moves.HAZE, "Haze (N)", Type.ICE, -1, 30, -1, "Resets all stat changes.", -1, 0, 1)
.target(MoveTarget.BOTH_SIDES),
new SelfStatusMove(Moves.REFLECT, "Reflect (N)", Type.PSYCHIC, -1, 20, 74, "Halves damage from Physical attacks for 5 turns.", -1, 0, 1)
.target(MoveTarget.USER_SIDE),
new SelfStatusMove(Moves.FOCUS_ENERGY, "Focus Energy", Type.NORMAL, -1, 30, -1, "Increases critical hit ratio.", -1, 0, 1)
.attr(AddBattlerTagAttr, BattlerTagType.CRIT_BOOST, true, undefined, true),
new AttackMove(Moves.BIDE, "Bide (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, -1, 10, -1, "User takes damage for two turns then strikes back double.", -1, 0, 1)
.ignoresVirtual(),
.ignoresVirtual()
.target(MoveTarget.ATTACKER),
new SelfStatusMove(Moves.METRONOME, "Metronome", Type.NORMAL, -1, 10, 80, "User performs almost any move in the game at random.", -1, 0, 1)
.attr(RandomMoveAttr)
.ignoresVirtual(),
@ -2080,7 +2145,8 @@ export function initMoves() {
.ignoresVirtual(),
new AttackMove(Moves.SELF_DESTRUCT, "Self-Destruct", Type.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, "User faints.", -1, 0, 1)
.attr(SacrificialAttr)
.makesContact(false),
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.EGG_BOMB, "Egg Bomb", Type.NORMAL, MoveCategory.PHYSICAL, 100, 75, 10, -1, "", -1, 0, 1)
.makesContact(false),
new AttackMove(Moves.LICK, "Lick", Type.GHOST, MoveCategory.PHYSICAL, 30, 100, 30, -1, "May paralyze opponent.", 30, 0, 1)
@ -2098,9 +2164,10 @@ export function initMoves() {
.attr(FlinchAttr),
new AttackMove(Moves.CLAMP, "Clamp", Type.WATER, MoveCategory.PHYSICAL, 35, 85, 15, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 1)
.attr(TrapAttr, BattlerTagType.CLAMP),
new AttackMove(Moves.SWIFT, "Swift", Type.NORMAL, MoveCategory.SPECIAL, 60, -1, 20, 32, "Ignores Accuracy and Evasiveness.", -1, 0, 1),
new AttackMove(Moves.SWIFT, "Swift", Type.NORMAL, MoveCategory.SPECIAL, 60, -1, 20, 32, "Ignores Accuracy and Evasiveness.", -1, 0, 1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.SKULL_BASH, "Skull Bash", Type.NORMAL, MoveCategory.PHYSICAL, 130, 100, 10, -1, "Raises Defense on first turn, attacks on second.", 100, 0, 1)
.attr(ChargeAttr, ChargeAnim.SKULL_BASH_CHARGING, 'lowered\nits head!', null, true)
.attr(ChargeAttr, ChargeAnim.SKULL_BASH_CHARGING, 'lowered$$$its head!', null, true)
.attr(StatChangeAttr, BattleStat.DEF, 1, true)
.ignoresVirtual(),
new AttackMove(Moves.SPIKE_CANNON, "Spike Cannon", Type.NORMAL, MoveCategory.PHYSICAL, 20, 100, 15, -1, "Hits 2-5 times in one turn.", -1, 0, 1)
@ -2122,7 +2189,8 @@ export function initMoves() {
.attr(HitHealAttr)
.condition((user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP),
new StatusMove(Moves.POISON_GAS, "Poison Gas", Type.POISON, 90, 40, -1, "Poisons opponent.", -1, 0, 1)
.attr(StatusEffectAttr, StatusEffect.POISON),
.attr(StatusEffectAttr, StatusEffect.POISON)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BARRAGE, "Barrage", Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, "Hits 2-5 times in one turn.", -1, 0, 1)
.attr(MultiHitAttr)
.makesContact(false),
@ -2135,10 +2203,12 @@ export function initMoves() {
.attr(HighCritAttr)
.attr(FlinchAttr)
.makesContact(false)
.ignoresVirtual(),
.ignoresVirtual()
.target(MoveTarget.OTHER),
new SelfStatusMove(Moves.TRANSFORM, "Transform (N)", Type.NORMAL, -1, 10, -1, "User takes on the form and attacks of the opponent.", -1, 0, 1),
new AttackMove(Moves.BUBBLE, "Bubble", Type.WATER, MoveCategory.SPECIAL, 40, 100, 30, -1, "May lower opponent's Speed.", 10, 0, 1)
.attr(StatChangeAttr, BattleStat.SPD, -1),
.attr(StatChangeAttr, BattleStat.SPD, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.DIZZY_PUNCH, "Dizzy Punch", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, -1, "May confuse opponent.", 20, 0, 1)
.attr(ConfuseAttr),
new StatusMove(Moves.SPORE, "Spore", Type.GRASS, 100, 15, -1, "Puts opponent to sleep.", -1, 0, 1)
@ -2154,7 +2224,8 @@ export function initMoves() {
.attr(HighCritAttr),
new AttackMove(Moves.EXPLOSION, "Explosion", Type.NORMAL, MoveCategory.PHYSICAL, 250, 100, 5, -1, "User faints.", -1, 0, 1)
.attr(SacrificialAttr)
.makesContact(false),
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FURY_SWIPES, "Fury Swipes", Type.NORMAL, MoveCategory.PHYSICAL, 18, 80, 15, -1, "Hits 2-5 times in one turn.", -1, 0, 1)
.attr(MultiHitAttr),
new AttackMove(Moves.BONEMERANG, "Bonemerang", Type.GROUND, MoveCategory.PHYSICAL, 50, 90, 10, -1, "Hits twice in one turn.", -1, 0, 1)
@ -2166,7 +2237,8 @@ export function initMoves() {
.condition((user: Pokemon, target: Pokemon, move: Move) => user.status?.effect !== StatusEffect.SLEEP),
new AttackMove(Moves.ROCK_SLIDE, "Rock Slide", Type.ROCK, MoveCategory.PHYSICAL, 75, 90, 10, 86, "May cause flinching.", 30, 0, 1)
.attr(FlinchAttr)
.makesContact(false),
.makesContact(false)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.HYPER_FANG, "Hyper Fang", Type.NORMAL, MoveCategory.PHYSICAL, 80, 90, 15, -1, "May cause flinching.", 10, 0, 1)
.attr(FlinchAttr),
new SelfStatusMove(Moves.SHARPEN, "Sharpen", Type.NORMAL, -1, 30, -1, "Raises user's Attack.", -1, 0, 1)
@ -2185,7 +2257,8 @@ export function initMoves() {
new AttackMove(Moves.STRUGGLE, "Struggle", Type.NORMAL, MoveCategory.PHYSICAL, 50, -1, -1, -1, "Only usable when all PP are gone. Hurts the user.", -1, 0, 1)
.attr(RecoilAttr, true)
.attr(TypelessAttr)
.ignoresVirtual(),
.ignoresVirtual()
.target(MoveTarget.RANDOM_NEAR_ENEMY),
new SelfStatusMove(Moves.SKETCH, "Sketch", Type.NORMAL, -1, 1, -1, "Permanently copies the opponent's last move.", -1, 0, 2)
.attr(SketchAttr)
.ignoresVirtual(),
@ -2210,19 +2283,23 @@ export function initMoves() {
.attr(BypassSleepAttr)
.attr(FlinchAttr)
.condition((user: Pokemon, target: Pokemon, move: Move) => user.status?.effect === StatusEffect.SLEEP),
new StatusMove(Moves.CURSE, "Curse (N)", Type.GHOST, -1, 10, -1, "Ghosts lose 50% of max HP and curse the opponent; Non-Ghosts raise Attack, Defense and lower Speed.", -1, 0, 2),
new StatusMove(Moves.CURSE, "Curse (N)", Type.GHOST, -1, 10, -1, "Ghosts lose 50% of max HP and curse the opponent; Non-Ghosts raise Attack, Defense and lower Speed.", -1, 0, 2)
.target(MoveTarget.USER),
new AttackMove(Moves.FLAIL, "Flail", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, "The lower the user's HP, the higher the power.", -1, 0, 2)
.attr(LowHpPowerAttr),
new SelfStatusMove(Moves.CONVERSION_2, "Conversion 2 (N)", Type.NORMAL, -1, 30, -1, "User changes type to become resistant to opponent's last move.", -1, 0, 2),
new AttackMove(Moves.AEROBLAST, "Aeroblast", Type.FLYING, MoveCategory.SPECIAL, 100, 95, 5, -1, "High critical hit ratio.", -1, 0, 2)
.attr(HighCritAttr),
.attr(HighCritAttr)
.target(MoveTarget.OTHER),
new StatusMove(Moves.COTTON_SPORE, "Cotton Spore", Type.GRASS, 100, 40, -1, "Sharply lowers opponent's Speed.", -1, 0, 2)
.attr(StatChangeAttr, BattleStat.SPD, -2),
.attr(StatChangeAttr, BattleStat.SPD, -2)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.REVERSAL, "Reversal", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 15, 134, "The lower the user's HP, the higher the power.", -1, 0, 2)
.attr(LowHpPowerAttr),
new StatusMove(Moves.SPITE, "Spite (N)", Type.GHOST, 100, 10, -1, "The opponent's last move loses 2-5 PP.", -1, 0, 2),
new AttackMove(Moves.POWDER_SNOW, "Powder Snow", Type.ICE, MoveCategory.SPECIAL, 40, 100, 25, -1, "May freeze opponent.", 10, 0, 2)
.attr(StatusEffectAttr, StatusEffect.FREEZE),
.attr(StatusEffectAttr, StatusEffect.FREEZE)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new SelfStatusMove(Moves.PROTECT, "Protect", Type.NORMAL, -1, 10, 7, "Protects the user, but may fail if used consecutively.", -1, 4, 2)
.attr(ProtectAttr),
new AttackMove(Moves.MACH_PUNCH, "Mach Punch", Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 30, -1, "User attacks first.", -1, 1, 2),
@ -2239,16 +2316,19 @@ export function initMoves() {
new AttackMove(Moves.OCTAZOOKA, "Octazooka", Type.WATER, MoveCategory.SPECIAL, 65, 85, 10, -1, "May lower opponent's Accuracy.", 50, 0, 2)
.attr(StatChangeAttr, BattleStat.ACC, -1),
new StatusMove(Moves.SPIKES, "Spikes", Type.GROUND, -1, 20, 90, "Hurts opponents when they switch into battle.", -1, 0, 2)
.attr(AddArenaTrapTagAttr, ArenaTagType.SPIKES),
.attr(AddArenaTrapTagAttr, ArenaTagType.SPIKES)
.target(MoveTarget.ENEMY_SIDE),
new AttackMove(Moves.ZAP_CANNON, "Zap Cannon", Type.ELECTRIC, MoveCategory.SPECIAL, 120, 50, 5, -1, "Paralyzes opponent.", 100, 0, 2)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
new StatusMove(Moves.FORESIGHT, "Foresight (N)", Type.NORMAL, -1, 40, -1, "Resets opponent's Evasiveness, and allows Normal- and Fighting-type attacks to hit Ghosts.", -1, 0, 2), // TODO
new StatusMove(Moves.DESTINY_BOND, "Destiny Bond (N)", Type.GHOST, -1, 5, -1, "If the user faints, the opponent also faints.", -1, 0, 2)
.ignoresProtect(),
new StatusMove(Moves.PERISH_SONG, "Perish Song (N)", Type.NORMAL, -1, 5, -1, "Any Pokémon in play when this attack is used faints in 3 turns.", -1, 0, 2)
.ignoresProtect(),
.ignoresProtect()
.target(MoveTarget.ALL),
new AttackMove(Moves.ICY_WIND, "Icy Wind", Type.ICE, MoveCategory.SPECIAL, 55, 95, 15, 34, "Lowers opponent's Speed.", 100, 0, 2)
.attr(StatChangeAttr, BattleStat.SPD, -1),
.attr(StatChangeAttr, BattleStat.SPD, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new SelfStatusMove(Moves.DETECT, "Detect", Type.FIGHTING, -1, 5, -1, "Protects the user, but may fail if used consecutively.", -1, 4, 2)
.attr(ProtectAttr),
new AttackMove(Moves.BONE_RUSH, "Bone Rush", Type.GROUND, MoveCategory.PHYSICAL, 25, 90, 10, -1, "Hits 2-5 times in one turn.", -1, 0, 2)
@ -2261,7 +2341,8 @@ export function initMoves() {
.attr(MissEffectAttr, frenzyMissFunc)
.attr(ConfuseAttr, true), // TODO: Update to still confuse if last hit misses
new StatusMove(Moves.SANDSTORM, "Sandstorm", Type.ROCK, -1, 10, 51, "Creates a sandstorm for 5 turns.", -1, 0, 2)
.attr(WeatherChangeAttr, WeatherType.SANDSTORM),
.attr(WeatherChangeAttr, WeatherType.SANDSTORM)
.target(MoveTarget.RANDOM_NEAR_ENEMY),
new AttackMove(Moves.GIGA_DRAIN, "Giga Drain", Type.GRASS, MoveCategory.SPECIAL, 75, 100, 10, 111, "User recovers half the HP inflicted on opponent.", -1, 4, 2)
.attr(HitHealAttr),
new SelfStatusMove(Moves.ENDURE, "Endure (N)", Type.NORMAL, -1, 10, 47, "Always left with at least 1 HP, but may fail if used consecutively.", -1, 0, 2),
@ -2288,18 +2369,21 @@ export function initMoves() {
.attr(BypassSleepAttr)
.attr(RandomMovesetMoveAttr)
.condition((user: Pokemon, target: Pokemon, move: Move) => user.status?.effect === StatusEffect.SLEEP),
new SelfStatusMove(Moves.HEAL_BELL, "Heal Bell (N)", Type.NORMAL, -1, 5, -1, "Heals the user's party's status conditions.", -1, 0, 2),
new SelfStatusMove(Moves.HEAL_BELL, "Heal Bell (N)", Type.NORMAL, -1, 5, -1, "Heals the user's party's status conditions.", -1, 0, 2)
.target(MoveTarget.USER_AND_ALLIES),
new AttackMove(Moves.RETURN, "Return (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 20, -1, "Power increases with higher Friendship.", -1, 0, 2),
new AttackMove(Moves.PRESENT, "Present (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, 90, 15, -1, "Either deals damage or heals.", -1, 0, 2)
.makesContact(false),
new AttackMove(Moves.FRUSTRATION, "Frustration (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 20, -1, "Power decreases with higher Friendship.", -1, 0, 2),
new SelfStatusMove(Moves.SAFEGUARD, "Safeguard (N)", Type.NORMAL, -1, 25, -1, "The user's party is protected from status conditions.", -1, 0, 2),
new SelfStatusMove(Moves.SAFEGUARD, "Safeguard (N)", Type.NORMAL, -1, 25, -1, "The user's party is protected from status conditions.", -1, 0, 2)
.target(MoveTarget.USER_SIDE),
new StatusMove(Moves.PAIN_SPLIT, "Pain Split (N)", Type.NORMAL, -1, 20, -1, "The user's and opponent's HP becomes the average of both.", -1, 0, 2),
new AttackMove(Moves.SACRED_FIRE, "Sacred Fire", Type.FIRE, MoveCategory.PHYSICAL, 100, 95, 5, -1, "May burn opponent.", 50, 0, 2)
.attr(StatusEffectAttr, StatusEffect.BURN)
.makesContact(false),
new AttackMove(Moves.MAGNITUDE, "Magnitude (N)", Type.GROUND, MoveCategory.PHYSICAL, -1, 100, 30, -1, "Hits with random power.", -1, 0, 2)
.makesContact(false),
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.DYNAMIC_PUNCH, "Dynamic Punch", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 50, 5, -1, "Confuses opponent.", 100, 0, 2)
.attr(ConfuseAttr),
new AttackMove(Moves.MEGAHORN, "Megahorn", Type.BUG, MoveCategory.PHYSICAL, 120, 85, 10, -1, "", -1, 0, 2),
@ -2312,7 +2396,8 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.SPD, 1, true)
.attr(LapseBattlerTagAttr, [ BattlerTagType.BIND, BattlerTagType.WRAP, BattlerTagType.FIRE_SPIN, BattlerTagType.WHIRLPOOL, BattlerTagType.CLAMP, BattlerTagType.SAND_TOMB, BattlerTagType.MAGMA_STORM ], true),
new StatusMove(Moves.SWEET_SCENT, "Sweet Scent", Type.NORMAL, 100, 20, -1, "Lowers opponent's Evasiveness.", -1, 0, 2)
.attr(StatChangeAttr, BattleStat.EVA, -1),
.attr(StatChangeAttr, BattleStat.EVA, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.IRON_TAIL, "Iron Tail", Type.STEEL, MoveCategory.PHYSICAL, 100, 75, 15, -1, "May lower opponent's Defense.", 30, 0, 2)
.attr(StatChangeAttr, BattleStat.DEF, -1),
new AttackMove(Moves.METAL_CLAW, "Metal Claw", Type.STEEL, MoveCategory.PHYSICAL, 50, 95, 35, 31, "May raise user's Attack.", 10, 0, 2)
@ -2331,12 +2416,15 @@ export function initMoves() {
.attr(HitsTagAttr, BattlerTagType.FLYING, true)
.attr(FlinchAttr), // TODO
new SelfStatusMove(Moves.RAIN_DANCE, "Rain Dance", Type.WATER, -1, 5, 50, "Makes it rain for 5 turns.", -1, 0, 2)
.attr(WeatherChangeAttr, WeatherType.RAIN),
.attr(WeatherChangeAttr, WeatherType.RAIN)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new SelfStatusMove(Moves.SUNNY_DAY, "Sunny Day", Type.FIRE, -1, 5, 49, "Makes it sunny for 5 turns.", -1, 0, 2)
.attr(WeatherChangeAttr, WeatherType.SUNNY),
.attr(WeatherChangeAttr, WeatherType.SUNNY)
.target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.CRUNCH, "Crunch", Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, 108, "May lower opponent's Defense.", 20, 0, 2)
.attr(StatChangeAttr, BattleStat.DEF, -1),
new AttackMove(Moves.MIRROR_COAT, "Mirror Coat (N)", Type.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 20, -1, "When hit by a Special Attack, user strikes back with 2x power.", -1, -5, 2),
new AttackMove(Moves.MIRROR_COAT, "Mirror Coat (N)", Type.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 20, -1, "When hit by a Special Attack, user strikes back with 2x power.", -1, -5, 2)
.target(MoveTarget.ATTACKER),
new SelfStatusMove(Moves.PSYCH_UP, "Psych Up (N)", Type.NORMAL, -1, 10, -1, "Copies the opponent's stat changes.", -1, 0, 2),
new AttackMove(Moves.EXTREME_SPEED, "Extreme Speed", Type.NORMAL, MoveCategory.PHYSICAL, 80, 100, 5, -1, "User attacks first.", -1, 2, 2),
new AttackMove(Moves.ANCIENT_POWER, "Ancient Power", Type.ROCK, MoveCategory.SPECIAL, 60, 100, 5, -1, "May raise all user's stats at once.", 10, 0, 2)
@ -2354,14 +2442,17 @@ export function initMoves() {
.attr(FlinchAttr)
.condition((user: Pokemon, target: Pokemon, move: Move) => user.scene.currentBattle.turn === 1),
new AttackMove(Moves.UPROAR, "Uproar (N)", Type.NORMAL, MoveCategory.SPECIAL, 90, 100, 10, -1, "User attacks for 3 turns and prevents sleep.", -1, 0, 3)
.ignoresVirtual(),
.ignoresVirtual()
.target(MoveTarget.RANDOM_NEAR_ENEMY),
new SelfStatusMove(Moves.STOCKPILE, "Stockpile (N)", Type.NORMAL, -1, 20, -1, "Stores energy for use with Spit Up and Swallow.", -1, 0, 3),
new AttackMove(Moves.SPIT_UP, "Spit Up (N)", Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, "Power depends on how many times the user performed Stockpile.", -1, 0, 3),
new SelfStatusMove(Moves.SWALLOW, "Swallow (N)", Type.NORMAL, -1, 10, -1, "The more times the user has performed Stockpile, the more HP is recovered.", -1, 0, 3),
new AttackMove(Moves.HEAT_WAVE, "Heat Wave", Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 118, "May burn opponent.", 10, 0, 3)
.attr(StatusEffectAttr, StatusEffect.BURN),
.attr(StatusEffectAttr, StatusEffect.BURN)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new SelfStatusMove(Moves.HAIL, "Hail", Type.ICE, -1, 10, -1, "Non-Ice types are damaged for 5 turns.", -1, 0, 3)
.attr(WeatherChangeAttr, WeatherType.HAIL),
.attr(WeatherChangeAttr, WeatherType.HAIL)
.target(MoveTarget.BOTH_SIDES),
new StatusMove(Moves.TORMENT, "Torment (N)", Type.DARK, 100, 15, -1, "Opponent cannot use the same move in a row.", -1, 0, 3),
new StatusMove(Moves.FLATTER, "Flatter", Type.DARK, 100, 15, -1, "Confuses opponent, but raises its Special Attack.", -1, 0, 3)
.attr(StatChangeAttr, BattleStat.SPATK, 1)
@ -2383,7 +2474,8 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.SPDEF, 1, true), // TODO
new StatusMove(Moves.TAUNT, "Taunt (N)", Type.DARK, 100, 20, 87, "Opponent can only use moves that attack.", -1, 0, 3),
new SelfStatusMove(Moves.HELPING_HAND, "Helping Hand (N)", Type.NORMAL, -1, 20, 130, "In Double Battles, boosts the power of the partner's move.", -1, 5, 3), // TODO
new StatusMove(Moves.TRICK, "Trick (N)", Type.PSYCHIC, 100, 10, 109, "Swaps held items with the opponent.", -1, 0, 3),
new StatusMove(Moves.TRICK, "Trick (N)", Type.PSYCHIC, 100, 10, 109, "Swaps held items with the opponent.", -1, 0, 3)
.target(MoveTarget.NEAR_ALLY),
new SelfStatusMove(Moves.ROLE_PLAY, "Role Play (N)", Type.PSYCHIC, -1, 10, -1, "User copies the opponent's Ability.", -1, 0, 3),
new SelfStatusMove(Moves.WISH, "Wish (N)", Type.NORMAL, -1, 10, -1, "The user recovers HP in the following turn.", -1, 0, 3),
new SelfStatusMove(Moves.ASSIST, "Assist", Type.NORMAL, -1, 20, -1, "User performs a move known by its allies at random.", -1, 0, 3)
@ -2403,9 +2495,11 @@ export function initMoves() {
new AttackMove(Moves.KNOCK_OFF, "Knock Off (N)", Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, "Removes opponent's held item for the rest of the battle.", -1, 0, 3),
new AttackMove(Moves.ENDEAVOR, "Endeavor (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, "Reduces opponent's HP to same as user's.", -1, 0, 3),
new AttackMove(Moves.ERUPTION, "Eruption", Type.FIRE, MoveCategory.SPECIAL, 150, 100, 5, -1, "Stronger when the user's HP is higher.", -1, 0, 3)
.attr(HpPowerAttr),
.attr(HpPowerAttr)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new StatusMove(Moves.SKILL_SWAP, "Skill Swap (N)", Type.PSYCHIC, -1, 10, 98, "The user swaps Abilities with the opponent.", -1, 0, 3),
new StatusMove(Moves.IMPRISON, "Imprison (N)", Type.PSYCHIC, -1, 10, 92, "Opponent is unable to use moves that the user also knows.", -1, 0, 3),
new StatusMove(Moves.IMPRISON, "Imprison (N)", Type.PSYCHIC, -1, 10, 92, "Opponent is unable to use moves that the user also knows.", -1, 0, 3)
.target(MoveTarget.USER),
new SelfStatusMove(Moves.REFRESH, "Refresh", Type.NORMAL, -1, 20, -1, "Cures paralysis, poison, and burns.", -1, 0, 3)
.attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN)
.condition((user: Pokemon, target: Pokemon, move: Move) => user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)),
@ -2414,7 +2508,7 @@ export function initMoves() {
new AttackMove(Moves.SECRET_POWER, "Secret Power (N)", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, -1, "Effects of the attack vary with the location.", 30, 0, 3)
.makesContact(false),
new AttackMove(Moves.DIVE, "Dive", Type.WATER, MoveCategory.PHYSICAL, 80, 100, 10, -1, "Dives underwater on first turn, attacks on second turn.", -1, 0, 3)
.attr(ChargeAttr, ChargeAnim.DIVE_CHARGING, 'hid\nunderwater!')
.attr(ChargeAttr, ChargeAnim.DIVE_CHARGING, 'hid$$$underwater!')
.ignoresVirtual(),
new AttackMove(Moves.ARM_THRUST, "Arm Thrust", Type.FIGHTING, MoveCategory.PHYSICAL, 15, 100, 20, -1, "Hits 2-5 times in one turn.", -1, 0, 3)
.attr(MultiHitAttr),
@ -2430,19 +2524,22 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.ATK, -2),
new StatusMove(Moves.TEETER_DANCE, "Teeter Dance", Type.NORMAL, 100, 20, -1, "Confuses all Pokémon.", -1, 0, 3)
.attr(ConfuseAttr, true)
.attr(ConfuseAttr),
.attr(ConfuseAttr)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.BLAZE_KICK, "Blaze Kick", Type.FIRE, MoveCategory.PHYSICAL, 85, 90, 10, -1, "High critical hit ratio. May burn opponent.", 10, 0, 3)
.attr(HighCritAttr)
.attr(StatusEffectAttr, StatusEffect.BURN),
new SelfStatusMove(Moves.MUD_SPORT, "Mud Sport", Type.GROUND, -1, 15, -1, "Weakens the power of Electric-type moves.", -1, 0, 3)
.attr(AddArenaTagAttr, ArenaTagType.MUD_SPORT, 5),
.attr(AddArenaTagAttr, ArenaTagType.MUD_SPORT, 5)
.target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.ICE_BALL, "Ice Ball", Type.ICE, MoveCategory.PHYSICAL, 30, 90, 20, -1, "Doubles in power each turn for 5 turns.", -1, 0, 3)
.attr(ConsecutiveUseDoublePowerAttr, 5, true, true),
new AttackMove(Moves.NEEDLE_ARM, "Needle Arm", Type.GRASS, MoveCategory.PHYSICAL, 60, 100, 15, -1, "May cause flinching.", 30, 0, 3)
.attr(FlinchAttr),
new SelfStatusMove(Moves.SLACK_OFF, "Slack Off", Type.NORMAL, -1, 5, -1, "User recovers half its max HP.", -1, 0, 3)
.attr(HealAttr),
new AttackMove(Moves.HYPER_VOICE, "Hyper Voice", Type.NORMAL, MoveCategory.SPECIAL, 90, 100, 10, 117, "", -1, 0, 3),
new AttackMove(Moves.HYPER_VOICE, "Hyper Voice", Type.NORMAL, MoveCategory.SPECIAL, 90, 100, 10, 117, "", -1, 0, 3)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.POISON_FANG, "Poison Fang", Type.POISON, MoveCategory.PHYSICAL, 50, 100, 15, -1, "May badly poison opponent.", 50, 0, 3)
.attr(StatusEffectAttr, StatusEffect.TOXIC),
new AttackMove(Moves.CRUSH_CLAW, "Crush Claw", Type.NORMAL, MoveCategory.PHYSICAL, 75, 95, 10, -1, "May lower opponent's Defense.", 50, 0, 3)
@ -2456,11 +2553,13 @@ export function initMoves() {
new AttackMove(Moves.ASTONISH, "Astonish", Type.GHOST, MoveCategory.PHYSICAL, 30, 100, 15, -1, "May cause flinching.", 30, 0, 3)
.attr(FlinchAttr),
new AttackMove(Moves.WEATHER_BALL, "Weather Ball (N)", Type.NORMAL, MoveCategory.SPECIAL, 50, 100, 10, -1, "Move's power and type changes with the weather.", -1, 0, 3),
new SelfStatusMove(Moves.AROMATHERAPY, "Aromatherapy (N)", Type.GRASS, -1, 5, -1, "Cures all status problems in your party.", -1, 0, 3),
new SelfStatusMove(Moves.AROMATHERAPY, "Aromatherapy (N)", Type.GRASS, -1, 5, -1, "Cures all status problems in your party.", -1, 0, 3)
.target(MoveTarget.USER_AND_ALLIES),
new StatusMove(Moves.FAKE_TEARS, "Fake Tears", Type.DARK, 100, 20, 3, "Sharply lowers opponent's Special Defense.", -1, 0, 3)
.attr(StatChangeAttr, BattleStat.SPDEF, -2),
new AttackMove(Moves.AIR_CUTTER, "Air Cutter", Type.FLYING, MoveCategory.SPECIAL, 60, 95, 25, 40, "High critical hit ratio.", -1, 0, 3)
.attr(HighCritAttr),
.attr(HighCritAttr)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.OVERHEAT, "Overheat", Type.FIRE, MoveCategory.SPECIAL, 130, 90, 5, 157, "Sharply lowers user's Special Attack.", 100, 0, 3)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new StatusMove(Moves.ODOR_SLEUTH, "Odor Sleuth (N)", Type.NORMAL, -1, 40, -1, "Resets opponent's Evasiveness, and allows Normal- and Fighting-type attacks to hit Ghosts.", -1, 0, 3),
@ -2479,7 +2578,8 @@ export function initMoves() {
new SelfStatusMove(Moves.COSMIC_POWER, "Cosmic Power", Type.PSYCHIC, -1, 20, -1, "Raises user's Defense and Special Defense.", -1, 0, 3)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true),
new AttackMove(Moves.WATER_SPOUT, "Water Spout", Type.WATER, MoveCategory.SPECIAL, 150, 100, 5, -1, "The higher the user's HP, the higher the damage caused.", -1, 0, 3)
.attr(HpPowerAttr),
.attr(HpPowerAttr)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.SIGNAL_BEAM, "Signal Beam", Type.BUG, MoveCategory.SPECIAL, 75, 100, 15, -1, "May confuse opponent.", 10, 0, 3)
.attr(ConfuseAttr),
new AttackMove(Moves.SHADOW_PUNCH, "Shadow Punch", Type.GHOST, MoveCategory.PHYSICAL, 60, -1, 20, -1, "Ignores Accuracy and Evasiveness.", -1, 0, 3),
@ -2493,11 +2593,13 @@ export function initMoves() {
new AttackMove(Moves.SHEER_COLD, "Sheer Cold", Type.ICE, MoveCategory.SPECIAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 3)
.attr(OneHitKOAttr),
new AttackMove(Moves.MUDDY_WATER, "Muddy Water", Type.WATER, MoveCategory.SPECIAL, 90, 85, 10, -1, "May lower opponent's Accuracy.", 30, 0, 3)
.attr(StatChangeAttr, BattleStat.ACC, -1),
.attr(StatChangeAttr, BattleStat.ACC, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BULLET_SEED, "Bullet Seed", Type.GRASS, MoveCategory.PHYSICAL, 25, 100, 30, 56, "Hits 2-5 times in one turn.", -1, 0, 3)
.attr(MultiHitAttr)
.makesContact(false),
new AttackMove(Moves.AERIAL_ACE, "Aerial Ace", Type.FLYING, MoveCategory.PHYSICAL, 60, -1, 20, 27, "Ignores Accuracy and Evasiveness.", -1, 0, 3),
new AttackMove(Moves.AERIAL_ACE, "Aerial Ace", Type.FLYING, MoveCategory.PHYSICAL, 60, -1, 20, 27, "Ignores Accuracy and Evasiveness.", -1, 0, 3)
.target(MoveTarget.OTHER),
new AttackMove(Moves.ICICLE_SPEAR, "Icicle Spear", Type.ICE, MoveCategory.PHYSICAL, 25, 100, 30, -1, "Hits 2-5 times in one turn.", -1, 0, 3)
.attr(MultiHitAttr)
.makesContact(false),
@ -2507,7 +2609,8 @@ export function initMoves() {
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, 1, true),
new SelfStatusMove(Moves.HOWL, "Howl", Type.NORMAL, -1, 40, -1, "Raises Attack of allies.", -1, 0, 3)
.attr(StatChangeAttr, BattleStat.ATK, 1, true), // TODO
new AttackMove(Moves.DRAGON_CLAW, "Dragon Claw", Type.DRAGON, MoveCategory.PHYSICAL, 80, 100, 15, 78, "", -1, 0, 3),
new AttackMove(Moves.DRAGON_CLAW, "Dragon Claw", Type.DRAGON, MoveCategory.PHYSICAL, 80, 100, 15, 78, "", -1, 0, 3)
.target(MoveTarget.USER_AND_ALLIES),
new AttackMove(Moves.FRENZY_PLANT, "Frenzy Plant", Type.GRASS, MoveCategory.SPECIAL, 150, 90, 5, 155, "User must recharge next turn.", -1, 0, 3)
.attr(AddBattlerTagAttr, BattlerTagType.RECHARGING, true),
new SelfStatusMove(Moves.BULK_UP, "Bulk Up", Type.FIGHTING, -1, 20, 64, "Raises user's Attack and Defense.", -1, 0, 3)
@ -2515,7 +2618,8 @@ export function initMoves() {
new AttackMove(Moves.BOUNCE, "Bounce", Type.FLYING, MoveCategory.PHYSICAL, 85, 85, 5, -1, "Springs up on first turn, attacks on second. May paralyze opponent.", 30, 0, 3)
.attr(ChargeAttr, ChargeAnim.BOUNCE_CHARGING, 'sprang up!', BattlerTagType.FLYING)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
.ignoresVirtual(),
.ignoresVirtual()
.target(MoveTarget.OTHER),
new AttackMove(Moves.MUD_SHOT, "Mud Shot", Type.GROUND, MoveCategory.SPECIAL, 55, 95, 15, 35, "Lowers opponent's Speed.", 100, 0, 3)
.attr(StatChangeAttr, BattleStat.SPD, -1),
new AttackMove(Moves.POISON_TAIL, "Poison Tail", Type.POISON, MoveCategory.PHYSICAL, 50, 100, 25, 26, "High critical hit ratio. May poison opponent.", 10, 0, 3)
@ -2527,7 +2631,8 @@ export function initMoves() {
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
new AttackMove(Moves.MAGICAL_LEAF, "Magical Leaf", Type.GRASS, MoveCategory.SPECIAL, 60, -1, 20, 33, "Ignores Accuracy and Evasiveness.", -1, 0, 3),
new SelfStatusMove(Moves.WATER_SPORT, "Water Sport", Type.WATER, -1, 15, -1, "Weakens the power of Fire-type moves.", -1, 0, 3)
.attr(AddArenaTagAttr, ArenaTagType.WATER_SPORT, 5),
.attr(AddArenaTagAttr, ArenaTagType.WATER_SPORT, 5)
.target(MoveTarget.BOTH_SIDES),
new SelfStatusMove(Moves.CALM_MIND, "Calm Mind", Type.PSYCHIC, -1, 20, 129, "Raises user's Special Attack and Special Defense.", -1, 0, 3)
.attr(StatChangeAttr, [ BattleStat.SPATK, BattleStat.SPDEF ], 1, true),
new AttackMove(Moves.LEAF_BLADE, "Leaf Blade", Type.GRASS, MoveCategory.PHYSICAL, 90, 100, 15, -1, "High critical hit ratio.", -1, 0, 3)
@ -2539,15 +2644,17 @@ export function initMoves() {
.makesContact(false),
new AttackMove(Moves.SHOCK_WAVE, "Shock Wave", Type.ELECTRIC, MoveCategory.SPECIAL, 60, -1, 20, -1, "Ignores Accuracy and Evasiveness.", -1, 0, 3),
new AttackMove(Moves.WATER_PULSE, "Water Pulse", Type.WATER, MoveCategory.SPECIAL, 60, 100, 20, 11, "May confuse opponent.", 20, 0, 3)
.attr(ConfuseAttr),
.attr(ConfuseAttr)
.target(MoveTarget.OTHER),
new AttackMove(Moves.DOOM_DESIRE, "Doom Desire", Type.STEEL, MoveCategory.SPECIAL, 140, 100, 5, -1, "Damage occurs 2 turns later.", -1, 0, 3)
.attr(ChargeAttr, ChargeAnim.DOOM_DESIRE_CHARGING, 'chose\nDOOM DESIRE as its destiny!'), // Fix this move to work properly
.attr(ChargeAttr, ChargeAnim.DOOM_DESIRE_CHARGING, 'chose$$$DOOM DESIRE as its destiny!'), // Fix this move to work properly
new AttackMove(Moves.PSYCHO_BOOST, "Psycho Boost", Type.PSYCHIC, MoveCategory.SPECIAL, 140, 90, 5, -1, "Sharply lowers user's Special Attack.", 100, 0, 3)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new SelfStatusMove(Moves.ROOST, "Roost", Type.FLYING, -1, 5, -1, "User recovers half of its max HP and loses the Flying type temporarily.", -1, 0, 4)
.attr(HitHealAttr)
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, true, 1),
new SelfStatusMove(Moves.GRAVITY, "Gravity (N)", Type.PSYCHIC, -1, 5, -1, "Prevents moves like FLY and BOUNCE and the Ability LEVITATE for 5 turns.", -1, 0, 4),
new SelfStatusMove(Moves.GRAVITY, "Gravity (N)", Type.PSYCHIC, -1, 5, -1, "Prevents moves like FLY and BOUNCE and the Ability LEVITATE for 5 turns.", -1, 0, 4)
.target(MoveTarget.BOTH_SIDES),
new StatusMove(Moves.MIRACLE_EYE, "Miracle Eye (N)", Type.PSYCHIC, -1, 40, -1, "Resets opponent's Evasiveness, removes Dark's Psychic immunity.", -1, 0, 4),
new AttackMove(Moves.WAKE_UP_SLAP, "Wake-Up Slap (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 70, 100, 10, -1, "Power doubles if opponent is asleep, but wakes it up.", -1, 0, 4),
new AttackMove(Moves.HAMMER_ARM, "Hammer Arm", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 90, 10, -1, "Lowers user's Speed.", 100, 0, 4)
@ -2563,12 +2670,16 @@ export function initMoves() {
.condition((user: Pokemon, target: Pokemon, move: Move) => !!target.getTag(BattlerTagType.PROTECTED))
.makesContact(false)
.ignoresProtect(),
new AttackMove(Moves.PLUCK, "Pluck (N)", Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 20, -1, "If the opponent is holding a berry, its effect is stolen by user.", -1, 0, 4),
new SelfStatusMove(Moves.TAILWIND, "Tailwind (N)", Type.FLYING, -1, 15, 113, "Doubles Speed for 4 turns.", -1, 0, 4),
new AttackMove(Moves.PLUCK, "Pluck (N)", Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 20, -1, "If the opponent is holding a berry, its effect is stolen by user.", -1, 0, 4)
.target(MoveTarget.OTHER),
new SelfStatusMove(Moves.TAILWIND, "Tailwind (N)", Type.FLYING, -1, 15, 113, "Doubles Speed for 4 turns.", -1, 0, 4)
.target(MoveTarget.USER_SIDE),
new SelfStatusMove(Moves.ACUPRESSURE, "Acupressure", Type.NORMAL, -1, 30, -1, "Sharply raises a random stat.", -1, 0, 4)
.attr(StatChangeAttr, BattleStat.RAND, 2, true),
.attr(StatChangeAttr, BattleStat.RAND, 2, true)
.target(MoveTarget.USER_OR_NEAR_ALLY),
new AttackMove(Moves.METAL_BURST, "Metal Burst (N)", Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, "Deals damage equal to 1.5x opponent's attack.", -1, 0, 4)
.makesContact(false),
.makesContact(false)
.target(MoveTarget.ATTACKER),
new AttackMove(Moves.U_TURN, "U-turn (N)", Type.BUG, MoveCategory.PHYSICAL, 70, 100, 20, 60, "User switches out immediately after attacking.", -1, 0, 4),
new AttackMove(Moves.CLOSE_COMBAT, "Close Combat", Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, 167, "Lowers user's Defense and Special Defense.", 100, 0, 4)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
@ -2580,15 +2691,18 @@ export function initMoves() {
new StatusMove(Moves.PSYCHO_SHIFT, "Psycho Shift (N)", Type.PSYCHIC, 100, 10, -1, "Transfers user's status condition to the opponent.", -1, 0, 4),
new AttackMove(Moves.TRUMP_CARD, "Trump Card (N)", Type.NORMAL, MoveCategory.SPECIAL, -1, -1, 5, -1, "The lower the PP, the higher the power.", -1, 0, 4)
.makesContact(),
new StatusMove(Moves.HEAL_BLOCK, "Heal Block (N)", Type.PSYCHIC, 100, 15, -1, "Prevents the opponent from restoring HP for 5 turns.", -1, 0, 4),
new StatusMove(Moves.HEAL_BLOCK, "Heal Block (N)", Type.PSYCHIC, 100, 15, -1, "Prevents the opponent from restoring HP for 5 turns.", -1, 0, 4)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.WRING_OUT, "Wring Out (N)", Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 5, -1, "The higher the opponent's HP, the higher the damage.", -1, 0, 4)
.makesContact(),
new SelfStatusMove(Moves.POWER_TRICK, "Power Trick (N)", Type.PSYCHIC, -1, 10, -1, "User's own Attack and Defense switch.", -1, 0, 4),
new StatusMove(Moves.GASTRO_ACID, "Gastro Acid (N)", Type.POISON, 100, 10, -1, "Cancels out the effect of the opponent's Ability.", -1, 0, 4),
new StatusMove(Moves.LUCKY_CHANT, "Lucky Chant (N)", Type.NORMAL, -1, 30, -1, "Opponent cannot land critical hits for 5 turns.", -1, 0, 4)
.attr(AddBattlerTagAttr, BattlerTagType.NO_CRIT, false, 5),
.attr(AddBattlerTagAttr, BattlerTagType.NO_CRIT, false, 5)
.target(MoveTarget.USER_SIDE),
new StatusMove(Moves.ME_FIRST, "Me First (N)", Type.NORMAL, -1, 20, -1, "User copies the opponent's attack with 1.5× power.", -1, 0, 4)
.ignoresVirtual(),
.ignoresVirtual()
.target(MoveTarget.NEAR_ENEMY),
new SelfStatusMove(Moves.COPYCAT, "Copycat", Type.NORMAL, -1, 20, -1, "Copies opponent's last move.", -1, 0, 4)
.attr(CopyMoveAttr)
.ignoresVirtual(),
@ -2599,7 +2713,8 @@ export function initMoves() {
new StatusMove(Moves.WORRY_SEED, "Worry Seed (N)", Type.GRASS, 100, 10, -1, "Changes the opponent's Ability to Insomnia.", -1, 0, 4),
new AttackMove(Moves.SUCKER_PUNCH, "Sucker Punch (N)", Type.DARK, MoveCategory.PHYSICAL, 70, 100, 5, -1, "User attacks first, but only works if opponent is readying an attack.", -1, 0, 4),
new StatusMove(Moves.TOXIC_SPIKES, "Toxic Spikes", Type.POISON, -1, 20, 91, "Poisons opponents when they switch into battle.", -1, 0, 4)
.attr(AddArenaTrapTagAttr, ArenaTagType.TOXIC_SPIKES),
.attr(AddArenaTrapTagAttr, ArenaTagType.TOXIC_SPIKES)
.target(MoveTarget.ENEMY_SIDE),
new StatusMove(Moves.HEART_SWAP, "Heart Swap (N)", Type.PSYCHIC, -1, 10, -1, "Stat changes are swapped with the opponent.", -1, 0, 4),
new SelfStatusMove(Moves.AQUA_RING, "Aqua Ring", Type.WATER, -1, 20, -1, "Restores a little HP each turn.", -1, 0, 4)
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, undefined, true),
@ -2609,24 +2724,28 @@ export function initMoves() {
.attr(StatusEffectAttr, StatusEffect.BURN),
new AttackMove(Moves.FORCE_PALM, "Force Palm", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, "May paralyze opponent.", 30, 0, 4)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
new AttackMove(Moves.AURA_SPHERE, "Aura Sphere", Type.FIGHTING, MoveCategory.SPECIAL, 80, -1, 20, 112, "Ignores Accuracy and Evasiveness.", -1, 0, 4),
new AttackMove(Moves.AURA_SPHERE, "Aura Sphere", Type.FIGHTING, MoveCategory.SPECIAL, 80, -1, 20, 112, "Ignores Accuracy and Evasiveness.", -1, 0, 4)
.target(MoveTarget.OTHER),
new SelfStatusMove(Moves.ROCK_POLISH, "Rock Polish", Type.ROCK, -1, 20, -1, "Sharply raises user's Speed.", -1, 0, 4)
.attr(StatChangeAttr, BattleStat.SPD, 2, true),
new AttackMove(Moves.POISON_JAB, "Poison Jab", Type.POISON, MoveCategory.PHYSICAL, 80, 100, 20, 83, "May poison the opponent.", 30, 0, 4)
.attr(StatusEffectAttr, StatusEffect.POISON),
new AttackMove(Moves.DARK_PULSE, "Dark Pulse", Type.DARK, MoveCategory.SPECIAL, 80, 100, 15, 94, "May cause flinching.", 20, 0, 4)
.attr(FlinchAttr),
.attr(FlinchAttr)
.target(MoveTarget.OTHER),
new AttackMove(Moves.NIGHT_SLASH, "Night Slash", Type.DARK, MoveCategory.PHYSICAL, 70, 100, 15, -1, "High critical hit ratio.", -1, 0, 4)
.attr(HighCritAttr),
new AttackMove(Moves.AQUA_TAIL, "Aqua Tail", Type.WATER, MoveCategory.PHYSICAL, 90, 90, 10, -1, "", -1, 0, 4),
new AttackMove(Moves.SEED_BOMB, "Seed Bomb", Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 15, 71, "", -1, 0, 4)
.makesContact(false),
new AttackMove(Moves.AIR_SLASH, "Air Slash", Type.FLYING, MoveCategory.SPECIAL, 75, 95, 15, 65, "May cause flinching.", 30, 0, 4)
.attr(FlinchAttr),
.attr(FlinchAttr)
.target(MoveTarget.OTHER),
new AttackMove(Moves.X_SCISSOR, "X-Scissor", Type.BUG, MoveCategory.PHYSICAL, 80, 100, 15, 105, "", -1, 0, 4),
new AttackMove(Moves.BUG_BUZZ, "Bug Buzz", Type.BUG, MoveCategory.SPECIAL, 90, 100, 10, 162, "May lower opponent's Special Defense.", 10, 0, 4)
.attr(StatChangeAttr, BattleStat.SPDEF, -1),
new AttackMove(Moves.DRAGON_PULSE, "Dragon Pulse", Type.DRAGON, MoveCategory.SPECIAL, 85, 100, 10, 115, "", -1, 0, 4),
new AttackMove(Moves.DRAGON_PULSE, "Dragon Pulse", Type.DRAGON, MoveCategory.SPECIAL, 85, 100, 10, 115, "", -1, 0, 4)
.target(MoveTarget.OTHER),
new AttackMove(Moves.DRAGON_RUSH, "Dragon Rush", Type.DRAGON, MoveCategory.PHYSICAL, 100, 75, 10, -1, "May cause flinching.", 20, 0, 4)
.attr(FlinchAttr),
new AttackMove(Moves.POWER_GEM, "Power Gem", Type.ROCK, MoveCategory.SPECIAL, 80, 100, 20, 101, "", -1, 0, 4),
@ -2638,7 +2757,8 @@ export function initMoves() {
new AttackMove(Moves.ENERGY_BALL, "Energy Ball", Type.GRASS, MoveCategory.SPECIAL, 90, 100, 10, 119, "May lower opponent's Special Defense.", 10, 0, 4)
.attr(StatChangeAttr, BattleStat.SPDEF, -1),
new AttackMove(Moves.BRAVE_BIRD, "Brave Bird", Type.FLYING, MoveCategory.PHYSICAL, 120, 100, 15, 164, "User receives recoil damage.", -1, 0, 4)
.attr(RecoilAttr),
.attr(RecoilAttr)
.target(MoveTarget.OTHER),
new AttackMove(Moves.EARTH_POWER, "Earth Power", Type.GROUND, MoveCategory.SPECIAL, 90, 100, 10, 133, "May lower opponent's Special Defense.", 10, 0, 4)
.attr(StatChangeAttr, BattleStat.SPDEF, -1),
new StatusMove(Moves.SWITCHEROO, "Switcheroo (N)", Type.DARK, 100, 10, -1, "Swaps held items with the opponent.", -1, 0, 4),
@ -2681,13 +2801,16 @@ export function initMoves() {
.attr(ClearWeatherAttr, WeatherType.FOG),
new StatusMove(Moves.TRICK_ROOM, "Trick Room", Type.PSYCHIC, -1, 5, 161, "Slower Pokémon move first in the turn for 5 turns.", -1, 0, 4)
.attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5)
.ignoresProtect(),
.ignoresProtect()
.target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.DRACO_METEOR, "Draco Meteor", Type.DRAGON, MoveCategory.SPECIAL, 130, 90, 5, 169, "Sharply lowers user's Special Attack.", 100, -7, 4)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new AttackMove(Moves.DISCHARGE, "Discharge", Type.ELECTRIC, MoveCategory.SPECIAL, 80, 100, 15, -1, "May paralyze opponent.", 30, 0, 4)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.LAVA_PLUME, "Lava Plume", Type.FIRE, MoveCategory.SPECIAL, 80, 100, 15, -1, "May burn opponent.", 30, 0, 4)
.attr(StatusEffectAttr, StatusEffect.BURN),
.attr(StatusEffectAttr, StatusEffect.BURN)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.LEAF_STORM, "Leaf Storm", Type.GRASS, MoveCategory.SPECIAL, 130, 90, 5, 159, "Sharply lowers user's Special Attack.", 100, 0, 4)
.attr(StatChangeAttr, BattleStat.SPATK, -2, true),
new AttackMove(Moves.POWER_WHIP, "Power Whip", Type.GRASS, MoveCategory.PHYSICAL, 120, 85, 10, -1, "", -1, 0, 4),
@ -2709,12 +2832,14 @@ export function initMoves() {
.makesContact(false),
new StatusMove(Moves.CAPTIVATE, "Captivate (N)", Type.NORMAL, 100, 20, -1, "Sharply lowers opponent's Special Attack if opposite gender.", -1, 0, 4), // TODO
new StatusMove(Moves.STEALTH_ROCK, "Stealth Rock", Type.ROCK, -1, 20, 116, "Damages opponent switching into battle.", -1, 0, 4)
.attr(AddArenaTrapTagAttr, ArenaTagType.STEALTH_ROCK),
.attr(AddArenaTrapTagAttr, ArenaTagType.STEALTH_ROCK)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.GRASS_KNOT, "Grass Knot", Type.GRASS, MoveCategory.SPECIAL, -1, 100, 20, 81, "The heavier the opponent, the stronger the attack.", -1, 0, 4)
.attr(WeightPowerAttr)
.makesContact(),
new AttackMove(Moves.CHATTER, "Chatter", Type.FLYING, MoveCategory.SPECIAL, 65, 100, 20, -1, "Confuses opponent.", 100, 0, 4)
.attr(ConfuseAttr),
.attr(ConfuseAttr)
.target(MoveTarget.OTHER),
new AttackMove(Moves.JUDGMENT, "Judgment (N)", Type.NORMAL, MoveCategory.SPECIAL, 100, 100, 10, -1, "Type depends on the Arceus Plate being held.", -1, 0, 4),
new AttackMove(Moves.BUG_BITE, "Bug Bite (N)", Type.BUG, MoveCategory.PHYSICAL, 60, 100, 20, -1, "Receives the effect from the opponent's held berry.", -1, 0, 4),
new AttackMove(Moves.CHARGE_BEAM, "Charge Beam", Type.ELECTRIC, MoveCategory.SPECIAL, 50, 90, 10, 23, "May raise user's Special Attack.", 70, 0, 4)
@ -2743,22 +2868,25 @@ export function initMoves() {
new AttackMove(Moves.MAGMA_STORM, "Magma Storm", Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 4)
.attr(TrapAttr, BattlerTagType.MAGMA_STORM),
new StatusMove(Moves.DARK_VOID, "Dark Void", Type.DARK, 50, 10, -1, "Puts all adjacent opponents to sleep.", -1, 0, 4)
.attr(StatusEffectAttr, StatusEffect.SLEEP),
.attr(StatusEffectAttr, StatusEffect.SLEEP)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.SEED_FLARE, "Seed Flare", Type.GRASS, MoveCategory.SPECIAL, 120, 85, 5, -1, "May lower opponent's Special Defense.", 40, 0, 4)
.attr(StatChangeAttr, BattleStat.SPDEF, -1),
new AttackMove(Moves.OMINOUS_WIND, "Ominous Wind", Type.GHOST, MoveCategory.SPECIAL, 60, 100, 5, -1, "May raise all user's stats at once.", 10, 0, 4)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true),
new AttackMove(Moves.SHADOW_FORCE, "Shadow Force", Type.GHOST, MoveCategory.PHYSICAL, 120, 100, 5, -1, "Disappears on first turn, attacks on second. Can strike through PROTECT/DETECT.", -1, 0, 4)
.attr(ChargeAttr, ChargeAnim.SHADOW_FORCE_CHARGING, 'vanished\ninstantly!', BattlerTagType.HIDDEN)
.attr(ChargeAttr, ChargeAnim.SHADOW_FORCE_CHARGING, 'vanished$$$instantly!', BattlerTagType.HIDDEN)
.ignoresProtect()
.ignoresVirtual(),
new SelfStatusMove(Moves.HONE_CLAWS, "Hone Claws", Type.DARK, -1, 15, -1, "Raises user's Attack and Accuracy.", -1, 0, 5)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.ACC ], 1, true),
new SelfStatusMove(Moves.WIDE_GUARD, "Wide Guard (N)", Type.ROCK, -1, 10, -1, "Protects the user's team from multi-target attacks.", -1, 3, 5),
new SelfStatusMove(Moves.WIDE_GUARD, "Wide Guard (N)", Type.ROCK, -1, 10, -1, "Protects the user's team from multi-target attacks.", -1, 3, 5)
.target(MoveTarget.USER_SIDE),
new StatusMove(Moves.GUARD_SPLIT, "Guard Split (N)", Type.PSYCHIC, -1, 10, -1, "Averages Defense and Special Defense with the target.", -1, 0, 5),
new StatusMove(Moves.POWER_SPLIT, "Power Split (N)", Type.PSYCHIC, -1, 10, -1, "Averages Attack and Special Attack with the target.", -1, 0, 5),
new StatusMove(Moves.WONDER_ROOM, "Wonder Room (N)", Type.PSYCHIC, -1, 10, -1, "Swaps every Pokémon's Defense and Special Defense for 5 turns.", -1, -7, 5)
.ignoresProtect(),
.ignoresProtect()
.target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.PSYSHOCK, "Psyshock (N)", Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, 54, "Inflicts damage based on the target's Defense, not Special Defense.", -1, 0, 5),
new AttackMove(Moves.VENOSHOCK, "Venoshock (N)", Type.POISON, MoveCategory.SPECIAL, 65, 100, 10, 45, "Inflicts double damage if the target is poisoned.", -1, 0, 5),
new SelfStatusMove(Moves.AUTOTOMIZE, "Autotomize", Type.STEEL, -1, 15, -1, "Reduces weight and sharply raises Speed.", -1, 0, 5)
@ -2766,7 +2894,8 @@ export function initMoves() {
new SelfStatusMove(Moves.RAGE_POWDER, "Rage Powder (N)", Type.BUG, -1, 20, -1, "Forces attacks to hit user, not team-mates.", -1, 3, 5),
new StatusMove(Moves.TELEKINESIS, "Telekinesis (N)", Type.PSYCHIC, -1, 15, -1, "Ignores opponent's Evasiveness for three turns, add Ground immunity.", -1, 0, 5),
new StatusMove(Moves.MAGIC_ROOM, "Magic Room (N)", Type.PSYCHIC, -1, 10, -1, "Suppresses the effects of held items for five turns.", -1, -7, 5)
.ignoresProtect(),
.ignoresProtect()
.target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.SMACK_DOWN, "Smack Down (N)", Type.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, -1, "Makes Flying-type Pokémon vulnerable to Ground moves.", 100, 0, 5) // TODO, logic with fly
.makesContact(false),
new AttackMove(Moves.STORM_THROW, "Storm Throw (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, "Always results in a critical hit.", 100, 0, 5), // TODO
@ -2776,7 +2905,8 @@ export function initMoves() {
new SelfStatusMove(Moves.QUIVER_DANCE, "Quiver Dance", Type.BUG, -1, 20, -1, "Raises user's Special Attack, Special Defense and Speed.", -1, 0, 5)
.attr(StatChangeAttr, [ BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true),
new AttackMove(Moves.HEAVY_SLAM, "Heavy Slam (N)", Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, 121, "The heavier the user, the stronger the attack.", -1, 0, 5),
new AttackMove(Moves.SYNCHRONOISE, "Synchronoise (N)", Type.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, "Hits any Pokémon that shares a type with the user.", -1, 0, 5),
new AttackMove(Moves.SYNCHRONOISE, "Synchronoise (N)", Type.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, "Hits any Pokémon that shares a type with the user.", -1, 0, 5)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.ELECTRO_BALL, "Electro Ball (N)", Type.ELECTRIC, MoveCategory.SPECIAL, -1, 100, 10, 72, "The faster the user, the stronger the attack.", -1, 0, 5),
new StatusMove(Moves.SOAK, "Soak (N)", Type.WATER, 100, 20, -1, "Changes the target's type to water.", -1, 0, 5),
new AttackMove(Moves.FLAME_CHARGE, "Flame Charge", Type.FIRE, MoveCategory.PHYSICAL, 50, 100, 20, 38, "Raises user's Speed.", 100, 0, 5)
@ -2798,28 +2928,33 @@ export function initMoves() {
new AttackMove(Moves.CHIP_AWAY, "Chip Away (N)", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, -1, "Ignores opponent's stat changes.", -1, 0, 5),
new AttackMove(Moves.CLEAR_SMOG, "Clear Smog (N)", Type.POISON, MoveCategory.SPECIAL, 50, -1, 15, -1, "Removes all of the target's stat changes.", -1, 0, 5),
new AttackMove(Moves.STORED_POWER, "Stored Power (N)", Type.PSYCHIC, MoveCategory.SPECIAL, 20, 100, 10, 41, "Power increases when user's stats have been raised.", -1, 0, 5),
new SelfStatusMove(Moves.QUICK_GUARD, "Quick Guard (N)", Type.FIGHTING, -1, 15, -1, "Protects the user's team from high-priority moves.", -1, 3, 5),
new SelfStatusMove(Moves.QUICK_GUARD, "Quick Guard (N)", Type.FIGHTING, -1, 15, -1, "Protects the user's team from high-priority moves.", -1, 3, 5)
.target(MoveTarget.USER_SIDE),
new StatusMove(Moves.ALLY_SWITCH, "Ally Switch (N)", Type.PSYCHIC, -1, 15, -1, "User switches with opposite teammate.", -1, 0, 5)
.ignoresProtect(), // TODO
new AttackMove(Moves.SCALD, "Scald", Type.WATER, MoveCategory.SPECIAL, 80, 100, 15, -1, "May burn opponent.", 30, 1, 5)
.attr(StatusEffectAttr, StatusEffect.BURN),
.attr(StatusEffectAttr, StatusEffect.BURN)
.target(MoveTarget.USER),
new SelfStatusMove(Moves.SHELL_SMASH, "Shell Smash", Type.NORMAL, -1, 15, -1, "Sharply raises user's Attack, Special Attack and Speed but lowers Defense and Special Defense.", -1, 0, 5)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 2, true)
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true),
new StatusMove(Moves.HEAL_PULSE, "Heal Pulse", Type.PSYCHIC, -1, 10, -1, "Restores half the target's max HP.", -1, 0, 5)
.attr(HealAttr, 0.5, false, false),
.attr(HealAttr, 0.5, false, false)
.target(MoveTarget.OTHER),
new AttackMove(Moves.HEX, "Hex", Type.GHOST, MoveCategory.SPECIAL, 65, 100, 10, 29, "Inflicts more damage if the target has a status condition.", -1, 0, 5)
.attr(MovePowerMultiplierAttr, (user: Pokemon, target: Pokemon, move: Move) => target.status ? 2 : 1),
new AttackMove(Moves.SKY_DROP, "Sky Drop", Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 10, -1, "Takes opponent into the air on first turn, drops them on second turn.", -1, 0, 5)
.attr(ChargeAttr, ChargeAnim.SKY_DROP_CHARGING, 'took {TARGET}\ninto the sky!', BattlerTagType.FLYING) // TODO: Add 2nd turn message
.attr(ChargeAttr, ChargeAnim.SKY_DROP_CHARGING, 'took {TARGET}$$$into the sky!', BattlerTagType.FLYING) // TODO: Add 2nd turn message
.ignoresVirtual(),
new SelfStatusMove(Moves.SHIFT_GEAR, "Shift Gear", Type.STEEL, -1, 10, -1, "Raises user's Attack and sharply raises Speed.", -1, 0, 5)
.attr(StatChangeAttr, BattleStat.ATK, 1, true)
.attr(StatChangeAttr, BattleStat.SPD, 2, true),
new AttackMove(Moves.CIRCLE_THROW, "Circle Throw (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 90, 10, -1, "In battles, the opponent switches. In the wild, the Pokémon runs.", -1, -6, 5),
new AttackMove(Moves.INCINERATE, "Incinerate (N)", Type.FIRE, MoveCategory.SPECIAL, 60, 100, 15, -1, "Destroys the target's held berry.", -1, 0, 5),
new AttackMove(Moves.INCINERATE, "Incinerate (N)", Type.FIRE, MoveCategory.SPECIAL, 60, 100, 15, -1, "Destroys the target's held berry.", -1, 0, 5)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new StatusMove(Moves.QUASH, "Quash", Type.DARK, 100, 15, -1, "Makes the target act last this turn.", -1, 0, 5),
new AttackMove(Moves.ACROBATICS, "Acrobatics (N)", Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, 14, "Stronger when the user does not have a held item.", -1, 0, 5),
new AttackMove(Moves.ACROBATICS, "Acrobatics (N)", Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, 14, "Stronger when the user does not have a held item.", -1, 0, 5)
.target(MoveTarget.OTHER),
new StatusMove(Moves.REFLECT_TYPE, "Reflect Type", Type.NORMAL, -1, 15, -1, "User becomes the target's type.", -1, 0, 5)
.attr(CopyTypeAttr),
new AttackMove(Moves.RETALIATE, "Retaliate (N)", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 5, -1, "Inflicts double damage if a teammate fainted on the last turn.", -1, 0, 5),
@ -2835,16 +2970,19 @@ export function initMoves() {
new AttackMove(Moves.GRASS_PLEDGE, "Grass Pledge (N)", Type.GRASS, MoveCategory.SPECIAL, 80, 100, 10, 146, "Added effects appear if preceded by Water Pledge or succeeded by Fire Pledge.", -1, 0, 5),
new AttackMove(Moves.VOLT_SWITCH, "Volt Switch (N)", Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 20, 48, "User must switch out after attacking.", -1, 0, 5),
new AttackMove(Moves.STRUGGLE_BUG, "Struggle Bug", Type.BUG, MoveCategory.SPECIAL, 50, 100, 20, 15, "Lowers opponent's Special Attack.", 100, 0, 5)
.attr(StatChangeAttr, BattleStat.SPATK, -1),
.attr(StatChangeAttr, BattleStat.SPATK, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BULLDOZE, "Bulldoze", Type.GROUND, MoveCategory.PHYSICAL, 60, 100, 20, 28, "Lowers opponent's Speed.", 100, 0, 5)
.attr(StatChangeAttr, BattleStat.SPD, -1)
.makesContact(false),
.makesContact(false)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FROST_BREATH, "Frost Breath (N)", Type.ICE, MoveCategory.SPECIAL, 60, 90, 10, -1, "Always results in a critical hit.", 100, 0, 5), // TODO
new AttackMove(Moves.DRAGON_TAIL, "Dragon Tail (N)", Type.DRAGON, MoveCategory.PHYSICAL, 60, 90, 10, 44, "In battles, the opponent switches. In the wild, the Pokémon runs.", -1, -6, 5),
new SelfStatusMove(Moves.WORK_UP, "Work Up", Type.NORMAL, -1, 30, -1, "Raises user's Attack and Special Attack.", -1, 0, 5)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, true),
new AttackMove(Moves.ELECTROWEB, "Electroweb", Type.ELECTRIC, MoveCategory.SPECIAL, 55, 95, 15, -1, "Lowers opponent's Speed.", 100, 0, 5)
.attr(StatChangeAttr, BattleStat.SPD, -1),
.attr(StatChangeAttr, BattleStat.SPD, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.WILD_CHARGE, "Wild Charge", Type.ELECTRIC, MoveCategory.PHYSICAL, 90, 100, 15, 147, "User receives recoil damage.", -1, 0, 5)
.attr(RecoilAttr),
new AttackMove(Moves.DRILL_RUN, "Drill Run", Type.GROUND, MoveCategory.PHYSICAL, 80, 95, 10, 106, "High critical hit ratio.", -1, 0, 5)
@ -2872,19 +3010,23 @@ export function initMoves() {
.attr(MultiHitAttr),
new AttackMove(Moves.HURRICANE, "Hurricane", Type.FLYING, MoveCategory.SPECIAL, 110, 70, 10, 160, "May confuse opponent.", 30, 0, 5)
.attr(ThunderAccuracyAttr)
.attr(ConfuseAttr),
.attr(ConfuseAttr)
.target(MoveTarget.OTHER),
new AttackMove(Moves.HEAD_CHARGE, "Head Charge", Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 15, -1, "User receives recoil damage.", -1, 0, 5)
.attr(RecoilAttr),
new AttackMove(Moves.GEAR_GRIND, "Gear Grind", Type.STEEL, MoveCategory.PHYSICAL, 50, 85, 15, -1, "Hits twice in one turn.", -1, 0, 5)
.attr(MultiHitAttr, MultiHitType._2),
new AttackMove(Moves.SEARING_SHOT, "Searing Shot", Type.FIRE, MoveCategory.SPECIAL, 100, 100, 5, -1, "May burn opponent.", 30, 0, 5)
.attr(StatusEffectAttr, StatusEffect.BURN),
.attr(StatusEffectAttr, StatusEffect.BURN)
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.TECHNO_BLAST, "Techno Blast (N)", Type.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, -1, "Type depends on the Drive being held.", -1, 0, 5),
new AttackMove(Moves.RELIC_SONG, "Relic Song", Type.NORMAL, MoveCategory.SPECIAL, 75, 100, 10, -1, "May put the target to sleep.", 10, 0, 5)
.attr(StatusEffectAttr, StatusEffect.SLEEP),
.attr(StatusEffectAttr, StatusEffect.SLEEP)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.SECRET_SWORD, "Secret Sword (N)", Type.FIGHTING, MoveCategory.SPECIAL, 85, 100, 10, -1, "Inflicts damage based on the target's Defense, not Special Defense.", -1, 0, 5),
new AttackMove(Moves.GLACIATE, "Glaciate", Type.ICE, MoveCategory.SPECIAL, 65, 95, 10, -1, "Lowers opponent's Speed.", 100, 0, 5)
.attr(StatChangeAttr, BattleStat.SPD, -1),
.attr(StatChangeAttr, BattleStat.SPD, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.BOLT_STRIKE, "Bolt Strike", Type.ELECTRIC, MoveCategory.PHYSICAL, 130, 85, 5, -1, "May paralyze opponent.", 20, 0, 5)
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
new AttackMove(Moves.BLUE_FLARE, "Blue Flare", Type.FIRE, MoveCategory.SPECIAL, 130, 85, 5, -1, "May burn opponent.", 20, 0, 5)
@ -2895,11 +3037,12 @@ export function initMoves() {
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
.makesContact(false),
new AttackMove(Moves.ICE_BURN, "Ice Burn", Type.ICE, MoveCategory.SPECIAL, 140, 90, 5, -1, "Charges on first turn, attacks on second. May burn opponent.", 30, 0, 5)
.attr(ChargeAttr, ChargeAnim.ICE_BURN_CHARGING, 'became cloaked\nin freezing air!')
.attr(ChargeAttr, ChargeAnim.ICE_BURN_CHARGING, 'became cloaked$$$in freezing air!')
.attr(StatusEffectAttr, StatusEffect.BURN)
.ignoresVirtual(),
new AttackMove(Moves.SNARL, "Snarl", Type.DARK, MoveCategory.SPECIAL, 55, 95, 15, 30, "Lowers opponent's Special Attack.", 100, 0, 5)
.attr(StatChangeAttr, BattleStat.SPATK, -1),
.attr(StatChangeAttr, BattleStat.SPATK, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),
new AttackMove(Moves.ICICLE_CRASH, "Icicle Crash", Type.ICE, MoveCategory.PHYSICAL, 85, 90, 10, -1, "May cause flinching.", 30, 0, 5)
.attr(FlinchAttr)
.makesContact(false),
@ -2908,18 +3051,19 @@ export function initMoves() {
new AttackMove(Moves.FUSION_FLARE, "Fusion Flare (N)", Type.FIRE, MoveCategory.SPECIAL, 100, 100, 5, -1, "Power increases if Fusion Bolt is used in the same turn.", -1, 0, 5),
new AttackMove(Moves.FUSION_BOLT, "Fusion Bolt (N)", Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 100, 5, -1, "Power increases if Fusion Flare is used in the same turn.", -1, 0, 5)
.makesContact(false),
new AttackMove(Moves.MOONBLAST, 'Moonblast', Type.FAIRY, MoveCategory.SPECIAL, 95, 100, 15, -1, "May lower opponent's Special Attack.", 30, 0, 6)
new AttackMove(Moves.MOONBLAST, "Moonblast", Type.FAIRY, MoveCategory.SPECIAL, 95, 100, 15, -1, "May lower opponent's Special Attack.", 30, 0, 6)
.attr(StatChangeAttr, BattleStat.SPATK, -1),
new AttackMove(Moves.PHANTOM_FORCE, "Phantom Force", Type.GHOST, MoveCategory.PHYSICAL, 90, 100, 10, -1, "Disappears on first turn, attacks on second. Can strike through PROTECT/DETECT.", -1, 0, 6)
.attr(ChargeAttr, ChargeAnim.PHANTOM_FORCE_CHARGING, 'vanished\ninstantly!', BattlerTagType.HIDDEN)
.attr(ChargeAttr, ChargeAnim.PHANTOM_FORCE_CHARGING, 'vanished$$$instantly!', BattlerTagType.HIDDEN)
.ignoresProtect()
.ignoresVirtual(),
new SelfStatusMove(Moves.GEOMANCY, "Geomancy", Type.FAIRY, -1, 10, -1, "Charges on the first turn, sharply raises user's Special Attack, Special Defense and Speed on the second.", -1, 0, 6)
.attr(ChargeAttr, ChargeAnim.GEOMANCY_CHARGING, "is charging\nits power!")
.attr(ChargeAttr, ChargeAnim.GEOMANCY_CHARGING, "is charging$$$its power!")
.attr(StatChangeAttr, [ BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true)
.ignoresVirtual(),
new AttackMove(Moves.OBLIVION_WING, "Oblivion Wing", Type.FLYING, MoveCategory.SPECIAL, 80, 100, 10, -1, "User recovers 3/4 the HP inflicted on the opponent.", -1, 0, 6)
.attr(HitHealAttr, 0.75),
.attr(HitHealAttr, 0.75)
.target(MoveTarget.OTHER),
new AttackMove(Moves.DYNAMAX_CANNON, "Dynamax Cannon", Type.DRAGON, MoveCategory.SPECIAL, 100, 100, 5, -1, "Power is doubled if the target is over level 200.", -1, 0, 8)
.attr(MovePowerMultiplierAttr, (user: Pokemon, target: Pokemon, move: Move) => target.level > 200 ? 2 : 1)
.ignoresVirtual()