From 00f4e7407d0ad845168b6be96b7f3833bedb7bf6 Mon Sep 17 00:00:00 2001 From: Kirk Scheibelhut Date: Mon, 13 Jan 2025 11:50:41 -0800 Subject: [PATCH] update deps not react though because DefinitelyTyped/DefinitelyTyped#64464 --- examples/js/package.json | 10 +++---- package.json | 30 ++++++++++---------- src/lib/gen1/README.md | 29 ++++++++----------- src/lib/gen1/mechanics.zig | 9 +----- src/lib/gen1/test.zig | 3 +- src/test/benchmark.ts | 51 +++++++++++++++++----------------- src/test/integration.ts | 18 ++++++------ src/test/showdown.ts | 31 +++++++++------------ src/test/showdown/gen1.test.ts | 4 +-- src/test/showdown/gen2.test.ts | 4 +-- 10 files changed, 85 insertions(+), 104 deletions(-) diff --git a/examples/js/package.json b/examples/js/package.json index 1e2b0ee8..926480f4 100644 --- a/examples/js/package.json +++ b/examples/js/package.json @@ -1,16 +1,16 @@ { "dependencies": { - "@pkmn/data": "^0.9.23", - "@pkmn/dex": "^0.9.23", + "@pkmn/data": "^0.9.27", + "@pkmn/dex": "^0.9.27", "@pkmn/engine": "file:../..", "@pkmn/sets": "^5.1.2" }, "devDependencies": { "parcel-reporter-static-files-copy": "^1.5.3", - "parcel": "^2.13.0", + "parcel": "^2.13.3", "vite-plugin-commonjs": "^0.10.4", - "vite": "^5.4.11", - "typescript": "^5.7.2" + "vite": "^6.0.7", + "typescript": "^5.7.3" }, "scripts": { "prestart": "tsc -p .", diff --git a/package.json b/package.json index 68d5c12e..2640619d 100644 --- a/package.json +++ b/package.json @@ -94,38 +94,38 @@ }, "publishConfig": {"access": "public"}, "dependencies": { - "@pkmn/data": "^0.9.23", - "@pkmn/protocol": "^0.6.29" + "@pkmn/data": "^0.9.27", + "@pkmn/protocol": "^0.6.30" }, "devDependencies": { - "@pkmn/eslint-config": "^9.3.0", - "@pkmn/img": "^0.2.33", + "@pkmn/eslint-config": "^9.5.0", + "@pkmn/img": "^0.2.34", "@pkmn/sets": "^5.1.2", - "@pkmn/sim": "0.9.23", - "@pkmn/smogon": "^0.5.15", + "@pkmn/sim": "0.9.27", + "@pkmn/smogon": "^0.5.17", "@types/html-minifier": "^4.0.5", "@types/jest": "^29.5.14", "@types/minimist": "^1.2.5", "@types/mustache": "^4.2.5", - "@types/node": "^22.9.3", + "@types/node": "^22.10.6", "@types/react": "^18.3.12", "@types/semver": "^7.5.8", - "@types/vscode": "^1.95.0", - "@vitest/coverage-v8": "^2.1.5", + "@types/vscode": "^1.96.0", + "@vitest/coverage-v8": "^2.1.8", "@vscode/vsce": "^3.2.1", - "binaryen": "^120.0.0", - "esbuild": "^0.24.0", - "eslint": "^9.15.0", + "binaryen": "^121.0.0", + "esbuild": "^0.24.2", + "eslint": "^9.18.0", "html-minifier": "^4.0.0", "json-stringify-pretty-compact": "3.0.0", "minimist": "^1.2.8", "mustache": "^4.2.0", "semver": "^7.6.3", "source-map-support": "^0.5.21", - "table": "^6.8.2", + "table": "^6.9.0", "trakr": "^0.2.0", - "typescript": "^5.7.2", - "vitest": "^2.1.5" + "typescript": "^5.7.3", + "vitest": "^2.1.8" }, "scripts": { "lint": "eslint --cache src", diff --git a/src/lib/gen1/README.md b/src/lib/gen1/README.md index 8a9311f2..641752c9 100644 --- a/src/lib/gen1/README.md +++ b/src/lib/gen1/README.md @@ -560,10 +560,8 @@ Smogon](https://www.smogon.com/forums/posts/5933177/show): - Pokémon Showdown doesn't implement type effectiveness precedence correctly. - Pokémon Showdown checks for type and OHKO immunity before accuracy. - Confusion self-hits use the wrong damage formula resulting in off-by-one errors (and also fail to - account for an opponent's Reflect). Furthermore, the confusion self-hit damage erroneously gets - inflicted on the confused user's substitute if the confused user had been attempting to use a - self-targeting move. Finally, Pokémon Showdown erroneously considers the *uncapped* self-hit - damage for the purposes of tracking the battle's last damage. + account for an opponent's Reflect). Furthermore, Pokémon Showdown erroneously considers the + *uncapped* self-hit damage for the purposes of tracking the battle's last damage. Beyond these general bugs, several move effects are implemented incorrectly by Pokémon Showdown. Some of these moves are [too fundamentally broken to be implemented](#unimplementable) by the pkmn @@ -615,19 +613,16 @@ engine, but the following moves have their broken behavior preserved in `-Dshowd the RNG). More importantly, these moves should *not* cause the tracked last battle damage to be zeroed, but on Pokémon Showdown they do. These should also `|-fail|...|[still]` instead of doing nothing. -- **Substitute**: in addition to the [Substitute + Confusion - glitch](https://pkmn.cc/bulba-glitch-1#Substitute_.2B_Confusion_glitch) not being implemented - correctly (covered earlier), the [Substitute 1/4 - glitch](https://glitchcity.wiki/Substitute_%C2%BC_HP_glitch) also fails in many cases due to - Pokémon Showdown implementing the health check based on floating point division instead of integer - division like on the cartridge (meaning the Substitute 1/4 glitch only occurs if the Pokémon's - maximum HP is evenly divisible by 4). Substitute also incorrectly blocks Dream Eater on - Pokémon Showdown and incorrectly still heals 1 HP for any draining moves if the attack does 0 - damage. Finally, Pokémon Showdown uses a `subFainted` field to track whether a Substitute was - broken to know when to nullify a move's effect, only it doesn't get cleared at the end of - the turn and can result in incorrect behavior on subsequent turns with the moves Mirror Move and - Metronome that invoke `runMove` (which is where `subFainted` gets cleared) on the user but skips - calling it for the eventual true target. +- **Substitute**: the [Substitute 1/4 glitch](https://glitchcity.wiki/Substitute_%C2%BC_HP_glitch) + fails in many cases due to Pokémon Showdown implementing the health check based on floating point + division instead of integer division like on the cartridge (meaning the Substitute 1/4 glitch only + occurs if the Pokémon's maximum HP is evenly divisible by 4). Substitute also incorrectly blocks + Dream Eater on Pokémon Showdown and incorrectly still heals 1 HP for any draining moves if the + attack does 0 damage. Finally, Pokémon Showdown uses a `subFainted` field to track whether a + Substitute was broken to know when to nullify a move's effect, only it doesn't get cleared at the + end of the turn and can result in incorrect behavior on subsequent turns with the moves Mirror + Move and Metronome that invoke `runMove` (which is where `subFainted` gets cleared) on the user + but skips calling it for the eventual true target. In addition to numerous cases where Pokémon Showdown uses the wrong type of message (e.g. `|-fail` vs. `|-miss|` vs. `|-immune|`, e.g. in the case of Leech Seed) which aren't documented here, Pokémon diff --git a/src/lib/gen1/mechanics.zig b/src/lib/gen1/mechanics.zig index 8f5dc8aa..ef7b4c41 100644 --- a/src/lib/gen1/mechanics.zig +++ b/src/lib/gen1/mechanics.zig @@ -618,17 +618,10 @@ fn beforeMove( return .err; } } - // Pokémon Showdown incorrectly changes the "target" of the confusion self-hit based - // on the targeting behavior of the confused Pokémon's selected move which results - // in the wrong behavior with respect to the Substitute + Confusion glitch - const target = if (showdown and Move.get(side.last_selected_move).target == .Self) - player - else - player.foe(); const uncapped = battle.last_damage; // Skipping adjustDamage / randomizeDamage / checkHit - _ = try applyDamage(battle, player, target, .Confusion, options); + _ = try applyDamage(battle, player, player.foe(), .Confusion, options); // Pokémon Showdown thinks that confusion damage is uncapped ¯\_(ツ)_/¯ if (showdown) battle.last_damage = uncapped; diff --git a/src/lib/gen1/test.zig b/src/lib/gen1/test.zig index 8fc93b81..836ee1d7 100644 --- a/src/lib/gen1/test.zig +++ b/src/lib/gen1/test.zig @@ -9688,7 +9688,6 @@ test "Substitute + Confusion glitch" { try t.log.expected.move(.{ P2.ident(1), Move.Supersonic, P1.ident(1) }); try t.log.expected.fail(.{ P1.ident(1), .None }); try t.log.expected.activate(.{ P1.ident(1), .Confusion }); - if (showdown) try t.log.expected.activate(.{ P1.ident(1), .Substitute }); try t.log.expected.turn(.{4}); // Pokémon Showdown incorrectly applies damage to the confused Pokémon's sub when @@ -9696,7 +9695,7 @@ test "Substitute + Confusion glitch" { try expectEqual(Result.Default, try t.update(move(3), move(1))); // (140/256) * (2/3) * (1/2) vs. (2/3) * (1/2) try if (showdown) t.expectProbability(35, 192) else t.expectProbability(1, 3); - try expectEqual(@as(u8, if (showdown) 2 else 7), t.actual.p1.active.volatiles.substitute); + try expectEqual(@as(u8, 7), t.actual.p1.active.volatiles.substitute); try t.verify(); } diff --git a/src/test/benchmark.ts b/src/test/benchmark.ts index ea71a52e..b34a03f9 100644 --- a/src/test/benchmark.ts +++ b/src/test/benchmark.ts @@ -5,13 +5,13 @@ import * as fs from 'fs'; import * as path from 'path'; import {Generation, Generations, ID, PokemonSet, StatsTable} from '@pkmn/data'; -import {Battle, Dex, PRNG, PRNGSeed, Pokemon, Side, SideID, Teams} from '@pkmn/sim'; +import {Battle, Dex, PRNG, Pokemon, Side, SideID, Teams} from '@pkmn/sim'; import minimist from 'minimist'; import * as engine from '../pkg'; import {newSeed, toBigInt} from './integration'; -import {Choices, formatFor, patch} from './showdown'; +import {Choices, PRNGSeed, formatFor, patch} from './showdown'; import {decimal, regression, summarize} from './stats'; const BLOCKLIST = ['mimic', 'metronome', 'mirrormove', 'transform'] as ID[]; @@ -43,15 +43,15 @@ export const Options = new class { const lookup = engine.Lookup.get(gen); const team: Partial[] = []; - const n = prng.randomChance(1, 100) ? prng.next(1, 5 + 1) : 6; + const n = prng.randomChance(1, 100) ? prng.random(1, 5 + 1) : 6; for (let i = 0; i < n; i++) { - const species = lookup.speciesByNum(prng.next(1, 151 + 1)); - const level = prng.randomChance(1, 20) ? prng.next(1, 99 + 1) : 100; + const species = lookup.speciesByNum(prng.random(1, 151 + 1)); + const level = prng.randomChance(1, 20) ? prng.random(1, 99 + 1) : 100; const ivs = {} as StatsTable; for (const stat of gen.stats) { if (stat === 'hp' || stat === 'spd') continue; - ivs[stat] = gen.stats.toIV(prng.randomChance(1, 5) ? prng.next(1, 15 + 1) : 15); + ivs[stat] = gen.stats.toIV(prng.randomChance(1, 5) ? prng.random(1, 15 + 1) : 15); } ivs.hp = gen.stats.toIV(gen.stats.getHPDV(ivs)); ivs.spd = ivs.spa; @@ -59,16 +59,16 @@ export const Options = new class { const evs = {} as StatsTable; for (const stat of gen.stats) { if (stat === 'spd') break; - const exp = prng.randomChance(1, 20) ? prng.next(0, 0xFFFF + 1) : 0xFFFF; + const exp = prng.randomChance(1, 20) ? prng.random(0, 0xFFFF + 1) : 0xFFFF; evs[stat] = Math.min(255, Math.trunc(Math.ceil(Math.sqrt(exp)))); } evs.spd = evs.spa; const moves: ID[] = []; - const m = prng.randomChance(1, 100) ? prng.next(1, 3 + 1) : 4; + const m = prng.randomChance(1, 100) ? prng.random(1, 3 + 1) : 4; for (let j = 0; j < m; j++) { let move: ID; - while (moves.includes((move = lookup.moveByNum(prng.next(1, 164 + 1)))) || + while (moves.includes((move = lookup.moveByNum(prng.random(1, 164 + 1)))) || BLOCKLIST.includes(move)); moves.push(move); } @@ -83,36 +83,36 @@ export const Options = new class { const lookup = engine.Lookup.get(gen); const team: Partial[] = []; - const n = prng.randomChance(1, 100) ? prng.next(1, 5 + 1) : 6; + const n = prng.randomChance(1, 100) ? prng.random(1, 5 + 1) : 6; for (let i = 0; i < n; i++) { - const species = lookup.speciesByNum(prng.next(1, 251 + 1)); - const level = prng.randomChance(1, 20) ? prng.next(1, 99 + 1) : 100; + const species = lookup.speciesByNum(prng.random(1, 251 + 1)); + const level = prng.randomChance(1, 20) ? prng.random(1, 99 + 1) : 100; const item = prng.randomChance(1, 10) ? undefined - : lookup.itemByNum(prng.next(1, 62 + 1)); + : lookup.itemByNum(prng.random(1, 62 + 1)); const ivs = {} as StatsTable; for (const stat of gen.stats) { if (stat === 'hp' || stat === 'spd') continue; - ivs[stat] = gen.stats.toIV(prng.randomChance(1, 5) ? prng.next(1, 15 + 1) : 15); + ivs[stat] = gen.stats.toIV(prng.randomChance(1, 5) ? prng.random(1, 15 + 1) : 15); } ivs.hp = gen.stats.toIV(gen.stats.getHPDV(ivs)); ivs.spd = ivs.spa; const evs = {} as StatsTable; for (const stat of gen.stats) { - const exp = prng.randomChance(1, 20) ? prng.next(0, 0xFFFF + 1) : 0xFFFF; + const exp = prng.randomChance(1, 20) ? prng.random(0, 0xFFFF + 1) : 0xFFFF; evs[stat] = Math.min(255, Math.trunc(Math.ceil(Math.sqrt(exp)))); } const moves: ID[] = []; - const m = prng.randomChance(1, 100) ? prng.next(1, 3 + 1) : 4; + const m = prng.randomChance(1, 100) ? prng.random(1, 3 + 1) : 4; for (let j = 0; j < m; j++) { let move: ID; - while (moves.includes((move = lookup.moveByNum(prng.next(1, 250 + 1))))); + while (moves.includes((move = lookup.moveByNum(prng.random(1, 250 + 1))))); moves.push(move); } - const happiness = prng.randomChance(1, 10 + 1) ? prng.next(0, 255) : 255; + const happiness = prng.randomChance(1, 10 + 1) ? prng.random(0, 255) : 255; team.push({species, level, item, ivs, evs, moves, happiness}); } @@ -202,9 +202,9 @@ const CONFIGURATIONS: {[name: string]: Configuration} = { battle.setPlayer('p2', {name: 'Player B', team: team2}); while (!battle.ended) { let possible = choices(battle, 'p1'); - const c1 = possible[p1.next(possible.length)]; + const c1 = possible[p1.random(possible.length)]; possible = choices(battle, 'p2'); - const c2 = possible[p2.next(possible.length)]; + const c2 = possible[p2.random(possible.length)]; battle.makeChoices(c1, c2); } turns += battle.turn; @@ -213,7 +213,7 @@ const CONFIGURATIONS: {[name: string]: Configuration} = { } } - return Promise.resolve([duration, turns, serialize(prng.seed)] as const); + return Promise.resolve([duration, turns, serialize(prng.getSeed() as PRNGSeed)] as const); }, }, '@pkmn/engine': { @@ -232,7 +232,7 @@ const CONFIGURATIONS: {[name: string]: Configuration} = { // since this code only runs in Pokémon Showdown compatibility mode we // can avoid handling that (and save a branch) as it doesn't implement // the softlock - const choose = (p: PRNG, choices: engine.Choice[]) => choices[p.next(choices.length)]; + const choose = (p: PRNG, choices: engine.Choice[]) => choices[p.random(choices.length)]; const p1 = new PRNG(newSeed(prng)); const p2 = new PRNG(newSeed(prng)); @@ -252,7 +252,7 @@ const CONFIGURATIONS: {[name: string]: Configuration} = { } } - return Promise.resolve([duration, turns, serialize(prng.seed)] as const); + return Promise.resolve([duration, turns, serialize(prng.getSeed() as PRNGSeed)] as const); }, }, 'libpkmn': { @@ -266,7 +266,8 @@ const CONFIGURATIONS: {[name: string]: Configuration} = { const libpkmn = (format: ID, prng: PRNG, battles: number, showdown = true) => { const warmup = Math.min(1000, Math.max(Math.floor(battles / 10), 1)); const exe = path.resolve(ROOT, 'build', 'bin', `benchmark${showdown ? '-showdown' : ''}`); - const stdout = sh(exe, [format[3], `${warmup}/${battles}`, serialize(prng.seed)]); + const stdout = + sh(exe, [format[3], `${warmup}/${battles}`, serialize(prng.getSeed() as PRNGSeed)]); const [duration, turn, seed] = stdout.split(','); return [BigInt(duration), Number(turn), seed.trim()] as const; }; @@ -406,7 +407,7 @@ if (require.main === module) { summary(data); } else if (previous) { const prng = new PRNG(seed); - regression(previous, data, (min, max) => prng.next(min, max)); + regression(previous, data, (min, max) => prng.random(min, max)); } else { for (const [name, samples] of Object.entries(data)) { console.log(`${name}\t${samples.join(',')}`); diff --git a/src/test/integration.ts b/src/test/integration.ts index af0be946..75f77b76 100644 --- a/src/test/integration.ts +++ b/src/test/integration.ts @@ -7,7 +7,7 @@ import * as tty from 'tty'; import {Generation, GenerationNum, Generations} from '@pkmn/data'; import {Protocol} from '@pkmn/protocol'; -import {Battle, BattleStreams, Dex, ID, PRNG, PRNGSeed, Streams, Teams, toID} from '@pkmn/sim'; +import {Battle, BattleStreams, Dex, ID, PRNG, Streams, Teams, toID} from '@pkmn/sim'; import * as sim from '@pkmn/sim/tools'; import {minify} from 'html-minifier'; import minimist from 'minimist'; @@ -19,7 +19,7 @@ import {LAYOUT, LE} from '../pkg/data'; import {error, render} from '../tools/debug'; import * as display from '../tools/display'; -import {Choices, FILTER, formatFor, patch} from './showdown'; +import {Choices, FILTER, PRNGSeed, formatFor, patch} from './showdown'; const ROOT = path.resolve(__dirname, '..', '..'); const ANSI = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; @@ -73,7 +73,7 @@ class Runner { // try again! (note that validate marks used to ensure progress) if (this.skip) return Promise.resolve(); - const seed = this.prng.seed.slice() as PRNGSeed; + const seed = this.prng.getSeed().slice() as PRNGSeed; const create = (o: sim.AIOptions) => (s: Streams.ObjectReadWriteStream) => o.createAI(s, {seed: newSeed(this.prng), move: 0.7, mega: 0.6, ...o}); @@ -238,7 +238,7 @@ function play( } const request = partial.showdown.result = toResult(control, p1options.spec.name); - partial.showdown.seed = control.prng.seed.slice(); + partial.showdown.seed = control.prng.getSeed().slice() as PRNGSeed; const chunk = control.getDebugLog(); partial.showdown.chunk = chunk; @@ -253,7 +253,7 @@ function play( compare(chunk, parsed); assert.deepEqual(result, request); - assert.deepEqual(battle.prng, control.prng.seed); + assert.deepEqual(battle.prng, control.prng.getSeed()); if (replay && index >= replay.length) break; [c1, c2] = getChoices(); @@ -272,7 +272,7 @@ function play( } while (!control.ended); if (control.ended) assert.notEqual(result.type, undefined); - assert.deepEqual(battle.prng, control.prng.seed); + assert.deepEqual(battle.prng, control.prng.getSeed()); } catch (err: any) { if (!replay) { const num = toBigInt(seed); @@ -831,7 +831,7 @@ export async function run(gens: Generations, options: string | Flags, errors?: E } export function newSeed(prng: PRNG): PRNGSeed { - return [prng.next(0x10000), prng.next(0x10000), prng.next(0x10000), prng.next(0x10000)]; + return [prng.random(0x10000), prng.random(0x10000), prng.random(0x10000), prng.random(0x10000)]; } export function toBigInt(seed: PRNGSeed): bigint { @@ -896,13 +896,13 @@ if (require.main === module) { unit ? +argv.duration.slice(0, -1) * {s: 1e3, m: 6e4, h: 3.6e6}[unit]! : argv.duration; argv.cycles = argv.cycles ?? (duration ? 1 : 10); const prng = new PRNG(argv.seed ? argv.seed.split(',').map((s: string) => Number(s)) : null); - if (!argv.seed) console.error('Seed:', prng.seed.join(',')); + if (!argv.seed) console.error('Seed:', prng.getSeed().join(',')); const options = {prng, log: process.stdout.isTTY, ...argv, duration}; const errors = argv.summary ? new Errors() : undefined; const code = await run(gens, options, errors); if (code && errors) { - const file = path.join(ROOT, 'logs', `${prng.seed.join('-')}.html`); + const file = path.join(ROOT, 'logs', `${prng.getSeed().join('-')}.html`); const link = path.join(ROOT, 'logs', 'summary.html'); fs.writeFileSync(file, errors.toString()); symlink(file, link); diff --git a/src/test/showdown.ts b/src/test/showdown.ts index 76bffd65..2cccb2f4 100644 --- a/src/test/showdown.ts +++ b/src/test/showdown.ts @@ -3,9 +3,11 @@ import * as path from 'path'; import {Generation, PokemonSet} from '@pkmn/data'; import { ActionChoice, Battle, BattleQueue, Effect, Field, ID, PRNG, - PRNGSeed, Pokemon, Side, SideID, extractChannelMessages, + Pokemon, Side, SideID, extractChannelMessages, } from '@pkmn/sim'; +export type PRNGSeed = [number, number, number, number]; + export interface Roll { key: string; value: number; @@ -39,7 +41,7 @@ export const ROLLS = { return (move: string, skip: string[] = []) => { const moves = all.filter(m => !skip.includes(m)); const value = ranged(moves.indexOf(move) + 1, moves.length) - 1; - return {key: 'data/moves.ts:12200:23', value}; + return {key: 'data/mods/gen4/moves.ts:1064:23', value}; }; }, }; @@ -216,13 +218,14 @@ export const patch = { }; } if (debug) { - const next = battle.prng.next.bind(battle.prng); - battle.prng.next = (from?: number, to?: number) => { - const seed = battle.prng.seed.join(','); + const next = battle.prng.random.bind(battle.prng); + battle.prng.random = (from?: number, to?: number) => { + const orig = battle.prng.getSeed().join(); const result = next(from, to); - const roll = (battle.prng.seed[0] << 16 >>> 0) + battle.prng.seed[1]; + const seed = battle.prng.getSeed() as PRNGSeed; + const roll = (seed[0] << 16 >>> 0) + seed[1]; const original = `0x${(roll).toString(16).padStart(8, '0').toUpperCase()}`; - battle.add('debug', location(), seed, original); + battle.add('debug', location(), orig, original); return result; }; } else { @@ -393,7 +396,7 @@ export class FixedRNG extends PRNG { this.index = 0; } - override next(from?: number, to?: number): number { + override random(from?: number, to?: number): number { if (this.index >= this.rolls.length) throw new Error('Insufficient number of rolls provided'); const roll = this.rolls[this.index++]; const n = this.index; @@ -414,18 +417,10 @@ export class FixedRNG extends PRNG { return result; } - override get startingSeed(): PRNGSeed { - throw new Error('Unsupported operation'); - } - override clone(): PRNG { throw new Error('Unsupported operation'); } - override nextFrame(): PRNGSeed { - throw new Error('Unsupported operation'); - } - exhausted(): boolean { return this.index === this.rolls.length; } @@ -452,9 +447,9 @@ function filter(raw: string[]) { const METHOD = /^ {4}at ((?:\w|\.)+) \((.*\d)\)/; const NON_TERMINAL = new Set([ 'location', 'PRNG.randomChance', 'PRNG.sample', - 'FixedRNG.next', 'FixedRNG.randomChance', 'FixedRNG.sample', 'FixedRNG.shuffle', + 'FixedRNG.random', 'FixedRNG.randomChance', 'FixedRNG.sample', 'FixedRNG.shuffle', 'Battle.random', 'Battle.randomChance', 'Battle.sample', 'Battle.speedSort', 'Battle.runEvent', - 'PRNG.battle.prng.next', 'PRNG.battle.prng.shuffle', + 'PRNG.battle.prng.random', 'PRNG.battle.prng.shuffle', ]); function location() { diff --git a/src/test/showdown/gen1.test.ts b/src/test/showdown/gen1.test.ts index 62e47f00..109d3da4 100644 --- a/src/test/showdown/gen1.test.ts +++ b/src/test/showdown/gen1.test.ts @@ -7205,8 +7205,7 @@ describe('Gen 1', () => { // selecting a self-targeting move battle.makeChoices('move 3', 'move 1'); expect(battle.p1.pokemon[0].hp).toBe(p1hp); - // expect(battle.p1.pokemon[0].volatiles['substitute'].hp).toBe(7); - expect(battle.p1.pokemon[0].volatiles['substitute'].hp).toBe(2); + expect(battle.p1.pokemon[0].volatiles['substitute'].hp).toBe(7); verify(battle, [ '|move|p2a: Zubat|Supersonic|p1a: Bulbasaur', @@ -7223,7 +7222,6 @@ describe('Gen 1', () => { '|move|p2a: Zubat|Supersonic|p1a: Bulbasaur', '|-fail|p1a: Bulbasaur', '|-activate|p1a: Bulbasaur|confusion', - '|-activate|p1a: Bulbasaur|Substitute|[damage]', '|turn|4', ]); } diff --git a/src/test/showdown/gen2.test.ts b/src/test/showdown/gen2.test.ts index ef644d1a..f1927067 100644 --- a/src/test/showdown/gen2.test.ts +++ b/src/test/showdown/gen2.test.ts @@ -8123,7 +8123,7 @@ describe('Gen 2', () => { }); test('Present effect', () => { - const present = {key: 'data/moves.ts:14411:22', value: ranged(1, 10) - 1}; + const present = {key: 'data/moves.ts:14405:22', value: ranged(1, 10) - 1}; const present40 = {...present, value: ranged(6, 10) - 1}; const present120 = {...present, value: ranged(10, 10) - 1}; const battle = startBattle([ @@ -8330,7 +8330,7 @@ describe('Gen 2', () => { }); test('Magnitude effect', () => { - const mag8 = {key: 'data/moves.ts:11277:19', value: ranged(85, 100) - 1}; + const mag8 = {key: 'data/moves.ts:11273:19', value: ranged(85, 100) - 1}; const mag5 = {...mag8, value: ranged(15, 100) - 1}; const battle = startBattle([ QKC, mag8, NO_CRIT, MIN_DMG, QKC, mag5, NO_CRIT, MIN_DMG, NO_CRIT, MIN_DMG, QKC,