@pkmn/engine 0.1.0-dev.f3aaee39 → 0.1.0-dev.f6545544

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