Support inheritance of ability, item, and move conditions (#11754)
Some checks are pending
Node.js CI / build (18.x) (push) Waiting to run

This commit is contained in:
André Bastos Dias 2026-03-19 10:44:48 +00:00 committed by GitHub
parent 2dfe57c13a
commit 815b5f260a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 278 additions and 1409 deletions

View File

@ -211,22 +211,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
}, },
disable: { disable: {
num: 50, inherit: true,
accuracy: 55,
basePower: 0,
category: "Status",
name: "Disable",
pp: 20,
priority: 0,
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
volatileStatus: 'disable',
onTryHit(target) { onTryHit(target) {
// This function should not return if the checks are met. Adding && undefined ensures this happens. return target.moveSlots.some(ms => ms.pp > 0);
return target.moveSlots.some(ms => ms.pp > 0) &&
!('disable' in target.volatiles) &&
undefined;
}, },
condition: { condition: {
inherit: true,
durationCallback: undefined,
onStart(pokemon) { onStart(pokemon) {
// disable can only select moves that have pp > 0, hence the onTryHit modification // disable can only select moves that have pp > 0, hence the onTryHit modification
const moveSlot = this.sample(pokemon.moveSlots.filter(ms => ms.pp > 0)); const moveSlot = this.sample(pokemon.moveSlots.filter(ms => ms.pp > 0));
@ -235,9 +226,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
// 1-8 turns (which will in effect translate to 0-7 missed turns for the target) // 1-8 turns (which will in effect translate to 0-7 missed turns for the target)
this.effectState.time = this.random(1, 9); this.effectState.time = this.random(1, 9);
}, },
onEnd(pokemon) {
this.add('-end', pokemon, 'Disable');
},
onBeforeMovePriority: 6, onBeforeMovePriority: 6,
onBeforeMove(pokemon, target, move) { onBeforeMove(pokemon, target, move) {
pokemon.volatiles['disable'].time--; pokemon.volatiles['disable'].time--;
@ -252,17 +240,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return false; return false;
} }
}, },
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
}, },
secondary: null,
target: "normal",
type: "Normal",
}, },
dizzypunch: { dizzypunch: {
inherit: true, inherit: true,
@ -319,11 +297,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
focusenergy: { focusenergy: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon) { inherit: true,
this.add('-start', pokemon, 'move: Focus Energy');
},
// This does nothing as it's dealt with on critical hit calculation. // This does nothing as it's dealt with on critical hit calculation.
onModifyMove() {}, onModifyCritRatio() {},
}, },
}, },
glare: { glare: {
@ -408,9 +384,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
onHit() {}, onHit() {},
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'move: Leech Seed');
},
onAfterMoveSelfPriority: 1, onAfterMoveSelfPriority: 1,
onAfterMoveSelf(pokemon) { onAfterMoveSelf(pokemon) {
const leecher = this.getAtSlot(pokemon.volatiles['leechseed'].sourceSlot); const leecher = this.getAtSlot(pokemon.volatiles['leechseed'].sourceSlot);
@ -436,15 +410,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
}, },
lightscreen: { lightscreen: {
num: 113, inherit: true,
accuracy: true,
basePower: 0,
category: "Status",
name: "Light Screen",
pp: 30,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'lightscreen', volatileStatus: 'lightscreen',
sideCondition: undefined,
onTryHit(pokemon) { onTryHit(pokemon) {
if (pokemon.volatiles['lightscreen']) { if (pokemon.volatiles['lightscreen']) {
return false; return false;
@ -456,7 +424,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
}, },
target: "self", target: "self",
type: "Psychic",
}, },
metronome: { metronome: {
inherit: true, inherit: true,
@ -497,6 +464,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-start', source, 'Mimic', move.name); this.add('-start', source, 'Mimic', move.name);
}, },
}, },
minimize: {
inherit: true,
condition: {
inherit: true,
onSourceModifyDamage() {},
},
},
mirrormove: { mirrormove: {
inherit: true, inherit: true,
onHit(pokemon) { onHit(pokemon) {
@ -511,9 +485,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mist: { mist: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon) { inherit: true,
this.add('-start', pokemon, 'Mist');
},
onTryBoost(boost, target, source, effect) { onTryBoost(boost, target, source, effect) {
if (effect.effectType === 'Move' && effect.category !== 'Status') return; if (effect.effectType === 'Move' && effect.category !== 'Status') return;
if (source && target !== source) { if (source && target !== source) {
@ -629,15 +601,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
}, },
reflect: { reflect: {
num: 115, inherit: true,
accuracy: true,
basePower: 0,
category: "Status",
name: "Reflect",
pp: 20,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'reflect', volatileStatus: 'reflect',
sideCondition: undefined,
onTryHit(pokemon) { onTryHit(pokemon) {
if (pokemon.volatiles['reflect']) { if (pokemon.volatiles['reflect']) {
return false; return false;
@ -648,9 +614,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-start', pokemon, 'Reflect'); this.add('-start', pokemon, 'Reflect');
}, },
}, },
secondary: null,
target: "self", target: "self",
type: "Psychic",
}, },
rest: { rest: {
inherit: true, inherit: true,
@ -782,15 +746,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onModifyMove() {}, onModifyMove() {},
}, },
substitute: { substitute: {
num: 164, inherit: true,
accuracy: true,
basePower: 0,
category: "Status",
name: "Substitute",
pp: 10,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'substitute',
onTryHit(target) { onTryHit(target) {
if (target.volatiles['substitute']) { if (target.volatiles['substitute']) {
this.add('-fail', target, 'move: Substitute'); this.add('-fail', target, 'move: Substitute');
@ -810,11 +766,16 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
}, },
condition: { condition: {
inherit: true,
onStart(target) { onStart(target) {
this.add('-start', target, 'Substitute'); this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4) + 1; this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
delete target.volatiles['partiallytrapped']; if (target.volatiles['partiallytrapped']) {
this.add('-end', target, target.volatiles['partiallytrapped'].sourceEffect, '[partiallytrapped]', '[silent]');
delete target.volatiles['partiallytrapped'];
}
}, },
onTryPrimaryHit() {},
onTryHitPriority: -1, onTryHitPriority: -1,
onTryHit(target, source, move) { onTryHit(target, source, move) {
if (move.category === 'Status') { if (move.category === 'Status') {
@ -878,13 +839,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
return 0; return 0;
}, },
onEnd(target) {
this.add('-end', target, 'Substitute');
},
}, },
secondary: null,
target: "self",
type: "Normal",
}, },
superfang: { superfang: {
inherit: true, inherit: true,

View File

@ -13,12 +13,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
substitute: { substitute: {
inherit: true, inherit: true,
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,
onTryHit(target, source, move) { onTryHit(target, source, move) {
if (move.drain) { if (move.drain) {
this.add('-miss', source); this.add('-miss', source);
@ -76,9 +71,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
return accuracy; return accuracy;
}, },
onEnd(target) {
this.add('-end', target, 'Substitute');
},
}, },
}, },
swift: { swift: {

View File

@ -160,11 +160,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
volatileStatus: 'rage', volatileStatus: 'rage',
}, },
condition: { condition: {
inherit: true,
// Rage lock // Rage lock
onStart(target, source, effect) { onStart(target, source, effect) {
this.effectState.move = 'rage'; this.effectState.move = 'rage';
}, },
onLockMove: 'rage',
onHit(target, source, move) { onHit(target, source, move) {
if (target.boosts.atk < 6 && (move.category !== 'Status' || move.id === 'disable')) { if (target.boosts.atk < 6 && (move.category !== 'Status' || move.id === 'disable')) {
this.boost({ atk: 1 }); this.boost({ atk: 1 });
@ -220,12 +220,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
}, },
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,
onTryHit(target, source, move) { onTryHit(target, source, move) {
if (target === source) { if (target === source) {
this.debug('sub bypass: self hit'); this.debug('sub bypass: self hit');
@ -275,9 +270,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
return 0; return 0;
}, },
onEnd(target) {
this.add('-end', target, 'Substitute');
},
}, },
secondary: null, secondary: null,
target: "self", target: "self",

View File

@ -51,64 +51,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
bide: { bide: {
inherit: true, inherit: true,
condition: { condition: {
duration: 3, inherit: true,
durationCallback(target, source, effect) { durationCallback(target, source, effect) {
return this.random(3, 5); return this.random(3, 5);
}, },
onLockMove: 'bide',
onStart(pokemon) {
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onBeforeMove(pokemon, target, move) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide');
if (!this.effectState.totalDamage) {
this.add('-fail', pokemon);
return false;
}
target = this.effectState.lastDamageSource;
if (!target) {
this.add('-fail', pokemon);
return false;
}
if (!target.isActive) {
const possibleTarget = this.getRandomTarget(pokemon, this.dex.moves.get('pound'));
if (!possibleTarget) {
this.add('-miss', pokemon);
return false;
}
target = possibleTarget;
}
const moveData = {
id: 'bide',
name: "Bide",
accuracy: 100,
damage: this.effectState.totalDamage * 2,
category: "Physical",
priority: 0,
flags: { contact: 1, protect: 1 },
effectType: 'Move',
type: 'Normal',
} as unknown as ActiveMove;
this.actions.tryMoveHit(target, pokemon, moveData);
pokemon.removeVolatile('bide');
return false;
}
this.add('-activate', pokemon, 'move: Bide');
},
onMoveAborted(pokemon) {
pokemon.removeVolatile('bide');
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Bide', '[silent]');
},
}, },
}, },
counter: { counter: {
@ -139,12 +85,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
curse: { curse: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon, source) { inherit: true,
this.add('-start', pokemon, 'Curse', `[of] ${source}`); onAfterMoveSelfPriority: 0, // explicit
},
onAfterMoveSelf(pokemon) { onAfterMoveSelf(pokemon) {
this.damage(pokemon.baseMaxhp / 4); this.damage(pokemon.baseMaxhp / 4);
}, },
onResidual() {},
}, },
}, },
detect: { detect: {
@ -157,10 +103,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return source.status !== 'slp'; return source.status !== 'slp';
}, },
condition: { condition: {
duration: 2, inherit: true,
onImmunity(type, pokemon) {
if (type === 'sandstorm') return false;
},
onInvulnerability(target, source, move) { onInvulnerability(target, source, move) {
if (move.id === 'earthquake' || move.id === 'magnitude' || move.id === 'fissure') { if (move.id === 'earthquake' || move.id === 'magnitude' || move.id === 'fissure') {
return; return;
@ -172,6 +115,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return; if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
return false; return false;
}, },
onSourceModifyDamage() {},
onSourceBasePower(basePower, target, source, move) { onSourceBasePower(basePower, target, source, move) {
if (move.id === 'earthquake' || move.id === 'magnitude') { if (move.id === 'earthquake' || move.id === 'magnitude') {
return this.chainModify(2); return this.chainModify(2);
@ -186,9 +130,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
encore: { encore: {
inherit: true, inherit: true,
condition: { condition: {
durationCallback() { inherit: true,
return this.random(3, 7);
},
onStart(target) { onStart(target) {
const lockedMove = target.lastMoveEncore?.id || ''; const lockedMove = target.lastMoveEncore?.id || '';
const moveSlot = lockedMove ? target.getMoveData(lockedMove) : null; const moveSlot = lockedMove ? target.getMoveData(lockedMove) : null;
@ -199,30 +141,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.effectState.move = lockedMove; this.effectState.move = lockedMove;
this.add('-start', target, 'Encore'); this.add('-start', target, 'Encore');
}, },
onOverrideAction(pokemon) {
return this.effectState.move;
},
onResidualOrder: 13, onResidualOrder: 13,
onResidual(target) { onResidualSubOrder: undefined,
const lockedMoveSlot = target.getMoveData(this.effectState.move);
if (lockedMoveSlot && lockedMoveSlot.pp <= 0) {
// early termination if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
}, },
}, },
endure: { endure: {
@ -244,7 +164,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return source.status !== 'slp'; return source.status !== 'slp';
}, },
condition: { condition: {
duration: 2, inherit: true,
onInvulnerability(target, source, move) { onInvulnerability(target, source, move) {
if (move.id === 'gust' || move.id === 'twister' || move.id === 'thunder' || move.id === 'whirlwind') { if (move.id === 'gust' || move.id === 'twister' || move.id === 'thunder' || move.id === 'whirlwind') {
return; return;
@ -260,6 +180,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return; if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
return false; return false;
}, },
onSourceModifyDamage() {},
onSourceBasePower(basePower, target, source, move) { onSourceBasePower(basePower, target, source, move) {
if (move.id === 'gust' || move.id === 'twister') { if (move.id === 'gust' || move.id === 'twister') {
return this.chainModify(2); return this.chainModify(2);
@ -270,9 +191,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
focusenergy: { focusenergy: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon) { inherit: true,
this.add('-start', pokemon, 'move: Focus Energy');
},
onModifyCritRatio(critRatio) { onModifyCritRatio(critRatio) {
return critRatio + 1; return critRatio + 1;
}, },
@ -284,17 +203,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (target.volatiles['foresight']) return false; if (target.volatiles['foresight']) return false;
}, },
condition: { condition: {
onStart(pokemon) { inherit: true,
this.add('-start', pokemon, 'Foresight'); noCopy: false,
},
onNegateImmunity(pokemon, type) {
if (pokemon.hasType('Ghost') && ['Normal', 'Fighting'].includes(type)) return false;
},
onModifyBoost(boosts) {
if (boosts.evasion && boosts.evasion > 0) {
boosts.evasion = 0;
}
},
}, },
}, },
frustration: { frustration: {
@ -340,9 +250,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
onHit() {}, onHit() {},
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'move: Leech Seed'); onResidual() {},
},
onAfterMoveSelfPriority: 2, onAfterMoveSelfPriority: 2,
onAfterMoveSelf(pokemon) { onAfterMoveSelf(pokemon) {
if (!pokemon.hp) return; if (!pokemon.hp) return;
@ -378,10 +287,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (target.volatiles['foresight'] || target.volatiles['lockon']) return false; if (target.volatiles['foresight'] || target.volatiles['lockon']) return false;
}, },
condition: { condition: {
duration: 2, inherit: true,
onSourceAccuracy(accuracy, target, source, move) { onSourceInvulnerability() {},
if (move && source === this.effectState.target && target === this.effectState.source) return true;
},
}, },
}, },
lowkick: { lowkick: {
@ -449,15 +356,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
}, },
mist: { mist: {
num: 54, inherit: true,
accuracy: true,
basePower: 0,
category: "Status",
name: "Mist",
pp: 30,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'mist', volatileStatus: 'mist',
sideCondition: undefined,
condition: { condition: {
onStart(pokemon) { onStart(pokemon) {
this.add('-start', pokemon, 'Mist'); this.add('-start', pokemon, 'Mist');
@ -478,9 +379,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
}, },
}, },
secondary: null,
target: "self", target: "self",
type: "Ice",
}, },
moonlight: { moonlight: {
inherit: true, inherit: true,
@ -509,13 +408,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
nightmare: { nightmare: {
inherit: true, inherit: true,
condition: { condition: {
noCopy: true, inherit: true,
onStart(pokemon) { onResidual() {},
if (pokemon.status !== 'slp') {
return false;
}
this.add('-start', pokemon, 'Nightmare');
},
onAfterMoveSelfPriority: 1, onAfterMoveSelfPriority: 1,
onAfterMoveSelf(pokemon) { onAfterMoveSelf(pokemon) {
if (pokemon.status === 'slp') this.damage(pokemon.baseMaxhp / 4); if (pokemon.status === 'slp') this.damage(pokemon.baseMaxhp / 4);
@ -535,16 +429,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
perishsong: { perishsong: {
inherit: true, inherit: true,
condition: { condition: {
duration: 4, inherit: true,
onEnd(target) {
this.add('-start', target, 'perish0');
target.faint();
},
onResidualOrder: 4, onResidualOrder: 4,
onResidual(pokemon) {
const duration = pokemon.volatiles['perishsong'].duration;
this.add('-start', pokemon, `perish${duration}`);
},
}, },
}, },
petaldance: { petaldance: {
@ -584,7 +470,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
onModifyMove() {}, onModifyMove() {},
condition: { condition: {
duration: 1, inherit: true,
onBeforeSwitchOut(pokemon) { onBeforeSwitchOut(pokemon) {
this.debug('Pursuit start'); this.debug('Pursuit start');
let alreadyAdded = false; let alreadyAdded = false;
@ -684,41 +570,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
safeguard: { safeguard: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
durationCallback(target, source, effect) {
if (source?.hasAbility('persistent')) {
this.add('-activate', source, 'ability: Persistent', effect);
return 7;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (!effect || !source) return;
if (effect.id === 'yawn') return;
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if (target !== source) {
this.debug('interrupting setStatus');
if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
this.add('-activate', target, 'move: Safeguard');
}
return null;
}
},
onTryAddVolatile(status, target, source, effect) {
if (!effect || !source) return;
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if ((status.id === 'confusion' || status.id === 'yawn') && target !== source) {
if (effect.effectType === 'Move' && !effect.secondaries) this.add('-activate', target, 'move: Safeguard');
return null;
}
},
onSideStart(side) {
this.add('-sidestart', side, 'Safeguard');
},
onSideResidualOrder: 8, onSideResidualOrder: 8,
onSideEnd(side) {
this.add('-sideend', side, 'Safeguard');
},
}, },
}, },
selfdestruct: { selfdestruct: {
@ -784,31 +637,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
spikes: { spikes: {
inherit: true, inherit: true,
condition: { condition: {
// this is a side condition inherit: true,
onSideStart(side) { onSideRestart: undefined,
if (!this.effectState.layers || this.effectState.layers === 0) {
this.add('-sidestart', side, 'Spikes');
this.effectState.layers = 1;
} else {
return false;
}
},
onSwitchIn(pokemon) {
if (!pokemon.runImmunity('Ground')) return;
const damageAmounts = [0, 3];
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
},
}, },
}, },
substitute: { substitute: {
inherit: true, inherit: true,
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
onTryPrimaryHit(target, source, move) { onTryPrimaryHit(target, source, move) {
if (move.stallingMove) { if (move.stallingMove) {
this.add('-fail', source); this.add('-fail', source);
@ -861,9 +697,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.runEvent('AfterSubDamage', target, source, move, damage); this.runEvent('AfterSubDamage', target, source, move, damage);
return this.HIT_SUBSTITUTE; return this.HIT_SUBSTITUTE;
}, },
onEnd(target) {
this.add('-end', target, 'Substitute');
},
}, },
}, },
swagger: { swagger: {

View File

@ -91,6 +91,8 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}, },
}, },
lightningrod: { lightningrod: {
inherit: true,
onAnyRedirectTarget() {},
onFoeRedirectTarget(target, source, source2, move) { onFoeRedirectTarget(target, source, source2, move) {
// don't count Hidden Power as Electric-type // don't count Hidden Power as Electric-type
if (this.dex.moves.get(move.id).type !== 'Electric') return; if (this.dex.moves.get(move.id).type !== 'Electric') return;
@ -98,10 +100,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.effectState.target; return this.effectState.target;
} }
}, },
flags: { breakable: 1 },
name: "Lightning Rod",
rating: 0,
num: 32,
}, },
magnetpull: { magnetpull: {
inherit: true, inherit: true,

View File

@ -82,6 +82,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
num: 208, num: 208,
gen: 3, gen: 3,
isNonstandard: "Unobtainable", isNonstandard: "Unobtainable",
// No competitive use
}, },
fastball: { fastball: {
inherit: true, inherit: true,

View File

@ -26,10 +26,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
astonish: { astonish: {
inherit: true, inherit: true,
basePowerCallback(pokemon, target) { flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
if (target.volatiles['minimize']) return 60;
return 30;
},
}, },
beatup: { beatup: {
inherit: true, inherit: true,
@ -63,18 +60,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
accuracy: 100, accuracy: 100,
priority: 0, priority: 0,
condition: { condition: {
duration: 3, inherit: true,
onLockMove: 'bide', onAfterSetStatus() {},
onStart(pokemon) {
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onBeforeMove(pokemon, target, move) { onBeforeMove(pokemon, target, move) {
if (this.effectState.duration === 1) { if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide'); this.add('-end', pokemon, 'move: Bide');
@ -112,12 +99,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
this.add('-activate', pokemon, 'move: Bide'); this.add('-activate', pokemon, 'move: Bide');
}, },
onMoveAborted(pokemon) {
pokemon.removeVolatile('bide');
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Bide', '[silent]');
},
}, },
}, },
blizzard: { blizzard: {
@ -183,17 +164,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
counter: { counter: {
inherit: true, inherit: true,
condition: { condition: {
duration: 1, inherit: true,
noCopy: true,
onStart(target, source, move) {
this.effectState.slot = null;
this.effectState.damage = 0;
},
onRedirectTargetPriority: -1,
onRedirectTarget(target, source, source2) { onRedirectTarget(target, source, source2) {
if (source !== this.effectState.target || !this.effectState.slot) return; if (source !== this.effectState.target || !this.effectState.slot) return;
return this.getAtSlot(this.effectState.slot); return this.getAtSlot(this.effectState.slot);
}, },
onDamagingHit() {},
onDamagePriority: -101, onDamagePriority: -101,
onDamage(damage, target, source, effect) { onDamage(damage, target, source, effect) {
if ( if (
@ -227,48 +203,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
accuracy: 55, accuracy: 55,
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 }, flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
volatileStatus: 'disable',
condition: { condition: {
inherit: true,
durationCallback() { durationCallback() {
return this.random(2, 6); return this.random(2, 6);
}, },
noCopy: true, "onResidualOrder": undefined,
onStart(pokemon) { "onResidualSubOrder": undefined,
if (!this.queue.willMove(pokemon)) {
this.effectState.duration!++;
}
if (!pokemon.lastMove) {
return false;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === pokemon.lastMove.id) {
if (!moveSlot.pp) {
return false;
} else {
this.add('-start', pokemon, 'Disable', moveSlot.move);
this.effectState.move = pokemon.lastMove.id;
return;
}
}
}
return false;
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Disable');
},
onBeforeMove(attacker, defender, move) {
if (move.id === this.effectState.move) {
this.add('cant', attacker, 'Disable', move);
return false;
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
}, },
}, },
dive: { dive: {
@ -312,51 +253,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
volatileStatus: 'encore', volatileStatus: 'encore',
condition: { condition: {
inherit: true,
durationCallback() { durationCallback() {
return this.random(3, 7); return this.random(3, 7);
}, },
onStart(target, source) {
const moveSlot = target.lastMove ? target.getMoveData(target.lastMove.id) : null;
if (!target.lastMove || target.lastMove.flags['failencore'] || !moveSlot || moveSlot.pp <= 0) {
// it failed
return false;
}
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
},
onOverrideAction(pokemon) {
return this.effectState.move;
},
onResidualOrder: 10,
onResidualSubOrder: 14,
onResidual(target) {
const moveSlot = target.getMoveData(this.effectState.move);
if (moveSlot && moveSlot.pp <= 0) {
// early termination if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
}, },
}, },
extrasensory: { extrasensory: {
inherit: true, inherit: true,
basePowerCallback(pokemon, target) { flags: { protect: 1, mirror: 1, metronome: 1, minimize: 1 },
if (target.volatiles['minimize']) return 160;
return 80;
},
}, },
fakeout: { fakeout: {
inherit: true, inherit: true,
@ -401,12 +306,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
volatileStatus: undefined, volatileStatus: undefined,
slotCondition: 'followme', slotCondition: 'followme',
condition: { condition: {
duration: 1, inherit: true,
onStart(target, source, effect) { onStart(target, source, effect) {
this.add('-singleturn', target, 'move: Follow Me'); this.add('-singleturn', target, 'move: Follow Me');
this.effectState.slot = target.getSlot(); this.effectState.slot = target.getSlot();
}, },
onFoeRedirectTargetPriority: 1,
onFoeRedirectTarget(target, source, source2, move) { onFoeRedirectTarget(target, source, source2, move) {
const userSlot = this.getAtSlot(this.effectState.slot); const userSlot = this.getAtSlot(this.effectState.slot);
if (this.validTarget(userSlot, source, move.target)) { if (this.validTarget(userSlot, source, move.target)) {
@ -504,17 +408,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mirrorcoat: { mirrorcoat: {
inherit: true, inherit: true,
condition: { condition: {
duration: 1, inherit: true,
noCopy: true,
onStart(target, source, move) {
this.effectState.slot = null;
this.effectState.damage = 0;
},
onRedirectTargetPriority: -1,
onRedirectTarget(target, source, source2) { onRedirectTarget(target, source, source2) {
if (source !== this.effectState.target || !this.effectState.slot) return; if (source !== this.effectState.target || !this.effectState.slot) return;
return this.getAtSlot(this.effectState.slot); return this.getAtSlot(this.effectState.slot);
}, },
onDamagingHit() {},
onDamagePriority: -101, onDamagePriority: -101,
onDamage(damage, target, source, effect) { onDamage(damage, target, source, effect) {
if ( if (
@ -555,10 +454,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
needlearm: { needlearm: {
inherit: true, inherit: true,
basePowerCallback(pokemon, target) { flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
if (target.volatiles['minimize']) return 120;
return 60;
},
}, },
nightmare: { nightmare: {
inherit: true, inherit: true,
@ -697,28 +593,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { protect: 1, bypasssub: 1, metronome: 1 }, flags: { protect: 1, bypasssub: 1, metronome: 1 },
condition: { condition: {
inherit: true,
duration: 2, duration: 2,
onStart(target) { durationCallback: undefined,
this.add('-start', target, 'move: Taunt');
},
onResidualOrder: 10,
onResidualSubOrder: 15,
onEnd(target) { onEnd(target) {
this.add('-end', target, 'move: Taunt', '[silent]'); this.add('-end', target, 'move: Taunt', '[silent]');
}, },
onDisableMove(pokemon) { onBeforeMovePriority: undefined,
for (const moveSlot of pokemon.moveSlots) {
if (this.dex.moves.get(moveSlot.move).category === 'Status') {
pokemon.disableMove(moveSlot.id);
}
}
},
onBeforeMove(attacker, defender, move) {
if (move.category === 'Status') {
this.add('cant', attacker, 'move: Taunt', move);
return false;
}
},
}, },
}, },
teeterdance: { teeterdance: {
@ -732,37 +613,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
uproar: { uproar: {
inherit: true, inherit: true,
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'Uproar'); durationCallback() {
// 2-5 turns return this.random(2, 6);
this.effectState.duration = this.random(2, 6);
},
onResidual(target) {
if (target.volatiles['throatchop']) {
target.removeVolatile('uproar');
return;
}
if (target.lastMove && target.lastMove.id === 'struggle') {
// don't lock
delete target.volatiles['uproar'];
}
this.add('-start', target, 'Uproar', '[upkeep]');
},
onResidualOrder: 10,
onResidualSubOrder: 11,
onEnd(target) {
this.add('-end', target, 'Uproar');
},
onLockMove: 'uproar',
onAnySetStatus(status, pokemon) {
if (status.id === 'slp') {
if (pokemon === this.effectState.target) {
this.add('-fail', pokemon, 'slp', '[from] Uproar', '[msg]');
} else {
this.add('-fail', pokemon, 'slp', '[from] Uproar');
}
return null;
}
}, },
}, },
}, },

View File

@ -7,10 +7,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
inherit: true, inherit: true,
isNonstandard: "Unobtainable", isNonstandard: "Unobtainable",
}, },
enigmaberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
fastball: { fastball: {
inherit: true, inherit: true,
isNonstandard: "Unobtainable", isNonstandard: "Unobtainable",

View File

@ -23,6 +23,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onResidualSubOrder: 10, onResidualSubOrder: 10,
}, },
blaze: { blaze: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onBasePowerPriority: 2, onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) { onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Fire' && attacker.hp <= attacker.maxhp / 3) { if (move.type === 'Fire' && attacker.hp <= attacker.maxhp / 3) {
@ -30,9 +33,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5); return this.chainModify(1.5);
} }
}, },
name: "Blaze",
rating: 2,
num: 66,
}, },
cloudnine: { cloudnine: {
inherit: true, inherit: true,
@ -58,7 +58,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onSourceModifyAccuracy(accuracy) { onSourceModifyAccuracy(accuracy) {
if (typeof accuracy !== 'number') return; if (typeof accuracy !== 'number') return;
this.debug('compoundeyes - enhancing accuracy'); this.debug('compoundeyes - enhancing accuracy');
return accuracy * 1.3; return this.chainModify(1.3);
}, },
inherit: true, inherit: true,
}, },
@ -128,19 +128,15 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
} }
}, },
condition: { condition: {
noCopy: true, // doesn't get copied by Baton Pass inherit: true,
onStart(target) { onModifyAtk() {},
this.add('-start', target, 'ability: Flash Fire'); onModifySpA() {},
},
onModifyDamagePhase1(atk, attacker, defender, move) { onModifyDamagePhase1(atk, attacker, defender, move) {
if (move.type === 'Fire') { if (move.type === 'Fire') {
this.debug('Flash Fire boost'); this.debug('Flash Fire boost');
return this.chainModify(1.5); return this.chainModify(1.5);
} }
}, },
onEnd(target) {
this.add('-end', target, 'ability: Flash Fire', '[silent]');
},
}, },
}, },
flowergift: { flowergift: {
@ -200,20 +196,19 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onSourceModifyAccuracyPriority: 7, onSourceModifyAccuracyPriority: 7,
onSourceModifyAccuracy(accuracy, target, source, move) { onSourceModifyAccuracy(accuracy, target, source, move) {
if (move.category === 'Physical' && typeof accuracy === 'number') { if (move.category === 'Physical' && typeof accuracy === 'number') {
return accuracy * 0.8; return this.chainModify(0.8);
} }
}, },
}, },
hydration: { hydration: {
inherit: true,
onResidual() {},
onWeather(target, source, effect) { onWeather(target, source, effect) {
if (effect.id === 'raindance' && target.status) { if (effect.id === 'raindance' && target.status) {
this.add('-activate', target, 'ability: Hydration'); this.add('-activate', target, 'ability: Hydration');
target.cureStatus(); target.cureStatus();
} }
}, },
name: "Hydration",
rating: 1.5,
num: 93,
}, },
insomnia: { insomnia: {
inherit: true, inherit: true,
@ -270,31 +265,24 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}, },
}, },
magicguard: { magicguard: {
onDamage(damage, target, source, effect) { inherit: true,
if (effect.effectType !== 'Move') {
return false;
}
},
onSetStatus(status, target, source, effect) { onSetStatus(status, target, source, effect) {
if (effect && effect.id === 'toxicspikes') { if (effect && effect.id === 'toxicspikes') {
return false; return false;
} }
}, },
name: "Magic Guard",
rating: 4.5, rating: 4.5,
num: 98,
}, },
minus: { minus: {
inherit: true,
onModifySpAPriority: undefined,
onModifySpA(spa, pokemon) { onModifySpA(spa, pokemon) {
for (const ally of pokemon.allies()) { for (const allyActive of pokemon.allies()) {
if (ally.ability === 'plus') { if (allyActive.hasAbility('plus')) {
return spa * 1.5; return this.chainModify(1.5);
} }
} }
}, },
name: "Minus",
rating: 0,
num: 58,
}, },
naturalcure: { naturalcure: {
inherit: true, inherit: true,
@ -318,6 +306,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}, },
}, },
overgrow: { overgrow: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onBasePowerPriority: 2, onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) { onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Grass' && attacker.hp <= attacker.maxhp / 3) { if (move.type === 'Grass' && attacker.hp <= attacker.maxhp / 3) {
@ -325,26 +316,23 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5); return this.chainModify(1.5);
} }
}, },
name: "Overgrow",
rating: 2,
num: 65,
}, },
pickup: { pickup: {
name: "Pickup", inherit: true,
onResidual() {},
rating: 0, rating: 0,
num: 53, // No competitive use
}, },
plus: { plus: {
inherit: true,
onModifySpAPriority: undefined,
onModifySpA(spa, pokemon) { onModifySpA(spa, pokemon) {
for (const ally of pokemon.allies()) { for (const allyActive of pokemon.allies()) {
if (ally.ability === 'minus') { if (allyActive.hasAbility('minus')) {
return spa * 1.5; return this.chainModify(1.5);
} }
} }
}, },
name: "Plus",
rating: 0,
num: 57,
}, },
poisonpoint: { poisonpoint: {
inherit: true, inherit: true,
@ -357,16 +345,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}, },
}, },
pressure: { pressure: {
onStart(pokemon) { inherit: true,
this.add('-ability', pokemon, 'Pressure');
},
onDeductPP(target, source) { onDeductPP(target, source) {
if (target === source) return; if (target === source) return;
return 1; return 1;
}, },
name: "Pressure",
rating: 1.5, rating: 1.5,
num: 46,
}, },
roughskin: { roughskin: {
inherit: true, inherit: true,
@ -383,7 +367,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return; if (typeof accuracy !== 'number') return;
if (this.field.isWeather('sandstorm')) { if (this.field.isWeather('sandstorm')) {
this.debug('Sand Veil - decreasing accuracy'); this.debug('Sand Veil - decreasing accuracy');
return accuracy * 0.8; return this.chainModify(0.8);
} }
}, },
}, },
@ -404,16 +388,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onResidualSubOrder: 3, onResidualSubOrder: 3,
}, },
simple: { simple: {
inherit: true,
onChangeBoost() {},
onModifyBoost(boosts) { onModifyBoost(boosts) {
let key: BoostID; let key: BoostID;
for (key in boosts) { for (key in boosts) {
boosts[key]! *= 2; boosts[key]! *= 2;
} }
}, },
flags: { breakable: 1 },
name: "Simple",
rating: 4,
num: 86,
}, },
snowcloak: { snowcloak: {
inherit: true, inherit: true,
@ -422,7 +404,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return; if (typeof accuracy !== 'number') return;
if (this.field.isWeather('hail')) { if (this.field.isWeather('hail')) {
this.debug('Snow Cloak - decreasing accuracy'); this.debug('Snow Cloak - decreasing accuracy');
return accuracy * 0.8; return this.chainModify(0.8);
} }
}, },
}, },
@ -442,9 +424,10 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}, },
}, },
stench: { stench: {
name: "Stench", inherit: true,
onModifyMove() {},
rating: 0, rating: 0,
num: 1, // No competitive use
}, },
stickyhold: { stickyhold: {
inherit: true, inherit: true,
@ -466,6 +449,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
rating: 0, rating: 0,
}, },
swarm: { swarm: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onBasePowerPriority: 2, onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) { onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Bug' && attacker.hp <= attacker.maxhp / 3) { if (move.type === 'Bug' && attacker.hp <= attacker.maxhp / 3) {
@ -473,9 +459,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5); return this.chainModify(1.5);
} }
}, },
name: "Swarm",
rating: 2,
num: 68,
}, },
synchronize: { synchronize: {
inherit: true, inherit: true,
@ -495,23 +478,25 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return; if (typeof accuracy !== 'number') return;
if (target?.volatiles['confusion']) { if (target?.volatiles['confusion']) {
this.debug('Tangled Feet - decreasing accuracy'); this.debug('Tangled Feet - decreasing accuracy');
return accuracy * 0.5; return this.chainModify(0.5);
} }
}, },
}, },
thickfat: { thickfat: {
inherit: true,
onSourceModifyAtk() {},
onSourceModifySpA() {},
onSourceBasePowerPriority: 1, onSourceBasePowerPriority: 1,
onSourceBasePower(basePower, attacker, defender, move) { onSourceBasePower(basePower, attacker, defender, move) {
if (move.type === 'Ice' || move.type === 'Fire') { if (move.type === 'Ice' || move.type === 'Fire') {
return this.chainModify(0.5); return this.chainModify(0.5);
} }
}, },
flags: { breakable: 1 },
name: "Thick Fat",
rating: 3.5,
num: 47,
}, },
torrent: { torrent: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onBasePowerPriority: 2, onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) { onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Water' && attacker.hp <= attacker.maxhp / 3) { if (move.type === 'Water' && attacker.hp <= attacker.maxhp / 3) {
@ -519,9 +504,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5); return this.chainModify(1.5);
} }
}, },
name: "Torrent",
rating: 2,
num: 67,
}, },
trace: { trace: {
inherit: true, inherit: true,

View File

@ -144,7 +144,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
}, },
focussash: { focussash: {
inherit: true, inherit: true,
onDamage() { }, onDamage() {},
onTryHit(target, source, move) { onTryHit(target, source, move) {
if (target !== source && target.hp === target.maxhp) { if (target !== source && target.hp === target.maxhp) {
target.addVolatile('focussash'); target.addVolatile('focussash');
@ -306,11 +306,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
metronome: { metronome: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon) { inherit: true,
this.effectState.numConsecutive = 0;
this.effectState.lastMove = '';
},
onTryMovePriority: -2,
onTryMove(pokemon, target, move) { onTryMove(pokemon, target, move) {
if (!pokemon.hasItem('metronome')) { if (!pokemon.hasItem('metronome')) {
pokemon.removeVolatile('metronome'); pokemon.removeVolatile('metronome');
@ -323,6 +319,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
} }
this.effectState.lastMove = move.id; this.effectState.lastMove = move.id;
}, },
onModifyDamage() {},
onModifyDamagePhase2(damage, source, target, move) { onModifyDamagePhase2(damage, source, target, move) {
return damage * (1 + (this.effectState.numConsecutive / 10)); return damage * (1 + (this.effectState.numConsecutive / 10));
}, },
@ -331,7 +328,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
micleberry: { micleberry: {
inherit: true, inherit: true,
condition: { condition: {
duration: 2, inherit: true,
onSourceModifyAccuracyPriority: 3, onSourceModifyAccuracyPriority: 3,
onSourceModifyAccuracy(accuracy, target, source) { onSourceModifyAccuracy(accuracy, target, source) {
this.add('-enditem', source, 'Micle Berry'); this.add('-enditem', source, 'Micle Berry');

View File

@ -37,14 +37,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { metronome: 1 }, flags: { metronome: 1 },
condition: { condition: {
onStart(pokemon) { inherit: true,
this.add('-start', pokemon, 'Aqua Ring');
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 2, onResidualSubOrder: 2,
onResidual(pokemon) {
this.heal(pokemon.baseMaxhp / 16);
},
}, },
}, },
assist: { assist: {
@ -109,18 +104,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
bide: { bide: {
inherit: true, inherit: true,
condition: { condition: {
duration: 3, inherit: true,
onLockMove: 'bide',
onStart(pokemon) {
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onAfterSetStatus(status, pokemon) { onAfterSetStatus(status, pokemon) {
if (status.id === 'slp' || status.id === 'frz') { if (status.id === 'slp' || status.id === 'frz') {
pokemon.removeVolatile('bide'); pokemon.removeVolatile('bide');
@ -164,12 +148,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
this.add('-activate', pokemon, 'move: Bide'); this.add('-activate', pokemon, 'move: Bide');
}, },
onMoveAborted(pokemon) {
pokemon.removeVolatile('bide');
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Bide', '[silent]');
},
}, },
}, },
bind: { bind: {
@ -303,14 +281,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
}, },
condition: { condition: {
onStart(pokemon, source) { inherit: true,
this.add('-start', pokemon, 'Curse', `[of] ${source}`);
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 8, onResidualSubOrder: 8,
onResidual(pokemon) {
this.damage(pokemon.baseMaxhp / 4);
},
}, },
type: "???", type: "???",
}, },
@ -321,36 +294,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
detect: { detect: {
inherit: true, inherit: true,
priority: 3, priority: 3,
condition: {
duration: 1,
onStart(target) {
this.add('-singleturn', target, 'Protect');
},
onTryHitPriority: 3,
onTryHit(target, source, move) {
if (!move.flags['protect']) return;
this.add('-activate', target, 'Protect');
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is NOT reset
if (source.volatiles['lockedmove'].trueDuration >= 2) {
source.volatiles['lockedmove'].duration = 2;
}
}
return null;
},
},
}, },
disable: { disable: {
inherit: true, inherit: true,
accuracy: 80, accuracy: 80,
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 }, flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
volatileStatus: 'disable',
condition: { condition: {
inherit: true,
duration: undefined,
durationCallback() { durationCallback() {
return this.random(4, 8); return this.random(4, 8);
}, },
noCopy: true,
onStart(pokemon) { onStart(pokemon) {
if (!this.queue.willMove(pokemon)) { if (!this.queue.willMove(pokemon)) {
this.effectState.duration!++; this.effectState.duration!++;
@ -373,23 +327,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 13, onResidualSubOrder: 13,
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Disable');
},
onBeforeMovePriority: 7,
onBeforeMove(attacker, defender, move) {
if (move.id === this.effectState.move) {
this.add('cant', attacker, 'Disable', move);
return false;
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
}, },
}, },
doomdesire: { doomdesire: {
@ -451,16 +388,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
}, },
condition: { condition: {
duration: 5, inherit: true,
onStart(pokemon) {
this.add('-start', pokemon, 'Embargo');
},
// Item suppression implemented in Pokemon.ignoringItem() within sim/pokemon.js
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 18, onResidualSubOrder: 18,
onEnd(pokemon) {
this.add('-end', pokemon, 'Embargo');
},
}, },
}, },
encore: { encore: {
@ -468,43 +398,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1, failencore: 1 }, flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1, failencore: 1 },
volatileStatus: 'encore', volatileStatus: 'encore',
condition: { condition: {
inherit: true,
duration: undefined,
durationCallback() { durationCallback() {
return this.random(4, 9); return this.random(4, 9);
}, },
onStart(target, source) {
const moveSlot = target.lastMove ? target.getMoveData(target.lastMove.id) : null;
if (!target.lastMove || target.lastMove.flags['failencore'] || !moveSlot || moveSlot.pp <= 0) {
// it failed
return false;
}
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
},
onOverrideAction(pokemon) {
return this.effectState.move;
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 14, onResidualSubOrder: 14,
onResidual(target) {
const moveSlot = target.getMoveData(this.effectState.move);
if (moveSlot && moveSlot.pp <= 0) {
// early termination if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
}, },
}, },
endeavor: { endeavor: {
@ -619,10 +519,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
basePower: 10, basePower: 10,
condition: { condition: {
duration: 2, inherit: true,
onStart() {
this.effectState.multiplier = 1;
},
onRestart() { onRestart() {
if (this.effectState.multiplier < 16) { if (this.effectState.multiplier < 16) {
this.effectState.multiplier <<= 1; this.effectState.multiplier <<= 1;
@ -678,77 +575,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
gravity: { gravity: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
durationCallback(source, effect) {
if (source?.hasAbility('persistent')) {
this.add('-activate', source, 'ability: Persistent', '[move] Gravity');
return 7;
}
return 5;
},
onFieldStart(target, source) {
if (source?.hasAbility('persistent')) {
this.add('-fieldstart', 'move: Gravity', '[persistent]');
} else {
this.add('-fieldstart', 'move: Gravity');
}
for (const pokemon of this.getAllActive()) {
let applies = false;
if (pokemon.removeVolatile('bounce') || pokemon.removeVolatile('fly')) {
applies = true;
this.queue.cancelMove(pokemon);
pokemon.removeVolatile('twoturnmove');
}
if (pokemon.volatiles['skydrop']) {
applies = true;
this.queue.cancelMove(pokemon);
if (pokemon.volatiles['skydrop'].source) {
this.add('-end', pokemon.volatiles['twoturnmove'].source, 'Sky Drop', '[interrupt]');
}
pokemon.removeVolatile('skydrop');
pokemon.removeVolatile('twoturnmove');
}
if (pokemon.volatiles['magnetrise']) {
applies = true;
delete pokemon.volatiles['magnetrise'];
}
if (pokemon.volatiles['telekinesis']) {
applies = true;
delete pokemon.volatiles['telekinesis'];
}
if (applies) this.add('-activate', pokemon, 'move: Gravity');
}
},
onModifyAccuracy(accuracy) {
if (typeof accuracy !== 'number') return;
return this.chainModify([6840, 4096]);
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (this.dex.moves.get(moveSlot.id).flags['gravity']) {
pokemon.disableMove(moveSlot.id);
}
}
},
// groundedness implemented in battle.engine.js:BattlePokemon#isGrounded
onBeforeMovePriority: 6,
onBeforeMove(pokemon, target, move) {
if (move.flags['gravity'] && !move.isZ) {
this.add('cant', pokemon, 'move: Gravity', move);
return false;
}
},
onModifyMove(move, pokemon, target) {
if (move.flags['gravity'] && !move.isZ) {
this.add('cant', pokemon, 'move: Gravity', move);
return false;
}
},
onFieldResidualOrder: 9, onFieldResidualOrder: 9,
onFieldEnd() { onFieldResidualSubOrder: undefined,
this.add('-fieldend', 'move: Gravity');
},
}, },
}, },
growth: { growth: {
@ -786,36 +615,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { protect: 1, mirror: 1, metronome: 1 }, flags: { protect: 1, mirror: 1, metronome: 1 },
condition: { condition: {
duration: 5, inherit: true,
durationCallback(target, source, effect) {
if (source?.hasAbility('persistent')) {
this.add('-activate', source, 'ability: Persistent', '[move] Heal Block');
return 7;
}
return 5;
},
onStart(pokemon) {
this.add('-start', pokemon, 'move: Heal Block');
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (this.dex.moves.get(moveSlot.id).flags['heal']) {
pokemon.disableMove(moveSlot.id);
}
}
},
onBeforeMovePriority: 6,
onBeforeMove(pokemon, target, move) {
if (move.flags['heal']) {
this.add('cant', pokemon, 'move: Heal Block', move);
return false;
}
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 17, onResidualSubOrder: 17,
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Heal Block');
},
onTryHeal(damage, pokemon, source, effect) { onTryHeal(damage, pokemon, source, effect) {
if (effect && (effect.id === 'drain' || effect.id === 'leechseed' || effect.id === 'wish')) { if (effect && (effect.id === 'drain' || effect.id === 'leechseed' || effect.id === 'wish')) {
return false; return false;
@ -875,22 +677,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
ingrain: { ingrain: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon) { inherit: true,
this.add('-start', pokemon, 'move: Ingrain');
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 1, onResidualSubOrder: 1,
onResidual(pokemon) {
this.heal(pokemon.baseMaxhp / 16);
},
onTrapPokemon(pokemon) {
pokemon.tryTrap();
},
// groundedness implemented in battle.engine.js:BattlePokemon#isGrounded
onDragOut(pokemon) {
this.add('-activate', pokemon, 'move: Ingrain');
return null;
},
}, },
}, },
jumpkick: { jumpkick: {
@ -925,34 +714,16 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
leechseed: { leechseed: {
inherit: true, inherit: true,
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'move: Leech Seed');
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 5, onResidualSubOrder: 5,
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 damage = this.damage(pokemon.baseMaxhp / 8, pokemon, target);
if (damage) {
this.heal(damage, target, pokemon);
}
},
}, },
}, },
lightscreen: { lightscreen: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
durationCallback(target, source, effect) { onAnyModifyDamage() {},
if (source?.hasItem('lightclay')) {
return 8;
}
return 5;
},
onAnyModifyDamagePhase1(damage, source, target, move) { onAnyModifyDamagePhase1(damage, source, target, move) {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') { if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) { if (!target.getMoveHitData(move).crit && !move.infiltrates) {
@ -962,41 +733,24 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
} }
}, },
onSideStart(side) {
this.add('-sidestart', side, 'Light Screen');
},
onSideResidualOrder: 2, onSideResidualOrder: 2,
onSideEnd(side) { onSideResidualSubOrder: undefined,
this.add('-sideend', side, 'Light Screen');
},
}, },
}, },
lockon: { lockon: {
inherit: true, inherit: true,
condition: { condition: {
duration: 2, inherit: true,
onSourceInvulnerabilityPriority: 1, noCopy: false,
onSourceInvulnerability(target, source, move) {
if (move && source === this.effectState.target && target === this.effectState.source) return 0;
},
onSourceAccuracy(accuracy, target, source, move) {
if (move && source === this.effectState.target && target === this.effectState.source) return true;
},
}, },
}, },
luckychant: { luckychant: {
inherit: true, inherit: true,
flags: { metronome: 1 }, flags: { metronome: 1 },
condition: { condition: {
duration: 5, inherit: true,
onSideStart(side) {
this.add('-sidestart', side, 'move: Lucky Chant');
},
onCriticalHit: false,
onSideResidualOrder: 6, onSideResidualOrder: 6,
onSideEnd(side) { onSideResidualSubOrder: undefined,
this.add('-sideend', side, 'move: Lucky Chant');
},
}, },
}, },
lunardance: { lunardance: {
@ -1033,8 +787,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
magiccoat: { magiccoat: {
inherit: true, inherit: true,
condition: { condition: {
duration: 1, inherit: true,
onTryHitPriority: 2,
onTryHit(target, source, move) { onTryHit(target, source, move) {
if (target === source || move.hasBounced || !move.flags['reflectable']) { if (target === source || move.hasBounced || !move.flags['reflectable']) {
return; return;
@ -1045,6 +798,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.actions.useMove(newMove, target, { target: source }); this.actions.useMove(newMove, target, { target: source });
return null; return null;
}, },
onAllyTryHitSide() {},
}, },
}, },
magmastorm: { magmastorm: {
@ -1056,25 +810,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
flags: { gravity: 1, metronome: 1 }, flags: { gravity: 1, metronome: 1 },
volatileStatus: 'magnetrise', volatileStatus: 'magnetrise',
condition: { condition: {
duration: 5, inherit: true,
onStart(target) { onStart(target) {
if (target.volatiles['ingrain'] || target.ability === 'levitate') return false; if (target.volatiles['ingrain'] || target.ability === 'levitate') return false;
this.add('-start', target, 'Magnet Rise'); this.add('-start', target, 'Magnet Rise');
}, },
onImmunity(type) {
if (type === 'Ground') return false;
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 16, onResidualSubOrder: 16,
onEnd(target) {
this.add('-end', target, 'Magnet Rise');
},
}, },
}, },
mefirst: { mefirst: {
inherit: true, inherit: true,
condition: { condition: {
duration: 1, inherit: true,
onBasePower() {},
onModifyDamagePhase2(damage) { onModifyDamagePhase2(damage) {
return damage * 1.5; return damage * 1.5;
}, },
@ -1162,30 +911,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mist: { mist: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
onTryBoost(boost, target, source, effect) {
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if (source && target !== source) {
let showMsg = false;
let i: BoostID;
for (i in boost) {
if (boost[i]! < 0) {
delete boost[i];
showMsg = true;
}
}
if (showMsg && !(effect as ActiveMove).secondaries) {
this.add('-activate', target, 'move: Mist');
}
}
},
onSideStart(side) {
this.add('-sidestart', side, 'Mist');
},
onSideResidualOrder: 3, onSideResidualOrder: 3,
onSideEnd(side) { onSideResidualSubOrder: undefined,
this.add('-sideend', side, 'Mist');
},
}, },
}, },
moonlight: { moonlight: {
@ -1215,9 +943,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mudsport: { mudsport: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon) { inherit: true,
this.add('-start', pokemon, 'move: Mud Sport'); noCopy: false,
},
onAnyBasePowerPriority: 3, onAnyBasePowerPriority: 3,
onAnyBasePower(basePower, user, target, move) { onAnyBasePower(basePower, user, target, move) {
if (move.type === 'Electric') { if (move.type === 'Electric') {
@ -1237,18 +964,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
nightmare: { nightmare: {
inherit: true, inherit: true,
condition: { condition: {
noCopy: true, inherit: true,
onStart(pokemon) {
if (pokemon.status !== 'slp' && !pokemon.hasAbility('comatose')) {
return false;
}
this.add('-start', pokemon, 'Nightmare');
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 7, onResidualSubOrder: 7,
onResidual(pokemon) {
this.damage(pokemon.baseMaxhp / 4);
},
}, },
}, },
odorsleuth: { odorsleuth: {
@ -1278,16 +996,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
perishsong: { perishsong: {
inherit: true, inherit: true,
condition: { condition: {
duration: 4, inherit: true,
onEnd(target) {
this.add('-start', target, 'perish0');
target.faint();
},
onResidualOrder: 12, onResidualOrder: 12,
onResidual(pokemon) {
const duration = pokemon.volatiles['perishsong'].duration;
this.add('-start', pokemon, `perish${duration}`);
},
}, },
}, },
petaldance: { petaldance: {
@ -1308,11 +1018,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
priority: 3, priority: 3,
condition: { condition: {
duration: 1, inherit: true,
onStart(target) {
this.add('-singleturn', target, 'Protect');
},
onTryHitPriority: 3,
onTryHit(target, source, move) { onTryHit(target, source, move) {
if (!move.flags['protect']) return; if (!move.flags['protect']) return;
this.add('-activate', target, 'Protect'); this.add('-activate', target, 'Protect');
@ -1346,7 +1052,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
}, },
condition: { condition: {
duration: 1, inherit: true,
onBeforeSwitchOut(pokemon) { onBeforeSwitchOut(pokemon) {
this.debug('Pursuit start'); this.debug('Pursuit start');
let alreadyAdded = false; let alreadyAdded = false;
@ -1403,13 +1109,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
reflect: { reflect: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
durationCallback(target, source, effect) { onAnyModifyDamage() {},
if (source?.hasItem('lightclay')) {
return 8;
}
return 5;
},
onAnyModifyDamagePhase1(damage, source, target, move) { onAnyModifyDamagePhase1(damage, source, target, move) {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') { if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) { if (!target.getMoveHitData(move).crit && !move.infiltrates) {
@ -1419,13 +1120,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
} }
}, },
onSideStart(side) {
this.add('-sidestart', side, 'Reflect');
},
onSideResidualOrder: 1, onSideResidualOrder: 1,
onSideEnd(side) { onSideResidualSubOrder: undefined,
this.add('-sideend', side, 'Reflect');
},
}, },
}, },
reversal: { reversal: {
@ -1470,45 +1166,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
safeguard: { safeguard: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
durationCallback(target, source, effect) {
if (source?.hasAbility('persistent')) {
this.add('-activate', source, 'ability: Persistent', '[move] Safeguard');
return 7;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (!effect || !source) return;
if (effect.id === 'yawn') return;
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if (target !== source) {
this.debug('interrupting setStatus');
if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
this.add('-activate', target, 'move: Safeguard');
}
return null;
}
},
onTryAddVolatile(status, target, source, effect) {
if (!effect || !source) return;
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if ((status.id === 'confusion' || status.id === 'yawn') && target !== source) {
if (effect.effectType === 'Move' && !effect.secondaries) this.add('-activate', target, 'move: Safeguard');
return null;
}
},
onSideStart(side, source) {
if (source?.hasAbility('persistent')) {
this.add('-sidestart', side, 'Safeguard', '[persistent]');
} else {
this.add('-sidestart', side, 'Safeguard');
}
},
onSideResidualOrder: 4, onSideResidualOrder: 4,
onSideEnd(side) { onSideResidualSubOrder: undefined,
this.add('-sideend', side, 'Safeguard');
},
}, },
}, },
sandtomb: { sandtomb: {
@ -1566,11 +1226,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { bypasssub: 1, noassist: 1, failcopycat: 1 }, flags: { bypasssub: 1, noassist: 1, failcopycat: 1 },
condition: { condition: {
duration: 1, inherit: true,
onStart(pokemon) {
this.add('-singleturn', pokemon, 'Snatch');
},
onAnyPrepareHitPriority: -1,
onAnyPrepareHit(source, target, move) { onAnyPrepareHit(source, target, move) {
const snatchUser = this.effectState.source; const snatchUser = this.effectState.source;
if (snatchUser.isSkyDropped()) return; if (snatchUser.isSkyDropped()) return;
@ -1594,16 +1250,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { metronome: 1, mustpressure: 1 }, flags: { metronome: 1, mustpressure: 1 },
condition: { condition: {
// this is a side condition inherit: true,
onSideStart(side) { onSwitchIn() {},
this.add('-sidestart', side, 'Spikes');
this.effectState.layers = 1;
},
onSideRestart(side) {
if (this.effectState.layers >= 3) return false;
this.add('-sidestart', side, 'Spikes');
this.effectState.layers++;
},
onEntryHazard(pokemon) { onEntryHazard(pokemon) {
if (!pokemon.isGrounded() || pokemon.hasItem('heavydutyboots')) return; if (!pokemon.isGrounded() || pokemon.hasItem('heavydutyboots')) return;
const damageAmounts = [0, 3, 4, 6]; // 1/8, 1/6, 1/4 const damageAmounts = [0, 3, 4, 6]; // 1/8, 1/6, 1/4
@ -1619,10 +1267,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { metronome: 1, mustpressure: 1 }, flags: { metronome: 1, mustpressure: 1 },
condition: { condition: {
// this is a side condition inherit: true,
onSideStart(side) { onSwitchIn() {},
this.add('-sidestart', side, 'move: Stealth Rock');
},
onEntryHazard(pokemon) { onEntryHazard(pokemon) {
if (pokemon.hasItem('heavydutyboots')) return; if (pokemon.hasItem('heavydutyboots')) return;
const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6); const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6);
@ -1643,12 +1289,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
substitute: { substitute: {
inherit: true, inherit: true,
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
onTryPrimaryHit(target, source, move) { onTryPrimaryHit(target, source, move) {
if (target === source || move.flags['bypasssub']) { if (target === source || move.flags['bypasssub']) {
return; return;
@ -1681,9 +1322,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.runEvent('AfterSubDamage', target, source, move, damage); this.runEvent('AfterSubDamage', target, source, move, damage);
return this.HIT_SUBSTITUTE; return this.HIT_SUBSTITUTE;
}, },
onEnd(target) {
this.add('-end', target, 'Substitute');
},
}, },
}, },
suckerpunch: { suckerpunch: {
@ -1735,6 +1373,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
tailwind: { tailwind: {
inherit: true, inherit: true,
condition: { condition: {
inherit: true,
duration: 3, duration: 3,
durationCallback(target, source, effect) { durationCallback(target, source, effect) {
if (source?.hasAbility('persistent')) { if (source?.hasAbility('persistent')) {
@ -1743,26 +1382,19 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
return 3; return 3;
}, },
onSideStart(side, source) {
if (source?.hasAbility('persistent')) {
this.add('-sidestart', side, 'move: Tailwind', '[persistent]');
} else {
this.add('-sidestart', side, 'move: Tailwind');
}
},
onModifySpe(spe) { onModifySpe(spe) {
return spe * 2; return spe * 2;
}, },
onSideResidualOrder: 5, onSideResidualOrder: 5,
onSideEnd(side) { onSideResidualSubOrder: undefined,
this.add('-sideend', side, 'move: Tailwind');
},
}, },
}, },
taunt: { taunt: {
inherit: true, inherit: true,
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 }, flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
condition: { condition: {
inherit: true,
duration: undefined,
durationCallback() { durationCallback() {
return this.random(3, 6); return this.random(3, 6);
}, },
@ -1771,9 +1403,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 15, onResidualSubOrder: 15,
onEnd(target) {
this.add('-end', target, 'move: Taunt');
},
onDisableMove(pokemon) { onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) { for (const moveSlot of pokemon.moveSlots) {
if (this.dex.moves.get(moveSlot.id).category === 'Status') { if (this.dex.moves.get(moveSlot.id).category === 'Status') {
@ -1807,16 +1436,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { metronome: 1, mustpressure: 1 }, flags: { metronome: 1, mustpressure: 1 },
condition: { condition: {
// this is a side condition inherit: true,
onSideStart(side) { onSwitchIn() {},
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++;
},
onEntryHazard(pokemon) { onEntryHazard(pokemon) {
if (!pokemon.isGrounded()) return; if (!pokemon.isGrounded()) return;
if (pokemon.hasType('Poison')) { if (pokemon.hasType('Poison')) {
@ -1846,67 +1467,22 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
trickroom: { trickroom: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
durationCallback(source, effect) {
if (source?.hasAbility('persistent')) {
this.add('-activate', source, 'ability: Persistent', '[move] Trick Room');
return 7;
}
return 5;
},
onFieldStart(target, source) {
if (source?.hasAbility('persistent')) {
this.add('-fieldstart', 'move: Trick Room', `[of] ${source}`, '[persistent]');
} else {
this.add('-fieldstart', 'move: Trick Room', `[of] ${source}`);
}
},
onFieldRestart(target, source) {
this.field.removePseudoWeather('trickroom');
},
// Speed modification is changed in Pokemon.getActionSpeed() in sim/pokemon.js
onFieldResidualOrder: 13, onFieldResidualOrder: 13,
onFieldEnd() { onFieldResidualSubOrder: undefined,
this.add('-fieldend', 'move: Trick Room');
},
}, },
}, },
uproar: { uproar: {
inherit: true, inherit: true,
basePower: 50, basePower: 50,
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'Uproar'); duration: undefined,
// 3-6 turns durationCallback() {
this.effectState.duration = this.random(3, 7); return this.random(3, 7);
},
onResidual(target) {
if (target.volatiles['throatchop']) {
target.removeVolatile('uproar');
return;
}
if (target.lastMove && target.lastMove.id === 'struggle') {
// don't lock
delete target.volatiles['uproar'];
}
this.add('-start', target, 'Uproar', '[upkeep]');
}, },
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 11, onResidualSubOrder: 11,
onEnd(target) {
this.add('-end', target, 'Uproar');
},
onLockMove: 'uproar',
onAnySetStatus(status, pokemon) {
if (status.id === 'slp') {
if (pokemon === this.effectState.target) {
this.add('-fail', pokemon, 'slp', '[from] Uproar', '[msg]');
} else {
this.add('-fail', pokemon, 'slp', '[from] Uproar');
}
return null;
}
},
}, },
}, },
volttackle: { volttackle: {
@ -1916,9 +1492,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
watersport: { watersport: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon) { inherit: true,
this.add('-start', pokemon, 'move: Water Sport'); noCopy: false,
},
onAnyBasePowerPriority: 3, onAnyBasePowerPriority: 3,
onAnyBasePower(basePower, user, target, move) { onAnyBasePower(basePower, user, target, move) {
if (move.type === 'Fire') { if (move.type === 'Fire') {
@ -1981,17 +1556,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
yawn: { yawn: {
inherit: true, inherit: true,
condition: { condition: {
noCopy: true, // doesn't get copied by Baton Pass inherit: true,
duration: 2,
onStart(target, source) {
this.add('-start', target, 'move: Yawn', `[of] ${source}`);
},
onResidualOrder: 10, onResidualOrder: 10,
onResidualSubOrder: 19, onResidualSubOrder: 19,
onEnd(target) {
this.add('-end', target, 'move: Yawn', '[silent]');
target.trySetStatus('slp', this.effectState.source);
},
}, },
}, },
}; };

View File

@ -36,8 +36,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
autotomize: { autotomize: {
inherit: true, inherit: true,
volatileStatus: 'autotomize', volatileStatus: 'autotomize',
onHit(pokemon) { onHit() {},
},
condition: { condition: {
noCopy: true, // doesn't get copied by Baton Pass noCopy: true, // doesn't get copied by Baton Pass
onStart(pokemon) { onStart(pokemon) {
@ -78,6 +77,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { protect: 1, reflectable: 1, mirror: 1, metronome: 1 }, flags: { protect: 1, reflectable: 1, mirror: 1, metronome: 1 },
}, },
bodyslam: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
},
bounce: { bounce: {
inherit: true, inherit: true,
flags: { contact: 1, charge: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, metronome: 1, nosleeptalk: 1 }, flags: { contact: 1, charge: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, metronome: 1, nosleeptalk: 1 },
@ -192,6 +195,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, punch: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, punch: 1, metronome: 1 },
}, },
dragonrush: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
},
dreameater: { dreameater: {
inherit: true, inherit: true,
flags: { protect: 1, mirror: 1, metronome: 1 }, flags: { protect: 1, mirror: 1, metronome: 1 },
@ -260,10 +267,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
basePower: 20, basePower: 20,
condition: { condition: {
duration: 2, inherit: true,
onStart() {
this.effectState.multiplier = 1;
},
onRestart() { onRestart() {
if (this.effectState.multiplier < 8) { if (this.effectState.multiplier < 8) {
this.effectState.multiplier <<= 1; this.effectState.multiplier <<= 1;
@ -363,6 +367,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return success; return success;
}, },
}, },
heatcrash: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
},
heatwave: { heatwave: {
inherit: true, inherit: true,
basePower: 100, basePower: 100,
@ -494,13 +502,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
lightscreen: { lightscreen: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
durationCallback(target, source, effect) {
if (source?.hasItem('lightclay')) {
return 8;
}
return 5;
},
onAnyModifyDamage(damage, source, target, move) { onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') { if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) { if (!target.getMoveHitData(move).crit && !move.infiltrates) {
@ -510,14 +512,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
} }
}, },
onSideStart(side) {
this.add('-sidestart', side, 'move: Light Screen');
},
onSideResidualOrder: 26,
onSideResidualSubOrder: 2,
onSideEnd(side) {
this.add('-sideend', side, 'move: Light Screen');
},
}, },
}, },
lowsweep: { lowsweep: {
@ -527,24 +521,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
magiccoat: { magiccoat: {
inherit: true, inherit: true,
condition: { condition: {
duration: 1, inherit: true,
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) { onAllyTryHitSide(target, source, move) {
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable']) { if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable']) {
return; return;
@ -587,12 +564,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
pp: 20, pp: 20,
condition: { condition: {
noCopy: true, inherit: true,
onSourceModifyDamage(damage, source, target, move) { onAccuracy() {},
if (['stomp', 'steamroller'].includes(move.id)) {
return this.chainModify(2);
}
},
}, },
}, },
moonlight: { moonlight: {
@ -689,11 +662,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
source.addVolatile('stall'); source.addVolatile('stall');
}, },
condition: { condition: {
duration: 1, inherit: true,
onSideStart(target, source) {
this.add('-singleturn', source, 'Quick Guard');
},
onTryHitPriority: 4,
onTryHit(target, source, effect) { onTryHit(target, source, effect) {
// Quick Guard only blocks moves with a natural positive priority // Quick Guard only blocks moves with a natural positive priority
// (e.g. it doesn't block 0 priority moves boosted by Prankster) // (e.g. it doesn't block 0 priority moves boosted by Prankster)
@ -720,13 +689,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
reflect: { reflect: {
inherit: true, inherit: true,
condition: { condition: {
duration: 5, inherit: true,
durationCallback(target, source, effect) {
if (source?.hasItem('lightclay')) {
return 8;
}
return 5;
},
onAnyModifyDamage(damage, source, target, move) { onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') { if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) { if (!target.getMoveHitData(move).crit && !move.infiltrates) {
@ -736,14 +699,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} }
} }
}, },
onSideStart(side) {
this.add('-sidestart', side, 'Reflect');
},
onSideResidualOrder: 26,
onSideResidualSubOrder: 1,
onSideEnd(side) {
this.add('-sideend', side, 'Reflect');
},
}, },
}, },
relicsong: { relicsong: {
@ -881,12 +836,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
substitute: { substitute: {
inherit: true, inherit: true,
condition: { condition: {
onStart(target) { inherit: true,
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
onTryPrimaryHit(target, source, move) { onTryPrimaryHit(target, source, move) {
if (target === source || move.flags['bypasssub']) { if (target === source || move.flags['bypasssub']) {
return; return;
@ -918,9 +868,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.runEvent('AfterSubDamage', target, source, move, damage); this.runEvent('AfterSubDamage', target, source, move, damage);
return this.HIT_SUBSTITUTE; return this.HIT_SUBSTITUTE;
}, },
onEnd(target) {
this.add('-end', target, 'Substitute');
},
}, },
}, },
submission: { submission: {

View File

@ -34,48 +34,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}, },
}, },
}, },
encore: {
inherit: true,
condition: {
duration: 3,
onStart(target) {
const moveSlot = target.lastMove ? target.getMoveData(target.lastMove.id) : null;
if (!target.lastMove || target.lastMove.flags['failencore'] || !moveSlot || moveSlot.pp <= 0) {
// it failed
return false;
}
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
if (!this.queue.willMove(target)) {
this.effectState.duration!++;
}
},
onOverrideAction(pokemon, target, move) {
if (move.id !== this.effectState.move) return this.effectState.move;
},
onResidualOrder: 16,
onResidual(target) {
const lockedMoveSlot = target.getMoveData(this.effectState.move);
if (lockedMoveSlot && lockedMoveSlot.pp <= 0) {
// Encore ends early if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
},
fellstinger: { fellstinger: {
inherit: true, inherit: true,
basePower: 30, basePower: 30,
@ -87,6 +45,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
basePower: 80, basePower: 80,
}, },
heavyslam: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
},
leechlife: { leechlife: {
inherit: true, inherit: true,
basePower: 20, basePower: 20,
@ -96,29 +58,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true, inherit: true,
flags: { protect: 1, bypasssub: 1, noassist: 1, failcopycat: 1, failmefirst: 1, nosleeptalk: 1 }, flags: { protect: 1, bypasssub: 1, noassist: 1, failcopycat: 1, failmefirst: 1, nosleeptalk: 1 },
}, },
minimize: {
inherit: true,
condition: {
noCopy: true,
onSourceModifyDamage(damage, source, target, move) {
const boostedMoves = [
'stomp', 'steamroller', 'bodyslam', 'flyingpress', 'dragonrush', 'phantomforce', 'heatcrash', 'shadowforce',
];
if (boostedMoves.includes(move.id)) {
return this.chainModify(2);
}
},
onAccuracy(accuracy, target, source, move) {
const boostedMoves = [
'stomp', 'steamroller', 'bodyslam', 'flyingpress', 'dragonrush', 'phantomforce', 'heatcrash', 'shadowforce',
];
if (boostedMoves.includes(move.id)) {
return true;
}
return accuracy;
},
},
},
metronome: { metronome: {
inherit: true, inherit: true,
flags: { noassist: 1, failcopycat: 1, nosleeptalk: 1 }, flags: { noassist: 1, failcopycat: 1, nosleeptalk: 1 },
@ -126,39 +65,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mistyterrain: { mistyterrain: {
inherit: true, inherit: true,
condition: { condition: {
effectType: 'Terrain', inherit: true,
duration: 5, onTryAddVolatile() {},
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (!target.isGrounded() || target.isSemiInvulnerable()) return;
if (effect && ((effect as Move).status || effect.id === 'yawn')) {
this.add('-activate', target, 'move: Misty Terrain');
}
return false;
},
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Dragon' && defender.isGrounded() && !defender.isSemiInvulnerable()) {
this.debug('misty terrain weaken');
return this.chainModify(0.5);
}
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Misty Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Misty Terrain');
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'Misty Terrain');
},
}, },
}, },
mysticalfire: { mysticalfire: {
@ -179,28 +87,25 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.boost({ atk: -1, spa: -1 }, target, source); this.boost({ atk: -1, spa: -1 }, target, source);
}, },
}, },
phantomforce: {
inherit: true,
flags: { contact: 1, charge: 1, mirror: 1, metronome: 1, nosleeptalk: 1, noassist: 1, failinstruct: 1, minimize: 1 },
},
powder: { powder: {
inherit: true, inherit: true,
condition: { condition: {
duration: 1, inherit: true,
onStart(target) {
this.add('-singleturn', target, 'Powder');
},
onTryMovePriority: 1, onTryMovePriority: 1,
onTryMove(pokemon, target, move) {
if (move.type === 'Fire') {
this.add('-activate', pokemon, 'move: Powder');
this.damage(this.clampIntRange(Math.round(pokemon.maxhp / 4), 1));
this.attrLastMove('[still]');
return false;
}
},
}, },
}, },
rockblast: { rockblast: {
inherit: true, inherit: true,
flags: { protect: 1, mirror: 1, metronome: 1 }, flags: { protect: 1, mirror: 1, metronome: 1 },
}, },
shadowforce: {
inherit: true,
flags: { contact: 1, charge: 1, mirror: 1, metronome: 1, nosleeptalk: 1, noassist: 1, failinstruct: 1, minimize: 1 },
},
sheercold: { sheercold: {
inherit: true, inherit: true,
ohko: true, ohko: true,
@ -263,11 +168,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
wideguard: { wideguard: {
inherit: true, inherit: true,
condition: { condition: {
duration: 1, inherit: true,
onSideStart(target, source) {
this.add('-singleturn', source, 'Wide Guard');
},
onTryHitPriority: 4,
onTryHit(target, source, effect) { onTryHit(target, source, effect) {
// Wide Guard blocks damaging spread moves // Wide Guard blocks damaging spread moves
if ( if (

View File

@ -72,14 +72,8 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onTryBoost() {}, onTryBoost() {},
}, },
rattled: { rattled: {
onDamagingHit(damage, target, source, move) { inherit: true,
if (['Dark', 'Bug', 'Ghost'].includes(move.type)) { onAfterBoost() {},
this.boost({ spe: 1 });
}
},
name: "Rattled",
rating: 1.5,
num: 155,
}, },
scrappy: { scrappy: {
inherit: true, inherit: true,

View File

@ -182,47 +182,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
electricterrain: { electricterrain: {
inherit: true, inherit: true,
condition: { condition: {
effectType: 'Terrain', inherit: true,
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (status.id === 'slp' && target.isGrounded() && !target.isSemiInvulnerable()) {
if (effect.id === 'yawn' || (effect.effectType === 'Move' && !effect.secondaries)) {
this.add('-activate', target, 'move: Electric Terrain');
}
return false;
}
},
onTryAddVolatile(status, target) {
if (!target.isGrounded() || target.isSemiInvulnerable()) return;
if (status.id === 'yawn') {
this.add('-activate', target, 'move: Electric Terrain');
return null;
}
},
onBasePower(basePower, attacker, defender, move) { onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Electric' && attacker.isGrounded() && !attacker.isSemiInvulnerable()) { if (move.type === 'Electric' && attacker.isGrounded() && !attacker.isSemiInvulnerable()) {
this.debug('electric terrain boost'); this.debug('electric terrain boost');
return this.chainModify(1.5); return this.chainModify(1.5);
} }
}, },
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Electric Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Electric Terrain');
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Electric Terrain');
},
}, },
}, },
embargo: { embargo: {
@ -316,14 +282,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
grassyterrain: { grassyterrain: {
inherit: true, inherit: true,
condition: { condition: {
effectType: 'Terrain', inherit: true,
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onBasePower(basePower, attacker, defender, move) { onBasePower(basePower, attacker, defender, move) {
const weakenedMoves = ['earthquake', 'bulldoze', 'magnitude']; const weakenedMoves = ['earthquake', 'bulldoze', 'magnitude'];
if (weakenedMoves.includes(move.id) && defender.isGrounded() && !defender.isSemiInvulnerable()) { if (weakenedMoves.includes(move.id) && defender.isGrounded() && !defender.isSemiInvulnerable()) {
@ -335,27 +294,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return this.chainModify(1.5); return this.chainModify(1.5);
} }
}, },
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Grassy Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Grassy Terrain');
}
},
onResidualOrder: 5,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (pokemon.isGrounded() && !pokemon.isSemiInvulnerable()) {
this.heal(pokemon.baseMaxhp / 16, pokemon, pokemon);
} else {
this.debug(`Pokemon semi-invuln or not grounded; Grassy Terrain skipped`);
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Grassy Terrain');
},
}, },
}, },
guardianofalola: { guardianofalola: {
@ -558,11 +496,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
kingsshield: { kingsshield: {
inherit: true, inherit: true,
condition: { condition: {
duration: 1, inherit: true,
onStart(target) {
this.add('-singleturn', target, 'Protect');
},
onTryHitPriority: 3,
onTryHit(target, source, move) { onTryHit(target, source, move) {
if (!move.flags['protect'] || move.category === 'Status') { if (!move.flags['protect'] || move.category === 'Status') {
if (move.isZ || move.isMax) target.getMoveHitData(move).zBrokeProtect = true; if (move.isZ || move.isMax) target.getMoveHitData(move).zBrokeProtect = true;
@ -780,48 +714,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
psychicterrain: { psychicterrain: {
inherit: true, inherit: true,
condition: { condition: {
effectType: 'Terrain', inherit: true,
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onTryHitPriority: 4,
onTryHit(target, source, effect) {
if (effect && (effect.priority <= 0.1 || effect.target === 'self')) {
return;
}
if (target.isSemiInvulnerable() || target.isAlly(source)) return;
if (!target.isGrounded()) {
const baseMove = this.dex.moves.get(effect.id);
if (baseMove.priority > 0) {
this.hint("Psychic Terrain doesn't affect Pokémon immune to Ground.");
}
return;
}
this.add('-activate', target, 'move: Psychic Terrain');
return null;
},
onBasePower(basePower, attacker, defender, move) { onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Psychic' && attacker.isGrounded() && !attacker.isSemiInvulnerable()) { if (move.type === 'Psychic' && attacker.isGrounded() && !attacker.isSemiInvulnerable()) {
this.debug('psychic terrain boost'); this.debug('psychic terrain boost');
return this.chainModify(1.5); return this.chainModify(1.5);
} }
}, },
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Psychic Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Psychic Terrain');
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Psychic Terrain');
},
}, },
}, },
psychoboost: { psychoboost: {

View File

@ -19,6 +19,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
doubleironbash: { doubleironbash: {
inherit: true, inherit: true,
isNonstandard: null, isNonstandard: null,
flags: { contact: 1, protect: 1, mirror: 1, punch: 1, minimize: 1 },
}, },
floatyfall: { floatyfall: {
inherit: true, inherit: true,

View File

@ -59,19 +59,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
charge: { charge: {
inherit: true, inherit: true,
condition: { condition: {
onStart(pokemon, source, effect) { inherit: true,
this.add('-start', pokemon, 'Charge');
},
onRestart(pokemon, source, effect) {
this.add('-start', pokemon, 'Charge');
},
onBasePowerPriority: 9,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Electric') {
this.debug('charge boost');
return this.chainModify(2);
}
},
onMoveAborted(pokemon, target, move) { onMoveAborted(pokemon, target, move) {
if (move.id !== 'charge') { if (move.id !== 'charge') {
pokemon.removeVolatile('charge'); pokemon.removeVolatile('charge');
@ -82,9 +70,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
pokemon.removeVolatile('charge'); pokemon.removeVolatile('charge');
} }
}, },
onEnd(pokemon) {
this.add('-end', pokemon, 'Charge', '[silent]');
},
}, },
}, },
chatter: { chatter: {
@ -526,9 +511,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
stickyweb: { stickyweb: {
inherit: true, inherit: true,
condition: { condition: {
onSideStart(side) { inherit: true,
this.add('-sidestart', side, 'move: Sticky Web');
},
onSwitchIn(pokemon) { onSwitchIn(pokemon) {
if (!pokemon.isGrounded() || pokemon.hasItem('heavydutyboots')) return; if (!pokemon.isGrounded() || pokemon.hasItem('heavydutyboots')) return;
this.add('-activate', pokemon, 'move: Sticky Web'); this.add('-activate', pokemon, 'move: Sticky Web');

View File

@ -19,91 +19,60 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
} }
}, },
condition: { condition: {
noCopy: true, inherit: true,
onStart(pokemon, source, effect) { onModifyAtk() {
if (effect?.name === 'Booster Energy') {
this.effectState.fromBooster = true;
this.add('-activate', pokemon, 'ability: Protosynthesis', '[fromitem]');
} else {
this.add('-activate', pokemon, 'ability: Protosynthesis');
}
this.effectState.bestStat = pokemon.getBestStat(false, true);
this.add('-start', pokemon, 'protosynthesis' + this.effectState.bestStat);
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (this.effectState.bestStat !== 'atk') return; if (this.effectState.bestStat !== 'atk') return;
this.debug('Protosynthesis atk boost'); this.debug('Protosynthesis atk boost');
return this.chainModify([5325, 4096]); return this.chainModify([5325, 4096]);
}, },
onModifyDefPriority: 6, onModifyDef() {
onModifyDef(def, pokemon) {
if (this.effectState.bestStat !== 'def') return; if (this.effectState.bestStat !== 'def') return;
this.debug('Protosynthesis def boost'); this.debug('Protosynthesis def boost');
return this.chainModify([5325, 4096]); return this.chainModify([5325, 4096]);
}, },
onModifySpAPriority: 5, onModifySpA() {
onModifySpA(spa, pokemon) {
if (this.effectState.bestStat !== 'spa') return; if (this.effectState.bestStat !== 'spa') return;
this.debug('Protosynthesis spa boost'); this.debug('Protosynthesis spa boost');
return this.chainModify([5325, 4096]); return this.chainModify([5325, 4096]);
}, },
onModifySpDPriority: 6, onModifySpD() {
onModifySpD(spd, pokemon) {
if (this.effectState.bestStat !== 'spd') return; if (this.effectState.bestStat !== 'spd') return;
this.debug('Protosynthesis spd boost'); this.debug('Protosynthesis spd boost');
return this.chainModify([5325, 4096]); return this.chainModify([5325, 4096]);
}, },
onModifySpe(spe, pokemon) { onModifySpe() {
if (this.effectState.bestStat !== 'spe') return; if (this.effectState.bestStat !== 'spe') return;
this.debug('Protosynthesis spe boost'); this.debug('Protosynthesis spe boost');
return this.chainModify(1.5); return this.chainModify(1.5);
}, },
onEnd(pokemon) {
this.add('-end', pokemon, 'Protosynthesis');
},
}, },
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1, cantsuppress: 1 }, flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1, cantsuppress: 1 },
}, },
quarkdrive: { quarkdrive: {
inherit: true, inherit: true,
condition: { condition: {
noCopy: true, inherit: true,
onStart(pokemon, source, effect) { onModifyAtk() {
if (effect?.name === 'Booster Energy') {
this.effectState.fromBooster = true;
this.add('-activate', pokemon, 'ability: Quark Drive', '[fromitem]');
} else {
this.add('-activate', pokemon, 'ability: Quark Drive');
}
this.effectState.bestStat = pokemon.getBestStat(false, true);
this.add('-start', pokemon, 'quarkdrive' + this.effectState.bestStat);
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (this.effectState.bestStat !== 'atk') return; if (this.effectState.bestStat !== 'atk') return;
this.debug('Quark Drive atk boost'); this.debug('Quark Drive atk boost');
return this.chainModify([5325, 4096]); return this.chainModify([5325, 4096]);
}, },
onModifyDefPriority: 6, onModifyDef() {
onModifyDef(def, pokemon) {
if (this.effectState.bestStat !== 'def') return; if (this.effectState.bestStat !== 'def') return;
this.debug('Quark Drive def boost'); this.debug('Quark Drive def boost');
return this.chainModify([5325, 4096]); return this.chainModify([5325, 4096]);
}, },
onModifySpAPriority: 5, onModifySpA() {
onModifySpA(spa, pokemon) {
if (this.effectState.bestStat !== 'spa') return; if (this.effectState.bestStat !== 'spa') return;
this.debug('Quark Drive spa boost'); this.debug('Quark Drive spa boost');
return this.chainModify([5325, 4096]); return this.chainModify([5325, 4096]);
}, },
onModifySpDPriority: 6, onModifySpD() {
onModifySpD(spd, pokemon) {
if (this.effectState.bestStat !== 'spd') return; if (this.effectState.bestStat !== 'spd') return;
this.debug('Quark Drive spd boost'); this.debug('Quark Drive spd boost');
return this.chainModify([5325, 4096]); return this.chainModify([5325, 4096]);
}, },
onModifySpe(spe, pokemon) { onModifySpe() {
if (this.effectState.bestStat !== 'spe') return; if (this.effectState.bestStat !== 'spe') return;
this.debug('Quark Drive spe boost'); this.debug('Quark Drive spe boost');
return this.chainModify(1.5); return this.chainModify(1.5);

View File

@ -1644,7 +1644,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Body Slam", name: "Body Slam",
pp: 15, pp: 15,
priority: 0, priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1, minimize: 1 },
secondary: { secondary: {
chance: 30, chance: 30,
status: 'par', status: 'par',
@ -4349,7 +4349,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Dragon Rush", name: "Dragon Rush",
pp: 10, pp: 10,
priority: 0, priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
secondary: { secondary: {
chance: 20, chance: 20,
volatileStatus: 'flinch', volatileStatus: 'flinch',
@ -6149,7 +6149,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
category: "Physical", category: "Physical",
name: "Flying Press", name: "Flying Press",
pp: 10, pp: 10,
flags: { contact: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, nonsky: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, nonsky: 1, metronome: 1, minimize: 1 },
onEffectiveness(typeMod, target, type, move) { onEffectiveness(typeMod, target, type, move) {
return typeMod + this.dex.getEffectiveness('Flying', type); return typeMod + this.dex.getEffectiveness('Flying', type);
}, },
@ -8608,7 +8608,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
return false; return false;
} }
}, },
onModifyMove(move, pokemon, target) { onModifyMove(move, pokemon) {
if (move.flags['heal'] && !move.isZ && !move.isMax) { if (move.flags['heal'] && !move.isZ && !move.isMax) {
this.add('cant', pokemon, 'move: Heal Block', move); this.add('cant', pokemon, 'move: Heal Block', move);
return false; return false;
@ -8801,7 +8801,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Heat Crash", name: "Heat Crash",
pp: 10, pp: 10,
priority: 0, priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1, minimize: 1 },
onTryHit(target, pokemon, move) { onTryHit(target, pokemon, move) {
if (target.volatiles['dynamax']) { if (target.volatiles['dynamax']) {
this.add('-fail', pokemon, 'Dynamax'); this.add('-fail', pokemon, 'Dynamax');
@ -8859,7 +8859,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Heavy Slam", name: "Heavy Slam",
pp: 10, pp: 10,
priority: 0, priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1, minimize: 1 },
onTryHit(target, pokemon, move) { onTryHit(target, pokemon, move) {
if (target.volatiles['dynamax']) { if (target.volatiles['dynamax']) {
this.add('-fail', pokemon, 'Dynamax'); this.add('-fail', pokemon, 'Dynamax');
@ -11364,7 +11364,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Malicious Moonsault", name: "Malicious Moonsault",
pp: 1, pp: 1,
priority: 0, priority: 0,
flags: { contact: 1 }, flags: { contact: 1, minimize: 1 },
isZ: "inciniumz", isZ: "inciniumz",
secondary: null, secondary: null,
target: "normal", target: "normal",
@ -12365,18 +12365,12 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
noCopy: true, noCopy: true,
onRestart: () => null, onRestart: () => null,
onSourceModifyDamage(damage, source, target, move) { onSourceModifyDamage(damage, source, target, move) {
const boostedMoves = [ if (move.flags['minimize']) {
'stomp', 'steamroller', 'bodyslam', 'flyingpress', 'dragonrush', 'heatcrash', 'heavyslam', 'maliciousmoonsault', 'supercellslam',
];
if (boostedMoves.includes(move.id)) {
return this.chainModify(2); return this.chainModify(2);
} }
}, },
onAccuracy(accuracy, target, source, move) { onAccuracy(accuracy, target, source, move) {
const boostedMoves = [ if (move.flags['minimize']) {
'stomp', 'steamroller', 'bodyslam', 'flyingpress', 'dragonrush', 'heatcrash', 'heavyslam', 'maliciousmoonsault', 'supercellslam',
];
if (boostedMoves.includes(move.id)) {
return true; return true;
} }
return accuracy; return accuracy;
@ -16174,7 +16168,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return; if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if (target !== source) { if (target !== source) {
this.debug('interrupting setStatus'); this.debug('interrupting setStatus');
if (effect.name === 'Synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) { if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
this.add('-activate', target, 'move: Safeguard'); this.add('-activate', target, 'move: Safeguard');
} }
return null; return null;
@ -18520,7 +18514,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Steamroller", name: "Steamroller",
pp: 20, pp: 20,
priority: 0, priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
secondary: { secondary: {
chance: 30, chance: 30,
volatileStatus: 'flinch', volatileStatus: 'flinch',
@ -18702,7 +18696,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Stomp", name: "Stomp",
pp: 20, pp: 20,
priority: 0, priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1, minimize: 1 },
secondary: { secondary: {
chance: 30, chance: 30,
volatileStatus: 'flinch', volatileStatus: 'flinch',
@ -19131,7 +19125,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Supercell Slam", name: "Supercell Slam",
pp: 15, pp: 15,
priority: 0, priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 }, flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
hasCrashDamage: true, hasCrashDamage: true,
onMoveFail(target, source, move) { onMoveFail(target, source, move) {
this.damage(source.baseMaxhp / 2, source, source, this.dex.conditions.get('Supercell Slam')); this.damage(source.baseMaxhp / 2, source, source, this.dex.conditions.get('Supercell Slam'));

View File

@ -1,4 +1,4 @@
import type { PokemonEventMethods, ConditionData } from './dex-conditions'; import type { PokemonEventMethods, ConditionData, ModdedConditionData } from './dex-conditions';
import { assignMissingFields, BasicEffect, toID } from './dex-data'; import { assignMissingFields, BasicEffect, toID } from './dex-data';
import { Utils } from '../lib/utils'; import { Utils } from '../lib/utils';
@ -24,7 +24,10 @@ export interface AbilityData extends Partial<Ability>, AbilityEventMethods, Poke
name: string; name: string;
} }
export type ModdedAbilityData = AbilityData | Partial<AbilityData> & { inherit: true }; export type ModdedAbilityData = AbilityData | Partial<AbilityData> & {
inherit: true,
condition?: ModdedConditionData,
};
export interface AbilityDataTable { [abilityid: IDEntry]: AbilityData } export interface AbilityDataTable { [abilityid: IDEntry]: AbilityData }
export interface ModdedAbilityDataTable { [abilityid: IDEntry]: ModdedAbilityData } export interface ModdedAbilityDataTable { [abilityid: IDEntry]: ModdedAbilityData }

View File

@ -1,4 +1,4 @@
import type { PokemonEventMethods, ConditionData } from './dex-conditions'; import type { PokemonEventMethods, ConditionData, ModdedConditionData } from './dex-conditions';
import { assignMissingFields, BasicEffect, toID } from './dex-data'; import { assignMissingFields, BasicEffect, toID } from './dex-data';
import { Utils } from '../lib/utils'; import { Utils } from '../lib/utils';
@ -16,6 +16,7 @@ export interface ItemData extends Partial<Item>, PokemonEventMethods {
export type ModdedItemData = ItemData | Partial<Omit<ItemData, 'name'>> & { export type ModdedItemData = ItemData | Partial<Omit<ItemData, 'name'>> & {
inherit: true, inherit: true,
onCustap?: (this: Battle, pokemon: Pokemon) => void, onCustap?: (this: Battle, pokemon: Pokemon) => void,
condition?: ModdedConditionData,
}; };
export interface ItemDataTable { [itemid: IDEntry]: ItemData } export interface ItemDataTable { [itemid: IDEntry]: ItemData }

View File

@ -1,5 +1,5 @@
import { Utils } from '../lib/utils'; import { Utils } from '../lib/utils';
import type { ConditionData } from './dex-conditions'; import type { ConditionData, ModdedConditionData } from './dex-conditions';
import { assignMissingFields, BasicEffect, toID } from './dex-data'; import { assignMissingFields, BasicEffect, toID } from './dex-data';
/** /**
@ -45,6 +45,7 @@ interface MoveFlags {
gravity?: 1; // Prevented from being executed or selected during Gravity's effect. gravity?: 1; // Prevented from being executed or selected during Gravity's effect.
heal?: 1; // Prevented from being executed or selected during Heal Block's effect. heal?: 1; // Prevented from being executed or selected during Heal Block's effect.
metronome?: 1; // Can be selected by Metronome. metronome?: 1; // Can be selected by Metronome.
minimize?: 1; // Deals double damage if the user is minimized.
mirror?: 1; // Can be copied by Mirror Move. mirror?: 1; // Can be copied by Mirror Move.
mustpressure?: 1; // Additional PP is deducted due to Pressure when it ordinarily would not. mustpressure?: 1; // Additional PP is deducted due to Pressure when it ordinarily would not.
noassist?: 1; // Cannot be selected by Assist. noassist?: 1; // Cannot be selected by Assist.
@ -278,6 +279,7 @@ export type ModdedMoveData = MoveData | Partial<Omit<MoveData, 'name'>> & {
bodyofwaterBoosted?: boolean, bodyofwaterBoosted?: boolean,
longWhipBoost?: boolean, longWhipBoost?: boolean,
gen?: number, gen?: number,
condition?: ModdedConditionData,
}; };
export interface MoveDataTable { [moveid: IDEntry]: MoveData } export interface MoveDataTable { [moveid: IDEntry]: MoveData }

View File

@ -651,6 +651,15 @@ export class ModdedDex {
// instead of overwriting entirely // instead of overwriting entirely
delete childTypedData[entryId].inherit; delete childTypedData[entryId].inherit;
// {inherit: true} can also be used to inherit parts of conditions
if (childTypedData[entryId].condition?.inherit) {
delete childTypedData[entryId].condition.inherit;
childTypedData[entryId].condition = {
...parentTypedData[entryId].condition,
...childTypedData[entryId].condition,
};
}
// Merge parent and child's entry, with child overwriting parent. // Merge parent and child's entry, with child overwriting parent.
childTypedData[entryId] = { ...parentTypedData[entryId], ...childTypedData[entryId] }; childTypedData[entryId] = { ...parentTypedData[entryId], ...childTypedData[entryId] };
} }