@pkmn/engine 0.1.0-dev.6c5fdce2 → 0.1.0-dev.6cc9e067
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 +34 -11
- package/build/pkg/addon.js +6 -7
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +4 -5
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.js +4 -4
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js +2 -2
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js +2 -3
- package/build/tools/debug.js.map +1 -1
- package/build.zig +57 -60
- package/package.json +29 -22
- package/src/bin/install-pkmn-engine +26 -18
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/protocol.zig +16 -21
- package/src/lib/common/rng.zig +11 -11
- package/src/lib/gen1/chance.zig +27 -26
- package/src/lib/gen1/data/species.zig +1 -1
- package/src/lib/gen1/data.zig +18 -18
- package/src/lib/gen1/helpers.zig +35 -15
- package/src/lib/gen1/mechanics.zig +41 -14
- package/src/lib/gen2/chance.zig +38 -37
- package/src/lib/gen2/data.zig +8 -8
- package/src/lib/gen2/generated.zig +0 -2
- package/src/lib/gen2/helpers.zig +37 -7
- package/src/lib/gen2/mechanics.zig +112 -32
- package/src/lib/{binding/node.zig → node.zig} +3 -6
- package/src/lib/pkmn.zig +27 -12
- 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
|
@@ -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;
|
|
@@ -73,7 +73,7 @@ pub const ArgType = enum(u8) {
|
|
|
73
73
|
EndAbility,
|
|
74
74
|
ClearNegativeBoost,
|
|
75
75
|
FormeChange,
|
|
76
|
-
|
|
76
|
+
LastNoTarget, // FIXME
|
|
77
77
|
|
|
78
78
|
// Gen 4
|
|
79
79
|
SwapBoost,
|
|
@@ -220,6 +220,7 @@ pub const Activate = enum(u8) {
|
|
|
220
220
|
BeatUp, // FIXME of
|
|
221
221
|
|
|
222
222
|
Magnitude,
|
|
223
|
+
Spite,
|
|
223
224
|
};
|
|
224
225
|
|
|
225
226
|
pub const Start = enum(u8) {
|
|
@@ -544,6 +545,7 @@ pub fn Log(comptime Writer: type) type {
|
|
|
544
545
|
// ident: ID, reason: Activate
|
|
545
546
|
// ident: ID, reason: .SubstituteBlock, m: <Move>
|
|
546
547
|
// ident: ID, reason: .Magnitude, num: u8
|
|
548
|
+
// ident: ID, reason: .Spite, m: <Move>, num: u8
|
|
547
549
|
pub fn activate(self: Self, args: anytype) Error!void {
|
|
548
550
|
if (!enabled) return;
|
|
549
551
|
|
|
@@ -561,6 +563,9 @@ pub fn Log(comptime Writer: type) type {
|
|
|
561
563
|
assert(reason == .Magnitude);
|
|
562
564
|
try self.writer.writeByte(args[2]);
|
|
563
565
|
}
|
|
566
|
+
} else if (args.len == 4) {
|
|
567
|
+
assert(reason == .Spite);
|
|
568
|
+
try self.writer.writeAll(&.{ @intFromEnum(args[2]), args[3] });
|
|
564
569
|
}
|
|
565
570
|
}
|
|
566
571
|
|
|
@@ -1202,14 +1207,11 @@ pub fn expectLog(
|
|
|
1202
1207
|
) !void {
|
|
1203
1208
|
if (!enabled) return;
|
|
1204
1209
|
|
|
1205
|
-
const color =
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
} else {
|
|
1211
|
-
break :color std.io.getStdErr().supportsAnsiEscapeCodes();
|
|
1212
|
-
}
|
|
1210
|
+
const color = if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR"))
|
|
1211
|
+
true
|
|
1212
|
+
else switch (std.io.tty.detectConfig(std.io.getStdErr())) {
|
|
1213
|
+
.escape_codes => true,
|
|
1214
|
+
else => false,
|
|
1213
1215
|
};
|
|
1214
1216
|
|
|
1215
1217
|
expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
|
|
@@ -1248,20 +1250,13 @@ fn N(e: anytype) u8 {
|
|
|
1248
1250
|
const p1 = Player.P1;
|
|
1249
1251
|
const p2 = Player.P2;
|
|
1250
1252
|
|
|
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
1253
|
var buf: [pkmn.LOGS_SIZE]u8 = undefined;
|
|
1262
1254
|
var stream: ByteStream = .{ .buffer = &buf };
|
|
1263
1255
|
var log: FixedLog = .{ .writer = stream.writer() };
|
|
1264
1256
|
|
|
1257
|
+
const gen1 = pkmn.gen1;
|
|
1258
|
+
const gen2 = pkmn.gen2;
|
|
1259
|
+
|
|
1265
1260
|
const M1 = gen1.Move;
|
|
1266
1261
|
const S1 = gen1.Species;
|
|
1267
1262
|
|
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;
|
|
@@ -92,13 +92,14 @@ pub const Actions = extern struct {
|
|
|
92
92
|
}
|
|
93
93
|
};
|
|
94
94
|
|
|
95
|
+
// TODO: ziglang/zig#19730
|
|
95
96
|
test Actions {
|
|
96
97
|
const a: Actions = .{ .p1 = .{ .hit = .true, .critical_hit = .false, .damage = 245 } };
|
|
97
98
|
const b: Actions = .{ .p1 = .{ .hit = .false, .critical_hit = .true, .damage = 246 } };
|
|
98
99
|
const c: Actions = .{ .p1 = .{ .hit = .true } };
|
|
99
|
-
const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
|
|
100
|
-
const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
|
|
101
|
-
const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
|
|
100
|
+
// const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
|
|
101
|
+
// const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
|
|
102
|
+
// const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
|
|
102
103
|
|
|
103
104
|
try expect(a.eql(a));
|
|
104
105
|
try expect(!a.eql(b));
|
|
@@ -111,8 +112,8 @@ test Actions {
|
|
|
111
112
|
try expect(b.matches(a));
|
|
112
113
|
try expect(!a.matches(c));
|
|
113
114
|
try expect(!c.matches(a));
|
|
114
|
-
try expect(d.matches(e));
|
|
115
|
-
try expect(!d.matches(f));
|
|
115
|
+
// try expect(d.matches(e));
|
|
116
|
+
// try expect(!d.matches(f));
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
/// Information about the RNG that was observed during a Generation I battle `update` for a
|
|
@@ -706,19 +707,19 @@ test "Chance.damage" {
|
|
|
706
707
|
|
|
707
708
|
try chance.damage(.P1, 217);
|
|
708
709
|
if (showdown) {
|
|
709
|
-
try expectValue(
|
|
710
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
710
711
|
try expectProbability(&chance.probability, 1, 39);
|
|
711
712
|
} else {
|
|
712
713
|
try expectProbability(&chance.probability, 1, 1);
|
|
713
|
-
try expectValue(
|
|
714
|
+
try expectValue(0, chance.actions.p1.damage);
|
|
714
715
|
|
|
715
716
|
try chance.commit(.P1, .miss);
|
|
716
717
|
try expectProbability(&chance.probability, 1, 1);
|
|
717
|
-
try expectValue(
|
|
718
|
+
try expectValue(0, chance.actions.p1.damage);
|
|
718
719
|
|
|
719
720
|
try chance.commit(.P1, .hit);
|
|
720
721
|
try expectProbability(&chance.probability, 1, 39);
|
|
721
|
-
try expectValue(
|
|
722
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
722
723
|
}
|
|
723
724
|
}
|
|
724
725
|
|
|
@@ -770,13 +771,13 @@ test "Chance.moveSlot" {
|
|
|
770
771
|
|
|
771
772
|
try chance.moveSlot(.P2, 2, &ms, 2);
|
|
772
773
|
try expectProbability(&chance.probability, 1, 2);
|
|
773
|
-
try expectValue(
|
|
774
|
+
try expectValue(2, chance.actions.p2.move_slot);
|
|
774
775
|
|
|
775
776
|
chance.reset();
|
|
776
777
|
|
|
777
778
|
try chance.moveSlot(.P1, 1, &ms, 0);
|
|
778
779
|
try expectProbability(&chance.probability, 1, 3);
|
|
779
|
-
try expectValue(
|
|
780
|
+
try expectValue(1, chance.actions.p1.move_slot);
|
|
780
781
|
}
|
|
781
782
|
|
|
782
783
|
test "Chance.multiHit" {
|
|
@@ -784,32 +785,32 @@ test "Chance.multiHit" {
|
|
|
784
785
|
|
|
785
786
|
try chance.multiHit(.P1, 3);
|
|
786
787
|
try expectProbability(&chance.probability, 3, 8);
|
|
787
|
-
try expectValue(
|
|
788
|
+
try expectValue(3, chance.actions.p1.multi_hit);
|
|
788
789
|
|
|
789
790
|
chance.reset();
|
|
790
791
|
|
|
791
792
|
try chance.multiHit(.P2, 5);
|
|
792
793
|
try expectProbability(&chance.probability, 1, 8);
|
|
793
|
-
try expectValue(
|
|
794
|
+
try expectValue(5, chance.actions.p2.multi_hit);
|
|
794
795
|
}
|
|
795
796
|
|
|
796
797
|
test "Chance.duration" {
|
|
797
798
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
798
799
|
|
|
799
800
|
chance.duration(.sleep, .P1, .P2, 2);
|
|
800
|
-
try expectValue(
|
|
801
|
-
try expectValue(
|
|
801
|
+
try expectValue(2, chance.actions.p1.duration);
|
|
802
|
+
try expectValue(1, chance.actions.p2.durations.sleep);
|
|
802
803
|
|
|
803
804
|
chance.reset();
|
|
804
805
|
|
|
805
806
|
chance.duration(.binding, .P2, .P2, 4);
|
|
806
807
|
if (!showdown) {
|
|
807
|
-
try expectValue(
|
|
808
|
-
try expectValue(
|
|
808
|
+
try expectValue(0, chance.actions.p2.duration);
|
|
809
|
+
try expectValue(0, chance.actions.p2.durations.binding);
|
|
809
810
|
try chance.commit(.P2, .hit);
|
|
810
811
|
}
|
|
811
|
-
try expectValue(
|
|
812
|
-
try expectValue(
|
|
812
|
+
try expectValue(4, chance.actions.p2.duration);
|
|
813
|
+
try expectValue(1, chance.actions.p2.durations.binding);
|
|
813
814
|
}
|
|
814
815
|
|
|
815
816
|
test "Chance.sleep" {
|
|
@@ -819,7 +820,7 @@ test "Chance.sleep" {
|
|
|
819
820
|
chance.actions.p1.durations.sleep = @intCast(i);
|
|
820
821
|
try chance.sleep(.P1, 0);
|
|
821
822
|
try expectProbability(&chance.probability, 1, d);
|
|
822
|
-
try expectValue(
|
|
823
|
+
try expectValue(0, chance.actions.p1.durations.sleep);
|
|
823
824
|
|
|
824
825
|
chance.reset();
|
|
825
826
|
|
|
@@ -842,7 +843,7 @@ test "Chance.confusion" {
|
|
|
842
843
|
chance.actions.p2.durations.confusion = @intCast(i);
|
|
843
844
|
try chance.confusion(.P2, 0);
|
|
844
845
|
try expectProbability(&chance.probability, 1, d);
|
|
845
|
-
try expectValue(
|
|
846
|
+
try expectValue(0, chance.actions.p2.durations.confusion);
|
|
846
847
|
|
|
847
848
|
chance.reset();
|
|
848
849
|
}
|
|
@@ -865,7 +866,7 @@ test "Chance.disable" {
|
|
|
865
866
|
chance.actions.p1.durations.disable = @intCast(i);
|
|
866
867
|
try chance.disable(.P1, 0);
|
|
867
868
|
try expectProbability(&chance.probability, 1, d);
|
|
868
|
-
try expectValue(
|
|
869
|
+
try expectValue(0, chance.actions.p1.durations.disable);
|
|
869
870
|
|
|
870
871
|
chance.reset();
|
|
871
872
|
|
|
@@ -888,7 +889,7 @@ test "Chance.attacking" {
|
|
|
888
889
|
chance.actions.p2.durations.attacking = @intCast(i);
|
|
889
890
|
try chance.attacking(.P2, 0);
|
|
890
891
|
try expectProbability(&chance.probability, 1, d);
|
|
891
|
-
try expectValue(
|
|
892
|
+
try expectValue(0, chance.actions.p2.durations.attacking);
|
|
892
893
|
|
|
893
894
|
chance.reset();
|
|
894
895
|
}
|
|
@@ -914,7 +915,7 @@ test "Chance.binding" {
|
|
|
914
915
|
chance.actions.p1.durations.binding = @intCast(i);
|
|
915
916
|
try chance.binding(.P1, 0);
|
|
916
917
|
try expectProbability(&chance.probability, p, q);
|
|
917
|
-
try expectValue(
|
|
918
|
+
try expectValue(0, chance.actions.p1.durations.binding);
|
|
918
919
|
|
|
919
920
|
chance.reset();
|
|
920
921
|
|
|
@@ -934,7 +935,7 @@ test "Chance.psywave" {
|
|
|
934
935
|
|
|
935
936
|
try chance.psywave(.P2, 100, 150);
|
|
936
937
|
try expectProbability(&chance.probability, 1, 150);
|
|
937
|
-
try expectValue(
|
|
938
|
+
try expectValue(101, chance.actions.p2.psywave);
|
|
938
939
|
}
|
|
939
940
|
|
|
940
941
|
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
|
@@ -86,18 +86,38 @@ pub const Battle = struct {
|
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
fn prng(rand: *PSRNG) data.PRNG {
|
|
89
|
-
// GLITCH: initial bytes in seed can only range from 0-252, not 0-255
|
|
90
|
-
const max: u8 = 253;
|
|
91
89
|
return .{
|
|
92
90
|
.src = .{
|
|
93
91
|
.seed = if (showdown)
|
|
94
92
|
rand.newSeed()
|
|
95
|
-
else
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
else seed: {
|
|
94
|
+
// GLITCH: The initial RNG seed in Gen I link battles is heavily constrained
|
|
95
|
+
// https://www.smogon.com/forums/threads/rng-in-rby-link-battles.3746779
|
|
96
|
+
var seed = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
97
|
+
|
|
98
|
+
// Bytes in seed can only range from 0-252, not 0-255
|
|
99
|
+
const max: u8 = 253;
|
|
100
|
+
// Instructions take multiples of 4 cycles to execute
|
|
101
|
+
var timer: u16 = 4 * rand.range(u16, 0, 16384);
|
|
102
|
+
var add: u8 = rand.range(u8, 0, 256);
|
|
103
|
+
var carry: u8 = 0;
|
|
104
|
+
|
|
105
|
+
var i: u8 = 0;
|
|
106
|
+
while (i < seed.len) {
|
|
107
|
+
const div: u8 = @intCast(timer >> 8);
|
|
108
|
+
add +%= div +% carry;
|
|
109
|
+
if (add < max) {
|
|
110
|
+
seed[i] = add;
|
|
111
|
+
i += 1;
|
|
112
|
+
timer +%= 472;
|
|
113
|
+
carry = 1;
|
|
114
|
+
} else {
|
|
115
|
+
timer +%= 452;
|
|
116
|
+
carry = 0;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
break :seed seed;
|
|
120
|
+
},
|
|
101
121
|
},
|
|
102
122
|
};
|
|
103
123
|
}
|
|
@@ -478,12 +498,12 @@ test "Rolls.damage" {
|
|
|
478
498
|
test "Rolls.coalesce" {
|
|
479
499
|
var summaries =
|
|
480
500
|
calc.Summaries{ .p1 = .{ .damage = .{ .base = 74, .final = 69, .capped = true } } };
|
|
481
|
-
try expectEqual(
|
|
482
|
-
try expectEqual(
|
|
483
|
-
try expectEqual(
|
|
501
|
+
try expectEqual(0, try Rolls.coalesce(.P2, 0, &summaries, false));
|
|
502
|
+
try expectEqual(241, try Rolls.coalesce(.P2, 238, &summaries, false));
|
|
503
|
+
try expectEqual(255, try Rolls.coalesce(.P2, 238, &summaries, true));
|
|
484
504
|
summaries.p1.damage.final = 74;
|
|
485
|
-
try expectEqual(
|
|
486
|
-
try expectEqual(
|
|
505
|
+
try expectEqual(217, try Rolls.coalesce(.P2, 217, &summaries, false));
|
|
506
|
+
try expectEqual(255, try Rolls.coalesce(.P2, 217, &summaries, true));
|
|
487
507
|
}
|
|
488
508
|
|
|
489
509
|
test "Rolls.hit" {
|
|
@@ -771,9 +791,9 @@ test "Rolls.psywave" {
|
|
|
771
791
|
|
|
772
792
|
try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p1, &side, .None));
|
|
773
793
|
var rolls = Rolls.psywave(actions.p2, &side, .None);
|
|
774
|
-
try expectEqual(
|
|
794
|
+
try expectEqual(150, rolls[rolls.len - 1]);
|
|
775
795
|
side.stored().level = 81;
|
|
776
796
|
rolls = Rolls.psywave(actions.p2, &side, .None);
|
|
777
|
-
try expectEqual(
|
|
797
|
+
try expectEqual(121, rolls[rolls.len - 1]);
|
|
778
798
|
try expectEqualSlices(u8, &.{0}, Rolls.psywave(actions.p2, &side, .false));
|
|
779
799
|
}
|