@pkmn/engine 0.1.0-dev.a93847b2 → 0.1.0-dev.ac652f4e

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 (83) 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/layout.json +15 -2
  16. package/build/pkg/data/protocol.json +23 -9
  17. package/build/pkg/data.d.ts +27 -5
  18. package/build/pkg/data.js.map +1 -1
  19. package/build/pkg/gen1.d.ts +15 -18
  20. package/build/pkg/gen1.js +28 -19
  21. package/build/pkg/gen1.js.map +1 -1
  22. package/build/pkg/index.d.ts +42 -91
  23. package/build/pkg/index.js +23 -70
  24. package/build/pkg/index.js.map +1 -1
  25. package/build/pkg/protocol.d.ts +20 -1
  26. package/build/pkg/protocol.js +109 -107
  27. package/build/pkg/protocol.js.map +1 -1
  28. package/build/tools/debug.js +53 -76
  29. package/build/tools/debug.js.map +1 -1
  30. package/build/tools/display/debug.jsx +152 -0
  31. package/build/tools/display/debug.jsx.map +1 -0
  32. package/build/tools/display/index.js +152 -0
  33. package/build/tools/display/index.js.map +1 -0
  34. package/build/tools/display/ui.jsx +359 -0
  35. package/build/tools/display/ui.jsx.map +1 -0
  36. package/build/tools/display/util.js +33 -0
  37. package/build/tools/display/util.js.map +1 -0
  38. package/build.zig +344 -101
  39. package/package.json +59 -132
  40. package/src/bin/install-pkmn-engine +31 -20
  41. package/src/bin/pkmn-debug +1 -1
  42. package/src/lib/bindings/c.zig +255 -0
  43. package/src/lib/{binding → bindings}/node.zig +8 -21
  44. package/src/lib/bindings/wasm.zig +59 -0
  45. package/src/lib/common/array.zig +77 -0
  46. package/src/lib/common/data.zig +8 -8
  47. package/src/lib/common/debug.zig +39 -8
  48. package/src/lib/common/js.zig +4 -2
  49. package/src/lib/common/optional.zig +14 -10
  50. package/src/lib/common/options.zig +6 -0
  51. package/src/lib/common/protocol.zig +400 -402
  52. package/src/lib/common/rational.zig +328 -159
  53. package/src/lib/common/rng.zig +16 -9
  54. package/src/lib/common/util.zig +60 -1
  55. package/src/lib/gen1/calc.zig +697 -161
  56. package/src/lib/gen1/chance.zig +406 -281
  57. package/src/lib/gen1/data/moves.zig +11 -13
  58. package/src/lib/gen1/data/species.zig +3 -5
  59. package/src/lib/gen1/data/types.zig +5 -6
  60. package/src/lib/gen1/data.zig +38 -41
  61. package/src/lib/gen1/helpers.zig +92 -548
  62. package/src/lib/gen1/mechanics.zig +593 -483
  63. package/src/lib/gen2/calc.zig +38 -28
  64. package/src/lib/gen2/chance.zig +85 -497
  65. package/src/lib/gen2/data/items.zig +3 -5
  66. package/src/lib/gen2/data/moves.zig +4 -6
  67. package/src/lib/gen2/data/species.zig +1 -3
  68. package/src/lib/gen2/data/types.zig +10 -11
  69. package/src/lib/gen2/data.zig +33 -34
  70. package/src/lib/gen2/generated.zig +45 -101
  71. package/src/lib/gen2/helpers.zig +46 -25
  72. package/src/lib/gen2/mechanics.zig +1121 -555
  73. package/src/lib/node.zig +18 -0
  74. package/src/lib/pkmn.zig +37 -15
  75. package/src/lib/wasm.zig +17 -0
  76. package/src/tools/display/dom.ts +93 -0
  77. package/src/tools/display/ui.css +354 -0
  78. package/build/test/display.js +0 -400
  79. package/build/test/display.js.map +0 -1
  80. package/src/lib/binding/wasm.zig +0 -12
  81. package/src/lib/gen1/README.md +0 -894
  82. package/src/lib/gen2/README.md +0 -330
  83. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,11 +1,9 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const data = @import("../../gen2/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
-
9
7
  const Type = data.Type;
10
8
 
11
9
  /// Representation of a held item in Generation II Pokémon.
@@ -216,14 +214,14 @@ pub const Item = enum(u8) {
216
214
  pub const size = 196;
217
215
 
218
216
  /// Returns a `Type` boosted by this item or `null` if the item is not a type-boosting item.
219
- pub inline fn boost(item: Item) ?Type {
217
+ pub fn boost(item: Item) ?Type {
220
218
  assert(item != .None);
221
219
  if (item == .PolkadotBow) return .Normal;
222
220
  return if (@intFromEnum(item) <= 18) @enumFromInt(@intFromEnum(item) - 1) else null;
223
221
  }
224
222
 
225
223
  /// Whether or not this item is Mail.
226
- pub inline fn isMail(item: Item) bool {
224
+ pub fn isMail(item: Item) bool {
227
225
  assert(item != .None);
228
226
  return @intFromEnum(item) > 60 and @intFromEnum(item) <= 70;
229
227
  }
@@ -1,12 +1,10 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
- const rng = @import("../../common/rng.zig");
6
3
  const gen2 = @import("../../gen2/data.zig");
4
+ const rng = @import("../../common/rng.zig");
5
+ const std = @import("std");
7
6
 
8
7
  const assert = std.debug.assert;
9
-
10
8
  const percent = rng.Gen12.percent;
11
9
  const Type = gen2.Type;
12
10
 
@@ -2562,7 +2560,7 @@ pub const Move = enum(u8) {
2562
2560
  }
2563
2561
 
2564
2562
  /// Whether this effect has a high critical rate.
2565
- pub inline fn isHighCritical(effect: Effect) bool {
2563
+ pub fn isHighCritical(effect: Effect) bool {
2566
2564
  return effect == .HighCritical or effect == .RazorWind;
2567
2565
  }
2568
2566
  };
@@ -2865,7 +2863,7 @@ pub const Move = enum(u8) {
2865
2863
  };
2866
2864
 
2867
2865
  /// Returns the `Data` corresponding to the move.
2868
- pub inline fn get(id: Move) Data {
2866
+ pub fn get(id: Move) Data {
2869
2867
  assert(id != .None);
2870
2868
  return DATA[@intFromEnum(id) - 1];
2871
2869
  }
@@ -1,11 +1,9 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const gen2 = @import("../../gen2/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
-
9
7
  const Stats = gen2.Stats;
10
8
  const Types = gen2.Types;
11
9
 
@@ -1,8 +1,7 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const gen1 = @import("../../gen1/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
7
  const Effectiveness = gen1.Effectiveness;
@@ -164,27 +163,27 @@ pub const Type = enum(u8) {
164
163
  pub const size = 18;
165
164
 
166
165
  /// Whether or not this type is considered to be special as opposed to physical.
167
- pub inline fn special(self: Type) bool {
166
+ pub fn special(self: Type) bool {
168
167
  return @intFromEnum(self) >= @intFromEnum(Type.Fire);
169
168
  }
170
169
 
171
170
  /// The `Effectiveness` of type `t2` vs. type `t1`.
172
- pub inline fn effectiveness(t1: Type, t2: Type) Effectiveness {
171
+ pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
173
172
  return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
174
173
  }
175
174
 
176
175
  /// The precedence order of Type `type`.
177
- pub inline fn precedence(self: Type) u8 {
176
+ pub fn precedence(self: Type) u8 {
178
177
  return PRECEDENCE[@intFromEnum(self)];
179
178
  }
180
179
 
181
180
  /// The internal index of this Type used by Present.
182
- pub inline fn present(self: Type) u8 {
181
+ pub fn present(self: Type) u8 {
183
182
  return INDEXES[@intFromEnum(self)];
184
183
  }
185
184
 
186
185
  /// The Type corresponding to a random roll of `num` for Conversion 2.
187
- pub inline fn conversion2(num: u8) Type {
186
+ pub fn conversion2(num: u8) Type {
188
187
  assert(num != 6);
189
188
  assert(num < 10 or num >= 20);
190
189
  assert(num <= 27);
@@ -192,7 +191,7 @@ pub const Type = enum(u8) {
192
191
  }
193
192
 
194
193
  /// The Type corresponding to a Hidden Power `index`.
195
- pub inline fn hiddenPower(index: u8) Type {
194
+ pub fn hiddenPower(index: u8) Type {
196
195
  return HIDDEN_POWER[index];
197
196
  }
198
197
  };
@@ -209,17 +208,17 @@ pub const Types = extern struct {
209
208
  }
210
209
 
211
210
  /// Whether this typing is immune to type `t`.
212
- pub inline fn immune(self: Types, t: Type) bool {
211
+ pub fn immune(self: Types, t: Type) bool {
213
212
  return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
214
213
  }
215
214
 
216
215
  /// Whether this typing includes type `t`.
217
- pub inline fn includes(self: Types, t: Type) bool {
216
+ pub fn includes(self: Types, t: Type) bool {
218
217
  return self.type1 == t or self.type2 == t;
219
218
  }
220
219
 
221
220
  /// Whether this typing is immune to damage from Sandstorm.
222
- pub inline fn sandstormImmune(self: Types) bool {
221
+ pub fn sandstormImmune(self: Types) bool {
223
222
  return @intFromEnum(self.type1) <= @intFromEnum(Type.Steel) or
224
223
  @intFromEnum(self.type2) <= @intFromEnum(Type.Steel);
225
224
  }
@@ -1,24 +1,20 @@
1
- const std = @import("std");
2
- const builtin = @import("builtin");
3
-
4
- const pkmn = @import("../pkmn.zig");
5
-
6
- const data = @import("../common/data.zig");
7
1
  const DEBUG = @import("../common/debug.zig").print;
8
- const protocol = @import("../common/protocol.zig");
9
- const rng = @import("../common/rng.zig");
10
- const util = @import("../common/util.zig");
11
2
 
3
+ const builtin = @import("builtin");
4
+ const calc = @import("calc.zig");
5
+ const chance = @import("chance.zig");
6
+ const data = @import("../common/data.zig");
7
+ const gen1 = @import("../gen1/data.zig");
12
8
  const items = @import("data/items.zig");
9
+ const mechanics = @import("mechanics.zig");
13
10
  const moves = @import("data/moves.zig");
11
+ const pkmn = @import("../pkmn.zig");
12
+ const protocol = @import("../common/protocol.zig");
13
+ const rng = @import("../common/rng.zig");
14
14
  const species = @import("data/species.zig");
15
+ const std = @import("std");
15
16
  const types = @import("data/types.zig");
16
-
17
- const gen1 = @import("../gen1/data.zig");
18
-
19
- const calc = @import("calc.zig");
20
- const chance = @import("chance.zig");
21
- const mechanics = @import("mechanics.zig");
17
+ const util = @import("../common/util.zig");
22
18
 
23
19
  const assert = std.debug.assert;
24
20
  const expectEqual = std.testing.expectEqual;
@@ -45,6 +41,7 @@ const Player = data.Player;
45
41
  const Result = data.Result;
46
42
 
47
43
  const PointerType = util.PointerType;
44
+ const isPointerTo = util.isPointerTo;
48
45
 
49
46
  const showdown = pkmn.options.showdown;
50
47
 
@@ -62,17 +59,17 @@ pub fn Battle(comptime RNG: anytype) type {
62
59
 
63
60
  _: [padding]u8 = .{0} ** padding,
64
61
 
65
- pub inline fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
66
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
62
+ pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
63
+ assert(isPointerTo(self, Self));
67
64
  return &self.sides[@intFromEnum(player)];
68
65
  }
69
66
 
70
- pub inline fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
71
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
67
+ pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
68
+ assert(isPointerTo(self, Self));
72
69
  return &self.sides[@intFromEnum(player.foe())];
73
70
  }
74
71
 
75
- pub inline fn active(self: *const Self, player: Player) ID {
72
+ pub fn active(self: *const Self, player: Player) ID {
76
73
  return player.ident(@intCast(self.side(player).pokemon[0].position));
77
74
  }
78
75
 
@@ -133,27 +130,27 @@ pub const Side = extern struct {
133
130
  assert(@sizeOf(Side) == 248);
134
131
  }
135
132
 
136
- pub inline fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
137
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
133
+ pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
134
+ assert(isPointerTo(self, Side));
138
135
  assert(slot > 0 and slot <= 6);
139
136
  const id = self.pokemon[slot - 1].position;
140
137
  assert(id > 0 and id <= 6);
141
138
  return &self.pokemon[id - 1];
142
139
  }
143
140
 
144
- pub inline fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
145
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
141
+ pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
142
+ assert(isPointerTo(self, Side));
146
143
  return self.get(1);
147
144
  }
148
145
 
149
- pub inline fn lastMove(self: anytype, encore: bool) Move {
146
+ pub fn lastMove(self: anytype, encore: bool) Move {
150
147
  assert(self.last_used_move != .None or !self.active.volatiles.dirty);
151
148
  if (encore) return self.last_used_move;
152
149
  return if (self.active.volatiles.dirty) .None else self.last_used_move;
153
150
  }
154
151
 
155
152
  // TODO
156
- // pub inline fn useMove(self: anytype) void {
153
+ // pub fn useMove(self: anytype) void {
157
154
  // assert(side.last_selected_move != .None);
158
155
  // self.last_used_move = side.last_selected_move;
159
156
  // self.active.volatiles.dirty = false;
@@ -175,8 +172,8 @@ pub const ActivePokemon = extern struct {
175
172
  assert(@sizeOf(ActivePokemon) == 44);
176
173
  }
177
174
 
178
- pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
179
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
175
+ pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
176
+ assert(isPointerTo(self, Pokemon));
180
177
  assert(mslot > 0 and mslot <= 4);
181
178
  assert(self.moves[mslot - 1].id != .None);
182
179
  return &self.moves[mslot - 1];
@@ -200,8 +197,8 @@ pub const Pokemon = extern struct {
200
197
  assert(@sizeOf(Pokemon) == 32);
201
198
  }
202
199
 
203
- pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
204
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
200
+ pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
201
+ assert(isPointerTo(self, Pokemon));
205
202
  assert(mslot > 0 and mslot <= 4);
206
203
  assert(self.moves[mslot - 1].id != .None);
207
204
  return &self.moves[mslot - 1];
@@ -225,7 +222,7 @@ pub const DVs = packed struct(u16) {
225
222
  return .{ .gender = g, .pow = p, .type = t };
226
223
  }
227
224
 
228
- pub inline fn power(dvs: DVs) u8 {
225
+ pub fn power(dvs: DVs) u8 {
229
226
  return @as(u8, dvs.pow) + 30;
230
227
  }
231
228
 
@@ -239,7 +236,7 @@ pub const DVs = packed struct(u16) {
239
236
  };
240
237
  const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
241
238
  ((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
242
- var t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
239
+ const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
243
240
  return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
244
241
  }
245
242
  };
@@ -314,16 +311,18 @@ pub const Volatiles = packed struct(u128) {
314
311
  Encore: bool = false,
315
312
  LockOn: bool = false,
316
313
  DestinyBond: bool = false,
314
+ Trapped: bool = false,
317
315
 
318
- trapped: bool = false,
319
316
  switched: bool = false,
317
+ // TODO: replace with simply looking at Choice on Battle
320
318
  switching: bool = false,
319
+ // TODO: simply store both last moves on side
321
320
  dirty: bool = false,
322
321
 
323
322
  frozen: bool = false,
324
323
  minimized: bool = false,
325
324
  _: u10 = 0,
326
- // TODO?
325
+ // TODO: is this needed for unmodified stats?
327
326
  transform: u4 = 0,
328
327
 
329
328
  bide: u16 = 0,
@@ -1,39 +1,32 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const common = @import("../common/data.zig");
6
-
7
4
  const data = @import("data.zig");
8
5
  const mechanics = @import("mechanics.zig");
6
+ const std = @import("std");
9
7
 
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;
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;
22
13
  const canCharge = mechanics.canCharge;
14
+ const canMove = mechanics.canMove;
15
+ const checkCriticalHit = mechanics.checkCriticalHit;
16
+ const checkHit = mechanics.checkHit;
23
17
  const decrementPP = mechanics.decrementPP;
18
+ const destinyBond = mechanics.destinyBond;
24
19
  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
20
  const effectChance = mechanics.effectChance;
33
- const afterMove = mechanics.afterMove;
34
- const buildRage = mechanics.buildRage;
21
+ const Effectiveness = data.Effectiveness;
22
+ const Effects = mechanics.Effects;
35
23
  const kingsRock = mechanics.kingsRock;
36
- const destinyBond = mechanics.destinyBond;
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;
37
30
 
38
31
  const SECONDARY = true;
39
32
  const KINGS = true;
@@ -42,7 +35,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
42
35
  var log = options.log;
43
36
 
44
37
  var side = battle.side(player);
45
- var volatiles = &side.active.volatiles;
38
+ const volatiles = &side.active.volatiles;
46
39
 
47
40
  const ident = battle.active(player);
48
41
  const foe_ident = battle.active(player.foe());
@@ -97,17 +90,8 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
97
90
  },
98
91
  .OHKO => {
99
92
  if (!try canMove(battle, player, state, options)) return;
100
-
101
- // OHKO calls adjustDamage but only actually cares about immunity
102
- assert(move.type == .Normal or move.type == .Ground);
103
- const foe = battle.foe(player);
104
- const immune = if (move.type == .Normal)
105
- foe.active.types.includes(.Ghost) and !foe.active.volatiles.Foresight
106
- else
107
- foe.active.types.includes(.Ghost);
108
- state.effectiveness = if (immune) 0 else Effectiveness.neutral;
109
-
110
- try Effects.ohko(battle, player, state, options);
93
+ try Effects.ohko.immune(battle, player, state, options);
94
+ try Effects.ohko.damage(battle, player, state, options);
111
95
  try applyDamage(battle, player, state, options);
112
96
  try reportOutcome(battle, player, state, options);
113
97
  _ = try afterMove(!KINGS, battle, player, state, options);
@@ -118,9 +102,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
118
102
  try calcDamage(battle, player, state, options);
119
103
  try adjustDamage(battle, player, state, options);
120
104
  try randomizeDamage(battle, player, state, options);
121
-
122
- if (battle.foe(player).active.volatiles.Flying) state.damage *|= 2;
123
-
105
+ try Effects.double.flying(battle, player, state, options);
124
106
  try checkHit(battle, player, state, options);
125
107
  try applyDamage(battle, player, state, options);
126
108
  try reportOutcome(battle, player, state, options);
@@ -157,9 +139,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
157
139
  try calcDamage(battle, player, state, options);
158
140
  try adjustDamage(battle, player, state, options);
159
141
  try randomizeDamage(battle, player, state, options);
160
-
161
- if (battle.foe(player).active.volatiles.minimized) state.damage *|= 2;
162
-
142
+ try Effects.double.minimize(battle, player, state, options);
163
143
  try checkHit(battle, player, state, options);
164
144
  try effectChance(battle, player, state, options);
165
145
  try applyDamage(battle, player, state, options);
@@ -188,7 +168,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
188
168
  if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
189
169
  // TODO rampage
190
170
  // usedmovetext
191
- try log.move(ident, state.move, foe_ident); // FIXME self? from?
171
+ try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
192
172
  try checkHit(battle, player, state, options);
193
173
  try checkCriticalHit(battle, player, state, options);
194
174
  try calcDamage(battle, player, state, options);
@@ -273,7 +253,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
273
253
  try Effects.hyperBeam(battle, player, state, options);
274
254
  _ = try afterMove(!KINGS, battle, player, state, options);
275
255
  },
276
- .Counter => {
256
+ .MirrorCoat, .Counter => {
277
257
  if (!try canMove(battle, player, state, options)) return;
278
258
  try Effects.counter(battle, player, state, options);
279
259
  try applyDamage(battle, player, state, options);
@@ -308,7 +288,6 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
308
288
  if (!try canMove(battle, player, state, options)) return;
309
289
  try checkCriticalHit(battle, player, state, options);
310
290
  try calcDamage(battle, player, state, options);
311
- // TODO thunderaccuracy
312
291
  try checkHit(battle, player, state, options);
313
292
  try effectChance(battle, player, state, options);
314
293
  try adjustDamage(battle, player, state, options);
@@ -324,9 +303,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
324
303
  try calcDamage(battle, player, state, options);
325
304
  try adjustDamage(battle, player, state, options);
326
305
  try randomizeDamage(battle, player, state, options);
327
-
328
- if (battle.foe(player).active.volatiles.Underground) state.damage *|= 2;
329
-
306
+ try Effects.double.underground(battle, player, state, options);
330
307
  try checkHit(battle, player, state, options);
331
308
  try effectChance(battle, player, state, options);
332
309
  try applyDamage(battle, player, state, options);
@@ -339,13 +316,10 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
339
316
  try calcDamage(battle, player, state, options);
340
317
  try adjustDamage(battle, player, state, options);
341
318
  try checkHit(battle, player, state, options);
342
-
343
- assert(volatiles.Rage);
344
- state.damage *|= (volatiles.rage +| 1);
345
-
319
+ try Effects.rage.damage(battle, player, state, options);
346
320
  try randomizeDamage(battle, player, state, options);
347
321
  // TODO failuretext
348
- try Effects.rage(battle, player, state, options);
322
+ try Effects.rage.start(battle, player, state, options);
349
323
  try applyDamage(battle, player, state, options);
350
324
  try reportOutcome(battle, player, state, options);
351
325
  _ = try afterMove(KINGS, battle, player, state, options);
@@ -363,47 +337,32 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
363
337
  if (!try canMove(battle, player, state, options)) return;
364
338
  try Effects.heal(battle, player, state, options);
365
339
  },
340
+ .LightScreen => {
341
+ if (!try canMove(battle, player, state, options)) return;
342
+ try Effects.lightScreen(battle, player, state, options);
343
+ },
366
344
  .Haze => {
367
345
  if (!try canMove(battle, player, state, options)) return;
368
346
  try Effects.haze(battle, player, state, options);
369
347
  },
370
- .LightScreen, .Reflect => {
348
+ .Reflect => {
371
349
  if (!try canMove(battle, player, state, options)) return;
372
- try Effects.screens(battle, player, state, options);
350
+ try Effects.reflect(battle, player, state, options);
373
351
  },
374
352
  .FocusEnergy => {
375
353
  if (!try canMove(battle, player, state, options)) return;
376
354
  try Effects.focusEnergy(battle, player, state, options);
377
355
  },
378
356
  .Bide => {
379
- if (!volatiles.Bide) return;
380
-
381
- assert(volatiles.attacks > 0);
382
- // if (options.calc.modify(player, .attacking)) |extend| {
383
- // if (!extend) volatiles.attacks = 0;
384
- // } else {
385
- volatiles.attacks -= 1;
386
- // }
387
- try options.chance.attacking(player, volatiles.attacks);
388
-
389
- if (volatiles.attacks != 0) return try options.log.activate(ident, .Bide);
390
-
391
- volatiles.Bide = false;
392
- try options.log.end(ident, .Bide);
393
-
394
- state.damage = volatiles.bide *% 2;
395
- volatiles.bide = 0;
396
-
397
- if (state.damage == 0) state.miss = true;
398
-
357
+ try Effects.bide.store(battle, player, state, options);
399
358
  // doturn
400
359
  const charging = false; // TODO
401
360
  const skip_pp = charging or state.move == .Struggle or
402
361
  (volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
403
362
  if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
404
363
  // usedmovetext
405
- try log.move(ident, state.move, foe_ident); // FIXME self? from?
406
- // TODO unleashenergy
364
+ try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
365
+ try Effects.bide.unleash(battle, player, state, options);
407
366
 
408
367
  if (state.immune()) {
409
368
  state.damage = 0;
@@ -522,7 +481,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
522
481
  try randomizeDamage(battle, player, state, options);
523
482
  try checkHit(battle, player, state, options);
524
483
  try effectChance(battle, player, state, options);
525
- try Effects.snore(battle, player, state, options);
484
+ if (!try Effects.snore(battle, player, state, options)) return;
526
485
  try applyDamage(battle, player, state, options);
527
486
  try reportOutcome(battle, player, state, options);
528
487
  if (!try afterMove(!KINGS, battle, player, state, options)) return;
@@ -582,19 +541,19 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
582
541
  try Effects.sandstorm(battle, player, state, options);
583
542
  },
584
543
  .Rollout => {
585
- // TODO checkcurl
544
+ try Effects.rollout.check(battle, player, state, options);
586
545
  // doturn
587
546
  const charging = false; // TODO
588
547
  const skip_pp = charging or state.move == .Struggle or
589
548
  (volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
590
549
  if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
591
550
  // usedmovetext
592
- try log.move(ident, state.move, foe_ident); // FIXME self? from?
551
+ try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
593
552
  try checkCriticalHit(battle, player, state, options);
594
553
  try calcDamage(battle, player, state, options);
595
554
  try adjustDamage(battle, player, state, options);
596
555
  try checkHit(battle, player, state, options);
597
- // TODO rolloutpower
556
+ try Effects.rollout.power(battle, player, state, options);
598
557
  try randomizeDamage(battle, player, state, options);
599
558
  try applyDamage(battle, player, state, options);
600
559
  try reportOutcome(battle, player, state, options);
@@ -615,12 +574,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
615
574
  .Swagger => {
616
575
  if (!try canMove(battle, player, state, options)) return;
617
576
  try checkHit(battle, player, state, options);
618
- // TODO switchturn
619
- // TODO attackup2
620
- // TODO switchturn
621
- // TODO failuretext
622
- // TODO switchturn
623
- // TODO switchturn
577
+ try Effects.boost(battle, player.foe(), state, options);
624
578
  try Effects.confusionChance(battle, player, state, options);
625
579
  },
626
580
  .FuryCutter => {
@@ -694,14 +648,12 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
694
648
  .Magnitude => {
695
649
  if (!try canMove(battle, player, state, options)) return;
696
650
  try checkCriticalHit(battle, player, state, options);
697
- // TODO getmagnitude
651
+ try Effects.magnitude(battle, player, state, options);
698
652
  try calcDamage(battle, player, state, options);
699
653
  try adjustDamage(battle, player, state, options);
700
654
  try randomizeDamage(battle, player, state, options);
701
655
  try checkHit(battle, player, state, options);
702
-
703
- if (battle.foe(player).active.volatiles.Underground) state.damage *|= 2;
704
-
656
+ try Effects.double.underground(battle, player, state, options);
705
657
  try applyDamage(battle, player, state, options);
706
658
  try reportOutcome(battle, player, state, options);
707
659
  _ = try afterMove(KINGS, battle, player, state, options);
@@ -755,9 +707,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
755
707
  try calcDamage(battle, player, state, options);
756
708
  try adjustDamage(battle, player, state, options);
757
709
  try randomizeDamage(battle, player, state, options);
758
-
759
- if (battle.foe(player).active.volatiles.Flying) state.damage *|= 2;
760
-
710
+ try Effects.double.flying(battle, player, state, options);
761
711
  try checkHit(battle, player, state, options);
762
712
  try effectChance(battle, player, state, options);
763
713
  try applyDamage(battle, player, state, options);
@@ -773,12 +723,6 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
773
723
  if (!try canMove(battle, player, state, options)) return;
774
724
  try Effects.sunnyDay(battle, player, state, options);
775
725
  },
776
- .MirrorCoat => {
777
- if (!try canMove(battle, player, state, options)) return;
778
- try Effects.mirrorCoat(battle, player, state, options);
779
- try applyDamage(battle, player, state, options);
780
- _ = try afterMove(KINGS, battle, player, state, options);
781
- },
782
726
  .PsychUp => {
783
727
  if (!try canMove(battle, player, state, options)) return;
784
728
  try Effects.psychUp(battle, player, state, options);