@pkmn/engine 0.1.0-dev.a93847b2 → 0.1.0-dev.abd68573
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 +39 -16
- package/build/pkg/addon.js +6 -7
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +4 -4
- 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 +5 -5
- 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 +5 -4
- package/build/tools/debug.js.map +1 -1
- package/build.zig +90 -76
- package/package.json +31 -23
- package/src/bin/install-pkmn-engine +26 -18
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/protocol.zig +393 -396
- package/src/lib/common/rational.zig +11 -7
- package/src/lib/common/rng.zig +20 -11
- package/src/lib/gen1/calc.zig +7 -7
- package/src/lib/gen1/chance.zig +31 -30
- package/src/lib/gen1/data/moves.zig +9 -9
- package/src/lib/gen1/data/species.zig +2 -2
- package/src/lib/gen1/data/types.zig +4 -4
- package/src/lib/gen1/data.zig +32 -32
- package/src/lib/gen1/helpers.zig +48 -28
- package/src/lib/gen1/mechanics.zig +277 -255
- package/src/lib/gen2/calc.zig +1 -1
- package/src/lib/gen2/chance.zig +42 -41
- package/src/lib/gen2/data/items.zig +2 -2
- package/src/lib/gen2/data/moves.zig +2 -2
- package/src/lib/gen2/data/types.zig +9 -9
- package/src/lib/gen2/data.zig +23 -21
- package/src/lib/gen2/generated.zig +27 -78
- package/src/lib/gen2/mechanics.zig +1052 -459
- package/src/lib/{binding/node.zig → node.zig} +9 -12
- 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 -330
|
@@ -44,7 +44,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
44
44
|
/// Both p and q must be >= 1, and if computable at comptime must have no common factors.
|
|
45
45
|
pub fn update(r: *Self, p: anytype, q: anytype) Error!void {
|
|
46
46
|
// FIXME
|
|
47
|
-
// std.debug.print("({d}/{d}) * ", .{p, q});
|
|
47
|
+
// std.debug.print("({d}/{d}) * ", .{ p, q });
|
|
48
48
|
assert(p >= 1);
|
|
49
49
|
assert(q >= 1);
|
|
50
50
|
|
|
@@ -185,16 +185,16 @@ pub fn Rational(comptime T: type) type {
|
|
|
185
185
|
try writer.print("{d}/{d}", .{ self.p, self.q });
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
fn multiplication(r: *Self, p: anytype, q: anytype) !void {
|
|
189
189
|
r.p = try std.math.mul(T, r.p, p);
|
|
190
190
|
r.q = try std.math.mul(T, r.q, q);
|
|
191
191
|
}
|
|
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;
|
|
@@ -203,7 +203,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
// https://en.wikipedia.org/wiki/Euclidean_algorithm
|
|
206
|
-
|
|
206
|
+
fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
|
|
207
207
|
assert(p >= 1);
|
|
208
208
|
assert(q >= 1);
|
|
209
209
|
|
|
@@ -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/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;
|
|
@@ -25,6 +25,11 @@ pub fn PRNG(comptime gen: comptime_int) type {
|
|
|
25
25
|
pub fn next(self: *Self) Output(gen) {
|
|
26
26
|
return self.src.next();
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
pub fn advance(self: *Self, n: usize) void {
|
|
30
|
+
if (!options.advance) return;
|
|
31
|
+
for (0..n) |_| self.src.advance();
|
|
32
|
+
}
|
|
28
33
|
};
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -61,11 +66,15 @@ pub const PSRNG = extern struct {
|
|
|
61
66
|
(@as(u64, self.range(u16, 0, 0x10000)) << 16) |
|
|
62
67
|
(@as(u64, self.range(u16, 0, 0x10000)));
|
|
63
68
|
}
|
|
69
|
+
|
|
70
|
+
pub fn Bound(comptime T: type) type {
|
|
71
|
+
return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
|
|
72
|
+
}
|
|
64
73
|
};
|
|
65
74
|
|
|
66
75
|
test PSRNG {
|
|
67
76
|
var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
|
|
68
|
-
try expectEqual(
|
|
77
|
+
try expectEqual(121, psrng.range(u8, 0, 256));
|
|
69
78
|
try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
|
|
70
79
|
}
|
|
71
80
|
|
|
@@ -89,6 +98,10 @@ pub const Gen12 = extern struct {
|
|
|
89
98
|
self.index = (self.index + 1) % 9;
|
|
90
99
|
return val;
|
|
91
100
|
}
|
|
101
|
+
|
|
102
|
+
pub fn advance(self: *Gen12) void {
|
|
103
|
+
_ = self.next();
|
|
104
|
+
}
|
|
92
105
|
};
|
|
93
106
|
|
|
94
107
|
test Gen12 {
|
|
@@ -98,9 +111,9 @@ test Gen12 {
|
|
|
98
111
|
try expectEqual(e, rng.next());
|
|
99
112
|
}
|
|
100
113
|
|
|
101
|
-
try expectEqual(
|
|
102
|
-
try expectEqual(
|
|
103
|
-
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);
|
|
104
117
|
}
|
|
105
118
|
|
|
106
119
|
// https://pkmn.cc/pokeemerald/src/random.c
|
|
@@ -188,7 +201,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
188
201
|
for (0..n) |_| _ = self.next();
|
|
189
202
|
}
|
|
190
203
|
|
|
191
|
-
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 {
|
|
192
205
|
assert(showdown);
|
|
193
206
|
return @intCast(@as(u64, self.next()) * (to - from) / divisor + from);
|
|
194
207
|
}
|
|
@@ -197,7 +210,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
197
210
|
self: *Self,
|
|
198
211
|
comptime T: type,
|
|
199
212
|
numerator: T,
|
|
200
|
-
denominator: Bound(T),
|
|
213
|
+
denominator: PSRNG.Bound(T),
|
|
201
214
|
) bool {
|
|
202
215
|
assert(showdown);
|
|
203
216
|
assert(denominator > 0);
|
|
@@ -228,7 +241,3 @@ fn Output(comptime gen: comptime_int) type {
|
|
|
228
241
|
else => unreachable,
|
|
229
242
|
};
|
|
230
243
|
}
|
|
231
|
-
|
|
232
|
-
fn Bound(comptime T: type) type {
|
|
233
|
-
return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
|
|
234
|
-
}
|
package/src/lib/gen1/calc.zig
CHANGED
|
@@ -50,7 +50,7 @@ pub const Summaries = extern struct {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/// Returns the `Summary` for the given `player`.
|
|
53
|
-
pub
|
|
53
|
+
pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Summary) {
|
|
54
54
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Summaries);
|
|
55
55
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
56
56
|
}
|
|
@@ -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,
|
|
@@ -387,7 +387,7 @@ pub fn transitions(
|
|
|
387
387
|
return stats;
|
|
388
388
|
}
|
|
389
389
|
|
|
390
|
-
|
|
390
|
+
fn matches(actions: Actions, i: usize, frontier: []Actions) bool {
|
|
391
391
|
for (frontier, 0..) |f, j| {
|
|
392
392
|
// TODO: is skipping this redundant check worth it?
|
|
393
393
|
if (i == j) continue;
|
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;
|
|
@@ -37,19 +37,19 @@ pub const Actions = extern struct {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/// Returns the `Action` for the given `player`.
|
|
40
|
-
pub
|
|
40
|
+
pub fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Action) {
|
|
41
41
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Actions);
|
|
42
42
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/// Perform a reset by clearing fields which should not persist across updates.
|
|
46
|
-
pub
|
|
46
|
+
pub fn reset(self: *Actions) void {
|
|
47
47
|
self.p1.reset();
|
|
48
48
|
self.p2.reset();
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/// Returns true if `a` is equal to `b`.
|
|
52
|
-
pub
|
|
52
|
+
pub fn eql(a: Actions, b: Actions) bool {
|
|
53
53
|
return @as(u128, @bitCast(a)) == @as(u128, @bitCast(b));
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -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
|
|
@@ -159,7 +160,7 @@ pub const Action = packed struct(u64) {
|
|
|
159
160
|
pub const Field = std.meta.FieldEnum(Action);
|
|
160
161
|
|
|
161
162
|
/// Perform a reset by clearing fields which should not persist across updates.
|
|
162
|
-
pub
|
|
163
|
+
pub fn reset(self: *Action) void {
|
|
163
164
|
self.* = @bitCast(@as(u64, @bitCast(self.*)) & DURATIONS);
|
|
164
165
|
}
|
|
165
166
|
|
|
@@ -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" {
|
|
@@ -1599,43 +1599,43 @@ pub const Move = enum(u8) {
|
|
|
1599
1599
|
}
|
|
1600
1600
|
|
|
1601
1601
|
/// Whether this effect activates during the "begin" step of move execution.
|
|
1602
|
-
pub
|
|
1602
|
+
pub fn onBegin(effect: Effect) bool {
|
|
1603
1603
|
return @intFromEnum(effect) > 0 and @intFromEnum(effect) <= 16;
|
|
1604
1604
|
}
|
|
1605
1605
|
|
|
1606
1606
|
/// Whether this effect lowers stats.
|
|
1607
|
-
pub
|
|
1607
|
+
pub fn isStatDown(effect: Effect) bool {
|
|
1608
1608
|
return @intFromEnum(effect) > 16 and @intFromEnum(effect) <= 21;
|
|
1609
1609
|
}
|
|
1610
1610
|
|
|
1611
1611
|
/// Whether this effect activates during the "end" step of move execution.
|
|
1612
|
-
pub
|
|
1612
|
+
pub fn onEnd(effect: Effect) bool {
|
|
1613
1613
|
return @intFromEnum(effect) > 16 and @intFromEnum(effect) <= 31;
|
|
1614
1614
|
}
|
|
1615
1615
|
|
|
1616
1616
|
/// Whether this effect is considered to "always happen".
|
|
1617
|
-
pub
|
|
1617
|
+
pub fn alwaysHappens(effect: Effect) bool {
|
|
1618
1618
|
return @intFromEnum(effect) > 31 and @intFromEnum(effect) <= 38;
|
|
1619
1619
|
}
|
|
1620
1620
|
|
|
1621
1621
|
/// Whether this effect is handled specially by the engine.
|
|
1622
|
-
pub
|
|
1622
|
+
pub fn isSpecial(effect: Effect) bool {
|
|
1623
1623
|
// NB: isSpecial includes isMulti up to Twineedle
|
|
1624
1624
|
return @intFromEnum(effect) > 31 and @intFromEnum(effect) <= 46;
|
|
1625
1625
|
}
|
|
1626
1626
|
|
|
1627
1627
|
/// Whether this effect is a multi-hit effect.
|
|
1628
|
-
pub
|
|
1628
|
+
pub fn isMulti(effect: Effect) bool {
|
|
1629
1629
|
return @intFromEnum(effect) > 44 and @intFromEnum(effect) <= 47;
|
|
1630
1630
|
}
|
|
1631
1631
|
|
|
1632
1632
|
/// Whether this effect is has chance of lowering stats.
|
|
1633
|
-
pub
|
|
1633
|
+
pub fn isStatDownChance(effect: Effect) bool {
|
|
1634
1634
|
return @intFromEnum(effect) > 47 and @intFromEnum(effect) <= 51;
|
|
1635
1635
|
}
|
|
1636
1636
|
|
|
1637
1637
|
/// Whether this effect has a secondary chance.
|
|
1638
|
-
pub
|
|
1638
|
+
pub fn isSecondaryChance(effect: Effect) bool {
|
|
1639
1639
|
// NB: isSecondaryChance includes isStatDownChance as well as Twineedle
|
|
1640
1640
|
return (@intFromEnum(effect) > 46 and @intFromEnum(effect) <= 61);
|
|
1641
1641
|
}
|
|
@@ -1853,7 +1853,7 @@ pub const Move = enum(u8) {
|
|
|
1853
1853
|
};
|
|
1854
1854
|
|
|
1855
1855
|
/// Returns the `Data` corresponding to the move.
|
|
1856
|
-
pub
|
|
1856
|
+
pub fn get(id: Move) Data {
|
|
1857
1857
|
assert(id != .None and id != .SKIP_TURN);
|
|
1858
1858
|
return DATA[@intFromEnum(id) - 1];
|
|
1859
1859
|
}
|
|
@@ -1091,8 +1091,8 @@ 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
|
|
1095
|
-
pub
|
|
1094
|
+
/// The Pokémon's critical hit ratio out of 256.
|
|
1095
|
+
pub fn chance(id: Species) u8 {
|
|
1096
1096
|
assert(id != .None);
|
|
1097
1097
|
return CHANCES[@intFromEnum(id) - 1];
|
|
1098
1098
|
}
|
|
@@ -90,12 +90,12 @@ pub const Type = enum(u4) {
|
|
|
90
90
|
pub const size = 15;
|
|
91
91
|
|
|
92
92
|
/// Whether or not this type is considered to be special as opposed to physical.
|
|
93
|
-
pub
|
|
93
|
+
pub fn special(self: Type) bool {
|
|
94
94
|
return @intFromEnum(self) >= @intFromEnum(Type.Fire);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/// The `Effectiveness` of type `t2` vs. type `t1`.
|
|
98
|
-
pub
|
|
98
|
+
pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
|
|
99
99
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -120,12 +120,12 @@ pub const Types = packed struct {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/// Whether this typing is immune to type `t`.
|
|
123
|
-
pub
|
|
123
|
+
pub fn immune(self: Types, t: Type) bool {
|
|
124
124
|
return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/// Whether this typing includes type `t`.
|
|
128
|
-
pub
|
|
128
|
+
pub fn includes(self: Types, t: Type) bool {
|
|
129
129
|
return self.type1 == t or self.type2 == t;
|
|
130
130
|
}
|
|
131
131
|
};
|