@pkmn/sim 0.4.21 → 0.4.25

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 (70) hide show
  1. package/build/config/formats.js +198 -136
  2. package/build/config/formats.js.map +1 -1
  3. package/build/data/aliases.js +5 -3
  4. package/build/data/aliases.js.map +1 -1
  5. package/build/data/conditions.js +5 -1
  6. package/build/data/conditions.js.map +1 -1
  7. package/build/data/formats-data.js +16 -16
  8. package/build/data/formats-data.js.map +1 -1
  9. package/build/data/mods/gen1/scripts.js +17 -20
  10. package/build/data/mods/gen1/scripts.js.map +1 -1
  11. package/build/data/mods/gen2/scripts.js +15 -21
  12. package/build/data/mods/gen2/scripts.js.map +1 -1
  13. package/build/data/mods/gen4/conditions.js +6 -0
  14. package/build/data/mods/gen4/conditions.js.map +1 -1
  15. package/build/data/mods/gen6/conditions.js +4 -1
  16. package/build/data/mods/gen6/conditions.js.map +1 -1
  17. package/build/data/mods/gen6/pokedex.js +17 -17
  18. package/build/data/mods/gen6/pokedex.js.map +1 -1
  19. package/build/data/mods/gen7/formats-data.js +2 -2
  20. package/build/data/mods/gen7/formats-data.js.map +1 -1
  21. package/build/data/moves.js +22 -9
  22. package/build/data/moves.js.map +1 -1
  23. package/build/data/rulesets.js +3 -1
  24. package/build/data/rulesets.js.map +1 -1
  25. package/build/lib/streams.d.ts +1 -199
  26. package/build/lib/streams.js +11 -772
  27. package/build/lib/streams.js.map +1 -1
  28. package/build/sim/battle-actions.d.ts +1 -1
  29. package/build/sim/battle-actions.js +19 -43
  30. package/build/sim/battle-actions.js.map +1 -1
  31. package/build/sim/battle.d.ts +1 -0
  32. package/build/sim/battle.js +5 -0
  33. package/build/sim/battle.js.map +1 -1
  34. package/build/sim/dex-moves.d.ts +31 -11
  35. package/build/sim/dex-moves.js +4 -3
  36. package/build/sim/dex-moves.js.map +1 -1
  37. package/build/sim/dex-species.js +11 -1
  38. package/build/sim/dex-species.js.map +1 -1
  39. package/build/sim/exported-global-types.d.ts +1 -0
  40. package/build/sim/global-types.d.ts +1 -0
  41. package/build/sim/side.js +2 -2
  42. package/build/sim/side.js.map +1 -1
  43. package/build/sim/team-validator.js +1 -1
  44. package/build/sim/team-validator.js.map +1 -1
  45. package/build/sim/tools/runner.d.ts +1 -6
  46. package/build/sim/tools/runner.js +6 -6
  47. package/build/sim/tools/runner.js.map +1 -1
  48. package/config/formats.ts +210 -141
  49. package/data/aliases.ts +5 -3
  50. package/data/conditions.ts +5 -1
  51. package/data/formats-data.ts +16 -16
  52. package/data/mods/gen1/scripts.ts +22 -18
  53. package/data/mods/gen2/scripts.ts +19 -18
  54. package/data/mods/gen4/conditions.ts +6 -0
  55. package/data/mods/gen6/conditions.ts +4 -1
  56. package/data/mods/gen6/pokedex.ts +17 -17
  57. package/data/mods/gen7/formats-data.ts +2 -2
  58. package/data/moves.ts +19 -9
  59. package/data/rulesets.ts +3 -1
  60. package/lib/streams.ts +1 -874
  61. package/package.json +3 -2
  62. package/sim/battle-actions.ts +20 -41
  63. package/sim/battle.ts +6 -0
  64. package/sim/dex-moves.ts +35 -13
  65. package/sim/dex-species.ts +10 -1
  66. package/sim/exported-global-types.ts +1 -0
  67. package/sim/global-types.ts +1 -0
  68. package/sim/side.ts +2 -2
  69. package/sim/team-validator.ts +1 -1
  70. package/sim/tools/runner.ts +2 -0
@@ -276,7 +276,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
276
276
  randomBattleMoves: ["earthquake", "knockoff", "rapidspin", "stealthrock", "swordsdance", "toxic", "spikes", "stoneedge"],
277
277
  randomBattleLevel: 86,
278
278
  randomDoubleBattleMoves: ["drillrun", "knockoff", "protect", "stealthrock", "stoneedge", "swordsdance"],
279
- randomDoubleBattleLevel: 88,
279
+ randomDoubleBattleLevel: 89,
280
280
  tier: "PU",
281
281
  doublesTier: "(DUU)",
282
282
  },
@@ -467,7 +467,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
467
467
  },
