@pkmn/engine 0.1.0-dev.f918c3bd → 0.1.0-dev.fb6653d6

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 +44 -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 +97 -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 +23 -9
  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 +13 -17
  21. package/build/pkg/gen1.js +8 -12
  22. package/build/pkg/gen1.js.map +1 -1
  23. package/build/pkg/index.d.ts +40 -91
  24. package/build/pkg/index.js +6 -63
  25. package/build/pkg/index.js.map +1 -1
  26. package/build/pkg/protocol.d.ts +20 -1
  27. package/build/pkg/protocol.js +109 -107
  28. package/build/pkg/protocol.js.map +1 -1
  29. package/build/tools/debug.js +36 -69
  30. package/build/tools/debug.js.map +1 -1
  31. package/build/tools/display/debug.jsx +141 -0
  32. package/build/tools/display/debug.jsx.map +1 -0
  33. package/build/tools/display/index.js +142 -0
  34. package/build/tools/display/index.js.map +1 -0
  35. package/build/tools/display/ui.jsx +349 -0
  36. package/build/tools/display/ui.jsx.map +1 -0
  37. package/build/tools/display/util.js +18 -0
  38. package/build/tools/display/util.js.map +1 -0
  39. package/build.zig +303 -101
  40. package/package.json +61 -132
  41. package/src/bin/install-pkmn-engine +30 -20
  42. package/src/bin/pkmn-debug +1 -1
  43. package/src/lib/{binding → bindings}/node.zig +8 -21
  44. package/src/lib/bindings/wasm.zig +58 -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 +21 -10
  50. package/src/lib/common/options.zig +6 -0
  51. package/src/lib/common/protocol.zig +421 -393
  52. package/src/lib/common/rational.zig +131 -35
  53. package/src/lib/common/rng.zig +16 -9
  54. package/src/lib/common/util.zig +50 -1
  55. package/src/lib/gen1/calc.zig +687 -160
  56. package/src/lib/gen1/chance.zig +434 -307
  57. package/src/lib/gen1/data/moves.zig +26 -14
  58. package/src/lib/gen1/data/species.zig +4 -6
  59. package/src/lib/gen1/data/types.zig +7 -8
  60. package/src/lib/gen1/data.zig +44 -47
  61. package/src/lib/gen1/helpers.zig +91 -562
  62. package/src/lib/gen1/mechanics.zig +641 -557
  63. package/src/lib/gen2/calc.zig +153 -0
  64. package/src/lib/gen2/chance.zig +902 -0
  65. package/src/lib/gen2/data/items.zig +13 -21
  66. package/src/lib/gen2/data/moves.zig +67 -47
  67. package/src/lib/gen2/data/species.zig +2 -4
  68. package/src/lib/gen2/data/types.zig +134 -32
  69. package/src/lib/gen2/data.zig +56 -54
  70. package/src/lib/gen2/generated.zig +801 -0
  71. package/src/lib/gen2/helpers.zig +46 -25
  72. package/src/lib/gen2/mechanics.zig +2778 -362
  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 +96 -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 -328
  83. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,8 +1,7 @@
1
- //! Code generated by `tools/generate` - manual edits will be overwritten
2
-
3
- const std = @import("std");
1
+ //! Code generated by `tools/generate` - manual edits will be overwritten.
4
2
 
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;
@@ -14,15 +13,15 @@ const I = Effectiveness.Immune;
14
13
 
15
14
  /// Representation of a Generation II type in Pokémon.
