diff --git a/src/arena.ts b/src/arena.ts index c637322be..d96591c73 100644 --- a/src/arena.ts +++ b/src/arena.ts @@ -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); diff --git a/src/battle-phases.ts b/src/battle-phases.ts index 53eed4f2e..508110ef1 100644 --- a/src/battle-phases.ts +++ b/src/battle-phases.ts @@ -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) { @@ -117,6 +118,8 @@ export class EncounterPhase extends BattlePhase { end() { 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); } }); } @@ -504,8 +508,11 @@ export class CommandPhase extends BattlePhase { case Command.RUN: return true; } + + const speedDelayed = new Utils.BooleanHolder(playerSpeed < enemySpeed); + this.scene.arena.applyTags(TrickRoomTag, speedDelayed); - return playerSpeed < enemySpeed || (playerSpeed === enemySpeed && Utils.randInt(2) === 1); + 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(); diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index a7e40843d..ee5a25846 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -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); } } \ No newline at end of file diff --git a/src/data/battler-tag.ts b/src/data/battler-tag.ts index af21f88b0..3ef76ef72 100644 --- a/src/data/battler-tag.ts +++ b/src/data/battler-tag.ts @@ -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); } } \ No newline at end of file diff --git a/src/data/move.ts b/src/data/move.ts index 8b7e1f8ce..dc049f6c4 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8,7 +8,7 @@ import { StatusEffect, getStatusEffectDescriptor } from "./status-effect"; import { Type } from "./type"; import * as Utils from "../utils"; import { WeatherType } from "./weather"; -import { ArenaTagType } from "./arena-tag"; +import { ArenaTagType, ArenaTrapTag } from "./arena-tag"; export enum MoveCategory { PHYSICAL, @@ -20,6 +20,8 @@ export enum MoveFlags { IGNORE_PROTECT = 1 } +type MoveCondition = (user: Pokemon, target: Pokemon, move: Move) => boolean; + export default class Move { public id: Moves; public name: string; @@ -36,8 +38,9 @@ export default class Move { public generation: integer; public attrs: MoveAttr[]; private flags: integer; + private conditions: MoveCondition[]; - 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, ...attrs: MoveAttr[]) { + 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) { this.id = id; this.name = name.toUpperCase(); this.type = type; @@ -51,19 +54,45 @@ export default class Move { this.chance = chance; this.priority = priority; this.generation = generation; - this.attrs = attrs; + this.attrs = []; this.flags = (this.selfTarget ? MoveFlags.IGNORE_PROTECT : 0); + this.conditions = []; } getAttrs(attrType: { new(...args: any[]): MoveAttr }): MoveAttr[] { return this.attrs.filter(a => a instanceof attrType); } + attr MoveAttr>(AttrType: T, ...args: ConstructorParameters): Move { + const attr = new AttrType(...args); + this.attrs.push(attr); + const attrCondition = attr.getCondition(); + if (attrCondition) + this.conditions.push(attrCondition); + + return this; + } + + addAttr(attr: MoveAttr): Move { + this.attrs.push(attr); + const attrCondition = attr.getCondition(); + if (attrCondition) + this.conditions.push(attrCondition); + + return this; + } + hasFlag(flag: MoveFlags): boolean { return !!(this.flags & flag); } + condition(condition: MoveCondition): Move { + this.conditions.push(condition); + + return this; + } + ignoreProtect(ignoreProtect?: boolean): Move { if (ignoreProtect) this.flags |= MoveFlags.IGNORE_PROTECT; @@ -71,23 +100,32 @@ export default class Move { this.flags ^= MoveFlags.IGNORE_PROTECT; return this; } + + applyConditions(user: Pokemon, target: Pokemon, move: Move): boolean { + for (let condition of this.conditions) { + if (!condition(user, target, move)) + return false; + } + + return true; + } } 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, ...attrs: MoveAttr[]) { - super(id, name, type, category, false, power, accuracy, pp, tm, effect, chance, priority, generation, ...attrs); + 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); } } 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, ...attrs: MoveAttr[]) { - super(id, name, type, MoveCategory.STATUS, false, -1, accuracy, pp, tm, effect, chance, priority, generation, ...attrs); + 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); } } 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, ...attrs: MoveAttr[]) { - super(id, name, type, MoveCategory.STATUS, true, -1, accuracy, pp, tm, effect, chance, priority, generation, ...attrs); + 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); } } @@ -654,12 +692,14 @@ export enum Moves { FUSION_BOLT } -type MoveAttrFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean; - export abstract class MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { return true; } + + getCondition(): MoveCondition { + return null; + } } export class MoveEffectAttr extends MoveAttr { @@ -918,7 +958,7 @@ export class HealStatusEffectAttr extends MoveEffectAttr { export class BypassSleepAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (user.status?.effect === StatusEffect.SLEEP) { - user.addTag(BattlerTagType.BYPASS_SLEEP, 1); + user.addTag(BattlerTagType.BYPASS_SLEEP, 1, move.id, user.id); return true; } @@ -938,6 +978,10 @@ export class WeatherChangeAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { return user.scene.arena.trySetWeather(this.weatherType, true); } + + getCondition(): MoveCondition { + return (user: Pokemon, target: Pokemon, move: Move) => !user.scene.arena.weather || (user.scene.arena.weather.weatherType !== this.weatherType && !user.scene.arena.weather.isImmutable()); + } } export class ClearWeatherAttr extends MoveEffectAttr { @@ -990,7 +1034,7 @@ export class ChargeAttr extends OverrideMoveEffectAttr { new MoveChargeAnim(this.chargeAnim, move.id, user, target).play(user.scene, () => { user.scene.queueMessage(getPokemonMessage(user, ` ${this.chargeText.replace('{TARGET}', target.name)}`)); if (this.tagType) - user.addTag(this.tagType, 1); + user.addTag(this.tagType, 1, move.id, user.id); if (this.chargeEffect) applyMoveAttrs(MoveEffectAttr, user, target, move); user.getMoveHistory().push({ move: move.id, result: MoveResult.OTHER }); @@ -1195,6 +1239,18 @@ export class HpPowerAttr extends VariablePowerAttr { } } +export class TurnDamagedDoublePowerAttr extends VariablePowerAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const power = args[0] as Utils.NumberHolder; + if (target.turnData.damageDealt) { // Would need to be updated for doublebattles + power.value *= 2; + return true; + } + + return false; + } +} + export class SolarBeamPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const power = args[0] as Utils.NumberHolder; @@ -1252,50 +1308,10 @@ export class BlizzardAccuracyAttr extends VariableAccuracyAttr { } } -export class ConditionalMoveAttr extends MoveAttr { - private successFunc: MoveAttrFunc; - - constructor(successFunc: MoveAttrFunc) { - super(); - - this.successFunc = successFunc; - } - - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (!(args[0] as Utils.BooleanHolder).value && !this.successFunc(user, target, move)) { - (args[0] as Utils.BooleanHolder).value = true; - return true; - } - - return false; - } -} - -export class WaningConsecutiveUseConditionalMoveAttr extends ConditionalMoveAttr { - constructor() { - super(((user: Pokemon, target: Pokemon, move: Move): boolean => { - let timesUsed = 0; - const moveHistory = user.getLastXMoves(-1); - let turnMove: TurnMove; - while (moveHistory.length && (turnMove = moveHistory.shift()).move === move.id && turnMove.result === MoveResult.STATUS) - timesUsed++; - if (timesUsed) - return !Utils.randInt(Math.pow(2, timesUsed)); - return true; - })); - } -} - -export class WeatherConditionalMoveAttr extends ConditionalMoveAttr { - constructor(weatherType: WeatherType) { - super((user: Pokemon, target: Pokemon, move: Move) => !user.scene.arena.weather || (user.scene.arena.weather.weatherType !== weatherType && !user.scene.arena.weather.isImmutable())); - } -} - export class MissEffectAttr extends MoveAttr { - private missEffectFunc: MoveAttrFunc; + private missEffectFunc: MoveCondition; - constructor(missEffectFunc: MoveAttrFunc) { + constructor(missEffectFunc: MoveCondition) { super(); this.missEffectFunc = missEffectFunc; @@ -1337,11 +1353,9 @@ export class DisableMoveAttr extends MoveEffectAttr { return false; } -} - -export class DisableMoveConditionalMoveAttr extends ConditionalMoveAttr { - constructor() { - super((user: Pokemon, target: Pokemon, move: Move) => { + + getCondition(): MoveCondition { + return (user: Pokemon, target: Pokemon, move: Move) => { const moveQueue = target.getLastXMoves(); let turnMove: TurnMove; while (moveQueue.length) { @@ -1355,7 +1369,7 @@ export class DisableMoveConditionalMoveAttr extends ConditionalMoveAttr { return !move.isDisabled(); } - }); + }; } } @@ -1376,7 +1390,7 @@ export class FrenzyAttr extends MoveEffectAttr { if (!user.getTag(BattlerTagType.FRENZY)) { const turnCount = Utils.randInt(2) + 1; new Array(turnCount).fill(null).map(() => user.getMoveQueue().push({ move: move.id, ignorePP: true })); - user.addTag(BattlerTagType.FRENZY, 1); + user.addTag(BattlerTagType.FRENZY, 1, move.id, user.id); } else { applyMoveAttrs(AddBattlerTagAttr, user, target, move, args); user.lapseTag(BattlerTagType.FRENZY); @@ -1388,21 +1402,25 @@ export class FrenzyAttr extends MoveEffectAttr { } } -export const frenzyMissFunc = (user: Pokemon, target: Pokemon, move: Move) => { +export const frenzyMissFunc: MoveCondition = (user: Pokemon, target: Pokemon, move: Move) => { while (user.getMoveQueue().length && user.getMoveQueue()[0].move === move.id) user.getMoveQueue().shift(); - user.lapseTag(BattlerTagType.FRENZY) + user.lapseTag(BattlerTagType.FRENZY); + + return true; }; export class AddBattlerTagAttr extends MoveEffectAttr { public tagType: BattlerTagType; public turnCount: integer; + private failOnOverlap: boolean; - constructor(tagType: BattlerTagType, selfTarget?: boolean, turnCount?: integer) { + constructor(tagType: BattlerTagType, selfTarget?: boolean, turnCount?: integer, failOnOverlap?: boolean) { super(selfTarget); this.tagType = tagType; this.turnCount = turnCount; + this.failOnOverlap = !!failOnOverlap; } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -1410,12 +1428,18 @@ export class AddBattlerTagAttr extends MoveEffectAttr { return false; if (move.chance < 0 || move.chance === 100 || Utils.randInt(100) < move.chance) { - (this.selfTarget ? user : target).addTag(this.tagType, this.turnCount, user.id, move.id); + (this.selfTarget ? user : target).addTag(this.tagType, this.turnCount, move.id, user.id); return true; } return false; } + + getCondition(): MoveCondition { + return this.failOnOverlap + ? (user: Pokemon, target: Pokemon, move: Move) => !(this.selfTarget ? user : target).getTag(this.tagType) + : null; + } } export class LapseBattlerTagAttr extends MoveEffectAttr { @@ -1456,9 +1480,22 @@ export class TrapAttr extends AddBattlerTagAttr { } } -export class NoTagOverlapConditionalAttr extends ConditionalMoveAttr { - constructor(tagType: BattlerTagType, selfTarget?: boolean) { - super((user: Pokemon, target: Pokemon, move: Move) => !(selfTarget ? user : target).getTag(tagType)); +export class ProtectAttr extends AddBattlerTagAttr { + constructor() { + super(BattlerTagType.PROTECTED, true); + } + + getCondition(): MoveCondition { + return ((user: Pokemon, target: Pokemon, move: Move): boolean => { + let timesUsed = 0; + const moveHistory = user.getLastXMoves(-1); + let turnMove: TurnMove; + while (moveHistory.length && (turnMove = moveHistory.shift()).move === move.id && turnMove.result === MoveResult.STATUS) + timesUsed++; + if (timesUsed) + return !Utils.randInt(Math.pow(2, timesUsed)); + return true; + }); } } @@ -1490,7 +1527,7 @@ export class AddArenaTagAttr extends MoveEffectAttr { return false; if (move.chance < 0 || move.chance === 100 || Utils.randInt(100) < move.chance) { - user.scene.arena.addTag(this.tagType, this.turnCount); + user.scene.arena.addTag(this.tagType, this.turnCount, move.id, user.id); return true; } @@ -1498,6 +1535,17 @@ export class AddArenaTagAttr extends MoveEffectAttr { } } +export class AddArenaTrapTagAttr extends AddArenaTagAttr { + getCondition(): MoveCondition { + return (user: Pokemon, target: Pokemon, move: Move) => { + if (!user.scene.arena.getTag(this.tagType)) + return true; + const tag = user.scene.arena.getTag(this.tagType) as ArenaTrapTag; + return tag.layers < tag.maxLayers; + }; + } +} + export class CopyTypeAttr extends MoveEffectAttr { constructor() { super(true); @@ -1599,24 +1647,12 @@ export class CopyMoveAttr extends OverrideMoveEffectAttr { return true; } + + getCondition(): MoveCondition { + return targetMoveCopiableCondition; + } } -const targetMoveSketchableCondition = (user: Pokemon, target: Pokemon, move: Move) => { - if (!targetMoveCopiableCondition(user, target, move)) - return false; - - const targetMoves = target.getMoveHistory().filter(m => !m.virtual); - if (!targetMoves.length) - return false; - - const sketchableMove = targetMoves[0]; - - if (user.moveset.find(m => m.moveId === sketchableMove.move)) - return false; - - return true; -}; - export class SketchAttr extends MoveEffectAttr { constructor() { super(true); @@ -1643,6 +1679,24 @@ export class SketchAttr extends MoveEffectAttr { return true; } + + getCondition(): MoveCondition { + return (user: Pokemon, target: Pokemon, move: Move) => { + if (!targetMoveCopiableCondition(user, target, move)) + return false; + + const targetMoves = target.getMoveHistory().filter(m => !m.virtual); + if (!targetMoves.length) + return false; + + const sketchableMove = targetMoves[0]; + + if (user.moveset.find(m => m.moveId === sketchableMove.move)) + return false; + + return true; + }; + } } export function applyMoveAttrs(attrType: { new(...args: any[]): MoveAttr }, user: Pokemon, target: Pokemon, move: Move, ...args: any[]): Promise { @@ -1661,426 +1715,674 @@ export function applyMoveAttrs(attrType: { new(...args: any[]): MoveAttr }, user export const allMoves = [ new StatusMove(Moves.NONE, "-", Type.NORMAL, MoveCategory.STATUS, -1, -1, "", -1, 0, 1), new AttackMove(Moves.POUND, "Pound", Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, "", -1, 0, 1), - new AttackMove(Moves.KARATE_CHOP, "Karate Chop", Type.FIGHTING, MoveCategory.PHYSICAL, 50, 100, 25, -1, "High critical hit ratio.", -1, 0, 1, new HighCritAttr()), - new AttackMove(Moves.DOUBLE_SLAP, "Double Slap", Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 10, -1, "Hits 2-5 times in one turn.", -1, 0, 1, new MultiHitAttr()), - new AttackMove(Moves.COMET_PUNCH, "Comet Punch", Type.NORMAL, MoveCategory.PHYSICAL, 18, 85, 15, -1, "Hits 2-5 times in one turn.", -1, 0, 1, new MultiHitAttr()), + new AttackMove(Moves.KARATE_CHOP, "Karate Chop", Type.FIGHTING, MoveCategory.PHYSICAL, 50, 100, 25, -1, "High critical hit ratio.", -1, 0, 1) + .attr(HighCritAttr), + new AttackMove(Moves.DOUBLE_SLAP, "Double Slap", Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 10, -1, "Hits 2-5 times in one turn.", -1, 0, 1) + .attr(MultiHitAttr), + new AttackMove(Moves.COMET_PUNCH, "Comet Punch", Type.NORMAL, MoveCategory.PHYSICAL, 18, 85, 15, -1, "Hits 2-5 times in one turn.", -1, 0, 1) + .attr(MultiHitAttr), new AttackMove(Moves.MEGA_PUNCH, "Mega Punch", Type.NORMAL, MoveCategory.PHYSICAL, 80, 85, 20, -1, "", -1, 0, 1), new AttackMove(Moves.PAY_DAY, "Pay Day (N)", Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 20, -1, "Money is earned after the battle.", -1, 0, 1), - new AttackMove(Moves.FIRE_PUNCH, "Fire Punch", Type.FIRE, MoveCategory.PHYSICAL, 75, 100, 15, 67, "May burn opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.BURN)), - new AttackMove(Moves.ICE_PUNCH, "Ice Punch", Type.ICE, MoveCategory.PHYSICAL, 75, 100, 15, 69, "May freeze opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.FREEZE)), - new AttackMove(Moves.THUNDER_PUNCH, "Thunder Punch", Type.ELECTRIC, MoveCategory.PHYSICAL, 75, 100, 15, 68, "May paralyze opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS)), + new AttackMove(Moves.FIRE_PUNCH, "Fire Punch", Type.FIRE, MoveCategory.PHYSICAL, 75, 100, 15, 67, "May burn opponent.", 10, 0, 1) + .attr(StatusEffectAttr, StatusEffect.BURN), + new AttackMove(Moves.ICE_PUNCH, "Ice Punch", Type.ICE, MoveCategory.PHYSICAL, 75, 100, 15, 69, "May freeze opponent.", 10, 0, 1) + .attr(StatusEffectAttr, StatusEffect.FREEZE), + new AttackMove(Moves.THUNDER_PUNCH, "Thunder Punch", Type.ELECTRIC, MoveCategory.PHYSICAL, 75, 100, 15, 68, "May paralyze opponent.", 10, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), new AttackMove(Moves.SCRATCH, "Scratch", Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, "", -1, 0, 1), new AttackMove(Moves.VISE_GRIP, "Vise Grip", Type.NORMAL, MoveCategory.PHYSICAL, 55, 100, 30, -1, "", -1, 0, 1), - new AttackMove(Moves.GUILLOTINE, "Guillotine", Type.NORMAL, MoveCategory.PHYSICAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 1, new 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, - new ChargeAttr(ChargeAnim.RAZOR_WIND_CHARGING, 'whipped\nup a whirlwind!'), new HighCritAttr()), - new SelfStatusMove(Moves.SWORDS_DANCE, "Swords Dance", Type.NORMAL, -1, 20, 88, "Sharply raises user's Attack.", -1, 0, 1, new StatChangeAttr(BattleStat.ATK, 2, true)), + 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(HighCritAttr), + 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, - new HitsTagAttr(BattlerTagType.FLYING, true)), + 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), 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, - new ChargeAttr(ChargeAnim.FLY_CHARGING, 'flew\nup high!', BattlerTagType.FLYING)), - new AttackMove(Moves.BIND, "Bind", Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 1, new TrapAttr(BattlerTagType.BIND)), + 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), + 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), new AttackMove(Moves.SLAM, "Slam", Type.NORMAL, MoveCategory.PHYSICAL, 80, 75, 20, -1, "", -1, 0, 1), new AttackMove(Moves.VINE_WHIP, "Vine Whip", Type.GRASS, MoveCategory.PHYSICAL, 45, 100, 25, -1, "", -1, 0, 1), - new AttackMove(Moves.STOMP, "Stomp", Type.NORMAL, MoveCategory.PHYSICAL, 65, 100, 20, -1, "May cause flinching.", 30, 0, 1, new FlinchAttr()), - new AttackMove(Moves.DOUBLE_KICK, "Double Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 30, 100, 30, -1, "Hits twice in one turn.", -1, 0, 1, new MultiHitAttr(MultiHitType._2)), + new AttackMove(Moves.STOMP, "Stomp", Type.NORMAL, MoveCategory.PHYSICAL, 65, 100, 20, -1, "May cause flinching.", 30, 0, 1) + .attr(FlinchAttr), + new AttackMove(Moves.DOUBLE_KICK, "Double Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 30, 100, 30, -1, "Hits twice in one turn.", -1, 0, 1) + .attr(MultiHitAttr, MultiHitType._2), new AttackMove(Moves.MEGA_KICK, "Mega Kick", Type.NORMAL, MoveCategory.PHYSICAL, 120, 75, 5, -1, "", -1, 0, 1), - new AttackMove(Moves.JUMP_KICK, "Jump Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 95, 10, -1, "If it misses, the user loses half their HP.", -1, 0, 1, - new MissEffectAttr((user: Pokemon, target: Pokemon, move: Move) => { user.damage(Math.floor(user.getMaxHp() / 2)); return true; })), - new AttackMove(Moves.ROLLING_KICK, "Rolling Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 85, 15, -1, "May cause flinching.", 30, 0, 1, new FlinchAttr()), - new StatusMove(Moves.SAND_ATTACK, "Sand Attack", Type.GROUND, 100, 15, -1, "Lowers opponent's Accuracy.", -1, 0, 1, new StatChangeAttr(BattleStat.ACC, -1)), - new AttackMove(Moves.HEADBUTT, "Headbutt", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 15, -1, "May cause flinching.", 30, 0, 1, new FlinchAttr()), + new AttackMove(Moves.JUMP_KICK, "Jump Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 95, 10, -1, "If it misses, the user loses half their HP.", -1, 0, 1) + .attr(MissEffectAttr, (user: Pokemon, target: Pokemon, move: Move) => { user.damage(Math.floor(user.getMaxHp() / 2)); return true; }), + new AttackMove(Moves.ROLLING_KICK, "Rolling Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 85, 15, -1, "May cause flinching.", 30, 0, 1) + .attr(FlinchAttr), + new StatusMove(Moves.SAND_ATTACK, "Sand Attack", Type.GROUND, 100, 15, -1, "Lowers opponent's Accuracy.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.ACC, -1), + new AttackMove(Moves.HEADBUTT, "Headbutt", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 15, -1, "May cause flinching.", 30, 0, 1) + .attr(FlinchAttr), new AttackMove(Moves.HORN_ATTACK, "Horn Attack", Type.NORMAL, MoveCategory.PHYSICAL, 65, 100, 25, -1, "", -1, 0, 1), - new AttackMove(Moves.FURY_ATTACK, "Fury Attack", Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, "Hits 2-5 times in one turn.", -1, 0, 1, new MultiHitAttr()), - new AttackMove(Moves.HORN_DRILL, "Horn Drill", Type.NORMAL, MoveCategory.PHYSICAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 1, new OneHitKOAttr()), + new AttackMove(Moves.FURY_ATTACK, "Fury Attack", Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, "Hits 2-5 times in one turn.", -1, 0, 1) + .attr(MultiHitAttr), + new AttackMove(Moves.HORN_DRILL, "Horn Drill", Type.NORMAL, MoveCategory.PHYSICAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 1) + .attr(OneHitKOAttr), new AttackMove(Moves.TACKLE, "Tackle", Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, "", -1, 0, 1), - new AttackMove(Moves.BODY_SLAM, "Body Slam", Type.NORMAL, MoveCategory.PHYSICAL, 85, 100, 15, 66, "May paralyze opponent.", 30, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.WRAP, "Wrap", Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 1, new TrapAttr(BattlerTagType.WRAP)), - new AttackMove(Moves.TAKE_DOWN, "Take Down", Type.NORMAL, MoveCategory.PHYSICAL, 90, 85, 20, 1, "User receives recoil damage.", -1, 0, 1, new RecoilAttr()), - new AttackMove(Moves.THRASH, "Thrash", Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 10, -1, "User attacks for 2-3 turns but then becomes confused.", -1, 0, 1, - new FrenzyAttr(), frenzyMissFunc, new 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, new RecoilAttr()), - new StatusMove(Moves.TAIL_WHIP, "Tail Whip", Type.NORMAL, 100, 30, -1, "Lowers opponent's Defense.", -1, 0, 1, new StatChangeAttr(BattleStat.DEF, -1)), - new AttackMove(Moves.POISON_STING, "Poison Sting", Type.POISON, MoveCategory.PHYSICAL, 15, 100, 35, -1, "May poison the opponent.", 30, 0, 1, new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.TWINEEDLE, "Twineedle", Type.BUG, MoveCategory.PHYSICAL, 25, 100, 20, -1, "Hits twice in one turn. May poison opponent.", 20, 0, 1, new MultiHitAttr(MultiHitType._2), new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.PIN_MISSILE, "Pin Missile", Type.BUG, MoveCategory.PHYSICAL, 25, 95, 20, -1, "Hits 2-5 times in one turn.", -1, 1, 0,new MultiHitAttr()), - new StatusMove(Moves.LEER, "Leer", Type.NORMAL, 100, 30, -1, "Lowers opponent's Defense.", 100, 0, 1, new StatChangeAttr(BattleStat.DEF, -1)), - new AttackMove(Moves.BITE, "Bite", Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, -1, "May cause flinching.", 30, 0, 1, new FlinchAttr()), - new StatusMove(Moves.GROWL, "Growl", Type.NORMAL, 100, 40, -1, "Lowers opponent's Attack.", -1, 0, 1, new StatChangeAttr(BattleStat.ATK, -1)), + new AttackMove(Moves.BODY_SLAM, "Body Slam", Type.NORMAL, MoveCategory.PHYSICAL, 85, 100, 15, 66, "May paralyze opponent.", 30, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + new AttackMove(Moves.WRAP, "Wrap", Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 1) + .attr(TrapAttr, BattlerTagType.WRAP), + new AttackMove(Moves.TAKE_DOWN, "Take Down", Type.NORMAL, MoveCategory.PHYSICAL, 90, 85, 20, 1, "User receives recoil damage.", -1, 0, 1) + .attr(RecoilAttr), + new AttackMove(Moves.THRASH, "Thrash", Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 10, -1, "User attacks for 2-3 turns but then becomes confused.", -1, 0, 1) + .attr(FrenzyAttr) + .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), + new StatusMove(Moves.TAIL_WHIP, "Tail Whip", Type.NORMAL, 100, 30, -1, "Lowers opponent's Defense.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.DEF, -1), + 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), + new AttackMove(Moves.TWINEEDLE, "Twineedle", Type.BUG, MoveCategory.PHYSICAL, 25, 100, 20, -1, "Hits twice in one turn. May poison opponent.", 20, 0, 1) + .attr(MultiHitAttr, MultiHitType._2) + .attr(StatusEffectAttr, StatusEffect.POISON), + new AttackMove(Moves.PIN_MISSILE, "Pin Missile", Type.BUG, MoveCategory.PHYSICAL, 25, 95, 20, -1, "Hits 2-5 times in one turn.", -1, 1, 0) + .attr(MultiHitAttr), + new StatusMove(Moves.LEER, "Leer", Type.NORMAL, 100, 30, -1, "Lowers opponent's Defense.", 100, 0, 1) + .attr(StatChangeAttr, BattleStat.DEF, -1), + 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), 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, new StatusEffectAttr(StatusEffect.SLEEP)), - new StatusMove(Moves.SUPERSONIC, "Supersonic", Type.NORMAL, 55, 20, -1, "Confuses opponent.", -1, 0, 1, new ConfuseAttr()), - new AttackMove(Moves.SONIC_BOOM, "Sonic Boom", Type.NORMAL, MoveCategory.SPECIAL, -1, 90, 20, -1, "Always inflicts 20 HP.", -1, 0, 1, new FixedDamageAttr(20)), - new StatusMove(Moves.DISABLE, "Disable", Type.NORMAL, 100, 20, -1, "Opponent can't use its last attack for a few turns.", -1, 0, 1, new DisableMoveConditionalMoveAttr(), new DisableMoveAttr()), - new AttackMove(Moves.ACID, "Acid", Type.POISON, MoveCategory.SPECIAL, 40, 100, 30, -1, "May lower opponent's Special Defense.", 10, 0, 1, new StatChangeAttr(BattleStat.SPDEF, -1)), - new AttackMove(Moves.EMBER, "Ember", Type.FIRE, MoveCategory.SPECIAL, 40, 100, 25, -1, "May burn opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.BURN)), - new AttackMove(Moves.FLAMETHROWER, "Flamethrower", Type.FIRE, MoveCategory.SPECIAL, 90, 100, 15, 125, "May burn opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.BURN)), + new StatusMove(Moves.SING, "Sing", Type.NORMAL, 55, 15, -1, "Puts opponent to sleep.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.SLEEP), + new StatusMove(Moves.SUPERSONIC, "Supersonic", Type.NORMAL, 55, 20, -1, "Confuses opponent.", -1, 0, 1) + .attr(ConfuseAttr), + new AttackMove(Moves.SONIC_BOOM, "Sonic Boom", Type.NORMAL, MoveCategory.SPECIAL, -1, 90, 20, -1, "Always inflicts 20 HP.", -1, 0, 1) + .attr(FixedDamageAttr, 20), + 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), + 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 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, new StatusEffectAttr(StatusEffect.FREEZE)), - new AttackMove(Moves.BLIZZARD, "Blizzard", Type.ICE, MoveCategory.SPECIAL, 110, 70, 5, 143, "May freeze opponent.", 10, 0, 1, new BlizzardAccuracyAttr(), new 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, new ConfuseAttr()), - new AttackMove(Moves.BUBBLE_BEAM, "Bubble Beam", Type.WATER, MoveCategory.SPECIAL, 65, 100, 20, -1, "May lower opponent's Speed.", 10, 0, 1, new 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, new 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, new AddBattlerTagAttr(BattlerTagType.RECHARGING, true)), + 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), + 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), + 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.SUBMISSION, "Submission", Type.FIGHTING, MoveCategory.PHYSICAL, 80, 80, 20, -1, "User receives recoil damage.", -1, 0, 1, new 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, new WeightPowerAttr()), + 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.SEISMIC_TOSS, "Seismic Toss", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, -1, "Inflicts damage equal to user's level (maximum 150).", -1, 0, 1, new LevelPowerAttr()), + 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), - new AttackMove(Moves.ABSORB, "Absorb", Type.GRASS, MoveCategory.SPECIAL, 20, 100, 25, -1, "User recovers half the HP inflicted on opponent.", -1, 0, 1, new HitHealAttr()), - new AttackMove(Moves.MEGA_DRAIN, "Mega Drain", Type.GRASS, MoveCategory.SPECIAL, 40, 100, 15, -1, "User recovers half the HP inflicted on opponent.", -1, 0, 1, new HitHealAttr()), - new StatusMove(Moves.LEECH_SEED, "Leech Seed", Type.GRASS, 90, 10, -1, "Drains HP from opponent each turn.", -1, 0, 1, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => !target.getTag(BattlerTagType.SEEDED) && !target.isOfType(Type.GRASS)), new AddBattlerTagAttr(BattlerTagType.SEEDED)), - new SelfStatusMove(Moves.GROWTH, "Growth", Type.NORMAL, -1, 20, -1, "Raises user's Attack and Special Attack.", -1, 0, 1, new GrowthStatChangeAttr()), - new AttackMove(Moves.RAZOR_LEAF, "Razor Leaf", Type.GRASS, MoveCategory.PHYSICAL, 55, 95, 25, -1, "High critical hit ratio.", -1, 0, 1, new HighCritAttr()), - 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, - new SolarBeamChargeAttr(), new SolarBeamPowerAttr()), - new StatusMove(Moves.POISON_POWDER, "Poison Powder", Type.POISON, 75, 35, -1, "Poisons opponent.", -1, 0, 1, new StatusEffectAttr(StatusEffect.POISON)), - new StatusMove(Moves.STUN_SPORE, "Stun Spore", Type.GRASS, 75, 30, -1, "Paralyzes opponent.", -1, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new StatusMove(Moves.SLEEP_POWDER, "Sleep Powder", Type.GRASS, 75, 15, -1, "Puts opponent to sleep.", -1, 0, 1, new StatusEffectAttr(StatusEffect.SLEEP)), - new AttackMove(Moves.PETAL_DANCE, "Petal Dance", Type.GRASS, MoveCategory.SPECIAL, 120, 100, 10, -1, "User attacks for 2-3 turns but then becomes confused.", -1, 0, 1, - new FrenzyAttr(), frenzyMissFunc, new ConfuseAttr(true)), // TODO: Update to still confuse if last hit misses - new StatusMove(Moves.STRING_SHOT, "String Shot", Type.BUG, 95, 40, -1, "Sharply lowers opponent's Speed.", -1, 0, 1, new StatChangeAttr(BattleStat.SPD, -2)), - new AttackMove(Moves.DRAGON_RAGE, "Dragon Rage", Type.DRAGON, MoveCategory.SPECIAL, -1, 100, 10, -1, "Always inflicts 40 HP.", -1, 0, 1, new 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, new TrapAttr(BattlerTagType.FIRE_SPIN)), - new AttackMove(Moves.THUNDER_SHOCK, "Thunder Shock", Type.ELECTRIC, MoveCategory.SPECIAL, 40, 100, 30, -1, "May paralyze opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.THUNDERBOLT, "Thunderbolt", Type.ELECTRIC, MoveCategory.SPECIAL, 90, 100, 15, 126, "May paralyze opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new StatusMove(Moves.THUNDER_WAVE, "Thunder Wave", Type.ELECTRIC, 90, 20, 82, "Paralyzes opponent.", -1, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS), new ThunderAccuracyAttr()), - new AttackMove(Moves.THUNDER, "Thunder", Type.ELECTRIC, MoveCategory.SPECIAL, 110, 70, 10, 166, "May paralyze opponent.", 30, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS)), + new AttackMove(Moves.ABSORB, "Absorb", Type.GRASS, MoveCategory.SPECIAL, 20, 100, 25, -1, "User recovers half the HP inflicted on opponent.", -1, 0, 1) + .attr(HitHealAttr), + new AttackMove(Moves.MEGA_DRAIN, "Mega Drain", Type.GRASS, MoveCategory.SPECIAL, 40, 100, 15, -1, "User recovers half the HP inflicted on opponent.", -1, 0, 1) + .attr(HitHealAttr), + new StatusMove(Moves.LEECH_SEED, "Leech Seed", Type.GRASS, 90, 10, -1, "Drains HP from opponent each turn.", -1, 0, 1) + .attr(AddBattlerTagAttr, BattlerTagType.SEEDED) + .condition((user: Pokemon, target: Pokemon, move: Move) => !target.getTag(BattlerTagType.SEEDED) && !target.isOfType(Type.GRASS)), + new SelfStatusMove(Moves.GROWTH, "Growth", Type.NORMAL, -1, 20, -1, "Raises user's Attack and Special Attack.", -1, 0, 1) + .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), + 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), + new StatusMove(Moves.POISON_POWDER, "Poison Powder", Type.POISON, 75, 35, -1, "Poisons opponent.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.POISON), + new StatusMove(Moves.STUN_SPORE, "Stun Spore", Type.GRASS, 75, 30, -1, "Paralyzes opponent.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + new StatusMove(Moves.SLEEP_POWDER, "Sleep Powder", Type.GRASS, 75, 15, -1, "Puts opponent to sleep.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.SLEEP), + new AttackMove(Moves.PETAL_DANCE, "Petal Dance", Type.GRASS, MoveCategory.SPECIAL, 120, 100, 10, -1, "User attacks for 2-3 turns but then becomes confused.", -1, 0, 1) + .attr(FrenzyAttr) + .attr(MissEffectAttr, frenzyMissFunc) + .attr(ConfuseAttr, true), // TODO: Update to still confuse if last hit misses + 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), + 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) + .attr(TrapAttr, BattlerTagType.FIRE_SPIN), + new AttackMove(Moves.THUNDER_SHOCK, "Thunder Shock", Type.ELECTRIC, MoveCategory.SPECIAL, 40, 100, 30, -1, "May paralyze opponent.", 10, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + new AttackMove(Moves.THUNDERBOLT, "Thunderbolt", Type.ELECTRIC, MoveCategory.SPECIAL, 90, 100, 15, 126, "May paralyze opponent.", 10, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + new StatusMove(Moves.THUNDER_WAVE, "Thunder Wave", Type.ELECTRIC, 90, 20, 82, "Paralyzes opponent.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS) + .attr(ThunderAccuracyAttr), + new AttackMove(Moves.THUNDER, "Thunder", Type.ELECTRIC, MoveCategory.SPECIAL, 110, 70, 10, 166, "May paralyze opponent.", 30, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), new AttackMove(Moves.ROCK_THROW, "Rock Throw", Type.ROCK, MoveCategory.PHYSICAL, 50, 90, 15, -1, "", -1, 0, 1), - 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, - new HitsTagAttr(BattlerTagType.UNDERGROUND, true)), - new AttackMove(Moves.FISSURE, "Fissure", Type.GROUND, MoveCategory.PHYSICAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 1, new OneHitKOAttr()), - new AttackMove(Moves.DIG, "Dig", Type.GROUND, MoveCategory.PHYSICAL, 80, 100, 10, 55, "Digs underground on first turn, attacks on second. Can also escape from caves.", -1, 0, 1, - new ChargeAttr(ChargeAnim.DIG_CHARGING, 'dug a hole!', BattlerTagType.UNDERGROUND)), - new StatusMove(Moves.TOXIC, "Toxic", Type.POISON, 90, 10, -1, "Badly poisons opponent.", -1, 0, 1, new StatusEffectAttr(StatusEffect.TOXIC)), - new AttackMove(Moves.CONFUSION, "Confusion", Type.PSYCHIC, MoveCategory.SPECIAL, 50, 100, 25, -1, "May confuse opponent.", 10, 0, 1, new ConfuseAttr()), - new AttackMove(Moves.PSYCHIC, "Psychic", Type.PSYCHIC, MoveCategory.SPECIAL, 90, 100, 10, 120, "May lower opponent's Special Defense.", 10, 0, 1, new StatChangeAttr(BattleStat.SPDEF, -1)), - new StatusMove(Moves.HYPNOSIS, "Hypnosis", Type.PSYCHIC, 60, 20, -1, "Puts opponent to sleep.", -1, 0, 1, new StatusEffectAttr(StatusEffect.SLEEP)), - new SelfStatusMove(Moves.MEDITATE, "Meditate", Type.PSYCHIC, -1, 40, -1, "Raises user's Attack.", -1, 0, 1, new StatChangeAttr(BattleStat.ATK, 1, true)), - new SelfStatusMove(Moves.AGILITY, "Agility", Type.PSYCHIC, -1, 30, 4, "Sharply raises user's Speed.", -1, 0, 1, new StatChangeAttr(BattleStat.SPD, 2, true)), + 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), + new AttackMove(Moves.FISSURE, "Fissure", Type.GROUND, MoveCategory.PHYSICAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 1) + .attr(OneHitKOAttr), + new AttackMove(Moves.DIG, "Dig", Type.GROUND, MoveCategory.PHYSICAL, 80, 100, 10, 55, "Digs underground on first turn, attacks on second. Can also escape from caves.", -1, 0, 1) + .attr(ChargeAttr, ChargeAnim.DIG_CHARGING, 'dug a hole!', BattlerTagType.UNDERGROUND), + new StatusMove(Moves.TOXIC, "Toxic", Type.POISON, 90, 10, -1, "Badly poisons opponent.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.TOXIC), + new AttackMove(Moves.CONFUSION, "Confusion", Type.PSYCHIC, MoveCategory.SPECIAL, 50, 100, 25, -1, "May confuse opponent.", 10, 0, 1) + .attr(ConfuseAttr), + new AttackMove(Moves.PSYCHIC, "Psychic", Type.PSYCHIC, MoveCategory.SPECIAL, 90, 100, 10, 120, "May lower opponent's Special Defense.", 10, 0, 1) + .attr(StatChangeAttr, BattleStat.SPDEF, -1), + new StatusMove(Moves.HYPNOSIS, "Hypnosis", Type.PSYCHIC, 60, 20, -1, "Puts opponent to sleep.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.SLEEP), + new SelfStatusMove(Moves.MEDITATE, "Meditate", Type.PSYCHIC, -1, 40, -1, "Raises user's Attack.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.ATK, 1, true), + new SelfStatusMove(Moves.AGILITY, "Agility", Type.PSYCHIC, -1, 30, 4, "Sharply raises user's Speed.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.SPD, 2, true), new AttackMove(Moves.QUICK_ATTACK, "Quick Attack", Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 30, -1, "User attacks first.", -1, 1, 1), new AttackMove(Moves.RAGE, "Rage (N)", Type.NORMAL, MoveCategory.PHYSICAL, 20, 100, 20, -1, "Raises user's Attack when hit.", -1, 0, 1), // TODO new SelfStatusMove(Moves.TELEPORT, "Teleport (N)", Type.PSYCHIC, -1, 20, -1, "Allows user to flee wild battles.", -1, 0, 1), - new AttackMove(Moves.NIGHT_SHADE, "Night Shade", Type.GHOST, MoveCategory.SPECIAL, -1, 100, 15, 42, "Inflicts damage equal to user's level (maximum 150).", -1, 0, 1, new LevelPowerAttr()), - new StatusMove(Moves.MIMIC, "Mimic", Type.NORMAL, -1, 10, -1, "Copies the opponent's last move.", -1, 0, 1, new ConditionalMoveAttr(targetMoveCopiableCondition), new CopyMoveAttr()), - new StatusMove(Moves.SCREECH, "Screech", Type.NORMAL, 85, 40, -1, "Sharply lowers opponent's Defense.", -1, 0, 1, new StatChangeAttr(BattleStat.DEF, -2)), - new SelfStatusMove(Moves.DOUBLE_TEAM, "Double Team", Type.NORMAL, -1, 15, -1, "Raises user's Evasiveness.", -1, 0, 1, new StatChangeAttr(BattleStat.EVA, 1, true)), - new SelfStatusMove(Moves.RECOVER, "Recover", Type.NORMAL, -1, 5, -1, "User recovers half its max HP.", -1, 0, 1, new HealAttr(0.5)), - new SelfStatusMove(Moves.HARDEN, "Harden", Type.NORMAL, -1, 30, -1, "Raises user's Defense.", -1, 0, 1, new StatChangeAttr(BattleStat.DEF, 1, true)), - new SelfStatusMove(Moves.MINIMIZE, "Minimize", Type.NORMAL, -1, 10, -1, "Sharply raises user's Evasiveness.", -1, 0, 1, new StatChangeAttr(BattleStat.EVA, 1, true)), - new StatusMove(Moves.SMOKESCREEN, "Smokescreen", Type.NORMAL, 100, 20, -1, "Lowers opponent's Accuracy.", -1, 0, 1, new StatChangeAttr(BattleStat.ACC, -1)), - new StatusMove(Moves.CONFUSE_RAY, "Confuse Ray", Type.GHOST, 100, 10, 17, "Confuses opponent.", -1, 0, 1, new ConfuseAttr()), - new SelfStatusMove(Moves.WITHDRAW, "Withdraw", Type.WATER, -1, 40, -1, "Raises user's Defense.", -1, 0, 1, new StatChangeAttr(BattleStat.DEF, 1, true)), - new SelfStatusMove(Moves.DEFENSE_CURL, "Defense Curl", Type.NORMAL, -1, 40, -1, "Raises user's Defense.", -1, 0, 1, new StatChangeAttr(BattleStat.DEF, 1, true)), - new SelfStatusMove(Moves.BARRIER, "Barrier", Type.PSYCHIC, -1, 20, -1, "Sharply raises user's Defense.", -1, 0, 1, new StatChangeAttr(BattleStat.DEF, 2, true)), + new AttackMove(Moves.NIGHT_SHADE, "Night Shade", Type.GHOST, MoveCategory.SPECIAL, -1, 100, 15, 42, "Inflicts damage equal to user's level (maximum 150).", -1, 0, 1) + .attr(LevelPowerAttr), + new StatusMove(Moves.MIMIC, "Mimic", Type.NORMAL, -1, 10, -1, "Copies the opponent's last move.", -1, 0, 1) + .attr(CopyMoveAttr), + new StatusMove(Moves.SCREECH, "Screech", Type.NORMAL, 85, 40, -1, "Sharply lowers opponent's Defense.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.DEF, -2), + new SelfStatusMove(Moves.DOUBLE_TEAM, "Double Team", Type.NORMAL, -1, 15, -1, "Raises user's Evasiveness.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.EVA, 1, true), + new SelfStatusMove(Moves.RECOVER, "Recover", Type.NORMAL, -1, 5, -1, "User recovers half its max HP.", -1, 0, 1) + .attr(HealAttr, 0.5), + new SelfStatusMove(Moves.HARDEN, "Harden", Type.NORMAL, -1, 30, -1, "Raises user's Defense.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.DEF, 1, true), + new SelfStatusMove(Moves.MINIMIZE, "Minimize", Type.NORMAL, -1, 10, -1, "Sharply raises user's Evasiveness.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.EVA, 1, true), + new StatusMove(Moves.SMOKESCREEN, "Smokescreen", Type.NORMAL, 100, 20, -1, "Lowers opponent's Accuracy.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.ACC, -1), + new StatusMove(Moves.CONFUSE_RAY, "Confuse Ray", Type.GHOST, 100, 10, 17, "Confuses opponent.", -1, 0, 1) + .attr(ConfuseAttr), + new SelfStatusMove(Moves.WITHDRAW, "Withdraw", Type.WATER, -1, 40, -1, "Raises user's Defense.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.DEF, 1, true), + new SelfStatusMove(Moves.DEFENSE_CURL, "Defense Curl", Type.NORMAL, -1, 40, -1, "Raises user's Defense.", -1, 0, 1) + .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.FOCUS_ENERGY, "Focus Energy (N)", Type.NORMAL, -1, 30, -1, "Increases critical hit ratio.", -1, 0, 1), 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), - new SelfStatusMove(Moves.METRONOME, "Metronome", Type.NORMAL, -1, 10, 80, "User performs almost any move in the game at random.", -1, 0, 1, new RandomMoveAttr()), + 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), new SelfStatusMove(Moves.MIRROR_MOVE, "Mirror Move (N)", Type.FLYING, -1, 20, -1, "User performs the opponent's last move.", -1, 0, 1), - new AttackMove(Moves.SELF_DESTRUCT, "Self-Destruct", Type.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, "User faints.", -1, 0, 1, new SacrificialAttr()), + new AttackMove(Moves.SELF_DESTRUCT, "Self-Destruct", Type.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, "User faints.", -1, 0, 1) + .attr(SacrificialAttr), new AttackMove(Moves.EGG_BOMB, "Egg Bomb", Type.NORMAL, MoveCategory.PHYSICAL, 100, 75, 10, -1, "", -1, 0, 1), - new AttackMove(Moves.LICK, "Lick", Type.GHOST, MoveCategory.PHYSICAL, 30, 100, 30, -1, "May paralyze opponent.", 30, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.SMOG, "Smog", Type.POISON, MoveCategory.SPECIAL, 30, 70, 20, -1, "May poison opponent.", 40, 0, 1, new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.SLUDGE, "Sludge", Type.POISON, MoveCategory.SPECIAL, 65, 100, 20, -1, "May poison opponent.", 30, 0, 1, new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.BONE_CLUB, "Bone Club", Type.GROUND, MoveCategory.PHYSICAL, 65, 85, 20, -1, "May cause flinching.", 10, 0, 1, new FlinchAttr()), - new AttackMove(Moves.FIRE_BLAST, "Fire Blast", Type.FIRE, MoveCategory.SPECIAL, 110, 85, 5, 141, "May burn opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.BURN)), - new AttackMove(Moves.WATERFALL, "Waterfall", Type.WATER, MoveCategory.PHYSICAL, 80, 100, 15, 77, "May cause flinching.", 20, 0, 1, new 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, new TrapAttr(BattlerTagType.CLAMP)), + new AttackMove(Moves.LICK, "Lick", Type.GHOST, MoveCategory.PHYSICAL, 30, 100, 30, -1, "May paralyze opponent.", 30, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + new AttackMove(Moves.SMOG, "Smog", Type.POISON, MoveCategory.SPECIAL, 30, 70, 20, -1, "May poison opponent.", 40, 0, 1) + .attr(StatusEffectAttr, StatusEffect.POISON), + new AttackMove(Moves.SLUDGE, "Sludge", Type.POISON, MoveCategory.SPECIAL, 65, 100, 20, -1, "May poison opponent.", 30, 0, 1) + .attr(StatusEffectAttr, StatusEffect.POISON), + new AttackMove(Moves.BONE_CLUB, "Bone Club", Type.GROUND, MoveCategory.PHYSICAL, 65, 85, 20, -1, "May cause flinching.", 10, 0, 1) + .attr(FlinchAttr), + new AttackMove(Moves.FIRE_BLAST, "Fire Blast", Type.FIRE, MoveCategory.SPECIAL, 110, 85, 5, 141, "May burn opponent.", 10, 0, 1) + .attr(StatusEffectAttr, StatusEffect.BURN), + new AttackMove(Moves.WATERFALL, "Waterfall", Type.WATER, MoveCategory.PHYSICAL, 80, 100, 15, 77, "May cause flinching.", 20, 0, 1) + .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.SKULL_BASH, "Skull Bash", Type.NORMAL, MoveCategory.PHYSICAL, 130, 100, 10, -1, "Raises Defense on first turn, attacks on second.", 100, 0, 1, - new ChargeAttr(ChargeAnim.SKULL_BASH_CHARGING, 'lowered\nits head!', null, true), new StatChangeAttr(BattleStat.DEF, 1, true)), - 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, new MultiHitAttr()), - new AttackMove(Moves.CONSTRICT, "Constrict", Type.NORMAL, MoveCategory.PHYSICAL, 10, 100, 35, -1, "May lower opponent's Speed by one stage.", 10, 0, 1, new StatChangeAttr(BattleStat.SPD, -1)), - new SelfStatusMove(Moves.AMNESIA, "Amnesia", Type.PSYCHIC, -1, 20, 128, "Sharply raises user's Special Defense.", -1, 0, 1, new StatChangeAttr(BattleStat.SPDEF, 2, true)), - new StatusMove(Moves.KINESIS, "Kinesis", Type.PSYCHIC, 80, 15, -1, "Lowers opponent's Accuracy.", -1, 0, 1, new StatChangeAttr(BattleStat.ACC, -1)), - new SelfStatusMove(Moves.SOFT_BOILED, "Soft-Boiled", Type.NORMAL, -1, 5, -1, "User recovers half its max HP.", -1, 0, 1, new HealAttr(0.5)), - new AttackMove(Moves.HIGH_JUMP_KICK, "High Jump Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 130, 90, 10, -1, "If it misses, the user loses half their HP.", -1, 0, 1, - new MissEffectAttr((user: Pokemon, target: Pokemon, move: Move) => { user.damage(Math.floor(user.getMaxHp() / 2)); return true; })), - new StatusMove(Moves.GLARE, "Glare", Type.NORMAL, 100, 30, -1, "Paralyzes opponent.", -1, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.DREAM_EATER, "Dream Eater", Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 15, -1, "User recovers half the HP inflicted on a sleeping opponent.", -1, 0, 1, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP), new HitHealAttr()), - new StatusMove(Moves.POISON_GAS, "Poison Gas", Type.POISON, 90, 40, -1, "Poisons opponent.", -1, 0, 1, new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.BARRAGE, "Barrage", Type.NORMAL, MoveCategory.PHYSICAL, 15, 85, 20, -1, "Hits 2-5 times in one turn.", -1, 0, 1, new MultiHitAttr()), - new AttackMove(Moves.LEECH_LIFE, "Leech Life", Type.BUG, MoveCategory.PHYSICAL, 80, 100, 10, 95, "User recovers half the HP inflicted on opponent.", -1, 0, 1, new HitHealAttr()), - new StatusMove(Moves.LOVELY_KISS, "Lovely Kiss", Type.NORMAL, 75, 10, -1, "Puts opponent to sleep.", -1, 0, 1, new StatusEffectAttr(StatusEffect.SLEEP)), - new AttackMove(Moves.SKY_ATTACK, "Sky Attack", Type.FLYING, MoveCategory.PHYSICAL, 140, 90, 5, -1, "Charges on first turn, attacks on second. May cause flinching. High critical hit ratio.", 30, 0, 1, - new ChargeAttr(ChargeAnim.SKY_ATTACK_CHARGING, 'is glowing!'), new HighCritAttr(), new FlinchAttr()), + 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(StatChangeAttr, BattleStat.DEF, 1, true), + 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) + .attr(MultiHitAttr), + new AttackMove(Moves.CONSTRICT, "Constrict", Type.NORMAL, MoveCategory.PHYSICAL, 10, 100, 35, -1, "May lower opponent's Speed by one stage.", 10, 0, 1) + .attr(StatChangeAttr, BattleStat.SPD, -1), + new SelfStatusMove(Moves.AMNESIA, "Amnesia", Type.PSYCHIC, -1, 20, 128, "Sharply raises user's Special Defense.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.SPDEF, 2, true), + new StatusMove(Moves.KINESIS, "Kinesis", Type.PSYCHIC, 80, 15, -1, "Lowers opponent's Accuracy.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.ACC, -1), + new SelfStatusMove(Moves.SOFT_BOILED, "Soft-Boiled", Type.NORMAL, -1, 5, -1, "User recovers half its max HP.", -1, 0, 1) + .attr(HealAttr, 0.5), + new AttackMove(Moves.HIGH_JUMP_KICK, "High Jump Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 130, 90, 10, -1, "If it misses, the user loses half their HP.", -1, 0, 1) + .attr(MissEffectAttr, (user: Pokemon, target: Pokemon, move: Move) => { user.damage(Math.floor(user.getMaxHp() / 2)); return true; }), + new StatusMove(Moves.GLARE, "Glare", Type.NORMAL, 100, 30, -1, "Paralyzes opponent.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + new AttackMove(Moves.DREAM_EATER, "Dream Eater", Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 15, -1, "User recovers half the HP inflicted on a sleeping opponent.", -1, 0, 1) + .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), + 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), + new AttackMove(Moves.LEECH_LIFE, "Leech Life", Type.BUG, MoveCategory.PHYSICAL, 80, 100, 10, 95, "User recovers half the HP inflicted on opponent.", -1, 0, 1) + .attr(HitHealAttr), + new StatusMove(Moves.LOVELY_KISS, "Lovely Kiss", Type.NORMAL, 75, 10, -1, "Puts opponent to sleep.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.SLEEP), + new AttackMove(Moves.SKY_ATTACK, "Sky Attack", Type.FLYING, MoveCategory.PHYSICAL, 140, 90, 5, -1, "Charges on first turn, attacks on second. May cause flinching. High critical hit ratio.", 30, 0, 1) + .attr(ChargeAttr, ChargeAnim.SKY_ATTACK_CHARGING, 'is glowing!') + .attr(HighCritAttr) + .attr(FlinchAttr), 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, new StatChangeAttr(BattleStat.SPD, -1)), - new AttackMove(Moves.DIZZY_PUNCH, "Dizzy Punch", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, -1, "May confuse opponent.", 20, 0, 1, new ConfuseAttr()), - new StatusMove(Moves.SPORE, "Spore", Type.GRASS, 100, 15, -1, "Puts opponent to sleep.", -1, 0, 1, new StatusEffectAttr(StatusEffect.SLEEP)), - new StatusMove(Moves.FLASH, "Flash", Type.NORMAL, 100, 20, -1, "Lowers opponent's Accuracy.", -1, 0, 1, new StatChangeAttr(BattleStat.ACC, -1)), - new AttackMove(Moves.PSYWAVE, "Psywave", Type.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 15, -1, "Inflicts damage 50-150% of user's level (maximum 150).", -1, 0, 1, new RandomLevelPowerAttr()), + 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), + 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) + .attr(StatusEffectAttr, StatusEffect.SLEEP), + new StatusMove(Moves.FLASH, "Flash", Type.NORMAL, 100, 20, -1, "Lowers opponent's Accuracy.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.ACC, -1), + new AttackMove(Moves.PSYWAVE, "Psywave", Type.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 15, -1, "Inflicts damage 50-150% of user's level (maximum 150).", -1, 0, 1) + .attr(RandomLevelPowerAttr), new SelfStatusMove(Moves.SPLASH, "Splash", Type.NORMAL, -1, 40, -1, "Doesn't do ANYTHING.", -1, 0, 1), - new SelfStatusMove(Moves.ACID_ARMOR, "Acid Armor", Type.POISON, -1, 20, -1, "Sharply raises user's Defense.", -1, 0, 1, new StatChangeAttr(BattleStat.DEF, 2, true)), - new AttackMove(Moves.CRABHAMMER, "Crabhammer", Type.WATER, MoveCategory.PHYSICAL, 100, 90, 10, -1, "High critical hit ratio.", -1, 0, 1, new HighCritAttr()), - new AttackMove(Moves.EXPLOSION, "Explosion", Type.NORMAL, MoveCategory.PHYSICAL, 250, 100, 5, -1, "User faints.", -1, 0, 1, new SacrificialAttr()), - 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, new MultiHitAttr()), - new AttackMove(Moves.BONEMERANG, "Bonemerang", Type.GROUND, MoveCategory.PHYSICAL, 50, 90, 10, -1, "Hits twice in one turn.", -1, 0, 1, new MultiHitAttr(MultiHitType._2)), - new SelfStatusMove(Moves.REST, "Rest", Type.PSYCHIC, -1, 5, 85, "User sleeps for 2 turns, but user is fully healed.", -1, 0, 1, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => user.status?.effect !== StatusEffect.SLEEP), new StatusEffectAttr(StatusEffect.SLEEP, true, 3), new HealAttr(1, true)), - new AttackMove(Moves.ROCK_SLIDE, "Rock Slide", Type.ROCK, MoveCategory.PHYSICAL, 75, 90, 10, 86, "May cause flinching.", 30, 0, 1, new FlinchAttr()), - new AttackMove(Moves.HYPER_FANG, "Hyper Fang", Type.NORMAL, MoveCategory.PHYSICAL, 80, 90, 15, -1, "May cause flinching.", 10, 0, 1, new FlinchAttr()), - new SelfStatusMove(Moves.SHARPEN, "Sharpen", Type.NORMAL, -1, 30, -1, "Raises user's Attack.", -1, 0, 1, new StatChangeAttr(BattleStat.ATK, 1, true)), + new SelfStatusMove(Moves.ACID_ARMOR, "Acid Armor", Type.POISON, -1, 20, -1, "Sharply raises user's Defense.", -1, 0, 1) + .attr(StatChangeAttr, BattleStat.DEF, 2, true), + new AttackMove(Moves.CRABHAMMER, "Crabhammer", Type.WATER, MoveCategory.PHYSICAL, 100, 90, 10, -1, "High critical hit ratio.", -1, 0, 1) + .attr(HighCritAttr), + new AttackMove(Moves.EXPLOSION, "Explosion", Type.NORMAL, MoveCategory.PHYSICAL, 250, 100, 5, -1, "User faints.", -1, 0, 1) + .attr(SacrificialAttr), + 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) + .attr(MultiHitAttr, MultiHitType._2), + new SelfStatusMove(Moves.REST, "Rest", Type.PSYCHIC, -1, 5, 85, "User sleeps for 2 turns, but user is fully healed.", -1, 0, 1) + .attr(StatusEffectAttr, StatusEffect.SLEEP, true, 3) + .attr(HealAttr, 1, true) + .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), + 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) + .attr(StatChangeAttr, BattleStat.ATK, 1, true), new SelfStatusMove(Moves.CONVERSION, "Conversion (N)", Type.NORMAL, -1, 30, -1, "Changes user's type to that of its first move.", -1, 0, 1), - new AttackMove(Moves.TRI_ATTACK, "Tri Attack", Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, "May paralyze, burn or freeze opponent.", 20, 0, 1, new StatusEffectAttr(StatusEffect.PARALYSIS), new StatusEffectAttr(StatusEffect.BURN), new StatusEffectAttr(StatusEffect.FREEZE)), // TODO: Check if independent - new AttackMove(Moves.SUPER_FANG, "Super Fang", Type.NORMAL, MoveCategory.PHYSICAL, -1, 90, 10, -1, "Always takes off half of the opponent's HP.", -1, 0, 1, new TargetHalfHpDamageAttr()), - new AttackMove(Moves.SLASH, "Slash", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, -1, "High critical hit ratio.", -1, 0, 1, new HighCritAttr()), + new AttackMove(Moves.TRI_ATTACK, "Tri Attack", Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, -1, "May paralyze, burn or freeze opponent.", 20, 0, 1) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS) + .attr(StatusEffectAttr, StatusEffect.BURN) + .attr(StatusEffectAttr, StatusEffect.FREEZE), // TODO: Check if independent + new AttackMove(Moves.SUPER_FANG, "Super Fang", Type.NORMAL, MoveCategory.PHYSICAL, -1, 90, 10, -1, "Always takes off half of the opponent's HP.", -1, 0, 1) + .attr(TargetHalfHpDamageAttr), + new AttackMove(Moves.SLASH, "Slash", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, -1, "High critical hit ratio.", -1, 0, 1) + .attr(HighCritAttr), new SelfStatusMove(Moves.SUBSTITUTE, "Substitute (N)", Type.NORMAL, -1, 10, 103, "Uses HP to creates a decoy that takes hits.", -1, 0, 1), 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), - new SelfStatusMove(Moves.SKETCH, "Sketch", Type.NORMAL, -1, 1, -1, "Permanently copies the opponent's last move.", -1, 0, 2, - new ConditionalMoveAttr(targetMoveSketchableCondition), new SketchAttr()), - new AttackMove(Moves.TRIPLE_KICK, "Triple Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 10, 90, 10, -1, "Hits thrice in one turn at increasing power.", -1, 0, 2, - new MultiHitAttr(MultiHitType._3_INCR), new MissEffectAttr((user: Pokemon, target: Pokemon, move: Move) => { + new SelfStatusMove(Moves.SKETCH, "Sketch", Type.NORMAL, -1, 1, -1, "Permanently copies the opponent's last move.", -1, 0, 2) + .attr(SketchAttr), + new AttackMove(Moves.TRIPLE_KICK, "Triple Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 10, 90, 10, -1, "Hits thrice in one turn at increasing power.", -1, 0, 2) + .attr(MultiHitAttr, MultiHitType._3_INCR) + .attr(MissEffectAttr, (user: Pokemon, target: Pokemon, move: Move) => { user.turnData.hitsLeft = 0; return true; - })), + }), new AttackMove(Moves.THIEF, "Thief (N)", Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, 18, "Also steals opponent's held item.", -1, 0, 2), new StatusMove(Moves.SPIDER_WEB, "Spider Web (N)", Type.BUG, -1, 10, -1, "Opponent cannot escape/switch.", -1, 0, 2), new SelfStatusMove(Moves.MIND_READER, "Mind Reader (N)", Type.NORMAL, -1, 5, -1, "User's next attack is guaranteed to hit.", -1, 0, 2), - new StatusMove(Moves.NIGHTMARE, "Nightmare", Type.GHOST, 100, 15, -1, "The sleeping opponent loses 25% of its max HP each turn.", -1, 0, 2, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP), new AddBattlerTagAttr(BattlerTagType.NIGHTMARE)), - new AttackMove(Moves.FLAME_WHEEL, "Flame Wheel", Type.FIRE, MoveCategory.PHYSICAL, 60, 100, 25, -1, "May burn opponent.", 10, 0, 2, new StatusEffectAttr(StatusEffect.BURN)), - new AttackMove(Moves.SNORE, "Snore", Type.NORMAL, MoveCategory.SPECIAL, 50, 100, 15, -1, "Can only be used if asleep. May cause flinching.", 30, 0, 2, - new BypassSleepAttr(), new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => user.status?.effect === StatusEffect.SLEEP), new FlinchAttr()), + new StatusMove(Moves.NIGHTMARE, "Nightmare", Type.GHOST, 100, 15, -1, "The sleeping opponent loses 25% of its max HP each turn.", -1, 0, 2) + .attr(AddBattlerTagAttr, BattlerTagType.NIGHTMARE) + .condition((user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP), + new AttackMove(Moves.FLAME_WHEEL, "Flame Wheel", Type.FIRE, MoveCategory.PHYSICAL, 60, 100, 25, -1, "May burn opponent.", 10, 0, 2) + .attr(StatusEffectAttr, StatusEffect.BURN), + new AttackMove(Moves.SNORE, "Snore", Type.NORMAL, MoveCategory.SPECIAL, 50, 100, 15, -1, "Can only be used if asleep. May cause flinching.", 30, 0, 2) + .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 AttackMove(Moves.FLAIL, "Flail (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, "The lower the user's HP, the higher the power.", -1, 0, 2), 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, new HighCritAttr()), - new StatusMove(Moves.COTTON_SPORE, "Cotton Spore", Type.GRASS, 100, 40, -1, "Sharply lowers opponent's Speed.", -1, 0, 2, new StatChangeAttr(BattleStat.SPD, -2)), - 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, new LowHpPowerAttr()), + new AttackMove(Moves.AEROBLAST, "Aeroblast", Type.FLYING, MoveCategory.SPECIAL, 100, 95, 5, -1, "High critical hit ratio.", -1, 0, 2) + .attr(HighCritAttr), + 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), + 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, new StatusEffectAttr(StatusEffect.FREEZE)), - new SelfStatusMove(Moves.PROTECT, "Protect", Type.NORMAL, -1, 10, 7, "Protects the user, but may fail if used consecutively.", -1, 4, 2, - new WaningConsecutiveUseConditionalMoveAttr(), new AddBattlerTagAttr(BattlerTagType.PROTECTED, true)), + 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), + 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), - new StatusMove(Moves.SCARY_FACE, "Scary Face", Type.NORMAL, 100, 10, 6, "Sharply lowers opponent's Speed.", -1, 0, 2, new StatChangeAttr(BattleStat.SPD, -2)), + new StatusMove(Moves.SCARY_FACE, "Scary Face", Type.NORMAL, 100, 10, 6, "Sharply lowers opponent's Speed.", -1, 0, 2) + .attr(StatChangeAttr, BattleStat.SPD, -2), new AttackMove(Moves.FEINT_ATTACK, "Feint Attack", Type.DARK, MoveCategory.PHYSICAL, 60, -1, 20, -1, "Ignores Accuracy and Evasiveness.", -1, 0, 2), - new StatusMove(Moves.SWEET_KISS, "Sweet Kiss", Type.FAIRY, 75, 10, -1, "Confuses opponent.", -1, 0, 2, new ConfuseAttr()), + new StatusMove(Moves.SWEET_KISS, "Sweet Kiss", Type.FAIRY, 75, 10, -1, "Confuses opponent.", -1, 0, 2) + .attr(ConfuseAttr), new SelfStatusMove(Moves.BELLY_DRUM, "Belly Drum (N)", Type.NORMAL, -1, 10, -1, "User loses 50% of its max HP, but Attack raises to maximum.", -1, 0, 2), - new AttackMove(Moves.SLUDGE_BOMB, "Sludge Bomb", Type.POISON, MoveCategory.SPECIAL, 90, 100, 10, 148, "May poison opponent.", 30, 0, 2, new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.MUD_SLAP, "Mud-Slap", Type.GROUND, MoveCategory.SPECIAL, 20, 100, 10, 5, "Lowers opponent's Accuracy.", 100, 0, 2, new StatChangeAttr(BattleStat.ACC, -1)), - new AttackMove(Moves.OCTAZOOKA, "Octazooka", Type.WATER, MoveCategory.SPECIAL, 65, 85, 10, -1, "May lower opponent's Accuracy.", 50, 0, 2, new StatChangeAttr(BattleStat.ACC, -1)), - new StatusMove(Moves.SPIKES, "Spikes (N)", Type.GROUND, -1, 20, 90, "Hurts opponents when they switch into battle.", -1, 0, 2), - new AttackMove(Moves.ZAP_CANNON, "Zap Cannon", Type.ELECTRIC, MoveCategory.SPECIAL, 120, 50, 5, -1, "Paralyzes opponent.", 100, 0, 2, new StatusEffectAttr(StatusEffect.PARALYSIS)), + new AttackMove(Moves.SLUDGE_BOMB, "Sludge Bomb", Type.POISON, MoveCategory.SPECIAL, 90, 100, 10, 148, "May poison opponent.", 30, 0, 2) + .attr(StatusEffectAttr, StatusEffect.POISON), + new AttackMove(Moves.MUD_SLAP, "Mud-Slap", Type.GROUND, MoveCategory.SPECIAL, 20, 100, 10, 5, "Lowers opponent's Accuracy.", 100, 0, 2) + .attr(StatChangeAttr, BattleStat.ACC, -1), + 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), + 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).ignoreProtect(), - 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).ignoreProtect(), - new AttackMove(Moves.ICY_WIND, "Icy Wind", Type.ICE, MoveCategory.SPECIAL, 55, 95, 15, 34, "Lowers opponent's Speed.", 100, 0, 2, new StatChangeAttr(BattleStat.SPD, -1)), - new SelfStatusMove(Moves.DETECT, "Detect", Type.FIGHTING, -1, 5, -1, "Protects the user, but may fail if used consecutively.", -1, 4, 2, - new WaningConsecutiveUseConditionalMoveAttr(), new AddBattlerTagAttr(BattlerTagType.PROTECTED, true)), - 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, new MultiHitAttr()), + new StatusMove(Moves.DESTINY_BOND, "Destiny Bond (N)", Type.GHOST, -1, 5, -1, "If the user faints, the opponent also faints.", -1, 0, 2) + .ignoreProtect(), + 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) + .ignoreProtect(), + 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), + 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) + .attr(MultiHitAttr), new SelfStatusMove(Moves.LOCK_ON, "Lock-On (N)", Type.NORMAL, -1, 5, -1, "User's next attack is guaranteed to hit.", -1, 0, 2), - new AttackMove(Moves.OUTRAGE, "Outrage", Type.DRAGON, MoveCategory.PHYSICAL, 120, 100, 10, 156, "User attacks for 2-3 turns but then becomes confused.", -1, 0, 2, - new FrenzyAttr(), frenzyMissFunc, new 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, new WeatherConditionalMoveAttr(WeatherType.SANDSTORM), new WeatherChangeAttr(WeatherType.SANDSTORM)), - 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, new HitHealAttr()), + new AttackMove(Moves.OUTRAGE, "Outrage", Type.DRAGON, MoveCategory.PHYSICAL, 120, 100, 10, 156, "User attacks for 2-3 turns but then becomes confused.", -1, 0, 2) + .attr(FrenzyAttr) + .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), + 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), - new StatusMove(Moves.CHARM, "Charm", Type.FAIRY, 100, 20, 2, "Sharply lowers opponent's Attack.", -1, 0, 2, new StatChangeAttr(BattleStat.ATK, -2)), - new AttackMove(Moves.ROLLOUT, "Rollout", Type.ROCK, MoveCategory.PHYSICAL, 30, 90, 20, -1, "Doubles in power each turn for 5 turns.", -1, 0, 2, new ConsecutiveUseDoublePowerAttr(5, true, true)), // TODO: Defense Curl logic + new StatusMove(Moves.CHARM, "Charm", Type.FAIRY, 100, 20, 2, "Sharply lowers opponent's Attack.", -1, 0, 2) + .attr(StatChangeAttr, BattleStat.ATK, -2), + new AttackMove(Moves.ROLLOUT, "Rollout", Type.ROCK, MoveCategory.PHYSICAL, 30, 90, 20, -1, "Doubles in power each turn for 5 turns.", -1, 0, 2) + .attr(ConsecutiveUseDoublePowerAttr, 5, true, true), // TODO: Defense Curl logic new AttackMove(Moves.FALSE_SWIPE, "False Swipe (N)", Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 40, 57, "Always leaves opponent with at least 1 HP.", -1, 0, 2), - new StatusMove(Moves.SWAGGER, "Swagger", Type.NORMAL, 85, 15, -1, "Confuses opponent, but sharply raises its Attack.", -1, 0, 2, new StatChangeAttr(BattleStat.ATK, 2), new ConfuseAttr()), - new SelfStatusMove(Moves.MILK_DRINK, "Milk Drink", Type.NORMAL, -1, 5, -1, "User recovers half its max HP.", -1, 0, 2, new HealAttr(0.5)), - new AttackMove(Moves.SPARK, "Spark", Type.ELECTRIC, MoveCategory.PHYSICAL, 65, 100, 20, -1, "May paralyze opponent.", 30, 0, 2, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.FURY_CUTTER, "Fury Cutter", Type.BUG, MoveCategory.PHYSICAL, 40, 95, 20, -1, "Power increases each turn.", -1, 0, 2, new ConsecutiveUseDoublePowerAttr(3, true)), - new AttackMove(Moves.STEEL_WING, "Steel Wing", Type.STEEL, MoveCategory.PHYSICAL, 70, 90, 25, -1, "May raise user's Defense.", 10, 0, 2, new StatChangeAttr(BattleStat.DEF, 1, true)), - new StatusMove(Moves.MEAN_LOOK, "Mean Look", Type.NORMAL, -1, 5, -1, "Opponent cannot flee or switch.", -1, 0, 2, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => !target.getTag(BattlerTagType.TRAPPED)), new AddBattlerTagAttr(BattlerTagType.TRAPPED, false, 1)), + new StatusMove(Moves.SWAGGER, "Swagger", Type.NORMAL, 85, 15, -1, "Confuses opponent, but sharply raises its Attack.", -1, 0, 2) + .attr(StatChangeAttr, BattleStat.ATK, 2) + .attr(ConfuseAttr), + new SelfStatusMove(Moves.MILK_DRINK, "Milk Drink", Type.NORMAL, -1, 5, -1, "User recovers half its max HP.", -1, 0, 2) + .attr(HealAttr, 0.5), + new AttackMove(Moves.SPARK, "Spark", Type.ELECTRIC, MoveCategory.PHYSICAL, 65, 100, 20, -1, "May paralyze opponent.", 30, 0, 2) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + new AttackMove(Moves.FURY_CUTTER, "Fury Cutter", Type.BUG, MoveCategory.PHYSICAL, 40, 95, 20, -1, "Power increases each turn.", -1, 0, 2) + .attr(ConsecutiveUseDoublePowerAttr, 3, true), + new AttackMove(Moves.STEEL_WING, "Steel Wing", Type.STEEL, MoveCategory.PHYSICAL, 70, 90, 25, -1, "May raise user's Defense.", 10, 0, 2) + .attr(StatChangeAttr, BattleStat.DEF, 1, true), + new StatusMove(Moves.MEAN_LOOK, "Mean Look", Type.NORMAL, -1, 5, -1, "Opponent cannot flee or switch.", -1, 0, 2) + .attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, 1, true), new StatusMove(Moves.ATTRACT, "Attract (N)", Type.NORMAL, 100, 15, -1, "If opponent is the opposite gender, it's less likely to attack.", -1, 0, 2), - new SelfStatusMove(Moves.SLEEP_TALK, "Sleep Talk", Type.NORMAL, -1, 10, 70, "User performs one of its own moves while sleeping.", -1, 0, 2, - new BypassSleepAttr(), new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => user.status?.effect === StatusEffect.SLEEP), new RandomMovesetMoveAttr()), + new SelfStatusMove(Moves.SLEEP_TALK, "Sleep Talk", Type.NORMAL, -1, 10, 70, "User performs one of its own moves while sleeping.", -1, 0, 2) + .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 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), 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 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, new StatusEffectAttr(StatusEffect.BURN)), + 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), new AttackMove(Moves.MAGNITUDE, "Magnitude (N)", Type.GROUND, MoveCategory.PHYSICAL, -1, 100, 30, -1, "Hits with random power.", -1, 0, 2), - new AttackMove(Moves.DYNAMIC_PUNCH, "Dynamic Punch", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 50, 5, -1, "Confuses opponent.", 100, 0, 2, new ConfuseAttr()), + 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), - new AttackMove(Moves.DRAGON_BREATH, "Dragon Breath", Type.DRAGON, MoveCategory.SPECIAL, 60, 100, 20, -1, "May paralyze opponent.", 30, 0, 2, new StatusEffectAttr(StatusEffect.PARALYSIS)), + new AttackMove(Moves.DRAGON_BREATH, "Dragon Breath", Type.DRAGON, MoveCategory.SPECIAL, 60, 100, 20, -1, "May paralyze opponent.", 30, 0, 2) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), new SelfStatusMove(Moves.BATON_PASS, "Baton Pass (N)", Type.NORMAL, -1, 40, 132, "User switches out and gives stat changes to the incoming Pokémon.", -1, 0, 2), new StatusMove(Moves.ENCORE, "Encore (N)", Type.NORMAL, 100, 5, 122, "Forces opponent to keep using its last move for 3 turns.", -1, 0, 2), new AttackMove(Moves.PURSUIT, "Pursuit (N)", Type.DARK, MoveCategory.PHYSICAL, 40, 100, 20, -1, "Double power if the opponent is switching out.", -1, 0, 2), - new AttackMove(Moves.RAPID_SPIN, "Rapid Spin", Type.NORMAL, MoveCategory.PHYSICAL, 50, 100, 40, -1, "Raises user's Speed and removes entry hazards and trap move effects.", 100, 0, 2, - new StatChangeAttr(BattleStat.SPD, 1, true), new 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, new StatChangeAttr(BattleStat.EVA, -1)), - new AttackMove(Moves.IRON_TAIL, "Iron Tail", Type.STEEL, MoveCategory.PHYSICAL, 100, 75, 15, -1, "May lower opponent's Defense.", 30, 0, 2, new 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, new StatChangeAttr(BattleStat.ATK, 1, true)), + new AttackMove(Moves.RAPID_SPIN, "Rapid Spin", Type.NORMAL, MoveCategory.PHYSICAL, 50, 100, 40, -1, "Raises user's Speed and removes entry hazards and trap move effects.", 100, 0, 2) + .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), + 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) + .attr(StatChangeAttr, BattleStat.ATK, 1, true), new AttackMove(Moves.VITAL_THROW, "Vital Throw", Type.FIGHTING, MoveCategory.PHYSICAL, 70, -1, 10, -1, "User attacks last, but ignores Accuracy and Evasiveness.", -1, -1, 2), - new SelfStatusMove(Moves.MORNING_SUN, "Morning Sun", Type.NORMAL, -1, 5, -1, "User recovers HP. Amount varies with the weather.", -1, 0, 2, new WeatherHealAttr()), - new SelfStatusMove(Moves.SYNTHESIS, "Synthesis", Type.GRASS, -1, 5, -1, "User recovers HP. Amount varies with the weather.", -1, 0, 2, new WeatherHealAttr()), - new SelfStatusMove(Moves.MOONLIGHT, "Moonlight", Type.FAIRY, -1, 5, -1, "User recovers HP. Amount varies with the weather.", -1, 0, 2, new WeatherHealAttr()), + new SelfStatusMove(Moves.MORNING_SUN, "Morning Sun", Type.NORMAL, -1, 5, -1, "User recovers HP. Amount varies with the weather.", -1, 0, 2) + .attr(WeatherHealAttr), + new SelfStatusMove(Moves.SYNTHESIS, "Synthesis", Type.GRASS, -1, 5, -1, "User recovers HP. Amount varies with the weather.", -1, 0, 2) + .attr(WeatherHealAttr), + new SelfStatusMove(Moves.MOONLIGHT, "Moonlight", Type.FAIRY, -1, 5, -1, "User recovers HP. Amount varies with the weather.", -1, 0, 2) + .attr(WeatherHealAttr), new AttackMove(Moves.HIDDEN_POWER, "Hidden Power (N)", Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, -1, "Type and power depends on user's IVs.", -1, 0, 2), - new AttackMove(Moves.CROSS_CHOP, "Cross Chop", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 80, 5, -1, "High critical hit ratio.", -1, 0, 2, new HighCritAttr()), - new AttackMove(Moves.TWISTER, "Twister (P)", Type.DRAGON, MoveCategory.SPECIAL, 40, 100, 20, -1, "May cause flinching. Hits Pokémon using Fly/Bounce with double power.", 20, 0, 2, - new HitsTagAttr(BattlerTagType.FLYING, true), new FlinchAttr()), // TODO - new SelfStatusMove(Moves.RAIN_DANCE, "Rain Dance", Type.WATER, -1, 5, 50, "Makes it rain for 5 turns.", -1, 0, 2, new WeatherConditionalMoveAttr(WeatherType.RAIN), new WeatherChangeAttr(WeatherType.RAIN)), - new SelfStatusMove(Moves.SUNNY_DAY, "Sunny Day", Type.FIRE, -1, 5, 49, "Makes it sunny for 5 turns.", -1, 0, 2, new WeatherConditionalMoveAttr(WeatherType.SUNNY), new WeatherChangeAttr(WeatherType.SUNNY)), - new AttackMove(Moves.CRUNCH, "Crunch", Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, 108, "May lower opponent's Defense.", 20, 0, 2, new StatChangeAttr(BattleStat.DEF, -1)), + new AttackMove(Moves.CROSS_CHOP, "Cross Chop", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 80, 5, -1, "High critical hit ratio.", -1, 0, 2) + .attr(HighCritAttr), + new AttackMove(Moves.TWISTER, "Twister (P)", Type.DRAGON, MoveCategory.SPECIAL, 40, 100, 20, -1, "May cause flinching. Hits Pokémon using Fly/Bounce with double power.", 20, 0, 2) + .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), + 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), + 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 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, - new StatChangeAttr([ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true)), - new AttackMove(Moves.SHADOW_BALL, "Shadow Ball", Type.GHOST, MoveCategory.SPECIAL, 80, 100, 15, 114, "May lower opponent's Special Defense.", 20, 0, 2, new StatChangeAttr(BattleStat.SPDEF, -1)), + 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) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true), + new AttackMove(Moves.SHADOW_BALL, "Shadow Ball", Type.GHOST, MoveCategory.SPECIAL, 80, 100, 15, 114, "May lower opponent's Special Defense.", 20, 0, 2) + .attr(StatChangeAttr, BattleStat.SPDEF, -1), new AttackMove(Moves.FUTURE_SIGHT, "Future Sight (N)", Type.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, "Damage occurs 2 turns later.", -1, 0, 2), - new AttackMove(Moves.ROCK_SMASH, "Rock Smash", Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 15, -1, "May lower opponent's Defense.", 50, 0, 2, new StatChangeAttr(BattleStat.DEF, -1)), - new AttackMove(Moves.WHIRLPOOL, "Whirlpool", Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 2, new TrapAttr(BattlerTagType.WHIRLPOOL)), + new AttackMove(Moves.ROCK_SMASH, "Rock Smash", Type.FIGHTING, MoveCategory.PHYSICAL, 40, 100, 15, -1, "May lower opponent's Defense.", 50, 0, 2) + .attr(StatChangeAttr, BattleStat.DEF, -1), + new AttackMove(Moves.WHIRLPOOL, "Whirlpool", Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 2) + .attr(TrapAttr, BattlerTagType.WHIRLPOOL), new AttackMove(Moves.BEAT_UP, "Beat Up (N)", Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, "Each Pokémon in user's party attacks.", -1, 0, 2), - new AttackMove(Moves.FAKE_OUT, "Fake Out", Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 10, -1, "User attacks first, foe flinches. Only usable on first turn.", 100, 3, 3, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => user.scene.currentBattle.turn === 1), new FlinchAttr()), + new AttackMove(Moves.FAKE_OUT, "Fake Out", Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 10, -1, "User attacks first, foe flinches. Only usable on first turn.", 100, 3, 3) + .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), // TODO 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, new StatusEffectAttr(StatusEffect.BURN)), - new SelfStatusMove(Moves.HAIL, "Hail", Type.ICE, -1, 10, -1, "Non-Ice types are damaged for 5 turns.", -1, 0, 3, new WeatherConditionalMoveAttr(WeatherType.HAIL), new WeatherChangeAttr(WeatherType.HAIL)), + 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), + 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), 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, new StatChangeAttr(BattleStat.SPATK, 1), new ConfuseAttr()), - new StatusMove(Moves.WILL_O_WISP, "Will-O-Wisp", Type.FIRE, 85, 15, 107, "Burns opponent.", -1, 0, 3, new StatusEffectAttr(StatusEffect.BURN)), - new StatusMove(Moves.MEMENTO, "Memento", Type.DARK, 100, 10, -1, "User faints, sharply lowers opponent's Attack and Special Attack.", -1, 0, 3, - new SacrificialAttr(), new StatChangeAttr([ BattleStat.ATK, BattleStat.SPATK ], -2)), + 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) + .attr(ConfuseAttr), + new StatusMove(Moves.WILL_O_WISP, "Will-O-Wisp", Type.FIRE, 85, 15, 107, "Burns opponent.", -1, 0, 3) + .attr(StatusEffectAttr, StatusEffect.BURN), + new StatusMove(Moves.MEMENTO, "Memento", Type.DARK, 100, 10, -1, "User faints, sharply lowers opponent's Attack and Special Attack.", -1, 0, 3) + .attr(SacrificialAttr) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -2), new AttackMove(Moves.FACADE, "Facade (N)", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, 25, "Power doubles if user is burned, poisoned, or paralyzed.", -1, 0, 3), new AttackMove(Moves.FOCUS_PUNCH, "Focus Punch (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, -1, "If the user is hit before attacking, it flinches instead.", -1, -3, 3), - new AttackMove(Moves.SMELLING_SALTS, "Smelling Salts", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, -1, "Power doubles if opponent is paralyzed, but cures it.", -1, 0, 3, - new MovePowerMultiplierAttr((user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1), new HealStatusEffectAttr(false, StatusEffect.PARALYSIS)), + new AttackMove(Moves.SMELLING_SALTS, "Smelling Salts", Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 10, -1, "Power doubles if opponent is paralyzed, but cures it.", -1, 0, 3) + .attr(MovePowerMultiplierAttr, (user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.PARALYSIS ? 2 : 1) + .attr(HealStatusEffectAttr, false, StatusEffect.PARALYSIS), new SelfStatusMove(Moves.FOLLOW_ME, "Follow Me (N)", Type.NORMAL, -1, 20, -1, "In Double Battle, the user takes all the attacks.", -1, 3, 3), new SelfStatusMove(Moves.NATURE_POWER, "Nature Power (N)", Type.NORMAL, -1, 20, -1, "Uses a certain move based on the current terrain.", -1, 0, 3), - new SelfStatusMove(Moves.CHARGE, "Charge", Type.ELECTRIC, -1, 20, -1, "Raises user's Special Defense and next Electric move's power increases.", -1, 0, 3, new StatChangeAttr(BattleStat.SPDEF, 1, true)), // TODO + new SelfStatusMove(Moves.CHARGE, "Charge", Type.ELECTRIC, -1, 20, -1, "Raises user's Special Defense and next Electric move's power increases.", -1, 0, 3) + .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 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 (N)", Type.NORMAL, -1, 20, -1, "User performs a move known by its allies at random.", -1, 0, 3), - new SelfStatusMove(Moves.INGRAIN, "Ingrain", Type.GRASS, -1, 20, -1, "User restores HP each turn. User cannot escape/switch.", -1, 0, 3, - new NoTagOverlapConditionalAttr(BattlerTagType.INGRAIN, true), new AddBattlerTagAttr(BattlerTagType.INGRAIN, true)), - new AttackMove(Moves.SUPERPOWER, "Superpower", Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, "Lowers user's Attack and Defense.", 100, 0, 3, - new StatChangeAttr([ BattleStat.ATK, BattleStat.DEF ], -1, true)), + new SelfStatusMove(Moves.INGRAIN, "Ingrain", Type.GRASS, -1, 20, -1, "User restores HP each turn. User cannot escape/switch.", -1, 0, 3) + .attr(AddBattlerTagAttr, BattlerTagType.INGRAIN, true, undefined, true), + new AttackMove(Moves.SUPERPOWER, "Superpower", Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, "Lowers user's Attack and Defense.", 100, 0, 3) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1, true), new SelfStatusMove(Moves.MAGIC_COAT, "Magic Coat (N)", Type.PSYCHIC, -1, 15, -1, "Reflects moves that cause status conditions back to the attacker.", -1, 4, 3), new SelfStatusMove(Moves.RECYCLE, "Recycle (N)", Type.NORMAL, -1, 10, -1, "User's used hold item is restored.", -1, 0, 3), new AttackMove(Moves.REVENGE, "Revenge (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, "Power increases if user was hit first.", -1, -4, 3), new AttackMove(Moves.BRICK_BREAK, "Brick Break (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 75, 100, 15, 58, "Breaks through Reflect and Light Screen barriers.", -1, 0, 3), - new StatusMove(Moves.YAWN, "Yawn", Type.NORMAL, -1, 10, -1, "Puts opponent to sleep in the next turn.", -1, 0, 3, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => !target.status), new NoTagOverlapConditionalAttr(BattlerTagType.DROWSY), new AddBattlerTagAttr(BattlerTagType.DROWSY)), + new StatusMove(Moves.YAWN, "Yawn", Type.NORMAL, -1, 10, -1, "Puts opponent to sleep in the next turn.", -1, 0, 3) + .attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, undefined, true) + .condition((user: Pokemon, target: Pokemon, move: Move) => !target.status), 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, new HpPowerAttr()), + 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), 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 SelfStatusMove(Moves.REFRESH, "Refresh", Type.NORMAL, -1, 20, -1, "Cures paralysis, poison, and burns.", -1, 0, 3, - new ConditionalMoveAttr((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)), - new HealStatusEffectAttr(true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN)), + 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)), new SelfStatusMove(Moves.GRUDGE, "Grudge (N)", Type.GHOST, -1, 5, -1, "If the users faints after using this move, the PP for the opponent's last move is depleted.", -1, 0, 3), new SelfStatusMove(Moves.SNATCH, "Snatch (N)", Type.DARK, -1, 10, -1, "Steals the effects of the opponent's next move.", -1, 4, 3), 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), - 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, - new ChargeAttr(ChargeAnim.DIVE_CHARGING, 'hid\nunderwater!')), - 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, new MultiHitAttr()), - new SelfStatusMove(Moves.CAMOUFLAGE, "Camouflage", Type.NORMAL, -1, 20, -1, "Changes user's type according to the location.", -1, 0, 3, new CopyBiomeTypeAttr()), - new SelfStatusMove(Moves.TAIL_GLOW, "Tail Glow", Type.BUG, -1, 20, -1, "Drastically raises user's Special Attack.", -1, 0, 3, new StatChangeAttr(BattleStat.SPATK, 3, true)), - new AttackMove(Moves.LUSTER_PURGE, "Luster Purge", Type.PSYCHIC, MoveCategory.SPECIAL, 70, 100, 5, -1, "May lower opponent's Special Defense.", 50, 0, 3, new StatChangeAttr(BattleStat.SPDEF, -1)), - new AttackMove(Moves.MIST_BALL, "Mist Ball", Type.PSYCHIC, MoveCategory.SPECIAL, 70, 100, 5, -1, "May lower opponent's Special Attack.", 50, 0, 3, new StatChangeAttr(BattleStat.SPATK, -1)), - new StatusMove(Moves.FEATHER_DANCE, "Feather Dance", Type.FLYING, 100, 15, -1, "Sharply lowers opponent's Attack.", -1, 0, 3, new StatChangeAttr(BattleStat.ATK, -2)), - new StatusMove(Moves.TEETER_DANCE, "Teeter Dance", Type.NORMAL, 100, 20, -1, "Confuses all Pokémon.", -1, 0, 3, new ConfuseAttr(true), new ConfuseAttr()), - 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, new HighCritAttr(), new 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, new AddArenaTagAttr(ArenaTagType.MUD_SPORT, 5)), - 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, new 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, new FlinchAttr()), - new SelfStatusMove(Moves.SLACK_OFF, "Slack Off", Type.NORMAL, -1, 5, -1, "User recovers half its max HP.", -1, 0, 3, new HealAttr()), + 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!'), + 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), + new SelfStatusMove(Moves.CAMOUFLAGE, "Camouflage", Type.NORMAL, -1, 20, -1, "Changes user's type according to the location.", -1, 0, 3) + .attr(CopyBiomeTypeAttr), + new SelfStatusMove(Moves.TAIL_GLOW, "Tail Glow", Type.BUG, -1, 20, -1, "Drastically raises user's Special Attack.", -1, 0, 3) + .attr(StatChangeAttr, BattleStat.SPATK, 3, true), + new AttackMove(Moves.LUSTER_PURGE, "Luster Purge", Type.PSYCHIC, MoveCategory.SPECIAL, 70, 100, 5, -1, "May lower opponent's Special Defense.", 50, 0, 3) + .attr(StatChangeAttr, BattleStat.SPDEF, -1), + new AttackMove(Moves.MIST_BALL, "Mist Ball", Type.PSYCHIC, MoveCategory.SPECIAL, 70, 100, 5, -1, "May lower opponent's Special Attack.", 50, 0, 3) + .attr(StatChangeAttr, BattleStat.SPATK, -1), + new StatusMove(Moves.FEATHER_DANCE, "Feather Dance", Type.FLYING, 100, 15, -1, "Sharply lowers opponent's Attack.", -1, 0, 3) + .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), + 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), + 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.POISON_FANG, "Poison Fang", Type.POISON, MoveCategory.PHYSICAL, 50, 100, 15, -1, "May badly poison opponent.", 50, 0, 3, new 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, new StatChangeAttr(BattleStat.DEF, -1)), - new AttackMove(Moves.BLAST_BURN, "Blast Burn", Type.FIRE, MoveCategory.SPECIAL, 150, 90, 5, 153, "User must recharge next turn.", -1, 0, 3, new AddBattlerTagAttr(BattlerTagType.RECHARGING, true)), - new AttackMove(Moves.HYDRO_CANNON, "Hydro Cannon", Type.WATER, MoveCategory.SPECIAL, 150, 90, 5, 154, "User must recharge next turn.", -1, 0, 3, new AddBattlerTagAttr(BattlerTagType.RECHARGING, true)), - new AttackMove(Moves.METEOR_MASH, "Meteor Mash", Type.STEEL, MoveCategory.PHYSICAL, 90, 90, 10, -1, "May raise user's Attack.", 20, 0, 3, new StatChangeAttr(BattleStat.ATK, 1, true)), - new AttackMove(Moves.ASTONISH, "Astonish", Type.GHOST, MoveCategory.PHYSICAL, 30, 100, 15, -1, "May cause flinching.", 30, 0, 3, new FlinchAttr()), + 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) + .attr(StatChangeAttr, BattleStat.DEF, -1), + new AttackMove(Moves.BLAST_BURN, "Blast Burn", Type.FIRE, MoveCategory.SPECIAL, 150, 90, 5, 153, "User must recharge next turn.", -1, 0, 3) + .attr(AddBattlerTagAttr, BattlerTagType.RECHARGING, true), + new AttackMove(Moves.HYDRO_CANNON, "Hydro Cannon", Type.WATER, MoveCategory.SPECIAL, 150, 90, 5, 154, "User must recharge next turn.", -1, 0, 3) + .attr(AddBattlerTagAttr, BattlerTagType.RECHARGING, true), + new AttackMove(Moves.METEOR_MASH, "Meteor Mash", Type.STEEL, MoveCategory.PHYSICAL, 90, 90, 10, -1, "May raise user's Attack.", 20, 0, 3) + .attr(StatChangeAttr, BattleStat.ATK, 1, true), + 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 StatusMove(Moves.FAKE_TEARS, "Fake Tears", Type.DARK, 100, 20, 3, "Sharply lowers opponent's Special Defense.", -1, 0, 3, new 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, new HighCritAttr()), - new AttackMove(Moves.OVERHEAT, "Overheat", Type.FIRE, MoveCategory.SPECIAL, 130, 90, 5, 157, "Sharply lowers user's Special Attack.", 100, 0, 3, new StatChangeAttr(BattleStat.SPATK, -2, true)), + 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), + 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), - new AttackMove(Moves.ROCK_TOMB, "Rock Tomb", Type.ROCK, MoveCategory.PHYSICAL, 60, 95, 15, 36, "Lowers opponent's Speed.", 100, 0, 3, new StatChangeAttr(BattleStat.SPD, -1)), - new AttackMove(Moves.SILVER_WIND, "Silver Wind", Type.BUG, MoveCategory.SPECIAL, 60, 100, 5, -1, "May raise all stats of user at once.", 10, 0, 3, - new StatChangeAttr([ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true)), - new StatusMove(Moves.METAL_SOUND, "Metal Sound", Type.STEEL, 85, 40, -1, "Sharply lowers opponent's Special Defense.", -1, 0, 3, new StatChangeAttr(BattleStat.SPDEF, -2)), - new StatusMove(Moves.GRASS_WHISTLE, "Grass Whistle", Type.GRASS, 55, 15, -1, "Puts opponent to sleep.", -1, 0, 3, new StatusEffectAttr(StatusEffect.SLEEP)), - new StatusMove(Moves.TICKLE, "Tickle", Type.NORMAL, 100, 20, -1, "Lowers opponent's Attack and Defense.", -1, 0, 3, - new StatChangeAttr(BattleStat.ATK, -1), new StatChangeAttr(BattleStat.DEF, -1)), - new SelfStatusMove(Moves.COSMIC_POWER, "Cosmic Power", Type.PSYCHIC, -1, 20, -1, "Raises user's Defense and Special Defense.", -1, 0, 3, - new 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, new HpPowerAttr()), - new AttackMove(Moves.SIGNAL_BEAM, "Signal Beam", Type.BUG, MoveCategory.SPECIAL, 75, 100, 15, -1, "May confuse opponent.", 10, 0, 3, new ConfuseAttr()), + new AttackMove(Moves.ROCK_TOMB, "Rock Tomb", Type.ROCK, MoveCategory.PHYSICAL, 60, 95, 15, 36, "Lowers opponent's Speed.", 100, 0, 3) + .attr(StatChangeAttr, BattleStat.SPD, -1), + new AttackMove(Moves.SILVER_WIND, "Silver Wind", Type.BUG, MoveCategory.SPECIAL, 60, 100, 5, -1, "May raise all stats of user at once.", 10, 0, 3) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true), + new StatusMove(Moves.METAL_SOUND, "Metal Sound", Type.STEEL, 85, 40, -1, "Sharply lowers opponent's Special Defense.", -1, 0, 3) + .attr(StatChangeAttr, BattleStat.SPDEF, -2), + new StatusMove(Moves.GRASS_WHISTLE, "Grass Whistle", Type.GRASS, 55, 15, -1, "Puts opponent to sleep.", -1, 0, 3) + .attr(StatusEffectAttr, StatusEffect.SLEEP), + new StatusMove(Moves.TICKLE, "Tickle", Type.NORMAL, 100, 20, -1, "Lowers opponent's Attack and Defense.", -1, 0, 3) + .attr(StatChangeAttr, BattleStat.ATK, -1) + .attr(StatChangeAttr, BattleStat.DEF, -1), + 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), + 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), - new AttackMove(Moves.EXTRASENSORY, "Extrasensory", Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 20, -1, "May cause flinching.", 10, 0, 3, new FlinchAttr()), - new AttackMove(Moves.SKY_UPPERCUT, "Sky Uppercut", Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, "Hits the opponent, even during Fly.", -1, 0, 3, new HitsTagAttr(BattlerTagType.FLYING)), - new AttackMove(Moves.SAND_TOMB, "Sand Tomb", Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 3, new TrapAttr(BattlerTagType.SAND_TOMB)), - new AttackMove(Moves.SHEER_COLD, "Sheer Cold", Type.ICE, MoveCategory.SPECIAL, -1, 30, 5, -1, "One-Hit-KO, if it hits.", -1, 0, 3, new OneHitKOAttr()), - new AttackMove(Moves.MUDDY_WATER, "Muddy Water", Type.WATER, MoveCategory.SPECIAL, 90, 85, 10, -1, "May lower opponent's Accuracy.", 30, 0, 3, new StatChangeAttr(BattleStat.ACC, -1)), - 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, new MultiHitAttr()), + new AttackMove(Moves.EXTRASENSORY, "Extrasensory", Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 20, -1, "May cause flinching.", 10, 0, 3) + .attr(FlinchAttr), + new AttackMove(Moves.SKY_UPPERCUT, "Sky Uppercut", Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, "Hits the opponent, even during Fly.", -1, 0, 3) + .attr(HitsTagAttr, BattlerTagType.FLYING), + new AttackMove(Moves.SAND_TOMB, "Sand Tomb", Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, -1, "Traps opponent, damaging them for 4-5 turns.", 100, 0, 3) + .attr(TrapAttr, BattlerTagType.SAND_TOMB), + 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), + 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), 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.ICICLE_SPEAR, "Icicle Spear", Type.ICE, MoveCategory.PHYSICAL, 25, 100, 30, -1, "Hits 2-5 times in one turn.", -1, 0, 3, new MultiHitAttr()), - new SelfStatusMove(Moves.IRON_DEFENSE, "Iron Defense", Type.STEEL, -1, 15, 104, "Sharply raises user's Defense.", -1, 0, 3, new StatChangeAttr(BattleStat.DEF, 2, true)), - new StatusMove(Moves.BLOCK, "Block", Type.NORMAL, -1, 5, -1, "Opponent cannot flee or switch.", -1, 0, 3, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => !target.getTag(BattlerTagType.TRAPPED)), new AddBattlerTagAttr(BattlerTagType.TRAPPED, false, 1)), - new SelfStatusMove(Moves.HOWL, "Howl", Type.NORMAL, -1, 40, -1, "Raises Attack of allies.", -1, 0, 3, new StatChangeAttr(BattleStat.ATK, 1, true)), // TODO + 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), + new SelfStatusMove(Moves.IRON_DEFENSE, "Iron Defense", Type.STEEL, -1, 15, 104, "Sharply raises user's Defense.", -1, 0, 3) + .attr(StatChangeAttr, BattleStat.DEF, 2, true), + new StatusMove(Moves.BLOCK, "Block", Type.NORMAL, -1, 5, -1, "Opponent cannot flee or switch.", -1, 0, 3) + .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.FRENZY_PLANT, "Frenzy Plant", Type.GRASS, MoveCategory.SPECIAL, 150, 90, 5, 155, "User must recharge next turn.", -1, 0, 3, new 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, - new StatChangeAttr([ BattleStat.ATK, BattleStat.DEF ], 1, true)), - 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, - new ChargeAttr(ChargeAnim.BOUNCE_CHARGING, 'sprang up!', BattlerTagType.FLYING), new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.MUD_SHOT, "Mud Shot", Type.GROUND, MoveCategory.SPECIAL, 55, 95, 15, 35, "Lowers opponent's Speed.", 100, 0, 3, new 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, new HighCritAttr(), new StatusEffectAttr(StatusEffect.POISON)), + 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) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], 1, true), + 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), + 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) + .attr(HighCritAttr) + .attr(StatusEffectAttr, StatusEffect.POISON), new AttackMove(Moves.COVET, "Covet (N)", Type.NORMAL, MoveCategory.PHYSICAL, 60, 100, 25, -1, "Opponent's item is stolen by the user.", -1, 0, 3), - new AttackMove(Moves.VOLT_TACKLE, "Volt Tackle", Type.ELECTRIC, MoveCategory.PHYSICAL, 120, 100, 15, -1, "User receives recoil damage. May paralyze opponent.", 10, 0, 3, - new RecoilAttr(), new StatusEffectAttr(StatusEffect.PARALYSIS)), + new AttackMove(Moves.VOLT_TACKLE, "Volt Tackle", Type.ELECTRIC, MoveCategory.PHYSICAL, 120, 100, 15, -1, "User receives recoil damage. May paralyze opponent.", 10, 0, 3) + .attr(RecoilAttr) + .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, new AddArenaTagAttr(ArenaTagType.WATER_SPORT, 5)), - new SelfStatusMove(Moves.CALM_MIND, "Calm Mind", Type.PSYCHIC, -1, 20, 129, "Raises user's Special Attack and Special Defense.", -1, 0, 3, - new 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, new HighCritAttr()), - new SelfStatusMove(Moves.DRAGON_DANCE, "Dragon Dance", Type.DRAGON, -1, 20, 100, "Raises user's Attack and Speed.", -1, 0, 3, - new StatChangeAttr([ BattleStat.ATK, BattleStat.SPD ], 1, true)), - new AttackMove(Moves.ROCK_BLAST, "Rock Blast", Type.ROCK, MoveCategory.PHYSICAL, 25, 90, 10, 76, "Hits 2-5 times in one turn.", -1, 0, 3, new MultiHitAttr()), + 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), + 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) + .attr(HighCritAttr), + new SelfStatusMove(Moves.DRAGON_DANCE, "Dragon Dance", Type.DRAGON, -1, 20, 100, "Raises user's Attack and Speed.", -1, 0, 3) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPD ], 1, true), + new AttackMove(Moves.ROCK_BLAST, "Rock Blast", Type.ROCK, MoveCategory.PHYSICAL, 25, 90, 10, 76, "Hits 2-5 times in one turn.", -1, 0, 3) + .attr(MultiHitAttr), 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, new ConfuseAttr()), - new AttackMove(Moves.DOOM_DESIRE, "Doom Desire", Type.STEEL, MoveCategory.SPECIAL, 140, 100, 5, -1, "Damage occurs 2 turns later.", -1, 0, 3, - new ChargeAttr(ChargeAnim.DOOM_DESIRE_CHARGING, 'chose\nDOOM 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, new 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, new HitHealAttr(), new AddBattlerTagAttr(BattlerTagType.IGNORE_FLYING, true, 1)), + new AttackMove(Moves.WATER_PULSE, "Water Pulse", Type.WATER, MoveCategory.SPECIAL, 60, 100, 20, 11, "May confuse opponent.", 20, 0, 3) + .attr(ConfuseAttr), + 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 + 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 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, new StatChangeAttr(BattleStat.SPD, -1, true)), + new AttackMove(Moves.HAMMER_ARM, "Hammer Arm", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 90, 10, -1, "Lowers user's Speed.", 100, 0, 4) + .attr(StatChangeAttr, BattleStat.SPD, -1, true), new AttackMove(Moves.GYRO_BALL, "Gyro Ball (N)", Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 5, -1, "The slower the user, the stronger the attack.", -1, 0, 4), - new SelfStatusMove(Moves.HEALING_WISH, "Healing Wish", Type.PSYCHIC, -1, 10, -1, "The user faints and the next Pokémon released is fully healed.", -1, 0, 4, new SacrificialAttr()), // TODO - new AttackMove(Moves.BRINE, "Brine", Type.WATER, MoveCategory.SPECIAL, 65, 100, 10, -1, "Power doubles if opponent's HP is less than 50%.", -1, 0, 4, new MovePowerMultiplierAttr((user: Pokemon, target: Pokemon, move: Move) => target.getHpRatio() < 0.5 ? 2 : 1)), + new SelfStatusMove(Moves.HEALING_WISH, "Healing Wish", Type.PSYCHIC, -1, 10, -1, "The user faints and the next Pokémon released is fully healed.", -1, 0, 4) + .attr(SacrificialAttr), // TODO + new AttackMove(Moves.BRINE, "Brine", Type.WATER, MoveCategory.SPECIAL, 65, 100, 10, -1, "Power doubles if opponent's HP is less than 50%.", -1, 0, 4) + .attr(MovePowerMultiplierAttr, (user: Pokemon, target: Pokemon, move: Move) => target.getHpRatio() < 0.5 ? 2 : 1), new AttackMove(Moves.NATURAL_GIFT, "Natural Gift (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 15, -1, "Power and type depend on the user's held berry.", -1, 0, 4), - new AttackMove(Moves.FEINT, "Feint", Type.NORMAL, MoveCategory.PHYSICAL, 30, 100, 10, -1, "Only hits if opponent uses Protect or Detect in the same turn.", -1, 2, 4, - new ConditionalMoveAttr((user: Pokemon, target: Pokemon, move: Move) => !!target.getTag(BattlerTagType.PROTECTED))).ignoreProtect(), + new AttackMove(Moves.FEINT, "Feint", Type.NORMAL, MoveCategory.PHYSICAL, 30, 100, 10, -1, "Only hits if opponent uses Protect or Detect in the same turn.", -1, 2, 4) + .condition((user: Pokemon, target: Pokemon, move: Move) => !!target.getTag(BattlerTagType.PROTECTED)) + .ignoreProtect(), 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 SelfStatusMove(Moves.ACUPRESSURE, "Acupressure", Type.NORMAL, -1, 30, -1, "Sharply raises a random stat.", -1, 0, 4, new StatChangeAttr(BattleStat.RAND, 2, true)), + new SelfStatusMove(Moves.ACUPRESSURE, "Acupressure", Type.NORMAL, -1, 30, -1, "Sharply raises a random stat.", -1, 0, 4) + .attr(StatChangeAttr, BattleStat.RAND, 2, true), 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), 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, - new StatChangeAttr([ BattleStat.DEF, BattleStat.SPDEF ], -1, true)), + 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), new AttackMove(Moves.PAYBACK, "Payback (N)", Type.DARK, MoveCategory.PHYSICAL, 50, 100, 10, -1, "Power doubles if the user was attacked first.", -1, 0, 4), new AttackMove(Moves.ASSURANCE, "Assurance (N)", Type.DARK, MoveCategory.PHYSICAL, 60, 100, 10, -1, "Power doubles if opponent already took damage in the same turn.", -1, 0, 4), new StatusMove(Moves.EMBARGO, "Embargo (N)", Type.DARK, 100, 15, -1, "Opponent cannot use items.", -1, 0, 4), @@ -2091,199 +2393,308 @@ export const allMoves = [ 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), 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, new AddBattlerTagAttr(BattlerTagType.NO_CRIT, false, 5)), + 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), 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), - new SelfStatusMove(Moves.COPYCAT, "Copycat", Type.NORMAL, -1, 20, -1, "Copies opponent's last move.", -1, 0, 4, new ConditionalMoveAttr(targetMoveCopiableCondition), new CopyMoveAttr()), + new SelfStatusMove(Moves.COPYCAT, "Copycat", Type.NORMAL, -1, 20, -1, "Copies opponent's last move.", -1, 0, 4) + .attr(CopyMoveAttr), new StatusMove(Moves.POWER_SWAP, "Power Swap (N)", Type.PSYCHIC, -1, 10, -1, "User and opponent swap Attack and Special Attack.", -1, 0, 4), new StatusMove(Moves.GUARD_SWAP, "Guard Swap (N)", Type.PSYCHIC, -1, 10, -1, "User and opponent swap Defense and Special Defense.", -1, 0, 4), new AttackMove(Moves.PUNISHMENT, "Punishment (N)", Type.DARK, MoveCategory.PHYSICAL, -1, 100, 5, -1, "Power increases when opponent's stats have been raised.", -1, 0, 4), new AttackMove(Moves.LAST_RESORT, "Last Resort (N)", Type.NORMAL, MoveCategory.PHYSICAL, 140, 100, 5, -1, "Can only be used after all other moves are used.", -1, 0, 4), 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 (N)", Type.POISON, -1, 20, 91, "Poisons opponents when they switch into battle.", -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), 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, - new NoTagOverlapConditionalAttr(BattlerTagType.AQUA_RING, true), new AddBattlerTagAttr(BattlerTagType.AQUA_RING, true)), + 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), new SelfStatusMove(Moves.MAGNET_RISE, "Magnet Rise (N)", Type.ELECTRIC, -1, 10, -1, "User becomes immune to Ground-type moves for 5 turns.", -1, 0, 4), - new AttackMove(Moves.FLARE_BLITZ, "Flare Blitz", Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 165, "User receives recoil damage. May burn opponent.", 10, 0, 4, - new RecoilAttr(), new StatusEffectAttr(StatusEffect.BURN)), - new AttackMove(Moves.FORCE_PALM, "Force Palm", Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, "May paralyze opponent.", 30, 0, 4, new StatusEffectAttr(StatusEffect.PARALYSIS)), + new AttackMove(Moves.FLARE_BLITZ, "Flare Blitz", Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 165, "User receives recoil damage. May burn opponent.", 10, 0, 4) + .attr(RecoilAttr) + .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 SelfStatusMove(Moves.ROCK_POLISH, "Rock Polish", Type.ROCK, -1, 20, -1, "Sharply raises user's Speed.", -1, 0, 4, new 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, new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.DARK_PULSE, "Dark Pulse", Type.DARK, MoveCategory.SPECIAL, 80, 100, 15, 94, "May cause flinching.", 20, 0, 4, new FlinchAttr()), - new AttackMove(Moves.NIGHT_SLASH, "Night Slash", Type.DARK, MoveCategory.PHYSICAL, 70, 100, 15, -1, "High critical hit ratio.", -1, 0, 4, new HighCritAttr()), + 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), + 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), - new AttackMove(Moves.AIR_SLASH, "Air Slash", Type.FLYING, MoveCategory.SPECIAL, 75, 95, 15, 65, "May cause flinching.", 30, 0, 4, new FlinchAttr()), + new AttackMove(Moves.AIR_SLASH, "Air Slash", Type.FLYING, MoveCategory.SPECIAL, 75, 95, 15, 65, "May cause flinching.", 30, 0, 4) + .attr(FlinchAttr), 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, new StatChangeAttr(BattleStat.SPDEF, -1)), + 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_RUSH, "Dragon Rush", Type.DRAGON, MoveCategory.PHYSICAL, 100, 75, 10, -1, "May cause flinching.", 20, 0, 4, new FlinchAttr()), + 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), - new AttackMove(Moves.DRAIN_PUNCH, "Drain Punch", Type.FIGHTING, MoveCategory.PHYSICAL, 75, 100, 10, 73, "User recovers half the HP inflicted on opponent.", -1, 0, 4, new HitHealAttr()), + new AttackMove(Moves.DRAIN_PUNCH, "Drain Punch", Type.FIGHTING, MoveCategory.PHYSICAL, 75, 100, 10, 73, "User recovers half the HP inflicted on opponent.", -1, 0, 4) + .attr(HitHealAttr), new AttackMove(Moves.VACUUM_WAVE, "Vacuum Wave", Type.FIGHTING, MoveCategory.SPECIAL, 40, 100, 30, -1, "User attacks first.", -1, 0, 4), - new AttackMove(Moves.FOCUS_BLAST, "Focus Blast", Type.FIGHTING, MoveCategory.SPECIAL, 120, 70, 5, 158, "May lower opponent's Special Defense.", 10, 0, 4, new StatChangeAttr(BattleStat.SPDEF, -1)), - new AttackMove(Moves.ENERGY_BALL, "Energy Ball", Type.GRASS, MoveCategory.SPECIAL, 90, 100, 10, 119, "May lower opponent's Special Defense.", 10, 0, 4, new 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, new RecoilAttr()), - new AttackMove(Moves.EARTH_POWER, "Earth Power", Type.GROUND, MoveCategory.SPECIAL, 90, 100, 10, 133, "May lower opponent's Special Defense.", 10, 0, 4, new StatChangeAttr(BattleStat.SPDEF, -1)), + new AttackMove(Moves.FOCUS_BLAST, "Focus Blast", Type.FIGHTING, MoveCategory.SPECIAL, 120, 70, 5, 158, "May lower opponent's Special Defense.", 10, 0, 4) + .attr(StatChangeAttr, BattleStat.SPDEF, -1), + 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), + 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), - new AttackMove(Moves.GIGA_IMPACT, "Giga Impact", Type.NORMAL, MoveCategory.PHYSICAL, 150, 90, 5, 152, "User must recharge next turn.", -1, 0, 4, new AddBattlerTagAttr(BattlerTagType.RECHARGING, true)), - new SelfStatusMove(Moves.NASTY_PLOT, "Nasty Plot", Type.DARK, -1, 20, 140, "Sharply raises user's Special Attack.", -1, 0, 4, new StatChangeAttr(BattleStat.SPATK, 2, true)), + new AttackMove(Moves.GIGA_IMPACT, "Giga Impact", Type.NORMAL, MoveCategory.PHYSICAL, 150, 90, 5, 152, "User must recharge next turn.", -1, 0, 4) + .attr(AddBattlerTagAttr, BattlerTagType.RECHARGING, true), + new SelfStatusMove(Moves.NASTY_PLOT, "Nasty Plot", Type.DARK, -1, 20, 140, "Sharply raises user's Special Attack.", -1, 0, 4) + .attr(StatChangeAttr, BattleStat.SPATK, 2, true), new AttackMove(Moves.BULLET_PUNCH, "Bullet Punch", Type.STEEL, MoveCategory.PHYSICAL, 40, 100, 30, -1, "User attacks first.", -1, 1, 4), - new AttackMove(Moves.AVALANCHE, "Avalanche (N)", Type.ICE, MoveCategory.PHYSICAL, 60, 100, 10, 46, "Power doubles if user took damage first.", -1, -4, 4), - new AttackMove(Moves.ICE_SHARD, "Ice Shard (N)", Type.ICE, MoveCategory.PHYSICAL, 40, 100, 30, -1, "User attacks first.", -1, 1, 4), - new AttackMove(Moves.SHADOW_CLAW, "Shadow Claw", Type.GHOST, MoveCategory.PHYSICAL, 70, 100, 15, 61, "High critical hit ratio.", -1, 0, 4, new HighCritAttr()), - new AttackMove(Moves.THUNDER_FANG, "Thunder Fang", Type.ELECTRIC, MoveCategory.PHYSICAL, 65, 95, 15, 9, "May cause flinching and/or paralyze opponent.", 10, 0, 4, new FlinchAttr(), new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.ICE_FANG, "Ice Fang", Type.ICE, MoveCategory.PHYSICAL, 65, 95, 15, 10, "May cause flinching and/or freeze opponent.", 10, 0, 4, new FlinchAttr(), new StatusEffectAttr(StatusEffect.FREEZE)), - new AttackMove(Moves.FIRE_FANG, "Fire Fang", Type.FIRE, MoveCategory.PHYSICAL, 65, 95, 15, 8, "May cause flinching and/or burn opponent.", 10, 0, 4, new FlinchAttr(), new StatusEffectAttr(StatusEffect.BURN)), + new AttackMove(Moves.AVALANCHE, "Avalanche", Type.ICE, MoveCategory.PHYSICAL, 60, 100, 10, 46, "Power doubles if user took damage first.", -1, -4, 4) + .attr(TurnDamagedDoublePowerAttr), + new AttackMove(Moves.ICE_SHARD, "Ice Shard", Type.ICE, MoveCategory.PHYSICAL, 40, 100, 30, -1, "User attacks first.", -1, 1, 4), + new AttackMove(Moves.SHADOW_CLAW, "Shadow Claw", Type.GHOST, MoveCategory.PHYSICAL, 70, 100, 15, 61, "High critical hit ratio.", -1, 0, 4) + .attr(HighCritAttr), + new AttackMove(Moves.THUNDER_FANG, "Thunder Fang", Type.ELECTRIC, MoveCategory.PHYSICAL, 65, 95, 15, 9, "May cause flinching and/or paralyze opponent.", 10, 0, 4) + .attr(FlinchAttr) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + new AttackMove(Moves.ICE_FANG, "Ice Fang", Type.ICE, MoveCategory.PHYSICAL, 65, 95, 15, 10, "May cause flinching and/or freeze opponent.", 10, 0, 4) + .attr(FlinchAttr) + .attr(StatusEffectAttr, StatusEffect.FREEZE), + new AttackMove(Moves.FIRE_FANG, "Fire Fang", Type.FIRE, MoveCategory.PHYSICAL, 65, 95, 15, 8, "May cause flinching and/or burn opponent.", 10, 0, 4) + .attr(FlinchAttr) + .attr(StatusEffectAttr, StatusEffect.BURN), new AttackMove(Moves.SHADOW_SNEAK, "Shadow Sneak", Type.GHOST, MoveCategory.PHYSICAL, 40, 100, 30, -1, "User attacks first.", -1, 1, 4), - new AttackMove(Moves.MUD_BOMB, "Mud Bomb", Type.GROUND, MoveCategory.SPECIAL, 65, 85, 10, -1, "May lower opponent's Accuracy.", 30, 0, 4, new StatChangeAttr(BattleStat.ACC, -1)), - new AttackMove(Moves.PSYCHO_CUT, "Psycho Cut", Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 100, 20, -1, "High critical hit ratio.", -1, 0, 4, new HighCritAttr()), - new AttackMove(Moves.ZEN_HEADBUTT, "Zen Headbutt", Type.PSYCHIC, MoveCategory.PHYSICAL, 80, 90, 15, 59, "May cause flinching.", 20, 0, 4, new FlinchAttr()), - new AttackMove(Moves.MIRROR_SHOT, "Mirror Shot", Type.STEEL, MoveCategory.SPECIAL, 65, 85, 10, -1, "May lower opponent's Accuracy.", 30, 0, 4, new StatChangeAttr(BattleStat.ACC, -1)), - new AttackMove(Moves.FLASH_CANNON, "Flash Cannon", Type.STEEL, MoveCategory.SPECIAL, 80, 100, 10, 93, "May lower opponent's Special Defense.", 10, 0, 4, new StatChangeAttr(BattleStat.SPDEF, -1)), - new AttackMove(Moves.ROCK_CLIMB, "Rock Climb", Type.NORMAL, MoveCategory.PHYSICAL, 90, 85, 20, -1, "May confuse opponent.", 20, 0, 4, new ConfuseAttr()), - new StatusMove(Moves.DEFOG, "Defog", Type.FLYING, -1, 15, -1, "Lowers opponent's Evasiveness and clears fog.", -1, 0, 4, new StatChangeAttr(BattleStat.EVA, -1), new ClearWeatherAttr(WeatherType.FOG)), - new StatusMove(Moves.TRICK_ROOM, "Trick Room (N)", Type.PSYCHIC, -1, 5, 161, "Slower Pokémon move first in the turn for 5 turns.", -1, 0, 4).ignoreProtect(), - new AttackMove(Moves.DRACO_METEOR, "Draco Meteor", Type.DRAGON, MoveCategory.SPECIAL, 130, 90, 5, 169, "Sharply lowers user's Special Attack.", 100, -7, 4, new StatChangeAttr(BattleStat.SPATK, -2, true)), - new AttackMove(Moves.DISCHARGE, "Discharge", Type.ELECTRIC, MoveCategory.SPECIAL, 80, 100, 15, -1, "May paralyze opponent.", 30, 0, 4, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.LAVA_PLUME, "Lava Plume", Type.FIRE, MoveCategory.SPECIAL, 80, 100, 15, -1, "May burn opponent.", 30, 0, 4, new StatusEffectAttr(StatusEffect.BURN)), - new AttackMove(Moves.LEAF_STORM, "Leaf Storm", Type.GRASS, MoveCategory.SPECIAL, 130, 90, 5, 159, "Sharply lowers user's Special Attack.", 100, 0, 4, new StatChangeAttr(BattleStat.SPATK, -2, true)), + new AttackMove(Moves.MUD_BOMB, "Mud Bomb", Type.GROUND, MoveCategory.SPECIAL, 65, 85, 10, -1, "May lower opponent's Accuracy.", 30, 0, 4) + .attr(StatChangeAttr, BattleStat.ACC, -1), + new AttackMove(Moves.PSYCHO_CUT, "Psycho Cut", Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 100, 20, -1, "High critical hit ratio.", -1, 0, 4) + .attr(HighCritAttr), + new AttackMove(Moves.ZEN_HEADBUTT, "Zen Headbutt", Type.PSYCHIC, MoveCategory.PHYSICAL, 80, 90, 15, 59, "May cause flinching.", 20, 0, 4) + .attr(FlinchAttr), + new AttackMove(Moves.MIRROR_SHOT, "Mirror Shot", Type.STEEL, MoveCategory.SPECIAL, 65, 85, 10, -1, "May lower opponent's Accuracy.", 30, 0, 4) + .attr(StatChangeAttr, BattleStat.ACC, -1), + new AttackMove(Moves.FLASH_CANNON, "Flash Cannon", Type.STEEL, MoveCategory.SPECIAL, 80, 100, 10, 93, "May lower opponent's Special Defense.", 10, 0, 4) + .attr(StatChangeAttr, BattleStat.SPDEF, -1), + new AttackMove(Moves.ROCK_CLIMB, "Rock Climb", Type.NORMAL, MoveCategory.PHYSICAL, 90, 85, 20, -1, "May confuse opponent.", 20, 0, 4) + .attr(ConfuseAttr), + new StatusMove(Moves.DEFOG, "Defog", Type.FLYING, -1, 15, -1, "Lowers opponent's Evasiveness and clears fog.", -1, 0, 4) + .attr(StatChangeAttr, BattleStat.EVA, -1) + .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) + .ignoreProtect(), + 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), + 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), + 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), - new AttackMove(Moves.ROCK_WRECKER, "Rock Wrecker", Type.ROCK, MoveCategory.PHYSICAL, 150, 90, 5, -1, "User must recharge next turn.", -1, 0, 4, new AddBattlerTagAttr(BattlerTagType.RECHARGING, true)), - new AttackMove(Moves.CROSS_POISON, "Cross Poison", Type.POISON, MoveCategory.PHYSICAL, 70, 100, 20, -1, "High critical hit ratio. May poison opponent.", 10, 0, 4, - new HighCritAttr(), new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.GUNK_SHOT, "Gunk Shot", Type.POISON, MoveCategory.PHYSICAL, 120, 80, 5, 102, "May poison opponent.", 30, 0, 4, new StatusEffectAttr(StatusEffect.POISON)), - new AttackMove(Moves.IRON_HEAD, "Iron Head", Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 15, 99, "May cause flinching.", 30, 0, 4, new FlinchAttr()), + new AttackMove(Moves.ROCK_WRECKER, "Rock Wrecker", Type.ROCK, MoveCategory.PHYSICAL, 150, 90, 5, -1, "User must recharge next turn.", -1, 0, 4) + .attr(AddBattlerTagAttr, BattlerTagType.RECHARGING, true), + new AttackMove(Moves.CROSS_POISON, "Cross Poison", Type.POISON, MoveCategory.PHYSICAL, 70, 100, 20, -1, "High critical hit ratio. May poison opponent.", 10, 0, 4) + .attr(HighCritAttr) + .attr(StatusEffectAttr, StatusEffect.POISON), + new AttackMove(Moves.GUNK_SHOT, "Gunk Shot", Type.POISON, MoveCategory.PHYSICAL, 120, 80, 5, 102, "May poison opponent.", 30, 0, 4) + .attr(StatusEffectAttr, StatusEffect.POISON), + new AttackMove(Moves.IRON_HEAD, "Iron Head", Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 15, 99, "May cause flinching.", 30, 0, 4) + .attr(FlinchAttr), new AttackMove(Moves.MAGNET_BOMB, "Magnet Bomb", Type.STEEL, MoveCategory.PHYSICAL, 60, -1, 20, -1, "Ignores Accuracy and Evasiveness.", -1, 0, 4), - new AttackMove(Moves.STONE_EDGE, "Stone Edge", Type.ROCK, MoveCategory.PHYSICAL, 100, 80, 5, 150, "High critical hit ratio.", -1, 0, 4, new HighCritAttr()), + new AttackMove(Moves.STONE_EDGE, "Stone Edge", Type.ROCK, MoveCategory.PHYSICAL, 100, 80, 5, 150, "High critical hit ratio.", -1, 0, 4) + .attr(HighCritAttr), 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 (N)", Type.ROCK, -1, 20, 116, "Damages opponent switching into battle.", -1, 0, 4), - 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, new WeightPowerAttr()), - new AttackMove(Moves.CHATTER, "Chatter", Type.FLYING, MoveCategory.SPECIAL, 65, 100, 20, -1, "Confuses opponent.", 100, 0, 4, new ConfuseAttr()), + 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), + 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), + new AttackMove(Moves.CHATTER, "Chatter", Type.FLYING, MoveCategory.SPECIAL, 65, 100, 20, -1, "Confuses opponent.", 100, 0, 4) + .attr(ConfuseAttr), 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, new StatChangeAttr(BattleStat.SPATK, 1, true)), - new AttackMove(Moves.WOOD_HAMMER, "Wood Hammer", Type.GRASS, MoveCategory.PHYSICAL, 120, 100, 15, -1, "User receives recoil damage.", -1, 0, 4, new RecoilAttr()), + new AttackMove(Moves.CHARGE_BEAM, "Charge Beam", Type.ELECTRIC, MoveCategory.SPECIAL, 50, 90, 10, 23, "May raise user's Special Attack.", 70, 0, 4) + .attr(StatChangeAttr, BattleStat.SPATK, 1, true), + new AttackMove(Moves.WOOD_HAMMER, "Wood Hammer", Type.GRASS, MoveCategory.PHYSICAL, 120, 100, 15, -1, "User receives recoil damage.", -1, 0, 4) + .attr(RecoilAttr), new AttackMove(Moves.AQUA_JET, "Aqua Jet", Type.WATER, MoveCategory.PHYSICAL, 40, 100, 20, -1, "User attacks first.", -1, 1, 4), - new AttackMove(Moves.ATTACK_ORDER, "Attack Order", Type.BUG, MoveCategory.PHYSICAL, 90, 100, 15, -1, "High critical hit ratio.", -1, 0, 4, new HighCritAttr()), - new SelfStatusMove(Moves.DEFEND_ORDER, "Defend Order", Type.BUG, -1, 10, -1, "Raises user's Defense and Special Defense.", -1, 0, 4, - new StatChangeAttr([ BattleStat.DEF, BattleStat.SPDEF ], 1, true)), - new SelfStatusMove(Moves.HEAL_ORDER, "Heal Order", Type.BUG, -1, 10, -1, "User recovers half its max HP.", -1, 0, 4, new HealAttr(0.5)), - new AttackMove(Moves.HEAD_SMASH, "Head Smash", Type.ROCK, MoveCategory.PHYSICAL, 150, 80, 5, -1, "User receives recoil damage.", -1, 0, 4, new RecoilAttr()), - new AttackMove(Moves.DOUBLE_HIT, "Double Hit", Type.NORMAL, MoveCategory.PHYSICAL, 35, 90, 10, -1, "Hits twice in one turn.", -1, 0, 4, new MultiHitAttr(MultiHitType._2)), - new AttackMove(Moves.ROAR_OF_TIME, "Roar of Time", Type.DRAGON, MoveCategory.SPECIAL, 150, 90, 5, -1, "User must recharge next turn.", -1, 0, 4, new AddBattlerTagAttr(BattlerTagType.RECHARGING, true)), - new AttackMove(Moves.SPACIAL_REND, "Spacial Rend", Type.DRAGON, MoveCategory.SPECIAL, 100, 95, 5, -1, "High critical hit ratio.", -1, 0, 4, new HighCritAttr()), - new SelfStatusMove(Moves.LUNAR_DANCE, "Lunar Dance", Type.PSYCHIC, -1, 10, -1, "The user faints but the next Pokémon released is fully healed.", -1, 0, 4, new SacrificialAttr()), // TODO + new AttackMove(Moves.ATTACK_ORDER, "Attack Order", Type.BUG, MoveCategory.PHYSICAL, 90, 100, 15, -1, "High critical hit ratio.", -1, 0, 4) + .attr(HighCritAttr), + new SelfStatusMove(Moves.DEFEND_ORDER, "Defend Order", Type.BUG, -1, 10, -1, "Raises user's Defense and Special Defense.", -1, 0, 4) + .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true), + new SelfStatusMove(Moves.HEAL_ORDER, "Heal Order", Type.BUG, -1, 10, -1, "User recovers half its max HP.", -1, 0, 4) + .attr(HealAttr, 0.5), + new AttackMove(Moves.HEAD_SMASH, "Head Smash", Type.ROCK, MoveCategory.PHYSICAL, 150, 80, 5, -1, "User receives recoil damage.", -1, 0, 4) + .attr(RecoilAttr), + new AttackMove(Moves.DOUBLE_HIT, "Double Hit", Type.NORMAL, MoveCategory.PHYSICAL, 35, 90, 10, -1, "Hits twice in one turn.", -1, 0, 4) + .attr(MultiHitAttr, MultiHitType._2), + new AttackMove(Moves.ROAR_OF_TIME, "Roar of Time", Type.DRAGON, MoveCategory.SPECIAL, 150, 90, 5, -1, "User must recharge next turn.", -1, 0, 4) + .attr(AddBattlerTagAttr, BattlerTagType.RECHARGING, true), + new AttackMove(Moves.SPACIAL_REND, "Spacial Rend", Type.DRAGON, MoveCategory.SPECIAL, 100, 95, 5, -1, "High critical hit ratio.", -1, 0, 4) + .attr(HighCritAttr), + new SelfStatusMove(Moves.LUNAR_DANCE, "Lunar Dance", Type.PSYCHIC, -1, 10, -1, "The user faints but the next Pokémon released is fully healed.", -1, 0, 4) + .attr(SacrificialAttr), // TODO new AttackMove(Moves.CRUSH_GRIP, "Crush Grip (N)", Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, "More powerful when opponent has higher HP.", -1, 0, 4), - 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, new 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, new StatusEffectAttr(StatusEffect.SLEEP)), - new AttackMove(Moves.SEED_FLARE, "Seed Flare", Type.GRASS, MoveCategory.SPECIAL, 120, 85, 5, -1, "May lower opponent's Special Defense.", 40, 0, 4, new 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, - new 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, - new ChargeAttr(ChargeAnim.SHADOW_FORCE_CHARGING, 'vanished\ninstantly!')).ignoreProtect(), - new SelfStatusMove(Moves.HONE_CLAWS, "Hone Claws", Type.DARK, -1, 15, -1, "Raises user's Attack and Accuracy.", -1, 0, 5, - new StatChangeAttr([ BattleStat.ATK, BattleStat.ACC ], 1, true)), + 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), + 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!') + .ignoreProtect(), + 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 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).ignoreProtect(), + 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) + .ignoreProtect(), 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, new StatChangeAttr(BattleStat.SPD, 2, true)), // TODO + new SelfStatusMove(Moves.AUTOTOMIZE, "Autotomize", Type.STEEL, -1, 15, -1, "Reduces weight and sharply raises Speed.", -1, 0, 5) + .attr(StatChangeAttr, BattleStat.SPD, 2, true), // TODO 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).ignoreProtect(), + 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) + .ignoreProtect(), 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 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 new AttackMove(Moves.FLAME_BURST, "Flame Burst", Type.FIRE, MoveCategory.SPECIAL, 70, 100, 15, -1, "May also injure nearby Pokémon.", -1, 0, 5), // TODO - new AttackMove(Moves.SLUDGE_WAVE, "Sludge Wave", Type.POISON, MoveCategory.SPECIAL, 95, 100, 10, -1, "May poison opponent.", 10, 0, 5, new StatusEffectAttr(StatusEffect.POISON)), - new SelfStatusMove(Moves.QUIVER_DANCE, "Quiver Dance", Type.BUG, -1, 20, -1, "Raises user's Special Attack, Special Defense and Speed.", -1, 0, 5, - new StatChangeAttr([ BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 1, true)), + new AttackMove(Moves.SLUDGE_WAVE, "Sludge Wave", Type.POISON, MoveCategory.SPECIAL, 95, 100, 10, -1, "May poison opponent.", 10, 0, 5) + .attr(StatusEffectAttr, StatusEffect.POISON), + 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.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, new StatChangeAttr(BattleStat.SPD, 1, true)), - new SelfStatusMove(Moves.COIL, "Coil", Type.POISON, -1, 20, -1, "Raises user's Attack, Defense and Accuracy.", -1, 0, 5, - new StatChangeAttr([ BattleStat.ATK, BattleStat.DEF, BattleStat.ACC ], 1, true)), - new AttackMove(Moves.LOW_SWEEP, "Low Sweep", Type.FIGHTING, MoveCategory.PHYSICAL, 65, 100, 20, 39, "Lowers opponent's Speed.", 100, 0, 5, new StatChangeAttr(BattleStat.SPD, -1)), - new AttackMove(Moves.ACID_SPRAY, "Acid Spray", Type.POISON, MoveCategory.SPECIAL, 40, 100, 20, 13, "Sharply lowers opponent's Special Defense.", 100, 0, 5, new StatChangeAttr(BattleStat.SPDEF, -2)), + new AttackMove(Moves.FLAME_CHARGE, "Flame Charge", Type.FIRE, MoveCategory.PHYSICAL, 50, 100, 20, 38, "Raises user's Speed.", 100, 0, 5) + .attr(StatChangeAttr, BattleStat.SPD, 1, true), + new SelfStatusMove(Moves.COIL, "Coil", Type.POISON, -1, 20, -1, "Raises user's Attack, Defense and Accuracy.", -1, 0, 5) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF, BattleStat.ACC ], 1, true), + new AttackMove(Moves.LOW_SWEEP, "Low Sweep", Type.FIGHTING, MoveCategory.PHYSICAL, 65, 100, 20, 39, "Lowers opponent's Speed.", 100, 0, 5) + .attr(StatChangeAttr, BattleStat.SPD, -1), + new AttackMove(Moves.ACID_SPRAY, "Acid Spray", Type.POISON, MoveCategory.SPECIAL, 40, 100, 20, 13, "Sharply lowers opponent's Special Defense.", 100, 0, 5) + .attr(StatChangeAttr, BattleStat.SPDEF, -2), new AttackMove(Moves.FOUL_PLAY, "Foul Play (N)", Type.DARK, MoveCategory.PHYSICAL, 95, 100, 15, 62, "Uses the opponent's Attack stat.", -1, 0, 5), new StatusMove(Moves.SIMPLE_BEAM, "Simple Beam (N)", Type.NORMAL, 100, 15, -1, "Changes target's ability to Simple.", -1, 0, 5), new StatusMove(Moves.ENTRAINMENT, "Entrainment (N)", Type.NORMAL, 100, 15, -1, "Makes target's ability same as user's.", -1, 0, 5), - new StatusMove(Moves.AFTER_YOU, "After You (N)", Type.NORMAL, -1, 15, -1, "Gives target priority in the next turn.", -1, 0, 5).ignoreProtect(), + new StatusMove(Moves.AFTER_YOU, "After You (N)", Type.NORMAL, -1, 15, -1, "Gives target priority in the next turn.", -1, 0, 5) + .ignoreProtect(), new AttackMove(Moves.ROUND, "Round", Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, -1, "Power increases if teammates use it in the same turn.", -1, 0, 5), // TODO - new AttackMove(Moves.ECHOED_VOICE, "Echoed Voice", Type.NORMAL, MoveCategory.SPECIAL, 40, 100, 15, -1, "Power increases each turn.", -1, 0, 5, new ConsecutiveUseMultiBasePowerAttr(5, false)), + new AttackMove(Moves.ECHOED_VOICE, "Echoed Voice", Type.NORMAL, MoveCategory.SPECIAL, 40, 100, 15, -1, "Power increases each turn.", -1, 0, 5) + .attr(ConsecutiveUseMultiBasePowerAttr, 5, false), 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 StatusMove(Moves.ALLY_SWITCH, "Ally Switch (N)", Type.PSYCHIC, -1, 15, -1, "User switches with opposite teammate.", -1, 0, 5).ignoreProtect(), // TODO - new AttackMove(Moves.SCALD, "Scald", Type.WATER, MoveCategory.SPECIAL, 80, 100, 15, -1, "May burn opponent.", 30, 1, 5, new StatusEffectAttr(StatusEffect.BURN)), - 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, - new StatChangeAttr([ BattleStat.ATK, BattleStat.SPATK ], 2, true), new 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, new HealAttr(0.5, false, false)), - 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, - new 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, - new ChargeAttr(ChargeAnim.SKY_DROP_CHARGING, 'took {TARGET}\ninto the sky!', BattlerTagType.FLYING)), // TODO: Add 2nd turn message - new SelfStatusMove(Moves.SHIFT_GEAR, "Shift Gear", Type.STEEL, -1, 10, -1, "Raises user's Attack and sharply raises Speed.", -1, 0, 5, - new StatChangeAttr(BattleStat.ATK, 1, true), new StatChangeAttr(BattleStat.SPD, 2, true)), + new StatusMove(Moves.ALLY_SWITCH, "Ally Switch (N)", Type.PSYCHIC, -1, 15, -1, "User switches with opposite teammate.", -1, 0, 5) + .ignoreProtect(), // TODO + new AttackMove(Moves.SCALD, "Scald", Type.WATER, MoveCategory.SPECIAL, 80, 100, 15, -1, "May burn opponent.", 30, 1, 5) + .attr(StatusEffectAttr, StatusEffect.BURN), + 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), + 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 + 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 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 StatusMove(Moves.REFLECT_TYPE, "Reflect Type", Type.NORMAL, -1, 15, -1, "User becomes the target's type.", -1, 0, 5, new CopyTypeAttr()), + 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), - new AttackMove(Moves.FINAL_GAMBIT, "Final Gambit", Type.FIGHTING, MoveCategory.SPECIAL, -1, 100, 5, -1, "Inflicts damage equal to the user's remaining HP. User faints.", -1, 0, 5, new UserHpDamageAttr(), new SacrificialAttr()), - new StatusMove(Moves.BESTOW, "Bestow (N)", Type.NORMAL, -1, 15, -1, "Gives the user's held item to the target.", -1, 0, 5).ignoreProtect(), - new AttackMove(Moves.INFERNO, "Inferno", Type.FIRE, MoveCategory.SPECIAL, 100, 50, 5, -1, "Burns opponent.", 100, 0, 5, new StatusEffectAttr(StatusEffect.BURN)), + new AttackMove(Moves.FINAL_GAMBIT, "Final Gambit", Type.FIGHTING, MoveCategory.SPECIAL, -1, 100, 5, -1, "Inflicts damage equal to the user's remaining HP. User faints.", -1, 0, 5) + .attr(UserHpDamageAttr) + .attr(SacrificialAttr), + new StatusMove(Moves.BESTOW, "Bestow (N)", Type.NORMAL, -1, 15, -1, "Gives the user's held item to the target.", -1, 0, 5) + .ignoreProtect(), + new AttackMove(Moves.INFERNO, "Inferno", Type.FIRE, MoveCategory.SPECIAL, 100, 50, 5, -1, "Burns opponent.", 100, 0, 5) + .attr(StatusEffectAttr, StatusEffect.BURN), new AttackMove(Moves.WATER_PLEDGE, "Water Pledge (N)", Type.WATER, MoveCategory.SPECIAL, 80, 100, 10, 145, "Added effects appear if preceded by Fire Pledge or succeeded by Grass Pledge.", -1, 0, 5), new AttackMove(Moves.FIRE_PLEDGE, "Fire Pledge (N)", Type.FIRE, MoveCategory.SPECIAL, 80, 100, 10, 144, "Added effects appear if combined with Grass Pledge or Water Pledge.", -1, 0, 5), 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, new StatChangeAttr(BattleStat.SPATK, -1)), - new AttackMove(Moves.BULLDOZE, "Bulldoze", Type.GROUND, MoveCategory.PHYSICAL, 60, 100, 20, 28, "Lowers opponent's Speed.", 100, 0, 5, new StatChangeAttr(BattleStat.SPD, -1)), + 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), + 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), 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, - new 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, new StatChangeAttr(BattleStat.SPD, -1)), - new AttackMove(Moves.WILD_CHARGE, "Wild Charge", Type.ELECTRIC, MoveCategory.PHYSICAL, 90, 100, 15, 147, "User receives recoil damage.", -1, 0, 5, new RecoilAttr()), - new AttackMove(Moves.DRILL_RUN, "Drill Run", Type.GROUND, MoveCategory.PHYSICAL, 80, 95, 10, 106, "High critical hit ratio.", -1, 0, 5, new HighCritAttr()), - new AttackMove(Moves.DUAL_CHOP, "Dual Chop", Type.DRAGON, MoveCategory.PHYSICAL, 40, 90, 15, -1, "Hits twice in one turn.", -1, 0, 5, new MultiHitAttr(MultiHitType._2)), - new AttackMove(Moves.HEART_STAMP, "Heart Stamp", Type.PSYCHIC, MoveCategory.PHYSICAL, 60, 100, 25, -1, "May cause flinching.", 30, 0, 5, new FlinchAttr()), - new AttackMove(Moves.HORN_LEECH, "Horn Leech", Type.GRASS, MoveCategory.PHYSICAL, 75, 100, 10, -1, "User recovers half the HP inflicted on opponent.", -1, 0, 5, new HitHealAttr()), + 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), + 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) + .attr(HighCritAttr), + new AttackMove(Moves.DUAL_CHOP, "Dual Chop", Type.DRAGON, MoveCategory.PHYSICAL, 40, 90, 15, -1, "Hits twice in one turn.", -1, 0, 5) + .attr(MultiHitAttr, MultiHitType._2), + new AttackMove(Moves.HEART_STAMP, "Heart Stamp", Type.PSYCHIC, MoveCategory.PHYSICAL, 60, 100, 25, -1, "May cause flinching.", 30, 0, 5) + .attr(FlinchAttr), + new AttackMove(Moves.HORN_LEECH, "Horn Leech", Type.GRASS, MoveCategory.PHYSICAL, 75, 100, 10, -1, "User recovers half the HP inflicted on opponent.", -1, 0, 5) + .attr(HitHealAttr), new AttackMove(Moves.SACRED_SWORD, "Sacred Sword (N)", Type.FIGHTING, MoveCategory.PHYSICAL, 90, 100, 15, -1, "Ignores opponent's stat changes.", -1, 0, 5), - new AttackMove(Moves.RAZOR_SHELL, "Razor Shell", Type.WATER, MoveCategory.PHYSICAL, 75, 95, 10, -1, "May lower opponent's Defense.", 50, 0, 5, new StatChangeAttr(BattleStat.DEF, -1)), + new AttackMove(Moves.RAZOR_SHELL, "Razor Shell", Type.WATER, MoveCategory.PHYSICAL, 75, 95, 10, -1, "May lower opponent's Defense.", 50, 0, 5) + .attr(StatChangeAttr, BattleStat.DEF, -1), new AttackMove(Moves.HEAT_CRASH, "Heat Crash (N)", Type.FIRE, MoveCategory.PHYSICAL, -1, 100, 10, -1, "The heavier the user, the stronger the attack.", -1, 0, 5), - new AttackMove(Moves.LEAF_TORNADO, "Leaf Tornado", Type.GRASS, MoveCategory.SPECIAL, 65, 90, 10, -1, "May lower opponent's Accuracy.", 50, 0, 5, new StatChangeAttr(BattleStat.ACC, -1)), - new AttackMove(Moves.STEAMROLLER, "Steamroller", Type.BUG, MoveCategory.PHYSICAL, 65, 100, 20, -1, "May cause flinching.", 30, 0, 5, new FlinchAttr()), - new SelfStatusMove(Moves.COTTON_GUARD, "Cotton Guard", Type.GRASS, -1, 10, -1, "Drastically raises user's Defense.", -1, 0, 5, new StatChangeAttr(BattleStat.DEF, 3, true)), - new AttackMove(Moves.NIGHT_DAZE, "Night Daze", Type.DARK, MoveCategory.SPECIAL, 85, 95, 10, -1, "May lower opponent's Accuracy.", 40, 0, 5, new StatChangeAttr(BattleStat.ACC, -1)), + new AttackMove(Moves.LEAF_TORNADO, "Leaf Tornado", Type.GRASS, MoveCategory.SPECIAL, 65, 90, 10, -1, "May lower opponent's Accuracy.", 50, 0, 5) + .attr(StatChangeAttr, BattleStat.ACC, -1), + new AttackMove(Moves.STEAMROLLER, "Steamroller", Type.BUG, MoveCategory.PHYSICAL, 65, 100, 20, -1, "May cause flinching.", 30, 0, 5) + .attr(FlinchAttr), + new SelfStatusMove(Moves.COTTON_GUARD, "Cotton Guard", Type.GRASS, -1, 10, -1, "Drastically raises user's Defense.", -1, 0, 5) + .attr(StatChangeAttr, BattleStat.DEF, 3, true), + new AttackMove(Moves.NIGHT_DAZE, "Night Daze", Type.DARK, MoveCategory.SPECIAL, 85, 95, 10, -1, "May lower opponent's Accuracy.", 40, 0, 5) + .attr(StatChangeAttr, BattleStat.ACC, -1), new AttackMove(Moves.PSYSTRIKE, "Psystrike (N)", Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 10, -1, "Inflicts damage based on the target's Defense, not Special Defense.", -1, 0, 5), - new AttackMove(Moves.TAIL_SLAP, "Tail Slap", Type.NORMAL, MoveCategory.PHYSICAL, 25, 85, 10, -1, "Hits 2-5 times in one turn.", -1, 0, 5, new MultiHitAttr()), - new AttackMove(Moves.HURRICANE, "Hurricane", Type.FLYING, MoveCategory.SPECIAL, 110, 70, 10, 160, "May confuse opponent.", 30, 0, 5, new ThunderAccuracyAttr(), new ConfuseAttr()), - new AttackMove(Moves.HEAD_CHARGE, "Head Charge", Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 15, -1, "User receives recoil damage.", -1, 0, 5, new RecoilAttr()), - new AttackMove(Moves.GEAR_GRIND, "Gear Grind", Type.STEEL, MoveCategory.PHYSICAL, 50, 85, 15, -1, "Hits twice in one turn.", -1, 0, 5, new MultiHitAttr(MultiHitType._2)), - new AttackMove(Moves.SEARING_SHOT, "Searing Shot", Type.FIRE, MoveCategory.SPECIAL, 100, 100, 5, -1, "May burn opponent.", 30, 0, 5, new StatusEffectAttr(StatusEffect.BURN)), + new AttackMove(Moves.TAIL_SLAP, "Tail Slap", Type.NORMAL, MoveCategory.PHYSICAL, 25, 85, 10, -1, "Hits 2-5 times in one turn.", -1, 0, 5) + .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), + 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), 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, new StatusEffectAttr(StatusEffect.SLEEP)), + 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), 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, new StatChangeAttr(BattleStat.SPD, -1)), - new AttackMove(Moves.BOLT_STRIKE, "Bolt Strike", Type.ELECTRIC, MoveCategory.PHYSICAL, 130, 85, 5, -1, "May paralyze opponent.", 20, 0, 5, new StatusEffectAttr(StatusEffect.PARALYSIS)), - new AttackMove(Moves.BLUE_FLARE, "Blue Flare", Type.FIRE, MoveCategory.SPECIAL, 130, 85, 5, -1, "May burn opponent.", 20, 0, 5, new StatusEffectAttr(StatusEffect.BURN)), - new AttackMove(Moves.FIERY_DANCE, "Fiery Dance", Type.FIRE, MoveCategory.SPECIAL, 80, 100, 10, -1, "May raise user's Special Attack.", 50, 0, 5, new StatChangeAttr(BattleStat.SPATK, 1, true)), - new AttackMove(Moves.FREEZE_SHOCK, "Freeze Shock", Type.ICE, MoveCategory.PHYSICAL, 140, 90, 5, -1, "Charges on first turn, attacks on second. May paralyze opponent.", 30, 0, 5, new StatusEffectAttr(StatusEffect.PARALYSIS)), - 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, - new ChargeAttr(ChargeAnim.ICE_BURN_CHARGING, 'became cloaked\nin freezing air!'), new StatusEffectAttr(StatusEffect.BURN)), - new AttackMove(Moves.SNARL, "Snarl", Type.DARK, MoveCategory.SPECIAL, 55, 95, 15, 30, "Lowers opponent's Special Attack.", 100, 0, 5, new StatChangeAttr(BattleStat.SPATK, -1)), - new AttackMove(Moves.ICICLE_CRASH, "Icicle Crash", Type.ICE, MoveCategory.PHYSICAL, 85, 90, 10, -1, "May cause flinching.", 30, 0, 5, new FlinchAttr()), - new AttackMove(Moves.V_CREATE, "V-create", Type.FIRE, MoveCategory.PHYSICAL, 180, 95, 5, -1, "Lowers user's Defense, Special Defense and Speed.", 100, 0, 5, - new StatChangeAttr([ BattleStat.DEF, BattleStat.SPDEF, BattleStat.SPD ], -1, true)), + 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), + 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) + .attr(StatusEffectAttr, StatusEffect.BURN), + new AttackMove(Moves.FIERY_DANCE, "Fiery Dance", Type.FIRE, MoveCategory.SPECIAL, 80, 100, 10, -1, "May raise user's Special Attack.", 50, 0, 5) + .attr(StatChangeAttr, BattleStat.SPATK, 1, true), + new AttackMove(Moves.FREEZE_SHOCK, "Freeze Shock", Type.ICE, MoveCategory.PHYSICAL, 140, 90, 5, -1, "Charges on first turn, attacks on second. May paralyze opponent.", 30, 0, 5) + .attr(StatusEffectAttr, StatusEffect.PARALYSIS), + 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(StatusEffectAttr, StatusEffect.BURN), + 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), + new AttackMove(Moves.ICICLE_CRASH, "Icicle Crash", Type.ICE, MoveCategory.PHYSICAL, 85, 90, 10, -1, "May cause flinching.", 30, 0, 5) + .attr(FlinchAttr), + new AttackMove(Moves.V_CREATE, "V-create", Type.FIRE, MoveCategory.PHYSICAL, 180, 95, 5, -1, "Lowers user's Defense, Special Defense and Speed.", 100, 0, 5) + .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF, BattleStat.SPD ], -1, true), 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) ]; \ No newline at end of file diff --git a/src/data/status-effect.ts b/src/data/status-effect.ts index b6322c014..3bc3c35cd 100644 --- a/src/data/status-effect.ts +++ b/src/data/status-effect.ts @@ -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 ''; diff --git a/src/data/type.ts b/src/data/type.ts index 341f27e9d..54b0e5eef 100644 --- a/src/data/type.ts +++ b/src/data/type.ts @@ -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) { diff --git a/src/pokemon.ts b/src/pokemon.ts index 83c410f35..a8690f766 100644 --- a/src/pokemon.ts +++ b/src/pokemon.ts @@ -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) { diff --git a/src/system/auto-play.ts b/src/system/auto-play.ts index b55bf0928..f092de81f 100644 --- a/src/system/auto-play.ts +++ b/src/system/auto-play.ts @@ -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; }