mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-06-02 22:08:36 -05:00
Merge 4f423307dc into 6765d8422d
This commit is contained in:
commit
f22a514bbb
|
|
@ -3192,7 +3192,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
num: 253,
|
||||
},
|
||||
pickpocket: {
|
||||
onAfterMoveSecondary(target, source, move) {
|
||||
onAfterMoveSecondaryLast(target, source, move) {
|
||||
if (source && source !== target && move?.flags['contact']) {
|
||||
if (target.item || target.switchFlag || target.forceSwitchFlag || source.switchFlag === true) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -552,5 +552,172 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
return damage;
|
||||
},
|
||||
// Sheer Force shouldnt suppress Pickpocket
|
||||
useMoveInner(moveOrMoveName, pokemon, options) {
|
||||
let target = options?.target;
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
const zMove = options?.zMove;
|
||||
const maxMove = options?.maxMove;
|
||||
if (!sourceEffect && this.battle.effect.id) sourceEffect = this.battle.effect;
|
||||
if (sourceEffect && ['instruct', 'custapberry'].includes(sourceEffect.id)) sourceEffect = null;
|
||||
|
||||
let move = this.dex.getActiveMove(moveOrMoveName);
|
||||
pokemon.lastMoveUsed = move;
|
||||
if (move.id === 'weatherball' && zMove) {
|
||||
// Z-Weather Ball only changes types if it's used directly,
|
||||
// not if it's called by Z-Sleep Talk or something.
|
||||
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
|
||||
if (move.type !== 'Normal') sourceEffect = move;
|
||||
}
|
||||
if (zMove || (move.category !== 'Status' && sourceEffect && (sourceEffect as ActiveMove).isZ)) {
|
||||
move = this.getActiveZMove(move, pokemon);
|
||||
}
|
||||
if (maxMove && move.category !== 'Status') {
|
||||
// Max move outcome is dependent on the move type after type modifications from ability and the move itself
|
||||
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
|
||||
this.battle.runEvent('ModifyType', pokemon, target, move, move);
|
||||
}
|
||||
if (maxMove || (move.category !== 'Status' && sourceEffect && (sourceEffect as ActiveMove).isMax)) {
|
||||
move = this.getActiveMaxMove(move, pokemon);
|
||||
}
|
||||
|
||||
if (this.battle.activeMove) {
|
||||
move.priority = this.battle.activeMove.priority;
|
||||
if (!move.hasBounced) move.pranksterBoosted = this.battle.activeMove.pranksterBoosted;
|
||||
}
|
||||
const baseTarget = move.target;
|
||||
let targetRelayVar = { target };
|
||||
targetRelayVar = this.battle.runEvent('ModifyTarget', pokemon, target, move, targetRelayVar, true);
|
||||
if (targetRelayVar.target !== undefined) target = targetRelayVar.target;
|
||||
if (target === undefined) target = this.battle.getRandomTarget(pokemon, move);
|
||||
if (move.target === 'self' || move.target === 'allies') {
|
||||
target = pokemon;
|
||||
}
|
||||
if (sourceEffect) {
|
||||
move.sourceEffect = sourceEffect.id;
|
||||
move.ignoreAbility = (sourceEffect as ActiveMove).ignoreAbility;
|
||||
}
|
||||
let moveResult = false;
|
||||
|
||||
this.battle.setActiveMove(move, pokemon, target);
|
||||
|
||||
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
|
||||
this.battle.singleEvent('ModifyMove', move, null, pokemon, target, move, move);
|
||||
if (baseTarget !== move.target) {
|
||||
// Target changed in ModifyMove, so we must adjust it here
|
||||
// Adjust before the next event so the correct target is passed to the
|
||||
// event
|
||||
target = this.battle.getRandomTarget(pokemon, move);
|
||||
}
|
||||
move = this.battle.runEvent('ModifyType', pokemon, target, move, move);
|
||||
move = this.battle.runEvent('ModifyMove', pokemon, target, move, move);
|
||||
if (baseTarget !== move.target) {
|
||||
// Adjust again
|
||||
target = this.battle.getRandomTarget(pokemon, move);
|
||||
}
|
||||
if (!move || pokemon.fainted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let attrs = '';
|
||||
|
||||
let movename = move.name;
|
||||
if (move.id === 'hiddenpower') movename = 'Hidden Power';
|
||||
if (sourceEffect) attrs += `|[from] ${sourceEffect.fullname}`;
|
||||
if (zMove && move.isZ === true) {
|
||||
attrs = `|[anim]${movename}${attrs}`;
|
||||
movename = `Z-${movename}`;
|
||||
}
|
||||
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
|
||||
|
||||
if (zMove) this.runZPower(move, pokemon);
|
||||
|
||||
if (!target) {
|
||||
this.battle.attrLastMove('[notarget]');
|
||||
this.battle.add(this.battle.gen >= 5 ? '-fail' : '-notarget', pokemon);
|
||||
return false;
|
||||
}
|
||||
|
||||
const { targets, pressureTargets } = pokemon.getMoveTargets(move, target);
|
||||
if (targets.length) {
|
||||
target = targets[targets.length - 1]; // in case of redirection
|
||||
}
|
||||
|
||||
const callerMoveForPressure = sourceEffect && (sourceEffect as ActiveMove).pp ? sourceEffect as ActiveMove : null;
|
||||
if (!sourceEffect || callerMoveForPressure || sourceEffect.id === 'pursuit') {
|
||||
let extraPP = 0;
|
||||
for (const source of pressureTargets) {
|
||||
const ppDrop = this.battle.runEvent('DeductPP', source, pokemon, move);
|
||||
if (ppDrop !== true) {
|
||||
extraPP += ppDrop || 0;
|
||||
}
|
||||
}
|
||||
if (extraPP > 0) {
|
||||
pokemon.deductPP(callerMoveForPressure || moveOrMoveName, extraPP);
|
||||
}
|
||||
}
|
||||
|
||||
let tryMoveResult = this.battle.singleEvent('TryMove', move, null, pokemon, target, move);
|
||||
if (tryMoveResult) {
|
||||
tryMoveResult = this.battle.runEvent('TryMove', pokemon, target, move);
|
||||
}
|
||||
if (!tryMoveResult) {
|
||||
move.mindBlownRecoil = false;
|
||||
return tryMoveResult;
|
||||
}
|
||||
|
||||
this.battle.singleEvent('UseMoveMessage', move, null, pokemon, target, move);
|
||||
|
||||
if (move.ignoreImmunity === undefined) {
|
||||
move.ignoreImmunity = (move.category === 'Status');
|
||||
}
|
||||
|
||||
if (this.battle.gen !== 4 && move.selfdestruct === 'always') {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
|
||||
let damage: number | false | undefined | '' = false;
|
||||
if (move.target === 'all' || move.target === 'foeSide' || move.target === 'allySide' || move.target === 'allyTeam') {
|
||||
damage = this.tryMoveHit(targets, pokemon, move);
|
||||
if (damage === this.battle.NOT_FAIL) pokemon.moveThisTurnResult = null;
|
||||
if (damage || damage === 0 || damage === undefined) moveResult = true;
|
||||
} else {
|
||||
if (!targets.length) {
|
||||
this.battle.attrLastMove('[notarget]');
|
||||
this.battle.add(this.battle.gen >= 5 ? '-fail' : '-notarget', pokemon);
|
||||
return false;
|
||||
}
|
||||
if (this.battle.gen === 4 && move.selfdestruct === 'always') {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
moveResult = this.trySpreadMoveHit(targets, pokemon, move);
|
||||
}
|
||||
if (move.selfBoost && moveResult) this.moveHit(pokemon, pokemon, move, move.selfBoost, false, true);
|
||||
if (!pokemon.hp) {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
|
||||
if (!moveResult) {
|
||||
this.battle.singleEvent('MoveFail', move, null, target, pokemon, move);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(move.hasSheerForce && pokemon.hasAbility('sheerforce')) && !move.flags['futuremove']) {
|
||||
const originalHp = pokemon.hp;
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
if (pokemon && pokemon !== target && move.category !== 'Status') {
|
||||
if (pokemon.hp <= pokemon.maxhp / 2 && originalHp > pokemon.maxhp / 2) {
|
||||
this.battle.runEvent('EmergencyExit', pokemon, pokemon);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const curTarget of targets) {
|
||||
this.battle.singleEvent('AfterMoveSecondaryLast', move, null, curTarget, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondaryLast', curTarget, pokemon, move);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9425,11 +9425,8 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
|
|||
pp: 15,
|
||||
priority: 0,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
|
||||
onAfterHit(target, source) {
|
||||
this.field.clearTerrain();
|
||||
},
|
||||
onAfterSubDamage(damage, target, source) {
|
||||
if (source.hp) {
|
||||
onAfterMoveSecondaryLast(target, source) {
|
||||
if (source.hp && !source.forceSwitchFlag) {
|
||||
this.field.clearTerrain();
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -537,6 +537,10 @@ export class BattleActions {
|
|||
this.battle.runEvent('EmergencyExit', pokemon, pokemon);
|
||||
}
|
||||
}
|
||||
for (const curTarget of targets) {
|
||||
this.battle.singleEvent('AfterMoveSecondaryLast', move, null, curTarget, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondaryLast', curTarget, pokemon, move);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1747,7 +1751,7 @@ export class BattleActions {
|
|||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.priorityEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export interface EventMethods {
|
|||
onAfterTakeItem?: (this: Battle, item: Item, pokemon: Pokemon) => void;
|
||||
onAfterBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon, effect: Effect) => void;
|
||||
onAfterFaint?: (this: Battle, length: number, target: Pokemon, source: Pokemon, effect: Effect) => void;
|
||||
onAfterMoveSecondaryLast?: MoveEventMethods['onAfterMoveSecondaryLast'];
|
||||
onAfterMoveSecondarySelf?: MoveEventMethods['onAfterMoveSecondarySelf'];
|
||||
onAfterMoveSecondary?: MoveEventMethods['onAfterMoveSecondary'];
|
||||
onAfterMove?: MoveEventMethods['onAfterMove'];
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ export interface MoveEventMethods {
|
|||
|
||||
onAfterHit?: CommonHandlers['VoidSourceMove'];
|
||||
onAfterSubDamage?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void;
|
||||
onAfterMoveSecondaryLast?: CommonHandlers['VoidMove'];
|
||||
onAfterMoveSecondarySelf?: CommonHandlers['VoidSourceMove'];
|
||||
onAfterMoveSecondary?: CommonHandlers['VoidMove'];
|
||||
onAfterMove?: CommonHandlers['VoidSourceMove'];
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ describe('Pickpocket', () => {
|
|||
assert.holdsItem(battle.p2.active[0]);
|
||||
});
|
||||
|
||||
it.skip(`should steal items back and forth when hit by a Magician user`, () => {
|
||||
it(`should steal items back and forth when hit by a Magician user`, () => {
|
||||
battle = common.createBattle([[
|
||||
{ species: 'Weavile', ability: 'pickpocket', item: 'cheriberry', moves: ['agility'] },
|
||||
], [
|
||||
|
|
|
|||
|
|
@ -21,7 +21,19 @@ describe(`Ice Spinner`, () => {
|
|||
assert.false(battle.field.isTerrain('psychicterrain'));
|
||||
});
|
||||
|
||||
it.skip(`should not remove Terrains if the user faints from Life Orb`, () => {
|
||||
it(`should remove Terrains if target has a substitute`, () => {
|
||||
battle = common.createBattle([[
|
||||
{ species: 'wynaut', moves: ['sleeptalk', 'icespinner'] },
|
||||
], [
|
||||
{ species: 'registeel', ability: 'psychicsurge', moves: ['substitute', 'sleeptalk'] },
|
||||
]]);
|
||||
|
||||
battle.makeChoices('move sleeptalk', 'move substitute');
|
||||
battle.makeChoices('move ice spinner', 'move sleeptalk');
|
||||
assert.false(battle.field.isTerrain('psychicterrain'));
|
||||
});
|
||||
|
||||
it(`should not remove Terrains if the user faints from Life Orb`, () => {
|
||||
battle = common.createBattle([[
|
||||
{ species: 'shedinja', item: 'lifeorb', moves: ['icespinner'] },
|
||||
{ species: 'wynaut', moves: ['sleeptalk'] },
|
||||
|
|
@ -45,7 +57,7 @@ describe(`Ice Spinner`, () => {
|
|||
assert(battle.field.isTerrain('psychicterrain'));
|
||||
});
|
||||
|
||||
it.skip(`should not remove Terrains if the user is forced out via Red Card`, () => {
|
||||
it(`should not remove Terrains if the user is forced out via Red Card`, () => {
|
||||
battle = common.createBattle([[
|
||||
{ species: 'shedinja', moves: ['icespinner'] },
|
||||
{ species: 'wynaut', moves: ['sleeptalk'] },
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user