@pkmn/sim 0.5.5 → 0.5.8

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 (71) hide show
  1. package/build/config/formats.js +325 -254
  2. package/build/config/formats.js.map +1 -1
  3. package/build/data/aliases.js +4 -4
  4. package/build/data/aliases.js.map +1 -1
  5. package/build/data/formats-data.js +130 -17
  6. package/build/data/formats-data.js.map +1 -1
  7. package/build/data/items.js +2 -2
  8. package/build/data/items.js.map +1 -1
  9. package/build/data/learnsets.js +6 -5
  10. package/build/data/learnsets.js.map +1 -1
  11. package/build/data/mods/gen2/moves.js +13 -1
  12. package/build/data/mods/gen2/moves.js.map +1 -1
  13. package/build/data/mods/gen3/formats-data.js +3 -3
  14. package/build/data/mods/gen3/formats-data.js.map +1 -1
  15. package/build/data/mods/gen4/formats-data.js +4 -4
  16. package/build/data/mods/gen4/formats-data.js.map +1 -1
  17. package/build/data/mods/gen4/moves.js +7 -5
  18. package/build/data/mods/gen4/moves.js.map +1 -1
  19. package/build/data/mods/gen5/formats-data.js +1 -1
  20. package/build/data/mods/gen5/formats-data.js.map +1 -1
  21. package/build/data/mods/gen5/moves.js +6 -4
  22. package/build/data/mods/gen5/moves.js.map +1 -1
  23. package/build/data/mods/gen6/formats-data.js +3 -2
  24. package/build/data/mods/gen6/formats-data.js.map +1 -1
  25. package/build/data/mods/gen6/items.js +2 -2
  26. package/build/data/mods/gen6/items.js.map +1 -1
  27. package/build/data/mods/gen7/formats-data.js +2 -1
  28. package/build/data/mods/gen7/formats-data.js.map +1 -1
  29. package/build/data/mods/gen7/moves.js +3 -3
  30. package/build/data/mods/gen7/moves.js.map +1 -1
  31. package/build/data/mods/gen7/pokedex.js +4 -0
  32. package/build/data/mods/gen7/pokedex.js.map +1 -1
  33. package/build/data/moves.js +6 -5
  34. package/build/data/moves.js.map +1 -1
  35. package/build/data/pokedex.js +480 -11
  36. package/build/data/pokedex.js.map +1 -1
  37. package/build/data/rulesets.js +26 -1
  38. package/build/data/rulesets.js.map +1 -1
  39. package/build/sim/battle.js +23 -22
  40. package/build/sim/battle.js.map +1 -1
  41. package/build/sim/dex-species.js +5 -2
  42. package/build/sim/dex-species.js.map +1 -1
  43. package/build/sim/exported-global-types.d.ts +1 -0
  44. package/build/sim/global-types.d.ts +1 -0
  45. package/build/sim/team-validator.js +11 -0
  46. package/build/sim/team-validator.js.map +1 -1
  47. package/config/formats.ts +327 -257
  48. package/data/aliases.ts +4 -4
  49. package/data/formats-data.ts +130 -17
  50. package/data/items.ts +2 -2
  51. package/data/learnsets.ts +6 -5
  52. package/data/mods/gen2/moves.ts +13 -1
  53. package/data/mods/gen3/formats-data.ts +3 -3
  54. package/data/mods/gen4/formats-data.ts +4 -4
  55. package/data/mods/gen4/moves.ts +6 -4
  56. package/data/mods/gen5/formats-data.ts +1 -1
  57. package/data/mods/gen5/moves.ts +6 -4
  58. package/data/mods/gen6/formats-data.ts +3 -2
  59. package/data/mods/gen6/items.ts +2 -2
  60. package/data/mods/gen7/formats-data.ts +2 -1
  61. package/data/mods/gen7/moves.ts +3 -3
  62. package/data/mods/gen7/pokedex.ts +4 -0
  63. package/data/moves.ts +6 -5
  64. package/data/pokedex.ts +480 -11
  65. package/data/rulesets.ts +23 -1
  66. package/package.json +2 -2
  67. package/sim/battle.ts +24 -23
  68. package/sim/dex-species.ts +5 -2
  69. package/sim/exported-global-types.ts +1 -0
  70. package/sim/global-types.ts +1 -0
  71. package/sim/team-validator.ts +13 -0
package/data/rulesets.ts CHANGED
@@ -1219,6 +1219,27 @@ export const Rulesets: {[k: string]: FormatData} = {
1219
1219
  }
1220
1220
  },
1221
1221
  },
