@pkmn/engine 0.1.0-dev.b3f3e3a6 → 0.1.0-dev.bb8e286d
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 +3 -3
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +1 -0
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +2 -1
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.js +1 -1
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js.map +1 -1
- package/build.zig +19 -8
- package/package.json +11 -10
- package/src/bin/install-pkmn-engine +1 -1
- package/src/lib/binding/node.zig +6 -10
- package/src/lib/common/protocol.zig +53 -52
- package/src/lib/common/rational.zig +7 -3
- package/src/lib/gen1/calc.zig +5 -5
- package/src/lib/gen1/mechanics.zig +16 -26
- package/src/lib/gen2/data.zig +1 -1
- package/src/lib/gen2/generated.zig +1 -3
- package/src/lib/gen2/mechanics.zig +20 -24
package/src/lib/binding/node.zig
CHANGED
|
@@ -19,7 +19,7 @@ export fn napi_register_module_v1(env: c.napi_env, exports: c.napi_value) c.napi
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
pub fn register(env: c.napi_env) c.napi_value {
|
|
22
|
-
|
|
22
|
+
const object = js.Object.init(env);
|
|
23
23
|
const properties = [_]c.napi_property_descriptor{
|
|
24
24
|
js.Property.init("options", .{ .value = options(env) }),
|
|
25
25
|
js.Property.init("bindings", .{ .value = bindings(env) }),
|
|
@@ -29,7 +29,7 @@ pub fn register(env: c.napi_env) c.napi_value {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
fn options(env: c.napi_env) c.napi_value {
|
|
32
|
-
|
|
32
|
+
const object = js.Object.init(env);
|
|
33
33
|
const properties = [_]c.napi_property_descriptor{
|
|
34
34
|
js.Property.init("showdown", .{ .value = js.Boolean.init(env, pkmn.options.showdown) }),
|
|
35
35
|
js.Property.init("log", .{ .value = js.Boolean.init(env, pkmn.options.log) }),
|
|
@@ -41,7 +41,7 @@ fn options(env: c.napi_env) c.napi_value {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
fn bindings(env: c.napi_env) c.napi_value {
|
|
44
|
-
|
|
44
|
+
const array = js.Array.init(env, .{ .length = 1 });
|
|
45
45
|
js.Array.set(env, array, 0, bind(env, pkmn.gen1));
|
|
46
46
|
return array;
|
|
47
47
|
}
|
|
@@ -49,7 +49,7 @@ fn bindings(env: c.napi_env) c.napi_value {
|
|
|
49
49
|
fn bind(env: c.napi_env, gen: anytype) c.napi_value {
|
|
50
50
|
const choices_size: u32 = @intCast(gen.CHOICES_SIZE);
|
|
51
51
|
const logs_size: u32 = @intCast(gen.LOGS_SIZE);
|
|
52
|
-
|
|
52
|
+
const object = js.Object.init(env);
|
|
53
53
|
const properties = [_]c.napi_property_descriptor{
|
|
54
54
|
js.Property.init("CHOICES_SIZE", .{ .value = js.Number.init(env, choices_size) }),
|
|
55
55
|
js.Property.init("LOGS_SIZE", .{ .value = js.Number.init(env, logs_size) }),
|
|
@@ -72,7 +72,6 @@ fn update(gen: anytype) c.napi_callback {
|
|
|
72
72
|
var len: usize = 0;
|
|
73
73
|
assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
|
|
74
74
|
assert(len == @sizeOf(gen.Battle(gen.PRNG)));
|
|
75
|
-
assert(data != null);
|
|
76
75
|
|
|
77
76
|
var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
|
|
78
77
|
const c1: pkmn.Choice = @bitCast(js.Number.get(env, argv[1], u8));
|
|
@@ -85,9 +84,8 @@ fn update(gen: anytype) c.napi_callback {
|
|
|
85
84
|
else => result: {
|
|
86
85
|
assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
|
|
87
86
|
assert(len == gen.LOGS_SIZE);
|
|
88
|
-
assert(data != null);
|
|
89
87
|
|
|
90
|
-
|
|
88
|
+
const buf = @as([*]u8, @ptrCast(data.?))[0..gen.LOGS_SIZE];
|
|
91
89
|
var stream: pkmn.protocol.ByteStream = .{ .buffer = buf };
|
|
92
90
|
// TODO: extract out
|
|
93
91
|
var opts = pkmn.battle.options(
|
|
@@ -116,7 +114,6 @@ fn choices(gen: anytype) c.napi_callback {
|
|
|
116
114
|
var len: usize = 0;
|
|
117
115
|
assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
|
|
118
116
|
assert(len == @sizeOf(gen.Battle(gen.PRNG)));
|
|
119
|
-
assert(data != null);
|
|
120
117
|
|
|
121
118
|
var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
|
|
122
119
|
const player: pkmn.Player = @enumFromInt(js.Number.get(env, argv[1], u8));
|
|
@@ -124,9 +121,8 @@ fn choices(gen: anytype) c.napi_callback {
|
|
|
124
121
|
|
|
125
122
|
assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
|
|
126
123
|
assert(len == gen.CHOICES_SIZE);
|
|
127
|
-
assert(data != null);
|
|
128
124
|
|
|
129
|
-
|
|
125
|
+
const out = @as([*]pkmn.Choice, @ptrCast(data.?))[0..gen.CHOICES_SIZE];
|
|
130
126
|
const n = battle.choices(player, request, out);
|
|
131
127
|
return js.Number.init(env, @as(u8, @bitCast(n)));
|
|
132
128
|
}
|
|
@@ -14,6 +14,8 @@ const enabled = options.log;
|
|
|
14
14
|
const Player = data.Player;
|
|
15
15
|
const ID = data.ID;
|
|
16
16
|
|
|
17
|
+
const endian = builtin.cpu.arch.endian();
|
|
18
|
+
|
|
17
19
|
pub const ArgType = enum(u8) {
|
|
18
20
|
None,
|
|
19
21
|
|
|
@@ -359,8 +361,8 @@ pub fn Log(comptime Writer: type) type {
|
|
|
359
361
|
} else {
|
|
360
362
|
try self.writer.writeAll(&.{ @intFromEnum(args[1].species), args[1].level });
|
|
361
363
|
}
|
|
362
|
-
try self.writer.
|
|
363
|
-
try self.writer.
|
|
364
|
+
try self.writer.writeInt(u16, args[1].hp, endian);
|
|
365
|
+
try self.writer.writeInt(u16, args[1].stats.hp, endian);
|
|
364
366
|
try self.writer.writeAll(&.{args[1].status});
|
|
365
367
|
}
|
|
366
368
|
|
|
@@ -391,7 +393,7 @@ pub fn Log(comptime Writer: type) type {
|
|
|
391
393
|
if (!enabled) return;
|
|
392
394
|
|
|
393
395
|
try self.writer.writeByte(@intFromEnum(ArgType.Turn));
|
|
394
|
-
try self.writer.
|
|
396
|
+
try self.writer.writeInt(u16, args[0], endian);
|
|
395
397
|
try self.writer.writeByte(@intFromEnum(ArgType.None));
|
|
396
398
|
}
|
|
397
399
|
|
|
@@ -423,8 +425,8 @@ pub fn Log(comptime Writer: type) type {
|
|
|
423
425
|
@intFromEnum(ArgType.Damage),
|
|
424
426
|
@as(u8, @bitCast(args[0])),
|
|
425
427
|
});
|
|
426
|
-
try self.writer.
|
|
427
|
-
try self.writer.
|
|
428
|
+
try self.writer.writeInt(u16, args[1].hp, endian);
|
|
429
|
+
try self.writer.writeInt(u16, args[1].stats.hp, endian);
|
|
428
430
|
try self.writer.writeAll(&.{ args[1].status, @intFromEnum(@as(Damage, args[2])) });
|
|
429
431
|
if (args.len == 4) try self.writer.writeByte(@as(u8, @bitCast(args[3])));
|
|
430
432
|
}
|
|
@@ -436,8 +438,8 @@ pub fn Log(comptime Writer: type) type {
|
|
|
436
438
|
|
|
437
439
|
assert(args[2] != .Drain or args.len == 4);
|
|
438
440
|
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(args[0])) });
|
|
439
|
-
try self.writer.
|
|
440
|
-
try self.writer.
|
|
441
|
+
try self.writer.writeInt(u16, args[1].hp, endian);
|
|
442
|
+
try self.writer.writeInt(u16, args[1].stats.hp, endian);
|
|
441
443
|
try self.writer.writeAll(&.{ args[1].status, @intFromEnum(@as(Heal, args[2])) });
|
|
442
444
|
if (args.len == 4) try self.writer.writeByte(@as(u8, @bitCast(args[3])));
|
|
443
445
|
}
|
|
@@ -706,8 +708,8 @@ pub fn Log(comptime Writer: type) type {
|
|
|
706
708
|
if (!enabled) return;
|
|
707
709
|
|
|
708
710
|
try self.writer.writeAll(&.{ @intFromEnum(ArgType.SetHP), @as(u8, @bitCast(args[0])) });
|
|
709
|
-
try self.writer.
|
|
710
|
-
try self.writer.
|
|
711
|
+
try self.writer.writeInt(u16, args[1].hp, endian);
|
|
712
|
+
try self.writer.writeInt(u16, args[1].stats.hp, endian);
|
|
711
713
|
try self.writer.writeAll(&.{args[1].status});
|
|
712
714
|
try self.writer.writeByte(@intFromEnum(@as(SetHP, args[2])));
|
|
713
715
|
}
|
|
@@ -831,10 +833,10 @@ pub const ByteStream = struct {
|
|
|
831
833
|
try self.stream.writeByte(byte);
|
|
832
834
|
}
|
|
833
835
|
|
|
834
|
-
pub fn
|
|
836
|
+
pub fn writeInt(self: Writer, comptime T: type, v: T, end: std.builtin.Endian) Error!void {
|
|
835
837
|
// TODO: rework this to write directly to the buffer?
|
|
836
|
-
var bytes: [(@typeInfo(T).Int.bits
|
|
837
|
-
std.mem.
|
|
838
|
+
var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined;
|
|
839
|
+
std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(v)), &bytes, v, end);
|
|
838
840
|
return self.writeAll(&bytes);
|
|
839
841
|
}
|
|
840
842
|
};
|
|
@@ -943,19 +945,19 @@ pub fn format(
|
|
|
943
945
|
if (a[i] == N(gen.Gender.Unknown)) {
|
|
944
946
|
i += 1;
|
|
945
947
|
} else {
|
|
946
|
-
|
|
948
|
+
const gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
|
|
947
949
|
printc(", {s}", .{gender}, a, b, &i, 1, color);
|
|
948
950
|
}
|
|
949
951
|
}
|
|
950
952
|
printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
|
|
951
953
|
switch (endian) {
|
|
952
|
-
.
|
|
954
|
+
.big => {
|
|
953
955
|
var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
|
|
954
956
|
printc(" {d}", .{hp}, a, b, &i, 2, color);
|
|
955
957
|
hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
|
|
956
958
|
printc("/{d}", .{hp}, a, b, &i, 2, color);
|
|
957
959
|
},
|
|
958
|
-
.
|
|
960
|
+
.little => {
|
|
959
961
|
var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
|
|
960
962
|
printc(" {d}", .{hp}, a, b, &i, 2, color);
|
|
961
963
|
hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
|
|
@@ -986,8 +988,8 @@ pub fn format(
|
|
|
986
988
|
},
|
|
987
989
|
.Turn => {
|
|
988
990
|
const turn = switch (endian) {
|
|
989
|
-
.
|
|
990
|
-
.
|
|
991
|
+
.big => @as(u16, a[i]) << 8 | @as(u16, a[i + 1]),
|
|
992
|
+
.little => @as(u16, a[i + 1]) << 8 | @as(u16, a[i]),
|
|
991
993
|
};
|
|
992
994
|
printc(" {d}", .{turn}, a, b, &i, 2, color);
|
|
993
995
|
},
|
|
@@ -998,13 +1000,13 @@ pub fn format(
|
|
|
998
1000
|
var id = ID.from(@intCast(a[i]));
|
|
999
1001
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
1000
1002
|
switch (endian) {
|
|
1001
|
-
.
|
|
1003
|
+
.big => {
|
|
1002
1004
|
var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
|
|
1003
1005
|
printc(" {d}", .{hp}, a, b, &i, 2, color);
|
|
1004
1006
|
hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
|
|
1005
1007
|
printc("/{d}", .{hp}, a, b, &i, 2, color);
|
|
1006
1008
|
},
|
|
1007
|
-
.
|
|
1009
|
+
.little => {
|
|
1008
1010
|
var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
|
|
1009
1011
|
printc(" {d}", .{hp}, a, b, &i, 2, color);
|
|
1010
1012
|
hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
|
|
@@ -1083,7 +1085,8 @@ pub fn format(
|
|
|
1083
1085
|
const reason = a[i];
|
|
1084
1086
|
printc(" {s}", .{@tagName(@as(Start, @enumFromInt(reason)))}, a, b, &i, 1, color);
|
|
1085
1087
|
if (@as(Start, @enumFromInt(reason)) == .TypeChange) {
|
|
1086
|
-
|
|
1088
|
+
// FIXME
|
|
1089
|
+
const types = @as(gen1.Types, @bitCast(a[i]));
|
|
1087
1090
|
const args = .{
|
|
1088
1091
|
formatter(gen, .Type, @intFromEnum(types.type1)),
|
|
1089
1092
|
formatter(gen, .Type, @intFromEnum(types.type2)),
|
|
@@ -1125,13 +1128,13 @@ pub fn format(
|
|
|
1125
1128
|
const id = ID.from(@intCast(a[i]));
|
|
1126
1129
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
1127
1130
|
switch (endian) {
|
|
1128
|
-
.
|
|
1131
|
+
.big => {
|
|
1129
1132
|
var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
|
|
1130
1133
|
printc(" {d}", .{hp}, a, b, &i, 2, color);
|
|
1131
1134
|
hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
|
|
1132
1135
|
printc("/{d}", .{hp}, a, b, &i, 2, color);
|
|
1133
1136
|
},
|
|
1134
|
-
.
|
|
1137
|
+
.little => {
|
|
1135
1138
|
var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
|
|
1136
1139
|
printc(" {d}", .{hp}, a, b, &i, 2, color);
|
|
1137
1140
|
hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
|
|
@@ -1238,8 +1241,6 @@ fn expectEqualBytes(expected: []const u8, actual: []const u8, offset: usize) !vo
|
|
|
1238
1241
|
}
|
|
1239
1242
|
}
|
|
1240
1243
|
|
|
1241
|
-
const endian = builtin.target.cpu.arch.endian();
|
|
1242
|
-
|
|
1243
1244
|
fn N(e: anytype) u8 {
|
|
1244
1245
|
return @intFromEnum(e);
|
|
1245
1246
|
}
|
|
@@ -1349,8 +1350,8 @@ test "|switch|" {
|
|
|
1349
1350
|
try log.switched(.{ p2.ident(3), &snorlax });
|
|
1350
1351
|
const par = 0b1000000;
|
|
1351
1352
|
var expected: []const u8 = switch (endian) {
|
|
1352
|
-
.
|
|
1353
|
-
.
|
|
1353
|
+
.big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
|
|
1354
|
+
.little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
|
|
1354
1355
|
};
|
|
1355
1356
|
try expectLog1(expected, buf[0..9]);
|
|
1356
1357
|
stream.reset();
|
|
@@ -1360,8 +1361,8 @@ test "|switch|" {
|
|
|
1360
1361
|
snorlax.status = 0;
|
|
1361
1362
|
try log.switched(.{ p2.ident(3), &snorlax });
|
|
1362
1363
|
expected = switch (endian) {
|
|
1363
|
-
.
|
|
1364
|
-
.
|
|
1364
|
+
.big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
|
|
1365
|
+
.little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
|
|
1365
1366
|
};
|
|
1366
1367
|
try expectLog1(expected, buf[0..9]);
|
|
1367
1368
|
stream.reset();
|
|
@@ -1369,8 +1370,8 @@ test "|switch|" {
|
|
|
1369
1370
|
snorlax.hp = 400;
|
|
1370
1371
|
try log.switched(.{ p2.ident(3), &snorlax });
|
|
1371
1372
|
expected = switch (endian) {
|
|
1372
|
-
.
|
|
1373
|
-
.
|
|
1373
|
+
.big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
|
|
1374
|
+
.little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
|
|
1374
1375
|
};
|
|
1375
1376
|
try expectLog1(expected, buf[0..9]);
|
|
1376
1377
|
stream.reset();
|
|
@@ -1388,8 +1389,8 @@ test "|switch|" {
|
|
|
1388
1389
|
N(gen2.Gender.Female),
|
|
1389
1390
|
91,
|
|
1390
1391
|
} ++ switch (endian) {
|
|
1391
|
-
.
|
|
1392
|
-
.
|
|
1392
|
+
.big => .{ 0, 200, 1, 144, par },
|
|
1393
|
+
.little => .{ 200, 0, 144, 1, par },
|
|
1393
1394
|
});
|
|
1394
1395
|
try expectLog2(expected, buf[0..10]);
|
|
1395
1396
|
stream.reset();
|
|
@@ -1417,9 +1418,9 @@ test "|faint|" {
|
|
|
1417
1418
|
|
|
1418
1419
|
test "|turn|" {
|
|
1419
1420
|
try log.turn(.{42});
|
|
1420
|
-
|
|
1421
|
-
.
|
|
1422
|
-
.
|
|
1421
|
+
const expected = switch (endian) {
|
|
1422
|
+
.big => &.{ N(ArgType.Turn), 0, 42, N(ArgType.None) },
|
|
1423
|
+
.little => &.{ N(ArgType.Turn), 42, 0, N(ArgType.None) },
|
|
1423
1424
|
};
|
|
1424
1425
|
try expectLog1(expected, buf[0..4]);
|
|
1425
1426
|
stream.reset();
|
|
@@ -1443,8 +1444,8 @@ test "|-damage|" {
|
|
|
1443
1444
|
chansey.status = gen1.Status.slp(1);
|
|
1444
1445
|
try log.damage(.{ p2.ident(2), &chansey, .None });
|
|
1445
1446
|
var expected: []const u8 = switch (endian) {
|
|
1446
|
-
.
|
|
1447
|
-
.
|
|
1447
|
+
.big => &.{ N(ArgType.Damage), 0b1010, 2, 100, 2, 191, 1, N(Damage.None) },
|
|
1448
|
+
.little => &.{ N(ArgType.Damage), 0b1010, 100, 2, 191, 2, 1, N(Damage.None) },
|
|
1448
1449
|
};
|
|
1449
1450
|
try expectLog1(expected, buf[0..8]);
|
|
1450
1451
|
stream.reset();
|
|
@@ -1454,8 +1455,8 @@ test "|-damage|" {
|
|
|
1454
1455
|
chansey.status = 0;
|
|
1455
1456
|
try log.damage(.{ p2.ident(2), &chansey, .Confusion });
|
|
1456
1457
|
expected = switch (endian) {
|
|
1457
|
-
.
|
|
1458
|
-
.
|
|
1458
|
+
.big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0, N(Damage.Confusion) },
|
|
1459
|
+
.little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0, N(Damage.Confusion) },
|
|
1459
1460
|
};
|
|
1460
1461
|
try expectLog1(expected, buf[0..8]);
|
|
1461
1462
|
stream.reset();
|
|
@@ -1463,8 +1464,8 @@ test "|-damage|" {
|
|
|
1463
1464
|
chansey.status = gen1.Status.init(.PSN);
|
|
1464
1465
|
try log.damage(.{ p2.ident(2), &chansey, .RecoilOf, p1.ident(1) });
|
|
1465
1466
|
expected = switch (endian) {
|
|
1466
|
-
.
|
|
1467
|
-
.
|
|
1467
|
+
.big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0b1000, N(Damage.RecoilOf), 1 },
|
|
1468
|
+
.little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0b1000, N(Damage.RecoilOf), 1 },
|
|
1468
1469
|
};
|
|
1469
1470
|
try expectLog1(expected, buf[0..9]);
|
|
1470
1471
|
stream.reset();
|
|
@@ -1476,8 +1477,8 @@ test "|-heal|" {
|
|
|
1476
1477
|
chansey.status = gen1.Status.slp(1);
|
|
1477
1478
|
try log.heal(.{ p2.ident(2), &chansey, .None });
|
|
1478
1479
|
var expected: []const u8 = switch (endian) {
|
|
1479
|
-
.
|
|
1480
|
-
.
|
|
1480
|
+
.big => &.{ N(ArgType.Heal), 0b1010, 2, 100, 2, 191, 1, N(Heal.None) },
|
|
1481
|
+
.little => &.{ N(ArgType.Heal), 0b1010, 100, 2, 191, 2, 1, N(Heal.None) },
|
|
1481
1482
|
};
|
|
1482
1483
|
try expectLog1(expected, buf[0..8]);
|
|
1483
1484
|
stream.reset();
|
|
@@ -1487,16 +1488,16 @@ test "|-heal|" {
|
|
|
1487
1488
|
chansey.status = 0;
|
|
1488
1489
|
try log.heal(.{ p2.ident(2), &chansey, .Silent });
|
|
1489
1490
|
expected = switch (endian) {
|
|
1490
|
-
.
|
|
1491
|
-
.
|
|
1491
|
+
.big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Silent) },
|
|
1492
|
+
.little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Silent) },
|
|
1492
1493
|
};
|
|
1493
1494
|
try expectLog1(expected, buf[0..8]);
|
|
1494
1495
|
stream.reset();
|
|
1495
1496
|
|
|
1496
1497
|
try log.heal(.{ p2.ident(2), &chansey, .Drain, p1.ident(1) });
|
|
1497
1498
|
expected = switch (endian) {
|
|
1498
|
-
.
|
|
1499
|
-
.
|
|
1499
|
+
.big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Drain), 1 },
|
|
1500
|
+
.little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Drain), 1 },
|
|
1500
1501
|
};
|
|
1501
1502
|
try expectLog1(expected, buf[0..9]);
|
|
1502
1503
|
stream.reset();
|
|
@@ -1739,8 +1740,8 @@ test "|drag|" {
|
|
|
1739
1740
|
N(gen2.Gender.Female),
|
|
1740
1741
|
91,
|
|
1741
1742
|
} ++ switch (endian) {
|
|
1742
|
-
.
|
|
1743
|
-
.
|
|
1743
|
+
.big => .{ 0, 200, 1, 144, par },
|
|
1744
|
+
.little => .{ 200, 0, 144, 1, par },
|
|
1744
1745
|
});
|
|
1745
1746
|
try expectLog2(expected, buf[0..10]);
|
|
1746
1747
|
stream.reset();
|
|
@@ -1772,9 +1773,9 @@ test "|-sethp|" {
|
|
|
1772
1773
|
var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.PainSplit} });
|
|
1773
1774
|
blissey.hp = 612;
|
|
1774
1775
|
try log.sethp(.{ p2.ident(2), &blissey, .Silent });
|
|
1775
|
-
|
|
1776
|
-
.
|
|
1777
|
-
.
|
|
1776
|
+
const expected: []const u8 = switch (endian) {
|
|
1777
|
+
.big => &.{ N(ArgType.SetHP), 0b1010, 2, 100, 2, 201, 0, N(SetHP.Silent) },
|
|
1778
|
+
.little => &.{ N(ArgType.SetHP), 0b1010, 100, 2, 201, 2, 0, N(SetHP.Silent) },
|
|
1778
1779
|
};
|
|
1779
1780
|
try expectLog2(expected, buf[0..8]);
|
|
1780
1781
|
stream.reset();
|
|
@@ -192,9 +192,9 @@ pub fn Rational(comptime T: type) type {
|
|
|
192
192
|
|
|
193
193
|
fn addition(r: *Self, p: anytype, q: anytype) !void {
|
|
194
194
|
// (a/b) + (c/d) = (ad+bc)/(bd)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
const d = try std.math.mul(T, r.q, q);
|
|
196
|
+
const n1 = try std.math.mul(T, r.p, q);
|
|
197
|
+
const n2 = try std.math.mul(T, r.q, p);
|
|
198
198
|
|
|
199
199
|
r.p = try std.math.add(T, n1, n2);
|
|
200
200
|
r.q = d;
|
|
@@ -234,6 +234,8 @@ test Rational {
|
|
|
234
234
|
var r: Rational(t) = .{};
|
|
235
235
|
|
|
236
236
|
var c: t = 128;
|
|
237
|
+
_ = &c;
|
|
238
|
+
|
|
237
239
|
try r.update(c, 256);
|
|
238
240
|
try doTurn(&r);
|
|
239
241
|
|
|
@@ -320,6 +322,8 @@ test BigRational {
|
|
|
320
322
|
try r.reset();
|
|
321
323
|
|
|
322
324
|
var c: u8 = 128;
|
|
325
|
+
_ = &c;
|
|
326
|
+
|
|
323
327
|
try r.update(c, 256);
|
|
324
328
|
try doTurn(&r);
|
|
325
329
|
|
package/src/lib/gen1/calc.zig
CHANGED
|
@@ -211,8 +211,8 @@ pub fn transitions(
|
|
|
211
211
|
) !?Stats {
|
|
212
212
|
var stats: Stats = .{};
|
|
213
213
|
|
|
214
|
-
|
|
215
|
-
|
|
214
|
+
const actions = options.actions;
|
|
215
|
+
const cap = options.cap;
|
|
216
216
|
|
|
217
217
|
var seen = std.AutoHashMap(Actions, void).init(allocator);
|
|
218
218
|
defer seen.deinit();
|
|
@@ -232,8 +232,8 @@ pub fn transitions(
|
|
|
232
232
|
_ = try b.update(c1, c2, &opts);
|
|
233
233
|
stats.updates += 1;
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
const p1 = b.side(.P1);
|
|
236
|
+
const p2 = b.side(.P2);
|
|
237
237
|
|
|
238
238
|
var p: Rational(u128) = .{ .p = 0, .q = 1 };
|
|
239
239
|
try frontier.append(opts.chance.actions);
|
|
@@ -247,7 +247,7 @@ pub fn transitions(
|
|
|
247
247
|
var i: usize = 0;
|
|
248
248
|
assert(frontier.items.len == 1);
|
|
249
249
|
while (i < frontier.items.len) : (i += 1) {
|
|
250
|
-
|
|
250
|
+
const template = frontier.items[i];
|
|
251
251
|
opts.calc.overrides.durations = .{
|
|
252
252
|
.p1 = template.p1.durations,
|
|
253
253
|
.p2 = template.p2.durations,
|
|
@@ -71,8 +71,8 @@ pub fn update(battle: anytype, c1: Choice, c2: Choice, options: anytype) !Result
|
|
|
71
71
|
var p1 = battle.side(.P1);
|
|
72
72
|
var p2 = battle.side(.P2);
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const r1 = showdown and p1.active.volatiles.Binding and c2.type == .Switch;
|
|
75
|
+
const r2 = showdown and p2.active.volatiles.Binding and c1.type == .Switch;
|
|
76
76
|
|
|
77
77
|
if (try turnOrder(battle, c1, c2, options) == .P1) {
|
|
78
78
|
if (try doTurn(battle, .P1, c1, r1, s1, .P2, c2, r2, s2, options)) |r| return r;
|
|
@@ -90,11 +90,11 @@ fn start(battle: anytype, options: anytype) !Result {
|
|
|
90
90
|
const p1 = battle.side(.P1);
|
|
91
91
|
const p2 = battle.side(.P2);
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
const p1_slot = findFirstAlive(p1);
|
|
94
94
|
assert(!showdown or p1_slot == 1);
|
|
95
95
|
if (p1_slot == 0) return if (findFirstAlive(p2) == 0) Result.Tie else Result.Lose;
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const p2_slot = findFirstAlive(p2);
|
|
98
98
|
assert(!showdown or p2_slot == 1);
|
|
99
99
|
if (p2_slot == 0) return Result.Win;
|
|
100
100
|
|
|
@@ -635,8 +635,6 @@ fn beforeMove(
|
|
|
635
635
|
volatiles.state +%= battle.last_damage;
|
|
636
636
|
}
|
|
637
637
|
|
|
638
|
-
assert(volatiles.attacks > 0);
|
|
639
|
-
|
|
640
638
|
if (options.calc.modify(player, .attacking)) |extend| {
|
|
641
639
|
if (!extend) volatiles.attacks = 0;
|
|
642
640
|
} else {
|
|
@@ -676,8 +674,6 @@ fn beforeMove(
|
|
|
676
674
|
}
|
|
677
675
|
|
|
678
676
|
if (volatiles.Thrashing) {
|
|
679
|
-
assert(volatiles.attacks > 0);
|
|
680
|
-
|
|
681
677
|
if (options.calc.modify(player, .attacking)) |extend| {
|
|
682
678
|
if (!extend) volatiles.attacks = 0;
|
|
683
679
|
} else {
|
|
@@ -701,8 +697,6 @@ fn beforeMove(
|
|
|
701
697
|
}
|
|
702
698
|
|
|
703
699
|
if (volatiles.Binding) {
|
|
704
|
-
assert(volatiles.attacks > 0);
|
|
705
|
-
|
|
706
700
|
if (options.calc.modify(player, .binding)) |extend| {
|
|
707
701
|
if (!extend) volatiles.attacks = 0;
|
|
708
702
|
} else {
|
|
@@ -738,7 +732,6 @@ fn canMove(
|
|
|
738
732
|
const player_ident = battle.active(player);
|
|
739
733
|
const move = Move.get(side.last_selected_move);
|
|
740
734
|
|
|
741
|
-
var skip = skip_pp;
|
|
742
735
|
if (side.active.volatiles.Charging) {
|
|
743
736
|
side.active.volatiles.Charging = false;
|
|
744
737
|
side.active.volatiles.Invulnerable = false;
|
|
@@ -750,7 +743,7 @@ fn canMove(
|
|
|
750
743
|
}
|
|
751
744
|
|
|
752
745
|
side.last_used_move = side.last_selected_move;
|
|
753
|
-
if (!
|
|
746
|
+
if (!skip_pp) decrementPP(side, mslot, auto);
|
|
754
747
|
|
|
755
748
|
const target = if (move.target == .Self) player else player.foe();
|
|
756
749
|
try options.log.move(.{ player_ident, side.last_selected_move, battle.active(target), from });
|
|
@@ -902,7 +895,7 @@ fn doMove(
|
|
|
902
895
|
}
|
|
903
896
|
}
|
|
904
897
|
|
|
905
|
-
|
|
898
|
+
const zero = battle.last_damage == 0;
|
|
906
899
|
miss = if (showdown or skip)
|
|
907
900
|
miss
|
|
908
901
|
else
|
|
@@ -1679,7 +1672,6 @@ fn onBegin(
|
|
|
1679
1672
|
residual: *bool,
|
|
1680
1673
|
options: anytype,
|
|
1681
1674
|
) !void {
|
|
1682
|
-
assert(move.effect.onBegin());
|
|
1683
1675
|
return switch (move.effect) {
|
|
1684
1676
|
.Confusion => Effects.confusion(battle, player, move, options),
|
|
1685
1677
|
.Conversion => Effects.conversion(battle, player, options),
|
|
@@ -1702,7 +1694,6 @@ fn onBegin(
|
|
|
1702
1694
|
}
|
|
1703
1695
|
|
|
1704
1696
|
fn onEnd(battle: anytype, player: Player, move: Move.Data, options: anytype) !void {
|
|
1705
|
-
assert(move.effect.onEnd());
|
|
1706
1697
|
return switch (move.effect) {
|
|
1707
1698
|
.Bide => Effects.bide(battle, player, options),
|
|
1708
1699
|
// zig fmt: off
|
|
@@ -1724,7 +1715,6 @@ fn alwaysHappens(
|
|
|
1724
1715
|
residual: *bool,
|
|
1725
1716
|
options: anytype,
|
|
1726
1717
|
) !void {
|
|
1727
|
-
assert(move.effect.alwaysHappens());
|
|
1728
1718
|
return switch (move.effect) {
|
|
1729
1719
|
.DrainHP, .DreamEater => Effects.drainHP(battle, player, options),
|
|
1730
1720
|
.Explode => Effects.explode(battle, player),
|
|
@@ -1972,7 +1962,7 @@ pub const Effects = struct {
|
|
|
1972
1962
|
var side = battle.side(player);
|
|
1973
1963
|
var foe = battle.foe(player);
|
|
1974
1964
|
|
|
1975
|
-
|
|
1965
|
+
const side_stored = side.stored();
|
|
1976
1966
|
var foe_stored = foe.stored();
|
|
1977
1967
|
|
|
1978
1968
|
const player_ident = battle.active(player);
|
|
@@ -2441,7 +2431,7 @@ pub const Effects = struct {
|
|
|
2441
2431
|
}
|
|
2442
2432
|
return log.fail(.{ ident, .None });
|
|
2443
2433
|
}
|
|
2444
|
-
|
|
2434
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.atk) + 6))];
|
|
2445
2435
|
const stat = unmodifiedStats(battle, side).atk;
|
|
2446
2436
|
stats.atk = @min(MAX_STAT_VALUE, stat * mod[0] / mod[1]);
|
|
2447
2437
|
try log.boost(.{ ident, reason, n });
|
|
@@ -2461,7 +2451,7 @@ pub const Effects = struct {
|
|
|
2461
2451
|
}
|
|
2462
2452
|
return log.fail(.{ ident, .None });
|
|
2463
2453
|
}
|
|
2464
|
-
|
|
2454
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.def) + 6))];
|
|
2465
2455
|
const stat = unmodifiedStats(battle, side).def;
|
|
2466
2456
|
stats.def = @min(MAX_STAT_VALUE, stat * mod[0] / mod[1]);
|
|
2467
2457
|
try log.boost(.{ ident, .Defense, n });
|
|
@@ -2478,7 +2468,7 @@ pub const Effects = struct {
|
|
|
2478
2468
|
}
|
|
2479
2469
|
return log.fail(.{ ident, .None });
|
|
2480
2470
|
}
|
|
2481
|
-
|
|
2471
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.spe) + 6))];
|
|
2482
2472
|
const stat = unmodifiedStats(battle, side).spe;
|
|
2483
2473
|
stats.spe = @min(MAX_STAT_VALUE, stat * mod[0] / mod[1]);
|
|
2484
2474
|
try log.boost(.{ ident, .Speed, 2 });
|
|
@@ -2498,7 +2488,7 @@ pub const Effects = struct {
|
|
|
2498
2488
|
}
|
|
2499
2489
|
return log.fail(.{ ident, .None });
|
|
2500
2490
|
}
|
|
2501
|
-
|
|
2491
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.spc) + 6))];
|
|
2502
2492
|
const stat = unmodifiedStats(battle, side).spc;
|
|
2503
2493
|
stats.spc = @min(MAX_STAT_VALUE, stat * mod[0] / mod[1]);
|
|
2504
2494
|
try log.boost(.{ ident, .SpecialAttack, n });
|
|
@@ -2551,7 +2541,7 @@ pub const Effects = struct {
|
|
|
2551
2541
|
}
|
|
2552
2542
|
return log.fail(.{ foe_ident, .None });
|
|
2553
2543
|
}
|
|
2554
|
-
|
|
2544
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.atk) + 6))];
|
|
2555
2545
|
const stat = unmodifiedStats(battle, foe).atk;
|
|
2556
2546
|
stats.atk = @max(1, stat * mod[0] / mod[1]);
|
|
2557
2547
|
try log.boost(.{ foe_ident, .Attack, -1 });
|
|
@@ -2569,7 +2559,7 @@ pub const Effects = struct {
|
|
|
2569
2559
|
}
|
|
2570
2560
|
return log.fail(.{ foe_ident, .None });
|
|
2571
2561
|
}
|
|
2572
|
-
|
|
2562
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.def) + 6))];
|
|
2573
2563
|
const stat = unmodifiedStats(battle, foe).def;
|
|
2574
2564
|
stats.def = @max(1, stat * mod[0] / mod[1]);
|
|
2575
2565
|
try log.boost(.{ foe_ident, .Defense, -@as(i8, n) });
|
|
@@ -2586,7 +2576,7 @@ pub const Effects = struct {
|
|
|
2586
2576
|
}
|
|
2587
2577
|
return log.fail(.{ foe_ident, .None });
|
|
2588
2578
|
}
|
|
2589
|
-
|
|
2579
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.spe) + 6))];
|
|
2590
2580
|
const stat = unmodifiedStats(battle, foe).spe;
|
|
2591
2581
|
stats.spe = @max(1, stat * mod[0] / mod[1]);
|
|
2592
2582
|
try log.boost(.{ foe_ident, .Speed, -1 });
|
|
@@ -2606,7 +2596,7 @@ pub const Effects = struct {
|
|
|
2606
2596
|
}
|
|
2607
2597
|
return log.fail(.{ foe_ident, .None });
|
|
2608
2598
|
}
|
|
2609
|
-
|
|
2599
|
+
const mod = BOOSTS[@as(u4, @intCast(@as(i8, boosts.spc) + 6))];
|
|
2610
2600
|
const stat = unmodifiedStats(battle, foe).spc;
|
|
2611
2601
|
stats.spc = @max(1, stat * mod[0] / mod[1]);
|
|
2612
2602
|
try log.boost(.{ foe_ident, .SpecialAttack, -1 });
|
|
@@ -3038,7 +3028,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
|
|
|
3038
3028
|
const side = battle.side(player);
|
|
3039
3029
|
const foe = battle.foe(player);
|
|
3040
3030
|
|
|
3041
|
-
|
|
3031
|
+
const active = &side.active;
|
|
3042
3032
|
const stored = side.stored();
|
|
3043
3033
|
|
|
3044
3034
|
// While players are not given any input options on the cartridge in these cases,
|
package/src/lib/gen2/data.zig
CHANGED
|
@@ -239,7 +239,7 @@ pub const DVs = packed struct(u16) {
|
|
|
239
239
|
};
|
|
240
240
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
241
241
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
242
|
-
|
|
242
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
243
|
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
244
244
|
}
|
|
245
245
|
};
|
|
@@ -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());
|