16
15
  pub const Type = enum(u8) {
16
+ Ground,
17
+ Rock,
18
+ Steel,
17
19
  Normal,
18
20
  Fighting,
19
21
  Flying,
20
22
  Poison,
21
- Ground,
22
- Rock,
23
23
  Bug,
24
24
  Ghost,
25
- Steel,
26
25
  @"???",
27
26
  Fire,
28
27
  Water,
@@ -34,36 +33,36 @@ pub const Type = enum(u8) {
34
33
  Dark,
35
34
 
36
35
  const CHART: [18][18]Effectiveness = .{
37
- [_]Effectiveness{ N, N, N, N, N, R, N, I, R, N, N, N, N, N, N, N, N, N }, // Normal
38
- [_]Effectiveness{ S, N, R, R, N, S, R, I, S, N, N, N, N, N, R, S, N, S }, // Fighting
39
- [_]Effectiveness{ N, S, N, N, N, R, S, N, R, N, N, N, S, R, N, N, N, N }, // Flying
40
- [_]Effectiveness{ N, N, N, R, R, R, N, R, I, N, N, N, S, N, N, N, N, N }, // Poison
41
- [_]Effectiveness{ N, N, I, S, N, S, R, N, S, N, S, N, R, S, N, N, N, N }, // Ground
42
- [_]Effectiveness{ N, R, S, N, R, N, S, N, R, N, S, N, N, N, N, S, N, N }, // Rock
43
- [_]Effectiveness{ N, R, R, R, N, N, N, R, R, N, R, N, S, N, S, N, N, S }, // Bug
44
- [_]Effectiveness{ I, N, N, N, N, N, N, S, R, N, N, N, N, N, S, N, N, R }, // Ghost
45
- [_]Effectiveness{ N, N, N, N, N, S, N, N, R, N, R, R, N, R, N, S, N, N }, // Steel
36
+ [_]Effectiveness{ N, S, S, N, N, I, S, R, N, N, S, N, R, S, N, N, N, N }, // Ground
37
+ [_]Effectiveness{ R, N, R, N, R, S, N, S, N, N, S, N, N, N, N, S, N, N }, // Rock
38
+ [_]Effectiveness{ N, S, R, N, N, N, N, N, N, N, R, R, N, R, N, S, N, N }, // Steel
39
+ [_]Effectiveness{ N, R, R, N, N, N, N, N, I, N, N, N, N, N, N, N, N, N }, // Normal
40
+ [_]Effectiveness{ N, S, S, S, N, R, R, R, I, N, N, N, N, N, R, S, N, S }, // Fighting
41
+ [_]Effectiveness{ N, R, R, N, S, N, N, S, N, N, N, N, S, R, N, N, N, N }, // Flying
42
+ [_]Effectiveness{ R, R, I, N, N, N, R, N, R, N, N, N, S, N, N, N, N, N }, // Poison
43
+ [_]Effectiveness{ N, N, R, N, R, R, R, N, R, N, R, N, S, N, S, N, N, S }, // Bug
44
+ [_]Effectiveness{ N, N, R, I, N, N, N, N, S, N, N, N, N, N, S, N, N, R }, // Ghost
46
45
  [_]Effectiveness{ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N }, // ???
47
- [_]Effectiveness{ N, N, N, N, N, R, S, N, S, N, R, R, S, N, N, S, R, N }, // Fire
48
- [_]Effectiveness{ N, N, N, N, S, S, N, N, N, N, S, R, R, N, N, N, R, N }, // Water
49
- [_]Effectiveness{ N, N, R, R, S, S, R, N, R, N, R, S, R, N, N, N, R, N }, // Grass
50
- [_]Effectiveness{ N, N, S, N, I, N, N, N, N, N, N, S, R, R, N, N, R, N }, // Electric
51
- [_]Effectiveness{ N, S, N, S, N, N, N, N, R, N, N, N, N, N, R, N, N, I }, // Psychic
52
- [_]Effectiveness{ N, N, S, N, S, N, N, N, R, N, R, R, S, N, N, R, S, N }, // Ice
53
- [_]Effectiveness{ N, N, N, N, N, N, N, N, R, N, N, N, N, N, N, N, S, N }, // Dragon
54
- [_]Effectiveness{ N, R, N, N, N, N, N, S, R, N, N, N, N, N, S, N, N, R }, // Dark
46
+ [_]Effectiveness{ N, R, S, N, N, N, N, S, N, N, R, R, S, N, N, S, R, N }, // Fire
47
+ [_]Effectiveness{ S, S, N, N, N, N, N, N, N, N, S, R, R, N, N, N, R, N }, // Water
48
+ [_]Effectiveness{ S, S, R, N, N, R, R, R, N, N, R, S, R, N, N, N, R, N }, // Grass
49
+ [_]Effectiveness{ I, N, N, N, N, S, N, N, N, N, N, S, R, R, N, N, R, N }, // Electric
50
+ [_]Effectiveness{ N, N, R, N, S, N, S, N, N, N, N, N, N, N, R, N, N, I }, // Psychic
51
+ [_]Effectiveness{ S, N, R, N, N, S, N, N, N, N, R, R, S, N, N, R, S, N }, // Ice
52
+ [_]Effectiveness{ N, N, R, N, N, N, N, N, N, N, N, N, N, N, N, N, S, N }, // Dragon
53
+ [_]Effectiveness{ N, N, R, N, R, N, N, N, S, N, N, N, N, N, S, N, N, R }, // Dark
55
54
  };
56
55
 
57
56
  const PRECEDENCE = [_]u8{
57
+ 9, // Ground
58
+ 13, // Rock
59
+ 17, // Steel
58
60
  1, // Normal
59
61
  7, // Fighting
60
62
  10, // Flying
61
63
  8, // Poison
62
- 9, // Ground
63
- 13, // Rock
64
64
  12, // Bug
65
65
  14, // Ghost
66
- 17, // Steel
67
66
  0, // ???
68
67
  2, // Fire
69
68
  3, // Water
@@ -75,29 +74,126 @@ pub const Type = enum(u8) {
75
74
  16, // Dark
76
75
  };
77
76
 
77
+ const INDEXES = [_]u8{
78
+ 4, // Ground
79
+ 5, // Rock
80
+ 9, // Steel
81
+ 0, // Normal
82
+ 1, // Fighting
83
+ 2, // Flying
84
+ 3, // Poison
85
+ 7, // Bug
86
+ 8, // Ghost
87
+ 19, // ???
88
+ 20, // Fire
89
+ 21, // Water
90
+ 22, // Grass
91
+ 23, // Electric
92
+ 24, // Psychic
93
+ 25, // Ice
94
+ 26, // Dragon
95
+ 27, // Dark
96
+ };
97
+
98
+ const CONVERSION_2 = [_]Type{
99
+ .Normal,
100
+ .Fighting,
101
+ .Flying,
102
+ .Poison,
103
+ .Ground,
104
+ .Rock,
105
+ .@"???", // placeholder
106
+ .Bug,
107
+ .Ghost,
108
+ .Steel,
109
+ };
110
+
111
+ const HIDDEN_POWER = [_]Type{
112
+ .Fighting,
113
+ .Flying,
114
+ .Poison,
115
+ .Ground,
116
+ .Rock,
117
+ .Bug,
118
+ .Ghost,
119
+ .Steel,
120
+ .Fire,
121
+ .Water,
122
+ .Grass,
123
+ .Electric,
124
+ .Psychic,
125
+ .Ice,
126
+ .Dragon,
127
+ .Dark,
128
+ };
129
+
130
+ /// Order of Pokémon Showdown's types.
131
+ pub const SHOWDOWN = [_]Type{
132
+ .Fire,
133
+ .Ice,
134
+ .Steel,
135
+ .Electric,
136
+ .Ghost,
137
+ .Grass,
138
+ .Dark,
139
+ .Bug,
140
+ .Dragon,
141
+ .Fighting,
142
+ .Flying,
143
+ .Ground,
144
+ .Normal,
145
+ .Poison,
146
+ .Psychic,
147
+ .Rock,
148
+ .Water,
149
+ .@"???",
150
+ };
151
+
78
152
  comptime {
79
153
  assert(@bitSizeOf(Type) == 8);
80
154
  assert(@sizeOf(@TypeOf(CHART)) == 324);
81
155
  assert(@sizeOf(@TypeOf(PRECEDENCE)) == 18);
156
+ assert(@sizeOf(@TypeOf(INDEXES)) == 18);
157
+ assert(@sizeOf(@TypeOf(CONVERSION_2)) == 10);
158
+ assert(@sizeOf(@TypeOf(HIDDEN_POWER)) == 16);
159
+ assert(@sizeOf(@TypeOf(SHOWDOWN)) == 18);
82
160
  }
83
161
 
84
162
  /// The number of types in this generation.
85
163
  pub const size = 18;
86
164
 
87
165
  /// Whether or not this type is considered to be special as opposed to physical.
88
- pub inline fn special(self: Type) bool {
166
+ pub fn special(self: Type) bool {
89
167
  return @intFromEnum(self) >= @intFromEnum(Type.Fire);
90
168
  }
91
169
 
92
170
  /// The `Effectiveness` of type `t2` vs. type `t1`.
93
- pub inline fn effectiveness(t1: Type, t2: Type) Effectiveness {
171
+ pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
94
172
  return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
95
173
  }
96
174
 
97
- /// The precedence order of type type.
98
- pub inline fn precedence(self: Type) u8 {
175
+ /// The precedence order of Type `type`.
176
+ pub fn precedence(self: Type) u8 {
99
177
  return PRECEDENCE[@intFromEnum(self)];
100
178
  }
179
+
180
+ /// The internal index of this Type used by Present.
181
+ pub fn present(self: Type) u8 {
182
+ return INDEXES[@intFromEnum(self)];
183
+ }
184
+
185
+ /// The Type corresponding to a random roll of `num` for Conversion 2.
186
+ pub fn conversion2(num: u8) Type {
187
+ assert(num != 6);
188
+ assert(num < 10 or num >= 20);
189
+ assert(num <= 27);
190
+ return if (num < 10) CONVERSION_2[num] else @enumFromInt(num - 10);
191
+ }
192
+
193
+ /// The Type corresponding to a Hidden Power `index`.
194
+ pub fn hiddenPower(index: u8) Type {
195
+ return HIDDEN_POWER[index];
196
+ }
101
197
  };
102
198
 
103
199
  /// Representation of a Pokémon's typing.
@@ -112,12 +208,18 @@ pub const Types = extern struct {
112
208
  }
113
209
 
114
210
  /// Whether this typing is immune to type `t`.
115
- pub inline fn immune(self: Types, t: Type) bool {
211
+ pub fn immune(self: Types, t: Type) bool {
116
212
  return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
117
213
  }
118
214
 
119
215
  /// Whether this typing includes type `t`.
120
- pub inline fn includes(self: Types, t: Type) bool {
216
+ pub fn includes(self: Types, t: Type) bool {
121
217
  return self.type1 == t or self.type2 == t;
122
218
  }
219
+
220
+ /// Whether this typing is immune to damage from Sandstorm.
221
+ pub fn sandstormImmune(self: Types) bool {
222
+ return @intFromEnum(self.type1) <= @intFromEnum(Type.Steel) or
223
+ @intFromEnum(self.type2) <= @intFromEnum(Type.Steel);
224
+ }
123
225
  };
@@ -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,12 +41,14 @@ 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
 
51
48
  pub const PRNG = rng.PRNG(2);
52
49
 
53
50
  pub fn Battle(comptime RNG: anytype) type {
51
+ const padding = if (!showdown) 3 else 5;
54
52
  return extern struct {
55
53
  const Self = @This();
56
54
 
@@ -59,20 +57,19 @@ pub fn Battle(comptime RNG: anytype) type {
59
57
  turn: u16 = 0,
60
58
  field: Field = .{},
61
59
 
62
- _1: u8 = 0,
63
- _2: if (!showdown) u16 else u32 = 0,
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
 
@@ -106,13 +103,11 @@ pub const Side = extern struct {
106
103
  pokemon: [6]Pokemon = [_]Pokemon{.{}} ** 6,
107
104
  active: ActivePokemon align(8) = .{},
108
105
  conditions: Conditions = .{},
109
- _1: u32 = 0,
110
- _2: u16 = 0,
111
- // NB: wCurPlayerMove / wCurEnemyMove (?)
112
- _3: u8 = 0,
113
106
  // NB: wLastPlayerCounterMove / wLastEnemyCounterMove (wLastPlayerMove / wLastEnemyMove)
114
107
  last_used_move: Move = .None,
115
108
 
109
+ _: [7]u8 = .{0} ** 7,
110
+
116
111
  const Conditions = packed struct(u32) {
117
112
  Spikes: bool = false,
118
113
  Safeguard: bool = false,
@@ -135,27 +130,27 @@ pub const Side = extern struct {
135
130
  assert(@sizeOf(Side) == 248);
136
131
  }
137
132
 
138
- pub inline fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
139
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
133
+ pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
134
+ assert(isPointerTo(self, Side));
140
135
  assert(slot > 0 and slot <= 6);
141
136
  const id = self.pokemon[slot - 1].position;
142
137
  assert(id > 0 and id <= 6);
143
138
  return &self.pokemon[id - 1];
144
139
  }
145
140
 
146
- pub inline fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
147
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
141
+ pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
142
+ assert(isPointerTo(self, Side));
148
143
  return self.get(1);
149
144
  }
150
145
 
151
- pub inline fn lastMove(self: anytype, encore: bool) Move {
146
+ pub fn lastMove(self: anytype, encore: bool) Move {
152
147
  assert(self.last_used_move != .None or !self.active.volatiles.dirty);
153
148
  if (encore) return self.last_used_move;
154
149
  return if (self.active.volatiles.dirty) .None else self.last_used_move;
155
150
  }
156
151
 
157
152
  // TODO
158
- // pub inline fn useMove(self: anytype) void {
153
+ // pub fn useMove(self: anytype) void {
159
154
  // assert(side.last_selected_move != .None);
160
155
  // self.last_used_move = side.last_selected_move;
161
156
  // self.active.volatiles.dirty = false;
@@ -177,8 +172,8 @@ pub const ActivePokemon = extern struct {
177
172
  assert(@sizeOf(ActivePokemon) == 44);
178
173
  }
179
174
 
180
- pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
181
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
175
+ pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
176
+ assert(isPointerTo(self, Pokemon));
182
177
  assert(mslot > 0 and mslot <= 4);
183
178
  assert(self.moves[mslot - 1].id != .None);
184
179
  return &self.moves[mslot - 1];
@@ -202,8 +197,8 @@ pub const Pokemon = extern struct {
202
197
  assert(@sizeOf(Pokemon) == 32);
203
198
  }
204
199
 
205
- pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
206
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
200
+ pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
201
+ assert(isPointerTo(self, Pokemon));
207
202
  assert(mslot > 0 and mslot <= 4);
208
203
  assert(self.moves[mslot - 1].id != .None);
209
204
  return &self.moves[mslot - 1];
@@ -227,7 +222,7 @@ pub const DVs = packed struct(u16) {
227
222
  return .{ .gender = g, .pow = p, .type = t };
228
223
  }
229
224
 
230
- pub inline fn power(dvs: DVs) u8 {
225
+ pub fn power(dvs: DVs) u8 {
231
226
  return @as(u8, dvs.pow) + 30;
232
227
  }
233
228
 
@@ -241,9 +236,8 @@ pub const DVs = packed struct(u16) {
241
236
  };
242
237
  const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
243
238
  ((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
244
- var t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2) + 1;
245
- if (t >= @intFromEnum(Type.@"???")) t = t + 1;
246
- return .{ .gender = g, .pow = p, .type = @enumFromInt(t) };
239
+ const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
240
+ return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
247
241
  }
248
242
  };
249
243
 
@@ -282,6 +276,9 @@ pub const MoveSlot = extern struct {
282
276
 
283
277
  pub const Status = gen1.Status;
284
278
 
279
+ /// TODO
280
+ pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
281
+
285
282
  pub const Volatiles = packed struct(u128) {
286
283
  Bide: bool = false,
287
284
  Thrashing: bool = false,
@@ -314,18 +311,23 @@ 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
- _: u19 = 0,
323
+ minimized: bool = false,
324
+ _: u10 = 0,
325
+ // TODO: is this needed for unmodified stats?
326
+ transform: u4 = 0,
325
327
 
326
- bind: u4 = 0,
327
328
  bide: u16 = 0,
328
- disabled: Disabled = .{},
329
+ bind: Bind = .{},
330
+ disable: Disable = .{},
329
331
  rage: u8 = 0,
330
332
  substitute: u8 = 0,
331
333
  toxic: u8 = 0,
@@ -337,7 +339,12 @@ pub const Volatiles = packed struct(u128) {
337
339
  protect: u4 = 0,
338
340
  attacks: u4 = 0, // bide/thrashing/rollout turns
339
341
 
340
- const Disabled = packed struct(u8) {
342
+ const Bind = packed struct(u8) {
343
+ duration: u4 = 0,
344
+ reason: u4 = 0,
345
+ };
346
+
347
+ const Disable = packed struct(u8) {
341
348
  move: u4 = 0,
342
349
  duration: u4 = 0,
343
350
  };
@@ -404,15 +411,10 @@ test Item {
404
411
  try expectEqual(Type.Normal, Item.boost(.PolkadotBow).?);
405
412
  try expectEqual(Type.Dark, Item.boost(.BlackGlasses).?);
406
413
 
407
- try expect(!Item.mail(.UpGrade));
408
- try expect(Item.mail(.FlowerMail));
409
- try expect(Item.mail(.MirageMail));
410
- try expect(!Item.mail(.TownMap));
411
-
412
- try expect(!Item.berry(.LightBall));
413
- try expect(Item.berry(.PSNCureBerry));
414
- try expect(Item.berry(.GoldBerry));
415
- try expect(!Item.berry(.MasterBall));
414
+ try expect(!Item.isMail(.UpGrade));
415
+ try expect(Item.isMail(.FlowerMail));
416
+ try expect(Item.isMail(.MirageMail));
417
+ try expect(!Item.isMail(.TownMap));
416
418
  }
417
419
 
418
420
  pub const Move = moves.Move;