mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-04-25 15:40:31 -05:00
Also move mods/ to data/mods/ This makes PS more monorepo-like. The intent is to further separate the sim and the server code, but without fully committing to splitting the repository itself. We now support `./pokemon-showdown start` in addition to `./pokemon-showdown`. I'm not clear which I want to be the default yet.
186 lines
5.1 KiB
JavaScript
186 lines
5.1 KiB
JavaScript
'use strict';
|
|
|
|
/**@type {{[k: string]: ModdedMoveData}} */
|
|
let BattleMovedex = {
|
|
bind: {
|
|
inherit: true,
|
|
onBeforeMove: function () {},
|
|
},
|
|
clamp: {
|
|
inherit: true,
|
|
onBeforeMove: function () {},
|
|
},
|
|
firespin: {
|
|
inherit: true,
|
|
onBeforeMove: function () {},
|
|
},
|
|
highjumpkick: {
|
|
inherit: true,
|
|
desc: "If this attack misses the target, the user takes 1 HP of damage.",
|
|
shortDesc: "User takes 1 HP damage it would have dealt if miss.",
|
|
onMoveFail: function (target, source, move) {
|
|
if (!target.types.includes('Ghost')) {
|
|
this.directDamage(1, source);
|
|
}
|
|
},
|
|
},
|
|
jumpkick: {
|
|
inherit: true,
|
|
desc: "If this attack misses the target, the user 1HP of damage.",
|
|
shortDesc: "User takes 1 HP damage if miss.",
|
|
onMoveFail: function (target, source, move) {
|
|
this.damage(1, source);
|
|
},
|
|
},
|
|
leechseed: {
|
|
inherit: true,
|
|
onHit: function () {},
|
|
effect: {
|
|
onStart: function (target) {
|
|
this.add('-start', target, 'move: Leech Seed');
|
|
},
|
|
onAfterMoveSelfPriority: 1,
|
|
onAfterMoveSelf: function (pokemon) {
|
|
let leecher = pokemon.side.foe.active[pokemon.volatiles['leechseed'].sourcePosition];
|
|
if (!leecher || leecher.fainted || leecher.hp <= 0) {
|
|
this.debug('Nothing to leech into');
|
|
return;
|
|
}
|
|
let toLeech = this.clampIntRange(Math.floor(pokemon.maxhp / 16), 1);
|
|
let damage = this.damage(toLeech, pokemon, leecher);
|
|
if (damage) this.heal(damage, leecher, pokemon);
|
|
},
|
|
},
|
|
},
|
|
rage: {
|
|
inherit: true,
|
|
self: {
|
|
volatileStatus: 'rage',
|
|
},
|
|
effect: {
|
|
// Rage lock
|
|
duration: 255,
|
|
onStart: function (target, source, effect) {
|
|
this.effectData.move = 'rage';
|
|
},
|
|
onLockMove: 'rage',
|
|
onTryHit: function (target, source, move) {
|
|
if (target.boosts.atk < 6 && move.id === 'disable') {
|
|
this.boost({atk: 1});
|
|
}
|
|
},
|
|
onHit: function (target, source, move) {
|
|
if (target.boosts.atk < 6 && move.category !== 'Status') {
|
|
this.boost({atk: 1});
|
|
}
|
|
},
|
|
onMoveFail: function () {},
|
|
},
|
|
},
|
|
recover: {
|
|
inherit: true,
|
|
heal: null,
|
|
onHit: function (target) {
|
|
if (target.hp === target.maxhp) {
|
|
return false;
|
|
}
|
|
this.heal(Math.floor(target.maxhp / 2), target, target);
|
|
},
|
|
},
|
|
rest: {
|
|
inherit: true,
|
|
onHit: function (target) {
|
|
// Fails if the difference between
|
|
// max HP and current HP is 0, 255, or 511
|
|
if (target.hp >= target.maxhp) return false;
|
|
if (!target.setStatus('slp')) return false;
|
|
target.statusData.time = 2;
|
|
target.statusData.startTime = 2;
|
|
this.heal(target.maxhp); // Aeshetic only as the healing happens after you fall asleep in-game
|
|
this.add('-status', target, 'slp', '[from] move: Rest');
|
|
},
|
|
},
|
|
softboiled: {
|
|
inherit: true,
|
|
heal: null,
|
|
onHit: function (target) {
|
|
// Fail when health is 255 or 511 less than max
|
|
if (target.hp === target.maxhp) {
|
|
return false;
|
|
}
|
|
this.heal(Math.floor(target.maxhp / 2), target, target);
|
|
},
|
|
},
|
|
substitute: {
|
|
inherit: true,
|
|
effect: {
|
|
onStart: function (target) {
|
|
this.add('-start', target, 'Substitute');
|
|
this.effectData.hp = Math.floor(target.maxhp / 4);
|
|
delete target.volatiles['partiallytrapped'];
|
|
},
|
|
onTryHitPriority: -1,
|
|
onTryHit: function (target, source, move) {
|
|
if (target === source) {
|
|
this.debug('sub bypass: self hit');
|
|
return;
|
|
}
|
|
if (move.drain) {
|
|
this.add('-miss', source);
|
|
return null;
|
|
}
|
|
if (move.category === 'Status') {
|
|
let SubBlocked = ['leechseed', 'lockon', 'mindreader', 'nightmare'];
|
|
if (move.status || move.boosts || move.volatileStatus === 'confusion' || SubBlocked.includes(move.id)) {
|
|
this.add('-activate', target, 'Substitute', '[block] ' + move.name);
|
|
return null;
|
|
}
|
|
return;
|
|
}
|
|
if (move.volatileStatus && target === source) return;
|
|
let damage = this.getDamage(source, target, move);
|
|
if (!damage) return null;
|
|
damage = this.runEvent('SubDamage', target, source, move, damage);
|
|
if (!damage) return damage;
|
|
target.volatiles['substitute'].hp -= damage;
|
|
source.lastDamage = damage;
|
|
if (target.volatiles['substitute'].hp <= 0) {
|
|
this.debug('Substitute broke');
|
|
target.removeVolatile('substitute');
|
|
target.subFainted = true;
|
|
} else {
|
|
this.add('-activate', target, 'Substitute', '[damage]');
|
|
}
|
|
// Drain/recoil does not happen if the substitute breaks
|
|
if (target.volatiles['substitute']) {
|
|
if (move.recoil) {
|
|
this.damage(Math.round(damage * move.recoil[0] / move.recoil[1]), source, target, 'recoil');
|
|
}
|
|
}
|
|
this.runEvent('AfterSubDamage', target, source, move, damage);
|
|
// Add here counter damage
|
|
let lastAttackedBy = target.getLastAttackedBy();
|
|
if (!lastAttackedBy) {
|
|
target.attackedBy.push({source: source, move: move.id, damage: damage, thisTurn: true});
|
|
} else {
|
|
lastAttackedBy.move = move.id;
|
|
lastAttackedBy.damage = damage;
|
|
}
|
|
return 0;
|
|
},
|
|
onEnd: function (target) {
|
|
this.add('-end', target, 'Substitute');
|
|
},
|
|
},
|
|
secondary: null,
|
|
target: "self",
|
|
type: "Normal",
|
|
},
|
|
wrap: {
|
|
inherit: true,
|
|
onBeforeMove: function () {},
|
|
},
|
|
};
|
|
|
|
exports.BattleMovedex = BattleMovedex;
|