@pkmn/engine 0.1.0-dev.8b83af6b → 0.1.0-dev.90d6c14c
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.
- package/README.md +39 -36
- package/build/pkg/addon.js +3 -2
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/layout.json +24 -2
- package/build/pkg/gen1.js +13 -16
- package/build/pkg/gen1.js.map +1 -1
- package/build.zig +29 -13
- package/package.json +23 -14
- package/src/bin/install-pkmn-engine +9 -4
- package/src/lib/binding/node.zig +39 -131
- package/src/lib/binding/wasm.zig +2 -0
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/debug.zig +20 -11
- package/src/lib/common/js.zig +118 -0
- package/src/lib/common/optional.zig +60 -0
- package/src/lib/common/options.zig +9 -0
- package/src/lib/common/protocol.zig +45 -0
- package/src/lib/common/rational.zig +353 -0
- package/src/lib/common/rng.zig +5 -5
- package/src/lib/common/util.zig +12 -0
- package/src/lib/gen1/README.md +133 -135
- package/src/lib/gen1/calc.zig +427 -0
- package/src/lib/gen1/chance.zig +1044 -0
- package/src/lib/gen1/data.zig +35 -19
- package/src/lib/gen1/helpers.zig +428 -10
- package/src/lib/gen1/mechanics.zig +710 -414
- package/src/lib/gen2/README.md +12 -13
- package/src/lib/gen2/data.zig +22 -12
- package/src/lib/gen2/helpers.zig +3 -5
- package/src/lib/gen2/mechanics.zig +5 -4
- package/src/lib/pkmn.zig +61 -2
package/src/lib/gen1/data.zig
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
const builtin = @import("builtin");
|
|
3
3
|
|
|
4
|
+
const pkmn = @import("../pkmn.zig");
|
|
5
|
+
|
|
4
6
|
const data = @import("../common/data.zig");
|
|
5
|
-
const options = @import("../common/options.zig");
|
|
6
7
|
const protocol = @import("../common/protocol.zig");
|
|
7
8
|
const rng = @import("../common/rng.zig");
|
|
9
|
+
const util = @import("../common/util.zig");
|
|
8
10
|
|
|
9
11
|
const moves = @import("data/moves.zig");
|
|
10
12
|
const species = @import("data/species.zig");
|
|
11
13
|
const types = @import("data/types.zig");
|
|
12
14
|
|
|
15
|
+
const calc = @import("calc.zig");
|
|
16
|
+
const chance = @import("chance.zig");
|
|
13
17
|
const mechanics = @import("mechanics.zig");
|
|
14
18
|
|
|
15
19
|
const assert = std.debug.assert;
|
|
@@ -34,12 +38,17 @@ pub const LOGS_SIZE = if (builtin.mode == .ReleaseSmall)
|
|
|
34
38
|
else
|
|
35
39
|
std.math.ceilPowerOfTwo(usize, MAX_LOGS) catch unreachable;
|
|
36
40
|
|
|
41
|
+
/// Null object pattern implementation of pkmn.battle.Options for Generation I.
|
|
42
|
+
pub const NULL = pkmn.battle.options(protocol.NULL, chance.NULL, calc.NULL);
|
|
43
|
+
|
|
37
44
|
const Choice = data.Choice;
|
|
38
45
|
const ID = data.ID;
|
|
39
46
|
const Player = data.Player;
|
|
40
47
|
const Result = data.Result;
|
|
41
48
|
|
|
42
|
-
const
|
|
49
|
+
const PointerType = util.PointerType;
|
|
50
|
+
|
|
51
|
+
const showdown = pkmn.options.showdown;
|
|
43
52
|
|
|
44
53
|
/// The pseudo random number generator used by Generation I.
|
|
45
54
|
pub const PRNG = rng.PRNG(1);
|
|
@@ -61,24 +70,27 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
61
70
|
rng: RNG,
|
|
62
71
|
|
|
63
72
|
/// Returns the `Side` for the given `player`.
|
|
64
|
-
pub inline fn side(self:
|
|
73
|
+
pub inline fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
74
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
65
75
|
return &self.sides[@intFromEnum(player)];
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
/// Returns the `Side` of the opponent for the given `player`
|
|
69
|
-
pub inline fn foe(self:
|
|
79
|
+
pub inline fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
80
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
70
81
|
return &self.sides[@intFromEnum(player.foe())];
|
|
71
82
|
}
|
|
72
83
|
|
|
73
84
|
/// Returns an identifier for the active Pokémon of `player`.
|
|
74
|
-
pub inline fn active(self: *Self, player: Player) ID {
|
|
85
|
+
pub inline fn active(self: *const Self, player: Player) ID {
|
|
75
86
|
return player.ident(@intCast(self.side(player).order[0]));
|
|
76
87
|
}
|
|
77
88
|
|
|
78
89
|
/// Returns the result of applying Player 1's choice `c1` and Player 2's choice `c2` to the
|
|
79
|
-
/// battle, optionally writing protocol message logs to `log` if `options.log`
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
/// battle, optionally writing protocol message logs to `options.log` if `pkmn.options.log`
|
|
91
|
+
/// is enabled.
|
|
92
|
+
pub fn update(self: *Self, c1: Choice, c2: Choice, options: anytype) !Result {
|
|
93
|
+
return mechanics.update(self, c1, c2, options);
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
/// Fills in at most `out.len` possible choices for the `player` given the previous `result`
|
|
@@ -90,7 +102,7 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
90
102
|
/// interacts with Disable, in which case there are no possible choices for the player to
|
|
91
103
|
/// make (i.e. on the cartridge a soft-lock occurs).
|
|
92
104
|
///
|
|
93
|
-
/// This function will always return
|
|
105
|
+
/// This function will always return choices > 0 if `pkmn.options.showdown` is true.
|
|
94
106
|
pub fn choices(self: *Self, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
95
107
|
return mechanics.choices(self, player, request, out);
|
|
96
108
|
}
|
|
@@ -120,7 +132,8 @@ pub const Side = extern struct {
|
|
|
120
132
|
}
|
|
121
133
|
|
|
122
134
|
/// Returns the stored `Pokemon` corresponding to the one-indexed party `slot`.
|
|
123
|
-
pub inline fn get(self:
|
|
135
|
+
pub inline fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
136
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
124
137
|
assert(slot > 0 and slot <= 6);
|
|
125
138
|
const id = self.order[slot - 1];
|
|
126
139
|
assert(id > 0 and id <= 6);
|
|
@@ -128,7 +141,8 @@ pub const Side = extern struct {
|
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
/// Returns the stored `Pokemon` corresponding to the `active` Pokémon (slot 1).
|
|
131
|
-
pub inline fn stored(self:
|
|
144
|
+
pub inline fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
145
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
132
146
|
return self.get(1);
|
|
133
147
|
}
|
|
134
148
|
};
|
|
@@ -153,7 +167,8 @@ pub const ActivePokemon = extern struct {
|
|
|
153
167
|
}
|
|
154
168
|
|
|
155
169
|
/// Returns the active Pokémon's current move slot located at the one-indexed `mslot`.
|
|
156
|
-
pub inline fn move(self:
|
|
170
|
+
pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
171
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == ActivePokemon);
|
|
157
172
|
assert(mslot > 0 and mslot <= 4);
|
|
158
173
|
assert(self.moves[mslot - 1].id != .None);
|
|
159
174
|
return &self.moves[mslot - 1];
|
|
@@ -182,7 +197,8 @@ pub const Pokemon = extern struct {
|
|
|
182
197
|
}
|
|
183
198
|
|
|
184
199
|
/// Returns the Pokémon's original move slot located at the one-indexed `mslot`.
|
|
185
|
-
pub inline fn move(self:
|
|
200
|
+
pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
201
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
186
202
|
assert(mslot > 0 and mslot <= 4);
|
|
187
203
|
assert(self.moves[mslot - 1].id != .None);
|
|
188
204
|
return &self.moves[mslot - 1];
|
|
@@ -204,16 +220,16 @@ pub const MoveSlot = extern struct {
|
|
|
204
220
|
/// Details required to detect desyncs based on the move last selected/executed by players.
|
|
205
221
|
pub const MoveDetails = packed struct {
|
|
206
222
|
/// The move slot index of the last move selected in the battle menu by Player 1
|
|
207
|
-
p1_index: if (showdown) u8 else
|
|
223
|
+
p1_index: if (showdown) u8 else u4 = 0,
|
|
208
224
|
/// Whether the last move executed by Player 1 was counterable.
|
|
209
|
-
p1_counterable: if (showdown) u8 else
|
|
225
|
+
p1_counterable: if (showdown) u8 else u4 = 0,
|
|
210
226
|
/// The move slot index of the last move selected in the battle menu by Player 2
|
|
211
|
-
p2_index: if (showdown) u8 else
|
|
227
|
+
p2_index: if (showdown) u8 else u4 = 0,
|
|
212
228
|
/// Whether the last move executed by Player 2 was counterable.
|
|
213
|
-
p2_counterable: if (showdown) u8 else
|
|
229
|
+
p2_counterable: if (showdown) u8 else u4 = 0,
|
|
214
230
|
|
|
215
231
|
comptime {
|
|
216
|
-
assert(@sizeOf(MoveDetails) == if (showdown) 4 else
|
|
232
|
+
assert(@sizeOf(MoveDetails) == if (showdown) 4 else 2);
|
|
217
233
|
}
|
|
218
234
|
};
|
|
219
235
|
|
|
@@ -414,7 +430,7 @@ pub fn Stats(comptime T: type) type {
|
|
|
414
430
|
pub fn calc(comptime stat: []const u8, base: T, dv: u4, exp: u16, level: u8) T {
|
|
415
431
|
assert(level > 0 and level <= 100);
|
|
416
432
|
const float: f32 = @floatFromInt(exp);
|
|
417
|
-
const evs = @min(255, @as(u16, @intFromFloat(@ceil(@sqrt(float)))));
|
|
433
|
+
const evs: u16 = @min(255, @as(u16, @intFromFloat(@ceil(@sqrt(float)))));
|
|
418
434
|
const core: u32 = (2 *% (@as(u32, base) +% dv)) +% (evs / 4);
|
|
419
435
|
const factor: u32 = if (std.mem.eql(u8, stat, "hp")) level + 10 else 5;
|
|
420
436
|
return @intCast(core *% @as(u32, level) / 100 +% factor);
|