Jofthomas's picture
Jofthomas HF staff
Upload 4781 files
5c2ed06 verified
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,
},
};