@pkmn/engine 0.1.0-dev.028ab165

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 (62) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +343 -0
  3. package/build/pkg/addon.d.ts +7 -0
  4. package/build/pkg/addon.js +112 -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 +108 -0
  8. package/build/pkg/data/protocol.json +230 -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 +110 -0
  13. package/build/pkg/gen1.js +684 -0
  14. package/build/pkg/gen1.js.map +1 -0
  15. package/build/pkg/index.d.ts +386 -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 +73 -0
  19. package/build/pkg/protocol.js +473 -0
  20. package/build/pkg/protocol.js.map +1 -0
  21. package/build/test/display.js +400 -0
  22. package/build/test/display.js.map +1 -0
  23. package/build/tools/debug.js +135 -0
  24. package/build/tools/debug.js.map +1 -0
  25. package/build.zig +371 -0
  26. package/package.json +224 -0
  27. package/src/bin/install-pkmn-engine +396 -0
  28. package/src/bin/pkmn-debug +62 -0
  29. package/src/lib/binding/node.zig +134 -0
  30. package/src/lib/binding/wasm.zig +12 -0
  31. package/src/lib/common/battle.zig +17 -0
  32. package/src/lib/common/data.zig +117 -0
  33. package/src/lib/common/debug.zig +74 -0
  34. package/src/lib/common/js.zig +118 -0
  35. package/src/lib/common/optional.zig +67 -0
  36. package/src/lib/common/options.zig +49 -0
  37. package/src/lib/common/protocol.zig +1841 -0
  38. package/src/lib/common/rational.zig +353 -0
  39. package/src/lib/common/rng.zig +243 -0
  40. package/src/lib/common/util.zig +12 -0
  41. package/src/lib/gen1/README.md +894 -0
  42. package/src/lib/gen1/calc.zig +426 -0
  43. package/src/lib/gen1/chance.zig +1060 -0
  44. package/src/lib/gen1/data/moves.zig +1866 -0
  45. package/src/lib/gen1/data/species.zig +1105 -0
  46. package/src/lib/gen1/data/types.zig +131 -0
  47. package/src/lib/gen1/data.zig +634 -0
  48. package/src/lib/gen1/helpers.zig +779 -0
  49. package/src/lib/gen1/mechanics.zig +3128 -0
  50. package/src/lib/gen2/README.md +329 -0
  51. package/src/lib/gen2/calc.zig +143 -0
  52. package/src/lib/gen2/chance.zig +1314 -0
  53. package/src/lib/gen2/data/items.zig +230 -0
  54. package/src/lib/gen2/data/moves.zig +2878 -0
  55. package/src/lib/gen2/data/species.zig +1798 -0
  56. package/src/lib/gen2/data/types.zig +226 -0
  57. package/src/lib/gen2/data.zig +463 -0
  58. package/src/lib/gen2/generated.zig +808 -0
  59. package/src/lib/gen2/helpers.zig +219 -0
  60. package/src/lib/gen2/mechanics.zig +3551 -0
  61. package/src/lib/pkmn.zig +113 -0
  62. package/src/test/display/pkmn.html.tmpl +368 -0
