@pkmn/sim 0.5.14 → 0.5.15

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 (86) hide show
  1. package/build/config/formats.js +146 -135
  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 +2 -2
  8. package/build/data/formats-data.js.map +1 -1
  9. package/build/data/items.js +4 -2
  10. package/build/data/items.js.map +1 -1
  11. package/build/data/learnsets.js +5 -4
  12. package/build/data/learnsets.js.map +1 -1
  13. package/build/data/mods/gen1/scripts.js +1 -1
  14. package/build/data/mods/gen1/scripts.js.map +1 -1
  15. package/build/data/mods/gen2/items.js +28 -0
  16. package/build/data/mods/gen2/items.js.map +1 -1
  17. package/build/data/mods/gen2/moves.js +2 -2
  18. package/build/data/mods/gen2/moves.js.map +1 -1
  19. package/build/data/mods/gen3/items.js +28 -0
  20. package/build/data/mods/gen3/items.js.map +1 -1
  21. package/build/data/mods/gen4/abilities.js +20 -0
  22. package/build/data/mods/gen4/abilities.js.map +1 -1
  23. package/build/data/mods/gen4/items.js +28 -0
  24. package/build/data/mods/gen4/items.js.map +1 -1
  25. package/build/data/mods/gen4/moves.js +14 -6
  26. package/build/data/mods/gen4/moves.js.map +1 -1
  27. package/build/data/mods/gen5/items.js +0 -4
  28. package/build/data/mods/gen5/items.js.map +1 -1
  29. package/build/data/mods/gen6/items.js +24 -0
  30. package/build/data/mods/gen6/items.js.map +1 -1
  31. package/build/data/mods/gen7/abilities.js +31 -0
  32. package/build/data/mods/gen7/abilities.js.map +1 -1
  33. package/build/data/mods/gen7/items.js +12 -0
  34. package/build/data/mods/gen7/items.js.map +1 -1
  35. package/build/data/mods/gen7/moves.js +14 -0
  36. package/build/data/mods/gen7/moves.js.map +1 -1
  37. package/build/data/moves.js +25 -12
  38. package/build/data/moves.js.map +1 -1
  39. package/build/data/rulesets.js +71 -0
  40. package/build/data/rulesets.js.map +1 -1
  41. package/build/data/tags.js +3 -3
  42. package/build/data/tags.js.map +1 -1
  43. package/build/data/text/moves.js +8 -8
  44. package/build/data/text/moves.js.map +1 -1
  45. package/build/sim/battle-queue.d.ts +2 -2
  46. package/build/sim/battle-queue.js +8 -0
  47. package/build/sim/battle-queue.js.map +1 -1
  48. package/build/sim/battle.js +42 -2
  49. package/build/sim/battle.js.map +1 -1
  50. package/build/sim/dex-conditions.d.ts +2 -2
  51. package/build/sim/dex-conditions.js.map +1 -1
  52. package/build/sim/dex-moves.d.ts +1 -0
  53. package/build/sim/dex-moves.js.map +1 -1
  54. package/build/sim/pokemon.js +18 -5
  55. package/build/sim/pokemon.js.map +1 -1
  56. package/build/sim/team-validator.js +1 -1
  57. package/build/sim/team-validator.js.map +1 -1
  58. package/config/formats.ts +151 -140
  59. package/data/aliases.ts +2 -2
  60. package/data/conditions.ts +4 -1
  61. package/data/formats-data.ts +2 -2
  62. package/data/items.ts +4 -2
  63. package/data/learnsets.ts +5 -4
  64. package/data/mods/gen1/scripts.ts +1 -1
  65. package/data/mods/gen2/items.ts +28 -0
  66. package/data/mods/gen2/moves.ts +2 -2
  67. package/data/mods/gen3/items.ts +28 -0
  68. package/data/mods/gen4/abilities.ts +20 -0
  69. package/data/mods/gen4/items.ts +28 -0
  70. package/data/mods/gen4/moves.ts +14 -7
  71. package/data/mods/gen5/items.ts +0 -4
  72. package/data/mods/gen6/items.ts +24 -0
  73. package/data/mods/gen7/abilities.ts +31 -0
  74. package/data/mods/gen7/items.ts +12 -0
  75. package/data/mods/gen7/moves.ts +14 -0
  76. package/data/moves.ts +25 -11
  77. package/data/rulesets.ts +70 -0
  78. package/data/tags.ts +3 -3
  79. package/data/text/moves.ts +8 -8
  80. package/package.json +2 -2
  81. package/sim/battle-queue.ts +10 -2
  82. package/sim/battle.ts +39 -2
  83. package/sim/dex-conditions.ts +6 -2
  84. package/sim/dex-moves.ts +1 -0
  85. package/sim/pokemon.ts +19 -7
  86. package/sim/team-validator.ts +1 -1
