@pkmn/engine 0.1.0-dev.c5fe6d07 → 0.1.0-dev.ce4c0b2a

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 (76) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +46 -19
  3. package/build/pkg/addon/browser.d.ts +3 -0
  4. package/build/pkg/addon/browser.js +43 -0
  5. package/build/pkg/addon/browser.js.map +1 -0
  6. package/build/pkg/addon/node.d.ts +3 -0
  7. package/build/pkg/addon/node.js +96 -0
  8. package/build/pkg/addon/node.js.map +1 -0
  9. package/build/pkg/addon.d.ts +2 -0
  10. package/build/pkg/addon.js +35 -58
  11. package/build/pkg/addon.js.map +1 -1
  12. package/build/pkg/data/ids.json +12 -12
  13. package/build/pkg/data/layout.json +2 -2
  14. package/build/pkg/data/protocol.json +69 -12
  15. package/build/pkg/data.d.ts +27 -5
  16. package/build/pkg/data.js.map +1 -1
  17. package/build/pkg/gen1.js +3 -3
  18. package/build/pkg/gen1.js.map +1 -1
  19. package/build/pkg/index.d.ts +24 -10
  20. package/build/pkg/index.js +15 -10
  21. package/build/pkg/index.js.map +1 -1
  22. package/build/pkg/protocol.d.ts +20 -1
  23. package/build/pkg/protocol.js +123 -102
  24. package/build/pkg/protocol.js.map +1 -1
  25. package/build/tools/debug.js +36 -68
  26. package/build/tools/debug.js.map +1 -1
  27. package/build/tools/display/debug.jsx +128 -0
  28. package/build/tools/display/debug.jsx.map +1 -0
  29. package/build/tools/display/index.js +132 -0
  30. package/build/tools/display/index.js.map +1 -0
  31. package/build/tools/display/ui.jsx +349 -0
  32. package/build/tools/display/ui.jsx.map +1 -0
  33. package/build/tools/display/util.js +18 -0
  34. package/build/tools/display/util.js.map +1 -0
  35. package/build.zig +230 -99
  36. package/package.json +63 -30
  37. package/src/bin/install-pkmn-engine +29 -19
  38. package/src/bin/pkmn-debug +1 -1
  39. package/src/lib/common/array.zig +77 -0
  40. package/src/lib/common/data.zig +12 -24
  41. package/src/lib/common/debug.zig +11 -6
  42. package/src/lib/common/js.zig +4 -2
  43. package/src/lib/common/optional.zig +21 -10
  44. package/src/lib/common/options.zig +4 -0
  45. package/src/lib/common/protocol.zig +807 -327
  46. package/src/lib/common/rational.zig +125 -31
  47. package/src/lib/common/rng.zig +22 -13
  48. package/src/lib/common/util.zig +50 -1
  49. package/src/lib/gen1/calc.zig +660 -137
  50. package/src/lib/gen1/chance.zig +409 -284
  51. package/src/lib/gen1/data/moves.zig +192 -180
  52. package/src/lib/gen1/data/species.zig +3 -3
  53. package/src/lib/gen1/data/types.zig +7 -7
  54. package/src/lib/gen1/data.zig +48 -59
  55. package/src/lib/gen1/helpers.zig +94 -552
  56. package/src/lib/gen1/mechanics.zig +580 -518
  57. package/src/lib/gen2/calc.zig +161 -0
  58. package/src/lib/gen2/chance.zig +902 -0
  59. package/src/lib/gen2/data/items.zig +12 -18
  60. package/src/lib/gen2/data/moves.zig +663 -569
  61. package/src/lib/gen2/data/species.zig +1 -1
  62. package/src/lib/gen2/data/types.zig +134 -31
  63. package/src/lib/gen2/data.zig +107 -79
  64. package/src/lib/gen2/generated.zig +806 -0
  65. package/src/lib/gen2/helpers.zig +49 -25
  66. package/src/lib/gen2/mechanics.zig +3560 -12
  67. package/src/lib/{binding/node.zig → node.zig} +10 -13
  68. package/src/lib/pkmn.zig +32 -15
  69. package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
  70. package/src/tools/display/dom.ts +96 -0
  71. package/src/tools/display/ui.css +351 -0
  72. package/build/test/display.js +0 -400
  73. package/build/test/display.js.map +0 -1
  74. package/src/lib/gen1/README.md +0 -892
  75. package/src/lib/gen2/README.md +0 -308
  76. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -0,0 +1,806 @@
