@pkmn/engine 0.1.0-dev.80019d10 → 0.1.0-dev.8058a1d0
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 +59 -24
- 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 -75
- 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 +259 -112
- 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 +200 -0
- package/src/lib/{binding → bindings}/node.zig +15 -32
- package/src/lib/bindings/wasm.zig +50 -0
- package/src/lib/common/array.zig +70 -0
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/debug.zig +33 -28
- package/src/lib/common/js.zig +3 -7
- package/src/lib/common/optional.zig +12 -18
- package/src/lib/common/options.zig +6 -0
- package/src/lib/common/protocol.zig +256 -224
- package/src/lib/common/rational.zig +340 -253
- package/src/lib/common/rng.zig +7 -9
- package/src/lib/common/util.zig +33 -1
- package/src/lib/gen1/calc.zig +724 -175
- package/src/lib/gen1/chance.zig +453 -291
- 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 +91 -549
- package/src/lib/gen1/mechanics.zig +417 -294
- package/src/lib/gen2/calc.zig +35 -28
- package/src/lib/gen2/chance.zig +85 -503
- 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 +19 -26
- package/src/lib/gen2/helpers.zig +45 -26
- package/src/lib/gen2/mechanics.zig +234 -180
- 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,15 @@ 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
|
-
inline for (@typeInfo(Action).
|
|
56
|
+
inline for (@typeInfo(Actions).@"struct".fields) |player| {
|
|
57
|
+
inline for (@typeInfo(Action).@"struct".fields) |field| {
|
|
63
58
|
const a_val = @field(@field(a, player.name), field.name);
|
|
64
59
|
const b_val = @field(@field(b, player.name), field.name);
|
|
65
60
|
|
|
66
61
|
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))
|
|
62
|
+
.@"enum" => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
77
63
|
return false,
|
|
78
|
-
.
|
|
64
|
+
.int => if ((a_val > 0) != (b_val > 0)) return false,
|
|
79
65
|
else => unreachable,
|
|
80
66
|
}
|
|
81
67
|
}
|
|
@@ -83,7 +69,7 @@ pub const Actions = extern struct {
|
|
|
83
69
|
return true;
|
|
84
70
|
}
|
|
85
71
|
|
|
86
|
-
pub fn fmt(self: Actions, writer:
|
|
72
|
+
pub fn fmt(self: Actions, writer: *std.Io.Writer, shape: bool) !void {
|
|
87
73
|
try writer.writeAll("<P1 = ");
|
|
88
74
|
try self.p1.fmt(writer, shape);
|
|
89
75
|
try writer.writeAll(", P2 = ");
|
|
@@ -91,22 +77,15 @@ pub const Actions = extern struct {
|
|
|
91
77
|
try writer.writeAll(">");
|
|
92
78
|
}
|
|
93
79
|
|
|
94
|
-
pub fn format(a: Actions,
|
|
95
|
-
_ = .{ f, o };
|
|
80
|
+
pub fn format(a: Actions, w: *std.Io.Writer) !void {
|
|
96
81
|
try fmt(a, w, false);
|
|
97
82
|
}
|
|
98
83
|
};
|
|
99
84
|
|
|
100
85
|
test Actions {
|
|
101
|
-
const a: Actions = .{ .p1 = .{ .hit = .true, .
|
|
102
|
-
const b: Actions = .{ .p1 = .{ .hit = .false, .
|
|
86
|
+
const a: Actions = .{ .p1 = .{ .hit = .true, .confused = .false, .damages = 245 } };
|
|
87
|
+
const b: Actions = .{ .p1 = .{ .hit = .false, .confused = .true, .damages = 246 } };
|
|
103
88
|
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
89
|
|
|
111
90
|
try expect(a.eql(a));
|
|
112
91
|
try expect(!a.eql(b));
|
|
@@ -119,17 +98,21 @@ test Actions {
|
|
|
119
98
|
try expect(b.matches(a));
|
|
120
99
|
try expect(!a.matches(c));
|
|
121
100
|
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
101
|
}
|
|
127
102
|
|
|
103
|
+
/// Observation made about a duration - whether the duration has started, been continued, or ended.
|
|
104
|
+
pub const Observation = enum { started, continuing, ended };
|
|
105
|
+
|
|
106
|
+
pub const Damages = Array(5, u8);
|
|
107
|
+
pub const Criticals = Array(5, Optional(bool));
|
|
108
|
+
|
|
128
109
|
/// Information about the RNG that was observed during a Generation II battle `update` for a
|
|
129
110
|
/// single player.
|
|
130
111
|
pub const Action = packed struct(u128) {
|
|
131
|
-
///
|
|
132
|
-
|
|
112
|
+
/// TODO
|
|
113
|
+
damages: Damages.T = 0,
|
|
114
|
+
// TODO
|
|
115
|
+
critical_hits: Criticals.T = 0,
|
|
133
116
|
|
|
134
117
|
/// If not None, the Player to be returned by Rolls.speedTie.
|
|
135
118
|
speed_tie: Optional(Player) = .None,
|
|
@@ -137,50 +120,58 @@ pub const Action = packed struct(u128) {
|
|
|
137
120
|
quick_claw: Optional(bool) = .None,
|
|
138
121
|
/// If not None, the value to return for Rolls.hit.
|
|
139
122
|
hit: Optional(bool) = .None,
|
|
140
|
-
/// If not None, the value to be returned by Rolls.criticalHit.
|
|
141
|
-
critical_hit: Optional(bool) = .None,
|
|
142
|
-
|
|
143
123
|
/// If not None, the value to return for Rolls.confused.
|
|
144
124
|
confused: Optional(bool) = .None,
|
|
125
|
+
|
|
145
126
|
/// If not None, the value to return for Rolls.attract.
|
|
146
127
|
attract: Optional(bool) = .None,
|
|
147
128
|
/// If not None, the value to return for Rolls.paralyzed.
|
|
148
129
|
paralyzed: Optional(bool) = .None,
|
|
149
130
|
/// If not None, the value to return for Rolls.defrost.
|
|
150
131
|
defrost: Optional(bool) = .None,
|
|
151
|
-
|
|
152
132
|
/// If not None, the value to be returned for Rolls.secondaryChance.
|
|
153
133
|
secondary_chance: Optional(bool) = .None,
|
|
134
|
+
|
|
154
135
|
/// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
|
|
155
136
|
item: Optional(bool) = .None,
|
|
156
137
|
/// If not None, the value to be returned for Rolls.protect.
|
|
157
138
|
protect: Optional(bool) = .None,
|
|
158
139
|
/// If not None, the value to return for Rolls.triAttack.
|
|
159
140
|
tri_attack: Optional(TriAttack) = .None,
|
|
141
|
+
/// If not 0, the value to return for Rolls.tripleKick.
|
|
142
|
+
triple_kick: u2 = 0,
|
|
160
143
|
|
|
161
144
|
/// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
|
|
162
145
|
present: u3 = 0,
|
|
163
146
|
/// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
|
|
164
147
|
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.
|
|
148
|
+
/// If not 0, the amount of PP to deduct for Rolls.spite.
|
|
169
149
|
spite: u3 = 0,
|
|
170
|
-
/// If not None, the value to return for Rolls.conversion2.
|
|
171
|
-
conversion_2: Optional(Type) = .None,
|
|
172
|
-
|
|
173
150
|
/// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
|
|
174
151
|
/// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
|
|
175
|
-
move_slot:
|
|
152
|
+
move_slot: u3 = 0,
|
|
176
153
|
/// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
|
|
177
154
|
/// invalid values (eg. due to empty party slots or fainted members) will be ignored.
|
|
178
|
-
force_switch:
|
|
179
|
-
|
|
155
|
+
force_switch: u3 = 0,
|
|
180
156
|
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
181
|
-
multi_hit:
|
|
157
|
+
multi_hit: u3 = 0,
|
|
158
|
+
|
|
159
|
+
sleep: Optional(Observation) = .None,
|
|
160
|
+
/// TODO
|
|
161
|
+
confusion: Optional(Observation) = .None,
|
|
162
|
+
/// TODO
|
|
163
|
+
disable: Optional(Observation) = .None,
|
|
164
|
+
/// TODO
|
|
165
|
+
attacking: Optional(Observation) = .None,
|
|
166
|
+
/// TODO
|
|
167
|
+
binding: Optional(Observation) = .None,
|
|
168
|
+
/// TODO
|
|
169
|
+
encore: Optional(Observation) = .None,
|
|
170
|
+
|
|
182
171
|
/// If not 0, the value to by one of the Rolls.*Duration rolls.
|
|
183
|
-
duration:
|
|
172
|
+
duration: u3 = 0,
|
|
173
|
+
/// If not None, the value to return for Rolls.conversion2.
|
|
174
|
+
conversion_2: Optional(Type) = .None,
|
|
184
175
|
|
|
185
176
|
/// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
|
|
186
177
|
psywave: u8 = 0,
|
|
@@ -188,44 +179,19 @@ pub const Action = packed struct(u128) {
|
|
|
188
179
|
/// If not None, the Move to return for Rolls.metronome.
|
|
189
180
|
metronome: Move = .None,
|
|
190
181
|
|
|
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
182
|
pub const Field = std.meta.FieldEnum(Action);
|
|
199
183
|
|
|
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 };
|
|
184
|
+
pub fn format(a: Action, w: *std.Io.Writer) !void {
|
|
207
185
|
try fmt(a, w, false);
|
|
208
186
|
}
|
|
209
187
|
|
|
210
|
-
pub fn fmt(self: Action, writer:
|
|
188
|
+
pub fn fmt(self: Action, writer: *std.Io.Writer, shape: bool) !void {
|
|
211
189
|
try writer.writeByte('(');
|
|
212
190
|
var printed = false;
|
|
213
|
-
inline for (@typeInfo(Action).
|
|
191
|
+
inline for (@typeInfo(Action).@"struct".fields) |field| {
|
|
214
192
|
const val = @field(self, field.name);
|
|
215
193
|
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) {
|
|
194
|
+
.@"enum" => if (val != .None) {
|
|
229
195
|
if (printed) try writer.writeAll(", ");
|
|
230
196
|
if (shape) {
|
|
231
197
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -239,7 +205,7 @@ pub const Action = packed struct(u128) {
|
|
|
239
205
|
}
|
|
240
206
|
printed = true;
|
|
241
207
|
},
|
|
242
|
-
.
|
|
208
|
+
.int => if (val != 0) {
|
|
243
209
|
if (printed) try writer.writeAll(", ");
|
|
244
210
|
if (shape) {
|
|
245
211
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -255,36 +221,6 @@ pub const Action = packed struct(u128) {
|
|
|
255
221
|
}
|
|
256
222
|
};
|
|
257
223
|
|
|
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
224
|
/// Tracks chance actions and their associated probability during a Generation II battle update when
|
|
289
225
|
/// `options.chance` is enabled.
|
|
290
226
|
pub fn Chance(comptime Rational: type) type {
|
|
@@ -297,37 +233,15 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
297
233
|
/// RNG events were observed during a battle `update`.
|
|
298
234
|
actions: Actions = .{},
|
|
299
235
|
|
|
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
236
|
/// Possible error returned by operations tracking chance probability.
|
|
309
237
|
pub const Error = Rational.Error;
|
|
310
238
|
|
|
311
239
|
/// Convenience helper to clear fields which typically should be cleared between updates.
|
|
312
240
|
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
241
|
if (!enabled) return;
|
|
320
242
|
|
|
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]);
|
|
243
|
+
self.probability.reset();
|
|
244
|
+
self.actions = .{};
|
|
331
245
|
}
|
|
332
246
|
|
|
333
247
|
pub fn speedTie(self: *Self, p1: bool) Error!void {
|
|
@@ -353,19 +267,21 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
353
267
|
self.actions.get(player).hit = if (ok) .true else .false;
|
|
354
268
|
}
|
|
355
269
|
|
|
356
|
-
pub fn criticalHit(self: *Self, player: Player, crit: bool, rate: u8) Error!void {
|
|
270
|
+
pub fn criticalHit(self: *Self, player: Player, i: u3, crit: bool, rate: u8) Error!void {
|
|
357
271
|
if (!enabled) return;
|
|
358
272
|
|
|
359
273
|
const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
|
|
360
274
|
try self.probability.update(n, 256);
|
|
361
|
-
self.actions.get(player)
|
|
275
|
+
var a = self.actions.get(player);
|
|
276
|
+
a.critical_hits = Criticals.set(a.critical_hits, i, if (crit) .true else .false);
|
|
362
277
|
}
|
|
363
278
|
|
|
364
|
-
pub fn damage(self: *Self, player: Player, roll: u8) Error!void {
|
|
279
|
+
pub fn damage(self: *Self, player: Player, i: u3, roll: u8) Error!void {
|
|
365
280
|
if (!enabled) return;
|
|
366
281
|
|
|
367
282
|
try self.probability.update(1, 39);
|
|
368
|
-
self.actions.get(player)
|
|
283
|
+
var a = self.actions.get(player);
|
|
284
|
+
a.damages = Damages.set(a.damages, i, roll);
|
|
369
285
|
}
|
|
370
286
|
|
|
371
287
|
pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
|
|
@@ -517,122 +433,10 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
517
433
|
self.actions.get(player).multi_hit = n;
|
|
518
434
|
}
|
|
519
435
|
|
|
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 {
|
|
538
|
-
if (!enabled) return;
|
|
539
|
-
|
|
540
|
-
var durations = &self.actions.get(player).durations;
|
|
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 {
|
|
436
|
+
pub fn duration(self: *Self, player: Player, turns: u3) void {
|
|
590
437
|
if (!enabled) return;
|
|
591
438
|
|
|
592
|
-
|
|
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
|
-
}
|
|
439
|
+
self.actions.get(player).duration = if (options.key) 2 else turns;
|
|
636
440
|
}
|
|
637
441
|
};
|
|
638
442
|
}
|
|
@@ -684,22 +488,22 @@ test "Chance.hit" {
|
|
|
684
488
|
test "Chance.criticalHit" {
|
|
685
489
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
686
490
|
|
|
687
|
-
try chance.criticalHit(.P1, true, 17);
|
|
688
|
-
try expectValue(Optional(bool).true, chance.actions.p1.
|
|
491
|
+
try chance.criticalHit(.P1, 0, true, 17);
|
|
492
|
+
try expectValue(Optional(bool).true, Criticals.get(chance.actions.p1.critical_hits, 0));
|
|
689
493
|
try expectProbability(&chance.probability, 17, 256);
|
|
690
494
|
|
|
691
495
|
chance.reset();
|
|
692
496
|
|
|
693
|
-
try chance.criticalHit(.P2, false, 5);
|
|
497
|
+
try chance.criticalHit(.P2, 1, false, 5);
|
|
694
498
|
try expectProbability(&chance.probability, 251, 256);
|
|
695
|
-
try expectValue(Optional(bool).false, chance.actions.p2.
|
|
499
|
+
try expectValue(Optional(bool).false, Criticals.get(chance.actions.p2.critical_hits, 1));
|
|
696
500
|
}
|
|
697
501
|
|
|
698
502
|
test "Chance.damage" {
|
|
699
503
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
700
504
|
|
|
701
|
-
try chance.damage(.P1,
|
|
702
|
-
try expectValue(@as(u8,
|
|
505
|
+
try chance.damage(.P1, 0, 219);
|
|
506
|
+
try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
|
|
703
507
|
try expectProbability(&chance.probability, 1, 39);
|
|
704
508
|
}
|
|
705
509
|
|
|
@@ -915,19 +719,19 @@ test "Chance.moveSlot" {
|
|
|
915
719
|
|
|
916
720
|
try chance.moveSlot(.P2, 2, 2);
|
|
917
721
|
try expectProbability(&chance.probability, 1, 2);
|
|
918
|
-
try expectValue(@as(
|
|
722
|
+
try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
|
|
919
723
|
|
|
920
724
|
chance.reset();
|
|
921
725
|
|
|
922
726
|
try chance.moveSlot(.P1, 1, 3);
|
|
923
727
|
try expectProbability(&chance.probability, 1, 3);
|
|
924
|
-
try expectValue(@as(
|
|
728
|
+
try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
|
|
925
729
|
|
|
926
730
|
chance.reset();
|
|
927
731
|
|
|
928
732
|
try chance.moveSlot(.P1, 4, 1);
|
|
929
733
|
try expectProbability(&chance.probability, 1, 1);
|
|
930
|
-
try expectValue(@as(
|
|
734
|
+
try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
|
|
931
735
|
}
|
|
932
736
|
|
|
933
737
|
test "Chance.forceSwitch" {
|
|
@@ -935,19 +739,19 @@ test "Chance.forceSwitch" {
|
|
|
935
739
|
|
|
936
740
|
try chance.forceSwitch(.P2, 2, 2);
|
|
937
741
|
try expectProbability(&chance.probability, 1, 2);
|
|
938
|
-
try expectValue(@as(
|
|
742
|
+
try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
|
|
939
743
|
|
|
940
744
|
chance.reset();
|
|
941
745
|
|
|
942
746
|
try chance.forceSwitch(.P1, 1, 3);
|
|
943
747
|
try expectProbability(&chance.probability, 1, 3);
|
|
944
|
-
try expectValue(@as(
|
|
748
|
+
try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
|
|
945
749
|
|
|
946
750
|
chance.reset();
|
|
947
751
|
|
|
948
752
|
try chance.forceSwitch(.P1, 4, 1);
|
|
949
753
|
try expectProbability(&chance.probability, 1, 1);
|
|
950
|
-
try expectValue(@as(
|
|
754
|
+
try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
|
|
951
755
|
}
|
|
952
756
|
|
|
953
757
|
test "Chance.multiHit" {
|
|
@@ -955,212 +759,20 @@ test "Chance.multiHit" {
|
|
|
955
759
|
|
|
956
760
|
try chance.multiHit(.P1, 3);
|
|
957
761
|
try expectProbability(&chance.probability, 3, 8);
|
|
958
|
-
try expectValue(@as(
|
|
762
|
+
try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
|
|
959
763
|
|
|
960
764
|
chance.reset();
|
|
961
765
|
|
|
962
766
|
try chance.multiHit(.P2, 5);
|
|
963
767
|
try expectProbability(&chance.probability, 1, 8);
|
|
964
|
-
try expectValue(@as(
|
|
768
|
+
try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
|
|
965
769
|
}
|
|
966
770
|
|
|
967
771
|
test "Chance.duration" {
|
|
968
772
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
969
773
|
|
|
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
|
-
}
|
|
774
|
+
chance.duration(.P1, 2);
|
|
775
|
+
try expectValue(@as(u3, 2), chance.actions.p1.duration);
|
|
1164
776
|
}
|
|
1165
777
|
|
|
1166
778
|
pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
@@ -1168,7 +780,7 @@ pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
|
1168
780
|
|
|
1169
781
|
r.reduce();
|
|
1170
782
|
if (r.p != p or r.q != q) {
|
|
1171
|
-
print("expected {d}/{d}, found {}\n", .{ p, q, r });
|
|
783
|
+
print("expected {d}/{d}, found {f}\n", .{ p, q, r });
|
|
1172
784
|
return error.TestExpectedEqual;
|
|
1173
785
|
}
|
|
1174
786
|
}
|
|
@@ -1202,12 +814,12 @@ const Null = struct {
|
|
|
1202
814
|
_ = .{ self, player, ok, accuracy };
|
|
1203
815
|
}
|
|
1204
816
|
|
|
1205
|
-
pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
|
|
1206
|
-
_ = .{ self, player, crit, rate };
|
|
817
|
+
pub fn criticalHit(self: Null, player: Player, i: u3, crit: bool, rate: u8) Error!void {
|
|
818
|
+
_ = .{ self, player, i, crit, rate };
|
|
1207
819
|
}
|
|
1208
820
|
|
|
1209
|
-
pub fn damage(self: Null, player: Player, roll: u8) Error!void {
|
|
1210
|
-
_ = .{ self, player, roll };
|
|
821
|
+
pub fn damage(self: Null, player: Player, i: u3, roll: u8) Error!void {
|
|
822
|
+
_ = .{ self, player, i, roll };
|
|
1211
823
|
}
|
|
1212
824
|
|
|
1213
825
|
pub fn confused(self: Null, player: Player, ok: bool) Error!void {
|
|
@@ -1278,37 +890,7 @@ const Null = struct {
|
|
|
1278
890
|
_ = .{ self, player, move, n };
|
|
1279
891
|
}
|
|
1280
892
|
|
|
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 {
|
|
893
|
+
pub fn duration(self: Null, player: Player, turns: u3) void {
|
|
1312
894
|
_ = .{ self, player, turns };
|
|
1313
895
|
}
|
|
1314
896
|
};
|