1222
+ camomonsmod: {
1223
+ effectType: 'Rule',
1224
+ name: 'Camomons Mod',
1225
+ desc: `Pokémon have their types set to match their first two moves.`,
1226
+ onBegin() {
1227
+ this.add('rule', 'Camomons Mod: Pok\u00e9mon have their types set to match their first two moves.');
1228
+ },
1229
+ onModifySpeciesPriority: 2,
1230
+ onModifySpecies(species, target, source, effect) {
1231
+ if (!target) return; // Chat command
1232
+ if (effect && ['imposter', 'transform'].includes(effect.id)) return;
1233
+ const types = [...new Set(target.baseMoveSlots.slice(0, 2).map(move => this.dex.moves.get(move.id).type))];
1234
+ return {...species, types: types};
1235
+ },
1236
+ onSwitchIn(pokemon) {
1237
+ this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
1238
+ },
1239
+ onAfterMega(pokemon) {
1240
+ this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
1241
+ },
1242
+ },
1222
1243
  allowtradeback: {
1223
1244
  effectType: 'ValidatorRule',
1224
1245
  name: 'Allow Tradeback',
@@ -1834,7 +1855,7 @@ export const Rulesets: {[k: string]: FormatData} = {
1834
1855
  name: "Revelationmons Mod",
1835
1856
  desc: `The moves in the first slot(s) of a Pokémon's set have their types changed to match the Pokémon's type(s).`,
1836
1857
  onBegin() {
1837
- this.add('rule', 'Revelationmons Mod: The first moveslots have their types changed to match the Pokémon\'s types');
1858
+ this.add('rule', 'Revelationmons Mod: The first moveslots have their types changed to match the Pok\u00e9mon\'s types');
1838
1859
  },
1839
1860
  onValidateSet(set) {
1840
1861
  const species = this.dex.species.get(set.species);
@@ -1856,6 +1877,7 @@ export const Rulesets: {[k: string]: FormatData} = {
1856
1877
  ];
1857
1878
  if (noModifyType.includes(move.id)) return;
1858
1879
  for (const [i, type] of types.entries()) {
1880
+ if (!this.dex.types.isName(type)) continue;
1859
1881
  if (pokemon.moveSlots[i] && move.id === pokemon.moveSlots[i].id) move.type = type;
1860
1882
  }
1861
1883
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkmn/sim",
3
- "version": "0.5.5",
3
+ "version": "0.5.8",
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",
@@ -31,7 +31,7 @@
31
31
  "@pkmn/streams": "^1.0.0"
32
32
  },
33
33
  "devDependencies": {
34
- "mocha": "^9.1.4"
34
+ "mocha": "^9.2.1"
35
35
  },
36
36
  "scripts": {
37
37
  "compile": "tsc -p .",
package/sim/battle.ts CHANGED
@@ -1553,29 +1553,8 @@ export class Battle {
1553
1553
  maybeTriggerEndlessBattleClause(
1554
1554
  trappedBySide: boolean[], stalenessBySide: ('internal' | 'external' | undefined)[]
1555
1555
  ) {
1556
- if (this.turn <= 100) return;
1557
-
1558
- // the turn limit is not a part of Endless Battle Clause
1559
- if (this.turn >= 1000) {
1560
- this.add('message', `It is turn 1000. You have hit the turn limit!`);
1561
- this.tie();
1562
- return true;
1563
- }
1564
- if (
1565
- (this.turn >= 500 && this.turn % 100 === 0) || // every 100 turns past turn 500,
1566
- (this.turn >= 900 && this.turn % 10 === 0) || // every 10 turns past turn 900,
1567
- this.turn >= 990 // every turn past turn 990
1568
- ) {
1569
- const turnsLeft = 1000 - this.turn;
1570
- const turnsLeftText = (turnsLeft === 1 ? `1 turn` : `${turnsLeft} turns`);
1571
- this.add('bigerror', `You will auto-tie if the battle doesn't end in ${turnsLeftText} (on turn 1000).`);
1572
- }
1573
-
1574
- if (!this.ruleTable.has('endlessbattleclause')) return;
1575
- // for now, FFA doesn't support Endless Battle Clause
1576
- if (this.format.gameType === 'freeforall') return;
1577
-
1578
1556
  // Gen 1 Endless Battle Clause triggers
1557
+ // These are checked before the 100 turn minimum as the battle cannot progress if they are true
1579
1558
  if (this.gen <= 1) {
1580
1559
  const noProgressPossible = this.sides.every(side => {
1581
1560
  const foeAllGhosts = side.foe.pokemon.every(pokemon => pokemon.types.includes('Ghost'));
@@ -1593,7 +1572,7 @@ export class Battle {
1593
1572
  // a pokemon can't lose PP if it Transforms into a pokemon with only Transform
1594
1573
  (pokemon.moves.every(moveid => moveid === 'transform') && foeAllTransform) ||
1595
1574
  // Struggle can't damage yourself if every foe is a Ghost
1596
- pokemon.moveSlots.every(slot => slot.pp === 0) && foeAllGhosts
1575
+ (pokemon.moveSlots.every(slot => slot.pp === 0) && foeAllGhosts)
1597
1576
  ));
1598
1577
  });
1599
1578
  if (noProgressPossible) {
@@ -1602,6 +1581,28 @@ export class Battle {
1602
1581
  }
1603
1582
  }
1604
1583
 
1584
+ if (this.turn <= 100) return;
1585
+
1586
+ // the turn limit is not a part of Endless Battle Clause
1587
+ if (this.turn >= 1000) {
1588
+ this.add('message', `It is turn 1000. You have hit the turn limit!`);
1589
+ this.tie();
1590
+ return true;
1591
+ }
1592
+ if (
1593
+ (this.turn >= 500 && this.turn % 100 === 0) || // every 100 turns past turn 500,
1594
+ (this.turn >= 900 && this.turn % 10 === 0) || // every 10 turns past turn 900,
1595
+ this.turn >= 990 // every turn past turn 990
1596
+ ) {
1597
+ const turnsLeft = 1000 - this.turn;
1598
+ const turnsLeftText = (turnsLeft === 1 ? `1 turn` : `${turnsLeft} turns`);
1599
+ this.add('bigerror', `You will auto-tie if the battle doesn't end in ${turnsLeftText} (on turn 1000).`);
1600
+ }
1601
+
1602
+ if (!this.ruleTable.has('endlessbattleclause')) return;
1603
+ // for now, FFA doesn't support Endless Battle Clause
1604
+ if (this.format.gameType === 'freeforall') return;
1605
+
1605
1606
  // Are all Pokemon on every side stale, with at least one side containing an externally stale Pokemon?
1606
1607
  if (!stalenessBySide.every(s => !!s) || !stalenessBySide.some(s => s === 'external')) return;
1607
1608
 
@@ -295,7 +295,7 @@ export class Species extends BasicEffect implements Readonly<BasicEffect & Speci
295
295
  if (Array.isArray(data.changesFrom)) this.changesFrom = data.changesFrom[0];
296
296
 
297
297
  if (!this.gen && this.num >= 1) {
298
- if (this.num >= 810 || ['Gmax', 'Galar', 'Galar-Zen'].includes(this.forme)) {
298
+ if (this.num >= 810 || ['Gmax', 'Galar', 'Galar-Zen', 'Hisui'].includes(this.forme)) {
299
299
  this.gen = 8;
300
300
  } else if (this.num >= 722 || this.forme.startsWith('Alola') || this.forme === 'Starter') {
301
301
  this.gen = 7;
@@ -492,7 +492,10 @@ export class DexSpecies {
492
492
  species.tier = species.doublesTier = 'Illegal';
493
493
  }
494
494
  }
495
- species.nfe = !!(species.evos.length && this.get(species.evos[0]).gen <= this.dex.gen);
495
+ species.nfe = species.evos.some(evo => {
496
+ const evoSpecies = this.get(evo);
497
+ return !evoSpecies.isNonstandard || evoSpecies.isNonstandard === species?.isNonstandard;
498
+ });
496
499
  species.canHatch = species.canHatch ||
497
500
  (!['Ditto', 'Undiscovered'].includes(species.eggGroups[0]) && !species.prevo && species.name !== 'Manaphy');
498
501
  if (this.dex.gen === 1) species.bst -= species.baseStats.spd;
@@ -373,6 +373,7 @@ export interface ModdedBattleScriptsData extends Partial<BattleScriptsData> {
373
373
  init?: (this: ModdedDex) => void;
374
374
  natureModify?: (this: Battle, stats: StatsTable, set: PokemonSet) => StatsTable;
375
375
  nextTurn?: (this: Battle) => void;
376
+ runAction?: (this: Battle, action: Action) => void;
376
377
  spreadModify?: (this: Battle, baseStats: StatsTable, set: PokemonSet) => StatsTable;
377
378
  suppressingWeather?: (this: Battle) => boolean;
378
379
  trunc?: (n: number) => number;
@@ -373,6 +373,7 @@ interface ModdedBattleScriptsData extends Partial<BattleScriptsData> {
373
373
  init?: (this: ModdedDex) => void;
374
374
  natureModify?: (this: Battle, stats: StatsTable, set: PokemonSet) => StatsTable;
375
375
  nextTurn?: (this: Battle) => void;
376
+ runAction?: (this: Battle, action: Action) => void;
376
377
  spreadModify?: (this: Battle, baseStats: StatsTable, set: PokemonSet) => StatsTable;
377
378
  suppressingWeather?: (this: Battle) => boolean;
378
379
  trunc?: (n: number) => number;
@@ -1564,6 +1564,19 @@ export class TeamValidator {
1564
1564
 
1565
1565
  setHas['ability:' + ability.id] = true;
1566
1566
 
1567
+ if (this.format.id === 'gen8pokebilities') {
1568
+ const species = dex.species.get(set.species);
1569
+ const unSeenAbilities = Object.keys(species.abilities)
1570
+ .filter(key => key !== 'S' && (key !== 'H' || !species.unreleasedHidden))
1571
+ .map(key => species.abilities[key as "0" | "1" | "H" | "S"]);
1572
+
1573
+ if (ability.id !== this.toID(species.abilities['S'])) {
1574
+ for (const abilityName of unSeenAbilities) {
1575
+ setHas['ability:' + toID(abilityName)] = true;
1576
+ }
1577
+ }
1578
+ }
1579
+
1567
1580
  let banReason = ruleTable.check('ability:' + ability.id);
1568
1581
  if (banReason) {
1569
1582
  return `${set.name}'s ability ${ability.name} is ${banReason}.`;