@@ -0,0 +1,219 @@
1
+ const std = @import("std");
2
+
3
+ const common = @import("../common/data.zig");
4
+ const options = @import("../common/options.zig");
5
+ const protocol = @import("../common/protocol.zig");
6
+ const rng = @import("../common/rng.zig");
7
+
8
+ const gen1 = @import("../gen1/data.zig");
9
+
10
+ const data = @import("data.zig");
11
+
12
+ const assert = std.debug.assert;
13
+
14
+ const expectEqual = std.testing.expectEqual;
15
+
16
+ const Choice = common.Choice;
17
+
18
+ const showdown = options.showdown;
19
+
20
+ const PSRNG = rng.PSRNG;
21
+
22
+ const DVs = data.DVs;
23
+ const Item = data.Item;
24
+ const Move = data.Move;
25
+ const MoveSlot = data.MoveSlot;
26
+ const Species = data.Species;
27
+ const Stats = data.Stats;
28
+ const Status = data.Status;
29
+
30
+ pub const Options = struct {
31
+ cleric: bool = showdown,
32
+ };
33
+
34
+ pub const Battle = struct {
35
+ pub fn init(
36
+ seed: u64,
37
+ p1: []const Pokemon,
38
+ p2: []const Pokemon,
39
+ ) data.Battle(data.PRNG) {
40
+ var rand = PSRNG.init(seed);
41
+ return .{
42
+ .rng = prng(&rand),
43
+ .sides = .{ Side.init(p1), Side.init(p2) },
44
+ };
45
+ }
46
+
47
+ pub fn fixed(
48
+ comptime rolls: anytype,
49
+ p1: []const Pokemon,
50
+ p2: []const Pokemon,
51
+ ) data.Battle(rng.FixedRNG(2, rolls.len)) {
52
+ return .{
53
+ .rng = .{ .rolls = rolls },
54
+ .sides = .{ Side.init(p1), Side.init(p2) },
55
+ };
56
+ }
57
+
58
+ pub fn random(rand: *PSRNG, opt: Options) data.Battle(data.PRNG) {
59
+ return .{
60
+ .rng = prng(rand),
61
+ .turn = 0,
62
+ .sides = .{ Side.random(rand, opt), Side.random(rand, opt) },
63
+ };
64
+ }
65
+ };
66
+
67
+ pub fn prng(rand: *PSRNG) data.PRNG {
68
+ // FIXME: what is max range in gen2?
69
+ return .{
70
+ .src = .{
71
+ .seed = if (showdown)
72
+ rand.newSeed()
73
+ else
74
+ .{
75
+ rand.range(u8, 0, 256), rand.range(u8, 0, 256), rand.range(u8, 0, 256),
76
+ rand.range(u8, 0, 256), rand.range(u8, 0, 256), rand.range(u8, 0, 256),
77
+ rand.range(u8, 0, 256), rand.range(u8, 0, 256), rand.range(u8, 0, 256),
78
+ },
79
+ },
80
+ };
81
+ }
82
+
83
+ pub const Side = struct {
84
+ pub fn init(ps: []const Pokemon) data.Side {
85
+ assert(ps.len > 0 and ps.len <= 6);
86
+ var side = data.Side{};
87
+
88
+ for (0..ps.len) |i| {
89
+ side.pokemon[i] = Pokemon.init(ps[i]);
90
+ side.pokemon[i].position = @as(u4, @intCast(i)) + 1;
91
+ }
92
+ return side;
93
+ }
94
+
95
+ pub fn random(rand: *PSRNG, opt: Options) data.Side {
96
+ const n = if (rand.chance(u8, 1, 100)) rand.range(u4, 1, 5 + 1) else 6;
97
+ var side = data.Side{};
98
+
99
+ for (0..n) |i| {
100
+ side.pokemon[i] = Pokemon.random(rand, opt);
101
+ side.pokemon[i].position = @as(u4, @intCast(i)) + 1;
102
+ }
103
+
104
+ return side;
105
+ }
106
+ };
107
+
108
+ pub const EXP = 0xFFFF;
109
+
110
+ pub const Pokemon = struct {
111
+ species: Species,
112
+ moves: []const Move,
113
+ item: Item = .None,
114
+ hp: ?u16 = null,
115
+ status: u8 = 0,
116
+ level: u8 = 100,
117
+ dvs: gen1.DVs = .{},
118
+ stats: Stats(u16) = .{ .hp = EXP, .atk = EXP, .def = EXP, .spe = EXP, .spa = EXP, .spd = EXP },
119
+
120
+ pub fn init(p: Pokemon) data.Pokemon {
121
+ var pokemon = data.Pokemon{};
122
+ pokemon.species = p.species;
123
+ const species = Species.get(p.species);
124
+ inline for (@typeInfo(@TypeOf(pokemon.stats)).Struct.fields) |field| {
125
+ const hp = comptime std.mem.eql(u8, field.name, "hp");
126
+ const spc =
127
+ comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
128
+ @field(pokemon.stats, field.name) = Stats(u16).calc(
129
+ field.name,
130
+ @field(species.stats, field.name),
131
+ if (hp) p.dvs.hp() else if (spc) p.dvs.spc else @field(p.dvs, field.name),
132
+ @field(p.stats, field.name),
133
+ p.level,
134
+ );
135
+ }
136
+ assert(p.moves.len > 0 and p.moves.len <= 4);
137
+ for (p.moves, 0..) |m, j| {
138
+ pokemon.moves[j].id = m;
139
+ // NB: PP can be at most 61 legally (though can overflow to 63)
140
+ pokemon.moves[j].pp = @intCast(@min(Move.pp(m) / 5 * 8, 61));
141
+ }
142
+ pokemon.item = p.item;
143
+ if (p.hp) |hp| {
144
+ pokemon.hp = hp;
145
+ } else {
146
+ pokemon.hp = pokemon.stats.hp;
147
+ }
148
+ pokemon.status = p.status;
149
+ pokemon.types = species.types;
150
+ pokemon.level = p.level;
151
+ pokemon.dvs = DVs.from(p.species, p.dvs);
152
+ return pokemon;
153
+ }
154
+
155
+ pub fn random(rand: *PSRNG, opt: Options) data.Pokemon {
156
+ const s: Species = @enumFromInt(rand.range(u8, 1, Species.size + 1));
157
+ const species = Species.get(s);
158
+ const lvl = if (rand.chance(u8, 1, 20)) rand.range(u8, 1, 99 + 1) else 100;
159
+ // Pokémon Showdown does not support most items without in-battle held item effects
160
+ const max_item = @intFromEnum(if (showdown) Item.FlowerMail else Item.TM50);
161
+ const item = if (rand.chance(u8, 1, 10)) 0 else rand.range(u8, 1, max_item + 1);
162
+
163
+ var stats: Stats(u16) = .{};
164
+ const dvs = gen1.DVs.random(rand);
165
+ inline for (@typeInfo(@TypeOf(stats)).Struct.fields) |field| {
166
+ const hp = std.mem.eql(u8, field.name, "hp");
167
+ const spc = std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
168
+ @field(stats, field.name) = Stats(u16).calc(
169
+ field.name,
170
+ @field(species.stats, field.name),
171
+ if (hp) dvs.hp() else if (spc) dvs.spc else @field(dvs, field.name),
172
+ if (rand.chance(u8, 1, 20)) rand.range(u8, 0, 255 + 1) else 255,
173
+ lvl,
174
+ );
175
+ }
176
+
177
+ var ms = [_]MoveSlot{.{}} ** 4;
178
+ const n = if (rand.chance(u8, 1, 100)) rand.range(u4, 1, 3 + 1) else 4;
179
+ for (0..n) |i| {
180
+ var m: Move = .None;
181
+ sample: while (true) {
182
+ m = @enumFromInt(rand.range(u8, 1, 164 + 1));
183
+ for (0..i) |j| if (ms[j].id == m) continue :sample;
184
+ break;
185
+ }
186
+ const pp_ups: u8 =
187
+ if (!opt.cleric and rand.chance(u8, 1, 10)) rand.range(u2, 0, 2 + 1) else 3;
188
+ // NB: PP can be at most 61 legally (though can overflow to 63)
189
+ const max_pp: u8 = @intCast(Move.pp(m) + pp_ups * @min(Move.pp(m) / 5, 7));
190
+ ms[i] = .{
191
+ .id = m,
192
+ .pp = if (opt.cleric) max_pp else rand.range(u8, 0, max_pp + 1),
193
+ };
194
+ }
195
+ return .{
196
+ .species = s,
197
+ .types = species.types,
198
+ .dvs = DVs.from(s, dvs),
199
+ .level = lvl,
200
+ .stats = stats,
201
+ .hp = if (opt.cleric) stats.hp else rand.range(u16, 0, stats.hp + 1),
202
+ .status = if (!opt.cleric and rand.chance(u8, 1, 6 + 1))
203
+ 0 | (@as(u8, 1) << rand.range(u3, 1, 6 + 1))
204
+ else
205
+ 0,
206
+ .happiness = if (rand.chance(u8, 1, 10 + 1)) rand.range(u8, 0, 255) else 255,
207
+ .item = item,
208
+ .moves = ms,
209
+ };
210
+ }
211
+ };
212
+
213
+ pub fn move(slot: u4) Choice {
214
+ return .{ .type = .Move, .data = slot };
215
+ }
216
+
217
+ pub fn swtch(slot: u4) Choice {
218
+ return .{ .type = .Switch, .data = slot };
219
+ }