@pkmn/engine 0.1.0-dev.44b2e6ec → 0.1.0-dev.47dcb76c
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 +1 -1
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +2 -2
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.js.map +1 -1
- package/build/tools/debug.js.map +1 -1
- package/build.zig +50 -53
- package/package.json +27 -20
- package/src/bin/install-pkmn-engine +14 -14
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/protocol.zig +10 -20
- package/src/lib/common/rng.zig +11 -11
- package/src/lib/gen1/chance.zig +21 -21
- package/src/lib/gen1/data/species.zig +1 -1
- package/src/lib/gen1/data.zig +18 -18
- package/src/lib/gen1/helpers.zig +7 -7
- package/src/lib/gen1/mechanics.zig +41 -5
- package/src/lib/gen2/chance.zig +27 -27
- package/src/lib/gen2/data.zig +8 -8
- package/src/lib/{binding/node.zig → node.zig} +3 -2
- package/src/lib/pkmn.zig +26 -3
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
- package/src/lib/gen1/README.md +0 -894
- package/src/lib/gen2/README.md +0 -329
|
@@ -10,7 +10,7 @@ const path = require('path');
|
|
|
10
10
|
const {pipeline} = require('stream/promises');
|
|
11
11
|
const tty = require('tty');
|
|
12
12
|
|
|
13
|
-
const ZIG_VERSION = {major: 0, minor: 12, patch: 0, dev:
|
|
13
|
+
const ZIG_VERSION = {major: 0, minor: 12, patch: 0, dev: 2036};
|
|
14
14
|
const DEV = ZIG_VERSION.dev ? `-dev.${ZIG_VERSION.dev}` : '';
|
|
15
15
|
const VERSION = `${ZIG_VERSION.major}.${ZIG_VERSION.minor}.${ZIG_VERSION.patch}${DEV}`;
|
|
16
16
|
const INDEX = 'https://ziglang.org/download/index.json';
|
|
@@ -283,19 +283,19 @@ const downloadImportLib = async () => {
|
|
|
283
283
|
let error = false;
|
|
284
284
|
for (let i = 2; i < process.argv.length; i++) {
|
|
285
285
|
switch (process.argv[i]) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
286
|
+
case "--silent": {
|
|
287
|
+
SILENT = true;
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
case "--zig": {
|
|
291
|
+
if (options || only) error = true;
|
|
292
|
+
only = true;
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
default: {
|
|
296
|
+
if (options || only || !process.argv[i].startsWith('--options=')) error = true;
|
|
297
|
+
options = process.argv[i].slice(10).split(' ');
|
|
298
|
+
}
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
if (error) {
|
package/src/lib/common/data.zig
CHANGED
|
@@ -22,8 +22,8 @@ pub const Player = enum(u1) {
|
|
|
22
22
|
|
|
23
23
|
test Player {
|
|
24
24
|
try expectEqual(Player.P2, Player.P1.foe());
|
|
25
|
-
try expectEqual(
|
|
26
|
-
try expectEqual(
|
|
25
|
+
try expectEqual(0b0001, @as(u8, @bitCast(Player.P1.ident(1))));
|
|
26
|
+
try expectEqual(0b1101, @as(u8, @bitCast(Player.P2.ident(5))));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/// An identifier for a specific Pokémon in battle.
|
|
@@ -46,8 +46,8 @@ pub const ID = packed struct(u8) {
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
test ID {
|
|
49
|
-
try expectEqual(
|
|
50
|
-
try expectEqual(
|
|
49
|
+
try expectEqual(0b0001, @as(u8, @bitCast(ID{ .player = .P1, .id = 1 })));
|
|
50
|
+
try expectEqual(0b1101, @as(u8, @bitCast(ID{ .player = .P2, .id = 5 })));
|
|
51
51
|
const id: ID = .{ .player = .P2, .id = 4 };
|
|
52
52
|
try expectEqual(id, ID.from(id.int()));
|
|
53
53
|
}
|
|
@@ -3,8 +3,8 @@ const builtin = @import("builtin");
|
|
|
3
3
|
|
|
4
4
|
const pkmn = @import("../pkmn.zig");
|
|
5
5
|
|
|
6
|
-
const data = @import("
|
|
7
|
-
const options = @import("
|
|
6
|
+
const data = @import("data.zig");
|
|
7
|
+
const options = @import("options.zig");
|
|
8
8
|
|
|
9
9
|
const assert = std.debug.assert;
|
|
10
10
|
const print = std.debug.print;
|
|
@@ -1202,14 +1202,11 @@ pub fn expectLog(
|
|
|
1202
1202
|
) !void {
|
|
1203
1203
|
if (!enabled) return;
|
|
1204
1204
|
|
|
1205
|
-
const color =
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
} else {
|
|
1211
|
-
break :color std.io.getStdErr().supportsAnsiEscapeCodes();
|
|
1212
|
-
}
|
|
1205
|
+
const color = if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR"))
|
|
1206
|
+
true
|
|
1207
|
+
else switch (std.io.tty.detectConfig(std.io.getStdErr())) {
|
|
1208
|
+
.escape_codes => true,
|
|
1209
|
+
else => false,
|
|
1213
1210
|
};
|
|
1214
1211
|
|
|
1215
1212
|
expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
|
|
@@ -1248,20 +1245,13 @@ fn N(e: anytype) u8 {
|
|
|
1248
1245
|
const p1 = Player.P1;
|
|
1249
1246
|
const p2 = Player.P2;
|
|
1250
1247
|
|
|
1251
|
-
const gen1 = struct {
|
|
1252
|
-
pub usingnamespace @import("../gen1/data.zig");
|
|
1253
|
-
pub const helpers = @import("../gen1/helpers.zig");
|
|
1254
|
-
};
|
|
1255
|
-
|
|
1256
|
-
const gen2 = struct {
|
|
1257
|
-
pub usingnamespace @import("../gen2/data.zig");
|
|
1258
|
-
pub const helpers = @import("../gen2/helpers.zig");
|
|
1259
|
-
};
|
|
1260
|
-
|
|
1261
1248
|
var buf: [pkmn.LOGS_SIZE]u8 = undefined;
|
|
1262
1249
|
var stream: ByteStream = .{ .buffer = &buf };
|
|
1263
1250
|
var log: FixedLog = .{ .writer = stream.writer() };
|
|
1264
1251
|
|
|
1252
|
+
const gen1 = pkmn.gen1;
|
|
1253
|
+
const gen2 = pkmn.gen2;
|
|
1254
|
+
|
|
1265
1255
|
const M1 = gen1.Move;
|
|
1266
1256
|
const S1 = gen1.Species;
|
|
1267
1257
|
|
package/src/lib/common/rng.zig
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
|
|
3
|
-
const options = @import("
|
|
3
|
+
const options = @import("options.zig");
|
|
4
4
|
|
|
5
5
|
const assert = std.debug.assert;
|
|
6
6
|
const expectEqual = std.testing.expectEqual;
|
|
@@ -66,11 +66,15 @@ pub const PSRNG = extern struct {
|
|
|
66
66
|
(@as(u64, self.range(u16, 0, 0x10000)) << 16) |
|
|
67
67
|
(@as(u64, self.range(u16, 0, 0x10000)));
|
|
68
68
|
}
|
|
69
|
+
|
|
70
|
+
pub fn Bound(comptime T: type) type {
|
|
71
|
+
return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
|
|
72
|
+
}
|
|
69
73
|
};
|
|
70
74
|
|
|
71
75
|
test PSRNG {
|
|
72
76
|
var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
|
|
73
|
-
try expectEqual(
|
|
77
|
+
try expectEqual(121, psrng.range(u8, 0, 256));
|
|
74
78
|
try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -107,9 +111,9 @@ test Gen12 {
|
|
|
107
111
|
try expectEqual(e, rng.next());
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
try expectEqual(
|
|
111
|
-
try expectEqual(
|
|
112
|
-
try expectEqual(
|
|
114
|
+
try expectEqual(16, Gen12.percent(6) + 1);
|
|
115
|
+
try expectEqual(16, Gen12.percent(7) - 1);
|
|
116
|
+
try expectEqual(128, Gen12.percent(50) + 1);
|
|
113
117
|
}
|
|
114
118
|
|
|
115
119
|
// https://pkmn.cc/pokeemerald/src/random.c
|
|
@@ -197,7 +201,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
197
201
|
for (0..n) |_| _ = self.next();
|
|
198
202
|
}
|
|
199
203
|
|
|
200
|
-
pub fn range(self: *Self, comptime T: type, from: T, to: Bound(T)) T {
|
|
204
|
+
pub fn range(self: *Self, comptime T: type, from: T, to: PSRNG.Bound(T)) T {
|
|
201
205
|
assert(showdown);
|
|
202
206
|
return @intCast(@as(u64, self.next()) * (to - from) / divisor + from);
|
|
203
207
|
}
|
|
@@ -206,7 +210,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
206
210
|
self: *Self,
|
|
207
211
|
comptime T: type,
|
|
208
212
|
numerator: T,
|
|
209
|
-
denominator: Bound(T),
|
|
213
|
+
denominator: PSRNG.Bound(T),
|
|
210
214
|
) bool {
|
|
211
215
|
assert(showdown);
|
|
212
216
|
assert(denominator > 0);
|
|
@@ -237,7 +241,3 @@ fn Output(comptime gen: comptime_int) type {
|
|
|
237
241
|
else => unreachable,
|
|
238
242
|
};
|
|
239
243
|
}
|
|
240
|
-
|
|
241
|
-
fn Bound(comptime T: type) type {
|
|
242
|
-
return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
|
|
243
|
-
}
|
package/src/lib/gen1/chance.zig
CHANGED
|
@@ -14,7 +14,7 @@ const util = @import("../common/util.zig");
|
|
|
14
14
|
const Player = @import("../common/data.zig").Player;
|
|
15
15
|
const Optional = @import("../common/optional.zig").Optional;
|
|
16
16
|
|
|
17
|
-
const data = @import("
|
|
17
|
+
const data = @import("data.zig");
|
|
18
18
|
|
|
19
19
|
const enabled = options.chance;
|
|
20
20
|
const showdown = options.showdown;
|
|
@@ -706,19 +706,19 @@ test "Chance.damage" {
|
|
|
706
706
|
|
|
707
707
|
try chance.damage(.P1, 217);
|
|
708
708
|
if (showdown) {
|
|
709
|
-
try expectValue(
|
|
709
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
710
710
|
try expectProbability(&chance.probability, 1, 39);
|
|
711
711
|
} else {
|
|
712
712
|
try expectProbability(&chance.probability, 1, 1);
|
|
713
|
-
try expectValue(
|
|
713
|
+
try expectValue(0, chance.actions.p1.damage);
|
|
714
714
|
|
|
715
715
|
try chance.commit(.P1, .miss);
|
|
716
716
|
try expectProbability(&chance.probability, 1, 1);
|
|
717
|
-
try expectValue(
|
|
717
|
+
try expectValue(0, chance.actions.p1.damage);
|
|
718
718
|
|
|
719
719
|
try chance.commit(.P1, .hit);
|
|
720
720
|
try expectProbability(&chance.probability, 1, 39);
|
|
721
|
-
try expectValue(
|
|
721
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
724
|
|
|
@@ -770,13 +770,13 @@ test "Chance.moveSlot" {
|
|
|
770
770
|
|
|
771
771
|
try chance.moveSlot(.P2, 2, &ms, 2);
|
|
772
772
|
try expectProbability(&chance.probability, 1, 2);
|
|
773
|
-
try expectValue(
|
|
773
|
+
try expectValue(2, chance.actions.p2.move_slot);
|
|
774
774
|
|
|
775
775
|
chance.reset();
|
|
776
776
|
|
|
777
777
|
try chance.moveSlot(.P1, 1, &ms, 0);
|
|
778
778
|
try expectProbability(&chance.probability, 1, 3);
|
|
779
|
-
try expectValue(
|
|
779
|
+
try expectValue(1, chance.actions.p1.move_slot);
|
|
780
780
|
}
|
|
781
781
|
|
|
782
782
|
test "Chance.multiHit" {
|
|
@@ -784,32 +784,32 @@ test "Chance.multiHit" {
|
|
|
784
784
|
|
|
785
785
|
try chance.multiHit(.P1, 3);
|
|
786
786
|
try expectProbability(&chance.probability, 3, 8);
|
|
787
|
-
try expectValue(
|
|
787
|
+
try expectValue(3, chance.actions.p1.multi_hit);
|
|
788
788
|
|
|
789
789
|
chance.reset();
|
|
790
790
|
|
|
791
791
|
try chance.multiHit(.P2, 5);
|
|
792
792
|
try expectProbability(&chance.probability, 1, 8);
|
|
793
|
-
try expectValue(
|
|
793
|
+
try expectValue(5, chance.actions.p2.multi_hit);
|
|
794
794
|
}
|
|
795
795
|
|
|
796
796
|
test "Chance.duration" {
|
|
797
797
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
798
798
|
|
|
799
799
|
chance.duration(.sleep, .P1, .P2, 2);
|
|
800
|
-
try expectValue(
|
|
801
|
-
try expectValue(
|
|
800
|
+
try expectValue(2, chance.actions.p1.duration);
|
|
801
|
+
try expectValue(1, chance.actions.p2.durations.sleep);
|
|
802
802
|
|
|
803
803
|
chance.reset();
|
|
804
804
|
|
|
805
805
|
chance.duration(.binding, .P2, .P2, 4);
|
|
806
806
|
if (!showdown) {
|
|
807
|
-
try expectValue(
|
|
808
|
-
try expectValue(
|
|
807
|
+
try expectValue(0, chance.actions.p2.duration);
|
|
808
|
+
try expectValue(0, chance.actions.p2.durations.binding);
|
|
809
809
|
try chance.commit(.P2, .hit);
|
|
810
810
|
}
|
|
811
|
-
try expectValue(
|
|
812
|
-
try expectValue(
|
|
811
|
+
try expectValue(4, chance.actions.p2.duration);
|
|
812
|
+
try expectValue(1, chance.actions.p2.durations.binding);
|
|
813
813
|
}
|
|
814
814
|
|
|
815
815
|
test "Chance.sleep" {
|
|
@@ -819,7 +819,7 @@ test "Chance.sleep" {
|
|
|
819
819
|
chance.actions.p1.durations.sleep = @intCast(i);
|
|
820
820
|
try chance.sleep(.P1, 0);
|
|
821
821
|
try expectProbability(&chance.probability, 1, d);
|
|
822
|
-
try expectValue(
|
|
822
|
+
try expectValue(0, chance.actions.p1.durations.sleep);
|
|
823
823
|
|
|
824
824
|
chance.reset();
|
|
825
825
|
|
|
@@ -842,7 +842,7 @@ test "Chance.confusion" {
|
|
|
842
842
|
chance.actions.p2.durations.confusion = @intCast(i);
|
|
843
843
|
try chance.confusion(.P2, 0);
|
|
844
844
|
try expectProbability(&chance.probability, 1, d);
|
|
845
|
-
try expectValue(
|
|
845
|
+
try expectValue(0, chance.actions.p2.durations.confusion);
|
|
846
846
|
|
|
847
847
|
chance.reset();
|
|
848
848
|
}
|
|
@@ -865,7 +865,7 @@ test "Chance.disable" {
|
|
|
865
865
|
chance.actions.p1.durations.disable = @intCast(i);
|
|
866
866
|
try chance.disable(.P1, 0);
|
|
867
867
|
try expectProbability(&chance.probability, 1, d);
|
|
868
|
-
try expectValue(
|
|
868
|
+
try expectValue(0, chance.actions.p1.durations.disable);
|
|
869
869
|
|
|
870
870
|
chance.reset();
|
|
871
871
|
|
|
@@ -888,7 +888,7 @@ test "Chance.attacking" {
|
|
|
888
888
|
chance.actions.p2.durations.attacking = @intCast(i);
|
|
889
889
|
try chance.attacking(.P2, 0);
|
|
890
890
|
try expectProbability(&chance.probability, 1, d);
|
|
891
|
-
try expectValue(
|
|
891
|
+
try expectValue(0, chance.actions.p2.durations.attacking);
|
|
892
892
|
|
|
893
893
|
chance.reset();
|
|
894
894
|
}
|
|
@@ -914,7 +914,7 @@ test "Chance.binding" {
|
|
|
914
914
|
chance.actions.p1.durations.binding = @intCast(i);
|
|
915
915
|
try chance.binding(.P1, 0);
|
|
916
916
|
try expectProbability(&chance.probability, p, q);
|
|
917
|
-
try expectValue(
|
|
917
|
+
try expectValue(0, chance.actions.p1.durations.binding);
|
|
918
918
|
|
|
919
919
|
chance.reset();
|
|
920
920
|
|
|
@@ -934,7 +934,7 @@ test "Chance.psywave" {
|
|
|
934
934
|
|
|
935
935
|
try chance.psywave(.P2, 100, 150);
|
|
936
936
|
try expectProbability(&chance.probability, 1, 150);
|
|
937
|
-
try expectValue(
|
|
937
|
+
try expectValue(101, chance.actions.p2.psywave);
|
|
938
938
|
}
|
|
939
939
|
|
|
940
940
|
test "Chance.metronome" {
|
|
@@ -1091,7 +1091,7 @@ pub const Species = enum(u8) {
|
|
|
1091
1091
|
/// The number of Pokémon species in this generation.
|
|
1092
1092
|
pub const size = 151;
|
|
1093
1093
|
|
|
1094
|
-
/// The Pokémon's critical hit
|
|
1094
|
+
/// The Pokémon's critical hit ratio out of 256.
|
|
1095
1095
|
pub fn chance(id: Species) u8 {
|
|
1096
1096
|
assert(id != .None);
|
|
1097
1097
|
return CHANCES[@intFromEnum(id) - 1];
|
package/src/lib/gen1/data.zig
CHANGED
|
@@ -112,7 +112,7 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
112
112
|
/// make (i.e. on the cartridge a soft-lock occurs).
|
|
113
113
|
///
|
|
114
114
|
/// This function will always return choices > 0 if `pkmn.options.showdown` is true.
|
|
115
|
-
pub fn choices(self: *Self, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
115
|
+
pub fn choices(self: *const Self, player: Player, request: Choice.Type, out: []Choice) u8 {
|
|
116
116
|
return mechanics.choices(self, player, request, out);
|
|
117
117
|
}
|
|
118
118
|
};
|
|
@@ -316,12 +316,12 @@ test Status {
|
|
|
316
316
|
try expect(Status.is(Status.slp(5), .SLP));
|
|
317
317
|
try expect(!Status.is(Status.slp(5), .EXT));
|
|
318
318
|
try expect(!Status.is(Status.slp(7), .PSN));
|
|
319
|
-
try expectEqual(
|
|
319
|
+
try expectEqual(5, Status.duration(Status.slp(5)));
|
|
320
320
|
try expect(Status.is(Status.slf(2), .SLP));
|
|
321
321
|
try expect(Status.is(Status.slf(2), .EXT));
|
|
322
322
|
try expect(Status.is(Status.TOX, .PSN));
|
|
323
323
|
try expect(Status.is(Status.TOX, .EXT));
|
|
324
|
-
try expectEqual(
|
|
324
|
+
try expectEqual(1, Status.duration(Status.slp(1)));
|
|
325
325
|
}
|
|
326
326
|
|
|
327
327
|
/// Bitfield representation of volatile statuses and associated data in Generation I.
|
|
@@ -405,13 +405,13 @@ test Volatiles {
|
|
|
405
405
|
try expect(!volatiles.Transform);
|
|
406
406
|
try expect(!volatiles.MultiHit);
|
|
407
407
|
|
|
408
|
-
try expectEqual(
|
|
409
|
-
try expectEqual(
|
|
410
|
-
try expectEqual(
|
|
411
|
-
try expectEqual(
|
|
412
|
-
try expectEqual(
|
|
413
|
-
try expectEqual(
|
|
414
|
-
try expectEqual(
|
|
408
|
+
try expectEqual(235, volatiles.state);
|
|
409
|
+
try expectEqual(42, volatiles.substitute);
|
|
410
|
+
try expectEqual(2, volatiles.disable_move);
|
|
411
|
+
try expectEqual(4, volatiles.disable_duration);
|
|
412
|
+
try expectEqual(2, volatiles.confusion);
|
|
413
|
+
try expectEqual(4, volatiles.toxic);
|
|
414
|
+
try expectEqual(3, volatiles.attacks);
|
|
415
415
|
}
|
|
416
416
|
|
|
417
417
|
/// Representaiton of a Pokémon's stats in Generation I.
|
|
@@ -442,9 +442,9 @@ test Stats {
|
|
|
442
442
|
try expectEqual(0, stats.def);
|
|
443
443
|
|
|
444
444
|
var base = Species.get(.Gyarados).stats;
|
|
445
|
-
try expectEqual(
|
|
445
|
+
try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
446
446
|
base = Species.get(.Pidgeot).stats;
|
|
447
|
-
try expectEqual(
|
|
447
|
+
try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
/// Representation of a Pokémon's boosts in Generation I.
|
|
@@ -537,7 +537,7 @@ pub const Species = species.Species;
|
|
|
537
537
|
|
|
538
538
|
test Species {
|
|
539
539
|
try expectEqual(2, @intFromEnum(Species.Ivysaur));
|
|
540
|
-
try expectEqual(
|
|
540
|
+
try expectEqual(100, Species.get(.Mew).stats.def);
|
|
541
541
|
}
|
|
542
542
|
|
|
543
543
|
/// Representation of a Generation I type in Pokémon.
|
|
@@ -576,8 +576,8 @@ test Types {
|
|
|
576
576
|
try expectEqual(Effectiveness.Resisted, Type.effectiveness(.Fire, .Water));
|
|
577
577
|
try expectEqual(Effectiveness.Neutral, Type.effectiveness(.Normal, .Grass));
|
|
578
578
|
|
|
579
|
-
try expectEqual(
|
|
580
|
-
try expectEqual(
|
|
579
|
+
try expectEqual(3, Type.precedence(.Water, .Water));
|
|
580
|
+
try expectEqual(26, Type.precedence(.Bug, .Ghost));
|
|
581
581
|
try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
|
|
582
582
|
|
|
583
583
|
const t: Types = .{ .type1 = .Rock, .type2 = .Ground };
|
|
@@ -617,18 +617,18 @@ pub const DVs = struct {
|
|
|
617
617
|
|
|
618
618
|
test DVs {
|
|
619
619
|
var dvs: DVs = .{ .spc = 15, .spe = 15 };
|
|
620
|
-
try expectEqual(
|
|
620
|
+
try expectEqual(15, dvs.hp());
|
|
621
621
|
dvs = .{
|
|
622
622
|
.atk = 5,
|
|
623
623
|
.def = 15,
|
|
624
624
|
.spe = 13,
|
|
625
625
|
.spc = 13,
|
|
626
626
|
};
|
|
627
|
-
try expectEqual(
|
|
627
|
+
try expectEqual(15, dvs.hp());
|
|
628
628
|
dvs = .{
|
|
629
629
|
.def = 3,
|
|
630
630
|
.spe = 10,
|
|
631
631
|
.spc = 11,
|
|
632
632
|
};
|
|
633
|
-
try expectEqual(
|
|
633
|
+
try expectEqual(13, dvs.hp());
|
|
634
634
|
}
|
package/src/lib/gen1/helpers.zig
CHANGED
|
@@ -478,12 +478,12 @@ test "Rolls.damage" {
|
|
|
478
478
|
test "Rolls.coalesce" {
|
|
479
479
|
var summaries =
|
|
480
480
|
calc.Summaries{ .p1 = .{ .damage = .{ .base = 74, .final = 69, .capped = true } } };
|
|
481
|
-
try expectEqual(
|
|
482
|
-
try expectEqual(
|
|
483
|
-
try expectEqual(
|
|
481
|
+
try expectEqual(0, try Rolls.coalesce(.P2, 0, &summaries, false));
|
|
482
|
+
try expectEqual(241, try Rolls.coalesce(.P2, 238, &summaries, false));
|
|
483
|
+
try expectEqual(255, try Rolls.coalesce(.P2, 238, &summaries, true));
|
|
484
484
|
summaries.p1.damage.final = 74;
|
|
485
|
-
try expectEqual(
|
|
486
|
-
try expectEqual(
|
|
485
|
+
try expectEqual(217, try Rolls.coalesce(.P2, 217, &summaries, false));
|
|
486
|
+
try expectEqual(255, try Rolls.coalesce(.P2, 217, &summaries, true));
|
|
487
487
|
}
|
|
488
488
|
|
|
489
489
|
test "Rolls.hit" {
|
|
@@ -771,9 +771,9 @@ test "Rolls.psywave" {
|
|
|
771
771
|
|
|
772
772
|
try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p1, &side, .None));
|
|
773
773
|
var rolls = Rolls.psywave(actions.p2, &side, .None);
|
|
774
|
-
try expectEqual(
|
|
774
|
+
try expectEqual(150, rolls[rolls.len - 1]);
|
|
775
775
|
side.stored().level = 81;
|
|
776
776
|
rolls = Rolls.psywave(actions.p2, &side, .None);
|
|
777
|
-
try expectEqual(
|
|
777
|
+
try expectEqual(121, rolls[rolls.len - 1]);
|
|
778
778
|
try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p2, &side, .false));
|
|
779
779
|
}
|
|
@@ -1053,7 +1053,7 @@ fn checkCriticalHit(battle: anytype, player: Player, move: Move.Data, options: a
|
|
|
1053
1053
|
const side = battle.side(player);
|
|
1054
1054
|
|
|
1055
1055
|
// Base speed is used for the critical hit calculation, even when Transform-ed
|
|
1056
|
-
var rate =
|
|
1056
|
+
var rate: u16 = Species.chance(side.stored().species);
|
|
1057
1057
|
// GLITCH: Focus Energy reduces critical hit rate instead of increasing it
|
|
1058
1058
|
rate = if (side.active.volatiles.FocusEnergy) rate / 2 else @min(rate * 2, 255);
|
|
1059
1059
|
rate = if (move.effect == .HighCritical) @min(rate * 4, 255) else rate / 2;
|
|
@@ -1110,9 +1110,9 @@ fn calcDamage(
|
|
|
1110
1110
|
def = @max((def / 4) & 255, if (showdown) 1 else 0);
|
|
1111
1111
|
}
|
|
1112
1112
|
|
|
1113
|
-
const lvl =
|
|
1113
|
+
const lvl: u32 = side.stored().level * @as(u2, if (crit) 2 else 1);
|
|
1114
1114
|
|
|
1115
|
-
def =
|
|
1115
|
+
def = if (move.effect == .Explode) @max(def / 2, 1) else def;
|
|
1116
1116
|
|
|
1117
1117
|
if (def == 0) return false;
|
|
1118
1118
|
|
|
@@ -1395,7 +1395,7 @@ fn moveHit(
|
|
|
1395
1395
|
const overwritten = overwrite and state > 0;
|
|
1396
1396
|
assert(!overwritten or (0 < state and state <= 255 and !side.active.volatiles.Bide));
|
|
1397
1397
|
|
|
1398
|
-
var accuracy = if (overwritten) state else
|
|
1398
|
+
var accuracy: u16 = if (overwritten) state else move.accuracy;
|
|
1399
1399
|
var boost = BOOSTS[@as(u4, @intCast(@as(i8, side.active.boosts.accuracy) + 6))];
|
|
1400
1400
|
accuracy = accuracy * boost[0] / boost[1];
|
|
1401
1401
|
boost = BOOSTS[@as(u4, @intCast(@as(i8, -foe.active.boosts.evasion) + 6))];
|
|
@@ -2689,6 +2689,8 @@ pub const Rolls = struct {
|
|
|
2689
2689
|
fn speedTie(battle: anytype, options: anytype) !bool {
|
|
2690
2690
|
const p1 = if (options.calc.overridden(.P1, .speed_tie)) |player|
|
|
2691
2691
|
player == .P1
|
|
2692
|
+
else if (@hasDecl(@TypeOf(battle.rng), "speedTie"))
|
|
2693
|
+
battle.rng.speedTie()
|
|
2692
2694
|
else if (showdown)
|
|
2693
2695
|
battle.rng.range(u8, 0, 2) == 0
|
|
2694
2696
|
else
|
|
@@ -2701,6 +2703,8 @@ pub const Rolls = struct {
|
|
|
2701
2703
|
fn criticalHit(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
|
|
2702
2704
|
const crit = if (options.calc.overridden(player, .critical_hit)) |val|
|
|
2703
2705
|
val == .true
|
|
2706
|
+
else if (@hasDecl(@TypeOf(battle.rng), "criticalHit"))
|
|
2707
|
+
battle.rng.criticalHit(player, rate)
|
|
2704
2708
|
else if (showdown)
|
|
2705
2709
|
battle.rng.chance(u8, rate, 256)
|
|
2706
2710
|
else
|
|
@@ -2713,6 +2717,8 @@ pub const Rolls = struct {
|
|
|
2713
2717
|
fn damage(battle: anytype, player: Player, options: anytype) !u8 {
|
|
2714
2718
|
const roll = if (options.calc.overridden(player, .damage)) |val|
|
|
2715
2719
|
val
|
|
2720
|
+
else if (@hasDecl(@TypeOf(battle.rng), "damage"))
|
|
2721
|
+
battle.rng.damage(player)
|
|
2716
2722
|
else roll: {
|
|
2717
2723
|
if (showdown) break :roll battle.rng.range(u8, 217, 256);
|
|
2718
2724
|
while (true) {
|
|
@@ -2729,6 +2735,8 @@ pub const Rolls = struct {
|
|
|
2729
2735
|
fn hit(battle: anytype, player: Player, accuracy: u8, options: anytype) bool {
|
|
2730
2736
|
const ok = if (options.calc.overridden(player, .hit)) |val|
|
|
2731
2737
|
val == .true
|
|
2738
|
+
else if (@hasDecl(@TypeOf(battle.rng), "hit"))
|
|
2739
|
+
battle.rng.hit(player, accuracy)
|
|
2732
2740
|
else if (showdown)
|
|
2733
2741
|
battle.rng.chance(u8, accuracy, 256)
|
|
2734
2742
|
else
|
|
@@ -2741,6 +2749,8 @@ pub const Rolls = struct {
|
|
|
2741
2749
|
fn confused(battle: anytype, player: Player, options: anytype) !bool {
|
|
2742
2750
|
const cfz = if (options.calc.overridden(player, .confused)) |val|
|
|
2743
2751
|
val == .true
|
|
2752
|
+
else if (@hasDecl(@TypeOf(battle.rng), "confused"))
|
|
2753
|
+
battle.rng.confused(player)
|
|
2744
2754
|
else if (showdown)
|
|
2745
2755
|
!battle.rng.chance(u8, 128, 256)
|
|
2746
2756
|
else
|
|
@@ -2753,6 +2763,8 @@ pub const Rolls = struct {
|
|
|
2753
2763
|
fn paralyzed(battle: anytype, player: Player, options: anytype) !bool {
|
|
2754
2764
|
const par = if (options.calc.overridden(player, .paralyzed)) |val|
|
|
2755
2765
|
val == .true
|
|
2766
|
+
else if (@hasDecl(@TypeOf(battle.rng), "paralyzed"))
|
|
2767
|
+
battle.rng.paralyzed(player)
|
|
2756
2768
|
else if (showdown)
|
|
2757
2769
|
battle.rng.chance(u8, 63, 256)
|
|
2758
2770
|
else
|
|
@@ -2765,6 +2777,8 @@ pub const Rolls = struct {
|
|
|
2765
2777
|
fn confusionChance(battle: anytype, player: Player, options: anytype) !bool {
|
|
2766
2778
|
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2767
2779
|
val == .true
|
|
2780
|
+
else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
|
|
2781
|
+
battle.rng.secondaryChance(player, 25)
|
|
2768
2782
|
else if (showdown)
|
|
2769
2783
|
battle.rng.chance(u8, 25, 256)
|
|
2770
2784
|
else
|
|
@@ -2779,6 +2793,8 @@ pub const Rolls = struct {
|
|
|
2779
2793
|
|
|
2780
2794
|
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2781
2795
|
val == .true
|
|
2796
|
+
else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
|
|
2797
|
+
battle.rng.secondaryChance(player, rate)
|
|
2782
2798
|
else if (showdown)
|
|
2783
2799
|
battle.rng.chance(u8, rate, 256)
|
|
2784
2800
|
else
|
|
@@ -2793,6 +2809,8 @@ pub const Rolls = struct {
|
|
|
2793
2809
|
|
|
2794
2810
|
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2795
2811
|
val == .true
|
|
2812
|
+
else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
|
|
2813
|
+
battle.rng.secondaryChance(player, rate)
|
|
2796
2814
|
else if (showdown)
|
|
2797
2815
|
battle.rng.chance(u8, rate, 256)
|
|
2798
2816
|
else
|
|
@@ -2805,6 +2823,8 @@ pub const Rolls = struct {
|
|
|
2805
2823
|
fn unboost(battle: anytype, player: Player, options: anytype) !bool {
|
|
2806
2824
|
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2807
2825
|
val == .true
|
|
2826
|
+
else if (@hasDecl(@TypeOf(battle.rng), "secondaryChance"))
|
|
2827
|
+
battle.rng.secondaryChance(player, 85)
|
|
2808
2828
|
else if (showdown)
|
|
2809
2829
|
battle.rng.chance(u8, 85, 256)
|
|
2810
2830
|
else
|
|
@@ -2817,6 +2837,8 @@ pub const Rolls = struct {
|
|
|
2817
2837
|
fn metronome(battle: anytype, player: Player, options: anytype) !Move {
|
|
2818
2838
|
const move: Move = if (options.calc.overridden(player, .metronome)) |val|
|
|
2819
2839
|
val
|
|
2840
|
+
else if (@hasDecl(@TypeOf(battle.rng), "metronome"))
|
|
2841
|
+
battle.rng.metronome(player)
|
|
2820
2842
|
else if (showdown)
|
|
2821
2843
|
Move.METRONOME[battle.rng.range(u8, 0, Move.METRONOME.len)]
|
|
2822
2844
|
else move: {
|
|
@@ -2835,6 +2857,8 @@ pub const Rolls = struct {
|
|
|
2835
2857
|
fn psywave(battle: anytype, player: Player, max: u8, options: anytype) !u8 {
|
|
2836
2858
|
const power = if (options.calc.overridden(player, .psywave)) |val|
|
|
2837
2859
|
val - 1
|
|
2860
|
+
else if (@hasDecl(@TypeOf(battle.rng), "psywave"))
|
|
2861
|
+
battle.rng.psywave(player)
|
|
2838
2862
|
else if (showdown)
|
|
2839
2863
|
battle.rng.range(u8, 0, max)
|
|
2840
2864
|
else power: {
|
|
@@ -2852,6 +2876,8 @@ pub const Rolls = struct {
|
|
|
2852
2876
|
fn sleepDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
2853
2877
|
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2854
2878
|
@intCast(val)
|
|
2879
|
+
else if (@hasDecl(@TypeOf(battle.rng), "sleepDuration"))
|
|
2880
|
+
battle.rng.sleepDuration(player)
|
|
2855
2881
|
else if (showdown)
|
|
2856
2882
|
battle.rng.range(u3, 1, 8)
|
|
2857
2883
|
else duration: {
|
|
@@ -2869,6 +2895,8 @@ pub const Rolls = struct {
|
|
|
2869
2895
|
fn disableDuration(battle: anytype, player: Player, options: anytype) u4 {
|
|
2870
2896
|
const duration: u4 = if (options.calc.overridden(player, .duration)) |val|
|
|
2871
2897
|
val
|
|
2898
|
+
else if (@hasDecl(@TypeOf(battle.rng), "disableDuration"))
|
|
2899
|
+
battle.rng.disableDuration(player)
|
|
2872
2900
|
else if (showdown)
|
|
2873
2901
|
battle.rng.range(u4, 1, 9)
|
|
2874
2902
|
else
|
|
@@ -2882,6 +2910,8 @@ pub const Rolls = struct {
|
|
|
2882
2910
|
fn confusionDuration(battle: anytype, player: Player, self: bool, options: anytype) u3 {
|
|
2883
2911
|
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2884
2912
|
@intCast(val)
|
|
2913
|
+
else if (@hasDecl(@TypeOf(battle.rng), "confusionDuration"))
|
|
2914
|
+
battle.rng.confusionDuration(player, self)
|
|
2885
2915
|
else if (showdown)
|
|
2886
2916
|
battle.rng.range(u3, 2, 6)
|
|
2887
2917
|
else
|
|
@@ -2895,6 +2925,8 @@ pub const Rolls = struct {
|
|
|
2895
2925
|
fn attackingDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
2896
2926
|
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
2897
2927
|
@intCast(val)
|
|
2928
|
+
else if (@hasDecl(@TypeOf(battle.rng), "attackingDuration"))
|
|
2929
|
+
battle.rng.attackingDuration(player)
|
|
2898
2930
|
else if (showdown)
|
|
2899
2931
|
battle.rng.range(u3, 2, 4)
|
|
2900
2932
|
else
|
|
@@ -2916,6 +2948,8 @@ pub const Rolls = struct {
|
|
|
2916
2948
|
const roll = if (effect == .Binding) .duration else .multi_hit;
|
|
2917
2949
|
const n: u3 = if (options.calc.overridden(player, roll)) |val|
|
|
2918
2950
|
@intCast(val)
|
|
2951
|
+
else if (@hasDecl(@TypeOf(battle.rng), "distribution"))
|
|
2952
|
+
battle.rng.distribution(player)
|
|
2919
2953
|
else if (showdown)
|
|
2920
2954
|
DISTRIBUTION[battle.rng.range(u3, 0, DISTRIBUTION.len)]
|
|
2921
2955
|
else n: {
|
|
@@ -2948,7 +2982,9 @@ pub const Rolls = struct {
|
|
|
2948
2982
|
else
|
|
2949
2983
|
null;
|
|
2950
2984
|
|
|
2951
|
-
const slot: u4 = overridden orelse
|
|
2985
|
+
const slot: u4 = overridden orelse if (@hasDecl(@TypeOf(battle.rng), "moveSlot"))
|
|
2986
|
+
battle.rng.moveSlot(player, moves, check_pp)
|
|
2987
|
+
else slot: {
|
|
2952
2988
|
if (showdown) {
|
|
2953
2989
|
if (check_pp == 0) {
|
|
2954
2990
|
var i: usize = moves.len;
|