@pkmn/engine 0.1.0-dev.d56bdadd → 0.1.0-dev.d952b7c9
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/LICENSE +1 -3
- package/README.md +46 -19
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +43 -0
- package/build/pkg/addon/browser.js.map +1 -0
- package/build/pkg/addon/node.d.ts +3 -0
- package/build/pkg/addon/node.js +96 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon.d.ts +2 -0
- package/build/pkg/addon.js +35 -58
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +27 -5
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +1 -1
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +24 -10
- package/build/pkg/index.js +15 -10
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +20 -1
- package/build/pkg/protocol.js +109 -107
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +36 -68
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +128 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +132 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +349 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +18 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +206 -81
- package/package.json +51 -30
- package/src/bin/install-pkmn-engine +29 -19
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/debug.zig +11 -6
- package/src/lib/common/js.zig +4 -2
- package/src/lib/common/optional.zig +14 -10
- package/src/lib/common/options.zig +4 -0
- package/src/lib/common/protocol.zig +389 -407
- package/src/lib/common/rational.zig +121 -27
- package/src/lib/common/rng.zig +7 -7
- package/src/lib/common/util.zig +50 -1
- package/src/lib/gen1/calc.zig +657 -133
- package/src/lib/gen1/chance.zig +376 -267
- package/src/lib/gen1/data/species.zig +1 -1
- package/src/lib/gen1/data.zig +17 -16
- package/src/lib/gen1/helpers.zig +95 -538
- package/src/lib/gen1/mechanics.zig +492 -389
- package/src/lib/gen2/calc.zig +34 -16
- package/src/lib/gen2/chance.zig +84 -496
- package/src/lib/gen2/data.zig +8 -7
- package/src/lib/gen2/generated.zig +4 -6
- package/src/lib/gen2/helpers.zig +41 -13
- package/src/lib/gen2/mechanics.zig +448 -377
- package/src/lib/{binding/node.zig → node.zig} +9 -12
- package/src/lib/pkmn.zig +32 -15
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +351 -0
- package/build/test/display.js +0 -400
- package/build/test/display.js.map +0 -1
- package/src/lib/gen1/README.md +0 -894
- package/src/lib/gen2/README.md +0 -329
- package/src/test/display/pkmn.html.tmpl +0 -368
package/src/lib/gen2/data.zig
CHANGED
|
@@ -45,6 +45,7 @@ const Player = data.Player;
|
|
|
45
45
|
const Result = data.Result;
|
|
46
46
|
|
|
47
47
|
const PointerType = util.PointerType;
|
|
48
|
+
const isPointerTo = util.isPointerTo;
|
|
48
49
|
|
|
49
50
|
const showdown = pkmn.options.showdown;
|
|
50
51
|
|
|
@@ -63,12 +64,12 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
63
64
|
_: [padding]u8 = .{0} ** padding,
|
|
64
65
|
|
|
65
66
|
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
66
|
-
assert(
|
|
67
|
+
assert(isPointerTo(self, Self));
|
|
67
68
|
return &self.sides[@intFromEnum(player)];
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
71
|
-
assert(
|
|
72
|
+
assert(isPointerTo(self, Self));
|
|
72
73
|
return &self.sides[@intFromEnum(player.foe())];
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -134,7 +135,7 @@ pub const Side = extern struct {
|
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
137
|
-
assert(
|
|
138
|
+
assert(isPointerTo(self, Side));
|
|
138
139
|
assert(slot > 0 and slot <= 6);
|
|
139
140
|
const id = self.pokemon[slot - 1].position;
|
|
140
141
|
assert(id > 0 and id <= 6);
|
|
@@ -142,7 +143,7 @@ pub const Side = extern struct {
|
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
145
|
-
assert(
|
|
146
|
+
assert(isPointerTo(self, Side));
|
|
146
147
|
return self.get(1);
|
|
147
148
|
}
|
|
148
149
|
|
|
@@ -176,7 +177,7 @@ pub const ActivePokemon = extern struct {
|
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
179
|
-
assert(
|
|
180
|
+
assert(isPointerTo(self, Pokemon));
|
|
180
181
|
assert(mslot > 0 and mslot <= 4);
|
|
181
182
|
assert(self.moves[mslot - 1].id != .None);
|
|
182
183
|
return &self.moves[mslot - 1];
|
|
@@ -201,7 +202,7 @@ pub const Pokemon = extern struct {
|
|
|
201
202
|
}
|
|
202
203
|
|
|
203
204
|
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
204
|
-
assert(
|
|
205
|
+
assert(isPointerTo(self, Pokemon));
|
|
205
206
|
assert(mslot > 0 and mslot <= 4);
|
|
206
207
|
assert(self.moves[mslot - 1].id != .None);
|
|
207
208
|
return &self.moves[mslot - 1];
|
|
@@ -239,7 +240,7 @@ pub const DVs = packed struct(u16) {
|
|
|
239
240
|
};
|
|
240
241
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
241
242
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
242
|
-
|
|
243
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
244
|
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
244
245
|
}
|
|
245
246
|
};
|
|
@@ -7,8 +7,6 @@ const common = @import("../common/data.zig");
|
|
|
7
7
|
const data = @import("data.zig");
|
|
8
8
|
const mechanics = @import("mechanics.zig");
|
|
9
9
|
|
|
10
|
-
const assert = std.debug.assert;
|
|
11
|
-
|
|
12
10
|
const Player = common.Player;
|
|
13
11
|
const Result = common.Result;
|
|
14
12
|
|
|
@@ -42,7 +40,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
42
40
|
var log = options.log;
|
|
43
41
|
|
|
44
42
|
var side = battle.side(player);
|
|
45
|
-
|
|
43
|
+
const volatiles = &side.active.volatiles;
|
|
46
44
|
|
|
47
45
|
const ident = battle.active(player);
|
|
48
46
|
const foe_ident = battle.active(player.foe());
|
|
@@ -175,7 +173,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
175
173
|
if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
|
|
176
174
|
// TODO rampage
|
|
177
175
|
// usedmovetext
|
|
178
|
-
try log.move(ident, state.move, foe_ident); // FIXME self? from?
|
|
176
|
+
try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
|
|
179
177
|
try checkHit(battle, player, state, options);
|
|
180
178
|
try checkCriticalHit(battle, player, state, options);
|
|
181
179
|
try calcDamage(battle, player, state, options);
|
|
@@ -368,7 +366,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
368
366
|
(volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
|
|
369
367
|
if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
|
|
370
368
|
// usedmovetext
|
|
371
|
-
try log.move(ident, state.move, foe_ident); // FIXME self? from?
|
|
369
|
+
try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
|
|
372
370
|
try Effects.bide.unleash(battle, player, state, options);
|
|
373
371
|
|
|
374
372
|
if (state.immune()) {
|
|
@@ -555,7 +553,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
555
553
|
(volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
|
|
556
554
|
if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
|
|
557
555
|
// usedmovetext
|
|
558
|
-
try log.move(ident, state.move, foe_ident); // FIXME self? from?
|
|
556
|
+
try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
|
|
559
557
|
try checkCriticalHit(battle, player, state, options);
|
|
560
558
|
try calcDamage(battle, player, state, options);
|
|
561
559
|
try adjustDamage(battle, player, state, options);
|
package/src/lib/gen2/helpers.zig
CHANGED
|
@@ -2,7 +2,6 @@ const std = @import("std");
|
|
|
2
2
|
|
|
3
3
|
const common = @import("../common/data.zig");
|
|
4
4
|
const options = @import("../common/options.zig");
|
|
5
|
-
const protocol = @import("../common/protocol.zig");
|
|
6
5
|
const rng = @import("../common/rng.zig");
|
|
7
6
|
|
|
8
7
|
const gen1 = @import("../gen1/data.zig");
|
|
@@ -11,8 +10,6 @@ const data = @import("data.zig");
|
|
|
11
10
|
|
|
12
11
|
const assert = std.debug.assert;
|
|
13
12
|
|
|
14
|
-
const expectEqual = std.testing.expectEqual;
|
|
15
|
-
|
|
16
13
|
const Choice = common.Choice;
|
|
17
14
|
|
|
18
15
|
const showdown = options.showdown;
|
|
@@ -25,7 +22,8 @@ const Move = data.Move;
|
|
|
25
22
|
const MoveSlot = data.MoveSlot;
|
|
26
23
|
const Species = data.Species;
|
|
27
24
|
const Stats = data.Stats;
|
|
28
|
-
|
|
25
|
+
|
|
26
|
+
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
29
27
|
|
|
30
28
|
pub const Options = struct {
|
|
31
29
|
cleric: bool = showdown,
|
|
@@ -65,17 +63,47 @@ pub const Battle = struct {
|
|
|
65
63
|
};
|
|
66
64
|
|
|
67
65
|
pub fn prng(rand: *PSRNG) data.PRNG {
|
|
68
|
-
// FIXME: what is max range in gen2?
|
|
69
66
|
return .{
|
|
70
67
|
.src = .{
|
|
71
68
|
.seed = if (showdown)
|
|
72
69
|
rand.newSeed()
|
|
73
|
-
else
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
else seed: {
|
|
71
|
+
// GLITCH: The initial RNG seed in Gen II link battles is heavily constrained
|
|
72
|
+
// https://www.smogon.com/forums/threads/rng-in-rby-link-battles.3746779
|
|
73
|
+
var seed = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
74
|
+
|
|
75
|
+
// Bytes in seed can only range from 0-252, not 0-255
|
|
76
|
+
const max: u8 = 253;
|
|
77
|
+
// Instructions take multiples of 4 cycles to execute
|
|
78
|
+
var timer: u16 = 4 * rand.range(u16, 0, 16384);
|
|
79
|
+
var add: u8 = rand.range(u8, 0, 256);
|
|
80
|
+
var sub: u8 = rand.range(u8, 0, 256);
|
|
81
|
+
var carry: u8 = 0;
|
|
82
|
+
var div: u8 = 0;
|
|
83
|
+
|
|
84
|
+
var i: u8 = 0;
|
|
85
|
+
while (i < seed.len) {
|
|
86
|
+
div = @intCast(timer >> 8);
|
|
87
|
+
// This is effectively @addWithOverflow but with three operands
|
|
88
|
+
const result = @as(u16, add) + @as(u16, div) + @as(u16, carry);
|
|
89
|
+
add = @intCast(result & 255);
|
|
90
|
+
carry = @intFromBool(result > 255);
|
|
91
|
+
timer +%= 44;
|
|
92
|
+
div = @intCast(timer >> 8);
|
|
93
|
+
sub -%= div +% carry;
|
|
94
|
+
|
|
95
|
+
if (sub < max) {
|
|
96
|
+
seed[i] = sub;
|
|
97
|
+
i += 1;
|
|
98
|
+
timer +%= 152;
|
|
99
|
+
carry = 1;
|
|
100
|
+
} else {
|
|
101
|
+
timer +%= 132;
|
|
102
|
+
carry = 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
break :seed seed;
|
|
106
|
+
},
|
|
79
107
|
},
|
|
80
108
|
};
|
|
81
109
|
}
|
|
@@ -121,7 +149,7 @@ pub const Pokemon = struct {
|
|
|
121
149
|
var pokemon = data.Pokemon{};
|
|
122
150
|
pokemon.species = p.species;
|
|
123
151
|
const species = Species.get(p.species);
|
|
124
|
-
inline for (@typeInfo(@TypeOf(pokemon.stats))
|
|
152
|
+
inline for (@field(@typeInfo(@TypeOf(pokemon.stats)), @tagName(Struct)).fields) |field| {
|
|
125
153
|
const hp = comptime std.mem.eql(u8, field.name, "hp");
|
|
126
154
|
const spc =
|
|
127
155
|
comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
|
|
@@ -162,7 +190,7 @@ pub const Pokemon = struct {
|
|
|
162
190
|
|
|
163
191
|
var stats: Stats(u16) = .{};
|
|
164
192
|
const dvs = gen1.DVs.random(rand);
|
|
165
|
-
inline for (@typeInfo(@TypeOf(stats))
|
|
193
|
+
inline for (@field(@typeInfo(@TypeOf(stats)), @tagName(Struct)).fields) |field| {
|
|
166
194
|
const hp = std.mem.eql(u8, field.name, "hp");
|
|
167
195
|
const spc = std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
|
|
168
196
|
@field(stats, field.name) = Stats(u16).calc(
|