@pkmn/engine 0.1.0-dev.9a0c07c3 → 0.1.0-dev.9f75c7ae

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