@pkmn/sim 0.5.14 → 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 (127) hide show
  1. package/build/config/formats.js +167 -174
  2. package/build/config/formats.js.map +1 -1
  3. package/build/data/aliases.js +2 -2
  4. package/build/data/aliases.js.map +1 -1
  5. package/build/data/conditions.js +4 -1
  6. package/build/data/conditions.js.map +1 -1
  7. package/build/data/formats-data.js +3 -3
  8. package/build/data/formats-data.js.map +1 -1
  9. package/build/data/items.js +5 -5
  10. package/build/data/items.js.map +1 -1
  11. package/build/data/learnsets.js +7 -6
  12. package/build/data/learnsets.js.map +1 -1
  13. package/build/data/mods/gen1/formats-data.js +1 -1
  14. package/build/data/mods/gen1/formats-data.js.map +1 -1
  15. package/build/data/mods/gen1/moves.js +1 -4
  16. package/build/data/mods/gen1/moves.js.map +1 -1
  17. package/build/data/mods/gen1/scripts.js +1 -1
  18. package/build/data/mods/gen1/scripts.js.map +1 -1
  19. package/build/data/mods/gen2/items.js +28 -0
  20. package/build/data/mods/gen2/items.js.map +1 -1
  21. package/build/data/mods/gen2/moves.js +2 -5
  22. package/build/data/mods/gen2/moves.js.map +1 -1
  23. package/build/data/mods/gen3/items.js +28 -0
  24. package/build/data/mods/gen3/items.js.map +1 -1
  25. package/build/data/mods/gen3/moves.js +0 -10
  26. package/build/data/mods/gen3/moves.js.map +1 -1
  27. package/build/data/mods/gen3/scripts.js +2 -2
  28. package/build/data/mods/gen3/scripts.js.map +1 -1
  29. package/build/data/mods/gen4/abilities.js +20 -0
  30. package/build/data/mods/gen4/abilities.js.map +1 -1
  31. package/build/data/mods/gen4/items.js +28 -0
  32. package/build/data/mods/gen4/items.js.map +1 -1
  33. package/build/data/mods/gen4/moves.js +17 -10
  34. package/build/data/mods/gen4/moves.js.map +1 -1
  35. package/build/data/mods/gen4/rulesets.js +2 -1
  36. package/build/data/mods/gen4/rulesets.js.map +1 -1
  37. package/build/data/mods/gen5/items.js +0 -4
  38. package/build/data/mods/gen5/items.js.map +1 -1
  39. package/build/data/mods/gen5/rulesets.js +2 -1
  40. package/build/data/mods/gen5/rulesets.js.map +1 -1
  41. package/build/data/mods/gen6/items.js +24 -0
  42. package/build/data/mods/gen6/items.js.map +1 -1
  43. package/build/data/mods/gen7/abilities.js +31 -0
  44. package/build/data/mods/gen7/abilities.js.map +1 -1
  45. package/build/data/mods/gen7/formats-data.js +4 -4
  46. package/build/data/mods/gen7/formats-data.js.map +1 -1
  47. package/build/data/mods/gen7/items.js +12 -0
  48. package/build/data/mods/gen7/items.js.map +1 -1
  49. package/build/data/mods/gen7/moves.js +14 -0
  50. package/build/data/mods/gen7/moves.js.map +1 -1
  51. package/build/data/mods/gen7/rulesets.js +2 -1
  52. package/build/data/mods/gen7/rulesets.js.map +1 -1
  53. package/build/data/moves.js +84 -91
  54. package/build/data/moves.js.map +1 -1
  55. package/build/data/pokedex.js +2 -2
  56. package/build/data/pokedex.js.map +1 -1
  57. package/build/data/rulesets.js +74 -4
  58. package/build/data/rulesets.js.map +1 -1
  59. package/build/data/tags.js +3 -3
  60. package/build/data/tags.js.map +1 -1
  61. package/build/data/text/items.js +1 -0
  62. package/build/data/text/items.js.map +1 -1
  63. package/build/data/text/moves.js +13 -11
  64. package/build/data/text/moves.js.map +1 -1
  65. package/build/sim/battle-actions.js +12 -4
  66. package/build/sim/battle-actions.js.map +1 -1
  67. package/build/sim/battle-queue.d.ts +2 -2
  68. package/build/sim/battle-queue.js +8 -0
  69. package/build/sim/battle-queue.js.map +1 -1
  70. package/build/sim/battle.js +85 -7
  71. package/build/sim/battle.js.map +1 -1
  72. package/build/sim/dex-conditions.d.ts +3 -2
  73. package/build/sim/dex-conditions.js.map +1 -1
  74. package/build/sim/dex-moves.d.ts +2 -1
  75. package/build/sim/dex-moves.js.map +1 -1
  76. package/build/sim/exported-global-types.d.ts +1 -0
  77. package/build/sim/global-types.d.ts +1 -0
  78. package/build/sim/pokemon.js +18 -5
  79. package/build/sim/pokemon.js.map +1 -1
  80. package/build/sim/team-validator.js +16 -5
  81. package/build/sim/team-validator.js.map +1 -1
  82. package/build/sim/tools/exhaustive-runner.d.ts +8 -0
  83. package/build/sim/tools/exhaustive-runner.js +18 -7
  84. package/build/sim/tools/exhaustive-runner.js.map +1 -1
  85. package/config/formats.ts +172 -179
  86. package/data/aliases.ts +2 -2
  87. package/data/conditions.ts +4 -1
  88. package/data/formats-data.ts +3 -3
  89. package/data/items.ts +5 -5
  90. package/data/learnsets.ts +7 -6
  91. package/data/mods/gen1/formats-data.ts +1 -1
  92. package/data/mods/gen1/moves.ts +1 -4
  93. package/data/mods/gen1/scripts.ts +1 -1
  94. package/data/mods/gen2/items.ts +28 -0
  95. package/data/mods/gen2/moves.ts +2 -5
  96. package/data/mods/gen3/items.ts +28 -0
  97. package/data/mods/gen3/moves.ts +0 -10
  98. package/data/mods/gen3/scripts.ts +3 -3
  99. package/data/mods/gen4/abilities.ts +20 -0
  100. package/data/mods/gen4/items.ts +28 -0
  101. package/data/mods/gen4/moves.ts +16 -11
  102. package/data/mods/gen4/rulesets.ts +2 -1
  103. package/data/mods/gen5/items.ts +0 -4
  104. package/data/mods/gen5/rulesets.ts +2 -1
  105. package/data/mods/gen6/items.ts +24 -0
  106. package/data/mods/gen7/abilities.ts +31 -0
  107. package/data/mods/gen7/formats-data.ts +4 -4
  108. package/data/mods/gen7/items.ts +12 -0
  109. package/data/mods/gen7/moves.ts +14 -0
  110. package/data/mods/gen7/rulesets.ts +2 -1
  111. package/data/moves.ts +84 -81
  112. package/data/pokedex.ts +2 -2
  113. package/data/rulesets.ts +73 -6
  114. package/data/tags.ts +3 -3
  115. package/data/text/items.ts +2 -0
  116. package/data/text/moves.ts +14 -11
  117. package/package.json +2 -2
  118. package/sim/battle-actions.ts +16 -5
  119. package/sim/battle-queue.ts +10 -2
  120. package/sim/battle.ts +81 -7
  121. package/sim/dex-conditions.ts +7 -2
  122. package/sim/dex-moves.ts +2 -1
  123. package/sim/exported-global-types.ts +3 -0
  124. package/sim/global-types.ts +3 -0
  125. package/sim/pokemon.ts +19 -7
  126. package/sim/team-validator.ts +17 -5
  127. package/sim/tools/exhaustive-runner.ts +29 -11
