@pkmn/sim 0.5.16 → 0.5.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/build/config/formats.js +32 -51
  2. package/build/config/formats.js.map +1 -1
  3. package/build/data/items.js +1 -3
  4. package/build/data/items.js.map +1 -1
  5. package/build/data/learnsets.js +2 -2
  6. package/build/data/learnsets.js.map +1 -1
  7. package/build/data/mods/gen1/formats-data.js +1 -1
  8. package/build/data/mods/gen1/formats-data.js.map +1 -1
  9. package/build/data/mods/gen1/moves.js +1 -4
  10. package/build/data/mods/gen1/moves.js.map +1 -1
  11. package/build/data/mods/gen3/moves.js +0 -7
  12. package/build/data/mods/gen3/moves.js.map +1 -1
  13. package/build/data/mods/gen3/scripts.js +2 -2
  14. package/build/data/mods/gen3/scripts.js.map +1 -1
  15. package/build/data/mods/gen4/moves.js +1 -1
  16. package/build/data/mods/gen4/moves.js.map +1 -1
  17. package/build/data/mods/gen4/rulesets.js +2 -1
  18. package/build/data/mods/gen4/rulesets.js.map +1 -1
  19. package/build/data/mods/gen5/rulesets.js +2 -1
  20. package/build/data/mods/gen5/rulesets.js.map +1 -1
  21. package/build/data/mods/gen7/formats-data.js +4 -4
  22. package/build/data/mods/gen7/formats-data.js.map +1 -1
  23. package/build/data/mods/gen7/rulesets.js +2 -1
  24. package/build/data/mods/gen7/rulesets.js.map +1 -1
  25. package/build/data/moves.js +55 -74
  26. package/build/data/moves.js.map +1 -1
  27. package/build/data/pokedex.js +2 -2
  28. package/build/data/pokedex.js.map +1 -1
  29. package/build/data/rulesets.js +3 -4
  30. package/build/data/rulesets.js.map +1 -1
  31. package/build/data/text/items.js +1 -0
  32. package/build/data/text/items.js.map +1 -1
  33. package/build/data/text/moves.js +5 -3
  34. package/build/data/text/moves.js.map +1 -1
  35. package/build/sim/battle-actions.js +9 -1
  36. package/build/sim/battle-actions.js.map +1 -1
  37. package/build/sim/battle.js +39 -1
  38. package/build/sim/battle.js.map +1 -1
  39. package/build/sim/dex-conditions.d.ts +1 -0
  40. package/build/sim/dex-conditions.js.map +1 -1
  41. package/build/sim/exported-global-types.d.ts +1 -0
  42. package/build/sim/global-types.d.ts +1 -0
  43. package/build/sim/team-validator.js +15 -4
  44. package/build/sim/team-validator.js.map +1 -1
  45. package/build/sim/tools/exhaustive-runner.d.ts +8 -0
  46. package/build/sim/tools/exhaustive-runner.js +18 -7
  47. package/build/sim/tools/exhaustive-runner.js.map +1 -1
  48. package/config/formats.ts +32 -51
  49. package/data/items.ts +1 -3
  50. package/data/learnsets.ts +2 -2
  51. package/data/mods/gen1/formats-data.ts +1 -1
  52. package/data/mods/gen1/moves.ts +1 -4
  53. package/data/mods/gen3/moves.ts +0 -7
  54. package/data/mods/gen3/scripts.ts +3 -3
  55. package/data/mods/gen4/moves.ts +1 -1
  56. package/data/mods/gen4/rulesets.ts +2 -1
  57. package/data/mods/gen5/rulesets.ts +2 -1
  58. package/data/mods/gen7/formats-data.ts +4 -4
  59. package/data/mods/gen7/rulesets.ts +2 -1
  60. package/data/moves.ts +55 -65
  61. package/data/pokedex.ts +2 -2
  62. package/data/rulesets.ts +3 -6
  63. package/data/text/items.ts +2 -0
  64. package/data/text/moves.ts +6 -3
  65. package/package.json +1 -1
  66. package/sim/battle-actions.ts +13 -1
  67. package/sim/battle.ts +38 -1
  68. package/sim/dex-conditions.ts +1 -0
  69. package/sim/exported-global-types.ts +3 -0
  70. package/sim/global-types.ts +3 -0
  71. package/sim/team-validator.ts +16 -4
  72. package/sim/tools/exhaustive-runner.ts +29 -11
