@pkmn/engine 0.1.0-dev.44b2e6ec → 0.1.0-dev.44c4a618
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 +13 -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 +67 -86
- 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/debug.zig +2 -2
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/options.zig +2 -0
- package/src/lib/common/protocol.zig +15 -20
- package/src/lib/common/rng.zig +11 -11
- package/src/lib/gen1/calc.zig +81 -0
- package/src/lib/gen1/chance.zig +33 -30
- package/src/lib/gen1/data/species.zig +1 -1
- package/src/lib/gen1/data.zig +21 -21
- package/src/lib/gen1/helpers.zig +102 -15
- package/src/lib/gen1/mechanics.zig +46 -8
- package/src/lib/gen2/chance.zig +38 -37
- package/src/lib/gen2/data.zig +8 -8
- package/src/lib/gen2/helpers.zig +37 -7
- package/src/lib/gen2/mechanics.zig +112 -27
- package/src/lib/{binding/node.zig → node.zig} +3 -2
- 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;
|
|
@@ -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/calc.zig
CHANGED
|
@@ -387,6 +387,87 @@ pub fn transitions(
|
|
|
387
387
|
return stats;
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
+
pub fn update(
|
|
391
|
+
battle: anytype,
|
|
392
|
+
c1: Choice,
|
|
393
|
+
c2: Choice,
|
|
394
|
+
options: anytype,
|
|
395
|
+
allocator: std.mem.Allocator,
|
|
396
|
+
writer: anytype,
|
|
397
|
+
transition: bool,
|
|
398
|
+
) !Result {
|
|
399
|
+
options.chance.reset();
|
|
400
|
+
|
|
401
|
+
if (!pkmn.options.chance or !pkmn.options.calc or @TypeOf(battle.rng) != data.PRNG) {
|
|
402
|
+
return battle.update(c1, c2, options);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
var copy = battle.*;
|
|
406
|
+
const actions = options.chance.actions;
|
|
407
|
+
|
|
408
|
+
// Perfom the actual update
|
|
409
|
+
const result = battle.update(c1, c2, options);
|
|
410
|
+
|
|
411
|
+
// Ensure we can encode the diffs in less than MAX_DIFFS bytes.
|
|
412
|
+
var buf: [helpers.MAX_DIFFS]u8 = undefined;
|
|
413
|
+
var stream: protocol.ByteStream = .{ .buffer = &buf };
|
|
414
|
+
const n = try helpers.diff(©, battle, stream.writer());
|
|
415
|
+
|
|
416
|
+
// Applying the diff to the battle should take us back to the original copy
|
|
417
|
+
// of the battle (ignoring the RNG).
|
|
418
|
+
var patched = battle.*;
|
|
419
|
+
copy.rng = patched.rng;
|
|
420
|
+
helpers.patch(&patched, buf[0..n]);
|
|
421
|
+
try expectEqual(copy, patched);
|
|
422
|
+
|
|
423
|
+
if (!pkmn.options.chance or !pkmn.options.calc) return result;
|
|
424
|
+
|
|
425
|
+
if (transition) {
|
|
426
|
+
// Ensure we can generate all transitions from the same original state
|
|
427
|
+
// (we must change the battle's RNG from a FixedRNG to a PRNG because
|
|
428
|
+
// the transitions function relies on RNG for discovery of states)
|
|
429
|
+
const stats = try transitions(unfix(copy), c1, c2, allocator, writer, .{
|
|
430
|
+
.actions = actions,
|
|
431
|
+
.cap = true,
|
|
432
|
+
});
|
|
433
|
+
DEBUG(stats);
|
|
434
|
+
// TODO try expect(stats.frontier < pkmn.gen1.MAX_FRONTIER_SIZE);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Demonstrate that we can produce the same state by forcing the RNG to behave the
|
|
438
|
+
// same as we observed - note that because we do not pass in a durations override
|
|
439
|
+
// mask none of the durations will be extended.
|
|
440
|
+
var override = pkmn.battle.options(
|
|
441
|
+
protocol.NULL,
|
|
442
|
+
chance.NULL,
|
|
443
|
+
Calc{ .overrides = .{ .actions = actions } },
|
|
444
|
+
);
|
|
445
|
+
const overridden = copy.update(c1, c2, &override);
|
|
446
|
+
try expectEqual(result, overridden);
|
|
447
|
+
|
|
448
|
+
// The actual battle excluding its RNG field should match a copy updated with
|
|
449
|
+
// overridden RNG (the copy RNG may have advanced because of no-ops)
|
|
450
|
+
copy.rng = battle.rng;
|
|
451
|
+
try expectEqual(copy, battle.*);
|
|
452
|
+
|
|
453
|
+
return result;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
fn unfix(actual: anytype) data.Battle(data.PRNG) {
|
|
457
|
+
return .{
|
|
458
|
+
.sides = actual.sides,
|
|
459
|
+
.turn = actual.turn,
|
|
460
|
+
.last_damage = actual.last_damage,
|
|
461
|
+
.last_moves = actual.last_moves,
|
|
462
|
+
.rng = .{ .src = .{
|
|
463
|
+
.seed = if (pkmn.options.showdown)
|
|
464
|
+
0x12345678
|
|
465
|
+
else
|
|
466
|
+
.{ 123, 234, 56, 78, 9, 101, 112, 131, 4 },
|
|
467
|
+
} },
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
390
471
|
fn matches(actions: Actions, i: usize, frontier: []Actions) bool {
|
|
391
472
|
for (frontier, 0..) |f, j| {
|
|
392
473
|
// TODO: is skipping this redundant check worth it?
|
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
|
|
@@ -254,6 +255,8 @@ pub const Duration = packed struct(u16) {
|
|
|
254
255
|
|
|
255
256
|
pub const Commit = enum { hit, miss, binding };
|
|
256
257
|
|
|
258
|
+
const uN = if (options.miss) u8 else u9;
|
|
259
|
+
|
|
257
260
|
/// Tracks chance actions and their associated probability during a Generation I battle update when
|
|
258
261
|
/// `options.chance` is enabled.
|
|
259
262
|
pub fn Chance(comptime Rational: type) type {
|
|
@@ -292,13 +295,13 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
292
295
|
// shared structure to track this information (though it needs to be cleared appropriately)
|
|
293
296
|
pending: if (showdown) struct {
|
|
294
297
|
hit: bool = false,
|
|
295
|
-
hit_probablity:
|
|
298
|
+
hit_probablity: uN = 0,
|
|
296
299
|
} else struct {
|
|
297
300
|
crit: bool = false,
|
|
298
301
|
crit_probablity: u8 = 0,
|
|
299
302
|
damage_roll: u8 = 0,
|
|
300
303
|
hit: bool = false,
|
|
301
|
-
hit_probablity:
|
|
304
|
+
hit_probablity: uN = 0,
|
|
302
305
|
binding: u8 = 0,
|
|
303
306
|
} = .{},
|
|
304
307
|
|
|
@@ -397,7 +400,7 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
397
400
|
self.actions.p2.speed_tie = self.actions.p1.speed_tie;
|
|
398
401
|
}
|
|
399
402
|
|
|
400
|
-
pub fn hit(self: *Self, ok: bool, accuracy:
|
|
403
|
+
pub fn hit(self: *Self, ok: bool, accuracy: uN) void {
|
|
401
404
|
if (!enabled) return;
|
|
402
405
|
|
|
403
406
|
const p = if (ok) accuracy else @as(u8, @intCast(256 - @as(u9, accuracy)));
|
|
@@ -706,19 +709,19 @@ test "Chance.damage" {
|
|
|
706
709
|
|
|
707
710
|
try chance.damage(.P1, 217);
|
|
708
711
|
if (showdown) {
|
|
709
|
-
try expectValue(
|
|
712
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
710
713
|
try expectProbability(&chance.probability, 1, 39);
|
|
711
714
|
} else {
|
|
712
715
|
try expectProbability(&chance.probability, 1, 1);
|
|
713
|
-
try expectValue(
|
|
716
|
+
try expectValue(0, chance.actions.p1.damage);
|
|
714
717
|
|
|
715
718
|
try chance.commit(.P1, .miss);
|
|
716
719
|
try expectProbability(&chance.probability, 1, 1);
|
|
717
|
-
try expectValue(
|
|
720
|
+
try expectValue(0, chance.actions.p1.damage);
|
|
718
721
|
|
|
719
722
|
try chance.commit(.P1, .hit);
|
|
720
723
|
try expectProbability(&chance.probability, 1, 39);
|
|
721
|
-
try expectValue(
|
|
724
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
722
725
|
}
|
|
723
726
|
}
|
|
724
727
|
|
|
@@ -770,13 +773,13 @@ test "Chance.moveSlot" {
|
|
|
770
773
|
|
|
771
774
|
try chance.moveSlot(.P2, 2, &ms, 2);
|
|
772
775
|
try expectProbability(&chance.probability, 1, 2);
|
|
773
|
-
try expectValue(
|
|
776
|
+
try expectValue(2, chance.actions.p2.move_slot);
|
|
774
777
|
|
|
775
778
|
chance.reset();
|
|
776
779
|
|
|
777
780
|
try chance.moveSlot(.P1, 1, &ms, 0);
|
|
778
781
|
try expectProbability(&chance.probability, 1, 3);
|
|
779
|
-
try expectValue(
|
|
782
|
+
try expectValue(1, chance.actions.p1.move_slot);
|
|
780
783
|
}
|
|
781
784
|
|
|
782
785
|
test "Chance.multiHit" {
|
|
@@ -784,32 +787,32 @@ test "Chance.multiHit" {
|
|
|
784
787
|
|
|
785
788
|
try chance.multiHit(.P1, 3);
|
|
786
789
|
try expectProbability(&chance.probability, 3, 8);
|
|
787
|
-
try expectValue(
|
|
790
|
+
try expectValue(3, chance.actions.p1.multi_hit);
|
|
788
791
|
|
|
789
792
|
chance.reset();
|
|
790
793
|
|
|
791
794
|
try chance.multiHit(.P2, 5);
|
|
792
795
|
try expectProbability(&chance.probability, 1, 8);
|
|
793
|
-
try expectValue(
|
|
796
|
+
try expectValue(5, chance.actions.p2.multi_hit);
|
|
794
797
|
}
|
|
795
798
|
|
|
796
799
|
test "Chance.duration" {
|
|
797
800
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
798
801
|
|
|
799
802
|
chance.duration(.sleep, .P1, .P2, 2);
|
|
800
|
-
try expectValue(
|
|
801
|
-
try expectValue(
|
|
803
|
+
try expectValue(2, chance.actions.p1.duration);
|
|
804
|
+
try expectValue(1, chance.actions.p2.durations.sleep);
|
|
802
805
|
|
|
803
806
|
chance.reset();
|
|
804
807
|
|
|
805
808
|
chance.duration(.binding, .P2, .P2, 4);
|
|
806
809
|
if (!showdown) {
|
|
807
|
-
try expectValue(
|
|
808
|
-
try expectValue(
|
|
810
|
+
try expectValue(0, chance.actions.p2.duration);
|
|
811
|
+
try expectValue(0, chance.actions.p2.durations.binding);
|
|
809
812
|
try chance.commit(.P2, .hit);
|
|
810
813
|
}
|
|
811
|
-
try expectValue(
|
|
812
|
-
try expectValue(
|
|
814
|
+
try expectValue(4, chance.actions.p2.duration);
|
|
815
|
+
try expectValue(1, chance.actions.p2.durations.binding);
|
|
813
816
|
}
|
|
814
817
|
|
|
815
818
|
test "Chance.sleep" {
|
|
@@ -819,7 +822,7 @@ test "Chance.sleep" {
|
|
|
819
822
|
chance.actions.p1.durations.sleep = @intCast(i);
|
|
820
823
|
try chance.sleep(.P1, 0);
|
|
821
824
|
try expectProbability(&chance.probability, 1, d);
|
|
822
|
-
try expectValue(
|
|
825
|
+
try expectValue(0, chance.actions.p1.durations.sleep);
|
|
823
826
|
|
|
824
827
|
chance.reset();
|
|
825
828
|
|
|
@@ -842,7 +845,7 @@ test "Chance.confusion" {
|
|
|
842
845
|
chance.actions.p2.durations.confusion = @intCast(i);
|
|
843
846
|
try chance.confusion(.P2, 0);
|
|
844
847
|
try expectProbability(&chance.probability, 1, d);
|
|
845
|
-
try expectValue(
|
|
848
|
+
try expectValue(0, chance.actions.p2.durations.confusion);
|
|
846
849
|
|
|
847
850
|
chance.reset();
|
|
848
851
|
}
|
|
@@ -865,7 +868,7 @@ test "Chance.disable" {
|
|
|
865
868
|
chance.actions.p1.durations.disable = @intCast(i);
|
|
866
869
|
try chance.disable(.P1, 0);
|
|
867
870
|
try expectProbability(&chance.probability, 1, d);
|
|
868
|
-
try expectValue(
|
|
871
|
+
try expectValue(0, chance.actions.p1.durations.disable);
|
|
869
872
|
|
|
870
873
|
chance.reset();
|
|
871
874
|
|
|
@@ -888,7 +891,7 @@ test "Chance.attacking" {
|
|
|
888
891
|
chance.actions.p2.durations.attacking = @intCast(i);
|
|
889
892
|
try chance.attacking(.P2, 0);
|
|
890
893
|
try expectProbability(&chance.probability, 1, d);
|
|
891
|
-
try expectValue(
|
|
894
|
+
try expectValue(0, chance.actions.p2.durations.attacking);
|
|
892
895
|
|
|
893
896
|
chance.reset();
|
|
894
897
|
}
|
|
@@ -914,7 +917,7 @@ test "Chance.binding" {
|
|
|
914
917
|
chance.actions.p1.durations.binding = @intCast(i);
|
|
915
918
|
try chance.binding(.P1, 0);
|
|
916
919
|
try expectProbability(&chance.probability, p, q);
|
|
917
|
-
try expectValue(
|
|
920
|
+
try expectValue(0, chance.actions.p1.durations.binding);
|
|
918
921
|
|
|
919
922
|
chance.reset();
|
|
920
923
|
|
|
@@ -934,7 +937,7 @@ test "Chance.psywave" {
|
|
|
934
937
|
|
|
935
938
|
try chance.psywave(.P2, 100, 150);
|
|
936
939
|
try expectProbability(&chance.probability, 1, 150);
|
|
937
|
-
try expectValue(
|
|
940
|
+
try expectValue(101, chance.actions.p2.psywave);
|
|
938
941
|
}
|
|
939
942
|
|
|
940
943
|
test "Chance.metronome" {
|
|
@@ -988,7 +991,7 @@ const Null = struct {
|
|
|
988
991
|
_ = .{ self, p1 };
|
|
989
992
|
}
|
|
990
993
|
|
|
991
|
-
pub fn hit(self: Null, ok: bool, accuracy:
|
|
994
|
+
pub fn hit(self: Null, ok: bool, accuracy: uN) void {
|
|
992
995
|
_ = .{ self, ok, accuracy };
|
|
993
996
|
}
|
|
994
997
|
|
|
@@ -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
|
@@ -22,11 +22,11 @@ const expect = std.testing.expect;
|
|
|
22
22
|
|
|
23
23
|
/// The minimum size in bytes required to hold all Generation I choice options.
|
|
24
24
|
pub const MAX_CHOICES: usize = 9; // move 1..4, switch 2..6
|
|
25
|
-
/// The
|
|
26
|
-
/// At least as large as MAX_CHOICES.
|
|
25
|
+
/// The maximum number of bytes possibly logged by a single Generation I update.
|
|
27
26
|
pub const MAX_LOGS: usize = 180;
|
|
28
27
|
|
|
29
|
-
/// The
|
|
28
|
+
/// The optimal size in bytes required to hold all Generation I choice options.
|
|
29
|
+
/// At least as large as MAX_CHOICES.
|
|
30
30
|
pub const CHOICES_SIZE = if (builtin.mode == .ReleaseSmall)
|
|
31
31
|
MAX_CHOICES
|
|
32
32
|
else
|
|
@@ -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
|
}
|