@@ -296,7 +296,7 @@ export const MovesText: {[k: string]: MoveText} = {
296
296
  },
297
297
  banefulbunker: {
298
298
  name: "Baneful Bunker",
299
- desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user become poisoned. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
299
+ desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user become poisoned. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
300
300
  shortDesc: "Protects from moves. Contact: poison.",
301
301
  gen7: {
302
302
  desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user become poisoned. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
@@ -1159,7 +1159,7 @@ export const MovesText: {[k: string]: MoveText} = {
1159
1159
  },
1160
1160
  detect: {
1161
1161
  name: "Detect",
1162
- desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
1162
+ desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
1163
1163
  shortDesc: "Prevents moves from affecting the user this turn.",
1164
1164
  gen7: {
1165
1165
  desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
@@ -1583,7 +1583,7 @@ export const MovesText: {[k: string]: MoveText} = {
1583
1583
  },
1584
1584
  endure: {
1585
1585
  name: "Endure",
1586
- desc: "The user will survive attacks made by other Pokemon during this turn with at least 1 HP. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
1586
+ desc: "The user will survive attacks made by other Pokemon during this turn with at least 1 HP. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
1587
1587
  shortDesc: "User survives attacks this turn with at least 1 HP.",
1588
1588
  gen7: {
1589
1589
  desc: "The user will survive attacks made by other Pokemon during this turn with at least 1 HP. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
@@ -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",
@@ -3145,7 +3147,7 @@ export const MovesText: {[k: string]: MoveText} = {
3145
3147
  },
3146
3148
  kingsshield: {
3147
3149
  name: "King's Shield",
3148
- desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon trying to make contact with the user have their Attack lowered by 1 stage. Non-damaging moves go through this protection. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
3150
+ desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon trying to make contact with the user have their Attack lowered by 1 stage. Non-damaging moves go through this protection. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
3149
3151
  shortDesc: "Protects from damaging attacks. Contact: -1 Atk.",
3150
3152
  gen7: {
3151
3153
  desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon trying to make contact with the user have their Attack lowered by 2 stages. Non-damaging moves go through this protection. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
@@ -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",
@@ -4417,7 +4420,7 @@ export const MovesText: {[k: string]: MoveText} = {
4417
4420
  },
4418
4421
  protect: {
4419
4422
  name: "Protect",
4420
- desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
4423
+ desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
4421
4424
  shortDesc: "Prevents moves from affecting the user this turn.",
4422
4425
  gen7: {
4423
4426
  desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
@@ -4570,7 +4573,7 @@ export const MovesText: {[k: string]: MoveText} = {
4570
4573
  },
4571
4574
  quickguard: {
4572
4575
  name: "Quick Guard",
4573
- desc: "The user and its party members are protected from attacks with original or altered priority greater than 0 made by other Pokemon, including allies, during this turn. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
4576
+ desc: "The user and its party members are protected from attacks with original or altered priority greater than 0 made by other Pokemon, including allies, during this turn. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
4574
4577
  shortDesc: "Protects allies from priority attacks this turn.",
4575
4578
  gen7: {
4576
4579
  desc: "The user and its party members are protected from attacks with original or altered priority greater than 0 made by other Pokemon, including allies, during this turn. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
@@ -5613,7 +5616,7 @@ export const MovesText: {[k: string]: MoveText} = {
5613
5616
  },
5614
5617
  spikyshield: {
5615
5618
  name: "Spiky Shield",
5616
- desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user lose 1/8 of their maximum HP, rounded down. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
5619
+ desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user lose 1/8 of their maximum HP, rounded down. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
5617
5620
  shortDesc: "Protects from moves. Contact: loses 1/8 max HP.",
5618
5621
  gen7: {
5619
5622
  desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user lose 1/8 of their maximum HP, rounded down. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
@@ -6701,7 +6704,7 @@ export const MovesText: {[k: string]: MoveText} = {
6701
6704
  },
6702
6705
  wideguard: {
6703
6706
  name: "Wide Guard",
6704
- desc: "The user and its party members are protected from moves made by other Pokemon, including allies, during this turn that target all adjacent foes or all adjacent Pokemon. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
6707
+ desc: "The user and its party members are protected from moves made by other Pokemon, including allies, during this turn that target all adjacent foes or all adjacent Pokemon. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
6705
6708
  shortDesc: "Protects allies from multi-target moves this turn.",
6706
6709
  gen7: {
6707
6710
  desc: "The user and its party members are protected from moves made by other Pokemon, including allies, during this turn that target all adjacent foes or all adjacent Pokemon. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkmn/sim",
3
- "version": "0.5.14",
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",
@@ -31,7 +31,7 @@
31
31
  "@pkmn/streams": "^1.0.0"
32
32
  },
33
33
  "devDependencies": {
34
- "mocha": "^9.2.2"
34
+ "mocha": "^10.0.0"
35
35
  },
36
36
  "scripts": {
37
37
  "compile": "tsc -p .",
@@ -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
  }
@@ -1124,9 +1136,6 @@ export class BattleActions {
1124
1136
  continue;
1125
1137
  }
1126
1138
  damage[i] = curDamage;
1127
- if (move.selfdestruct === 'ifHit') {
1128
- this.battle.faint(source, source, move);
1129
- }
1130
1139
  }
1131
1140
  return damage;
1132
1141
  }
@@ -1230,6 +1239,9 @@ export class BattleActions {
1230
1239
  }
1231
1240
  }
1232
1241
  }
1242
+ if (moveData.selfdestruct === 'ifHit' && damage[i] !== false) {
1243
+ this.battle.faint(source, source, move);
1244
+ }
1233
1245
  if (moveData.selfSwitch) {
1234
1246
  if (this.battle.canSwitch(source.side)) {
1235
1247
  didSomething = true;
@@ -1243,7 +1255,6 @@ export class BattleActions {
1243
1255
  didAnything = this.combineResults(didAnything, didSomething);
1244
1256
  }
1245
1257
 
1246
-
1247
1258
  if (!didAnything && didAnything !== 0 && !moveData.self && !moveData.selfdestruct) {
1248
1259
  if (!isSelf && !isSecondary) {
1249
1260
  if (didAnything === false) {
@@ -20,8 +20,8 @@ import type {Battle} from './battle';
20
20
  /** A move action */
21
21
  export interface MoveAction {
22
22
  /** action type */
23
- choice: 'move' | 'beforeTurnMove';
24
- order: 3 | 5 | 200 | 201 | 199;
23
+ choice: 'move' | 'beforeTurnMove' | 'priorityChargeMove';
24
+ order: 3 | 5 | 200 | 201 | 199 | 106;
25
25
  /** priority of the action (lower first) */
26
26
  priority: number;
27
27
  /** fractional priority of the action (lower first) */
@@ -181,6 +181,7 @@ export class BattleQueue {
181
181
  switch: 103,
182
182
  megaEvo: 104,
183
183
  runDynamax: 105,
184
+ priorityChargeMove: 106,
184
185
 
185
186
  shift: 200,
186
187
  // default is 200 (for moves)
@@ -215,6 +216,13 @@ export class BattleQueue {
215
216
  pokemon: action.pokemon,
216
217
  }));
217
218
  }
219
+ if (!action.maxMove && !action.zmove && action.move.priorityChargeCallback) {
220
+ actions.unshift(...this.resolveAction({
221
+ choice: 'priorityChargeMove',
222
+ pokemon: action.pokemon,
223
+ move: action.move,
224
+ }));
225
+ }
218
226
  action.fractionalPriority = this.battle.runEvent('FractionalPriority', action.pokemon, null, action.move, 0);
219
227
  } else if (['switch', 'instaswitch'].includes(action.choice)) {
220
228
  if (typeof action.pokemon.switchFlag === 'string') {
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);
@@ -1419,6 +1419,20 @@ export class Battle {
1419
1419
  this.turn++;
1420
1420
  this.lastSuccessfulMoveThisTurn = null;
1421
1421
 
1422
+ const dynamaxEnding: Pokemon[] = [];
1423
+ for (const pokemon of this.getAllActive()) {
1424
+ if (pokemon.volatiles['dynamax']?.turns === 3) {
1425
+ dynamaxEnding.push(pokemon);
1426
+ }
1427
+ }
1428
+ if (dynamaxEnding.length > 1) {
1429
+ this.updateSpeed();
1430
+ this.speedSort(dynamaxEnding);
1431
+ }
1432
+ for (const pokemon of dynamaxEnding) {
1433
+ pokemon.removeVolatile('dynamax');
1434
+ }
1435
+
1422
1436
  const trappedBySide: boolean[] = [];
1423
1437
  const stalenessBySide: ('internal' | 'external' | undefined)[] = [];
1424
1438
  for (const side of this.sides) {
@@ -1548,6 +1562,23 @@ export class Battle {
1548
1562
  if (this.gen === 2) this.quickClawRoll = this.randomChance(60, 256);
1549
1563
  if (this.gen === 3) this.quickClawRoll = this.randomChance(1, 5);
1550
1564
 
1565
+ // Crazyhouse Progress checker because sidebars has trouble keeping track of Pokemon.
1566
+ // Please remove me once there is client support.
1567
+ if (this.ruleTable.has('crazyhouserule')) {
1568
+ for (const side of this.sides) {
1569
+ let buf = `raw|${side.name}'s team:<br />`;
1570
+ for (const pokemon of side.pokemon) {
1571
+ if (!buf.endsWith('<br />')) buf += '/</span>&#8203;';
1572
+ if (pokemon.fainted) {
1573
+ buf += `<span style="white-space:nowrap;"><span style="opacity:.3"><psicon pokemon="${pokemon.species.id}" /></span>`;
1574
+ } else {
1575
+ buf += `<span style="white-space:nowrap"><psicon pokemon="${pokemon.species.id}" />`;
1576
+ }
1577
+ }
1578
+ this.add(`${buf}</span>`);
1579
+ }
1580
+ }
1581
+
1551
1582
  this.makeRequest('move');
1552
1583
  }
1553
1584
 
@@ -2232,11 +2263,11 @@ export class Battle {
2232
2263
  if (this.activePerHalf > 2) {
2233
2264
  if (move.target === 'adjacentFoe' || move.target === 'normal' || move.target === 'randomNormal') {
2234
2265
  // even if a move can target an ally, auto-resolution will never make it target an ally
2235
- // i.e. if both your opponents faint before you use Flamethrower, it will fail instead of targeting your all
2266
+ // i.e. if both your opponents faint before you use Flamethrower, it will fail instead of targeting your ally
2236
2267
  const adjacentFoes = pokemon.adjacentFoes();
2237
2268
  if (adjacentFoes.length) return this.sample(adjacentFoes);
2238
- // no valid target at all, return a possibly-fainted foe for any possible redirection
2239
- return pokemon.side.foe.active[0];
2269
+ // no valid target at all, return slot directly across for any possible redirection
2270
+ return pokemon.side.foe.active[pokemon.side.foe.active.length - 1 - pokemon.position];
2240
2271
  }
2241
2272
  }
2242
2273
  return pokemon.side.randomFoe() || pokemon.side.foe.active[0];
@@ -2382,6 +2413,43 @@ export class Battle {
2382
2413
 
2383
2414
  this.add('start');
2384
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
+
2385
2453
  if (this.format.onBattleStart) this.format.onBattleStart.call(this);
2386
2454
  for (const rule of this.ruleTable.keys()) {
2387
2455
  if ('+*-!'.includes(rule.charAt(0))) continue;
@@ -2422,7 +2490,7 @@ export class Battle {
2422
2490
  action.pokemon.side.dynamaxUsed = true;
2423
2491
  if (action.pokemon.side.allySide) action.pokemon.side.allySide.dynamaxUsed = true;
2424
2492
  break;
2425
- case 'beforeTurnMove': {
2493
+ case 'beforeTurnMove':
2426
2494
  if (!action.pokemon.isActive) return false;
2427
2495
  if (action.pokemon.fainted) return false;
2428
2496
  this.debug('before turn callback: ' + action.move.id);
@@ -2431,7 +2499,13 @@ export class Battle {
2431
2499
  if (!action.move.beforeTurnCallback) throw new Error(`beforeTurnMove has no beforeTurnCallback`);
2432
2500
  action.move.beforeTurnCallback.call(this, action.pokemon, target);
2433
2501
  break;
2434
- }
2502
+ case 'priorityChargeMove':
2503
+ if (!action.pokemon.isActive) return false;
2504
+ if (action.pokemon.fainted) return false;
2505
+ this.debug('priority charge callback: ' + action.move.id);
2506
+ if (!action.move.priorityChargeCallback) throw new Error(`priorityChargeMove has no priorityChargeCallback`);
2507
+ action.move.priorityChargeCallback.call(this, action.pokemon);
2508
+ break;
2435
2509
 
2436
2510
  case 'event':
2437
2511
  this.runEvent(action.event!, action.pokemon);
@@ -2587,7 +2661,7 @@ export class Battle {
2587
2661
 
2588
2662
  if (this.gen < 5) this.eachEvent('Update');
2589
2663
 
2590
- if (this.gen >= 8 && this.queue.peek()?.choice === 'move') {
2664
+ if (this.gen >= 8 && (this.queue.peek()?.choice === 'move' || this.queue.peek()?.choice === 'runDynamax')) {
2591
2665
  // In gen 8, speed is updated dynamically so update the queue's speed properties and sort it.
2592
2666
  this.updateSpeed();
2593
2667
  for (const queueAction of this.queue.list) {
@@ -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;
@@ -635,8 +636,12 @@ export class Condition extends BasicEffect implements
635
636
  declare readonly durationCallback?: (this: Battle, target: Pokemon, source: Pokemon, effect: Effect | null) => number;
636
637
  declare readonly onCopy?: (this: Battle, pokemon: Pokemon) => void;
637
638
  declare readonly onEnd?: (this: Battle, target: Pokemon) => void;
638
- declare readonly onRestart?: (this: Battle, target: Pokemon, source: Pokemon, sourceEffect: Effect) => void;
639
- declare readonly onStart?: (this: Battle, target: Pokemon, source: Pokemon, sourceEffect: Effect) => void;
639
+ declare readonly onRestart?: (
640
+ this: Battle, target: Pokemon, source: Pokemon, sourceEffect: Effect
641
+ ) => boolean | null | void;
642
+ declare readonly onStart?: (
643
+ this: Battle, target: Pokemon, source: Pokemon, sourceEffect: Effect
644
+ ) => boolean | null | void;
640
645
 
641
646
  constructor(data: AnyObject) {
642
647
  super(data);
package/sim/dex-moves.ts CHANGED
@@ -105,6 +105,7 @@ export interface MoveEventMethods {
105
105
  beforeMoveCallback?: (this: Battle, pokemon: Pokemon, target: Pokemon | null, move: ActiveMove) => boolean | void;
106
106
  beforeTurnCallback?: (this: Battle, pokemon: Pokemon, target: Pokemon) => void;
107
107
  damageCallback?: (this: Battle, pokemon: Pokemon, target: Pokemon) => number | false;
108
+ priorityChargeCallback?: (this: Battle, pokemon: Pokemon) => void;
108
109
 
109
110
  onAfterHit?: CommonHandlers['VoidSourceMove'];
110
111
  onAfterSubDamage?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void;
@@ -195,7 +196,7 @@ export interface MoveData extends EffectData, MoveEventMethods, HitEffect {
195
196
  forceSwitch?: boolean;
196
197
  selfSwitch?: string | boolean;
197
198
  selfBoost?: {boosts?: SparseBoostsTable};
198
- selfdestruct?: string | boolean;
199
+ selfdestruct?: 'always' | 'ifHit' | boolean;
199
200
  breaksProtect?: boolean;
200
201
  /**
201
202
  * Note that this is only "true" recoil. Other self-damage, like Struggle,
@@ -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;
package/sim/pokemon.ts CHANGED
@@ -809,9 +809,12 @@ export class Pokemon {
809
809
  }
810
810
 
811
811
  ignoringItem() {
812
- return !!((this.battle.gen >= 5 && !this.isActive) ||
812
+ return !!(
813
+ this.itemState.knockedOff || // Gen 3-4
814
+ (this.battle.gen >= 5 && !this.isActive) ||
813
815
  (this.hasAbility('klutz') && !this.getItem().ignoreKlutz) ||
814
- this.volatiles['embargo'] || this.battle.field.pseudoWeather['magicroom']);
816
+ this.volatiles['embargo'] || this.battle.field.pseudoWeather['magicroom']
817
+ );
815
818
  }
816
819
 
817
820
  deductPP(move: string | Move, amount?: number | null, target?: Pokemon | null | false) {
@@ -1198,7 +1201,15 @@ export class Pokemon {
1198
1201
  }
1199
1202
  let boostName: BoostID;
1200
1203
  for (boostName in pokemon.boosts) {
1201
- this.boosts[boostName] = pokemon.boosts[boostName]!;
1204
+ this.boosts[boostName] = pokemon.boosts[boostName];
1205
+ if (this.battle.gen <= 1) {
1206
+ if (boostName === 'evasion' || boostName === 'accuracy') continue;
1207
+ if (this.boosts[boostName] >= 0) {
1208
+ this.modifyStat!(boostName, [1, 1.5, 2, 2.5, 3, 3.5, 4][this.boosts[boostName]]);
1209
+ } else {
1210
+ this.modifyStat!(boostName, [100, 66, 50, 40, 33, 28, 25][-this.boosts[boostName]] / 100);
1211
+ }
1212
+ }
1202
1213
  }
1203
1214
  if (this.battle.gen >= 6) {
1204
1215
  const volatilesToCopy = ['focusenergy', 'gmaxchistrike', 'laserfocus'];
@@ -1596,7 +1607,7 @@ export class Pokemon {
1596
1607
  }
1597
1608
 
1598
1609
  eatItem(force?: boolean, source?: Pokemon, sourceEffect?: Effect) {
1599
- if (!this.item) return false;
1610
+ if (!this.item || this.itemState.knockedOff) return false;
1600
1611
  if ((!this.hp && this.item !== 'jabocaberry' && this.item !== 'rowapberry') || !this.isActive) return false;
1601
1612
 
1602
1613
  if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
@@ -1636,7 +1647,7 @@ export class Pokemon {
1636
1647
 
1637
1648
  useItem(source?: Pokemon, sourceEffect?: Effect) {
1638
1649
  if ((!this.hp && !this.getItem().isGem) || !this.isActive) return false;
1639
- if (!this.item) return false;
1650
+ if (!this.item || this.itemState.knockedOff) return false;
1640
1651
 
1641
1652
  if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
1642
1653
  if (!source && this.battle.event && this.battle.event.target) source = this.battle.event.target;
@@ -1672,11 +1683,11 @@ export class Pokemon {
1672
1683
 
1673
1684
  takeItem(source?: Pokemon) {
1674
1685
  if (!this.isActive) return false;
1675
- if (!this.item) return false;
1686
+ if (!this.item || this.itemState.knockedOff) return false;
1676
1687
  if (!source) source = this;
1677
1688
  if (this.battle.gen === 4) {
1678
1689
  if (toID(this.ability) === 'multitype') return false;
1679
- if (source && toID(source.ability) === 'multitype') return false;
1690
+ if (toID(source.ability) === 'multitype') return false;
1680
1691
  }
1681
1692
  const item = this.getItem();
1682
1693
  if (this.battle.runEvent('TakeItem', this, source, null, item)) {
@@ -1690,6 +1701,7 @@ export class Pokemon {
1690
1701
 
1691
1702
  setItem(item: string | Item, source?: Pokemon, effect?: Effect) {
1692
1703
  if (!this.hp || !this.isActive) return false;
1704
+ if (this.itemState.knockedOff) return false;
1693
1705
  if (typeof item === 'string') item = this.battle.dex.items.get(item);
1694
1706
 
1695
1707
  const effectid = this.battle.effect ? this.battle.effect.id : '';
@@ -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
 
@@ -1564,7 +1576,7 @@ export class TeamValidator {
1564
1576
 
1565
1577
  setHas['ability:' + ability.id] = true;
1566
1578
 
1567
- if (this.format.id === 'gen8pokebilities') {
1579
+ if (this.format.id.startsWith('gen8pokebilities')) {
1568
1580
  const species = dex.species.get(set.species);
1569
1581
  const unSeenAbilities = Object.keys(species.abilities)
1570
1582
  .filter(key => key !== 'S' && (key !== 'H' || !species.unreleasedHidden))