@pkmn/engine 0.1.0-dev.02b7f810

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 (52) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +332 -0
  3. package/build/pkg/addon.d.ts +7 -0
  4. package/build/pkg/addon.js +111 -0
  5. package/build/pkg/addon.js.map +1 -0
  6. package/build/pkg/data/ids.json +240 -0
  7. package/build/pkg/data/layout.json +86 -0
  8. package/build/pkg/data/protocol.json +173 -0
  9. package/build/pkg/data.d.ts +91 -0
  10. package/build/pkg/data.js +150 -0
  11. package/build/pkg/data.js.map +1 -0
  12. package/build/pkg/gen1.d.ts +109 -0
  13. package/build/pkg/gen1.js +668 -0
  14. package/build/pkg/gen1.js.map +1 -0
  15. package/build/pkg/index.d.ts +383 -0
  16. package/build/pkg/index.js +122 -0
  17. package/build/pkg/index.js.map +1 -0
  18. package/build/pkg/protocol.d.ts +71 -0
  19. package/build/pkg/protocol.js +452 -0
  20. package/build/pkg/protocol.js.map +1 -0
  21. package/build/test/display.js +382 -0
  22. package/build/test/display.js.map +1 -0
  23. package/build/tools/debug.js +133 -0
  24. package/build/tools/debug.js.map +1 -0
  25. package/build.zig +346 -0
  26. package/package.json +202 -0
  27. package/src/bin/install-pkmn-engine +391 -0
  28. package/src/bin/pkmn-debug +62 -0
  29. package/src/lib/binding/node.zig +229 -0
  30. package/src/lib/binding/wasm.zig +10 -0
  31. package/src/lib/common/data.zig +129 -0
  32. package/src/lib/common/debug.zig +64 -0
  33. package/src/lib/common/options.zig +40 -0
  34. package/src/lib/common/protocol.zig +1297 -0
  35. package/src/lib/common/rng.zig +234 -0
  36. package/src/lib/gen1/README.md +791 -0
  37. package/src/lib/gen1/data/moves.zig +1854 -0
  38. package/src/lib/gen1/data/species.zig +1105 -0
  39. package/src/lib/gen1/data/types.zig +131 -0
  40. package/src/lib/gen1/data.zig +620 -0
  41. package/src/lib/gen1/helpers.zig +234 -0
  42. package/src/lib/gen1/mechanics.zig +2819 -0
  43. package/src/lib/gen2/README.md +309 -0
  44. package/src/lib/gen2/data/items.zig +236 -0
  45. package/src/lib/gen2/data/moves.zig +2784 -0
  46. package/src/lib/gen2/data/species.zig +1798 -0
  47. package/src/lib/gen2/data/types.zig +123 -0
  48. package/src/lib/gen2/data.zig +425 -0
  49. package/src/lib/gen2/helpers.zig +225 -0
  50. package/src/lib/gen2/mechanics.zig +53 -0
  51. package/src/lib/pkmn.zig +54 -0
  52. package/src/test/display/pkmn.html.tmpl +368 -0