@@ -50,6 +50,10 @@ export const Items: {[k: string]: ModdedItemData} = {
50
50
  }
51
51
  },
52
52
  },
53
+ fastball: {
54
+ inherit: true,
55
+ isNonstandard: null,
56
+ },
53
57
  focusband: {
54
58
  inherit: true,
55
59
  onDamage(damage, target, source, effect) {
@@ -68,6 +72,10 @@ export const Items: {[k: string]: ModdedItemData} = {
68
72
  }
69
73
  },
70
74
  },
75
+ heavyball: {
76
+ inherit: true,
77
+ isNonstandard: null,
78
+ },
71
79
  kingsrock: {
72
80
  inherit: true,
73
81
  onModifyMove(move) {
@@ -91,11 +99,19 @@ export const Items: {[k: string]: ModdedItemData} = {
91
99
  onResidualOrder: 5,
92
100
  onResidualSubOrder: 1,
93
101
  },
102
+ levelball: {
103
+ inherit: true,
104
+ isNonstandard: null,
105
+ },
94
106
  lightball: {
95
107
  inherit: true,
96
108
  // In Gen 2 this happens in stat calculation directly.
97
109
  onModifySpA() {},
98
110
  },
111
+ loveball: {
112
+ inherit: true,
113
+ isNonstandard: null,
114
+ },
99
115
  luckypunch: {
100
116
  inherit: true,
101
117
  onModifyCritRatioPriority: -1,
@@ -105,6 +121,10 @@ export const Items: {[k: string]: ModdedItemData} = {
105
121
  }
106
122
  },
107
123
  },
124
+ lureball: {
125
+ inherit: true,
126
+ isNonstandard: null,
127
+ },
108
128
  magnet: {
109
129
  inherit: true,
110
130
  onModifySpA() {},
@@ -138,6 +158,10 @@ export const Items: {[k: string]: ModdedItemData} = {
138
158
  }
139
159
  },
140
160
  },
161
+ moonball: {
162
+ inherit: true,
163
+ isNonstandard: null,
164
+ },
141
165
  mysticwater: {
142
166
  inherit: true,
143
167
  onModifySpA() {},
@@ -201,6 +225,10 @@ export const Items: {[k: string]: ModdedItemData} = {
201
225
  }
202
226
  },
203
227
  },
228
+ sportball: {
229
+ inherit: true,
230
+ isNonstandard: null,
231
+ },
204
232
  stick: {
205
233
  inherit: true,
206
234
  onModifyCritRatioPriority: -1,
@@ -129,7 +129,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
129
129
  return false;
130
130
  },
131
131
  beforeTurnCallback() {},
132
- onTryHit() {},
132
+ onTry() {},
133
133
  condition: {},
134
134
  priority: -1,
135
135
  },
@@ -446,7 +446,7 @@ export const Moves: {[k: string]: ModdedMoveData} = {
446
446
  return false;
447
447
  },
448
448
  beforeTurnCallback() {},
449
- onTryHit() {},
449
+ onTry() {},
450
450
  condition: {},
451
451
  priority: -1,
452
452
  },
@@ -83,6 +83,10 @@ export const Items: {[k: string]: ModdedItemData} = {
83
83
  gen: 3,
84
84
  isNonstandard: "Unobtainable",
85
85
  },
86
+ fastball: {
87
+ inherit: true,
88
+ isNonstandard: "Unobtainable",
89
+ },
86
90
  figyberry: {
87
91
  inherit: true,
88
92
  onUpdate() {},
@@ -115,6 +119,10 @@ export const Items: {[k: string]: ModdedItemData} = {
115
119
  }
116
120
  },
117
121
  },
122
+ heavyball: {
123
+ inherit: true,
124
+ isNonstandard: "Unobtainable",
125
+ },
118
126
  iapapaberry: {
119
127
  inherit: true,
120
128
  onUpdate() {},
@@ -160,6 +168,10 @@ export const Items: {[k: string]: ModdedItemData} = {
160
168
  return accuracy * 0.95;
161
169
  },
162
170
  },