1
+ //! Code generated by `tools/generate` - manual edits will be overwritten.
2
+
3
+ const std = @import("std");
4
+
5
+ const common = @import("../common/data.zig");
6
+
7
+ const data = @import("data.zig");
8
+ const mechanics = @import("mechanics.zig");
9
+
10
+ const Player = common.Player;
11
+ const Result = common.Result;
12
+
13
+ const Effectiveness = data.Effectiveness;
14
+ const Move = data.Move;
15
+
16
+ const Effects = mechanics.Effects;
17
+ const State = mechanics.State;
18
+
19
+ const canMove = mechanics.canMove;
20
+ const canCharge = mechanics.canCharge;
21
+ const decrementPP = mechanics.decrementPP;
22
+ const doMove = mechanics.doMove;
23
+ const checkHit = mechanics.checkHit;
24
+ const checkCriticalHit = mechanics.checkCriticalHit;
25
+ const calcDamage = mechanics.calcDamage;
26
+ const adjustDamage = mechanics.adjustDamage;
27
+ const randomizeDamage = mechanics.randomizeDamage;
28
+ const applyDamage = mechanics.applyDamage;
29
+ const reportOutcome = mechanics.reportOutcome;
30
+ const effectChance = mechanics.effectChance;
31
+ const afterMove = mechanics.afterMove;
32
+ const buildRage = mechanics.buildRage;
33
+ const kingsRock = mechanics.kingsRock;
34
+ const destinyBond = mechanics.destinyBond;
35
+
36
+ const SECONDARY = true;
37
+ const KINGS = true;
38
+
39
+ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype) !void {
40
+ var log = options.log;
41
+
42
+ var side = battle.side(player);
43
+ const volatiles = &side.active.volatiles;
44
+
45
+ const ident = battle.active(player);
46
+ const foe_ident = battle.active(player.foe());
47
+
48
+ const move = Move.get(state.move);
49
+ switch (move.effect) {
50
+ .AlwaysHit, .HighCritical, .Priority, .JumpKick, .None => {
51
+ if (!try canMove(battle, player, state, options)) return;
52
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
53
+ _ = try afterMove(KINGS, battle, player, state, options);
54
+ },
55
+ .DoubleHit, .MultiHit => {
56
+ if (!try canMove(battle, player, state, options)) return;
57
+ // TODO startloop
58
+ try checkHit(battle, player, state, options);
59
+ try checkCriticalHit(battle, player, state, options);
60
+ try calcDamage(battle, player, state, options);
61
+ try adjustDamage(battle, player, state, options);
62
+ try randomizeDamage(battle, player, state, options);
63
+
64
+ if (state.miss) state.damage = 0;
65
+
66
+ try applyDamage(battle, player, state, options);
67
+ // TODO critsupereffectivelooptext
68
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
69
+ // TODO endloop
70
+ try kingsRock(battle, player, state, options);
71
+ },
72
+ .PayDay => {
73
+ if (!try canMove(battle, player, state, options)) return;
74
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
75
+ try Effects.payDay(battle, player, state, options);
76
+ _ = try afterMove(KINGS, battle, player, state, options);
77
+ },
78
+ .BurnChance => {
79
+ if (!try canMove(battle, player, state, options)) return;
80
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
81
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
82
+ try Effects.burnChance(battle, player, state, options);
83
+ },
84
+ .FreezeChance => {
85
+ if (!try canMove(battle, player, state, options)) return;
86
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
87
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
88
+ try Effects.freezeChance(battle, player, state, options);
89
+ },
90
+ .ParalyzeChance => {
91
+ if (!try canMove(battle, player, state, options)) return;
92
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
93
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
94
+ try Effects.paralyzeChance(battle, player, state, options);
95
+ },
96
+ .OHKO => {
97
+ if (!try canMove(battle, player, state, options)) return;
98
+ try Effects.ohko.immune(battle, player, state, options);
99
+ try Effects.ohko.damage(battle, player, state, options);
100
+ try applyDamage(battle, player, state, options);
101
+ try reportOutcome(battle, player, state, options);
102
+ _ = try afterMove(!KINGS, battle, player, state, options);
103
+ },
104
+ .Gust => {
105
+ if (!try canMove(battle, player, state, options)) return;
106
+ try checkCriticalHit(battle, player, state, options);
107
+ try calcDamage(battle, player, state, options);
108
+ try adjustDamage(battle, player, state, options);
109
+ try randomizeDamage(battle, player, state, options);
110
+ try Effects.double.flying(battle, player, state, options);
111
+ try checkHit(battle, player, state, options);
112
+ try applyDamage(battle, player, state, options);
113
+ try reportOutcome(battle, player, state, options);
114
+ _ = try afterMove(!KINGS, battle, player, state, options);
115
+ },
116
+ .ForceSwitch => {
117
+ if (!try canMove(battle, player, state, options)) return;
118
+ try checkHit(battle, player, state, options);
119
+ try Effects.forceSwitch(battle, player, state, options);
120
+ },
121
+ .RazorWind, .SolarBeam, .FlyDig => {
122
+ if (!try canCharge(battle, player, state, options)) return;
123
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
124
+ _ = try afterMove(KINGS, battle, player, state, options);
125
+ },
126
+ .Binding => {
127
+ if (!try canMove(battle, player, state, options)) return;
128
+ try checkHit(battle, player, state, options);
129
+ try checkCriticalHit(battle, player, state, options);
130
+ try calcDamage(battle, player, state, options);
131
+ try adjustDamage(battle, player, state, options);
132
+ try randomizeDamage(battle, player, state, options);
133
+
134
+ if (state.miss) state.damage = 0;
135
+
136
+ try applyDamage(battle, player, state, options);
137
+ try reportOutcome(battle, player, state, options);
138
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
139
+ try Effects.binding(battle, player, state, options);
140
+ },
141
+ .Stomp => {
142
+ if (!try canMove(battle, player, state, options)) return;
143
+ try checkCriticalHit(battle, player, state, options);
144
+ try calcDamage(battle, player, state, options);
145
+ try adjustDamage(battle, player, state, options);
146
+ try randomizeDamage(battle, player, state, options);
147
+ try Effects.double.minimize(battle, player, state, options);
148
+ try checkHit(battle, player, state, options);
149
+ try effectChance(battle, player, state, options);
150
+ try applyDamage(battle, player, state, options);
151
+ try reportOutcome(battle, player, state, options);
152
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
153
+ try Effects.flinchChance(battle, player, state, options);
154
+ },
155
+ .FlinchChance => {
156
+ if (!try canMove(battle, player, state, options)) return;
157
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
158
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
159
+ try Effects.flinchChance(battle, player, state, options);
160
+ },
161
+ .Recoil => {
162
+ if (!try canMove(battle, player, state, options)) return;
163
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
164
+ try Effects.recoil(battle, player, state, options);
165
+ _ = try afterMove(KINGS, battle, player, state, options);
166
+ },
167
+ .Thrashing => {
168
+ // TODO checkrampage
169
+ // doturn
170
+ const charging = false; // TODO
171
+ const skip_pp = charging or state.move == .Struggle or
172
+ (volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
173
+ if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
174
+ // TODO rampage
175
+ // usedmovetext
176
+ try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
177
+ try checkHit(battle, player, state, options);
178
+ try checkCriticalHit(battle, player, state, options);
179
+ try calcDamage(battle, player, state, options);
180
+ try adjustDamage(battle, player, state, options);
181
+ try randomizeDamage(battle, player, state, options);
182
+
183
+ if (state.miss) state.damage = 0;
184
+
185
+ try applyDamage(battle, player, state, options);
186
+ try reportOutcome(battle, player, state, options);
187
+ _ = try afterMove(KINGS, battle, player, state, options);
188
+ },
189
+ .PoisonChance => {
190
+ if (!try canMove(battle, player, state, options)) return;
191
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
192
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
193
+ try Effects.poisonChance(battle, player, state, options);
194
+ },
195
+ .Twineedle => {
196
+ if (!try canMove(battle, player, state, options)) return;
197
+ // TODO startloop
198
+ try checkHit(battle, player, state, options);
199
+ try effectChance(battle, player, state, options);
200
+ try checkCriticalHit(battle, player, state, options);
201
+ try calcDamage(battle, player, state, options);
202
+ try adjustDamage(battle, player, state, options);
203
+ try randomizeDamage(battle, player, state, options);
204
+
205
+ if (state.miss) state.damage = 0;
206
+
207
+ try applyDamage(battle, player, state, options);
208
+ // TODO critsupereffectivelooptext
209
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
210
+ // TODO endloop
211
+ try kingsRock(battle, player, state, options);
212
+ try Effects.poisonChance(battle, player, state, options);
213
+ },
214
+ .Sleep => {
215
+ if (!try canMove(battle, player, state, options)) return;
216
+ try checkHit(battle, player, state, options);
217
+ // TODO checksafeguard
218
+ try Effects.sleep(battle, player, state, options);
219
+ },
220
+ .Confusion => {
221
+ if (!try canMove(battle, player, state, options)) return;
222
+ try checkHit(battle, player, state, options);
223
+ // TODO checksafeguard
224
+ try Effects.confusion(battle, player, state, options);
225
+ },
226
+ .SuperFang, .LevelDamage, .Psywave, .FixedDamage => {
227
+ if (!try canMove(battle, player, state, options)) return;
228
+ try Effects.fixedDamage(battle, player, state, options);
229
+ try checkHit(battle, player, state, options);
230
+
231
+ if (state.immune()) {
232
+ state.damage = 0;
233
+ state.miss = true;
234
+ }
235
+ state.effectiveness = Effectiveness.neutral;
236
+
237
+ try applyDamage(battle, player, state, options);
238
+ _ = try afterMove(KINGS, battle, player, state, options);
239
+ },
240
+ .Disable => {
241
+ if (!try canMove(battle, player, state, options)) return;
242
+ try checkHit(battle, player, state, options);
243
+ try Effects.disable(battle, player, state, options);
244
+ },
245
+ .Mist => {
246
+ if (!try canMove(battle, player, state, options)) return;
247
+ try Effects.mist(battle, player, state, options);
248
+ },
249
+ .ConfusionChance => {
250
+ if (!try canMove(battle, player, state, options)) return;
251
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
252
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
253
+ try Effects.confusionChance(battle, player, state, options);
254
+ },
255
+ .HyperBeam => {
256
+ if (!try canMove(battle, player, state, options)) return;
257
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
258
+ try Effects.hyperBeam(battle, player, state, options);
259
+ _ = try afterMove(!KINGS, battle, player, state, options);
260
+ },
261
+ .MirrorCoat, .Counter => {
262
+ if (!try canMove(battle, player, state, options)) return;
263
+ try Effects.counter(battle, player, state, options);
264
+ try applyDamage(battle, player, state, options);
265
+ _ = try afterMove(KINGS, battle, player, state, options);
266
+ },
267
+ .DreamEater, .DrainHP => {
268
+ if (!try canMove(battle, player, state, options)) return;
269
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
270
+ try Effects.drainHP(battle, player, state, options);
271
+ _ = try afterMove(KINGS, battle, player, state, options);
272
+ },
273
+ .LeechSeed => {
274
+ if (!try canMove(battle, player, state, options)) return;
275
+ try checkHit(battle, player, state, options);
276
+ try Effects.leechSeed(battle, player, state, options);
277
+ },
278
+ .Toxic, .Poison => {
279
+ if (!try canMove(battle, player, state, options)) return;
280
+ try checkHit(battle, player, state, options);
281
+ try adjustDamage(battle, player, state, options);
282
+ // TODO checksafeguard
283
+ try Effects.poison(battle, player, state, options);
284
+ },
285
+ .Paralyze => {
286
+ if (!try canMove(battle, player, state, options)) return;
287
+ try adjustDamage(battle, player, state, options);
288
+ try checkHit(battle, player, state, options);
289
+ // TODO checksafeguard
290
+ try Effects.paralyze(battle, player, state, options);
291
+ },
292
+ .Thunder => {
293
+ if (!try canMove(battle, player, state, options)) return;
294
+ try checkCriticalHit(battle, player, state, options);
295
+ try calcDamage(battle, player, state, options);
296
+ try checkHit(battle, player, state, options);
297
+ try effectChance(battle, player, state, options);
298
+ try adjustDamage(battle, player, state, options);
299
+ try randomizeDamage(battle, player, state, options);
300
+ try applyDamage(battle, player, state, options);
301
+ try reportOutcome(battle, player, state, options);
302
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
303
+ try Effects.paralyzeChance(battle, player, state, options);
304
+ },
305
+ .Earthquake => {
306
+ if (!try canMove(battle, player, state, options)) return;
307
+ try checkCriticalHit(battle, player, state, options);
308
+ try calcDamage(battle, player, state, options);
309
+ try adjustDamage(battle, player, state, options);
310
+ try randomizeDamage(battle, player, state, options);
311
+ try Effects.double.underground(battle, player, state, options);
312
+ try checkHit(battle, player, state, options);
313
+ try effectChance(battle, player, state, options);
314
+ try applyDamage(battle, player, state, options);
315
+ try reportOutcome(battle, player, state, options);
316
+ _ = try afterMove(!KINGS, battle, player, state, options);
317
+ },
318
+ .Rage => {
319
+ if (!try canMove(battle, player, state, options)) return;
320
+ try checkCriticalHit(battle, player, state, options);
321
+ try calcDamage(battle, player, state, options);
322
+ try adjustDamage(battle, player, state, options);
323
+ try checkHit(battle, player, state, options);
324
+ try Effects.rage.damage(battle, player, state, options);
325
+ try randomizeDamage(battle, player, state, options);
326
+ // TODO failuretext
327
+ try Effects.rage.start(battle, player, state, options);
328
+ try applyDamage(battle, player, state, options);
329
+ try reportOutcome(battle, player, state, options);
330
+ _ = try afterMove(KINGS, battle, player, state, options);
331
+ },
332
+ .Teleport => {
333
+ if (!try canMove(battle, player, state, options)) return;
334
+ try Effects.teleport(battle, player, state, options);
335
+ },
336
+ .Mimic => {
337
+ if (!try canMove(battle, player, state, options)) return;
338
+ try checkHit(battle, player, state, options);
339
+ try Effects.mimic(battle, player, state, options);
340
+ },
341
+ .Heal => {
342
+ if (!try canMove(battle, player, state, options)) return;
343
+ try Effects.heal(battle, player, state, options);
344
+ },
345
+ .LightScreen => {
346
+ if (!try canMove(battle, player, state, options)) return;
347
+ try Effects.lightScreen(battle, player, state, options);
348
+ },
349
+ .Haze => {
350
+ if (!try canMove(battle, player, state, options)) return;
351
+ try Effects.haze(battle, player, state, options);
352
+ },
353
+ .Reflect => {
354
+ if (!try canMove(battle, player, state, options)) return;
355
+ try Effects.reflect(battle, player, state, options);
356
+ },
357
+ .FocusEnergy => {
358
+ if (!try canMove(battle, player, state, options)) return;
359
+ try Effects.focusEnergy(battle, player, state, options);
360
+ },
361
+ .Bide => {
362
+ try Effects.bide.store(battle, player, state, options);
363
+ // doturn
364
+ const charging = false; // TODO
365
+ const skip_pp = charging or state.move == .Struggle or
366
+ (volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
367
+ if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
368
+ // usedmovetext
369
+ try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
370
+ try Effects.bide.unleash(battle, player, state, options);
371
+
372
+ if (state.immune()) {
373
+ state.damage = 0;
374
+ state.miss = true;
375
+ }
376
+ state.effectiveness = Effectiveness.neutral;
377
+
378
+ try checkHit(battle, player, state, options);
379
+ // TODO bidefailtext
380
+ try applyDamage(battle, player, state, options);
381
+ _ = try afterMove(KINGS, battle, player, state, options);
382
+ },
383
+ .Metronome => {
384
+ if (!try canMove(battle, player, state, options)) return;
385
+ try Effects.metronome(battle, player, state, options);
386
+ },
387
+ .MirrorMove => {
388
+ if (!try canMove(battle, player, state, options)) return;
389
+ try Effects.mirrorMove(battle, player, state, options);
390
+ },
391
+ .Explode => {
392
+ if (!try canMove(battle, player, state, options)) return;
393
+ try checkCriticalHit(battle, player, state, options);
394
+ try calcDamage(battle, player, state, options);
395
+ try adjustDamage(battle, player, state, options);
396
+ try randomizeDamage(battle, player, state, options);
397
+ try checkHit(battle, player, state, options);
398
+ try Effects.explode(battle, player, state, options);
399
+ try applyDamage(battle, player, state, options);
400
+ try reportOutcome(battle, player, state, options);
401
+ _ = try afterMove(KINGS, battle, player, state, options);
402
+ },
403
+ .SkullBash => {
404
+ if (!try canCharge(battle, player, state, options)) return;
405
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
406
+ if (!try afterMove(KINGS, battle, player, state, options)) return;
407
+ // TODO endturn
408
+ try Effects.boost(battle, player, state, options);
409
+ },
410
+ .SkyAttack => {
411
+ if (!try canCharge(battle, player, state, options)) return;
412
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
413
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
414
+ try Effects.flinchChance(battle, player, state, options);
415
+ try kingsRock(battle, player, state, options);
416
+ },
417
+ .Transform => {
418
+ if (!try canMove(battle, player, state, options)) return;
419
+ try Effects.transform(battle, player, state, options);
420
+ },
421
+ .Splash => {
422
+ if (!try canMove(battle, player, state, options)) return;
423
+ try Effects.splash(battle, player, state, options);
424
+ },
425
+ .Conversion => {
426
+ if (!try canMove(battle, player, state, options)) return;
427
+ try Effects.conversion(battle, player, state, options);
428
+ },
429
+ .TriAttack => {
430
+ if (!try canMove(battle, player, state, options)) return;
431
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
432
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
433
+ try Effects.triAttack(battle, player, state, options);
434
+ },
435
+ .Substitute => {
436
+ if (!try canMove(battle, player, state, options)) return;
437
+ try Effects.substitute(battle, player, state, options);
438
+ },
439
+ .Sketch => {
440
+ if (!try canMove(battle, player, state, options)) return;
441
+ try Effects.sketch(battle, player, state, options);
442
+ },
443
+ .TripleKick => {
444
+ if (!try canMove(battle, player, state, options)) return;
445
+ // TODO startloop
446
+ try checkHit(battle, player, state, options);
447
+ try checkCriticalHit(battle, player, state, options);
448
+ try calcDamage(battle, player, state, options);
449
+ try Effects.tripleKick(battle, player, state, options);
450
+ try adjustDamage(battle, player, state, options);
451
+ try randomizeDamage(battle, player, state, options);
452
+
453
+ if (state.miss) state.damage = 0;
454
+
455
+ try applyDamage(battle, player, state, options);
456
+ // TODO critsupereffectivelooptext
457
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
458
+ // TODO kickcounter
459
+ // TODO endloop
460
+ try kingsRock(battle, player, state, options);
461
+ },
462
+ .Thief => {
463
+ if (!try canMove(battle, player, state, options)) return;
464
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
465
+ try Effects.thief(battle, player, state, options);
466
+ _ = try afterMove(KINGS, battle, player, state, options);
467
+ },
468
+ .MeanLook => {
469
+ if (!try canMove(battle, player, state, options)) return;
470
+ try Effects.meanLook(battle, player, state, options);
471
+ },
472
+ .LockOn => {
473
+ if (!try canMove(battle, player, state, options)) return;
474
+ try checkHit(battle, player, state, options);
475
+ try Effects.lockOn(battle, player, state, options);
476
+ },
477
+ .Nightmare => {
478
+ if (!try canMove(battle, player, state, options)) return;
479
+ try Effects.nightmare(battle, player, state, options);
480
+ },
481
+ .Snore => {
482
+ if (!try canMove(battle, player, state, options)) return;
483
+ try checkCriticalHit(battle, player, state, options);
484
+ try calcDamage(battle, player, state, options);
485
+ try adjustDamage(battle, player, state, options);
486
+ try randomizeDamage(battle, player, state, options);
487
+ try checkHit(battle, player, state, options);
488
+ try effectChance(battle, player, state, options);
489
+ if (!try Effects.snore(battle, player, state, options)) return;
490
+ try applyDamage(battle, player, state, options);
491
+ try reportOutcome(battle, player, state, options);
492
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
493
+ try Effects.flinchChance(battle, player, state, options);
494
+ try kingsRock(battle, player, state, options);
495
+ },
496
+ .Curse => {
497
+ if (!try canMove(battle, player, state, options)) return;
498
+ try Effects.curse(battle, player, state, options);
499
+ },
500
+ .Reversal => {
501
+ if (!try canMove(battle, player, state, options)) return;
502
+ try Effects.reversal(battle, player, state, options);
503
+ try adjustDamage(battle, player, state, options);
504
+ try checkHit(battle, player, state, options);
505
+ try applyDamage(battle, player, state, options);
506
+ // TODO reversalsupereffectivetext
507
+ _ = try afterMove(KINGS, battle, player, state, options);
508
+ },
509
+ .Conversion2 => {
510
+ if (!try canMove(battle, player, state, options)) return;
511
+ try checkHit(battle, player, state, options);
512
+ try Effects.conversion2(battle, player, state, options);
513
+ },
514
+ .Spite => {
515
+ if (!try canMove(battle, player, state, options)) return;
516
+ try checkHit(battle, player, state, options);
517
+ try Effects.spite(battle, player, state, options);
518
+ },
519
+ .Endure, .Protect => {
520
+ if (!try canMove(battle, player, state, options)) return;
521
+ try Effects.protect(battle, player, state, options);
522
+ },
523
+ .BellyDrum => {
524
+ if (!try canMove(battle, player, state, options)) return;
525
+ try Effects.bellyDrum(battle, player, state, options);
526
+ },
527
+ .Spikes => {
528
+ if (!try canMove(battle, player, state, options)) return;
529
+ try Effects.spikes(battle, player, state, options);
530
+ },
531
+ .Foresight => {
532
+ if (!try canMove(battle, player, state, options)) return;
533
+ try checkHit(battle, player, state, options);
534
+ try Effects.foresight(battle, player, state, options);
535
+ },
536
+ .DestinyBond => {
537
+ if (!try canMove(battle, player, state, options)) return;
538
+ try Effects.destinyBond(battle, player, state, options);
539
+ },
540
+ .PerishSong => {
541
+ if (!try canMove(battle, player, state, options)) return;
542
+ try Effects.perishSong(battle, player, state, options);
543
+ },
544
+ .Sandstorm => {
545
+ if (!try canMove(battle, player, state, options)) return;
546
+ try Effects.sandstorm(battle, player, state, options);
547
+ },
548
+ .Rollout => {
549
+ try Effects.rollout.check(battle, player, state, options);
550
+ // doturn
551
+ const charging = false; // TODO
552
+ const skip_pp = charging or state.move == .Struggle or
553
+ (volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
554
+ if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
555
+ // usedmovetext
556
+ try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
557
+ try checkCriticalHit(battle, player, state, options);
558
+ try calcDamage(battle, player, state, options);
559
+ try adjustDamage(battle, player, state, options);
560
+ try checkHit(battle, player, state, options);
561
+ try Effects.rollout.power(battle, player, state, options);
562
+ try randomizeDamage(battle, player, state, options);
563
+ try applyDamage(battle, player, state, options);
564
+ try reportOutcome(battle, player, state, options);
565
+ _ = try afterMove(KINGS, battle, player, state, options);
566
+ },
567
+ .FalseSwipe => {
568
+ if (!try canMove(battle, player, state, options)) return;
569
+ try checkCriticalHit(battle, player, state, options);
570
+ try calcDamage(battle, player, state, options);
571
+ try adjustDamage(battle, player, state, options);
572
+ try randomizeDamage(battle, player, state, options);
573
+ try Effects.falseSwipe(battle, player, state, options);
574
+ try checkHit(battle, player, state, options);
575
+ try applyDamage(battle, player, state, options);
576
+ try reportOutcome(battle, player, state, options);
577
+ _ = try afterMove(KINGS, battle, player, state, options);
578
+ },
579
+ .Swagger => {
580
+ if (!try canMove(battle, player, state, options)) return;
581
+ try checkHit(battle, player, state, options);
582
+ try Effects.boost(battle, player.foe(), state, options);
583
+ try Effects.confusionChance(battle, player, state, options);
584
+ },
585
+ .FuryCutter => {
586
+ if (!try canMove(battle, player, state, options)) return;
587
+ try checkCriticalHit(battle, player, state, options);
588
+ try calcDamage(battle, player, state, options);
589
+ try adjustDamage(battle, player, state, options);
590
+ try checkHit(battle, player, state, options);
591
+ try Effects.furyCutter(battle, player, state, options);
592
+ try randomizeDamage(battle, player, state, options);
593
+ try applyDamage(battle, player, state, options);
594
+ try reportOutcome(battle, player, state, options);
595
+ _ = try afterMove(KINGS, battle, player, state, options);
596
+ },
597
+ .Attract => {
598
+ if (!try canMove(battle, player, state, options)) return;
599
+ try checkHit(battle, player, state, options);
600
+ try Effects.attract(battle, player, state, options);
601
+ },
602
+ .SleepTalk => {
603
+ if (!try canMove(battle, player, state, options)) return;
604
+ try Effects.sleepTalk(battle, player, state, options);
605
+ },
606
+ .HealBell => {
607
+ if (!try canMove(battle, player, state, options)) return;
608
+ try Effects.healBell(battle, player, state, options);
609
+ },
610
+ .Frustration, .Return => {
611
+ if (!try canMove(battle, player, state, options)) return;
612
+ try checkCriticalHit(battle, player, state, options);
613
+ try Effects.happiness(battle, player, state, options);
614
+ try calcDamage(battle, player, state, options);
615
+ try adjustDamage(battle, player, state, options);
616
+ try randomizeDamage(battle, player, state, options);
617
+ try checkHit(battle, player, state, options);
618
+ try applyDamage(battle, player, state, options);
619
+ try reportOutcome(battle, player, state, options);
620
+ _ = try afterMove(KINGS, battle, player, state, options);
621
+ },
622
+ .Present => {
623
+ if (!try canMove(battle, player, state, options)) return;
624
+ try checkHit(battle, player, state, options);
625
+ try checkCriticalHit(battle, player, state, options);
626
+ try Effects.present(battle, player, state, options);
627
+ try calcDamage(battle, player, state, options);
628
+ try adjustDamage(battle, player, state, options);
629
+ try randomizeDamage(battle, player, state, options);
630
+
631
+ if (state.miss) state.damage = 0;
632
+
633
+ try applyDamage(battle, player, state, options);
634
+ try reportOutcome(battle, player, state, options);
635
+ _ = try afterMove(KINGS, battle, player, state, options);
636
+ },
637
+ .Safeguard => {
638
+ if (!try canMove(battle, player, state, options)) return;
639
+ try Effects.safeguard(battle, player, state, options);
640
+ },
641
+ .PainSplit => {
642
+ if (!try canMove(battle, player, state, options)) return;
643
+ try checkHit(battle, player, state, options);
644
+ try Effects.painSplit(battle, player, state, options);
645
+ },
646
+ .FlameWheel, .SacredFire => {
647
+ if (!try canMove(battle, player, state, options)) return;
648
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
649
+ try Effects.defrost(battle, player, state, options);
650
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
651
+ try Effects.burnChance(battle, player, state, options);
652
+ },
653
+ .Magnitude => {
654
+ if (!try canMove(battle, player, state, options)) return;
655
+ try checkCriticalHit(battle, player, state, options);
656
+ try Effects.magnitude(battle, player, state, options);
657
+ try calcDamage(battle, player, state, options);
658
+ try adjustDamage(battle, player, state, options);
659
+ try randomizeDamage(battle, player, state, options);
660
+ try checkHit(battle, player, state, options);
661
+ try Effects.double.underground(battle, player, state, options);
662
+ try applyDamage(battle, player, state, options);
663
+ try reportOutcome(battle, player, state, options);
664
+ _ = try afterMove(KINGS, battle, player, state, options);
665
+ },
666
+ .BatonPass => {
667
+ if (!try canMove(battle, player, state, options)) return;
668
+ try Effects.batonPass(battle, player, state, options);
669
+ },
670
+ .Encore => {
671
+ if (!try canMove(battle, player, state, options)) return;
672
+ try checkHit(battle, player, state, options);
673
+ try Effects.encore(battle, player, state, options);
674
+ },
675
+ .Pursuit => {
676
+ if (!try canMove(battle, player, state, options)) return;
677
+ try checkCriticalHit(battle, player, state, options);
678
+ try calcDamage(battle, player, state, options);
679
+ try adjustDamage(battle, player, state, options);
680
+ try randomizeDamage(battle, player, state, options);
681
+ try Effects.pursuit(battle, player, state, options);
682
+ try checkHit(battle, player, state, options);
683
+ try applyDamage(battle, player, state, options);
684
+ try reportOutcome(battle, player, state, options);
685
+ _ = try afterMove(KINGS, battle, player, state, options);
686
+ },
687
+ .RapidSpin => {
688
+ if (!try canMove(battle, player, state, options)) return;
689
+ if (!try doMove(!SECONDARY, battle, player, state, options)) return;
690
+ try Effects.rapidSpin(battle, player, state, options);
691
+ _ = try afterMove(KINGS, battle, player, state, options);
692
+ },
693
+ .MorningSun, .Synthesis, .Moonlight => {
694
+ if (!try canMove(battle, player, state, options)) return;
695
+ try Effects.weatherHeal(battle, player, state, options);
696
+ },
697
+ .HiddenPower => {
698
+ if (!try canMove(battle, player, state, options)) return;
699
+ try checkCriticalHit(battle, player, state, options);
700
+ try Effects.hiddenPower(battle, player, state, options);
701
+ try calcDamage(battle, player, state, options);
702
+ try adjustDamage(battle, player, state, options);
703
+ try randomizeDamage(battle, player, state, options);
704
+ try checkHit(battle, player, state, options);
705
+ try applyDamage(battle, player, state, options);
706
+ try reportOutcome(battle, player, state, options);
707
+ _ = try afterMove(KINGS, battle, player, state, options);
708
+ },
709
+ .Twister => {
710
+ if (!try canMove(battle, player, state, options)) return;
711
+ try checkCriticalHit(battle, player, state, options);
712
+ try calcDamage(battle, player, state, options);
713
+ try adjustDamage(battle, player, state, options);
714
+ try randomizeDamage(battle, player, state, options);
715
+ try Effects.double.flying(battle, player, state, options);
716
+ try checkHit(battle, player, state, options);
717
+ try effectChance(battle, player, state, options);
718
+ try applyDamage(battle, player, state, options);
719
+ try reportOutcome(battle, player, state, options);
720
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
721
+ try Effects.flinchChance(battle, player, state, options);
722
+ },
723
+ .RainDance => {
724
+ if (!try canMove(battle, player, state, options)) return;
725
+ try Effects.rainDance(battle, player, state, options);
726
+ },
727
+ .SunnyDay => {
728
+ if (!try canMove(battle, player, state, options)) return;
729
+ try Effects.sunnyDay(battle, player, state, options);
730
+ },
731
+ .PsychUp => {
732
+ if (!try canMove(battle, player, state, options)) return;
733
+ try Effects.psychUp(battle, player, state, options);
734
+ },
735
+ .AllStatUpChance => {
736
+ if (!try canMove(battle, player, state, options)) return;
737
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
738
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
739
+ try Effects.allStatUpChance(battle, player, state, options);
740
+ },
741
+ .FutureSight => {
742
+ // TODO checkfuturesight
743
+ if (!try canMove(battle, player, state, options)) return;
744
+ try calcDamage(battle, player, state, options);
745
+ try Effects.futureSight(battle, player, state, options);
746
+ try randomizeDamage(battle, player, state, options);
747
+ try checkHit(battle, player, state, options);
748
+ try applyDamage(battle, player, state, options);
749
+ _ = try afterMove(!KINGS, battle, player, state, options);
750
+ },
751
+ .BeatUp => {
752
+ if (!try canMove(battle, player, state, options)) return;
753
+ // TODO startloop
754
+ try checkHit(battle, player, state, options);
755
+ try checkCriticalHit(battle, player, state, options);
756
+ try Effects.beatUp(battle, player, state, options);
757
+ try randomizeDamage(battle, player, state, options);
758
+
759
+ if (state.miss) state.damage = 0;
760
+
761
+ try applyDamage(battle, player, state, options);
762
+ try reportOutcome(battle, player, state, options);
763
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
764
+ // TODO endloop
765
+ // TODO beatupfailtext
766
+ try kingsRock(battle, player, state, options);
767
+ },
768
+ // zig fmt: off
769
+ .AttackUp1, .AttackUp2, .DefenseCurl, .DefenseUp1, .DefenseUp2,
770
+ .EvasionUp1, .SpAtkUp1, .SpDefUp2, .SpeedUp2 => {
771
+ // zig fmt: on
772
+ _ = try canMove(battle, player, state, options);
773
+ try Effects.boost(battle, player, state, options);
774
+ if (move.effect == .DefenseCurl) {
775
+ try Effects.defenseCurl(battle, player, state, options);
776
+ }
777
+ },
778
+ .AttackUpChance, .DefenseUpChance => {
779
+ _ = try canMove(battle, player, state, options);
780
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
781
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
782
+ try Effects.boost(battle, player, state, options);
783
+ },
784
+ // zig fmt: off
785
+ .AccuracyDown1, .AttackDown1, .AttackDown2, .DefenseDown1,
786
+ .DefenseDown2, .EvasionDown1, .SpeedDown1, .SpeedDown2 => {
787
+ // zig fmt: on
788
+ _ = try canMove(battle, player, state, options);
789
+ try checkHit(battle, player, state, options);
790
+ try Effects.unboost(battle, player, state, options);
791
+ },
792
+ // zig fmt: off
793
+ .AccuracyDownChance, .AttackDownChance, .DefenseDownChance,
794
+ .SpDefDownChance, .SpeedDownChance => {
795
+ // zig fmt: on
796
+ _ = try canMove(battle, player, state, options);
797
+ if (!try doMove(SECONDARY, battle, player, state, options)) return;
798
+ if (!try afterMove(!KINGS, battle, player, state, options)) return;
799
+ // GLITCH: moves that lower Defense can do so after breaking a Substitute
800
+ if (move.effect == .DefenseDownChance) {
801
+ try effectChance(battle, player, state, options);
802
+ }
803
+ try Effects.unboost(battle, player, state, options);
804
+ },
805
+ }
806
+ }