468
468
  persianalola: {
469
469
  randomBattleMoves: ["darkpulse", "hypnosis", "nastyplot", "thunderbolt"],
470
- randomBattleLevel: 83,
470
+ randomBattleLevel: 82,
471
471
  randomDoubleBattleMoves: ["fakeout", "foulplay", "icywind", "partingshot", "protect", "snarl", "taunt"],
472
472
  randomDoubleBattleLevel: 88,
473
473
  tier: "(PU)",
@@ -847,7 +847,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
847
847
  },
848
848
  exeggutoralola: {
849
849
  randomBattleMoves: ["dracometeor", "flamethrower", "gigadrain", "leafstorm", "trickroom"],
850
- randomBattleLevel: 86,
850
+ randomBattleLevel: 87,
851
851
  randomDoubleBattleMoves: ["dragonpulse", "energyball", "flamethrower", "protect", "trickroom"],
852
852
  randomDoubleBattleLevel: 88,
853
853
  tier: "PUBL",
@@ -1139,7 +1139,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
1139
1139
  randomBattleMoves: ["bounce", "dragondance", "earthquake", "powerwhip", "waterfall"],
1140
1140
  randomBattleLevel: 76,
1141
1141
  randomDoubleBattleMoves: ["bounce", "dragondance", "icefang", "powerwhip", "protect", "waterfall"],
1142
- randomDoubleBattleLevel: 82,
1142
+ randomDoubleBattleLevel: 81,
1143
1143
  tier: "UU",
1144
1144
  doublesTier: "(DUU)",
1145
1145
  },
@@ -1703,7 +1703,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
1703
1703
  tier: "NFE",
1704
1704
  },
1705
1705
  weavile: {
1706
- randomBattleMoves: ["iceshard", "iciclecrash", "knockoff", "lowkick", "swordsdance"],
1706
+ randomBattleMoves: ["iceshard", "knockoff", "lowkick", "swordsdance", "tripleaxel"],
1707
1707
  randomBattleLevel: 79,
1708
1708
  randomDoubleBattleMoves: ["fakeout", "iceshard", "knockoff", "swordsdance", "tripleaxel"],
1709
1709
  randomDoubleBattleLevel: 84,
@@ -1742,7 +1742,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
1742
1742
  },
1743
1743
  corsola: {
1744
1744
  randomBattleMoves: ["powergem", "recover", "scald", "stealthrock", "toxic"],
1745
- randomBattleLevel: 92,
1745
+ randomBattleLevel: 93,
1746
1746
  randomDoubleBattleMoves: ["icywind", "lifedew", "recover", "scald", "toxic"],
1747
1747
  randomDoubleBattleLevel: 95,
1748
1748
  tier: "(PU)",
@@ -1965,7 +1965,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
1965
1965
  tier: "Illegal",
1966
1966
  },
1967
1967
  zigzagoon: {
1968
- tier: "LC",
1968
+ tier: "NFE",
1969
1969
  },
1970
1970
  zigzagoongalar: {
1971
1971
  tier: "LC",
@@ -2707,7 +2707,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
2707
2707
  tier: "Illegal",
2708
2708
  },
2709
2709
  rayquaza: {
2710
- randomBattleMoves: ["dracometeor", "dragonascent", "extremespeed", "swordsdance", "vcreate", "earthquake"],
2710
+ randomBattleMoves: ["dracometeor", "dragonascent", "dragondance", "extremespeed", "swordsdance", "vcreate", "earthquake"],
2711
2711
  randomBattleLevel: 74,
2712
2712
  randomDoubleBattleMoves: ["dracometeor", "dragonascent", "dragonclaw", "dragondance", "earthpower", "extremespeed", "vcreate"],
2713
2713
  randomDoubleBattleLevel: 74,
@@ -2885,7 +2885,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
2885
2885
  },
2886
2886
  cherrim: {
2887
2887
  randomBattleMoves: ["dazzlinggleam", "energyball", "healingwish", "petaldance", "pollenpuff"],
2888
- randomBattleLevel: 92,
2888
+ randomBattleLevel: 93,
2889
2889
  randomDoubleBattleMoves: ["aromatherapy", "energyball", "helpinghand", "pollenpuff", "protect"],
2890
2890
  randomDoubleBattleLevel: 92,
2891
2891
  tier: "(PU)",
@@ -3445,7 +3445,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
3445
3445
  randomBattleMoves: ["healbell", "knockoff", "protect", "toxic", "wish"],
3446
3446
  randomBattleLevel: 88,
3447
3447
  randomDoubleBattleMoves: ["bodyslam", "healpulse", "helpinghand", "knockoff", "protect", "thunderwave"],
3448
- randomDoubleBattleLevel: 88,
3448
+ randomDoubleBattleLevel: 89,
3449
3449
  tier: "PU",
3450
3450
  doublesTier: "(DUU)",
3451
3451
  },