@@ -1934,6 +1934,8 @@ export const MovesText: {[k: string]: MoveText} = {
1934
1934
  name: "Flip Turn",
1935
1935
  desc: "If this move is successful and the user has not fainted, the user switches out even if it is trapped and is replaced immediately by a selected party member. The user does not switch out if there are no unfainted party members, or if the target switched out using an Eject Button or through the effect of the Emergency Exit or Wimp Out Abilities.",
1936
1936
  shortDesc: "User switches out after damaging the target.",
1937
+
1938
+ switchOut: "#uturn",
1937
1939
  },
1938
1940
  floatyfall: {
1939
1941
  name: "Floaty Fall",
@@ -3695,7 +3697,7 @@ export const MovesText: {[k: string]: MoveText} = {
3695
3697
  },
3696
3698
  metronome: {
3697
3699
  name: "Metronome",
3698
- desc: "A random move is selected for use, other than After You, Apple Acid, Assist, Astral Barrage, Aura Wheel, Baneful Bunker, Beak Blast, Behemoth Bash, Behemoth Blade, Belch, Bestow, Body Press, Branch Poke, Breaking Swipe, Celebrate, Chatter, Clangorous Soul, Copycat, Counter, Covet, Crafty Shield, Decorate, Destiny Bond, Detect, Diamond Storm, Double Iron Bash, Dragon Ascent, Dragon Energy, Drum Beating, Dynamax Cannon, Endure, Eternabeam, False Surrender, Feint, Fiery Wrath, Fleur Cannon, Focus Punch, Follow Me, Freeze Shock, Freezing Glare, Glacial Lance, Grav Apple, Helping Hand, Hold Hands, Hyperspace Fury, Hyperspace Hole, Ice Burn, Instruct, Jungle Healing, King's Shield, Life Dew, Light of Ruin, Mat Block, Me First, Meteor Assault, Metronome, Mimic, Mind Blown, Mirror Coat, Mirror Move, Moongeist Beam, Nature Power, Nature's Madness, Obstruct, Origin Pulse, Overdrive, Photon Geyser, Plasma Fists, Precipice Blades, Protect, Pyro Ball, Quash, Quick Guard, Rage Powder, Relic Song, Secret Sword, Shell Trap, Sketch, Sleep Talk, Snap Trap, Snarl, Snatch, Snore, Spectral Thief, Spiky Shield, Spirit Break, Spotlight, Steam Eruption, Steel Beam, Strange Steam, Struggle, Sunsteel Strike, Surging Strikes, Switcheroo, Techno Blast, Thief, Thousand Arrows, Thousand Waves, Thunder Cage, Thunderous Kick, Transform, Trick, V-create, Wicked Blow, or Wide Guard.",
3700
+ desc: "A random move is selected for use, other than After You, Apple Acid, Assist, Astral Barrage, Aura Wheel, Baneful Bunker, Beak Blast, Behemoth Bash, Behemoth Blade, Belch, Bestow, Body Press, Branch Poke, Breaking Swipe, Celebrate, Chatter, Clangorous Soul, Copycat, Counter, Covet, Crafty Shield, Decorate, Destiny Bond, Detect, Diamond Storm, Double Iron Bash, Dragon Ascent, Dragon Energy, Dragon Hammer, Drum Beating, Dynamax Cannon, Endure, Eternabeam, False Surrender, Feint, Fiery Wrath, Fleur Cannon, Focus Punch, Follow Me, Freeze Shock, Freezing Glare, Glacial Lance, Grav Apple, Helping Hand, Hold Hands, Hyperspace Fury, Hyperspace Hole, Ice Burn, Instruct, Jungle Healing, King's Shield, Life Dew, Light of Ruin, Mat Block, Me First, Meteor Assault, Metronome, Mimic, Mind Blown, Mirror Coat, Mirror Move, Moongeist Beam, Nature Power, Nature's Madness, Obstruct, Origin Pulse, Overdrive, Photon Geyser, Plasma Fists, Precipice Blades, Protect, Pyro Ball, Quash, Quick Guard, Rage Powder, Relic Song, Secret Sword, Shell Trap, Sketch, Sleep Talk, Snap Trap, Snarl, Snatch, Snore, Spectral Thief, Spiky Shield, Spirit Break, Spotlight, Steam Eruption, Steel Beam, Strange Steam, Struggle, Sunsteel Strike, Surging Strikes, Switcheroo, Techno Blast, Thief, Thousand Arrows, Thousand Waves, Thunder Cage, Thunderous Kick, Transform, Trick, V-create, Wicked Blow, or Wide Guard.",
3699
3701
  shortDesc: "Picks a random move.",
3700
3702
  gen7: {
3701
3703
  desc: "A random move is selected for use, other than After You, Assist, Baneful Bunker, Beak Blast, Belch, Bestow, Celebrate, Chatter, Copycat, Counter, Covet, Crafty Shield, Destiny Bond, Detect, Diamond Storm, Dragon Ascent, Endure, Feint, Fleur Cannon, Focus Punch, Follow Me, Freeze Shock, Helping Hand, Hold Hands, Hyperspace Fury, Hyperspace Hole, Ice Burn, Instruct, King's Shield, Light of Ruin, Mat Block, Me First, Metronome, Mimic, Mind Blown, Mirror Coat, Mirror Move, Nature Power, Origin Pulse, Photon Geyser, Plasma Fists, Precipice Blades, Protect, Quash, Quick Guard, Rage Powder, Relic Song, Secret Sword, Shell Trap, Sketch, Sleep Talk, Snarl, Snatch, Snore, Spectral Thief, Spiky Shield, Spotlight, Steam Eruption, Struggle, Switcheroo, Techno Blast, Thief, Thousand Arrows, Thousand Waves, Transform, Trick, V-create, or Wide Guard.",
@@ -3707,13 +3709,13 @@ export const MovesText: {[k: string]: MoveText} = {
3707
3709
  desc: "A random move is selected for use, other than After You, Assist, Bestow, Chatter, Copycat, Counter, Covet, Destiny Bond, Detect, Endure, Feint, Focus Punch, Follow Me, Freeze Shock, Helping Hand, Ice Burn, Me First, Metronome, Mimic, Mirror Coat, Mirror Move, Nature Power, Protect, Quash, Quick Guard, Rage Powder, Relic Song, Secret Sword, Sketch, Sleep Talk, Snarl, Snatch, Snore, Struggle, Switcheroo, Techno Blast, Thief, Transform, Trick, V-create, or Wide Guard.",
3708
3710
  },
3709
3711
  gen4: {
3710
- desc: "A random move is selected for use, other than Assist, Chatter, Copycat, Counter, Covet, Destiny Bond, Detect, Endure, Feint, Focus Punch, Follow Me, Helping Hand, Me First, Metronome, Mimic, Mirror Coat, Mirror Move, Protect, Sketch, Sleep Talk, Snatch, Struggle, Switcheroo, Thief, or Trick.",
3712
+ desc: "A random move is selected for use, other than Assist, Chatter, Copycat, Counter, Covet, Destiny Bond, Detect, Endure, Feint, Focus Punch, Follow Me, Helping Hand, Me First, Metronome, Mimic, Mirror Coat, Mirror Move, Protect, Sketch, Sleep Talk, Snatch, Struggle, Switcheroo, Thief, Trick, or any move the user already knows.",
3711
3713
  },
3712
3714
  gen3: {
3713
3715
  desc: "A random move is selected for use, other than Counter, Covet, Destiny Bond, Detect, Endure, Focus Punch, Follow Me, Helping Hand, Metronome, Mimic, Mirror Coat, Protect, Sketch, Sleep Talk, Snatch, Struggle, Thief, or Trick.",
3714
3716
  },
3715
3717
  gen2: {
3716
- desc: "A random move is selected for use, other than Counter, Destiny Bond, Detect, Endure, Metronome, Mimic, Mirror Coat, Protect, Sketch, Sleep Talk, Struggle, or Thief.",
3718
+ desc: "A random move is selected for use, other than Counter, Destiny Bond, Detect, Endure, Metronome, Mimic, Mirror Coat, Protect, Sketch, Sleep Talk, Struggle, Thief, or any move the user already knows.",
3717
3719
  },
3718
3720
  gen1: {
3719
3721
  desc: "A random move is selected for use, other than Metronome or Struggle.",
@@ -4167,6 +4169,7 @@ export const MovesText: {[k: string]: MoveText} = {
4167
4169
  },
4168
4170
 
4169
4171
  heal: "#memento",
4172
+ switchOut: "#uturn",
4170
4173
  },
4171
4174
  payback: {
4172
4175
  name: "Payback",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkmn/sim",
3
- "version": "0.5.16",
3
+ "version": "0.5.17",
4
4
  "description": "An automatically generated extraction of just the simulator portion of Pokémon Showdown",
5
5
  "homepage": "https://psim.us",
6
6
  "main": "build/sim/index.js",
@@ -133,6 +133,8 @@ export class BattleActions {
133
133
  oldActive.isActive = false;
134
134
  oldActive.isStarted = false;
135
135
  oldActive.usedItemThisTurn = false;
136
+ oldActive.statsRaisedThisTurn = false;
137
+ oldActive.statsLoweredThisTurn = false;
136
138
  oldActive.position = pokemon.position;
137
139
  pokemon.position = pos;
138
140
  side.pokemon[pokemon.position] = pokemon;
@@ -178,7 +180,17 @@ export class BattleActions {
178
180
  }
179
181
  runSwitch(pokemon: Pokemon) {
180
182
  this.battle.runEvent('Swap', pokemon);
181
- this.battle.runEvent('SwitchIn', pokemon);
183
+
184
+ if (this.battle.gen >= 5) {
185
+ this.battle.runEvent('SwitchIn', pokemon);
186
+ }
187
+
188
+ this.battle.runEvent('EntryHazard', pokemon);
189
+
190
+ if (this.battle.gen <= 4) {
191
+ this.battle.runEvent('SwitchIn', pokemon);
192
+ }
193
+
182
194
  if (this.battle.gen <= 2 && !pokemon.side.faintedThisTurn && pokemon.draggedIn !== this.battle.turn) {
183
195
  this.battle.runEvent('AfterSwitchInSelf', pokemon);
184
196
  }
package/sim/battle.ts CHANGED
@@ -711,7 +711,7 @@ export class Battle {
711
711
  }
712
712
  }
713
713
 
714
- if (eventid === 'Invulnerability' || eventid === 'TryHit' || eventid === 'DamagingHit') {
714
+ if (['Invulnerability', 'TryHit', 'DamagingHit', 'EntryHazard'].includes(eventid)) {
715
715
  handlers.sort(Battle.compareLeftToRightOrder);
716
716
  } else if (fastExit) {
717
717
  handlers.sort(Battle.compareRedirectOrder);
@@ -2413,6 +2413,43 @@ export class Battle {
2413
2413
 
2414
2414
  this.add('start');
2415
2415
 
2416
+ // Change Zacian/Zamazenta into their Crowned formes
2417
+ for (const pokemon of this.getAllPokemon()) {
2418
+ let rawSpecies: Species | null = null;
2419
+ if (pokemon.species.id === 'zacian' && pokemon.item === 'rustedsword') {
2420
+ rawSpecies = this.dex.species.get('Zacian-Crowned');
2421
+ } else if (pokemon.species.id === 'zamazenta' && pokemon.item === 'rustedshield') {
2422
+ rawSpecies = this.dex.species.get('Zamazenta-Crowned');
2423
+ }
2424
+ if (!rawSpecies) continue;
2425
+ const species = pokemon.setSpecies(rawSpecies);
2426
+ if (!species) continue;
2427
+ pokemon.baseSpecies = rawSpecies;
2428
+ pokemon.details = species.name + (pokemon.level === 100 ? '' : ', L' + pokemon.level) +
2429
+ (pokemon.gender === '' ? '' : ', ' + pokemon.gender) + (pokemon.set.shiny ? ', shiny' : '');
2430
+ pokemon.setAbility(species.abilities['0'], null, true);
2431
+ pokemon.baseAbility = pokemon.ability;
2432
+
2433
+ const behemothMove: {[k: string]: string} = {
2434
+ 'Zacian-Crowned': 'behemothblade', 'Zamazenta-Crowned': 'behemothbash',
2435
+ };
2436
+ const ironHead = pokemon.baseMoves.indexOf('ironhead');
2437
+ if (ironHead >= 0) {
2438
+ const move = this.dex.moves.get(behemothMove[rawSpecies.name]);
2439
+ pokemon.baseMoveSlots[ironHead] = {
2440
+ move: move.name,
2441
+ id: move.id,
2442
+ pp: (move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5,
2443
+ maxpp: (move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5,
2444
+ target: move.target,
2445
+ disabled: false,
2446
+ disabledSource: '',
2447
+ used: false,
2448
+ };
2449
+ pokemon.moveSlots = pokemon.baseMoveSlots.slice();
2450
+ }
2451
+ }
2452
+
2416
2453
  if (this.format.onBattleStart) this.format.onBattleStart.call(this);
2417
2454
  for (const rule of this.ruleTable.keys()) {
2418
2455
  if ('+*-!'.includes(rule.charAt(0))) continue;
@@ -53,6 +53,7 @@ export interface EventMethods {
53
53
  onDragOut?: (this: Battle, pokemon: Pokemon, source?: Pokemon, move?: ActiveMove) => void;
54
54
  onEatItem?: (this: Battle, item: Item, pokemon: Pokemon) => void;
55
55
  onEffectiveness?: MoveEventMethods['onEffectiveness'];
56
+ onEntryHazard?: (this: Battle, pokemon: Pokemon) => void;
56
57
  onFaint?: CommonHandlers['VoidEffect'];
57
58
  onFlinch?: ((this: Battle, pokemon: Pokemon) => boolean | void) | boolean;
58
59
  onFractionalPriority?: CommonHandlers['ModifierSourceMove'] | -0.1;
@@ -312,6 +312,9 @@ export interface ModdedBattlePokemon {
312
312
  clearBoosts?: (this: Pokemon) => void;
313
313
  calculateStat?: (this: Pokemon, statName: StatIDExceptHP, boost: number, modifier?: number) => number;
314
314
  cureStatus?: (this: Pokemon, silent?: boolean) => boolean;
315
+ formeChange?: (
316
+ this: Pokemon, speciesId: string | Species, source: Effect, isPermanent?: boolean, message?: string
317
+ ) => boolean;
315
318
  getAbility?: (this: Pokemon) => Ability;
316
319
  getActionSpeed?: (this: Pokemon) => number;
317
320
  getItem?: (this: Pokemon) => Item;
@@ -312,6 +312,9 @@ interface ModdedBattlePokemon {
312
312
  clearBoosts?: (this: Pokemon) => void;
313
313
  calculateStat?: (this: Pokemon, statName: StatIDExceptHP, boost: number, modifier?: number) => number;
314
314
  cureStatus?: (this: Pokemon, silent?: boolean) => boolean;
315
+ formeChange?: (
316
+ this: Pokemon, speciesId: string | Species, source: Effect, isPermanent?: boolean, message?: string
317
+ ) => boolean;
315
318
  getAbility?: (this: Pokemon) => Ability;
316
319
  getActionSpeed?: (this: Pokemon) => number;
317
320
  getItem?: (this: Pokemon) => Item;
@@ -543,6 +543,10 @@ export class TeamValidator {
543
543
  tierSpecies = dex.species.get('Kyogre-Primal');
544
544
  } else if (canMegaEvo && species.id === 'rayquaza' && set.moves.map(toID).includes('dragonascent' as ID)) {
545
545
  tierSpecies = dex.species.get('Rayquaza-Mega');
546
+ } else if (item.id === 'rustedsword' && species.id === 'zacian') {
547
+ tierSpecies = dex.species.get('Zacian-Crowned');
548
+ } else if (item.id === 'rustedshield' && species.id === 'zamazenta') {
549
+ tierSpecies = dex.species.get('Zamazenta-Crowned');
546
550
  }
547
551
  }
548
552
 
@@ -1315,10 +1319,10 @@ export class TeamValidator {
1315
1319
  const crowned: {[k: string]: string} = {
1316
1320
  'Zacian-Crowned': 'behemothblade', 'Zamazenta-Crowned': 'behemothbash',
1317
1321
  };
1318
- if (set.species in crowned) {
1319
- const ironHead = set.moves.map(toID).indexOf('ironhead' as ID);
1320
- if (ironHead >= 0) {
1321
- set.moves[ironHead] = crowned[set.species];
1322
+ if (species.name in crowned) {
1323
+ const behemothMove = set.moves.map(toID).indexOf(crowned[species.name] as ID);
1324
+ if (behemothMove >= 0) {
1325
+ set.moves[behemothMove] = 'ironhead';
1322
1326
  }
1323
1327
  }
1324
1328
  return problems;
@@ -1328,6 +1332,14 @@ export class TeamValidator {
1328
1332
  const dex = this.dex;
1329
1333
  const ruleTable = this.ruleTable;
1330
1334
 
1335
+ // https://www.smogon.com/forums/posts/8659168
1336
+ if (
1337
+ (tierSpecies.id === 'zamazentacrowned' && species.id === 'zamazenta') ||
1338
+ (tierSpecies.id === 'zaciancrowned' && species.id === 'zacian')
1339
+ ) {
1340
+ species = tierSpecies;
1341
+ }
1342
+
1331
1343
  setHas['pokemon:' + species.id] = true;
1332
1344
  setHas['basepokemon:' + toID(species.baseSpecies)] = true;
1333
1345
 
@@ -19,10 +19,18 @@ export interface ExhaustiveRunnerOptions {
19
19
  maxGames?: number;
20
20
  maxFailures?: number;
21
21
  dual?: boolean | 'debug';
22
+ possible?: ExhaustiveRunnerPossibilites;
22
23
  runner?: (options: RunnerOptions) => Promise<void>;
23
24
  cmd?: (cycles: number, format: string, seed: string) => string;
24
25
  }
25
26
 
27
+ export interface ExhaustiveRunnerPossibilites {
28
+ pokemon?: ID[];
29
+ items?: ID[];
30
+ abilities?: ID[];
31
+ moves?: ID[];
32
+ }
33
+
26
34
  export class ExhaustiveRunner {
27
35
  static readonly DEFAULT_CYCLES = 1;
28
36
  static readonly MAX_FAILURES = 10;
@@ -46,6 +54,7 @@ export class ExhaustiveRunner {
46
54
  private readonly maxGames?: number;
47
55
  private readonly maxFailures?: number;
48
56
  private readonly dual: boolean | 'debug';
57
+ private readonly possible?: ExhaustiveRunnerPossibilites;
49
58
 
50
59
  private readonly runner: (options: RunnerOptions) => Promise<void>;
51
60
  private readonly cmd: (cycles: number, format: string, seed: string) => string;
@@ -63,6 +72,7 @@ export class ExhaustiveRunner {
63
72
  this.maxFailures = options.maxFailures || ExhaustiveRunner.MAX_FAILURES;
64
73
  this.dual = options.dual || false;
65
74
  this.runner = options.runner || ((o: RunnerOptions) => new Runner(o).run());
75
+ this.possible = options.possible;
66
76
  this.cmd = options.cmd || ((cycles: number, format: string, seed: string) =>
67
77
  `node tools/simulate exhaustive --cycles=${cycles} --format=${format} --seed=${seed}`);
68
78
 
@@ -93,7 +103,7 @@ export class ExhaustiveRunner {
93
103
  error: true,
94
104
  });
95
105
 
96
- if (this.log) this.logProgress(pools);
106
+ if (this.log) this.logProgress(dex, pools);
97
107
  } catch (err) {
98
108
  this.failures++;
99
109
  console.error(
@@ -110,23 +120,31 @@ export class ExhaustiveRunner {
110
120
 
111
121
  private createPools(dex: typeof Dex): Pools {
112
122
  return {
113
- pokemon: new Pool(ExhaustiveRunner.onlyValid(dex.gen, dex.data.Pokedex, p => dex.species.get(p),
114
- (_, p) => (p.name !== 'Pichu-Spiky-eared' && p.name.substr(0, 8) !== 'Pikachu-')), this.prng),
115
- items: new Pool(ExhaustiveRunner.onlyValid(dex.gen, dex.data.Items, i => dex.items.get(i)), this.prng),
116
- abilities: new Pool(ExhaustiveRunner.onlyValid(dex.gen, dex.data.Abilities, a => dex.abilities.get(a)), this.prng),
117
- moves: new Pool(ExhaustiveRunner.onlyValid(dex.gen, dex.data.Moves, m => dex.moves.get(m),
118
- m => (m !== 'struggle' && (m === 'hiddenpower' || m.substr(0, 11) !== 'hiddenpower'))), this.prng),
123
+ pokemon: new Pool(this.possible?.pokemon ??
124
+ ExhaustiveRunner.onlyValid(dex.gen, dex.data.Pokedex, p => dex.species.get(p), (_, p) =>
125
+ (p.name !== 'Pichu-Spiky-eared' && p.name.substr(0, 8) !== 'Pikachu-')), this.prng),
126
+ items: new Pool(this.possible?.items ??
127
+ ExhaustiveRunner.onlyValid(dex.gen, dex.data.Items, i => dex.items.get(i)), this.prng),
128
+ abilities: new Pool(this.possible?.abilities ??
129
+ ExhaustiveRunner.onlyValid(dex.gen, dex.data.Abilities, a => dex.abilities.get(a)), this.prng),
130
+ moves: new Pool(this.possible?.moves ??
131
+ ExhaustiveRunner.onlyValid(dex.gen, dex.data.Moves, m => dex.moves.get(m), m =>
132
+ (m !== 'struggle' && (m === 'hiddenpower' || m.substr(0, 11) !== 'hiddenpower'))), this.prng),
119
133
  };
120
134
  }
121
135
 
122
- private logProgress(p: Pools) {
136
+ private logProgress(dex: typeof Dex, p: Pools) {
123
137
  // `\r` = return to the beginning of the line
124
138
  // `\x1b[k` (`\e[K`) = clear all characters from cursor position to EOL
125
139
  if (this.games) process.stdout.write('\r\x1b[K');
140
+
141
+ const msg = [`[${this.format}] P:${p.pokemon}`];
142
+ if (dex.gen >= 2) msg.push(`I:${p.items}`);
143
+ if (dex.gen >= 3) msg.push(`A:${p.abilities}`);
144
+ msg.push(`M:${p.moves} = ${this.games}`);
145
+
126
146
  // Deliberately don't print a `\n` character so that we can overwrite
127
- process.stdout.write(
128
- `[${this.format}] P:${p.pokemon} I:${p.items} A:${p.abilities} M:${p.moves} = ${this.games}`
129
- );
147
+ process.stdout.write(msg.join(' '));
130
148
  }
131
149
 
132
150
  private static getSignatures(dex: typeof Dex, pools: Pools): Map<string, {item: string, move?: string}[]> {