@pkmn/engine 0.1.0-dev.d56bdadd → 0.1.0-dev.d73cd76c
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 +66 -32
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +47 -0
- package/build/pkg/addon/browser.js.map +1 -0
- package/build/pkg/addon/node.d.ts +3 -0
- package/build/pkg/addon/node.js +110 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon/wasm.d.ts +2 -0
- package/build/pkg/addon/wasm.js +53 -0
- package/build/pkg/addon/wasm.js.map +1 -0
- package/build/pkg/addon.d.ts +26 -4
- package/build/pkg/addon.js +39 -71
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/layout.json +15 -2
- package/build/pkg/data/protocol.json +23 -9
- package/build/pkg/data.d.ts +27 -5
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +15 -18
- package/build/pkg/gen1.js +28 -19
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +42 -91
- package/build/pkg/index.js +23 -70
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +29 -1
- package/build/pkg/protocol.js +109 -107
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +84 -73
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +66 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +152 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +360 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +157 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +357 -135
- package/package.json +61 -132
- package/src/bin/install-pkmn-engine +47 -21
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/bindings/c.zig +201 -0
- package/src/lib/{binding → bindings}/node.zig +15 -32
- package/src/lib/bindings/wasm.zig +51 -0
- package/src/lib/common/array.zig +70 -0
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/debug.zig +45 -29
- package/src/lib/common/js.zig +3 -7
- package/src/lib/common/optional.zig +27 -23
- package/src/lib/common/options.zig +6 -0
- package/src/lib/common/protocol.zig +565 -552
- package/src/lib/common/rational.zig +340 -253
- package/src/lib/common/rng.zig +7 -9
- package/src/lib/common/util.zig +53 -1
- package/src/lib/gen1/calc.zig +724 -175
- package/src/lib/gen1/chance.zig +486 -300
- package/src/lib/gen1/data/moves.zig +2 -4
- package/src/lib/gen1/data/species.zig +2 -4
- package/src/lib/gen1/data/types.zig +3 -4
- package/src/lib/gen1/data.zig +29 -32
- package/src/lib/gen1/helpers.zig +113 -561
- package/src/lib/gen1/mechanics.zig +611 -488
- package/src/lib/gen2/calc.zig +35 -28
- package/src/lib/gen2/chance.zig +111 -511
- package/src/lib/gen2/data/items.zig +1 -3
- package/src/lib/gen2/data/moves.zig +2 -4
- package/src/lib/gen2/data/species.zig +1 -3
- package/src/lib/gen2/data/types.zig +7 -5
- package/src/lib/gen2/data.zig +27 -29
- package/src/lib/gen2/generated.zig +22 -29
- package/src/lib/gen2/helpers.zig +68 -39
- package/src/lib/gen2/mechanics.zig +504 -430
- package/src/lib/napi.h +2 -0
- package/src/lib/node.zig +14 -0
- package/src/lib/pkmn.zig +125 -29
- package/src/lib/wasm.zig +13 -0
- package/src/tools/display/dom.ts +108 -0
- package/src/tools/display/ui.css +354 -0
- package/build/test/display.js +0 -400
- package/build/test/display.js.map +0 -1
- package/src/lib/binding/wasm.zig +0 -12
- package/src/lib/gen1/README.md +0 -894
- package/src/lib/gen2/README.md +0 -329
- package/src/test/display/pkmn.html.tmpl +0 -368
package/src/lib/gen2/chance.zig
CHANGED
|
@@ -8,18 +8,19 @@ const expectEqual = std.testing.expectEqual;
|
|
|
8
8
|
|
|
9
9
|
const options = @import("../common/options.zig");
|
|
10
10
|
const rational = @import("../common/rational.zig");
|
|
11
|
-
const rng = @import("../common/rng.zig");
|
|
12
11
|
const util = @import("../common/util.zig");
|
|
13
12
|
|
|
13
|
+
const Array = @import("../common/array.zig").Array;
|
|
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;
|
|
21
21
|
|
|
22
|
-
const
|
|
22
|
+
const PointerType = util.PointerType;
|
|
23
|
+
const isPointerTo = util.isPointerTo;
|
|
23
24
|
|
|
24
25
|
const Move = data.Move;
|
|
25
26
|
const Type = data.Type;
|
|
@@ -37,17 +38,11 @@ pub const Actions = extern struct {
|
|
|
37
38
|
p2: Action = .{},
|
|
38
39
|
|
|
39
40
|
/// Returns the `Action` for the given `player`.
|
|
40
|
-
pub fn get(self: anytype, player: Player)
|
|
41
|
-
assert(
|
|
41
|
+
pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Action) {
|
|
42
|
+
assert(isPointerTo(self, Actions));
|
|
42
43
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
/// Perform a reset by clearing fields which should not persist across updates.
|
|
46
|
-
pub fn reset(self: *Actions) void {
|
|
47
|
-
self.p1.reset();
|
|
48
|
-
self.p2.reset();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
46
|
/// Returns true if `a` is equal to `b`.
|
|
52
47
|
pub fn eql(a: Actions, b: Actions) bool {
|
|
53
48
|
return @as(u128, @bitCast(a.p1)) == @as(u128, @bitCast(b.p1)) and
|
|
@@ -58,24 +53,28 @@ pub const Actions = extern struct {
|
|
|
58
53
|
/// same shape if they have the same fields set (though those fields need not necessarily be
|
|
59
54
|
/// set to the same value).
|
|
60
55
|
pub fn matches(a: Actions, b: Actions) bool {
|
|
61
|
-
inline for (@typeInfo(Actions)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
inline for (if (@hasField(@TypeOf(@typeInfo(Actions).@"struct"), "fields"))
|
|
57
|
+
@typeInfo(Actions).@"struct".fields
|
|
58
|
+
else
|
|
59
|
+
@typeInfo(Actions).@"struct".field_names) |player|
|
|
60
|
+
{
|
|
61
|
+
const player_name = if (@hasField(@TypeOf(player), "name"))
|
|
62
|
+
player.name
|
|
63
|
+
else
|
|
64
|
+
player;
|
|
65
|
+
inline for (if (@hasField(@TypeOf(@typeInfo(Action).@"struct"), "fields"))
|
|
66
|
+
@typeInfo(Action).@"struct".fields
|
|
67
|
+
else
|
|
68
|
+
@typeInfo(Action).@"struct".field_names) |field|
|
|
69
|
+
{
|
|
70
|
+
const field_name = if (@hasField(@TypeOf(field), "name")) field.name else field;
|
|
71
|
+
const a_val = @field(@field(a, player_name), field_name);
|
|
72
|
+
const b_val = @field(@field(b, player_name), field_name);
|
|
65
73
|
|
|
66
74
|
switch (@typeInfo(@TypeOf(a_val))) {
|
|
67
|
-
|
|
68
|
-
const a_val_f = @field(a_val, f.name);
|
|
69
|
-
const b_val_f = @field(b_val, f.name);
|
|
70
|
-
switch (@typeInfo(@TypeOf(a_val_f))) {
|
|
71
|
-
.Int => if ((a_val_f > 0) != (b_val_f > 0)) return false,
|
|
72
|
-
.Bool => if (a_val_f != b_val_f) return false,
|
|
73
|
-
else => unreachable,
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
.Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
75
|
+
.@"enum" => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
77
76
|
return false,
|
|
78
|
-
.
|
|
77
|
+
.int => if ((a_val > 0) != (b_val > 0)) return false,
|
|
79
78
|
else => unreachable,
|
|
80
79
|
}
|
|
81
80
|
}
|
|
@@ -83,7 +82,7 @@ pub const Actions = extern struct {
|
|
|
83
82
|
return true;
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
pub fn fmt(self: Actions, writer:
|
|
85
|
+
pub fn fmt(self: Actions, writer: *std.Io.Writer, shape: bool) !void {
|
|
87
86
|
try writer.writeAll("<P1 = ");
|
|
88
87
|
try self.p1.fmt(writer, shape);
|
|
89
88
|
try writer.writeAll(", P2 = ");
|
|
@@ -91,22 +90,15 @@ pub const Actions = extern struct {
|
|
|
91
90
|
try writer.writeAll(">");
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
pub fn format(a: Actions,
|
|
95
|
-
_ = .{ f, o };
|
|
93
|
+
pub fn format(a: Actions, w: *std.Io.Writer) !void {
|
|
96
94
|
try fmt(a, w, false);
|
|
97
95
|
}
|
|
98
96
|
};
|
|
99
97
|
|
|
100
98
|
test Actions {
|
|
101
|
-
const a: Actions = .{ .p1 = .{ .hit = .true, .
|
|
102
|
-
const b: Actions = .{ .p1 = .{ .hit = .false, .
|
|
99
|
+
const a: Actions = .{ .p1 = .{ .hit = .true, .confused = .false, .damages = 245 } };
|
|
100
|
+
const b: Actions = .{ .p1 = .{ .hit = .false, .confused = .true, .damages = 246 } };
|
|
103
101
|
const c: Actions = .{ .p1 = .{ .hit = .true } };
|
|
104
|
-
const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
|
|
105
|
-
const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
|
|
106
|
-
const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
|
|
107
|
-
const g: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1 } } };
|
|
108
|
-
const h: Actions =
|
|
109
|
-
.{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1, .thrash = true } } };
|
|
110
102
|
|
|
111
103
|
try expect(a.eql(a));
|
|
112
104
|
try expect(!a.eql(b));
|
|
@@ -119,17 +111,21 @@ test Actions {
|
|
|
119
111
|
try expect(b.matches(a));
|
|
120
112
|
try expect(!a.matches(c));
|
|
121
113
|
try expect(!c.matches(a));
|
|
122
|
-
try expect(d.matches(e));
|
|
123
|
-
try expect(!d.matches(f));
|
|
124
|
-
try expect(!g.matches(h));
|
|
125
|
-
try expect(h.matches(h));
|
|
126
114
|
}
|
|
127
115
|
|
|
116
|
+
/// Observation made about a duration - whether the duration has started, been continued, or ended.
|
|
117
|
+
pub const Observation = enum { started, continuing, ended };
|
|
118
|
+
|
|
119
|
+
pub const Damages = Array(5, u8);
|
|
120
|
+
pub const Criticals = Array(5, Optional(bool));
|
|
121
|
+
|
|
128
122
|
/// Information about the RNG that was observed during a Generation II battle `update` for a
|
|
129
123
|
/// single player.
|
|
130
124
|
pub const Action = packed struct(u128) {
|
|
131
|
-
///
|
|
132
|
-
|
|
125
|
+
/// TODO
|
|
126
|
+
damages: Damages.T = 0,
|
|
127
|
+
// TODO
|
|
128
|
+
critical_hits: Criticals.T = 0,
|
|
133
129
|
|
|
134
130
|
/// If not None, the Player to be returned by Rolls.speedTie.
|
|
135
131
|
speed_tie: Optional(Player) = .None,
|
|
@@ -137,50 +133,58 @@ pub const Action = packed struct(u128) {
|
|
|
137
133
|
quick_claw: Optional(bool) = .None,
|
|
138
134
|
/// If not None, the value to return for Rolls.hit.
|
|
139
135
|
hit: Optional(bool) = .None,
|
|
140
|
-
/// If not None, the value to be returned by Rolls.criticalHit.
|
|
141
|
-
critical_hit: Optional(bool) = .None,
|
|
142
|
-
|
|
143
136
|
/// If not None, the value to return for Rolls.confused.
|
|
144
137
|
confused: Optional(bool) = .None,
|
|
138
|
+
|
|
145
139
|
/// If not None, the value to return for Rolls.attract.
|
|
146
140
|
attract: Optional(bool) = .None,
|
|
147
141
|
/// If not None, the value to return for Rolls.paralyzed.
|
|
148
142
|
paralyzed: Optional(bool) = .None,
|
|
149
143
|
/// If not None, the value to return for Rolls.defrost.
|
|
150
144
|
defrost: Optional(bool) = .None,
|
|
151
|
-
|
|
152
145
|
/// If not None, the value to be returned for Rolls.secondaryChance.
|
|
153
146
|
secondary_chance: Optional(bool) = .None,
|
|
147
|
+
|
|
154
148
|
/// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
|
|
155
149
|
item: Optional(bool) = .None,
|
|
156
150
|
/// If not None, the value to be returned for Rolls.protect.
|
|
157
151
|
protect: Optional(bool) = .None,
|
|
158
152
|
/// If not None, the value to return for Rolls.triAttack.
|
|
159
153
|
tri_attack: Optional(TriAttack) = .None,
|
|
154
|
+
/// If not 0, the value to return for Rolls.tripleKick.
|
|
155
|
+
triple_kick: u2 = 0,
|
|
160
156
|
|
|
161
157
|
/// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
|
|
162
158
|
present: u3 = 0,
|
|
163
159
|
/// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
|
|
164
160
|
magnitude: u3 = 0,
|
|
165
|
-
/// If not 0, the
|
|
166
|
-
triple_kick: u2 = 0,
|
|
167
|
-
|
|
168
|
-
/// If not 0, the amount of PP to deduct for Rolls.spite.
|
|
161
|
+
/// If not 0, the amount of PP to deduct for Rolls.spite.
|
|
169
162
|
spite: u3 = 0,
|
|
170
|
-
/// If not None, the value to return for Rolls.conversion2.
|
|
171
|
-
conversion_2: Optional(Type) = .None,
|
|
172
|
-
|
|
173
163
|
/// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
|
|
174
164
|
/// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
|
|
175
|
-
move_slot:
|
|
165
|
+
move_slot: u3 = 0,
|
|
176
166
|
/// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
|
|
177
167
|
/// invalid values (eg. due to empty party slots or fainted members) will be ignored.
|
|
178
|
-
force_switch:
|
|
179
|
-
|
|
168
|
+
force_switch: u3 = 0,
|
|
180
169
|
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
181
|
-
multi_hit:
|
|
170
|
+
multi_hit: u3 = 0,
|
|
171
|
+
|
|
172
|
+
sleep: Optional(Observation) = .None,
|
|
173
|
+
/// TODO
|
|
174
|
+
confusion: Optional(Observation) = .None,
|
|
175
|
+
/// TODO
|
|
176
|
+
disable: Optional(Observation) = .None,
|
|
177
|
+
/// TODO
|
|
178
|
+
attacking: Optional(Observation) = .None,
|
|
179
|
+
/// TODO
|
|
180
|
+
binding: Optional(Observation) = .None,
|
|
181
|
+
/// TODO
|
|
182
|
+
encore: Optional(Observation) = .None,
|
|
183
|
+
|
|
182
184
|
/// If not 0, the value to by one of the Rolls.*Duration rolls.
|
|
183
|
-
duration:
|
|
185
|
+
duration: u3 = 0,
|
|
186
|
+
/// If not None, the value to return for Rolls.conversion2.
|
|
187
|
+
conversion_2: Optional(Type) = .None,
|
|
184
188
|
|
|
185
189
|
/// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
|
|
186
190
|
psywave: u8 = 0,
|
|
@@ -188,63 +192,43 @@ pub const Action = packed struct(u128) {
|
|
|
188
192
|
/// If not None, the Move to return for Rolls.metronome.
|
|
189
193
|
metronome: Move = .None,
|
|
190
194
|
|
|
191
|
-
_: u16 = 0,
|
|
192
|
-
|
|
193
|
-
/// Observed values of various durations. Does not influence future RNG calls. TODO
|
|
194
|
-
durations: Duration = .{},
|
|
195
|
-
|
|
196
|
-
pub const DURATIONS: u128 = 0xFFFFFFFF00000000_0000000000000000;
|
|
197
|
-
|
|
198
195
|
pub const Field = std.meta.FieldEnum(Action);
|
|
199
196
|
|
|
200
|
-
|
|
201
|
-
pub fn reset(self: *Action) void {
|
|
202
|
-
self.* = @bitCast(@as(u128, @bitCast(self.*)) & DURATIONS);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
|
|
206
|
-
_ = .{ f, o };
|
|
197
|
+
pub fn format(a: Action, w: *std.Io.Writer) !void {
|
|
207
198
|
try fmt(a, w, false);
|
|
208
199
|
}
|
|
209
200
|
|
|
210
|
-
pub fn fmt(self: Action, writer:
|
|
201
|
+
pub fn fmt(self: Action, writer: *std.Io.Writer, shape: bool) !void {
|
|
211
202
|
try writer.writeByte('(');
|
|
212
203
|
var printed = false;
|
|
213
|
-
inline for (@typeInfo(Action)
|
|
214
|
-
|
|
204
|
+
inline for (if (@hasField(@TypeOf(@typeInfo(Action).@"struct"), "fields"))
|
|
205
|
+
@typeInfo(Action).@"struct".fields
|
|
206
|
+
else
|
|
207
|
+
@typeInfo(Action).@"struct".field_names) |field|
|
|
208
|
+
{
|
|
209
|
+
const field_name = if (@hasField(@TypeOf(field), "name")) field.name else field;
|
|
210
|
+
const val = @field(self, field_name);
|
|
215
211
|
switch (@typeInfo(@TypeOf(val))) {
|
|
216
|
-
|
|
217
|
-
const v = @field(val, f.name);
|
|
218
|
-
if (v != 0) {
|
|
219
|
-
if (printed) try writer.writeAll(", ");
|
|
220
|
-
if (shape) {
|
|
221
|
-
try writer.print("{s}:?", .{f.name});
|
|
222
|
-
} else {
|
|
223
|
-
try writer.print("{s}:{d}", .{ f.name, v });
|
|
224
|
-
}
|
|
225
|
-
printed = true;
|
|
226
|
-
}
|
|
227
|
-
},
|
|
228
|
-
.Enum => if (val != .None) {
|
|
212
|
+
.@"enum" => if (val != .None) {
|
|
229
213
|
if (printed) try writer.writeAll(", ");
|
|
230
214
|
if (shape) {
|
|
231
|
-
try writer.print("{s}:?", .{
|
|
215
|
+
try writer.print("{s}:?", .{field_name});
|
|
232
216
|
} else if (@TypeOf(val) == Optional(bool)) {
|
|
233
217
|
try writer.print("{s}{s}", .{
|
|
234
218
|
if (val == .false) "!" else "",
|
|
235
|
-
|
|
219
|
+
field_name,
|
|
236
220
|
});
|
|
237
221
|
} else {
|
|
238
|
-
try writer.print("{s}:{s}", .{
|
|
222
|
+
try writer.print("{s}:{s}", .{ field_name, @tagName(val) });
|
|
239
223
|
}
|
|
240
224
|
printed = true;
|
|
241
225
|
},
|
|
242
|
-
.
|
|
226
|
+
.int => if (val != 0) {
|
|
243
227
|
if (printed) try writer.writeAll(", ");
|
|
244
228
|
if (shape) {
|
|
245
|
-
try writer.print("{s}:?", .{
|
|
229
|
+
try writer.print("{s}:?", .{field_name});
|
|
246
230
|
} else {
|
|
247
|
-
try writer.print("{s}:{d}", .{
|
|
231
|
+
try writer.print("{s}:{d}", .{ field_name, val });
|
|
248
232
|
}
|
|
249
233
|
printed = true;
|
|
250
234
|
},
|
|
@@ -255,36 +239,6 @@ pub const Action = packed struct(u128) {
|
|
|
255
239
|
}
|
|
256
240
|
};
|
|
257
241
|
|
|
258
|
-
test Action {
|
|
259
|
-
var a: Action = .{ .hit = .true, .durations = .{ .sleep = 3 }, .damage = 225 };
|
|
260
|
-
a.reset();
|
|
261
|
-
|
|
262
|
-
try expectEqual(Action{ .hit = .None, .durations = .{ .sleep = 3 }, .damage = 0 }, a);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/// Observed values for various durations that need to be tracked in order to properly
|
|
266
|
-
/// deduplicate transitions with a primary key. TODO
|
|
267
|
-
pub const Duration = packed struct(u32) {
|
|
268
|
-
/// The number of turns a Pokémon has been observed to be sleeping.
|
|
269
|
-
sleep: u3 = 0,
|
|
270
|
-
/// The number of turns a Pokémon has been observed to be confused.
|
|
271
|
-
confusion: u3 = 0,
|
|
272
|
-
/// TODO
|
|
273
|
-
thrash: bool = false,
|
|
274
|
-
/// The number of turns a Pokémon has been observed to be disabled.
|
|
275
|
-
disable: u4 = 0,
|
|
276
|
-
/// The number of turns a Pokémon has been observed to be attacking.
|
|
277
|
-
attacking: u3 = 0,
|
|
278
|
-
/// The number of turns a Pokémon has been observed to be binding their opponent.
|
|
279
|
-
binding: u3 = 0,
|
|
280
|
-
/// The number of turns a Pokémon has been observed to be encored.
|
|
281
|
-
encore: u3 = 0,
|
|
282
|
-
|
|
283
|
-
_: u12 = 0,
|
|
284
|
-
|
|
285
|
-
pub const Field = std.meta.FieldEnum(Duration);
|
|
286
|
-
};
|
|
287
|
-
|
|
288
242
|
/// Tracks chance actions and their associated probability during a Generation II battle update when
|
|
289
243
|
/// `options.chance` is enabled.
|
|
290
244
|
pub fn Chance(comptime Rational: type) type {
|
|
@@ -297,37 +251,15 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
297
251
|
/// RNG events were observed during a battle `update`.
|
|
298
252
|
actions: Actions = .{},
|
|
299
253
|
|
|
300
|
-
// Tracks the observed sleep durations for the Pokémon in both player's parties. Unlike
|
|
301
|
-
// other durations which are all tied to volatiles, sleep's counter persists through
|
|
302
|
-
// switching and so we must store it here. The indices of these arrays correspond to the
|
|
303
|
-
// `order` field of a Side. This information could be stored in actions but size is a
|
|
304
|
-
// concern so this is tracked separately as actions only purports to track RNG events
|
|
305
|
-
// observed during a single `update` (not across updates).
|
|
306
|
-
sleeps: [2][6]u3 = .{ .{0} ** 6, .{0} ** 6 },
|
|
307
|
-
|
|
308
254
|
/// Possible error returned by operations tracking chance probability.
|
|
309
255
|
pub const Error = Rational.Error;
|
|
310
256
|
|
|
311
257
|
/// Convenience helper to clear fields which typically should be cleared between updates.
|
|
312
258
|
pub fn reset(self: *Self) void {
|
|
313
|
-
self.probability.reset();
|
|
314
|
-
self.actions.reset();
|
|
315
|
-
// TODO: self.pending = .{};
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
pub fn switched(self: *Self, player: Player, in: u8, out: u8) void {
|
|
319
259
|
if (!enabled) return;
|
|
320
260
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
var action = self.actions.get(player);
|
|
325
|
-
|
|
326
|
-
const slp = action.durations.sleep;
|
|
327
|
-
action.durations = .{};
|
|
328
|
-
|
|
329
|
-
self.sleeps[@intFromEnum(player)][out - 1] = slp;
|
|
330
|
-
action.durations.sleep = @intCast(self.sleeps[@intFromEnum(player)][in - 1]);
|
|
261
|
+
self.probability.reset();
|
|
262
|
+
self.actions = .{};
|
|
331
263
|
}
|
|
332
264
|
|
|
333
265
|
pub fn speedTie(self: *Self, p1: bool) Error!void {
|
|
@@ -353,19 +285,21 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
353
285
|
self.actions.get(player).hit = if (ok) .true else .false;
|
|
354
286
|
}
|
|
355
287
|
|
|
356
|
-
pub fn criticalHit(self: *Self, player: Player, crit: bool, rate: u8) Error!void {
|
|
288
|
+
pub fn criticalHit(self: *Self, player: Player, i: u3, crit: bool, rate: u8) Error!void {
|
|
357
289
|
if (!enabled) return;
|
|
358
290
|
|
|
359
291
|
const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
|
|
360
292
|
try self.probability.update(n, 256);
|
|
361
|
-
self.actions.get(player)
|
|
293
|
+
var a = self.actions.get(player);
|
|
294
|
+
a.critical_hits = Criticals.set(a.critical_hits, i, if (crit) .true else .false);
|
|
362
295
|
}
|
|
363
296
|
|
|
364
|
-
pub fn damage(self: *Self, player: Player, roll: u8) Error!void {
|
|
297
|
+
pub fn damage(self: *Self, player: Player, i: u3, roll: u8) Error!void {
|
|
365
298
|
if (!enabled) return;
|
|
366
299
|
|
|
367
300
|
try self.probability.update(1, 39);
|
|
368
|
-
self.actions.get(player)
|
|
301
|
+
var a = self.actions.get(player);
|
|
302
|
+
a.damages = Damages.set(a.damages, i, roll);
|
|
369
303
|
}
|
|
370
304
|
|
|
371
305
|
pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
|
|
@@ -517,122 +451,10 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
517
451
|
self.actions.get(player).multi_hit = n;
|
|
518
452
|
}
|
|
519
453
|
|
|
520
|
-
pub fn duration(
|
|
521
|
-
self: *Self,
|
|
522
|
-
comptime field: Duration.Field,
|
|
523
|
-
player: Player,
|
|
524
|
-
target: Player,
|
|
525
|
-
turns: u4,
|
|
526
|
-
) void {
|
|
527
|
-
if (!enabled) return;
|
|
528
|
-
|
|
529
|
-
var durations = &self.actions.get(target).durations;
|
|
530
|
-
assert(@field(durations, @tagName(field)) == 0 or
|
|
531
|
-
(field == .confusion and player == target));
|
|
532
|
-
@field(durations, @tagName(field)) = 1;
|
|
533
|
-
if (field == .confusion) durations.thrash = player == target;
|
|
534
|
-
self.actions.get(player).duration = if (options.key) 1 else turns;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
pub fn sleep(self: *Self, player: Player, turns: u4) Error!void {
|
|
454
|
+
pub fn duration(self: *Self, player: Player, turns: u3) void {
|
|
538
455
|
if (!enabled) return;
|
|
539
456
|
|
|
540
|
-
|
|
541
|
-
const n = durations.sleep;
|
|
542
|
-
if (turns == 0) {
|
|
543
|
-
assert(n >= 1 and n <= 6);
|
|
544
|
-
if (n != 6) try self.probability.update(1, 7 - @as(u4, n));
|
|
545
|
-
durations.sleep = 0;
|
|
546
|
-
} else {
|
|
547
|
-
assert(n >= 1 and n < 6);
|
|
548
|
-
try self.probability.update(7 - @as(u4, n) - 1, 7 - @as(u4, n));
|
|
549
|
-
durations.sleep += 1;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
pub fn confusion(self: *Self, player: Player, turns: u4) Error!void {
|
|
554
|
-
if (!enabled) return;
|
|
555
|
-
|
|
556
|
-
var durations = &self.actions.get(player).durations;
|
|
557
|
-
const n = durations.confusion;
|
|
558
|
-
const hi: u8 = if (durations.thrash) 3 else 5;
|
|
559
|
-
const p = hi + 1;
|
|
560
|
-
if (turns == 0) {
|
|
561
|
-
assert(n >= 2 and n <= hi);
|
|
562
|
-
if (n != hi) try self.probability.update(1, p - @as(u4, n));
|
|
563
|
-
durations.confusion = 0;
|
|
564
|
-
} else {
|
|
565
|
-
assert(n >= 1 and n < hi);
|
|
566
|
-
if (n > 1) try self.probability.update(p - @as(u4, n) - 1, p - @as(u4, n));
|
|
567
|
-
durations.confusion += 1;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
pub fn disable(self: *Self, player: Player, turns: u4) Error!void {
|
|
572
|
-
if (!enabled) return;
|
|
573
|
-
|
|
574
|
-
var durations = &self.actions.get(player).durations;
|
|
575
|
-
const n = durations.disable;
|
|
576
|
-
const hi = if (showdown) 5 else 8;
|
|
577
|
-
const p = hi + 1;
|
|
578
|
-
if (turns == 0) {
|
|
579
|
-
assert(n >= 2 and n <= hi);
|
|
580
|
-
if (n != hi) try self.probability.update(1, p - n);
|
|
581
|
-
durations.disable = 0;
|
|
582
|
-
} else {
|
|
583
|
-
assert(n >= 1 and n < hi);
|
|
584
|
-
if (n > 1) try self.probability.update(p - n - 1, p - n);
|
|
585
|
-
durations.disable += 1;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
pub fn attacking(self: *Self, player: Player, turns: u4) Error!void {
|
|
590
|
-
if (!enabled) return;
|
|
591
|
-
|
|
592
|
-
var durations = &self.actions.get(player).durations;
|
|
593
|
-
const n = durations.attacking;
|
|
594
|
-
if (turns == 0) {
|
|
595
|
-
assert(n >= 2 and n <= 3);
|
|
596
|
-
if (n != 3) try self.probability.update(1, 4 - @as(u4, n));
|
|
597
|
-
durations.attacking = 0;
|
|
598
|
-
} else {
|
|
599
|
-
assert(n >= 1 and n < 3);
|
|
600
|
-
if (n > 1) try self.probability.update(4 - @as(u4, n) - 1, 4 - @as(u4, n));
|
|
601
|
-
durations.attacking += 1;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
pub fn binding(self: *Self, player: Player, turns: u4) Error!void {
|
|
606
|
-
if (!enabled) return;
|
|
607
|
-
|
|
608
|
-
var durations = &self.actions.get(player).durations;
|
|
609
|
-
const n = durations.binding;
|
|
610
|
-
if (turns == 0) {
|
|
611
|
-
assert(n >= 2 and n <= 5);
|
|
612
|
-
if (n != 5) try self.probability.update(1, 6 - @as(u4, n));
|
|
613
|
-
durations.binding = 0;
|
|
614
|
-
} else {
|
|
615
|
-
assert(n >= 1 and n < 5);
|
|
616
|
-
if (n > 1) try self.probability.update(6 - @as(u4, n) - 1, 6 - @as(u4, n));
|
|
617
|
-
durations.binding += 1;
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// TODO: consider sharing implementation with binding
|
|
622
|
-
pub fn encore(self: *Self, player: Player, turns: u4) Error!void {
|
|
623
|
-
if (!enabled) return;
|
|
624
|
-
|
|
625
|
-
var durations = &self.actions.get(player).durations;
|
|
626
|
-
const n = durations.encore;
|
|
627
|
-
if (turns == 0) {
|
|
628
|
-
assert(n >= 2 and n <= 5);
|
|
629
|
-
if (n != 5) try self.probability.update(1, 6 - @as(u4, n));
|
|
630
|
-
durations.encore = 0;
|
|
631
|
-
} else {
|
|
632
|
-
assert(n >= 1 and n < 5);
|
|
633
|
-
if (n > 1) try self.probability.update(6 - @as(u4, n) - 1, 6 - @as(u4, n));
|
|
634
|
-
durations.encore += 1;
|
|
635
|
-
}
|
|
457
|
+
self.actions.get(player).duration = if (options.key) 2 else turns;
|
|
636
458
|
}
|
|
637
459
|
};
|
|
638
460
|
}
|
|
@@ -684,22 +506,22 @@ test "Chance.hit" {
|
|
|
684
506
|
test "Chance.criticalHit" {
|
|
685
507
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
686
508
|
|
|
687
|
-
try chance.criticalHit(.P1, true, 17);
|
|
688
|
-
try expectValue(Optional(bool).true, chance.actions.p1.
|
|
509
|
+
try chance.criticalHit(.P1, 0, true, 17);
|
|
510
|
+
try expectValue(Optional(bool).true, Criticals.get(chance.actions.p1.critical_hits, 0));
|
|
689
511
|
try expectProbability(&chance.probability, 17, 256);
|
|
690
512
|
|
|
691
513
|
chance.reset();
|
|
692
514
|
|
|
693
|
-
try chance.criticalHit(.P2, false, 5);
|
|
515
|
+
try chance.criticalHit(.P2, 1, false, 5);
|
|
694
516
|
try expectProbability(&chance.probability, 251, 256);
|
|
695
|
-
try expectValue(Optional(bool).false, chance.actions.p2.
|
|
517
|
+
try expectValue(Optional(bool).false, Criticals.get(chance.actions.p2.critical_hits, 1));
|
|
696
518
|
}
|
|
697
519
|
|
|
698
520
|
test "Chance.damage" {
|
|
699
521
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
700
522
|
|
|
701
|
-
try chance.damage(.P1,
|
|
702
|
-
try expectValue(@as(u8,
|
|
523
|
+
try chance.damage(.P1, 0, 219);
|
|
524
|
+
try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
|
|
703
525
|
try expectProbability(&chance.probability, 1, 39);
|
|
704
526
|
}
|
|
705
527
|
|
|
@@ -915,19 +737,19 @@ test "Chance.moveSlot" {
|
|
|
915
737
|
|
|
916
738
|
try chance.moveSlot(.P2, 2, 2);
|
|
917
739
|
try expectProbability(&chance.probability, 1, 2);
|
|
918
|
-
try expectValue(@as(
|
|
740
|
+
try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
|
|
919
741
|
|
|
920
742
|
chance.reset();
|
|
921
743
|
|
|
922
744
|
try chance.moveSlot(.P1, 1, 3);
|
|
923
745
|
try expectProbability(&chance.probability, 1, 3);
|
|
924
|
-
try expectValue(@as(
|
|
746
|
+
try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
|
|
925
747
|
|
|
926
748
|
chance.reset();
|
|
927
749
|
|
|
928
750
|
try chance.moveSlot(.P1, 4, 1);
|
|
929
751
|
try expectProbability(&chance.probability, 1, 1);
|
|
930
|
-
try expectValue(@as(
|
|
752
|
+
try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
|
|
931
753
|
}
|
|
932
754
|
|
|
933
755
|
test "Chance.forceSwitch" {
|
|
@@ -935,19 +757,19 @@ test "Chance.forceSwitch" {
|
|
|
935
757
|
|
|
936
758
|
try chance.forceSwitch(.P2, 2, 2);
|
|
937
759
|
try expectProbability(&chance.probability, 1, 2);
|
|
938
|
-
try expectValue(@as(
|
|
760
|
+
try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
|
|
939
761
|
|
|
940
762
|
chance.reset();
|
|
941
763
|
|
|
942
764
|
try chance.forceSwitch(.P1, 1, 3);
|
|
943
765
|
try expectProbability(&chance.probability, 1, 3);
|
|
944
|
-
try expectValue(@as(
|
|
766
|
+
try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
|
|
945
767
|
|
|
946
768
|
chance.reset();
|
|
947
769
|
|
|
948
770
|
try chance.forceSwitch(.P1, 4, 1);
|
|
949
771
|
try expectProbability(&chance.probability, 1, 1);
|
|
950
|
-
try expectValue(@as(
|
|
772
|
+
try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
|
|
951
773
|
}
|
|
952
774
|
|
|
953
775
|
test "Chance.multiHit" {
|
|
@@ -955,212 +777,20 @@ test "Chance.multiHit" {
|
|
|
955
777
|
|
|
956
778
|
try chance.multiHit(.P1, 3);
|
|
957
779
|
try expectProbability(&chance.probability, 3, 8);
|
|
958
|
-
try expectValue(@as(
|
|
780
|
+
try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
|
|
959
781
|
|
|
960
782
|
chance.reset();
|
|
961
783
|
|
|
962
784
|
try chance.multiHit(.P2, 5);
|
|
963
785
|
try expectProbability(&chance.probability, 1, 8);
|
|
964
|
-
try expectValue(@as(
|
|
786
|
+
try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
|
|
965
787
|
}
|
|
966
788
|
|
|
967
789
|
test "Chance.duration" {
|
|
968
790
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
969
791
|
|
|
970
|
-
chance.duration(.
|
|
971
|
-
try expectValue(@as(
|
|
972
|
-
try expectValue(@as(u3, 1), chance.actions.p2.durations.sleep);
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
test "Chance.sleep" {
|
|
976
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
977
|
-
|
|
978
|
-
for ([_]u8{ 6, 5, 4, 3, 2, 1 }, 1..7) |d, i| {
|
|
979
|
-
chance.actions.p1.durations.sleep = @intCast(i);
|
|
980
|
-
try chance.sleep(.P1, 0);
|
|
981
|
-
try expectProbability(&chance.probability, 1, d);
|
|
982
|
-
try expectValue(@as(u3, 0), chance.actions.p1.durations.sleep);
|
|
983
|
-
|
|
984
|
-
chance.reset();
|
|
985
|
-
|
|
986
|
-
if (i < 6) {
|
|
987
|
-
chance.actions.p1.durations.sleep = @intCast(i);
|
|
988
|
-
try chance.sleep(.P1, 1);
|
|
989
|
-
try expectProbability(&chance.probability, d - 1, d);
|
|
990
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p1.durations.sleep);
|
|
991
|
-
|
|
992
|
-
chance.reset();
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
test "Chance.confusion" {
|
|
998
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
999
|
-
|
|
1000
|
-
chance.actions.p2.durations.thrash = false;
|
|
1001
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1002
|
-
if (i > 1) {
|
|
1003
|
-
chance.actions.p2.durations.confusion = @intCast(i);
|
|
1004
|
-
try chance.confusion(.P2, 0);
|
|
1005
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1006
|
-
try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
|
|
1007
|
-
try expectValue(false, chance.actions.p2.durations.thrash);
|
|
1008
|
-
|
|
1009
|
-
chance.reset();
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
if (i < 5) {
|
|
1013
|
-
chance.actions.p2.durations.confusion = @intCast(i);
|
|
1014
|
-
try chance.confusion(.P2, 1);
|
|
1015
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1016
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.confusion);
|
|
1017
|
-
try expectValue(false, chance.actions.p2.durations.thrash);
|
|
1018
|
-
|
|
1019
|
-
chance.reset();
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
chance.reset();
|
|
1024
|
-
|
|
1025
|
-
chance.actions.p2.durations.thrash = true;
|
|
1026
|
-
for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
|
|
1027
|
-
if (i > 1) {
|
|
1028
|
-
chance.actions.p2.durations.confusion = @intCast(i);
|
|
1029
|
-
try chance.confusion(.P2, 0);
|
|
1030
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1031
|
-
try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
|
|
1032
|
-
try expectValue(true, chance.actions.p2.durations.thrash);
|
|
1033
|
-
|
|
1034
|
-
chance.reset();
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
if (i < 3) {
|
|
1038
|
-
chance.actions.p2.durations.confusion = @intCast(i);
|
|
1039
|
-
try chance.confusion(.P2, 1);
|
|
1040
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1041
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.confusion);
|
|
1042
|
-
try expectValue(true, chance.actions.p2.durations.thrash);
|
|
1043
|
-
|
|
1044
|
-
chance.reset();
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
test "Chance.disable" {
|
|
1050
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1051
|
-
if (showdown) {
|
|
1052
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1053
|
-
if (i > 1) {
|
|
1054
|
-
chance.actions.p2.durations.disable = @intCast(i);
|
|
1055
|
-
try chance.disable(.P2, 0);
|
|
1056
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1057
|
-
try expectValue(@as(u4, 0), chance.actions.p2.durations.disable);
|
|
1058
|
-
|
|
1059
|
-
chance.reset();
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
if (i < 5) {
|
|
1063
|
-
chance.actions.p2.durations.disable = @intCast(i);
|
|
1064
|
-
try chance.disable(.P2, 1);
|
|
1065
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1066
|
-
try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p2.durations.disable);
|
|
1067
|
-
|
|
1068
|
-
chance.reset();
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
} else {
|
|
1072
|
-
for ([_]u8{ 1, 7, 6, 5, 4, 3, 2, 1 }, 1..9) |d, i| {
|
|
1073
|
-
if (i > 1) {
|
|
1074
|
-
chance.actions.p2.durations.disable = @intCast(i);
|
|
1075
|
-
try chance.disable(.P2, 0);
|
|
1076
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1077
|
-
try expectValue(@as(u4, 0), chance.actions.p2.durations.disable);
|
|
1078
|
-
|
|
1079
|
-
chance.reset();
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
if (i < 8) {
|
|
1083
|
-
chance.actions.p2.durations.disable = @intCast(i);
|
|
1084
|
-
try chance.disable(.P2, 1);
|
|
1085
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1086
|
-
try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p2.durations.disable);
|
|
1087
|
-
|
|
1088
|
-
chance.reset();
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
test "Chance.attacking" {
|
|
1095
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1096
|
-
|
|
1097
|
-
for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
|
|
1098
|
-
if (i > 1) {
|
|
1099
|
-
chance.actions.p2.durations.attacking = @intCast(i);
|
|
1100
|
-
try chance.attacking(.P2, 0);
|
|
1101
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1102
|
-
try expectValue(@as(u3, 0), chance.actions.p2.durations.attacking);
|
|
1103
|
-
|
|
1104
|
-
chance.reset();
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
if (i < 3) {
|
|
1108
|
-
chance.actions.p2.durations.attacking = @intCast(i);
|
|
1109
|
-
try chance.attacking(.P2, 1);
|
|
1110
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1111
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.attacking);
|
|
1112
|
-
|
|
1113
|
-
chance.reset();
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
test "Chance.binding" {
|
|
1119
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1120
|
-
|
|
1121
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1122
|
-
if (i > 1) {
|
|
1123
|
-
chance.actions.p2.durations.binding = @intCast(i);
|
|
1124
|
-
try chance.binding(.P2, 0);
|
|
1125
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1126
|
-
try expectValue(@as(u3, 0), chance.actions.p2.durations.binding);
|
|
1127
|
-
|
|
1128
|
-
chance.reset();
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
if (i < 5) {
|
|
1132
|
-
chance.actions.p2.durations.binding = @intCast(i);
|
|
1133
|
-
try chance.binding(.P2, 1);
|
|
1134
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1135
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.binding);
|
|
1136
|
-
|
|
1137
|
-
chance.reset();
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
test "Chance.encore" {
|
|
1143
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1144
|
-
|
|
1145
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1146
|
-
if (i > 1) {
|
|
1147
|
-
chance.actions.p2.durations.encore = @intCast(i);
|
|
1148
|
-
try chance.encore(.P2, 0);
|
|
1149
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1150
|
-
try expectValue(@as(u3, 0), chance.actions.p2.durations.encore);
|
|
1151
|
-
|
|
1152
|
-
chance.reset();
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
if (i < 5) {
|
|
1156
|
-
chance.actions.p2.durations.encore = @intCast(i);
|
|
1157
|
-
try chance.encore(.P2, 1);
|
|
1158
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1159
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.encore);
|
|
1160
|
-
|
|
1161
|
-
chance.reset();
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
792
|
+
chance.duration(.P1, 2);
|
|
793
|
+
try expectValue(@as(u3, 2), chance.actions.p1.duration);
|
|
1164
794
|
}
|
|
1165
795
|
|
|
1166
796
|
pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
@@ -1168,7 +798,7 @@ pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
|
1168
798
|
|
|
1169
799
|
r.reduce();
|
|
1170
800
|
if (r.p != p or r.q != q) {
|
|
1171
|
-
print("expected {d}/{d}, found {}\n", .{ p, q, r });
|
|
801
|
+
print("expected {d}/{d}, found {f}\n", .{ p, q, r });
|
|
1172
802
|
return error.TestExpectedEqual;
|
|
1173
803
|
}
|
|
1174
804
|
}
|
|
@@ -1202,12 +832,12 @@ const Null = struct {
|
|
|
1202
832
|
_ = .{ self, player, ok, accuracy };
|
|
1203
833
|
}
|
|
1204
834
|
|
|
1205
|
-
pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
|
|
1206
|
-
_ = .{ self, player, crit, rate };
|
|
835
|
+
pub fn criticalHit(self: Null, player: Player, i: u3, crit: bool, rate: u8) Error!void {
|
|
836
|
+
_ = .{ self, player, i, crit, rate };
|
|
1207
837
|
}
|
|
1208
838
|
|
|
1209
|
-
pub fn damage(self: Null, player: Player, roll: u8) Error!void {
|
|
1210
|
-
_ = .{ self, player, roll };
|
|
839
|
+
pub fn damage(self: Null, player: Player, i: u3, roll: u8) Error!void {
|
|
840
|
+
_ = .{ self, player, i, roll };
|
|
1211
841
|
}
|
|
1212
842
|
|
|
1213
843
|
pub fn confused(self: Null, player: Player, ok: bool) Error!void {
|
|
@@ -1278,37 +908,7 @@ const Null = struct {
|
|
|
1278
908
|
_ = .{ self, player, move, n };
|
|
1279
909
|
}
|
|
1280
910
|
|
|
1281
|
-
pub fn duration(
|
|
1282
|
-
self: Null,
|
|
1283
|
-
comptime field: Duration.Field,
|
|
1284
|
-
player: Player,
|
|
1285
|
-
target: Player,
|
|
1286
|
-
turns: u4,
|
|
1287
|
-
) void {
|
|
1288
|
-
_ = .{ self, field, player, target, turns };
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
pub fn sleep(self: Null, player: Player, turns: u4) Error!void {
|
|
1292
|
-
_ = .{ self, player, turns };
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
pub fn confusion(self: Null, player: Player, turns: u4) Error!void {
|
|
1296
|
-
_ = .{ self, player, turns };
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
pub fn disable(self: Null, player: Player, turns: u4) Error!void {
|
|
1300
|
-
_ = .{ self, player, turns };
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
pub fn attacking(self: Null, player: Player, turns: u4) Error!void {
|
|
1304
|
-
_ = .{ self, player, turns };
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
pub fn binding(self: Null, player: Player, turns: u4) Error!void {
|
|
1308
|
-
_ = .{ self, player, turns };
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
pub fn encore(self: Null, player: Player, turns: u4) Error!void {
|
|
911
|
+
pub fn duration(self: Null, player: Player, turns: u3) void {
|
|
1312
912
|
_ = .{ self, player, turns };
|
|
1313
913
|
}
|
|
1314
914
|
};
|