Spaces:
Running
Running
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { | |
stealthrock: { | |
inherit: true, | |
condition: { | |
// this is a side condition | |
onSideStart(side, source) { | |
this.add('-sidestart', side, 'move: Stealth Rock'); | |
}, | |
onSwitchIn(pokemon) { | |
const calc = calculate(this, this.effectState.source, pokemon, 'stealthrock'); | |
if (pokemon.hasItem('heavydutyboots') || !calc) return; | |
this.damage(calc * pokemon.maxhp / 8); | |
}, | |
}, | |
}, | |
gmaxsteelsurge: { | |
inherit: true, | |
condition: { | |
// this is a side condition | |
onSideStart(side, source) { | |
this.add('-sidestart', side, 'move: G-Max Steelsurge'); | |
}, | |
onSwitchIn(pokemon) { | |
const calc = calculate(this, this.effectState.source, pokemon, 'stealthrock'); | |
if (pokemon.hasItem('heavydutyboots') || !calc) return; | |
this.damage(calc * pokemon.maxhp / 8); | |
}, | |
}, | |
}, | |
spikes: { | |
inherit: true, | |
condition: { | |
// this is a side condition | |
onSideStart(side, source) { | |
this.add('-sidestart', side, 'Spikes'); | |
this.effectState.layers = 1; | |
}, | |
onSideRestart(side, source) { | |
if (this.effectState.layers >= 3) return false; | |
this.add('-sidestart', side, 'Spikes'); | |
this.effectState.layers++; | |
}, | |
onSwitchIn(pokemon) { | |
const calc = calculate(this, this.effectState.source, pokemon, 'spikes'); | |
if (!calc || !pokemon.isGrounded() || pokemon.hasItem('heavydutyboots')) return; | |
const damageAmounts = [0, 3, 4, 6]; // 1/8, 1/6, 1/4 | |
this.damage(calc * damageAmounts[this.effectState.layers] * pokemon.maxhp / 24); | |
}, | |
}, | |
}, | |
axekick: { | |
inherit: true, | |
onMoveFail(target, source, move) { | |
const calc = calculate(this, source, source, 'axekick'); | |
if (calc) this.damage(calc * source.baseMaxhp / 2, source, source, this.dex.conditions.get('High Jump Kick')); | |
}, | |
}, | |
curse: { | |
inherit: true, | |
condition: { | |
onStart(pokemon, source) { | |
this.add('-start', pokemon, 'Curse', `[of] ${source}`); | |
}, | |
onResidualOrder: 12, | |
onResidual(pokemon) { | |
const calc = calculate(this, this.effectState.source, pokemon, 'curse'); | |
if (calc) this.damage(calc * pokemon.baseMaxhp / 4); | |
}, | |
}, | |
}, | |
firepledge: { | |
inherit: true, | |
condition: { | |
duration: 4, | |
onSideStart(targetSide, source) { | |
this.add('-sidestart', targetSide, 'Fire Pledge'); | |
}, | |
onResidualOrder: 5, | |
onResidualSubOrder: 1, | |
onResidual(pokemon) { | |
const calc = calculate(this, this.effectState.source, pokemon, 'firepledge'); | |
if (!pokemon.hasType('Fire') && calc) this.damage(calc * pokemon.baseMaxhp / 8, pokemon); | |
}, | |
onSideResidualOrder: 26, | |
onSideResidualSubOrder: 8, | |
onSideEnd(targetSide) { | |
this.add('-sideend', targetSide, 'Fire Pledge'); | |
}, | |
}, | |
}, | |
flameburst: { | |
inherit: true, | |
onHit(target, source, move) { | |
for (const ally of target.adjacentAllies()) { | |
const calc = calculate(this, source, ally, 'flameburst'); | |
if (calc) this.damage(calc * ally.baseMaxhp / 16, ally, source, this.dex.conditions.get('Flame Burst')); | |
} | |
}, | |
onAfterSubDamage(damage, target, source, move) { | |
for (const ally of target.adjacentAllies()) { | |
const calc = calculate(this, source, ally, 'flameburst'); | |
if (calc) this.damage(calc * ally.baseMaxhp / 16, ally, source, this.dex.conditions.get('Flame Burst')); | |
} | |
}, | |
}, | |
highjumpkick: { | |
inherit: true, | |
onMoveFail(target, source, move) { | |
const calc = calculate(this, source, source, 'highjumpkick'); | |
if (calc) this.damage(calc * source.baseMaxhp / 2, source, source, this.dex.conditions.get('High Jump Kick')); | |
}, | |
}, | |
jumpkick: { | |
inherit: true, | |
onMoveFail(target, source, move) { | |
const calc = calculate(this, source, source, 'jumpkick'); | |
if (calc) this.damage(calc * source.baseMaxhp / 2, source, source, this.dex.conditions.get('Jump Kick')); | |
}, | |
}, | |
leechseed: { | |
inherit: true, | |
condition: { | |
onStart(target, source) { | |
this.add('-start', target, 'move: Leech Seed'); | |
}, | |
onResidualOrder: 8, | |
onResidual(pokemon) { | |
const target = this.getAtSlot(pokemon.volatiles['leechseed'].sourceSlot); | |
if (!target || target.fainted || target.hp <= 0) { | |
this.debug('Nothing to leech into'); | |
return; | |
} | |
const calc = calculate(this, this.effectState.source, pokemon, 'leechseed'); | |
const damage = this.damage(calc * pokemon.baseMaxhp / 8, pokemon, target); | |
if (damage) { | |
this.heal(damage, target, pokemon); | |
} | |
}, | |
}, | |
}, | |
mindblown: { | |
inherit: true, | |
onAfterMove(pokemon, target, move) { | |
if (move.mindBlownRecoil && !move.multihit) { | |
const hpBeforeRecoil = pokemon.hp; | |
const calc = calculate(this, pokemon, pokemon, 'mindblown'); | |
this.damage(Math.round(calc * pokemon.maxhp / 2), pokemon, pokemon, this.dex.conditions.get('Mind Blown'), true); | |
if (pokemon.hp <= pokemon.maxhp / 2 && hpBeforeRecoil > pokemon.maxhp / 2) { | |
this.runEvent('EmergencyExit', pokemon, pokemon); | |
} | |
} | |
}, | |
}, | |
nightmare: { | |
inherit: true, | |
condition: { | |
noCopy: true, | |
onStart(pokemon, source) { | |
if (pokemon.status !== 'slp' && !pokemon.hasAbility('comatose')) { | |
return false; | |
} | |
this.add('-start', pokemon, 'Nightmare'); | |
this.effectState.source = source; | |
}, | |
onResidualOrder: 11, | |
onResidual(pokemon) { | |
const calc = calculate(this, this.effectState.source, pokemon, 'nightmare'); | |
if (calc) this.damage(calc * pokemon.baseMaxhp / 4); | |
}, | |
}, | |
}, | |
powder: { | |
inherit: true, | |
condition: { | |
duration: 1, | |
onStart(target, source) { | |
this.add('-singleturn', target, 'Powder'); | |
}, | |
onTryMovePriority: -1, | |
onTryMove(pokemon, target, move) { | |
if (move.type === 'Fire') { | |
this.add('-activate', pokemon, 'move: Powder'); | |
const calc = calculate(this, this.effectState.source, pokemon, 'powder'); | |
if (calc) this.damage(this.clampIntRange(Math.round(calc * pokemon.maxhp / 4), 1)); | |
this.attrLastMove('[still]'); | |
return false; | |
} | |
}, | |
}, | |
}, | |
saltcure: { | |
inherit: true, | |
condition: { | |
noCopy: true, | |
onStart(pokemon, source) { | |
this.add('-start', pokemon, 'Salt Cure'); | |
this.effectState.source = source; | |
}, | |
onResidualOrder: 13, | |
onResidual(pokemon) { | |
const calc = calculate(this, this.effectState.source, pokemon, 'saltcure'); | |
if (calc) this.damage(calc * pokemon.baseMaxhp / (pokemon.hasType(['Water', 'Steel']) ? 4 : 8)); | |
}, | |
onEnd(pokemon) { | |
this.add('-end', pokemon, 'Salt Cure'); | |
}, | |
}, | |
}, | |
spikyshield: { | |
inherit: true, | |
condition: { | |
duration: 1, | |
onStart(target) { | |
this.add('-singleturn', target, 'move: Protect'); | |
}, | |
onTryHitPriority: 3, | |
onTryHit(target, source, move) { | |
if (!move.flags['protect']) { | |
if (['gmaxoneblow', 'gmaxrapidflow'].includes(move.id)) return; | |
if (move.isZ || move.isMax) target.getMoveHitData(move).zBrokeProtect = true; | |
return; | |
} | |
if (move.smartTarget) { | |
move.smartTarget = false; | |
} else { | |
this.add('-activate', target, 'move: Protect'); | |
} | |
const lockedmove = source.getVolatile('lockedmove'); | |
if (lockedmove) { | |
// Outrage counter is reset | |
if (source.volatiles['lockedmove'].duration === 2) { | |
delete source.volatiles['lockedmove']; | |
} | |
} | |
const calc = calculate(this, target, source, 'spikyshield'); | |
if (this.checkMoveMakesContact(move, source, target) && calc) { | |
this.damage(calc * source.baseMaxhp / 8, source, target); | |
} | |
return this.NOT_FAIL; | |
}, | |
onHit(target, source, move) { | |
const calc = calculate(this, target, source, 'spikyshield'); | |
if (calc && move.isZOrMaxPowered && this.checkMoveMakesContact(move, source, target)) { | |
this.damage(calc * source.baseMaxhp / 8, source, target); | |
} | |
}, | |
}, | |
}, | |
steelbeam: { | |
inherit: true, | |
onAfterMove(pokemon, target, move) { | |
if (move.mindBlownRecoil && !move.multihit) { | |
const hpBeforeRecoil = pokemon.hp; | |
const calc = calculate(this, pokemon, pokemon, 'steelbeam'); | |
this.damage(Math.round(calc * pokemon.maxhp / 2), pokemon, pokemon, this.dex.conditions.get('Steel Beam'), true); | |
if (pokemon.hp <= pokemon.maxhp / 2 && hpBeforeRecoil > pokemon.maxhp / 2) { | |
this.runEvent('EmergencyExit', pokemon, pokemon); | |
} | |
} | |
}, | |
}, | |
supercellslam: { | |
inherit: true, | |
onMoveFail(target, source, move) { | |
const calc = calculate(this, source, source, 'supercellslam'); | |
if (calc) this.damage(calc * source.baseMaxhp / 2, source, source, this.dex.conditions.get('Supercell Slam')); | |
}, | |
}, | |
toxicspikes: { | |
inherit: true, | |
condition: { | |
// this is a side condition | |
onSideStart(side) { | |
this.add('-sidestart', side, 'move: Toxic Spikes'); | |
this.effectState.layers = 1; | |
}, | |
onSideRestart(side) { | |
if (this.effectState.layers >= 2) return false; | |
this.add('-sidestart', side, 'move: Toxic Spikes'); | |
this.effectState.layers++; | |
}, | |
onSwitchIn(pokemon) { | |
if (!pokemon.isGrounded()) return; | |
if (pokemon.hasType('Poison')) { | |
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', `[of] ${pokemon}`); | |
pokemon.side.removeSideCondition('toxicspikes'); | |
} else if (pokemon.hasType('Steel') || pokemon.hasItem('heavydutyboots')) { | |
// do nothing | |
} else if (this.effectState.layers >= 2) { | |
pokemon.trySetStatus('tox', this.effectState.source); | |
} else { | |
pokemon.trySetStatus('psn', this.effectState.source); | |
} | |
}, | |
}, | |
}, | |
}; | |
function calculate(battle: Battle, source: Pokemon, pokemon: Pokemon, moveid = 'tackle') { | |
const move = battle.dex.getActiveMove(moveid); | |
move.type = source.getTypes()[0]; | |
const typeMod = 2 ** battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6); | |
if (!pokemon.runImmunity(move.type)) return 0; | |
return typeMod; | |
} | |