@@ -3608,7 +3608,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
3608
3608
  randomBattleMoves: ["energyball", "knockoff", "leechseed", "spikes", "spikyshield", "toxic"],
3609
3609
  randomBattleLevel: 94,
3610
3610
  randomDoubleBattleMoves: ["acupressure", "drainpunch", "helpinghand", "leafstorm", "spikyshield", "suckerpunch"],
3611
- randomDoubleBattleLevel: 95,
3611
+ randomDoubleBattleLevel: 96, // buffed twice in the last 6 months as of Nov 2021
3612
3612
  tier: "(PU)",
3613
3613
  doublesTier: "(DUU)",
3614
3614
  },
@@ -5110,7 +5110,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
5110
5110
  randomBattleMoves: ["defog", "flamethrower", "icebeam", "multiattack", "partingshot", "toxic"],
5111
5111
  randomBattleLevel: 84,
5112
5112
  randomDoubleBattleMoves: ["multiattack", "rockslide", "swordsdance", "tailwind"],
5113
- randomDoubleBattleLevel: 90,
5113
+ randomDoubleBattleLevel: 89,
5114
5114
  tier: "(PU)",
5115
5115
  doublesTier: "(DUU)",
5116
5116
  },
@@ -5218,7 +5218,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
5218
5218
  randomBattleLevel: 86,
5219
5219
  randomDoubleBattleMoves: ["dracometeor", "dragonpulse", "glare", "heatwave", "hurricane", "hypervoice", "protect", "roost"],
5220
5220
  randomDoubleBattleLevel: 88,
5221
- tier: "PU",
5221
+ tier: "PUBL",
5222
5222
  doublesTier: "(DUU)",
5223
5223
  },
5224
5224
  dhelmise: {
@@ -5240,7 +5240,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
5240
5240
  randomBattleLevel: 80,
5241
5241
  randomDoubleBattleMoves: ["bodypress", "dracometeor", "irondefense", "protect"],
5242
5242
  randomDoubleBattleLevel: 80,
5243
- tier: "UU",
5243
+ tier: "UUBL",
5244
5244
  doublesTier: "(DUU)",
5245
5245
  },