171
+ levelball: {
172
+ inherit: true,
173
+ isNonstandard: "Unobtainable",
174
+ },
163
175
  liechiberry: {
164
176
  inherit: true,
165
177
  onUpdate() {},
@@ -180,6 +192,14 @@ export const Items: {[k: string]: ModdedItemData} = {
180
192
  },
181
193
  onBasePower() {},
182
194
  },
195
+ loveball: {
196
+ inherit: true,
197
+ isNonstandard: "Unobtainable",
198
+ },
199
+ lureball: {
200
+ inherit: true,
201
+ isNonstandard: "Unobtainable",
202
+ },
183
203
  magnet: {
184
204
  inherit: true,
185
205
  onBasePower() {},
@@ -221,6 +241,10 @@ export const Items: {[k: string]: ModdedItemData} = {
221
241
  }
222
242
  },
223
243
  },
244
+ moonball: {
245
+ inherit: true,
246
+ isNonstandard: "Unobtainable",
247
+ },
224
248
  mysticwater: {
225
249
  inherit: true,
226
250
  onBasePower() {},
@@ -363,6 +387,10 @@ export const Items: {[k: string]: ModdedItemData} = {
363
387
  }
364
388
  },
365
389
  },
390
+ sportball: {
391
+ inherit: true,
392
+ isNonstandard: "Unobtainable",
393
+ },
366
394
  starfberry: {
367
395
  inherit: true,
368
396
  onUpdate() {},
@@ -160,6 +160,16 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
160
160
  this.add('-activate', pokemon, 'ability: Forewarn', warnMove);
161
161
  },
162
162
  },
163
+ frisk: {
164
+ inherit: true,
165
+ onStart(pokemon) {
166
+ for (const target of pokemon.foes()) {
167
+ if (target.item && !target.itemState.knockedOff) {
168
+ this.add('-item', target, target.getItem().name, '[from] ability: Frisk', '[of] ' + pokemon, '[identify]');
169
+ }
170
+ }
171
+ },
172
+ },
163
173
  hustle: {
164
174
  inherit: true,
165
175
  onSourceModifyAccuracyPriority: 7,
@@ -504,6 +514,16 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
504
514
  }
505
515
  },
506
516
  },
517
+ unburden: {
518
+ inherit: true,
519
+ condition: {
520
+ onModifySpe(spe, pokemon) {
521
+ if ((!pokemon.item || pokemon.itemState.knockedOff) && !pokemon.ignoringAbility()) {
522
+ return this.chainModify(2);
523
+ }
524
+ },
525
+ },
526
+ },
507
527
  vitalspirit: {
508
528
  inherit: true,
509
529
  rating: 2.5,
@@ -113,6 +113,10 @@ export const Items: {[k: string]: ModdedItemData} = {
113
113
  }
114
114
  },
115
115
  },
116
+ fastball: {
117
+ inherit: true,
118
+ isNonstandard: null,
119
+ },
116
120
  flameorb: {
117
121
  inherit: true,
118
122
  onResidualOrder: 10,
@@ -148,6 +152,10 @@ export const Items: {[k: string]: ModdedItemData} = {
148
152
  }
149
153
  },
150
154
  },
155
+ heavyball: {
156
+ inherit: true,
157
+ isNonstandard: null,
158
+ },
151
159
  ironball: {
152
160
  inherit: true,
153
161
  onEffectiveness() {},
@@ -181,6 +189,10 @@ export const Items: {[k: string]: ModdedItemData} = {
181
189
  onResidualOrder: 10,
182
190
  onResidualSubOrder: 4,
183
191
  },
192
+ levelball: {
193
+ inherit: true,
194
+ isNonstandard: null,
195
+ },
184
196
  lifeorb: {
185
197
  inherit: true,
186
198
  onModifyDamage() {},
@@ -214,6 +226,10 @@ export const Items: {[k: string]: ModdedItemData} = {
214
226
  }
215
227
  },
216
228
  },
229
+ loveball: {
230
+ inherit: true,
231
+ isNonstandard: null,
232
+ },
217
233
  luckypunch: {
218
234
  inherit: true,
219
235
  onModifyCritRatio(critRatio, user) {
@@ -222,6 +238,10 @@ export const Items: {[k: string]: ModdedItemData} = {
222
238
  }
223
239
  },
224
240
  },
241
+ lureball: {
242
+ inherit: true,
243
+ isNonstandard: null,
244
+ },
225
245
  lustrousorb: {
226
246
  inherit: true,
227
247
  onBasePower(basePower, user, target, move) {
@@ -286,6 +306,10 @@ export const Items: {[k: string]: ModdedItemData} = {
286
306
  },
287
307
  },
288
308
  },
