mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-21 17:25:10 -05:00
ESLint has a whole new config format, so I figure it's a good time to make the config system saner. - First, we no longer have separate eslint-no-types configs. Lint performance shouldn't be enough of a problem to justify the relevant maintenance complexity. - Second, our base config should work out-of-the-box now. `npx eslint` will work as expected, without any CLI flags. You should still use `npm run lint` which adds the `--cached` flag for performance. - Third, whatever updates I did fixed style linting, which apparently has been bugged for quite some time, considering all the obvious mixed-tabs-and-spaces issues I found in the upgrade. Also here are some changes to our style rules. In particular: - Curly brackets (for objects etc) now have spaces inside them. Sorry for the huge change. ESLint doesn't support our old style, and most projects use Prettier style, so we might as well match them in this way. See https://github.com/eslint-stylistic/eslint-stylistic/issues/415 - String + number concatenation is no longer allowed. We now consistently use template strings for this.
1056 lines
22 KiB
TypeScript
1056 lines
22 KiB
TypeScript
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|
absorb: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, metronome: 1 },
|
|
},
|
|
acidarmor: {
|
|
inherit: true,
|
|
pp: 40,
|
|
},
|
|
aircutter: {
|
|
inherit: true,
|
|
basePower: 55,
|
|
},
|
|
airslash: {
|
|
inherit: true,
|
|
pp: 20,
|
|
},
|
|
aromatherapy: {
|
|
inherit: true,
|
|
onHit(target, source) {
|
|
this.add('-activate', source, 'move: Aromatherapy');
|
|
const allies = [...target.side.pokemon, ...target.side.allySide?.pokemon || []];
|
|
for (const ally of allies) {
|
|
ally.cureStatus();
|
|
}
|
|
},
|
|
},
|
|
assurance: {
|
|
inherit: true,
|
|
basePower: 50,
|
|
},
|
|
aurasphere: {
|
|
inherit: true,
|
|
basePower: 90,
|
|
},
|
|
autotomize: {
|
|
inherit: true,
|
|
volatileStatus: 'autotomize',
|
|
onHit(pokemon) {
|
|
},
|
|
condition: {
|
|
noCopy: true, // doesn't get copied by Baton Pass
|
|
onStart(pokemon) {
|
|
if (pokemon.species.weighthg > 1) {
|
|
this.effectState.multiplier = 1;
|
|
this.add('-start', pokemon, 'Autotomize');
|
|
}
|
|
},
|
|
onRestart(pokemon) {
|
|
if (pokemon.species.weighthg - (this.effectState.multiplier * 1000) > 1) {
|
|
this.effectState.multiplier++;
|
|
this.add('-start', pokemon, 'Autotomize');
|
|
}
|
|
},
|
|
onModifyWeightPriority: 2,
|
|
onModifyWeight(weighthg, pokemon) {
|
|
if (this.effectState.multiplier) {
|
|
weighthg -= this.effectState.multiplier * 1000;
|
|
if (weighthg < 1) weighthg = 1;
|
|
return weighthg;
|
|
}
|
|
},
|
|
},
|
|
},
|
|
barrier: {
|
|
inherit: true,
|
|
pp: 30,
|
|
},
|
|
bestow: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, noassist: 1, failcopycat: 1 },
|
|
},
|
|
blizzard: {
|
|
inherit: true,
|
|
basePower: 120,
|
|
},
|
|
block: {
|
|
inherit: true,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, metronome: 1 },
|
|
},
|
|
bounce: {
|
|
inherit: true,
|
|
flags: { contact: 1, charge: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, metronome: 1, nosleeptalk: 1 },
|
|
},
|
|
bubble: {
|
|
inherit: true,
|
|
basePower: 20,
|
|
},
|
|
bugbuzz: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
camouflage: {
|
|
inherit: true,
|
|
onHit(target) {
|
|
if (!target.setType('Ground')) return false;
|
|
this.add('-start', target, 'typechange', 'Ground');
|
|
},
|
|
},
|
|
charm: {
|
|
inherit: true,
|
|
type: "Normal",
|
|
},
|
|
chatter: {
|
|
inherit: true,
|
|
basePower: 60,
|
|
onModifyMove(move, pokemon) {
|
|
if (pokemon.species.name !== 'Chatot') delete move.secondaries;
|
|
},
|
|
secondary: {
|
|
chance: 10,
|
|
volatileStatus: 'confusion',
|
|
},
|
|
flags: {
|
|
protect: 1, sound: 1, distance: 1, noassist: 1, failcopycat: 1,
|
|
failmefirst: 1, nosleeptalk: 1, failmimic: 1, nosketch: 1,
|
|
},
|
|
},
|
|
conversion: {
|
|
inherit: true,
|
|
onHit(target) {
|
|
const possibleTypes = target.moveSlots.map(moveSlot => {
|
|
const move = this.dex.moves.get(moveSlot.id);
|
|
if (move.id !== 'conversion' && !target.hasType(move.type)) {
|
|
return move.type;
|
|
}
|
|
return '';
|
|
}).filter(type => type);
|
|
if (!possibleTypes.length) {
|
|
return false;
|
|
}
|
|
const type = this.sample(possibleTypes);
|
|
|
|
if (!target.setType(type)) return false;
|
|
this.add('-start', target, 'typechange', type);
|
|
},
|
|
},
|
|
copycat: {
|
|
inherit: true,
|
|
onHit(pokemon) {
|
|
if (!this.lastMove || this.dex.moves.get(this.lastMove.id).flags['failcopycat']) {
|
|
return false;
|
|
}
|
|
this.actions.useMove(this.lastMove.id, pokemon);
|
|
},
|
|
},
|
|
cottonspore: {
|
|
inherit: true,
|
|
onTryHit() {},
|
|
target: "normal",
|
|
},
|
|
covet: {
|
|
inherit: true,
|
|
pp: 40,
|
|
},
|
|
crabhammer: {
|
|
inherit: true,
|
|
basePower: 90,
|
|
},
|
|
defog: {
|
|
inherit: true,
|
|
onHit(pokemon) {
|
|
if (!pokemon.volatiles['substitute']) this.boost({ evasion: -1 });
|
|
const sideConditions = ['reflect', 'lightscreen', 'safeguard', 'mist', 'spikes', 'toxicspikes', 'stealthrock'];
|
|
for (const condition of sideConditions) {
|
|
if (pokemon.side.removeSideCondition(condition)) {
|
|
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Defog', `[of] ${pokemon}`);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
dig: {
|
|
inherit: true,
|
|
flags: { contact: 1, charge: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1, nosleeptalk: 1 },
|
|
},
|
|
dive: {
|
|
inherit: true,
|
|
flags: { contact: 1, charge: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1, nosleeptalk: 1 },
|
|
},
|
|
dracometeor: {
|
|
inherit: true,
|
|
basePower: 140,
|
|
},
|
|
dragonpulse: {
|
|
inherit: true,
|
|
basePower: 90,
|
|
},
|
|
drainpunch: {
|
|
inherit: true,
|
|
flags: { contact: 1, protect: 1, mirror: 1, punch: 1, metronome: 1 },
|
|
},
|
|
dreameater: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, metronome: 1 },
|
|
},
|
|
echoedvoice: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
electroball: {
|
|
inherit: true,
|
|
basePowerCallback(pokemon, target) {
|
|
const ratio = Math.floor(pokemon.getStat('spe') / Math.max(1, target.getStat('spe')));
|
|
const bp = [40, 60, 80, 120, 150][Math.min(ratio, 4)];
|
|
this.debug(`BP: ${bp}`);
|
|
return bp;
|
|
},
|
|
},
|
|
energyball: {
|
|
inherit: true,
|
|
basePower: 80,
|
|
},
|
|
extrasensory: {
|
|
inherit: true,
|
|
pp: 30,
|
|
},
|
|
feint: {
|
|
inherit: true,
|
|
flags: { noassist: 1, failcopycat: 1 },
|
|
},
|
|
finalgambit: {
|
|
inherit: true,
|
|
flags: { contact: 1, protect: 1, metronome: 1 },
|
|
},
|
|
fireblast: {
|
|
inherit: true,
|
|
basePower: 120,
|
|
},
|
|
firepledge: {
|
|
inherit: true,
|
|
basePower: 50,
|
|
basePowerCallback(target, source, move) {
|
|
if (['grasspledge', 'waterpledge'].includes(move.sourceEffect)) {
|
|
this.add('-combine');
|
|
return 150;
|
|
}
|
|
return 50;
|
|
},
|
|
},
|
|
flamethrower: {
|
|
inherit: true,
|
|
basePower: 95,
|
|
},
|
|
fly: {
|
|
inherit: true,
|
|
flags: { contact: 1, charge: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, metronome: 1 },
|
|
},
|
|
followme: {
|
|
inherit: true,
|
|
priority: 3,
|
|
},
|
|
frostbreath: {
|
|
inherit: true,
|
|
basePower: 40,
|
|
},
|
|
furycutter: {
|
|
inherit: true,
|
|
basePower: 20,
|
|
condition: {
|
|
duration: 2,
|
|
onStart() {
|
|
this.effectState.multiplier = 1;
|
|
},
|
|
onRestart() {
|
|
if (this.effectState.multiplier < 8) {
|
|
this.effectState.multiplier <<= 1;
|
|
}
|
|
this.effectState.duration = 2;
|
|
},
|
|
},
|
|
},
|
|
futuresight: {
|
|
inherit: true,
|
|
basePower: 100,
|
|
onTry(source, target) {
|
|
if (!target.side.addSlotCondition(target, 'futuremove')) return false;
|
|
Object.assign(target.side.slotConditions[target.position]['futuremove'], {
|
|
duration: 3,
|
|
move: 'futuresight',
|
|
source,
|
|
moveData: {
|
|
id: 'futuresight',
|
|
name: "Future Sight",
|
|
accuracy: 100,
|
|
basePower: 100,
|
|
category: "Special",
|
|
priority: 0,
|
|
flags: { metronome: 1, futuremove: 1 },
|
|
ignoreImmunity: false,
|
|
effectType: 'Move',
|
|
type: 'Psychic',
|
|
},
|
|
});
|
|
this.add('-start', source, 'move: Future Sight');
|
|
return null;
|
|
},
|
|
},
|
|
gigadrain: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, metronome: 1 },
|
|
},
|
|
glare: {
|
|
inherit: true,
|
|
accuracy: 90,
|
|
},
|
|
grasswhistle: {
|
|
inherit: true,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
grasspledge: {
|
|
inherit: true,
|
|
basePower: 50,
|
|
basePowerCallback(target, source, move) {
|
|
if (['waterpledge', 'firepledge'].includes(move.sourceEffect)) {
|
|
this.add('-combine');
|
|
return 150;
|
|
}
|
|
return 50;
|
|
},
|
|
},
|
|
growl: {
|
|
inherit: true,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
growth: {
|
|
inherit: true,
|
|
pp: 40,
|
|
},
|
|
gunkshot: {
|
|
inherit: true,
|
|
accuracy: 70,
|
|
},
|
|
gyroball: {
|
|
inherit: true,
|
|
basePowerCallback(pokemon, target) {
|
|
let power = Math.floor(25 * target.getStat('spe') / Math.max(1, pokemon.getStat('spe'))) + 1;
|
|
if (power > 150) power = 150;
|
|
this.debug(`BP: ${power}`);
|
|
return power;
|
|
},
|
|
},
|
|
healbell: {
|
|
inherit: true,
|
|
flags: { snatch: 1, sound: 1, metronome: 1 },
|
|
onHit(target, source) {
|
|
this.add('-activate', source, 'move: Heal Bell');
|
|
const allies = [...target.side.pokemon, ...target.side.allySide?.pokemon || []];
|
|
for (const ally of allies) {
|
|
ally.cureStatus();
|
|
}
|
|
},
|
|
},
|
|
healpulse: {
|
|
inherit: true,
|
|
heal: [1, 2],
|
|
onHit() {},
|
|
},
|
|
heatwave: {
|
|
inherit: true,
|
|
basePower: 100,
|
|
},
|
|
hex: {
|
|
inherit: true,
|
|
basePower: 50,
|
|
},
|
|
hiddenpower: {
|
|
inherit: true,
|
|
basePower: 0,
|
|
basePowerCallback(pokemon) {
|
|
const bp = pokemon.hpPower || 70;
|
|
this.debug(`BP: ${bp}`);
|
|
return bp;
|
|
},
|
|
},
|
|
hiddenpowerbug: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerdark: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerdragon: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerelectric: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerfighting: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerfire: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerflying: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerghost: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowergrass: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerground: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerice: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerpoison: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerpsychic: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerrock: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowersteel: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hiddenpowerwater: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
hornleech: {
|
|
inherit: true,
|
|
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
|
|
},
|
|
hurricane: {
|
|
inherit: true,
|
|
basePower: 120,
|
|
},
|
|
hydropump: {
|
|
inherit: true,
|
|
basePower: 120,
|
|
},
|
|
hypervoice: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
icebeam: {
|
|
inherit: true,
|
|
basePower: 95,
|
|
},
|
|
incinerate: {
|
|
inherit: true,
|
|
basePower: 30,
|
|
onHit(pokemon, source) {
|
|
const item = pokemon.getItem();
|
|
if (item.isBerry && pokemon.takeItem(source)) {
|
|
this.add('-enditem', pokemon, item.name, '[from] move: Incinerate');
|
|
}
|
|
},
|
|
},
|
|
knockoff: {
|
|
inherit: true,
|
|
basePower: 20,
|
|
onBasePower() {},
|
|
},
|
|
leafstorm: {
|
|
inherit: true,
|
|
basePower: 140,
|
|
},
|
|
leechlife: {
|
|
inherit: true,
|
|
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
|
|
},
|
|
lick: {
|
|
inherit: true,
|
|
basePower: 20,
|
|
},
|
|
lightscreen: {
|
|
inherit: true,
|
|
condition: {
|
|
duration: 5,
|
|
durationCallback(target, source, effect) {
|
|
if (source?.hasItem('lightclay')) {
|
|
return 8;
|
|
}
|
|
return 5;
|
|
},
|
|
onAnyModifyDamage(damage, source, target, move) {
|
|
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') {
|
|
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
|
|
this.debug('Light Screen weaken');
|
|
if (this.activePerHalf > 1) return this.chainModify([2703, 4096]);
|
|
return this.chainModify(0.5);
|
|
}
|
|
}
|
|
},
|
|
onSideStart(side) {
|
|
this.add('-sidestart', side, 'move: Light Screen');
|
|
},
|
|
onSideResidualOrder: 26,
|
|
onSideResidualSubOrder: 2,
|
|
onSideEnd(side) {
|
|
this.add('-sideend', side, 'move: Light Screen');
|
|
},
|
|
},
|
|
},
|
|
lowsweep: {
|
|
inherit: true,
|
|
basePower: 60,
|
|
},
|
|
magiccoat: {
|
|
inherit: true,
|
|
condition: {
|
|
duration: 1,
|
|
onStart(target, source, effect) {
|
|
this.add('-singleturn', target, 'move: Magic Coat');
|
|
if (effect?.effectType === 'Move') {
|
|
this.effectState.pranksterBoosted = effect.pranksterBoosted;
|
|
}
|
|
},
|
|
onTryHitPriority: 2,
|
|
onTryHit(target, source, move) {
|
|
if (target === source || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
|
|
return;
|
|
}
|
|
const newMove = this.dex.getActiveMove(move.id);
|
|
newMove.hasBounced = true;
|
|
newMove.pranksterBoosted = this.effectState.pranksterBoosted;
|
|
this.actions.useMove(newMove, target, { target: source });
|
|
return null;
|
|
},
|
|
onAllyTryHitSide(target, source, move) {
|
|
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable']) {
|
|
return;
|
|
}
|
|
const newMove = this.dex.getActiveMove(move.id);
|
|
newMove.hasBounced = true;
|
|
newMove.pranksterBoosted = false;
|
|
this.actions.useMove(newMove, this.effectState.target, { target: source });
|
|
return null;
|
|
},
|
|
},
|
|
},
|
|
magicroom: {
|
|
inherit: true,
|
|
priority: -7,
|
|
},
|
|
magmastorm: {
|
|
inherit: true,
|
|
basePower: 120,
|
|
},
|
|
meanlook: {
|
|
inherit: true,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, metronome: 1 },
|
|
},
|
|
megadrain: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, metronome: 1 },
|
|
},
|
|
metalsound: {
|
|
inherit: true,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
meteormash: {
|
|
inherit: true,
|
|
accuracy: 85,
|
|
basePower: 100,
|
|
},
|
|
minimize: {
|
|
inherit: true,
|
|
pp: 20,
|
|
condition: {
|
|
noCopy: true,
|
|
onSourceModifyDamage(damage, source, target, move) {
|
|
if (['stomp', 'steamroller'].includes(move.id)) {
|
|
return this.chainModify(2);
|
|
}
|
|
},
|
|
},
|
|
},
|
|
moonlight: {
|
|
inherit: true,
|
|
type: "Normal",
|
|
},
|
|
mudsport: {
|
|
inherit: true,
|
|
pseudoWeather: undefined,
|
|
volatileStatus: 'mudsport',
|
|
condition: {
|
|
noCopy: true,
|
|
onStart(pokemon) {
|
|
this.add('-start', pokemon, 'Mud Sport');
|
|
},
|
|
onAnyBasePowerPriority: 1,
|
|
onAnyBasePower(basePower, user, target, move) {
|
|
if (move.type === 'Electric') {
|
|
this.debug('mud sport weaken');
|
|
return this.chainModify([1352, 4096]);
|
|
}
|
|
},
|
|
},
|
|
},
|
|
muddywater: {
|
|
inherit: true,
|
|
basePower: 95,
|
|
},
|
|
naturepower: {
|
|
inherit: true,
|
|
onTryHit() {},
|
|
onHit(pokemon) {
|
|
this.actions.useMove('earthquake', pokemon);
|
|
},
|
|
target: "self",
|
|
},
|
|
overheat: {
|
|
inherit: true,
|
|
basePower: 140,
|
|
},
|
|
perishsong: {
|
|
inherit: true,
|
|
flags: { sound: 1, distance: 1, metronome: 1 },
|
|
},
|
|
pinmissile: {
|
|
inherit: true,
|
|
accuracy: 85,
|
|
basePower: 14,
|
|
},
|
|
poisonfang: {
|
|
inherit: true,
|
|
secondary: {
|
|
chance: 30,
|
|
status: 'tox',
|
|
},
|
|
},
|
|
poisongas: {
|
|
inherit: true,
|
|
accuracy: 80,
|
|
},
|
|
poisonpowder: {
|
|
inherit: true,
|
|
onTryHit() {},
|
|
},
|
|
powergem: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
},
|
|
psychup: {
|
|
inherit: true,
|
|
onHit(target, source) {
|
|
let i: BoostID;
|
|
for (i in target.boosts) {
|
|
source.boosts[i] = target.boosts[i];
|
|
}
|
|
this.add('-copyboost', source, target, '[from] move: Psych Up');
|
|
},
|
|
},
|
|
psychoshift: {
|
|
inherit: true,
|
|
accuracy: 90,
|
|
},
|
|
psywave: {
|
|
inherit: true,
|
|
accuracy: 80,
|
|
},
|
|
quickguard: {
|
|
inherit: true,
|
|
stallingMove: true,
|
|
onTry(source) {
|
|
return this.queue.willAct() && this.runEvent('StallMove', source);
|
|
},
|
|
onHitSide(side, source) {
|
|
source.addVolatile('stall');
|
|
},
|
|
condition: {
|
|
duration: 1,
|
|
onSideStart(target, source) {
|
|
this.add('-singleturn', source, 'Quick Guard');
|
|
},
|
|
onTryHitPriority: 4,
|
|
onTryHit(target, source, effect) {
|
|
// Quick Guard only blocks moves with a natural positive priority
|
|
// (e.g. it doesn't block 0 priority moves boosted by Prankster)
|
|
if (effect && (effect.id === 'feint' || this.dex.moves.get(effect.id).priority <= 0)) {
|
|
return;
|
|
}
|
|
this.add('-activate', target, 'Quick Guard');
|
|
const lockedmove = source.getVolatile('lockedmove');
|
|
if (lockedmove) {
|
|
// Outrage counter is reset
|
|
if (source.volatiles['lockedmove'].duration === 2) {
|
|
delete source.volatiles['lockedmove'];
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
},
|
|
},
|
|
ragepowder: {
|
|
inherit: true,
|
|
priority: 3,
|
|
flags: { noassist: 1, failcopycat: 1 },
|
|
},
|
|
reflect: {
|
|
inherit: true,
|
|
condition: {
|
|
duration: 5,
|
|
durationCallback(target, source, effect) {
|
|
if (source?.hasItem('lightclay')) {
|
|
return 8;
|
|
}
|
|
return 5;
|
|
},
|
|
onAnyModifyDamage(damage, source, target, move) {
|
|
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
|
|
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
|
|
this.debug('Reflect weaken');
|
|
if (this.activePerHalf > 1) return this.chainModify([2703, 4096]);
|
|
return this.chainModify(0.5);
|
|
}
|
|
}
|
|
},
|
|
onSideStart(side) {
|
|
this.add('-sidestart', side, 'Reflect');
|
|
},
|
|
onSideResidualOrder: 26,
|
|
onSideResidualSubOrder: 1,
|
|
onSideEnd(side) {
|
|
this.add('-sideend', side, 'Reflect');
|
|
},
|
|
},
|
|
},
|
|
relicsong: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, sound: 1 },
|
|
},
|
|
roar: {
|
|
inherit: true,
|
|
accuracy: 100,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, bypasssub: 1, metronome: 1 },
|
|
},
|
|
rocktomb: {
|
|
inherit: true,
|
|
accuracy: 80,
|
|
basePower: 50,
|
|
pp: 10,
|
|
},
|
|
round: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
sacredsword: {
|
|
inherit: true,
|
|
pp: 20,
|
|
},
|
|
scald: {
|
|
inherit: true,
|
|
thawsTarget: false,
|
|
},
|
|
screech: {
|
|
inherit: true,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
secretpower: {
|
|
inherit: true,
|
|
secondary: {
|
|
chance: 30,
|
|
boosts: {
|
|
accuracy: -1,
|
|
},
|
|
},
|
|
},
|
|
shadowforce: {
|
|
inherit: true,
|
|
flags: { contact: 1, charge: 1, mirror: 1, metronome: 1, nosleeptalk: 1 },
|
|
},
|
|
sing: {
|
|
inherit: true,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
skillswap: {
|
|
inherit: true,
|
|
onHit(target, source) {
|
|
const targetAbility = target.ability;
|
|
const sourceAbility = source.ability;
|
|
if (targetAbility === sourceAbility) {
|
|
return false;
|
|
}
|
|
this.add('-activate', source, 'move: Skill Swap', this.dex.abilities.get(targetAbility), this.dex.abilities.get(sourceAbility), `[of] ${target}`);
|
|
source.setAbility(targetAbility);
|
|
target.setAbility(sourceAbility);
|
|
},
|
|
},
|
|
skullbash: {
|
|
inherit: true,
|
|
basePower: 100,
|
|
pp: 15,
|
|
},
|
|
skydrop: {
|
|
inherit: true,
|
|
flags: { contact: 1, charge: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, metronome: 1, nosleeptalk: 1 },
|
|
onTryHit(target, source, move) {
|
|
if (target.fainted) return false;
|
|
if (source.removeVolatile(move.id)) {
|
|
if (target !== source.volatiles['twoturnmove'].source) return false;
|
|
|
|
if (target.hasType('Flying')) {
|
|
this.add('-immune', target);
|
|
this.add('-end', target, 'Sky Drop');
|
|
return null;
|
|
}
|
|
} else {
|
|
if (target.volatiles['substitute'] || target.isAlly(source)) {
|
|
return false;
|
|
}
|
|
|
|
this.add('-prepare', source, move.name, target);
|
|
source.addVolatile('twoturnmove', target);
|
|
return null;
|
|
}
|
|
},
|
|
},
|
|
sleeppowder: {
|
|
inherit: true,
|
|
onTryHit() {},
|
|
},
|
|
smellingsalts: {
|
|
inherit: true,
|
|
basePower: 60,
|
|
},
|
|
smog: {
|
|
inherit: true,
|
|
basePower: 20,
|
|
},
|
|
snarl: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, sound: 1 },
|
|
},
|
|
snore: {
|
|
inherit: true,
|
|
basePower: 40,
|
|
flags: { protect: 1, mirror: 1, sound: 1 },
|
|
},
|
|
soak: {
|
|
inherit: true,
|
|
onHit(target) {
|
|
if (!target.setType('Water')) {
|
|
// Soak should animate even when it fails.
|
|
// Returning false would suppress the animation.
|
|
this.add('-fail', target);
|
|
return null;
|
|
}
|
|
this.add('-start', target, 'typechange', 'Water');
|
|
},
|
|
},
|
|
spore: {
|
|
inherit: true,
|
|
onTryHit() {},
|
|
},
|
|
stormthrow: {
|
|
inherit: true,
|
|
basePower: 40,
|
|
},
|
|
stringshot: {
|
|
inherit: true,
|
|
boosts: {
|
|
spe: -1,
|
|
},
|
|
},
|
|
strugglebug: {
|
|
inherit: true,
|
|
basePower: 30,
|
|
},
|
|
stunspore: {
|
|
inherit: true,
|
|
onTryHit() {},
|
|
},
|
|
substitute: {
|
|
inherit: true,
|
|
condition: {
|
|
onStart(target) {
|
|
this.add('-start', target, 'Substitute');
|
|
this.effectState.hp = Math.floor(target.maxhp / 4);
|
|
delete target.volatiles['partiallytrapped'];
|
|
},
|
|
onTryPrimaryHitPriority: -1,
|
|
onTryPrimaryHit(target, source, move) {
|
|
if (target === source || move.flags['bypasssub']) {
|
|
return;
|
|
}
|
|
let damage = this.actions.getDamage(source, target, move);
|
|
if (!damage && damage !== 0) {
|
|
this.add('-fail', source);
|
|
this.attrLastMove('[still]');
|
|
return null;
|
|
}
|
|
damage = this.runEvent('SubDamage', target, source, move, damage);
|
|
if (!damage) {
|
|
return damage;
|
|
}
|
|
if (damage > target.volatiles['substitute'].hp) {
|
|
damage = target.volatiles['substitute'].hp as number;
|
|
}
|
|
target.volatiles['substitute'].hp -= damage;
|
|
source.lastDamage = damage;
|
|
if (target.volatiles['substitute'].hp <= 0) {
|
|
if (move.ohko) this.add('-ohko');
|
|
target.removeVolatile('substitute');
|
|
} else {
|
|
this.add('-activate', target, 'Substitute', '[damage]');
|
|
}
|
|
if (move.recoil && damage) {
|
|
this.damage(this.actions.calcRecoilDamage(damage, move, source), source, target, 'recoil');
|
|
}
|
|
if (move.drain) {
|
|
this.heal(Math.ceil(damage * move.drain[0] / move.drain[1]), source, target, 'drain');
|
|
}
|
|
this.singleEvent('AfterSubDamage', move, null, target, source, move, damage);
|
|
this.runEvent('AfterSubDamage', target, source, move, damage);
|
|
return this.HIT_SUBSTITUTE;
|
|
},
|
|
onEnd(target) {
|
|
this.add('-end', target, 'Substitute');
|
|
},
|
|
},
|
|
},
|
|
submission: {
|
|
inherit: true,
|
|
pp: 25,
|
|
},
|
|
supersonic: {
|
|
inherit: true,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, metronome: 1 },
|
|
},
|
|
surf: {
|
|
inherit: true,
|
|
basePower: 95,
|
|
},
|
|
sweetkiss: {
|
|
inherit: true,
|
|
type: "Normal",
|
|
},
|
|
sweetscent: {
|
|
inherit: true,
|
|
boosts: {
|
|
evasion: -1,
|
|
},
|
|
},
|
|
swordsdance: {
|
|
inherit: true,
|
|
pp: 30,
|
|
},
|
|
synchronoise: {
|
|
inherit: true,
|
|
basePower: 70,
|
|
pp: 15,
|
|
},
|
|
tailwind: {
|
|
inherit: true,
|
|
pp: 30,
|
|
},
|
|
technoblast: {
|
|
inherit: true,
|
|
basePower: 85,
|
|
},
|
|
thief: {
|
|
inherit: true,
|
|
basePower: 40,
|
|
pp: 10,
|
|
},
|
|
thunder: {
|
|
inherit: true,
|
|
basePower: 120,
|
|
},
|
|
thunderbolt: {
|
|
inherit: true,
|
|
basePower: 95,
|
|
},
|
|
toxic: {
|
|
inherit: true,
|
|
onPrepareHit() {},
|
|
},
|
|
uproar: {
|
|
inherit: true,
|
|
flags: { protect: 1, mirror: 1, sound: 1, metronome: 1, nosleeptalk: 1 },
|
|
},
|
|
vinewhip: {
|
|
inherit: true,
|
|
basePower: 35,
|
|
pp: 15,
|
|
},
|
|
wakeupslap: {
|
|
inherit: true,
|
|
basePower: 60,
|
|
},
|
|
waterpledge: {
|
|
inherit: true,
|
|
basePower: 50,
|
|
basePowerCallback(target, source, move) {
|
|
if (['firepledge', 'grasspledge'].includes(move.sourceEffect)) {
|
|
this.add('-combine');
|
|
return 150;
|
|
}
|
|
return 50;
|
|
},
|
|
},
|
|
watersport: {
|
|
inherit: true,
|
|
pseudoWeather: undefined,
|
|
volatileStatus: 'watersport',
|
|
condition: {
|
|
noCopy: true,
|
|
onStart(pokemon) {
|
|
this.add('-start', pokemon, 'move: Water Sport');
|
|
},
|
|
onAnyBasePowerPriority: 1,
|
|
onAnyBasePower(basePower, user, target, move) {
|
|
if (move.type === 'Fire') {
|
|
this.debug('water sport weaken');
|
|
return this.chainModify([1352, 4096]);
|
|
}
|
|
},
|
|
},
|
|
},
|
|
whirlwind: {
|
|
inherit: true,
|
|
accuracy: 100,
|
|
flags: { protect: 1, reflectable: 1, mirror: 1, bypasssub: 1, metronome: 1 },
|
|
},
|
|
wideguard: {
|
|
inherit: true,
|
|
stallingMove: true,
|
|
onTry(source) {
|
|
return this.queue.willAct() && this.runEvent('StallMove', source);
|
|
},
|
|
onHitSide(side, source) {
|
|
source.addVolatile('stall');
|
|
},
|
|
},
|
|
willowisp: {
|
|
inherit: true,
|
|
accuracy: 75,
|
|
},
|
|
wonderroom: {
|
|
inherit: true,
|
|
priority: -7,
|
|
},
|
|
};
|