5246
5246
  kommoototem: {
@@ -5337,7 +5337,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
5337
5337
  celesteela: {
5338
5338
  randomBattleMoves: ["airslash", "earthquake", "fireblast", "flashcannon", "leechseed", "protect"],
5339
5339
  randomBattleLevel: 77,
5340
- randomDoubleBattleMoves: ["airslash", "autotomize", "earthquake", "fireblast", "flashcannon"],
5340
+ randomDoubleBattleMoves: ["airslash", "fireblast", "flashcannon", "leechseed", "protect", "wideguard"],
5341
5341
  randomDoubleBattleLevel: 78,
5342
5342
  randomBattleNoDynamaxMoves: ["airslash", "earthquake", "fireblast", "heavyslam", "leechseed", "protect"],
5343
5343
  tier: "UU",
@@ -5964,7 +5964,7 @@ export const FormatsData: {[k: string]: SpeciesFormatsData} = {
5964
5964
  randomBattleLevel: 86,
5965
5965
  randomDoubleBattleMoves: ["blizzard", "fishiousrend", "iciclecrash", "protect", "superfang"],
5966
5966
  randomDoubleBattleLevel: 88,
5967
- tier: "(PU)",
5967
+ tier: "NUBL",
5968
5968
  doublesTier: "(DUU)",
5969
5969
  },
5970
5970
  duraludon: {
@@ -579,7 +579,7 @@ export const Scripts: ModdedBattleScriptsData = {
579
579
  return damage;
580
580
  },
581
581
  // This calculates the damage pokemon does to target with move.
582
- getDamage(pokemon, target, move, suppressMessages) {
582
+ getDamage(source, target, move, suppressMessages) {
583
583
  // First of all, we get the move.
584
584
  if (typeof move === 'string') {
585
585
  move = this.battle.dex.getActiveMove(move);
@@ -607,12 +607,12 @@ export const Scripts: ModdedBattleScriptsData = {
607
607
 
608
608
  // We edit the damage through move's damage callback if necessary.
609
609
  if (move.damageCallback) {
610
- return move.damageCallback.call(this.battle, pokemon, target);
610
+ return move.damageCallback.call(this.battle, source, target);
611
611
  }
612
612
 
613
613
  // We take damage from damage=level moves (seismic toss).
614
614
  if (move.damage === 'level') {
615
- return pokemon.level;
615
+ return source.level;
616
616
  }
617
617
 
618
618
  // If there's a fix move damage, we return that.
@@ -626,13 +626,12 @@ export const Scripts: ModdedBattleScriptsData = {
626
626
  }
627
627
 
628
628
  // Let's check if we are in middle of a partial trap sequence to return the previous damage.
629
- if (pokemon.volatiles['partialtrappinglock'] && (target === pokemon.volatiles['partialtrappinglock'].locked)) {
630
- return pokemon.volatiles['partialtrappinglock'].damage;
629
+ if (source.volatiles['partialtrappinglock'] && (target === source.volatiles['partialtrappinglock'].locked)) {
630
+ return source.volatiles['partialtrappinglock'].damage;
631
631
  }
632
632
 
633
633
  // We check the category and typing to calculate later on the damage.
634
634
  if (!move.category) move.category = 'Physical';
635
- if (!move.defensiveCategory) move.defensiveCategory = move.category;
636
635
  // '???' is typeless damage: used for Struggle and Confusion etc
637
636
  if (!move.type) move.type = '???';
638
637
  const type = move.type;
@@ -640,7 +639,7 @@ export const Scripts: ModdedBattleScriptsData = {
640
639
  // We get the base power and apply basePowerCallback if necessary.
641
640
  let basePower: number | false | null = move.basePower;
642
641
  if (move.basePowerCallback) {
643
- basePower = move.basePowerCallback.call(this.battle, pokemon, target, move);
642
+ basePower = move.basePowerCallback.call(this.battle, source, target, move);
644
643
  }
645
644
  if (!basePower) {
646
645
  return basePower === 0 ? undefined : basePower;
@@ -652,10 +651,10 @@ export const Scripts: ModdedBattleScriptsData = {
652
651
  if (!isCrit) {
653
652
  // In gen 1, the critical chance is based on speed.
654
653
  // First, we get the base speed, divide it by 2 and floor it. This is our current crit chance.
655
- let critChance = Math.floor(pokemon.species.baseStats['spe'] / 2);
654
+ let critChance = Math.floor(source.species.baseStats['spe'] / 2);
656
655
 
657
656
  // Now we check for focus energy volatile.
658
- if (pokemon.volatiles['focusenergy']) {
657
+ if (source.volatiles['focusenergy']) {
659
658
  // If it exists, crit chance is divided by 2 again and floored.
660
659
  critChance = Math.floor(critChance / 2);
661
660
  } else {
@@ -683,7 +682,7 @@ export const Scripts: ModdedBattleScriptsData = {
683
682
 
684
683
  // Happens after crit calculation.
685
684
  if (basePower) {
686
- basePower = this.battle.runEvent('BasePower', pokemon, target, move, basePower);
685
+ basePower = this.battle.runEvent('BasePower', source, target, move, basePower);
687
686
  if (basePower && move.basePowerModifier) {
688
687
  basePower *= move.basePowerModifier;
689
688
  }
@@ -692,14 +691,17 @@ export const Scripts: ModdedBattleScriptsData = {
692
691
  basePower = this.battle.clampIntRange(basePower, 1);
693
692
 
694
693
  // We now check attacker's and defender's stats.
695
- let level = pokemon.level;
696
- let attacker = pokemon;
697
- const defender = target;
698
- if (move.useTargetOffensive) attacker = target;
699
- const atkType: StatIDExceptHP = (move.category === 'Physical') ? 'atk' : 'spa';
700
- const defType: StatIDExceptHP = (move.defensiveCategory === 'Physical') ? 'def' : 'spd';
701
- let attack = attacker.getStat(move.useSourceDefensiveAsOffensive ? defType : atkType);
694
+ let level = source.level;
695
+ const attacker = move.overrideOffensivePokemon === 'target' ? target : source;
696
+ const defender = move.overrideDefensivePokemon === 'source' ? source : target;
697
+
698
+ const isPhysical = move.category === 'Physical';
699
+ const atkType: StatIDExceptHP = move.overrideOffensiveStat || (isPhysical ? 'atk' : 'spa');
700
+ const defType: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd');
701
+
702
+ let attack = attacker.getStat(atkType);
702
703
  let defense = defender.getStat(defType);
704
+
703
705
  // In gen 1, screen effect is applied here.
704
706
  if ((defType === 'def' && defender.volatiles['reflect']) || (defType === 'spd' && defender.volatiles['lightscreen'])) {
705
707
  this.battle.debug('Screen doubling (Sp)Def');
@@ -716,10 +718,12 @@ export const Scripts: ModdedBattleScriptsData = {
716
718
  level *= 2;
717
719
  if (!suppressMessages) this.battle.add('-crit', target);
718
720
  }
721
+
719
722
  if (move.ignoreOffensive) {
720
723
  this.battle.debug('Negating (sp)atk boost/penalty.');
721
724
  attack = attacker.getStat(atkType, true);
722
725
  }
726
+
723
727
  if (move.ignoreDefensive) {
724
728
  this.battle.debug('Negating (sp)def boost/penalty.');
725
729
  // No screens
@@ -751,7 +755,7 @@ export const Scripts: ModdedBattleScriptsData = {
751
755
  damage += 2;
752
756
 
753
757
  // STAB damage bonus, the "???" type never gets STAB
754
- if (type !== '???' && pokemon.hasType(type)) {
758
+ if (type !== '???' && source.hasType(type)) {
755
759
  damage += Math.floor(damage / 2);
756
760
  }
757
761
 
@@ -466,7 +466,7 @@ export const Scripts: ModdedBattleScriptsData = {
466
466
  }
467
467
  return damage;
468
468
  },
469
- getDamage(pokemon, target, move, suppressMessages) {
469
+ getDamage(source, target, move, suppressMessages) {
470
470
  // First of all, we get the move.
471
471
  if (typeof move === 'string') {
472
472
  move = this.dex.getActiveMove(move);
@@ -494,12 +494,12 @@ export const Scripts: ModdedBattleScriptsData = {
494
494
 
495
495
  // We edit the damage through move's damage callback
496
496
  if (move.damageCallback) {
497
- return move.damageCallback.call(this.battle, pokemon, target);
497
+ return move.damageCallback.call(this.battle, source, target);
498
498
  }
499
499
 
500
500
  // We take damage from damage=level moves
501
501
  if (move.damage === 'level') {
502
- return pokemon.level;
502
+ return source.level;
503
503
  }
504
504
 
505
505
  // If there's a fix move damage, we run it
@@ -509,7 +509,6 @@ export const Scripts: ModdedBattleScriptsData = {
509
509
 
510
510
  // We check the category and typing to calculate later on the damage
511
511
  move.category = this.battle.getCategory(move);
512
- if (!move.defensiveCategory) move.defensiveCategory = move.category;
513
512
  // '???' is typeless damage: used for Struggle and Confusion etc
514
513
  if (!move.type) move.type = '???';
515
514
  const type = move.type;
@@ -517,7 +516,7 @@ export const Scripts: ModdedBattleScriptsData = {
517
516
  // We get the base power and apply basePowerCallback if necessary
518
517
  let basePower: number | false | null | undefined = move.basePower;
519
518
  if (move.basePowerCallback) {
520
- basePower = move.basePowerCallback.call(this.battle, pokemon, target, move);
519
+ basePower = move.basePowerCallback.call(this.battle, source, target, move);
521
520
  }
522
521
 
523
522
  // We check for Base Power
@@ -528,7 +527,7 @@ export const Scripts: ModdedBattleScriptsData = {
528
527
  basePower = this.battle.clampIntRange(basePower, 1);
529
528
 
530
529
  // Checking for the move's Critical Hit ratio
531
- let critRatio = this.battle.runEvent('ModifyCritRatio', pokemon, target, move, move.critRatio || 0);
530
+ let critRatio = this.battle.runEvent('ModifyCritRatio', source, target, move, move.critRatio || 0);
532
531
  critRatio = this.battle.clampIntRange(critRatio, 0, 5);
533
532
  const critMult = [0, 16, 8, 4, 3, 2];
534
533
  let isCrit = move.willCrit || false;
@@ -547,10 +546,10 @@ export const Scripts: ModdedBattleScriptsData = {
547
546
  // confusion damage
548
547
  if (move.isConfusionSelfHit) {
549
548
  move.type = move.baseMoveType!;
550
- basePower = this.battle.runEvent('BasePower', pokemon, target, move, basePower, true);
549
+ basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
551
550
  move.type = '???';
552
551
  } else {
553
- basePower = this.battle.runEvent('BasePower', pokemon, target, move, basePower, true);
552
+ basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
554
553
  }
555
554
  if (basePower && move.basePowerModifier) {
556
555
  basePower *= move.basePowerModifier;
@@ -560,20 +559,21 @@ export const Scripts: ModdedBattleScriptsData = {
560
559
  basePower = this.battle.clampIntRange(basePower, 1);
561
560
 
562
561
  // We now check for attacker and defender
563
- let level = pokemon.level;
562
+ let level = source.level;
564
563
 
565
564
  // Using Beat Up
566
565
  if (move.allies) {
567
- this.battle.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies[0].name);
566
+ this.battle.add('-activate', source, 'move: Beat Up', '[of] ' + move.allies[0].name);
568
567
  level = move.allies[0].level;
569
568
  }
570
569
 
571
- let attacker = pokemon;
572
- const defender = target;
573
- if (move.useTargetOffensive) attacker = target;
574
- let atkType: StatIDExceptHP = (move.category === 'Physical') ? 'atk' : 'spa';
575
- const defType: StatIDExceptHP = (move.defensiveCategory === 'Physical') ? 'def' : 'spd';
576
- if (move.useSourceDefensiveAsOffensive) atkType = defType;
570
+ const attacker = move.overrideOffensivePokemon === 'target' ? target : source;
571
+ const defender = move.overrideDefensivePokemon === 'source' ? source : target;
572
+
573
+ const isPhysical = move.category === 'Physical';
574
+ const atkType: StatIDExceptHP = move.overrideOffensiveStat || (isPhysical ? 'atk' : 'spa');
575
+ const defType: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd');
576
+
577
577
  let unboosted = false;
578
578
  let noburndrop = false;
579
579
 
@@ -586,7 +586,7 @@ export const Scripts: ModdedBattleScriptsData = {
586
586
  noburndrop = true;
587
587
  }
588
588
  }
589
- // Get stats now.
589
+
590
590
  let attack = attacker.getStat(atkType, unboosted, noburndrop);
591
591
  let defense = defender.getStat(defType, unboosted);
592
592
 
@@ -603,6 +603,7 @@ export const Scripts: ModdedBattleScriptsData = {
603
603
  // The attack drop from the burn is only applied when attacker's attack level is higher than defender's defense level.
604
604
  attack = attacker.getStat(atkType, true, true);
605
605
  }
606
+
606
607
  if (move.ignoreDefensive) {
607
608
  this.battle.debug('Negating (sp)def boost/penalty.');
608
609
  defense = target.getStat(defType, true, true);
@@ -666,7 +667,7 @@ export const Scripts: ModdedBattleScriptsData = {
666
667
  }
667
668
 
668
669
  // STAB damage bonus, the "???" type never gets STAB
669
- if (type !== '???' && pokemon.hasType(type)) {
670
+ if (type !== '???' && source.hasType(type)) {
670
671
  damage += Math.floor(damage / 2);
671
672
  }
672
673
 
@@ -6,6 +6,12 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
6
6
  },
7
7
  par: {
8
8
  inherit: true,
9
+ onModifySpe(spe, pokemon) {
10
+ if (!pokemon.hasAbility('quickfeet')) {
11
+ return this.chainModify(0.25);
12
+ }
13
+ return spe;
14
+ },
9
15
  onBeforeMove(pokemon) {
10
16
  if (!pokemon.hasAbility('magicguard') && this.randomChance(1, 4)) {
11
17
  this.add('cant', pokemon, 'par');
@@ -8,9 +8,12 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
8
8
  par: {
9
9
  inherit: true,
10
10
  onModifySpe(spe, pokemon) {
11
+ // Paralysis occurs after all other Speed modifiers, so evaluate all modifiers up to this point first
12
+ spe = this.finalModify(spe);
11
13
  if (!pokemon.hasAbility('quickfeet')) {
12
- return this.chainModify(0.25);
14
+ spe = Math.floor(spe * 25 / 100);
13
15
  }
16
+ return spe;
14
17
  },
15
18
  },
16
19
  confusion: {
@@ -171,87 +171,87 @@ export const Pokedex: {[k: string]: ModdedSpeciesData} = {
171
171
  arceusbug: {
172
172
  inherit: true,
173
173
  color: "Gray",
174
- requiredItem: "Insect Plate",
174
+ requiredItems: ["Insect Plate"],
175
175
  },
176
176
  arceusdark: {
177
177
  inherit: true,
178
178
  color: "Gray",
179
- requiredItem: "Dread Plate",
179
+ requiredItems: ["Dread Plate"],
180
180
  },
181
181
  arceusdragon: {
182
182
  inherit: true,
183
183
  color: "Gray",
184
- requiredItem: "Draco Plate",
184
+ requiredItems: ["Draco Plate"],
185
185
  },
186
186
  arceuselectric: {
187
187
  inherit: true,
188
188
  color: "Gray",
189
- requiredItem: "Zap Plate",
189
+ requiredItems: ["Zap Plate"],
190
190
  },
191
191
  arceusfairy: {
192
192
  inherit: true,
193
193
  color: "Gray",
194
- requiredItem: "Pixie Plate",
194
+ requiredItems: ["Pixie Plate"],
195
195
  },
196
196
  arceusfighting: {
197
197
  inherit: true,
198
198
  color: "Gray",
199
- requiredItem: "Fist Plate",
199
+ requiredItems: ["Fist Plate"],
200
200
  },
201
201
  arceusfire: {
202
202
  inherit: true,
203
203
  color: "Gray",
204
- requiredItem: "Flame Plate",
204
+ requiredItems: ["Flame Plate"],
205
205
  },
206
206
  arceusflying: {
207
207
  inherit: true,
208
208
  color: "Gray",
209
- requiredItem: "Sky Plate",
209
+ requiredItems: ["Sky Plate"],
210
210
  },
211
211
  arceusghost: {
212
212
  inherit: true,
213
213
  color: "Gray",
214
- requiredItem: "Spooky Plate",
214
+ requiredItems: ["Spooky Plate"],
215
215
  },
216
216
  arceusgrass: {
217
217
  inherit: true,
218
218
  color: "Gray",
219
- requiredItem: "Meadow Plate",
219
+ requiredItems: ["Meadow Plate"],
220
220
  },
221
221
  arceusground: {
222
222
  inherit: true,
223
223
  color: "Gray",
224
- requiredItem: "Earth Plate",
224
+ requiredItems: ["Earth Plate"],
225
225
  },
226
226
  arceusice: {
227
227
  inherit: true,
228
228
  color: "Gray",
229
- requiredItem: "Icicle Plate",
229
+ requiredItems: ["Icicle Plate"],
230
230
  },
231
231
  arceuspoison: {
232
232
  inherit: true,
233
233
  color: "Gray",
234
- requiredItem: "Toxic Plate",
234
+ requiredItems: ["Toxic Plate"],
235
235
  },
236
236
  arceuspsychic: {
237
237
  inherit: true,
238
238
  color: "Gray",
239
- requiredItem: "Mind Plate",
239
+ requiredItems: ["Mind Plate"],
240
240
  },
241
241
  arceusrock: {
242
242
  inherit: true,
243
243
  color: "Gray",
244
- requiredItem: "Stone Plate",
244
+ requiredItems: ["Stone Plate"],
245
245
  },
246
246
  arceussteel: {
247
247
  inherit: true,
248
248
  color: "Gray",
249
- requiredItem: "Iron Plate",
249
+ requiredItems: ["Iron Plate"],
250
250
  },
251
251
  arceuswater: {
252
252
  inherit: true,
253
253
  color: "Gray",
254
- requiredItem: "Splash Plate",
254
+ requiredItems: ["Splash Plate"],
255
255
  },
256
256
  roggenrola: {
257
257
  inherit: true,
@@ -529,7 +529,7 @@ export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
529
529
  doublesTier: "(DUU)",
530
530
  },
531
531
  farfetchd: {
532
- randomBattleMoves: ["bravebird", "knockoff", "leafblade", "return", "roost", "swordsdance"],
532
+ randomBattleMoves: ["bravebird", "knockoff", "leafblade", "return", "swordsdance"],
533
533
  randomDoubleBattleMoves: ["bravebird", "knockoff", "leafblade", "protect", "return", "swordsdance"],
534
534
  tier: "(PU)",
535
535
  doublesTier: "(DUU)",
@@ -2486,7 +2486,7 @@ export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
2486
2486
  tier: "LC",
2487
2487
  },
2488
2488
  gastrodon: {
2489
- randomBattleMoves: ["clearsmog", "earthquake", "icebeam", "recover", "scald", "toxic"],
2489
+ randomBattleMoves: ["earthquake", "icebeam", "recover", "scald", "toxic"],
2490
2490
  randomDoubleBattleMoves: ["earthpower", "icywind", "muddywater", "protect", "recover", "scald"],
2491
2491
  tier: "PU",
2492
2492
  doublesTier: "DOU",
package/data/moves.ts CHANGED
@@ -1399,7 +1399,7 @@ export const Moves: {[moveid: string]: MoveData} = {
1399
1399
  pp: 10,
1400
1400
  priority: 0,
1401
1401
  flags: {contact: 1, protect: 1, mirror: 1},
1402
- useSourceDefensiveAsOffensive: true,
1402
+ overrideOffensiveStat: 'def',
1403
1403
  secondary: null,
1404
1404
  target: "normal",
1405
1405
  type: "Fighting",
@@ -5621,7 +5621,7 @@ export const Moves: {[moveid: string]: MoveData} = {
5621
5621
  pp: 15,
5622
5622
  priority: 0,
5623
5623
  flags: {contact: 1, protect: 1, mirror: 1},
5624
- useTargetOffensive: true,
5624
+ overrideOffensivePokemon: 'target',
5625
5625
  secondary: null,
5626
5626
  target: "normal",
5627
5627
  type: "Dark",
@@ -6509,9 +6509,9 @@ export const Moves: {[moveid: string]: MoveData} = {
6509
6509
  flags: {},
6510
6510
  isMax: "Melmetal",
6511
6511
  self: {
6512
- onHit(source) {
6512
+ onHit(source, target, effect) {
6513
6513
  for (const pokemon of source.foes()) {
6514
- if (!pokemon.volatiles['dynamax']) pokemon.addVolatile('torment');
6514
+ if (!pokemon.volatiles['dynamax']) pokemon.addVolatile('torment', source, effect);
6515
6515
  }
6516
6516
  },
6517
6517
  },
@@ -13309,7 +13309,7 @@ export const Moves: {[moveid: string]: MoveData} = {
13309
13309
  accuracy: 100,
13310
13310
  basePower: 80,
13311
13311
  category: "Special",
13312
- defensiveCategory: "Physical",
13312
+ overrideDefensiveStat: 'def',
13313
13313
  name: "Psyshock",
13314
13314
  pp: 10,
13315
13315
  priority: 0,
@@ -13324,7 +13324,7 @@ export const Moves: {[moveid: string]: MoveData} = {
13324
13324
  accuracy: 100,
13325
13325
  basePower: 100,
13326
13326
  category: "Special",
13327
- defensiveCategory: "Physical",
13327
+ overrideDefensiveStat: 'def',
13328
13328
  name: "Psystrike",
13329
13329
  pp: 10,
13330
13330
  priority: 0,
@@ -14852,7 +14852,7 @@ export const Moves: {[moveid: string]: MoveData} = {
14852
14852
  accuracy: 100,
14853
14853
  basePower: 85,
14854
14854
  category: "Special",
14855
- defensiveCategory: "Physical",
14855
+ overrideDefensiveStat: 'def',
14856
14856
  name: "Secret Sword",
14857
14857
  pp: 10,
14858
14858
  priority: 0,
@@ -15857,6 +15857,7 @@ export const Moves: {[moveid: string]: MoveData} = {
15857
15857
  onRestart(pokemon) {
15858
15858
  if (pokemon.removeVolatile('fly') || pokemon.removeVolatile('bounce')) {
15859
15859
  this.queue.cancelMove(pokemon);
15860
+ pokemon.removeVolatile('twoturnmove');
15860
15861
  this.add('-start', pokemon, 'Smack Down');
15861
15862
  }
15862
15863
  },
@@ -18312,11 +18313,12 @@ export const Moves: {[moveid: string]: MoveData} = {
18312
18313
  volatileStatus: 'torment',
18313
18314
  condition: {
18314
18315
  noCopy: true,
18315
- onStart(pokemon) {
18316
+ onStart(pokemon, source, effect) {
18316
18317
  if (pokemon.volatiles['dynamax']) {
18317
18318
  delete pokemon.volatiles['torment'];
18318
18319
  return false;
18319
18320
  }
18321
+ if (effect?.id === 'gmaxmeltdown') this.effectState.duration = 3;
18320
18322
  this.add('-start', pokemon, 'Torment');
18321
18323
  },
18322
18324
  onEnd(pokemon) {
@@ -19436,13 +19438,21 @@ export const Moves: {[moveid: string]: MoveData} = {
19436
19438
  }
19437
19439
  return 5;
19438
19440
  },
19441
+ onModifyMove(move, source, target) {
19442
+ // This code is for moves that use defensive stats as the attacking stat; see below for most of the implementation
19443
+ if (!move.overrideOffensiveStat) return;
19444
+ const statAndBoosts = move.overrideOffensiveStat;
19445
+ if (!['def', 'spd'].includes(statAndBoosts)) return;
19446
+ move.overrideOffensiveStat = statAndBoosts === 'def' ? 'spd' : 'def';
19447
+ this.hint(`${move.name} uses ${statAndBoosts === 'def' ? '' : 'Sp. '}Def boosts when Wonder Room is active.`);
19448
+ },
19439
19449
  onFieldStart(field, source) {
19440
19450
  this.add('-fieldstart', 'move: Wonder Room', '[of] ' + source);
19441
19451
  },
19442
19452
  onFieldRestart(target, source) {
19443
19453
  this.field.removePseudoWeather('wonderroom');
19444
19454
  },
19445
- // Swapping defenses implemented in sim/pokemon.js:Pokemon#calculateStat and Pokemon#getStat
19455
+ // Swapping defenses partially implemented in sim/pokemon.js:Pokemon#calculateStat and Pokemon#getStat
19446
19456
  onFieldResidualOrder: 27,
19447
19457
  onFieldResidualSubOrder: 5,
19448
19458
  onFieldEnd() {
package/data/rulesets.ts CHANGED
@@ -1089,7 +1089,9 @@ export const Rulesets: {[k: string]: FormatData} = {
1089
1089
  if (!nonstandard && !move.isZ && !move.isMax && !this.ruleTable.isRestricted(`move:${move.id}`)) {
1090
1090
  const speciesTypes: string[] = [];
1091
1091
  const moveTypes: string[] = [];
1092
- for (let i = this.dex.gen; i >= species.gen && i >= move.gen; i--) {
1092
+ // BDSP can't import Pokemon from Home, so it shouldn't grant moves from archaic species types
1093
+ const minObtainableSpeciesGen = this.dex.currentMod === 'gen8bdsp' ? this.dex.gen : species.gen;
1094
+ for (let i = this.dex.gen; i >= minObtainableSpeciesGen && i >= move.gen; i--) {
1093
1095
  const dex = this.dex.forGen(i);
1094
1096
  moveTypes.push(dex.moves.get(move.name).type);
1095
1097