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, }, };