309
+ moonball: {
310
+ inherit: true,
311
+ isNonstandard: null,
312
+ },
289
313
  razorfang: {
290
314
  inherit: true,
291
315
  onModifyMove(move) {
@@ -301,6 +325,10 @@ export const Items: {[k: string]: ModdedItemData} = {
301
325
  }
302
326
  },
303
327
  },
328
+ sportball: {
329
+ inherit: true,
330
+ isNonstandard: null,
331
+ },
304
332
  stick: {
305
333
  inherit: true,
306
334
  onModifyCritRatio(critRatio, user) {
@@ -541,12 +541,16 @@ export const Moves: {[k: string]: ModdedMoveData} = {
541
541
  },
542
542
  focuspunch: {
543
543
  inherit: true,
544
- beforeMoveCallback() { },
544
+ priorityChargeCallback() {},
545
+ beforeTurnCallback(pokemon) {
546
+ pokemon.addVolatile('focuspunch');
547
+ },
548
+ beforeMoveCallback() {},
545
549
  onTry(pokemon) {
546
- if (pokemon.volatiles['focuspunch'] && pokemon.volatiles['focuspunch'].lostFocus) {
550
+ if (pokemon.volatiles['focuspunch']?.lostFocus) {
547
551
  this.attrLastMove('[still]');
548
552
  this.add('cant', pokemon, 'Focus Punch', 'Focus Punch');
549
- return false;
553
+ return null;
550
554
  }
551
555
  },
552
556
  },
@@ -829,10 +833,13 @@ export const Moves: {[k: string]: ModdedMoveData} = {
829
833
  },
830
834
  knockoff: {
831
835
  inherit: true,
832
- onAfterHit(target, source) {
833
- const item = target.takeItem();
834
- if (item) {
835
- this.add('-enditem', target, item.name, '[from] move: Knock Off', '[of] ' + source);
836
+ onAfterHit(target, source, move) {
837
+ if (!target.item || target.itemState.knockedOff) return;
838
+ const item = target.getItem();
839
+ if (this.singleEvent('TakeItem', item, target.itemState, target, target, move, item)) {
840
+ target.itemState.knockedOff = true;
841
+ this.add('-enditem', target, item.name, '[from] move: Knock Off');
842
+ this.hint("In Gens 3-4, Knock Off only makes the target's item unusable; it cannot obtain a new item.", true);
836
843
  }
837
844
  },
838
845
  },
@@ -299,10 +299,6 @@ export const Items: {[k: string]: ModdedItemData} = {
299
299
  type: "Dragon",
300
300
  },
301
301
  },
302
- normalgem: {
303
- inherit: true,
304
- isNonstandard: null,
305
- },
306
302
  occaberry: {
307
303
  inherit: true,
308
304
  naturalGift: {
@@ -25,6 +25,10 @@ export const Items: {[k: string]: ModdedItemData} = {
25
25
  inherit: true,
26
26
  isNonstandard: null,
27
27
  },
28
+ fastball: {
29
+ inherit: true,
30
+ isNonstandard: "Unobtainable",
31
+ },
28
32
  figyberry: {
29
33
  inherit: true,
30
34
  onUpdate(pokemon) {
@@ -39,6 +43,10 @@ export const Items: {[k: string]: ModdedItemData} = {
39
43
  }
40
44
  },
41
45
  },
46
+ heavyball: {
47
+ inherit: true,
48
+ isNonstandard: "Unobtainable",
49
+ },
42
50
  iapapaberry: {
43
51
  inherit: true,
44
52
  onUpdate(pokemon) {
@@ -63,6 +71,10 @@ export const Items: {[k: string]: ModdedItemData} = {
63
71
  }
64
72
  },
65
73
  },
74
+ levelball: {
75
+ inherit: true,
76
+ isNonstandard: "Unobtainable",
77
+ },
66
78
  lifeorb: {
67
79
  inherit: true,
68
80
  onAfterMoveSecondarySelf(source, target, move) {
@@ -71,6 +83,14 @@ export const Items: {[k: string]: ModdedItemData} = {
71
83
  }
72
84
  },
73
85
  },
86
+ loveball: {
87
+ inherit: true,
88
+ isNonstandard: "Unobtainable",
89
+ },
90
+ lureball: {
91
+ inherit: true,
92
+ isNonstandard: "Unobtainable",
93
+ },
74
94
  machobrace: {
75
95
  inherit: true,
76
96
  isNonstandard: null,
@@ -93,6 +113,10 @@ export const Items: {[k: string]: ModdedItemData} = {
93
113
  inherit: true,
94
114
  isNonstandard: null,
95
115
  },
116
+ moonball: {
117
+ inherit: true,
118
+ isNonstandard: "Unobtainable",
119
+ },
96
120
  nanabberry: {
97
121
  inherit: true,
98
122
  isNonstandard: null,
@@ -66,6 +66,37 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
66
66
  inherit: true,
67
67
  onBoost() {},
68
68
  },
69
+ slowstart: {
70
+ inherit: true,
71
+ condition: {
72
+ duration: 5,
73
+ onResidualOrder: 28,
74
+ onResidualSubOrder: 2,
75
+ onStart(target) {
76
+ this.add('-start', target, 'ability: Slow Start');
77
+ },
78
+ onModifyAtkPriority: 5,
79
+ onModifyAtk(atk, pokemon, target, move) {
80
+ // This is because the game checks the move's category in data, rather than what it is currently, unlike e.g. Huge Power
81
+ if (this.dex.moves.get(move.id).category === 'Physical') {
82
+ return this.chainModify(0.5);
83
+ }
84
+ },
85
+ onModifySpAPriority: 5,
86
+ onModifySpA(spa, pokemon, target, move) {
87
+ // Ordinary Z-moves like Breakneck Blitz will halve the user's Special Attack as well
88
+ if (this.dex.moves.get(move.id).category === 'Physical') {
89
+ return this.chainModify(0.5);
90
+ }
91
+ },
92
+ onModifySpe(spe, pokemon) {
93
+ return this.chainModify(0.5);
94
+ },
95
+ onEnd(target) {
96
+ this.add('-end', target, 'Slow Start');
97
+ },
98
+ },
99
+ },
69
100
  soundproof: {
70
101
  inherit: true,
71
102
  onTryHit(target, source, move) {
@@ -140,6 +140,10 @@ export const Items: {[k: string]: ModdedItemData} = {
140
140
  inherit: true,
141
141
  isNonstandard: null,
142
142
  },
143
+ dreamball: {
144
+ inherit: true,
145
+ isNonstandard: "Unobtainable",
146
+ },
143
147
  durinberry: {
144
148
  inherit: true,
145
149
  isNonstandard: "Unobtainable",
@@ -495,6 +499,10 @@ export const Items: {[k: string]: ModdedItemData} = {
495
499
  inherit: true,
496
500
  isNonstandard: null,
497
501
  },
502
+ safariball: {
503
+ inherit: true,
504
+ isNonstandard: "Unobtainable",
505
+ },
498
506
  sailfossil: {
499
507
  inherit: true,
500
508
  isNonstandard: null,
@@ -547,6 +555,10 @@ export const Items: {[k: string]: ModdedItemData} = {
547
555
  inherit: true,
548
556
  isNonstandard: null,
549
557
  },
558
+ sportball: {
559
+ inherit: true,
560
+ isNonstandard: "Unobtainable",
561
+ },
550
562
  steelgem: {
551
563
  inherit: true,
552
564
  isNonstandard: "Unobtainable",
@@ -259,6 +259,20 @@ export const Moves: {[k: string]: ModdedMoveData} = {
259
259
  return success;
260
260
  },
261
261
  },
262
+ fly: {
263
+ inherit: true,
264
+ onTryMove(attacker, defender, move) {
265
+ if (attacker.removeVolatile(move.id)) {
266
+ return;
267
+ }
268
+ this.add('-prepare', attacker, move.name);
269
+ if (!this.runEvent('ChargeMove', attacker, defender, move)) {
270
+ return;
271
+ }
272
+ attacker.addVolatile('twoturnmove', defender);
273
+ return null;
274
+ },
275
+ },
262
276
  foresight: {
263
277
  inherit: true,
264
278
  isNonstandard: null,
package/data/moves.ts CHANGED
@@ -1035,7 +1035,7 @@ export const Moves: {[moveid: string]: MoveData} = {
1035
1035
  pp: 15,
1036
1036
  priority: -3,
1037
1037
  flags: {bullet: 1, protect: 1},
1038
- beforeTurnCallback(pokemon) {
1038
+ priorityChargeCallback(pokemon) {
1039
1039
  pokemon.addVolatile('beakblast');
1040
1040
  },
1041
1041
  condition: {
@@ -2640,7 +2640,7 @@ export const Moves: {[moveid: string]: MoveData} = {
2640
2640
  beforeTurnCallback(pokemon) {
2641
2641
  pokemon.addVolatile('counter');
2642
2642
  },
2643
- onTryHit(target, source, move) {
2643
+ onTry(source) {
2644
2644
  if (!source.volatiles['counter']) return false;
2645
2645
  if (source.volatiles['counter'].slot === null) return false;
2646
2646
  },
@@ -3092,6 +3092,7 @@ export const Moves: {[moveid: string]: MoveData} = {
3092
3092
  volatileStatus: 'defensecurl',
3093
3093
  condition: {
3094
3094
  noCopy: true,
3095
+ onRestart: () => null,
3095
3096
  },
3096
3097
  secondary: null,
3097
3098
  target: "self",
@@ -5390,6 +5391,17 @@ export const Moves: {[moveid: string]: MoveData} = {
5390
5391
  if (!this.runEvent('ChargeMove', attacker, defender, move)) {
5391
5392
  return;
5392
5393
  }
5394
+
5395
+ // In SwSh, Fly's animation leaks the initial target through a camera focus
5396
+ // The animation leak target itself isn't "accurate"; the target it reveals is as if Fly weren't a charge movee
5397
+ // (Fly, like all other charge moves, will actually target slots on its charging turn, relevant for things like Follow Me)
5398
+ // We use a generic single-target move to represent this
5399
+ if (this.gameType === 'doubles' || this.gameType === 'multi') {
5400
+ const animatedTarget = attacker.getMoveTargets(this.dex.getActiveMove('aerialace'), defender).targets[0];
5401
+ if (animatedTarget) {
5402
+ this.hint(`${move.name}'s animation targeted ${animatedTarget.name}`);
5403
+ }
5404
+ }
5393
5405
  attacker.addVolatile('twoturnmove', defender);
5394
5406
  return null;
5395
5407
  },
@@ -5488,11 +5500,11 @@ export const Moves: {[moveid: string]: MoveData} = {
5488
5500
  pp: 20,
5489
5501
  priority: -3,
5490
5502
  flags: {contact: 1, protect: 1, punch: 1},
5491
- beforeTurnCallback(pokemon) {
5503
+ priorityChargeCallback(pokemon) {
5492
5504
  pokemon.addVolatile('focuspunch');
5493
5505
  },
5494
5506
  beforeMoveCallback(pokemon) {
5495
- if (pokemon.volatiles['focuspunch'] && pokemon.volatiles['focuspunch'].lostFocus) {
5507
+ if (pokemon.volatiles['focuspunch']?.lostFocus) {
5496
5508
  this.add('cant', pokemon, 'Focus Punch', 'Focus Punch');
5497
5509
  return true;
5498
5510
  }
@@ -5504,7 +5516,7 @@ export const Moves: {[moveid: string]: MoveData} = {
5504
5516
  },
5505
5517
  onHit(pokemon, source, move) {
5506
5518
  if (move.category !== 'Status') {
5507
- pokemon.volatiles['focuspunch'].lostFocus = true;
5519
+ this.effectState.lostFocus = true;
5508
5520
  }
5509
5521
  },
5510
5522
  onTryAddVolatile(status, pokemon) {
@@ -10925,7 +10937,7 @@ export const Moves: {[moveid: string]: MoveData} = {
10925
10937
  pp: 10,
10926
10938
  priority: 0,
10927
10939
  flags: {protect: 1, mirror: 1},
10928
- onTryHit(target, source, move) {
10940
+ onTry(source) {
10929
10941
  const lastDamagedBy = source.getLastDamagedBy(true);
10930
10942
  if (lastDamagedBy === undefined || !lastDamagedBy.thisTurn) return false;
10931
10943
  },
@@ -11187,6 +11199,7 @@ export const Moves: {[moveid: string]: MoveData} = {
11187
11199
  volatileStatus: 'minimize',
11188
11200
  condition: {
11189
11201
  noCopy: true,
11202
+ onRestart: () => null,
11190
11203
  onSourceModifyDamage(damage, source, target, move) {
11191
11204
  const boostedMoves = [
11192
11205
  'stomp', 'steamroller', 'bodyslam', 'flyingpress', 'dragonrush', 'heatcrash', 'heavyslam', 'maliciousmoonsault',
@@ -11264,7 +11277,7 @@ export const Moves: {[moveid: string]: MoveData} = {
11264
11277
  beforeTurnCallback(pokemon) {
11265
11278
  pokemon.addVolatile('mirrorcoat');
11266
11279
  },
11267
- onTryHit(target, source, move) {
11280
+ onTry(source) {
11268
11281
  if (!source.volatiles['mirrorcoat']) return false;
11269
11282
  if (source.volatiles['mirrorcoat'].slot === null) return false;
11270
11283
  },
@@ -13478,7 +13491,7 @@ export const Moves: {[moveid: string]: MoveData} = {
13478
13491
  let alreadyAdded = false;
13479
13492
  pokemon.removeVolatile('destinybond');
13480
13493
  for (const source of this.effectState.sources) {
13481
- if (!this.queue.cancelMove(source) || !source.hp) continue;
13494
+ if (!source.isAdjacent(pokemon) || !this.queue.cancelMove(source) || !source.hp) continue;
13482
13495
  if (!alreadyAdded) {
13483
13496
  this.add('-activate', pokemon, 'move: Pursuit');
13484
13497
  alreadyAdded = true;
@@ -14000,7 +14013,8 @@ export const Moves: {[moveid: string]: MoveData} = {
14000
14013
  }
14001
14014
  },
14002
14015
  onHit(target, source, move) {
14003
- if (!target.setStatus('slp', source, move)) return false;
14016
+ const result = target.setStatus('slp', source, move);
14017
+ if (!result) return result;
14004
14018
  target.statusState.time = 3;
14005
14019
  target.statusState.startTime = 3;
14006
14020
  this.heal(target.maxhp); // Aesthetic only as the healing happens after you fall asleep in-game
@@ -15210,7 +15224,7 @@ export const Moves: {[moveid: string]: MoveData} = {
15210
15224
  pp: 5,
15211
15225
  priority: -3,
15212
15226
  flags: {protect: 1},
15213
- beforeTurnCallback(pokemon) {
15227
+ priorityChargeCallback(pokemon) {
15214
15228
  pokemon.addVolatile('shelltrap');
15215
15229
  },
15216
15230
  onTryMove(pokemon) {
@@ -15227,7 +15241,7 @@ export const Moves: {[moveid: string]: MoveData} = {
15227
15241
  },
15228
15242
  onHit(pokemon, source, move) {
15229
15243
  if (!pokemon.isAlly(source) && move.category === 'Physical') {
15230
- pokemon.volatiles['shelltrap'].gotHit = true;
15244
+ this.effectState.gotHit = true;
15231
15245
  const action = this.queue.willMove(pokemon);
15232
15246
  if (action) {
15233
15247
  this.queue.prioritizeAction(action);
package/data/rulesets.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  // Note: These are the rules that formats use
2
2
 
3
3
  import {Utils} from "../lib";
4
+ import {Pokemon} from "../sim/pokemon";
4
5
 
5
6
  // The list of formats is stored in config/formats.js
6
7
  export const Rulesets: {[k: string]: FormatData} = {
@@ -1604,6 +1605,75 @@ export const Rulesets: {[k: string]: FormatData} = {
1604
1605
  pokemon.trapped = true;
1605
1606
  },
1606
1607
  },
1608
+ crazyhouserule: {
1609
+ effectType: 'Rule',
1610
+ name: 'Crazyhouse Rule',
1611
+ desc: "Pok\u00e9mon you KO are added to your team and removed from the opponent's, and vice versa.",
1612
+ onValidateRule(value) {
1613
+ if (this.format.gameType === 'doubles' || this.format.gameType === 'triples') {
1614
+ throw new Error(`Crazyhouse Rule currently does not support ${this.format.gameType} battles.`);
1615
+ }
1616
+ const ruleTable = this.ruleTable;
1617
+ const maxTeamSize = ruleTable.pickedTeamSize || ruleTable.maxTeamSize;
1618
+ const numPlayers = (this.format.gameType === 'freeforall' || this.format.gameType === 'multi') ? 4 : 2;
1619
+ const potentialMaxTeamSize = maxTeamSize * numPlayers;
1620
+ if (potentialMaxTeamSize > 24) {
1621
+ throw new Error(`Crazyhouse Rule cannot be added because a team can potentially have ${potentialMaxTeamSize} Pokemon on one team, which is more than the server limit of 24.`);
1622
+ }
1623
+ },
1624
+ // In order to prevent a case of the clones, housekeeping is needed.
1625
+ // This is especially needed to make sure one side doesn't end up with too many Pokemon.
1626
+ onBeforeSwitchIn(pokemon) {
1627
+ if (this.turn < 1 || !pokemon.side.faintedThisTurn) return;
1628
+ pokemon.side.pokemon = pokemon.side.pokemon.filter(x => !(x.fainted && !x.m.outofplay));
1629
+ for (let i = 0; i < pokemon.side.pokemon.length && i < 24; i++) {
1630
+ pokemon.side.pokemon[i].position = i;
1631
+ }
1632
+ },
1633
+ onFaint(target, source, effect) {
1634
+ if (!target.m.numSwaps) {
1635
+ target.m.numSwaps = 0;
1636
+ }
1637
+ target.m.numSwaps++;
1638
+ if (effect && effect.effectType === 'Move' && source.side.pokemon.length < 24 &&
1639
+ source.side !== target.side && target.m.numSwaps < 4) {
1640
+ const hpCost = this.clampIntRange(Math.floor((target.baseMaxhp * target.m.numSwaps) / 4), 1);
1641
+ // Just in case(tm) and for Shedinja
1642
+ if (hpCost === target.baseMaxhp) {
1643
+ target.m.outofplay = true;
1644
+ return;
1645
+ }
1646
+ source.side.pokemonLeft++;
1647
+ source.side.pokemon.length++;
1648
+
1649
+ // A new Pokemon is created and stuff gets aside akin to a deep clone.
1650
+ // This is because deepClone crashes when side is called recursively.
1651
+ // Until a refactor is made to prevent it, this is the best option to prevent crashes.
1652
+ const newPoke = new Pokemon(target.set, source.side);
1653
+ const newPos = source.side.pokemon.length - 1;
1654
+
1655
+ const doNotCarryOver = [
1656
+ 'fullname', 'side', 'fainted', 'status', 'hp', 'illusion',
1657
+ 'transformed', 'position', 'isActive', 'faintQueued',
1658
+ 'subFainted', 'getHealth', 'getDetails', 'moveSlots', 'ability',
1659
+ ];
1660
+ for (const [key, value] of Object.entries(target)) {
1661
+ if (doNotCarryOver.includes(key)) continue;
1662
+ // @ts-ignore
1663
+ newPoke[key] = value;
1664
+ }
1665
+ newPoke.maxhp = newPoke.baseMaxhp; // for dynamax
1666
+ newPoke.hp = newPoke.baseMaxhp - hpCost;
1667
+ newPoke.clearVolatile();
1668
+ newPoke.position = newPos;
1669
+ source.side.pokemon[newPos] = newPoke;
1670
+ this.add('poke', source.side.pokemon[newPos].side.id, source.side.pokemon[newPos].details, '');
1671
+ this.add('-message', `${target.name} was captured by ${newPoke.side.name}!`);
1672
+ } else {
1673
+ target.m.outofplay = true;
1674
+ }
1675
+ },
1676
+ },
1607
1677
  chimera1v1rule: {
1608
1678
  effectType: 'Rule',
1609
1679
  name: 'Chimera 1v1 Rule',
package/data/tags.ts CHANGED
@@ -198,9 +198,9 @@ export const Tags: {[id: string]: TagData} = {
198
198
  name: "ND UUBL",
199
199
  speciesFilter: species => [
200
200
  'Aerodactyl-Mega', 'Alakazam', 'Blacephalon', 'Blaziken', 'Diancie-Mega', 'Gallade-Mega', 'Gardevoir-Mega', 'Gengar', 'Gyarados',
201
- 'Gyarados-Mega', 'Hawlucha', 'Heracross-Mega', 'Hoopa-Unbound', 'Hydreigon', 'Jirachi', 'Latias', 'Latias-Mega', 'Latios', 'Latios-Mega',
202
- 'Manaphy', 'Medicham-Mega', 'Mew', 'Pinsir-Mega', 'Sableye-Mega', 'Slowbro-Mega', 'Slowking-Galar', 'Thundurus', 'Thundurus-Therian',
203
- 'Venusaur-Mega', 'Xurkitree', 'Zapdos-Galar',
201
+ 'Gyarados-Mega', 'Hawlucha', 'Heracross-Mega', 'Hoopa-Unbound', 'Hydreigon', 'Jirachi', 'Latias', 'Latias-Mega', 'Latios',
202
+ 'Latios-Mega', 'Manaphy', 'Medicham-Mega', 'Melmetal', 'Mew', 'Pinsir-Mega', 'Sableye-Mega', 'Slowbro-Mega', 'Slowking-Galar',
203
+ 'Thundurus', 'Thundurus-Therian', 'Venusaur-Mega', 'Xurkitree', 'Zapdos-Galar',
204
204
  ].includes(species.name),
205
205
  },
206
206