@pkmn/engine 0.1.0-dev.5570b5c5 → 0.1.0-dev.587596a6
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 -1
- package/README.md +29 -17
- 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 +34 -65
- 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 +23 -1
- 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 +40 -90
- package/build/pkg/index.js +23 -70
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +20 -1
- package/build/pkg/protocol.js +105 -103
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +68 -74
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +152 -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 +359 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +33 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +237 -98
- package/package.json +59 -138
- package/src/bin/install-pkmn-engine +25 -7
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/bindings/c.zig +200 -0
- package/src/lib/bindings/node.zig +117 -0
- package/src/lib/bindings/wasm.zig +50 -0
- package/src/lib/common/array.zig +70 -0
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/debug.zig +32 -11
- package/src/lib/common/js.zig +3 -7
- package/src/lib/common/optional.zig +11 -17
- package/src/lib/common/options.zig +6 -0
- package/src/lib/common/protocol.zig +148 -134
- package/src/lib/common/rational.zig +338 -255
- package/src/lib/common/rng.zig +5 -7
- package/src/lib/common/util.zig +33 -1
- package/src/lib/gen1/calc.zig +701 -171
- package/src/lib/gen1/chance.zig +407 -298
- package/src/lib/gen1/data/moves.zig +2 -4
- package/src/lib/gen1/data/species.zig +1 -3
- package/src/lib/gen1/data/types.zig +3 -4
- package/src/lib/gen1/data.zig +43 -46
- package/src/lib/gen1/helpers.zig +91 -549
- package/src/lib/gen1/mechanics.zig +355 -258
- package/src/lib/gen2/calc.zig +35 -28
- package/src/lib/gen2/chance.zig +91 -510
- 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 +33 -35
- package/src/lib/gen2/generated.zig +18 -23
- package/src/lib/gen2/helpers.zig +45 -26
- package/src/lib/gen2/mechanics.zig +97 -124
- package/src/lib/napi.h +2 -0
- package/src/lib/node.zig +4 -121
- package/src/lib/pkmn.zig +106 -33
- package/src/lib/wasm.zig +9 -9
- package/src/tools/display/dom.ts +93 -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/test/display/pkmn.html.tmpl +0 -368
package/src/lib/gen2/chance.zig
CHANGED
|
@@ -8,9 +8,9 @@ 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
|
|
|
@@ -19,7 +19,8 @@ const data = @import("data.zig");
|
|
|
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,23 +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
|
-
// TODO: ziglang/zig#19730
|
|
101
85
|
test Actions {
|
|
102
|
-
const a: Actions = .{ .p1 = .{ .hit = .true, .
|
|
103
|
-
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 } };
|
|
104
88
|
const c: Actions = .{ .p1 = .{ .hit = .true } };
|
|
105
|
-
// const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
|
|
106
|
-
// const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
|
|
107
|
-
// const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
|
|
108
|
-
// const g: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1 } } };
|
|
109
|
-
// const h: Actions =
|
|
110
|
-
// .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1, .thrash = true } } };
|
|
111
89
|
|
|
112
90
|
try expect(a.eql(a));
|
|
113
91
|
try expect(!a.eql(b));
|
|
@@ -120,17 +98,21 @@ test Actions {
|
|
|
120
98
|
try expect(b.matches(a));
|
|
121
99
|
try expect(!a.matches(c));
|
|
122
100
|
try expect(!c.matches(a));
|
|
123
|
-
// try expect(d.matches(e));
|
|
124
|
-
// try expect(!d.matches(f));
|
|
125
|
-
// try expect(!g.matches(h));
|
|
126
|
-
// try expect(h.matches(h));
|
|
127
101
|
}
|
|
128
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
|
+
|
|
129
109
|
/// Information about the RNG that was observed during a Generation II battle `update` for a
|
|
130
110
|
/// single player.
|
|
131
111
|
pub const Action = packed struct(u128) {
|
|
132
|
-
///
|
|
133
|
-
|
|
112
|
+
/// TODO
|
|
113
|
+
damages: Damages.T = 0,
|
|
114
|
+
// TODO
|
|
115
|
+
critical_hits: Criticals.T = 0,
|
|
134
116
|
|
|
135
117
|
/// If not None, the Player to be returned by Rolls.speedTie.
|
|
136
118
|
speed_tie: Optional(Player) = .None,
|
|
@@ -138,50 +120,58 @@ pub const Action = packed struct(u128) {
|
|
|
138
120
|
quick_claw: Optional(bool) = .None,
|
|
139
121
|
/// If not None, the value to return for Rolls.hit.
|
|
140
122
|
hit: Optional(bool) = .None,
|
|
141
|
-
/// If not None, the value to be returned by Rolls.criticalHit.
|
|
142
|
-
critical_hit: Optional(bool) = .None,
|
|
143
|
-
|
|
144
123
|
/// If not None, the value to return for Rolls.confused.
|
|
145
124
|
confused: Optional(bool) = .None,
|
|
125
|
+
|
|
146
126
|
/// If not None, the value to return for Rolls.attract.
|
|
147
127
|
attract: Optional(bool) = .None,
|
|
148
128
|
/// If not None, the value to return for Rolls.paralyzed.
|
|
149
129
|
paralyzed: Optional(bool) = .None,
|
|
150
130
|
/// If not None, the value to return for Rolls.defrost.
|
|
151
131
|
defrost: Optional(bool) = .None,
|
|
152
|
-
|
|
153
132
|
/// If not None, the value to be returned for Rolls.secondaryChance.
|
|
154
133
|
secondary_chance: Optional(bool) = .None,
|
|
134
|
+
|
|
155
135
|
/// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
|
|
156
136
|
item: Optional(bool) = .None,
|
|
157
137
|
/// If not None, the value to be returned for Rolls.protect.
|
|
158
138
|
protect: Optional(bool) = .None,
|
|
159
139
|
/// If not None, the value to return for Rolls.triAttack.
|
|
160
140
|
tri_attack: Optional(TriAttack) = .None,
|
|
141
|
+
/// If not 0, the value to return for Rolls.tripleKick.
|
|
142
|
+
triple_kick: u2 = 0,
|
|
161
143
|
|
|
162
144
|
/// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
|
|
163
145
|
present: u3 = 0,
|
|
164
146
|
/// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
|
|
165
147
|
magnitude: u3 = 0,
|
|
166
|
-
/// If not 0, the
|
|
167
|
-
triple_kick: u2 = 0,
|
|
168
|
-
|
|
169
|
-
/// 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.
|
|
170
149
|
spite: u3 = 0,
|
|
171
|
-
/// If not None, the value to return for Rolls.conversion2.
|
|
172
|
-
conversion_2: Optional(Type) = .None,
|
|
173
|
-
|
|
174
150
|
/// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
|
|
175
151
|
/// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
|
|
176
|
-
move_slot:
|
|
152
|
+
move_slot: u3 = 0,
|
|
177
153
|
/// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
|
|
178
154
|
/// invalid values (eg. due to empty party slots or fainted members) will be ignored.
|
|
179
|
-
force_switch:
|
|
180
|
-
|
|
155
|
+
force_switch: u3 = 0,
|
|
181
156
|
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
182
|
-
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
|
+
|
|
183
171
|
/// If not 0, the value to by one of the Rolls.*Duration rolls.
|
|
184
|
-
duration:
|
|
172
|
+
duration: u3 = 0,
|
|
173
|
+
/// If not None, the value to return for Rolls.conversion2.
|
|
174
|
+
conversion_2: Optional(Type) = .None,
|
|
185
175
|
|
|
186
176
|
/// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
|
|
187
177
|
psywave: u8 = 0,
|
|
@@ -189,44 +179,19 @@ pub const Action = packed struct(u128) {
|
|
|
189
179
|
/// If not None, the Move to return for Rolls.metronome.
|
|
190
180
|
metronome: Move = .None,
|
|
191
181
|
|
|
192
|
-
_: u16 = 0,
|
|
193
|
-
|
|
194
|
-
/// Observed values of various durations. Does not influence future RNG calls. TODO
|
|
195
|
-
durations: Duration = .{},
|
|
196
|
-
|
|
197
|
-
pub const DURATIONS: u128 = 0xFFFFFFFF00000000_0000000000000000;
|
|
198
|
-
|
|
199
182
|
pub const Field = std.meta.FieldEnum(Action);
|
|
200
183
|
|
|
201
|
-
|
|
202
|
-
pub fn reset(self: *Action) void {
|
|
203
|
-
self.* = @bitCast(@as(u128, @bitCast(self.*)) & DURATIONS);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
|
|
207
|
-
_ = .{ f, o };
|
|
184
|
+
pub fn format(a: Action, w: *std.Io.Writer) !void {
|
|
208
185
|
try fmt(a, w, false);
|
|
209
186
|
}
|
|
210
187
|
|
|
211
|
-
pub fn fmt(self: Action, writer:
|
|
188
|
+
pub fn fmt(self: Action, writer: *std.Io.Writer, shape: bool) !void {
|
|
212
189
|
try writer.writeByte('(');
|
|
213
190
|
var printed = false;
|
|
214
|
-
inline for (@typeInfo(Action).
|
|
191
|
+
inline for (@typeInfo(Action).@"struct".fields) |field| {
|
|
215
192
|
const val = @field(self, field.name);
|
|
216
193
|
switch (@typeInfo(@TypeOf(val))) {
|
|
217
|
-
|
|
218
|
-
const v = @field(val, f.name);
|
|
219
|
-
if (v != 0) {
|
|
220
|
-
if (printed) try writer.writeAll(", ");
|
|
221
|
-
if (shape) {
|
|
222
|
-
try writer.print("{s}:?", .{f.name});
|
|
223
|
-
} else {
|
|
224
|
-
try writer.print("{s}:{d}", .{ f.name, v });
|
|
225
|
-
}
|
|
226
|
-
printed = true;
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
.Enum => if (val != .None) {
|
|
194
|
+
.@"enum" => if (val != .None) {
|
|
230
195
|
if (printed) try writer.writeAll(", ");
|
|
231
196
|
if (shape) {
|
|
232
197
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -240,7 +205,7 @@ pub const Action = packed struct(u128) {
|
|
|
240
205
|
}
|
|
241
206
|
printed = true;
|
|
242
207
|
},
|
|
243
|
-
.
|
|
208
|
+
.int => if (val != 0) {
|
|
244
209
|
if (printed) try writer.writeAll(", ");
|
|
245
210
|
if (shape) {
|
|
246
211
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -256,36 +221,6 @@ pub const Action = packed struct(u128) {
|
|
|
256
221
|
}
|
|
257
222
|
};
|
|
258
223
|
|
|
259
|
-
test Action {
|
|
260
|
-
var a: Action = .{ .hit = .true, .durations = .{ .sleep = 3 }, .damage = 225 };
|
|
261
|
-
a.reset();
|
|
262
|
-
|
|
263
|
-
try expectEqual(Action{ .hit = .None, .durations = .{ .sleep = 3 }, .damage = 0 }, a);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/// Observed values for various durations that need to be tracked in order to properly
|
|
267
|
-
/// deduplicate transitions with a primary key. TODO
|
|
268
|
-
pub const Duration = packed struct(u32) {
|
|
269
|
-
/// The number of turns a Pokémon has been observed to be sleeping.
|
|
270
|
-
sleep: u3 = 0,
|
|
271
|
-
/// The number of turns a Pokémon has been observed to be confused.
|
|
272
|
-
confusion: u3 = 0,
|
|
273
|
-
/// TODO
|
|
274
|
-
thrash: bool = false,
|
|
275
|
-
/// The number of turns a Pokémon has been observed to be disabled.
|
|
276
|
-
disable: u4 = 0,
|
|
277
|
-
/// The number of turns a Pokémon has been observed to be attacking.
|
|
278
|
-
attacking: u3 = 0,
|
|
279
|
-
/// The number of turns a Pokémon has been observed to be binding their opponent.
|
|
280
|
-
binding: u3 = 0,
|
|
281
|
-
/// The number of turns a Pokémon has been observed to be encored.
|
|
282
|
-
encore: u3 = 0,
|
|
283
|
-
|
|
284
|
-
_: u12 = 0,
|
|
285
|
-
|
|
286
|
-
pub const Field = std.meta.FieldEnum(Duration);
|
|
287
|
-
};
|
|
288
|
-
|
|
289
224
|
/// Tracks chance actions and their associated probability during a Generation II battle update when
|
|
290
225
|
/// `options.chance` is enabled.
|
|
291
226
|
pub fn Chance(comptime Rational: type) type {
|
|
@@ -298,37 +233,15 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
298
233
|
/// RNG events were observed during a battle `update`.
|
|
299
234
|
actions: Actions = .{},
|
|
300
235
|
|
|
301
|
-
// Tracks the observed sleep durations for the Pokémon in both player's parties. Unlike
|
|
302
|
-
// other durations which are all tied to volatiles, sleep's counter persists through
|
|
303
|
-
// switching and so we must store it here. The indices of these arrays correspond to the
|
|
304
|
-
// `order` field of a Side. This information could be stored in actions but size is a
|
|
305
|
-
// concern so this is tracked separately as actions only purports to track RNG events
|
|
306
|
-
// observed during a single `update` (not across updates).
|
|
307
|
-
sleeps: [2][6]u3 = .{ .{0} ** 6, .{0} ** 6 },
|
|
308
|
-
|
|
309
236
|
/// Possible error returned by operations tracking chance probability.
|
|
310
237
|
pub const Error = Rational.Error;
|
|
311
238
|
|
|
312
239
|
/// Convenience helper to clear fields which typically should be cleared between updates.
|
|
313
240
|
pub fn reset(self: *Self) void {
|
|
314
|
-
self.probability.reset();
|
|
315
|
-
self.actions.reset();
|
|
316
|
-
// TODO: self.pending = .{};
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
pub fn switched(self: *Self, player: Player, in: u8, out: u8) void {
|
|
320
241
|
if (!enabled) return;
|
|
321
242
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
var action = self.actions.get(player);
|
|
326
|
-
|
|
327
|
-
const slp = action.durations.sleep;
|
|
328
|
-
action.durations = .{};
|
|
329
|
-
|
|
330
|
-
self.sleeps[@intFromEnum(player)][out - 1] = slp;
|
|
331
|
-
action.durations.sleep = @intCast(self.sleeps[@intFromEnum(player)][in - 1]);
|
|
243
|
+
self.probability.reset();
|
|
244
|
+
self.actions = .{};
|
|
332
245
|
}
|
|
333
246
|
|
|
334
247
|
pub fn speedTie(self: *Self, p1: bool) Error!void {
|
|
@@ -354,19 +267,21 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
354
267
|
self.actions.get(player).hit = if (ok) .true else .false;
|
|
355
268
|
}
|
|
356
269
|
|
|
357
|
-
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 {
|
|
358
271
|
if (!enabled) return;
|
|
359
272
|
|
|
360
273
|
const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
|
|
361
274
|
try self.probability.update(n, 256);
|
|
362
|
-
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);
|
|
363
277
|
}
|
|
364
278
|
|
|
365
|
-
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 {
|
|
366
280
|
if (!enabled) return;
|
|
367
281
|
|
|
368
282
|
try self.probability.update(1, 39);
|
|
369
|
-
self.actions.get(player)
|
|
283
|
+
var a = self.actions.get(player);
|
|
284
|
+
a.damages = Damages.set(a.damages, i, roll);
|
|
370
285
|
}
|
|
371
286
|
|
|
372
287
|
pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
|
|
@@ -518,122 +433,10 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
518
433
|
self.actions.get(player).multi_hit = n;
|
|
519
434
|
}
|
|
520
435
|
|
|
521
|
-
pub fn duration(
|
|
522
|
-
self: *Self,
|
|
523
|
-
comptime field: Duration.Field,
|
|
524
|
-
player: Player,
|
|
525
|
-
target: Player,
|
|
526
|
-
turns: u4,
|
|
527
|
-
) void {
|
|
528
|
-
if (!enabled) return;
|
|
529
|
-
|
|
530
|
-
var durations = &self.actions.get(target).durations;
|
|
531
|
-
assert(@field(durations, @tagName(field)) == 0 or
|
|
532
|
-
(field == .confusion and player == target));
|
|
533
|
-
@field(durations, @tagName(field)) = 1;
|
|
534
|
-
if (field == .confusion) durations.thrash = player == target;
|
|
535
|
-
self.actions.get(player).duration = if (options.key) 1 else turns;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
pub fn sleep(self: *Self, player: Player, turns: u4) Error!void {
|
|
539
|
-
if (!enabled) return;
|
|
540
|
-
|
|
541
|
-
var durations = &self.actions.get(player).durations;
|
|
542
|
-
const n = durations.sleep;
|
|
543
|
-
if (turns == 0) {
|
|
544
|
-
assert(n >= 1 and n <= 6);
|
|
545
|
-
if (n != 6) try self.probability.update(1, 7 - @as(u4, n));
|
|
546
|
-
durations.sleep = 0;
|
|
547
|
-
} else {
|
|
548
|
-
assert(n >= 1 and n < 6);
|
|
549
|
-
try self.probability.update(7 - @as(u4, n) - 1, 7 - @as(u4, n));
|
|
550
|
-
durations.sleep += 1;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
pub fn confusion(self: *Self, player: Player, turns: u4) Error!void {
|
|
555
|
-
if (!enabled) return;
|
|
556
|
-
|
|
557
|
-
var durations = &self.actions.get(player).durations;
|
|
558
|
-
const n = durations.confusion;
|
|
559
|
-
const hi: u8 = if (durations.thrash) 3 else 5;
|
|
560
|
-
const p = hi + 1;
|
|
561
|
-
if (turns == 0) {
|
|
562
|
-
assert(n >= 2 and n <= hi);
|
|
563
|
-
if (n != hi) try self.probability.update(1, p - @as(u4, n));
|
|
564
|
-
durations.confusion = 0;
|
|
565
|
-
} else {
|
|
566
|
-
assert(n >= 1 and n < hi);
|
|
567
|
-
if (n > 1) try self.probability.update(p - @as(u4, n) - 1, p - @as(u4, n));
|
|
568
|
-
durations.confusion += 1;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
pub fn disable(self: *Self, player: Player, turns: u4) Error!void {
|
|
573
|
-
if (!enabled) return;
|
|
574
|
-
|
|
575
|
-
var durations = &self.actions.get(player).durations;
|
|
576
|
-
const n = durations.disable;
|
|
577
|
-
const hi = if (showdown) 5 else 8;
|
|
578
|
-
const p = hi + 1;
|
|
579
|
-
if (turns == 0) {
|
|
580
|
-
assert(n >= 2 and n <= hi);
|
|
581
|
-
if (n != hi) try self.probability.update(1, p - n);
|
|
582
|
-
durations.disable = 0;
|
|
583
|
-
} else {
|
|
584
|
-
assert(n >= 1 and n < hi);
|
|
585
|
-
if (n > 1) try self.probability.update(p - n - 1, p - n);
|
|
586
|
-
durations.disable += 1;
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
pub fn attacking(self: *Self, player: Player, turns: u4) Error!void {
|
|
436
|
+
pub fn duration(self: *Self, player: Player, turns: u3) void {
|
|
591
437
|
if (!enabled) return;
|
|
592
438
|
|
|
593
|
-
|
|
594
|
-
const n = durations.attacking;
|
|
595
|
-
if (turns == 0) {
|
|
596
|
-
assert(n >= 2 and n <= 3);
|
|
597
|
-
if (n != 3) try self.probability.update(1, 4 - @as(u4, n));
|
|
598
|
-
durations.attacking = 0;
|
|
599
|
-
} else {
|
|
600
|
-
assert(n >= 1 and n < 3);
|
|
601
|
-
if (n > 1) try self.probability.update(4 - @as(u4, n) - 1, 4 - @as(u4, n));
|
|
602
|
-
durations.attacking += 1;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
pub fn binding(self: *Self, player: Player, turns: u4) Error!void {
|
|
607
|
-
if (!enabled) return;
|
|
608
|
-
|
|
609
|
-
var durations = &self.actions.get(player).durations;
|
|
610
|
-
const n = durations.binding;
|
|
611
|
-
if (turns == 0) {
|
|
612
|
-
assert(n >= 2 and n <= 5);
|
|
613
|
-
if (n != 5) try self.probability.update(1, 6 - @as(u4, n));
|
|
614
|
-
durations.binding = 0;
|
|
615
|
-
} else {
|
|
616
|
-
assert(n >= 1 and n < 5);
|
|
617
|
-
if (n > 1) try self.probability.update(6 - @as(u4, n) - 1, 6 - @as(u4, n));
|
|
618
|
-
durations.binding += 1;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// TODO: consider sharing implementation with binding
|
|
623
|
-
pub fn encore(self: *Self, player: Player, turns: u4) Error!void {
|
|
624
|
-
if (!enabled) return;
|
|
625
|
-
|
|
626
|
-
var durations = &self.actions.get(player).durations;
|
|
627
|
-
const n = durations.encore;
|
|
628
|
-
if (turns == 0) {
|
|
629
|
-
assert(n >= 2 and n <= 5);
|
|
630
|
-
if (n != 5) try self.probability.update(1, 6 - @as(u4, n));
|
|
631
|
-
durations.encore = 0;
|
|
632
|
-
} else {
|
|
633
|
-
assert(n >= 1 and n < 5);
|
|
634
|
-
if (n > 1) try self.probability.update(6 - @as(u4, n) - 1, 6 - @as(u4, n));
|
|
635
|
-
durations.encore += 1;
|
|
636
|
-
}
|
|
439
|
+
self.actions.get(player).duration = if (options.key) 2 else turns;
|
|
637
440
|
}
|
|
638
441
|
};
|
|
639
442
|
}
|
|
@@ -685,22 +488,22 @@ test "Chance.hit" {
|
|
|
685
488
|
test "Chance.criticalHit" {
|
|
686
489
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
687
490
|
|
|
688
|
-
try chance.criticalHit(.P1, true, 17);
|
|
689
|
-
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));
|
|
690
493
|
try expectProbability(&chance.probability, 17, 256);
|
|
691
494
|
|
|
692
495
|
chance.reset();
|
|
693
496
|
|
|
694
|
-
try chance.criticalHit(.P2, false, 5);
|
|
497
|
+
try chance.criticalHit(.P2, 1, false, 5);
|
|
695
498
|
try expectProbability(&chance.probability, 251, 256);
|
|
696
|
-
try expectValue(Optional(bool).false, chance.actions.p2.
|
|
499
|
+
try expectValue(Optional(bool).false, Criticals.get(chance.actions.p2.critical_hits, 1));
|
|
697
500
|
}
|
|
698
501
|
|
|
699
502
|
test "Chance.damage" {
|
|
700
503
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
701
504
|
|
|
702
|
-
try chance.damage(.P1,
|
|
703
|
-
try expectValue(
|
|
505
|
+
try chance.damage(.P1, 0, 219);
|
|
506
|
+
try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
|
|
704
507
|
try expectProbability(&chance.probability, 1, 39);
|
|
705
508
|
}
|
|
706
509
|
|
|
@@ -825,7 +628,7 @@ test "Chance.present" {
|
|
|
825
628
|
} else {
|
|
826
629
|
try expectProbability(&chance.probability, 25, 256);
|
|
827
630
|
}
|
|
828
|
-
try expectValue(4, chance.actions.p2.present);
|
|
631
|
+
try expectValue(@as(u3, 4), chance.actions.p2.present);
|
|
829
632
|
|
|
830
633
|
chance.reset();
|
|
831
634
|
|
|
@@ -835,7 +638,7 @@ test "Chance.present" {
|
|
|
835
638
|
} else {
|
|
836
639
|
try expectProbability(&chance.probability, 51, 256);
|
|
837
640
|
}
|
|
838
|
-
try expectValue(1, chance.actions.p1.present);
|
|
641
|
+
try expectValue(@as(u3, 1), chance.actions.p1.present);
|
|
839
642
|
}
|
|
840
643
|
|
|
841
644
|
test "Chance.magnitude" {
|
|
@@ -847,7 +650,7 @@ test "Chance.magnitude" {
|
|
|
847
650
|
} else {
|
|
848
651
|
try expectProbability(&chance.probability, 13, 256);
|
|
849
652
|
}
|
|
850
|
-
try expectValue(7, chance.actions.p2.magnitude);
|
|
653
|
+
try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
|
|
851
654
|
|
|
852
655
|
chance.reset();
|
|
853
656
|
|
|
@@ -857,7 +660,7 @@ test "Chance.magnitude" {
|
|
|
857
660
|
} else {
|
|
858
661
|
try expectProbability(&chance.probability, 51, 256);
|
|
859
662
|
}
|
|
860
|
-
try expectValue(5, chance.actions.p1.magnitude);
|
|
663
|
+
try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
|
|
861
664
|
}
|
|
862
665
|
|
|
863
666
|
test "Chance.tripleKick" {
|
|
@@ -865,7 +668,7 @@ test "Chance.tripleKick" {
|
|
|
865
668
|
|
|
866
669
|
try chance.tripleKick(.P1, 2);
|
|
867
670
|
try expectProbability(&chance.probability, 1, 3);
|
|
868
|
-
try expectValue(2, chance.actions.p1.triple_kick);
|
|
671
|
+
try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
|
|
869
672
|
}
|
|
870
673
|
|
|
871
674
|
test "Chance.spite" {
|
|
@@ -873,7 +676,7 @@ test "Chance.spite" {
|
|
|
873
676
|
|
|
874
677
|
try chance.spite(.P1, 3);
|
|
875
678
|
try expectProbability(&chance.probability, 1, 4);
|
|
876
|
-
try expectValue(3, chance.actions.p1.spite);
|
|
679
|
+
try expectValue(@as(u3, 3), chance.actions.p1.spite);
|
|
877
680
|
}
|
|
878
681
|
|
|
879
682
|
test "Chance.conversion2" {
|
|
@@ -900,7 +703,7 @@ test "Chance.psywave" {
|
|
|
900
703
|
|
|
901
704
|
try chance.psywave(.P2, 100, 150);
|
|
902
705
|
try expectProbability(&chance.probability, 1, 150);
|
|
903
|
-
try expectValue(100, chance.actions.p2.psywave);
|
|
706
|
+
try expectValue(@as(u8, 100), chance.actions.p2.psywave);
|
|
904
707
|
}
|
|
905
708
|
|
|
906
709
|
test "Chance.metronome" {
|
|
@@ -916,19 +719,19 @@ test "Chance.moveSlot" {
|
|
|
916
719
|
|
|
917
720
|
try chance.moveSlot(.P2, 2, 2);
|
|
918
721
|
try expectProbability(&chance.probability, 1, 2);
|
|
919
|
-
try expectValue(2, chance.actions.p2.move_slot);
|
|
722
|
+
try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
|
|
920
723
|
|
|
921
724
|
chance.reset();
|
|
922
725
|
|
|
923
726
|
try chance.moveSlot(.P1, 1, 3);
|
|
924
727
|
try expectProbability(&chance.probability, 1, 3);
|
|
925
|
-
try expectValue(1, chance.actions.p1.move_slot);
|
|
728
|
+
try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
|
|
926
729
|
|
|
927
730
|
chance.reset();
|
|
928
731
|
|
|
929
732
|
try chance.moveSlot(.P1, 4, 1);
|
|
930
733
|
try expectProbability(&chance.probability, 1, 1);
|
|
931
|
-
try expectValue(4, chance.actions.p1.move_slot);
|
|
734
|
+
try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
|
|
932
735
|
}
|
|
933
736
|
|
|
934
737
|
test "Chance.forceSwitch" {
|
|
@@ -936,19 +739,19 @@ test "Chance.forceSwitch" {
|
|
|
936
739
|
|
|
937
740
|
try chance.forceSwitch(.P2, 2, 2);
|
|
938
741
|
try expectProbability(&chance.probability, 1, 2);
|
|
939
|
-
try expectValue(2, chance.actions.p2.force_switch);
|
|
742
|
+
try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
|
|
940
743
|
|
|
941
744
|
chance.reset();
|
|
942
745
|
|
|
943
746
|
try chance.forceSwitch(.P1, 1, 3);
|
|
944
747
|
try expectProbability(&chance.probability, 1, 3);
|
|
945
|
-
try expectValue(1, chance.actions.p1.force_switch);
|
|
748
|
+
try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
|
|
946
749
|
|
|
947
750
|
chance.reset();
|
|
948
751
|
|
|
949
752
|
try chance.forceSwitch(.P1, 4, 1);
|
|
950
753
|
try expectProbability(&chance.probability, 1, 1);
|
|
951
|
-
try expectValue(4, chance.actions.p1.force_switch);
|
|
754
|
+
try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
|
|
952
755
|
}
|
|
953
756
|
|
|
954
757
|
test "Chance.multiHit" {
|
|
@@ -956,212 +759,20 @@ test "Chance.multiHit" {
|
|
|
956
759
|
|
|
957
760
|
try chance.multiHit(.P1, 3);
|
|
958
761
|
try expectProbability(&chance.probability, 3, 8);
|
|
959
|
-
try expectValue(3, chance.actions.p1.multi_hit);
|
|
762
|
+
try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
|
|
960
763
|
|
|
961
764
|
chance.reset();
|
|
962
765
|
|
|
963
766
|
try chance.multiHit(.P2, 5);
|
|
964
767
|
try expectProbability(&chance.probability, 1, 8);
|
|
965
|
-
try expectValue(5, chance.actions.p2.multi_hit);
|
|
768
|
+
try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
|
|
966
769
|
}
|
|
967
770
|
|
|
968
771
|
test "Chance.duration" {
|
|
969
772
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
970
773
|
|
|
971
|
-
chance.duration(.
|
|
972
|
-
try expectValue(2, chance.actions.p1.duration);
|
|
973
|
-
try expectValue(1, chance.actions.p2.durations.sleep);
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
test "Chance.sleep" {
|
|
977
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
978
|
-
|
|
979
|
-
for ([_]u8{ 6, 5, 4, 3, 2, 1 }, 1..7) |d, i| {
|
|
980
|
-
chance.actions.p1.durations.sleep = @intCast(i);
|
|
981
|
-
try chance.sleep(.P1, 0);
|
|
982
|
-
try expectProbability(&chance.probability, 1, d);
|
|
983
|
-
try expectValue(0, chance.actions.p1.durations.sleep);
|
|
984
|
-
|
|
985
|
-
chance.reset();
|
|
986
|
-
|
|
987
|
-
if (i < 6) {
|
|
988
|
-
chance.actions.p1.durations.sleep = @intCast(i);
|
|
989
|
-
try chance.sleep(.P1, 1);
|
|
990
|
-
try expectProbability(&chance.probability, d - 1, d);
|
|
991
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p1.durations.sleep);
|
|
992
|
-
|
|
993
|
-
chance.reset();
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
test "Chance.confusion" {
|
|
999
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1000
|
-
|
|
1001
|
-
chance.actions.p2.durations.thrash = false;
|
|
1002
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1003
|
-
if (i > 1) {
|
|
1004
|
-
chance.actions.p2.durations.confusion = @intCast(i);
|
|
1005
|
-
try chance.confusion(.P2, 0);
|
|
1006
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1007
|
-
try expectValue(0, chance.actions.p2.durations.confusion);
|
|
1008
|
-
try expectValue(false, chance.actions.p2.durations.thrash);
|
|
1009
|
-
|
|
1010
|
-
chance.reset();
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
if (i < 5) {
|
|
1014
|
-
chance.actions.p2.durations.confusion = @intCast(i);
|
|
1015
|
-
try chance.confusion(.P2, 1);
|
|
1016
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1017
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.confusion);
|
|
1018
|
-
try expectValue(false, chance.actions.p2.durations.thrash);
|
|
1019
|
-
|
|
1020
|
-
chance.reset();
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
chance.reset();
|
|
1025
|
-
|
|
1026
|
-
chance.actions.p2.durations.thrash = true;
|
|
1027
|
-
for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
|
|
1028
|
-
if (i > 1) {
|
|
1029
|
-
chance.actions.p2.durations.confusion = @intCast(i);
|
|
1030
|
-
try chance.confusion(.P2, 0);
|
|
1031
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1032
|
-
try expectValue(0, chance.actions.p2.durations.confusion);
|
|
1033
|
-
try expectValue(true, chance.actions.p2.durations.thrash);
|
|
1034
|
-
|
|
1035
|
-
chance.reset();
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
if (i < 3) {
|
|
1039
|
-
chance.actions.p2.durations.confusion = @intCast(i);
|
|
1040
|
-
try chance.confusion(.P2, 1);
|
|
1041
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1042
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.confusion);
|
|
1043
|
-
try expectValue(true, chance.actions.p2.durations.thrash);
|
|
1044
|
-
|
|
1045
|
-
chance.reset();
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
test "Chance.disable" {
|
|
1051
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1052
|
-
if (showdown) {
|
|
1053
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1054
|
-
if (i > 1) {
|
|
1055
|
-
chance.actions.p2.durations.disable = @intCast(i);
|
|
1056
|
-
try chance.disable(.P2, 0);
|
|
1057
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1058
|
-
try expectValue(0, chance.actions.p2.durations.disable);
|
|
1059
|
-
|
|
1060
|
-
chance.reset();
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
if (i < 5) {
|
|
1064
|
-
chance.actions.p2.durations.disable = @intCast(i);
|
|
1065
|
-
try chance.disable(.P2, 1);
|
|
1066
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1067
|
-
try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p2.durations.disable);
|
|
1068
|
-
|
|
1069
|
-
chance.reset();
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
} else {
|
|
1073
|
-
for ([_]u8{ 1, 7, 6, 5, 4, 3, 2, 1 }, 1..9) |d, i| {
|
|
1074
|
-
if (i > 1) {
|
|
1075
|
-
chance.actions.p2.durations.disable = @intCast(i);
|
|
1076
|
-
try chance.disable(.P2, 0);
|
|
1077
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1078
|
-
try expectValue(0, chance.actions.p2.durations.disable);
|
|
1079
|
-
|
|
1080
|
-
chance.reset();
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
if (i < 8) {
|
|
1084
|
-
chance.actions.p2.durations.disable = @intCast(i);
|
|
1085
|
-
try chance.disable(.P2, 1);
|
|
1086
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1087
|
-
try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p2.durations.disable);
|
|
1088
|
-
|
|
1089
|
-
chance.reset();
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
test "Chance.attacking" {
|
|
1096
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1097
|
-
|
|
1098
|
-
for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
|
|
1099
|
-
if (i > 1) {
|
|
1100
|
-
chance.actions.p2.durations.attacking = @intCast(i);
|
|
1101
|
-
try chance.attacking(.P2, 0);
|
|
1102
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1103
|
-
try expectValue(0, chance.actions.p2.durations.attacking);
|
|
1104
|
-
|
|
1105
|
-
chance.reset();
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
if (i < 3) {
|
|
1109
|
-
chance.actions.p2.durations.attacking = @intCast(i);
|
|
1110
|
-
try chance.attacking(.P2, 1);
|
|
1111
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1112
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.attacking);
|
|
1113
|
-
|
|
1114
|
-
chance.reset();
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
test "Chance.binding" {
|
|
1120
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1121
|
-
|
|
1122
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1123
|
-
if (i > 1) {
|
|
1124
|
-
chance.actions.p2.durations.binding = @intCast(i);
|
|
1125
|
-
try chance.binding(.P2, 0);
|
|
1126
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1127
|
-
try expectValue(0, chance.actions.p2.durations.binding);
|
|
1128
|
-
|
|
1129
|
-
chance.reset();
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
if (i < 5) {
|
|
1133
|
-
chance.actions.p2.durations.binding = @intCast(i);
|
|
1134
|
-
try chance.binding(.P2, 1);
|
|
1135
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1136
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.binding);
|
|
1137
|
-
|
|
1138
|
-
chance.reset();
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
test "Chance.encore" {
|
|
1144
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1145
|
-
|
|
1146
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1147
|
-
if (i > 1) {
|
|
1148
|
-
chance.actions.p2.durations.encore = @intCast(i);
|
|
1149
|
-
try chance.encore(.P2, 0);
|
|
1150
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1151
|
-
try expectValue(0, chance.actions.p2.durations.encore);
|
|
1152
|
-
|
|
1153
|
-
chance.reset();
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
if (i < 5) {
|
|
1157
|
-
chance.actions.p2.durations.encore = @intCast(i);
|
|
1158
|
-
try chance.encore(.P2, 1);
|
|
1159
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1160
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.encore);
|
|
1161
|
-
|
|
1162
|
-
chance.reset();
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
774
|
+
chance.duration(.P1, 2);
|
|
775
|
+
try expectValue(@as(u3, 2), chance.actions.p1.duration);
|
|
1165
776
|
}
|
|
1166
777
|
|
|
1167
778
|
pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
@@ -1169,7 +780,7 @@ pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
|
1169
780
|
|
|
1170
781
|
r.reduce();
|
|
1171
782
|
if (r.p != p or r.q != q) {
|
|
1172
|
-
print("expected {d}/{d}, found {}\n", .{ p, q, r });
|
|
783
|
+
print("expected {d}/{d}, found {f}\n", .{ p, q, r });
|
|
1173
784
|
return error.TestExpectedEqual;
|
|
1174
785
|
}
|
|
1175
786
|
}
|
|
@@ -1203,12 +814,12 @@ const Null = struct {
|
|
|
1203
814
|
_ = .{ self, player, ok, accuracy };
|
|
1204
815
|
}
|
|
1205
816
|
|
|
1206
|
-
pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
|
|
1207
|
-
_ = .{ 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 };
|
|
1208
819
|
}
|
|
1209
820
|
|
|
1210
|
-
pub fn damage(self: Null, player: Player, roll: u8) Error!void {
|
|
1211
|
-
_ = .{ self, player, roll };
|
|
821
|
+
pub fn damage(self: Null, player: Player, i: u3, roll: u8) Error!void {
|
|
822
|
+
_ = .{ self, player, i, roll };
|
|
1212
823
|
}
|
|
1213
824
|
|
|
1214
825
|
pub fn confused(self: Null, player: Player, ok: bool) Error!void {
|
|
@@ -1279,37 +890,7 @@ const Null = struct {
|
|
|
1279
890
|
_ = .{ self, player, move, n };
|
|
1280
891
|
}
|
|
1281
892
|
|
|
1282
|
-
pub fn duration(
|
|
1283
|
-
self: Null,
|
|
1284
|
-
comptime field: Duration.Field,
|
|
1285
|
-
player: Player,
|
|
1286
|
-
target: Player,
|
|
1287
|
-
turns: u4,
|
|
1288
|
-
) void {
|
|
1289
|
-
_ = .{ self, field, player, target, turns };
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
pub fn sleep(self: Null, player: Player, turns: u4) Error!void {
|
|
1293
|
-
_ = .{ self, player, turns };
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
pub fn confusion(self: Null, player: Player, turns: u4) Error!void {
|
|
1297
|
-
_ = .{ self, player, turns };
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
pub fn disable(self: Null, player: Player, turns: u4) Error!void {
|
|
1301
|
-
_ = .{ self, player, turns };
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
pub fn attacking(self: Null, player: Player, turns: u4) Error!void {
|
|
1305
|
-
_ = .{ self, player, turns };
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
pub fn binding(self: Null, player: Player, turns: u4) Error!void {
|
|
1309
|
-
_ = .{ self, player, turns };
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
pub fn encore(self: Null, player: Player, turns: u4) Error!void {
|
|
893
|
+
pub fn duration(self: Null, player: Player, turns: u3) void {
|
|
1313
894
|
_ = .{ self, player, turns };
|
|
1314
895
|
}
|
|
1315
896
|
};
|