@@ -0,0 +1,234 @@
1
+ const std = @import("std");
2
+
3
+ const options = @import("./options.zig");
4
+
5
+ const assert = std.debug.assert;
6
+ const expectEqual = std.testing.expectEqual;
7
+
8
+ const showdown = options.showdown;
9
+
10
+ pub fn PRNG(comptime gen: comptime_int) type {
11
+ if (showdown) return PSRNG;
12
+
13
+ const Source = switch (gen) {
14
+ 1, 2 => Gen12,
15
+ 3, 4 => Gen34,
16
+ 5, 6 => Gen56,
17
+ else => unreachable,
18
+ };
19
+
20
+ return extern struct {
21
+ const Self = @This();
22
+
23
+ src: Source,
24
+
25
+ pub fn next(self: *Self) Output(gen) {
26
+ return self.src.next();
27
+ }
28
+ };
29
+ }
30
+
31
+ pub const PSRNG = extern struct {
32
+ src: Gen56,
33
+
34
+ const divisor = 0x100000000;
35
+
36
+ pub fn init(seed: u64) PSRNG {
37
+ return .{ .src = .{ .seed = seed } };
38
+ }
39
+
40
+ pub fn next(self: *PSRNG) u32 {
41
+ return self.src.next();
42
+ }
43
+
44
+ pub fn advance(self: *PSRNG, n: usize) void {
45
+ if (!options.advance) return;
46
+ for (0..n) |_| self.src.advance();
47
+ }
48
+
49
+ pub fn range(self: *PSRNG, comptime T: type, from: T, to: Bound(T)) T {
50
+ return @intCast(T, @as(u64, self.src.next()) * (to - from) / divisor + from);
51
+ }
52
+
53
+ pub fn chance(self: *PSRNG, comptime T: type, numerator: T, denominator: Bound(T)) bool {
54
+ assert(denominator > 0);
55
+ return self.range(T, 0, denominator) < numerator;
56
+ }
57
+
58
+ pub fn newSeed(self: *PSRNG) u64 {
59
+ return (@as(u64, self.range(u16, 0, 0x10000)) << 48) |
60
+ (@as(u64, self.range(u16, 0, 0x10000)) << 32) |
61
+ (@as(u64, self.range(u16, 0, 0x10000)) << 16) |
62
+ (@as(u64, self.range(u16, 0, 0x10000)));
63
+ }
64
+ };
65
+
66
+ test PSRNG {
67
+ var psrng = PSRNG{ .src = .{ .seed = 0x0001000200030004 } };
68
+ try expectEqual(@as(u8, 121), psrng.range(u8, 0, 256));
69
+ try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
70
+ }
71
+
72
+ // https://pkmn.cc/pokered/engine/battle/core.asm#L6644-L6693
73
+ // https://pkmn.cc/pokecrystal/engine/battle/core.asm#L6922-L6938
74
+ pub const Gen12 = extern struct {
75
+ seed: [10]u8,
76
+ index: u8 = 0,
77
+
78
+ comptime {
79
+ assert(@sizeOf(Gen12) == 11);
80
+ }
81
+
82
+ pub fn percent(p: u8) u8 {
83
+ return @intCast(u8, (@as(u16, p) * 0xFF) / 100);
84
+ }
85
+
86
+ pub fn next(self: *Gen12) u8 {
87
+ const val = 5 *% self.seed[self.index] +% 1;
88
+ self.seed[self.index] = val;
89
+ self.index = (self.index + 1) % 10;
90
+ return val;
91
+ }
92
+ };
93
+
94
+ test Gen12 {
95
+ const expected = [_]u8{ 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 31, 56, 81 };
96
+ var rng = Gen12{ .seed = .{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } };
97
+ for (expected) |e| {
98
+ try expectEqual(e, rng.next());
99
+ }
100
+
101
+ try expectEqual(@as(u8, 16), Gen12.percent(6) + 1);
102
+ try expectEqual(@as(u8, 16), Gen12.percent(7) - 1);
103
+ try expectEqual(@as(u8, 128), Gen12.percent(50) + 1);
104
+ }
105
+
106
+ // https://pkmn.cc/pokeemerald/src/random.c
107
+ // https://pkmn.cc/pokediamond/arm9/src/math_util.c#L624-L630
108
+ pub const Gen34 = extern struct {
109
+ seed: u32,
110
+
111
+ comptime {
112
+ assert(@sizeOf(Gen34) == 4);
113
+ }
114
+
115
+ pub fn next(self: *Gen34) u16 {
116
+ self.advance();
117
+ return @intCast(u16, self.seed >> 16);
118
+ }
119
+
120
+ pub fn advance(self: *Gen34) void {
121
+ self.seed = 0x41C64E6D *% self.seed +% 0x00006073;
122
+ }
123
+ };
124
+
125
+ // https://pkmn.cc/PokeFinder/Source/Tests/RNG/LCRNGTest.cpp
126
+ test Gen34 {
127
+ const data = [_][3]u32{
128
+ .{ 0x00000000, 5, 0x8E425287 }, .{ 0x00000000, 10, 0xEF2CF4B2 },
129
+ .{ 0x80000000, 5, 0x0E425287 }, .{ 0x80000000, 10, 0x6F2CF4B2 },
130
+ };
131
+ for (data) |d| {
132
+ var rng = Gen34{ .seed = d[0] };
133
+ for (0..d[1]) |_| _ = rng.next();
134
+ try expectEqual(d[2], rng.seed);
135
+ }
136
+ }
137
+
138
+ pub const Gen56 = extern struct {
139
+ seed: u64,
140
+
141
+ comptime {
142
+ assert(@sizeOf(Gen56) == 8);
143
+ }
144
+
145
+ pub fn next(self: *Gen56) u32 {
146
+ self.advance();
147
+ return @intCast(u32, self.seed >> 32);
148
+ }
149
+
150
+ pub fn advance(self: *Gen56) void {
151
+ self.seed = 0x5D588B656C078965 *% self.seed +% 0x0000000000269EC3;
152
+ }
153
+ };
154
+
155
+ // https://pkmn.cc/PokeFinder/Source/Tests/RNG/LCRNG64Test.cpp
156
+ test Gen56 {
157
+ const data = [_][3]u64{
158
+ .{ 0x0000000000000000, 5, 0xC83FB970153A9227 },
159
+ .{ 0x0000000000000000, 10, 0x67795501267F125A },
160
+ .{ 0x8000000000000000, 5, 0x483FB970153A9227 },
161
+ .{ 0x8000000000000000, 10, 0xE7795501267F125A },
162
+ };
163
+ for (data) |d| {
164
+ var rng = Gen56{ .seed = d[0] };
165
+ for (0..d[1]) |_| _ = rng.next();
166
+ try expectEqual(d[2], rng.seed);
167
+ }
168
+ }
169
+
170
+ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
171
+ const divisor = 0x100000000;
172
+
173
+ return extern struct {
174
+ const Self = @This();
175
+
176
+ rolls: [len]Output(gen),
177
+ index: usize = 0,
178
+
179
+ pub fn next(self: *Self) Output(gen) {
180
+ if (self.index >= self.rolls.len) @panic("Insufficient number of rolls provided");
181
+ const roll = self.rolls[self.index];
182
+ self.index += 1;
183
+ return roll;
184
+ }
185
+
186
+ pub fn advance(self: *Self, n: usize) void {
187
+ assert(showdown);
188
+ for (0..n) |_| _ = self.next();
189
+ }
190
+
191
+ pub fn range(self: *Self, comptime T: type, from: T, to: Bound(T)) T {
192
+ assert(showdown);
193
+ return @intCast(T, @as(u64, self.next()) * (to - from) / divisor + from);
194
+ }
195
+
196
+ pub fn chance(
197
+ self: *Self,
198
+ comptime T: type,
199
+ numerator: T,
200
+ denominator: Bound(T),
201
+ ) bool {
202
+ assert(showdown);
203
+ assert(denominator > 0);
204
+ return self.range(T, 0, denominator) < numerator;
205
+ }
206
+
207
+ pub fn exhausted(self: Self) bool {
208
+ return self.index == self.rolls.len;
209
+ }
210
+ };
211
+ }
212
+
213
+ test FixedRNG {
214
+ const Type = if (showdown) u32 else u8;
215
+ const expected = [_]Type{ 42, 255, 0 };
216
+ var rng = FixedRNG(1, expected.len){ .rolls = expected };
217
+ for (expected) |e| {
218
+ try expectEqual(e, rng.next());
219
+ }
220
+ }
221
+
222
+ fn Output(comptime gen: comptime_int) type {
223
+ if (showdown) return u32;
224
+ return switch (gen) {
225
+ 1, 2 => u8,
226
+ 3, 4 => u16,
227
+ 5, 6 => u32,
228
+ else => unreachable,
229
+ };
230
+ }
231
+
232
+ fn Bound(comptime T: type) type {
233
+ return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
234
+ }