@pkmn/engine 0.1.0-dev.a0167a9d → 0.1.0-dev.a0447192
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/README.md +4 -2
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +43 -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 +96 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon.d.ts +2 -0
- package/build/pkg/addon.js +29 -51
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +23 -1
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +1 -1
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +22 -9
- package/build/pkg/index.js +15 -10
- 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 +35 -68
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +141 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +132 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +349 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +18 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +199 -66
- package/package.json +46 -29
- package/src/bin/install-pkmn-engine +7 -5
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/debug.zig +39 -8
- package/src/lib/common/js.zig +4 -2
- package/src/lib/common/optional.zig +13 -9
- package/src/lib/common/options.zig +2 -0
- package/src/lib/common/protocol.zig +41 -36
- package/src/lib/common/rational.zig +53 -51
- package/src/lib/common/rng.zig +4 -4
- package/src/lib/common/util.zig +50 -1
- package/src/lib/gen1/calc.zig +508 -127
- package/src/lib/gen1/chance.zig +316 -173
- package/src/lib/gen1/data.zig +28 -27
- package/src/lib/gen1/helpers.zig +15 -450
- package/src/lib/gen1/mechanics.zig +216 -145
- package/src/lib/gen2/calc.zig +34 -16
- package/src/lib/gen2/chance.zig +90 -592
- package/src/lib/gen2/data.zig +15 -14
- package/src/lib/gen2/helpers.zig +4 -6
- package/src/lib/gen2/mechanics.zig +47 -77
- package/src/lib/pkmn.zig +7 -5
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +359 -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,13 +19,18 @@ 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;
|
|
26
27
|
const Effectiveness = data.Effectiveness;
|
|
27
28
|
const TriAttack = data.TriAttack;
|
|
28
29
|
|
|
30
|
+
const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
|
|
31
|
+
const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
|
|
32
|
+
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
33
|
+
|
|
29
34
|
/// Actions taken by a hypothetical "chance player" that convey information about which RNG events
|
|
30
35
|
/// were observed during a Generation II battle `update`. This can additionally be provided as input
|
|
31
36
|
/// to the `update` call to override the normal behavior of the RNG in order to force specific
|
|
@@ -37,22 +42,11 @@ pub const Actions = extern struct {
|
|
|
37
42
|
p2: Action = .{},
|
|
38
43
|
|
|
39
44
|
/// Returns the `Action` for the given `player`.
|
|
40
|
-
pub fn get(self: anytype, player: Player)
|
|
41
|
-
assert(
|
|
45
|
+
pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Action) {
|
|
46
|
+
assert(isPointerTo(self, Actions));
|
|
42
47
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
43
48
|
}
|
|
44
49
|
|
|
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
|
-
/// TODO
|
|
52
|
-
pub fn durations(self: Actions) Durations {
|
|
53
|
-
return .{ .p1 = self.p1.durations(), .p2 = self.p2.durations() };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
50
|
/// Returns true if `a` is equal to `b`.
|
|
57
51
|
pub fn eql(a: Actions, b: Actions) bool {
|
|
58
52
|
return @as(u128, @bitCast(a.p1)) == @as(u128, @bitCast(b.p1)) and
|
|
@@ -63,26 +57,15 @@ pub const Actions = extern struct {
|
|
|
63
57
|
/// same shape if they have the same fields set (though those fields need not necessarily be
|
|
64
58
|
/// set to the same value).
|
|
65
59
|
pub fn matches(a: Actions, b: Actions) bool {
|
|
66
|
-
inline for (@typeInfo(Actions)
|
|
67
|
-
inline for (@typeInfo(Action)
|
|
60
|
+
inline for (@field(@typeInfo(Actions), @tagName(Struct)).fields) |player| {
|
|
61
|
+
inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
|
|
68
62
|
const a_val = @field(@field(a, player.name), field.name);
|
|
69
63
|
const b_val = @field(@field(b, player.name), field.name);
|
|
70
64
|
|
|
71
65
|
switch (@typeInfo(@TypeOf(a_val))) {
|
|
72
|
-
|
|
73
|
-
// .Struct => inline for (@typeInfo(@TypeOf(a_val)).Struct.fields) |f| {
|
|
74
|
-
// const a_val_f = @field(a_val, f.name);
|
|
75
|
-
// const b_val_f = @field(b_val, f.name);
|
|
76
|
-
// switch (@typeInfo(@TypeOf(a_val_f))) {
|
|
77
|
-
// .Int => if ((a_val_f > 0) != (b_val_f > 0)) return false,
|
|
78
|
-
// .Bool => if (a_val_f != b_val_f) return false,
|
|
79
|
-
// else => unreachable,
|
|
80
|
-
// }
|
|
81
|
-
// },
|
|
82
|
-
.Bool => if (a_val != b_val) return false, // TODO
|
|
83
|
-
.Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
66
|
+
Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
84
67
|
return false,
|
|
85
|
-
|
|
68
|
+
Int => if ((a_val > 0) != (b_val > 0)) return false,
|
|
86
69
|
else => unreachable,
|
|
87
70
|
}
|
|
88
71
|
}
|
|
@@ -104,17 +87,10 @@ pub const Actions = extern struct {
|
|
|
104
87
|
}
|
|
105
88
|
};
|
|
106
89
|
|
|
107
|
-
// TODO: ziglang/zig#19730
|
|
108
90
|
test Actions {
|
|
109
|
-
const a: Actions = .{ .p1 = .{ .hit = .true, .
|
|
110
|
-
const b: Actions = .{ .p1 = .{ .hit = .false, .
|
|
91
|
+
const a: Actions = .{ .p1 = .{ .hit = .true, .confused = .false, .damages = 245 } };
|
|
92
|
+
const b: Actions = .{ .p1 = .{ .hit = .false, .confused = .true, .damages = 246 } };
|
|
111
93
|
const c: Actions = .{ .p1 = .{ .hit = .true } };
|
|
112
|
-
const d: Actions = .{ .p2 = .{ .hit = .true, .durations_sleep = 2 } };
|
|
113
|
-
const e: Actions = .{ .p2 = .{ .hit = .false, .durations_sleep = 4 } };
|
|
114
|
-
const f: Actions = .{ .p1 = .{ .hit = .false, .durations_sleep = 4 } };
|
|
115
|
-
const g: Actions = .{ .p1 = .{ .hit = .false, .durations_confusion = 1 } };
|
|
116
|
-
const h: Actions =
|
|
117
|
-
.{ .p1 = .{ .hit = .false, .durations_confusion = 1, .durations_thrash = true } };
|
|
118
94
|
|
|
119
95
|
try expect(a.eql(a));
|
|
120
96
|
try expect(!a.eql(b));
|
|
@@ -127,17 +103,21 @@ test Actions {
|
|
|
127
103
|
try expect(b.matches(a));
|
|
128
104
|
try expect(!a.matches(c));
|
|
129
105
|
try expect(!c.matches(a));
|
|
130
|
-
try expect(d.matches(e));
|
|
131
|
-
try expect(!d.matches(f));
|
|
132
|
-
try expect(!g.matches(h));
|
|
133
|
-
try expect(h.matches(h));
|
|
134
106
|
}
|
|
135
107
|
|
|
108
|
+
/// Observation made about a duration - whether the duration has started, been continued, or ended.
|
|
109
|
+
pub const Observation = enum { started, continuing, ended };
|
|
110
|
+
|
|
111
|
+
pub const Damages = Array(5, u8);
|
|
112
|
+
pub const Criticals = Array(5, Optional(bool));
|
|
113
|
+
|
|
136
114
|
/// Information about the RNG that was observed during a Generation II battle `update` for a
|
|
137
115
|
/// single player.
|
|
138
116
|
pub const Action = packed struct(u128) {
|
|
139
|
-
///
|
|
140
|
-
|
|
117
|
+
/// TODO
|
|
118
|
+
damages: Damages.T = 0,
|
|
119
|
+
// TODO
|
|
120
|
+
critical_hits: Criticals.T = 0,
|
|
141
121
|
|
|
142
122
|
/// If not None, the Player to be returned by Rolls.speedTie.
|
|
143
123
|
speed_tie: Optional(Player) = .None,
|
|
@@ -145,50 +125,58 @@ pub const Action = packed struct(u128) {
|
|
|
145
125
|
quick_claw: Optional(bool) = .None,
|
|
146
126
|
/// If not None, the value to return for Rolls.hit.
|
|
147
127
|
hit: Optional(bool) = .None,
|
|
148
|
-
/// If not None, the value to be returned by Rolls.criticalHit.
|
|
149
|
-
critical_hit: Optional(bool) = .None,
|
|
150
|
-
|
|
151
128
|
/// If not None, the value to return for Rolls.confused.
|
|
152
129
|
confused: Optional(bool) = .None,
|
|
130
|
+
|
|
153
131
|
/// If not None, the value to return for Rolls.attract.
|
|
154
132
|
attract: Optional(bool) = .None,
|
|
155
133
|
/// If not None, the value to return for Rolls.paralyzed.
|
|
156
134
|
paralyzed: Optional(bool) = .None,
|
|
157
135
|
/// If not None, the value to return for Rolls.defrost.
|
|
158
136
|
defrost: Optional(bool) = .None,
|
|
159
|
-
|
|
160
137
|
/// If not None, the value to be returned for Rolls.secondaryChance.
|
|
161
138
|
secondary_chance: Optional(bool) = .None,
|
|
139
|
+
|
|
162
140
|
/// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
|
|
163
141
|
item: Optional(bool) = .None,
|
|
164
142
|
/// If not None, the value to be returned for Rolls.protect.
|
|
165
143
|
protect: Optional(bool) = .None,
|
|
166
144
|
/// If not None, the value to return for Rolls.triAttack.
|
|
167
145
|
tri_attack: Optional(TriAttack) = .None,
|
|
146
|
+
/// If not 0, the value to return for Rolls.tripleKick.
|
|
147
|
+
triple_kick: u2 = 0,
|
|
168
148
|
|
|
169
149
|
/// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
|
|
170
150
|
present: u3 = 0,
|
|
171
151
|
/// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
|
|
172
152
|
magnitude: u3 = 0,
|
|
173
|
-
/// If not 0, the
|
|
174
|
-
triple_kick: u2 = 0,
|
|
175
|
-
|
|
176
|
-
/// If not 0, the amount of PP to deduct for Rolls.spite.
|
|
153
|
+
/// If not 0, the amount of PP to deduct for Rolls.spite.
|
|
177
154
|
spite: u3 = 0,
|
|
178
|
-
/// If not None, the value to return for Rolls.conversion2.
|
|
179
|
-
conversion_2: Optional(Type) = .None,
|
|
180
|
-
|
|
181
155
|
/// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
|
|
182
156
|
/// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
|
|
183
|
-
move_slot:
|
|
157
|
+
move_slot: u3 = 0,
|
|
184
158
|
/// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
|
|
185
159
|
/// invalid values (eg. due to empty party slots or fainted members) will be ignored.
|
|
186
|
-
force_switch:
|
|
187
|
-
|
|
160
|
+
force_switch: u3 = 0,
|
|
188
161
|
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
189
|
-
multi_hit:
|
|
162
|
+
multi_hit: u3 = 0,
|
|
163
|
+
|
|
164
|
+
sleep: Optional(Observation) = .None,
|
|
165
|
+
/// TODO
|
|
166
|
+
confusion: Optional(Observation) = .None,
|
|
167
|
+
/// TODO
|
|
168
|
+
disable: Optional(Observation) = .None,
|
|
169
|
+
/// TODO
|
|
170
|
+
attacking: Optional(Observation) = .None,
|
|
171
|
+
/// TODO
|
|
172
|
+
binding: Optional(Observation) = .None,
|
|
173
|
+
/// TODO
|
|
174
|
+
encore: Optional(Observation) = .None,
|
|
175
|
+
|
|
190
176
|
/// If not 0, the value to by one of the Rolls.*Duration rolls.
|
|
191
|
-
duration:
|
|
177
|
+
duration: u3 = 0,
|
|
178
|
+
/// If not None, the value to return for Rolls.conversion2.
|
|
179
|
+
conversion_2: Optional(Type) = .None,
|
|
192
180
|
|
|
193
181
|
/// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
|
|
194
182
|
psywave: u8 = 0,
|
|
@@ -196,49 +184,8 @@ pub const Action = packed struct(u128) {
|
|
|
196
184
|
/// If not None, the Move to return for Rolls.metronome.
|
|
197
185
|
metronome: Move = .None,
|
|
198
186
|
|
|
199
|
-
_: u28 = 0,
|
|
200
|
-
|
|
201
|
-
// TODO: ziglang/zig#19730
|
|
202
|
-
/// Observed values of various durations_ Does not influence future RNG calls. TODO
|
|
203
|
-
// durations: Duration = .{},
|
|
204
|
-
|
|
205
|
-
/// The number of turns a Pokémon has been observed to be sleeping.
|
|
206
|
-
durations_sleep: u3 = 0,
|
|
207
|
-
/// The number of turns a Pokémon has been observed to be confused.
|
|
208
|
-
durations_confusion: u3 = 0,
|
|
209
|
-
/// TODO
|
|
210
|
-
durations_thrash: bool = false,
|
|
211
|
-
/// The number of turns a Pokémon has been observed to be disabled.
|
|
212
|
-
durations_disable: u4 = 0,
|
|
213
|
-
/// The number of turns a Pokémon has been observed to be attacking.
|
|
214
|
-
durations_attacking: u3 = 0,
|
|
215
|
-
/// The number of turns a Pokémon has been observed to be binding their opponent.
|
|
216
|
-
durations_binding: u3 = 0,
|
|
217
|
-
/// The number of turns a Pokémon has been observed to be encored.
|
|
218
|
-
durations_encore: u3 = 0,
|
|
219
|
-
|
|
220
|
-
pub const DURATIONS: u128 = 0xFFFFFFFF00000000_0000000000000000;
|
|
221
|
-
|
|
222
187
|
pub const Field = std.meta.FieldEnum(Action);
|
|
223
188
|
|
|
224
|
-
/// Perform a reset by clearing fields which should not persist across updates.
|
|
225
|
-
pub fn reset(self: *Action) void {
|
|
226
|
-
self.* = @bitCast(@as(u128, @bitCast(self.*)) & DURATIONS);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// TODO: ziglang/zig#19730
|
|
230
|
-
pub fn durations(self: Action) Duration {
|
|
231
|
-
return .{
|
|
232
|
-
.sleep = self.durations_sleep,
|
|
233
|
-
.confusion = self.durations_confusion,
|
|
234
|
-
.thrash = self.durations_thrash,
|
|
235
|
-
.disable = self.durations_disable,
|
|
236
|
-
.attacking = self.durations_attacking,
|
|
237
|
-
.binding = self.durations_binding,
|
|
238
|
-
.encore = self.durations_encore,
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
|
|
242
189
|
pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
|
|
243
190
|
_ = .{ f, o };
|
|
244
191
|
try fmt(a, w, false);
|
|
@@ -247,23 +194,10 @@ pub const Action = packed struct(u128) {
|
|
|
247
194
|
pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
|
|
248
195
|
try writer.writeByte('(');
|
|
249
196
|
var printed = false;
|
|
250
|
-
inline for (@typeInfo(Action)
|
|
197
|
+
inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
|
|
251
198
|
const val = @field(self, field.name);
|
|
252
199
|
switch (@typeInfo(@TypeOf(val))) {
|
|
253
|
-
|
|
254
|
-
// .Struct => inline for (@typeInfo(@TypeOf(val)).Struct.fields) |f| {
|
|
255
|
-
// const v = @field(val, f.name);
|
|
256
|
-
// if (v != 0) {
|
|
257
|
-
// if (printed) try writer.writeAll(", ");
|
|
258
|
-
// if (shape) {
|
|
259
|
-
// try writer.print("{s}:?", .{f.name});
|
|
260
|
-
// } else {
|
|
261
|
-
// try writer.print("{s}:{d}", .{ f.name, v });
|
|
262
|
-
// }
|
|
263
|
-
// printed = true;
|
|
264
|
-
// }
|
|
265
|
-
// },
|
|
266
|
-
.Enum => if (val != .None) {
|
|
200
|
+
Enum => if (val != .None) {
|
|
267
201
|
if (printed) try writer.writeAll(", ");
|
|
268
202
|
if (shape) {
|
|
269
203
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -277,7 +211,7 @@ pub const Action = packed struct(u128) {
|
|
|
277
211
|
}
|
|
278
212
|
printed = true;
|
|
279
213
|
},
|
|
280
|
-
|
|
214
|
+
Int => if (val != 0) {
|
|
281
215
|
if (printed) try writer.writeAll(", ");
|
|
282
216
|
if (shape) {
|
|
283
217
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -293,48 +227,6 @@ pub const Action = packed struct(u128) {
|
|
|
293
227
|
}
|
|
294
228
|
};
|
|
295
229
|
|
|
296
|
-
test Action {
|
|
297
|
-
var a: Action = .{ .hit = .true, .durations_sleep = 3, .damage = 225 };
|
|
298
|
-
a.reset();
|
|
299
|
-
|
|
300
|
-
try expectEqual(Action{ .hit = .None, .durations_sleep = 3, .damage = 0 }, a);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/// TODO
|
|
304
|
-
pub const Durations = extern struct {
|
|
305
|
-
/// Information about the durations for Player 1.
|
|
306
|
-
p1: Duration = .{},
|
|
307
|
-
/// Information about the durations for Player 2.
|
|
308
|
-
p2: Duration = .{},
|
|
309
|
-
|
|
310
|
-
comptime {
|
|
311
|
-
assert(@sizeOf(Durations) == 4);
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
/// Observed values for various durations that need to be tracked in order to properly
|
|
316
|
-
/// deduplicate transitions with a primary key. TODO
|
|
317
|
-
pub const Duration = packed struct(u32) {
|
|
318
|
-
/// The number of turns a Pokémon has been observed to be sleeping.
|
|
319
|
-
sleep: u3 = 0,
|
|
320
|
-
/// The number of turns a Pokémon has been observed to be confused.
|
|
321
|
-
confusion: u3 = 0,
|
|
322
|
-
/// TODO
|
|
323
|
-
thrash: bool = false,
|
|
324
|
-
/// The number of turns a Pokémon has been observed to be disabled.
|
|
325
|
-
disable: u4 = 0,
|
|
326
|
-
/// The number of turns a Pokémon has been observed to be attacking.
|
|
327
|
-
attacking: u3 = 0,
|
|
328
|
-
/// The number of turns a Pokémon has been observed to be binding their opponent.
|
|
329
|
-
binding: u3 = 0,
|
|
330
|
-
/// The number of turns a Pokémon has been observed to be encored.
|
|
331
|
-
encore: u3 = 0,
|
|
332
|
-
|
|
333
|
-
_: u12 = 0,
|
|
334
|
-
|
|
335
|
-
pub const Field = std.meta.FieldEnum(Duration);
|
|
336
|
-
};
|
|
337
|
-
|
|
338
230
|
/// Tracks chance actions and their associated probability during a Generation II battle update when
|
|
339
231
|
/// `options.chance` is enabled.
|
|
340
232
|
pub fn Chance(comptime Rational: type) type {
|
|
@@ -347,45 +239,15 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
347
239
|
/// RNG events were observed during a battle `update`.
|
|
348
240
|
actions: Actions = .{},
|
|
349
241
|
|
|
350
|
-
// Tracks the observed sleep durations for the Pokémon in both player's parties. Unlike
|
|
351
|
-
// other durations which are all tied to volatiles, sleep's counter persists through
|
|
352
|
-
// switching and so we must store it here. The indices of these arrays correspond to the
|
|
353
|
-
// `order` field of a Side. This information could be stored in actions but size is a
|
|
354
|
-
// concern so this is tracked separately as actions only purports to track RNG events
|
|
355
|
-
// observed during a single `update` (not across updates).
|
|
356
|
-
sleeps: [2][6]u3 = .{ .{0} ** 6, .{0} ** 6 },
|
|
357
|
-
|
|
358
242
|
/// Possible error returned by operations tracking chance probability.
|
|
359
243
|
pub const Error = Rational.Error;
|
|
360
244
|
|
|
361
245
|
/// Convenience helper to clear fields which typically should be cleared between updates.
|
|
362
246
|
pub fn reset(self: *Self) void {
|
|
363
|
-
self.probability.reset();
|
|
364
|
-
self.actions.reset();
|
|
365
|
-
// TODO: self.pending = .{};
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
pub fn switched(self: *Self, player: Player, in: u8, out: u8) void {
|
|
369
247
|
if (!enabled) return;
|
|
370
248
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
var action = self.actions.get(player);
|
|
375
|
-
|
|
376
|
-
const slp = action.durations_sleep;
|
|
377
|
-
// TODO: ziglang/zig#19730
|
|
378
|
-
// action.durations = .{};
|
|
379
|
-
action.durations_sleep = 0;
|
|
380
|
-
action.durations_confusion = 0;
|
|
381
|
-
action.durations_thrash = false;
|
|
382
|
-
action.durations_disable = 0;
|
|
383
|
-
action.durations_attacking = 0;
|
|
384
|
-
action.durations_binding = 0;
|
|
385
|
-
action.durations_encore = 0;
|
|
386
|
-
|
|
387
|
-
self.sleeps[@intFromEnum(player)][out - 1] = slp;
|
|
388
|
-
action.durations_sleep = @intCast(self.sleeps[@intFromEnum(player)][in - 1]);
|
|
249
|
+
self.probability.reset();
|
|
250
|
+
self.actions = .{};
|
|
389
251
|
}
|
|
390
252
|
|
|
391
253
|
pub fn speedTie(self: *Self, p1: bool) Error!void {
|
|
@@ -411,19 +273,21 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
411
273
|
self.actions.get(player).hit = if (ok) .true else .false;
|
|
412
274
|
}
|
|
413
275
|
|
|
414
|
-
pub fn criticalHit(self: *Self, player: Player, crit: bool, rate: u8) Error!void {
|
|
276
|
+
pub fn criticalHit(self: *Self, player: Player, i: u3, crit: bool, rate: u8) Error!void {
|
|
415
277
|
if (!enabled) return;
|
|
416
278
|
|
|
417
279
|
const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
|
|
418
280
|
try self.probability.update(n, 256);
|
|
419
|
-
self.actions.get(player)
|
|
281
|
+
var a = self.actions.get(player);
|
|
282
|
+
a.critical_hits = Criticals.set(a.critical_hits, i, if (crit) .true else .false);
|
|
420
283
|
}
|
|
421
284
|
|
|
422
|
-
pub fn damage(self: *Self, player: Player, roll: u8) Error!void {
|
|
285
|
+
pub fn damage(self: *Self, player: Player, i: u3, roll: u8) Error!void {
|
|
423
286
|
if (!enabled) return;
|
|
424
287
|
|
|
425
288
|
try self.probability.update(1, 39);
|
|
426
|
-
self.actions.get(player)
|
|
289
|
+
var a = self.actions.get(player);
|
|
290
|
+
a.damages = Damages.set(a.damages, i, roll);
|
|
427
291
|
}
|
|
428
292
|
|
|
429
293
|
pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
|
|
@@ -575,154 +439,10 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
575
439
|
self.actions.get(player).multi_hit = n;
|
|
576
440
|
}
|
|
577
441
|
|
|
578
|
-
pub fn duration(
|
|
579
|
-
self: *Self,
|
|
580
|
-
comptime field: Duration.Field,
|
|
581
|
-
player: Player,
|
|
582
|
-
target: Player,
|
|
583
|
-
turns: u4,
|
|
584
|
-
) void {
|
|
585
|
-
if (!enabled) return;
|
|
586
|
-
|
|
587
|
-
// TODO: ziglang/zig#19730
|
|
588
|
-
// var durations = &self.actions.get(target).durations;
|
|
589
|
-
// assert(@field(durations, @tagName(field)) == 0 or
|
|
590
|
-
// (field == .confusion and player == target));
|
|
591
|
-
// @field(durations, @tagName(field)) = 1;
|
|
592
|
-
// if (field == .confusion) durations_thrash = player == target;
|
|
593
|
-
switch (field) {
|
|
594
|
-
.sleep => {
|
|
595
|
-
assert(self.actions.get(target).durations_sleep == 0);
|
|
596
|
-
self.actions.get(target).durations_sleep = 1;
|
|
597
|
-
},
|
|
598
|
-
.confusion => {
|
|
599
|
-
assert(self.actions.get(target).durations_confusion == 0 or
|
|
600
|
-
player == target);
|
|
601
|
-
self.actions.get(target).durations_thrash = player == target;
|
|
602
|
-
self.actions.get(target).durations_confusion = 1;
|
|
603
|
-
},
|
|
604
|
-
.thrash => unreachable,
|
|
605
|
-
.disable => {
|
|
606
|
-
assert(self.actions.get(target).durations_disable == 0);
|
|
607
|
-
self.actions.get(target).durations_disable = 1;
|
|
608
|
-
},
|
|
609
|
-
.attacking => {
|
|
610
|
-
assert(self.actions.get(target).durations_attacking == 0);
|
|
611
|
-
self.actions.get(target).durations_attacking = 1;
|
|
612
|
-
},
|
|
613
|
-
.binding => {
|
|
614
|
-
assert(self.actions.get(target).durations_binding == 0);
|
|
615
|
-
self.actions.get(target).durations_binding = 1;
|
|
616
|
-
},
|
|
617
|
-
.encore => {
|
|
618
|
-
assert(self.actions.get(target).durations_encore == 0);
|
|
619
|
-
self.actions.get(target).durations_encore = 1;
|
|
620
|
-
},
|
|
621
|
-
._ => unreachable,
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
self.actions.get(player).duration = if (options.key) 1 else turns;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
pub fn sleep(self: *Self, player: Player, turns: u4) Error!void {
|
|
628
|
-
if (!enabled) return;
|
|
629
|
-
|
|
630
|
-
const durations_sleep = &self.actions.get(player).durations_sleep;
|
|
631
|
-
const n = durations_sleep.*;
|
|
632
|
-
if (turns == 0) {
|
|
633
|
-
assert(n >= 1 and n <= 6);
|
|
634
|
-
if (n != 6) try self.probability.update(1, 7 - @as(u4, n));
|
|
635
|
-
durations_sleep.* = 0;
|
|
636
|
-
} else {
|
|
637
|
-
assert(n >= 1 and n < 6);
|
|
638
|
-
try self.probability.update(7 - @as(u4, n) - 1, 7 - @as(u4, n));
|
|
639
|
-
durations_sleep.* += 1;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
pub fn confusion(self: *Self, player: Player, turns: u4) Error!void {
|
|
644
|
-
if (!enabled) return;
|
|
645
|
-
|
|
646
|
-
const durations_confusion = &self.actions.get(player).durations_confusion;
|
|
647
|
-
const n = durations_confusion.*;
|
|
648
|
-
const hi: u8 = if (self.actions.get(player).durations_thrash) 3 else 5;
|
|
649
|
-
const p = hi + 1;
|
|
650
|
-
if (turns == 0) {
|
|
651
|
-
assert(n >= 2 and n <= hi);
|
|
652
|
-
if (n != hi) try self.probability.update(1, p - @as(u4, n));
|
|
653
|
-
durations_confusion.* = 0;
|
|
654
|
-
} else {
|
|
655
|
-
assert(n >= 1 and n < hi);
|
|
656
|
-
if (n > 1) try self.probability.update(p - @as(u4, n) - 1, p - @as(u4, n));
|
|
657
|
-
durations_confusion.* += 1;
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
pub fn disable(self: *Self, player: Player, turns: u4) Error!void {
|
|
662
|
-
if (!enabled) return;
|
|
663
|
-
|
|
664
|
-
const durations_disable = &self.actions.get(player).durations_disable;
|
|
665
|
-
const n = durations_disable.*;
|
|
666
|
-
const hi = if (showdown) 5 else 8;
|
|
667
|
-
const p = hi + 1;
|
|
668
|
-
if (turns == 0) {
|
|
669
|
-
assert(n >= 2 and n <= hi);
|
|
670
|
-
if (n != hi) try self.probability.update(1, p - n);
|
|
671
|
-
durations_disable.* = 0;
|
|
672
|
-
} else {
|
|
673
|
-
assert(n >= 1 and n < hi);
|
|
674
|
-
if (n > 1) try self.probability.update(p - n - 1, p - n);
|
|
675
|
-
durations_disable.* += 1;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
pub fn attacking(self: *Self, player: Player, turns: u4) Error!void {
|
|
680
|
-
if (!enabled) return;
|
|
681
|
-
|
|
682
|
-
const durations_attacking = &self.actions.get(player).durations_attacking;
|
|
683
|
-
const n = durations_attacking.*;
|
|
684
|
-
if (turns == 0) {
|
|
685
|
-
assert(n >= 2 and n <= 3);
|
|
686
|
-
if (n != 3) try self.probability.update(1, 4 - @as(u4, n));
|
|
687
|
-
durations_attacking.* = 0;
|
|
688
|
-
} else {
|
|
689
|
-
assert(n >= 1 and n < 3);
|
|
690
|
-
if (n > 1) try self.probability.update(4 - @as(u4, n) - 1, 4 - @as(u4, n));
|
|
691
|
-
durations_attacking.* += 1;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
pub fn binding(self: *Self, player: Player, turns: u4) Error!void {
|
|
696
|
-
if (!enabled) return;
|
|
697
|
-
|
|
698
|
-
const durations_binding = &self.actions.get(player).durations_binding;
|
|
699
|
-
const n = durations_binding.*;
|
|
700
|
-
if (turns == 0) {
|
|
701
|
-
assert(n >= 2 and n <= 5);
|
|
702
|
-
if (n != 5) try self.probability.update(1, 6 - @as(u4, n));
|
|
703
|
-
durations_binding.* = 0;
|
|
704
|
-
} else {
|
|
705
|
-
assert(n >= 1 and n < 5);
|
|
706
|
-
if (n > 1) try self.probability.update(6 - @as(u4, n) - 1, 6 - @as(u4, n));
|
|
707
|
-
durations_binding.* += 1;
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
// TODO: consider sharing implementation with binding
|
|
712
|
-
pub fn encore(self: *Self, player: Player, turns: u4) Error!void {
|
|
442
|
+
pub fn duration(self: *Self, player: Player, turns: u3) void {
|
|
713
443
|
if (!enabled) return;
|
|
714
444
|
|
|
715
|
-
|
|
716
|
-
const n = durations_encore.*;
|
|
717
|
-
if (turns == 0) {
|
|
718
|
-
assert(n >= 2 and n <= 5);
|
|
719
|
-
if (n != 5) try self.probability.update(1, 6 - @as(u4, n));
|
|
720
|
-
durations_encore.* = 0;
|
|
721
|
-
} else {
|
|
722
|
-
assert(n >= 1 and n < 5);
|
|
723
|
-
if (n > 1) try self.probability.update(6 - @as(u4, n) - 1, 6 - @as(u4, n));
|
|
724
|
-
durations_encore.* += 1;
|
|
725
|
-
}
|
|
445
|
+
self.actions.get(player).duration = if (options.key) 2 else turns;
|
|
726
446
|
}
|
|
727
447
|
};
|
|
728
448
|
}
|
|
@@ -774,22 +494,22 @@ test "Chance.hit" {
|
|
|
774
494
|
test "Chance.criticalHit" {
|
|
775
495
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
776
496
|
|
|
777
|
-
try chance.criticalHit(.P1, true, 17);
|
|
778
|
-
try expectValue(Optional(bool).true, chance.actions.p1.
|
|
497
|
+
try chance.criticalHit(.P1, 0, true, 17);
|
|
498
|
+
try expectValue(Optional(bool).true, Criticals.get(chance.actions.p1.critical_hits, 0));
|
|
779
499
|
try expectProbability(&chance.probability, 17, 256);
|
|
780
500
|
|
|
781
501
|
chance.reset();
|
|
782
502
|
|
|
783
|
-
try chance.criticalHit(.P2, false, 5);
|
|
503
|
+
try chance.criticalHit(.P2, 1, false, 5);
|
|
784
504
|
try expectProbability(&chance.probability, 251, 256);
|
|
785
|
-
try expectValue(Optional(bool).false, chance.actions.p2.
|
|
505
|
+
try expectValue(Optional(bool).false, Criticals.get(chance.actions.p2.critical_hits, 1));
|
|
786
506
|
}
|
|
787
507
|
|
|
788
508
|
test "Chance.damage" {
|
|
789
509
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
790
510
|
|
|
791
|
-
try chance.damage(.P1,
|
|
792
|
-
try expectValue(
|
|
511
|
+
try chance.damage(.P1, 0, 219);
|
|
512
|
+
try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
|
|
793
513
|
try expectProbability(&chance.probability, 1, 39);
|
|
794
514
|
}
|
|
795
515
|
|
|
@@ -914,7 +634,7 @@ test "Chance.present" {
|
|
|
914
634
|
} else {
|
|
915
635
|
try expectProbability(&chance.probability, 25, 256);
|
|
916
636
|
}
|
|
917
|
-
try expectValue(4, chance.actions.p2.present);
|
|
637
|
+
try expectValue(@as(u3, 4), chance.actions.p2.present);
|
|
918
638
|
|
|
919
639
|
chance.reset();
|
|
920
640
|
|
|
@@ -924,7 +644,7 @@ test "Chance.present" {
|
|
|
924
644
|
} else {
|
|
925
645
|
try expectProbability(&chance.probability, 51, 256);
|
|
926
646
|
}
|
|
927
|
-
try expectValue(1, chance.actions.p1.present);
|
|
647
|
+
try expectValue(@as(u3, 1), chance.actions.p1.present);
|
|
928
648
|
}
|
|
929
649
|
|
|
930
650
|
test "Chance.magnitude" {
|
|
@@ -936,7 +656,7 @@ test "Chance.magnitude" {
|
|
|
936
656
|
} else {
|
|
937
657
|
try expectProbability(&chance.probability, 13, 256);
|
|
938
658
|
}
|
|
939
|
-
try expectValue(7, chance.actions.p2.magnitude);
|
|
659
|
+
try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
|
|
940
660
|
|
|
941
661
|
chance.reset();
|
|
942
662
|
|
|
@@ -946,7 +666,7 @@ test "Chance.magnitude" {
|
|
|
946
666
|
} else {
|
|
947
667
|
try expectProbability(&chance.probability, 51, 256);
|
|
948
668
|
}
|
|
949
|
-
try expectValue(5, chance.actions.p1.magnitude);
|
|
669
|
+
try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
|
|
950
670
|
}
|
|
951
671
|
|
|
952
672
|
test "Chance.tripleKick" {
|
|
@@ -954,7 +674,7 @@ test "Chance.tripleKick" {
|
|
|
954
674
|
|
|
955
675
|
try chance.tripleKick(.P1, 2);
|
|
956
676
|
try expectProbability(&chance.probability, 1, 3);
|
|
957
|
-
try expectValue(2, chance.actions.p1.triple_kick);
|
|
677
|
+
try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
|
|
958
678
|
}
|
|
959
679
|
|
|
960
680
|
test "Chance.spite" {
|
|
@@ -962,7 +682,7 @@ test "Chance.spite" {
|
|
|
962
682
|
|
|
963
683
|
try chance.spite(.P1, 3);
|
|
964
684
|
try expectProbability(&chance.probability, 1, 4);
|
|
965
|
-
try expectValue(3, chance.actions.p1.spite);
|
|
685
|
+
try expectValue(@as(u3, 3), chance.actions.p1.spite);
|
|
966
686
|
}
|
|
967
687
|
|
|
968
688
|
test "Chance.conversion2" {
|
|
@@ -989,7 +709,7 @@ test "Chance.psywave" {
|
|
|
989
709
|
|
|
990
710
|
try chance.psywave(.P2, 100, 150);
|
|
991
711
|
try expectProbability(&chance.probability, 1, 150);
|
|
992
|
-
try expectValue(100, chance.actions.p2.psywave);
|
|
712
|
+
try expectValue(@as(u8, 100), chance.actions.p2.psywave);
|
|
993
713
|
}
|
|
994
714
|
|
|
995
715
|
test "Chance.metronome" {
|
|
@@ -1005,19 +725,19 @@ test "Chance.moveSlot" {
|
|
|
1005
725
|
|
|
1006
726
|
try chance.moveSlot(.P2, 2, 2);
|
|
1007
727
|
try expectProbability(&chance.probability, 1, 2);
|
|
1008
|
-
try expectValue(2, chance.actions.p2.move_slot);
|
|
728
|
+
try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
|
|
1009
729
|
|
|
1010
730
|
chance.reset();
|
|
1011
731
|
|
|
1012
732
|
try chance.moveSlot(.P1, 1, 3);
|
|
1013
733
|
try expectProbability(&chance.probability, 1, 3);
|
|
1014
|
-
try expectValue(1, chance.actions.p1.move_slot);
|
|
734
|
+
try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
|
|
1015
735
|
|
|
1016
736
|
chance.reset();
|
|
1017
737
|
|
|
1018
738
|
try chance.moveSlot(.P1, 4, 1);
|
|
1019
739
|
try expectProbability(&chance.probability, 1, 1);
|
|
1020
|
-
try expectValue(4, chance.actions.p1.move_slot);
|
|
740
|
+
try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
|
|
1021
741
|
}
|
|
1022
742
|
|
|
1023
743
|
test "Chance.forceSwitch" {
|
|
@@ -1025,19 +745,19 @@ test "Chance.forceSwitch" {
|
|
|
1025
745
|
|
|
1026
746
|
try chance.forceSwitch(.P2, 2, 2);
|
|
1027
747
|
try expectProbability(&chance.probability, 1, 2);
|
|
1028
|
-
try expectValue(2, chance.actions.p2.force_switch);
|
|
748
|
+
try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
|
|
1029
749
|
|
|
1030
750
|
chance.reset();
|
|
1031
751
|
|
|
1032
752
|
try chance.forceSwitch(.P1, 1, 3);
|
|
1033
753
|
try expectProbability(&chance.probability, 1, 3);
|
|
1034
|
-
try expectValue(1, chance.actions.p1.force_switch);
|
|
754
|
+
try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
|
|
1035
755
|
|
|
1036
756
|
chance.reset();
|
|
1037
757
|
|
|
1038
758
|
try chance.forceSwitch(.P1, 4, 1);
|
|
1039
759
|
try expectProbability(&chance.probability, 1, 1);
|
|
1040
|
-
try expectValue(4, chance.actions.p1.force_switch);
|
|
760
|
+
try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
|
|
1041
761
|
}
|
|
1042
762
|
|
|
1043
763
|
test "Chance.multiHit" {
|
|
@@ -1045,212 +765,20 @@ test "Chance.multiHit" {
|
|
|
1045
765
|
|
|
1046
766
|
try chance.multiHit(.P1, 3);
|
|
1047
767
|
try expectProbability(&chance.probability, 3, 8);
|
|
1048
|
-
try expectValue(3, chance.actions.p1.multi_hit);
|
|
768
|
+
try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
|
|
1049
769
|
|
|
1050
770
|
chance.reset();
|
|
1051
771
|
|
|
1052
772
|
try chance.multiHit(.P2, 5);
|
|
1053
773
|
try expectProbability(&chance.probability, 1, 8);
|
|
1054
|
-
try expectValue(5, chance.actions.p2.multi_hit);
|
|
774
|
+
try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
|
|
1055
775
|
}
|
|
1056
776
|
|
|
1057
777
|
test "Chance.duration" {
|
|
1058
778
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1059
779
|
|
|
1060
|
-
chance.duration(.
|
|
1061
|
-
try expectValue(2, chance.actions.p1.duration);
|
|
1062
|
-
try expectValue(1, chance.actions.p2.durations_sleep);
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
test "Chance.sleep" {
|
|
1066
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1067
|
-
|
|
1068
|
-
for ([_]u8{ 6, 5, 4, 3, 2, 1 }, 1..7) |d, i| {
|
|
1069
|
-
chance.actions.p1.durations_sleep = @intCast(i);
|
|
1070
|
-
try chance.sleep(.P1, 0);
|
|
1071
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1072
|
-
try expectValue(0, chance.actions.p1.durations_sleep);
|
|
1073
|
-
|
|
1074
|
-
chance.reset();
|
|
1075
|
-
|
|
1076
|
-
if (i < 6) {
|
|
1077
|
-
chance.actions.p1.durations_sleep = @intCast(i);
|
|
1078
|
-
try chance.sleep(.P1, 1);
|
|
1079
|
-
try expectProbability(&chance.probability, d - 1, d);
|
|
1080
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p1.durations_sleep);
|
|
1081
|
-
|
|
1082
|
-
chance.reset();
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
test "Chance.confusion" {
|
|
1088
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1089
|
-
|
|
1090
|
-
chance.actions.p2.durations_thrash = false;
|
|
1091
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1092
|
-
if (i > 1) {
|
|
1093
|
-
chance.actions.p2.durations_confusion = @intCast(i);
|
|
1094
|
-
try chance.confusion(.P2, 0);
|
|
1095
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1096
|
-
try expectValue(0, chance.actions.p2.durations_confusion);
|
|
1097
|
-
try expectValue(false, chance.actions.p2.durations_thrash);
|
|
1098
|
-
|
|
1099
|
-
chance.reset();
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
if (i < 5) {
|
|
1103
|
-
chance.actions.p2.durations_confusion = @intCast(i);
|
|
1104
|
-
try chance.confusion(.P2, 1);
|
|
1105
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1106
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations_confusion);
|
|
1107
|
-
try expectValue(false, chance.actions.p2.durations_thrash);
|
|
1108
|
-
|
|
1109
|
-
chance.reset();
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
chance.reset();
|
|
1114
|
-
|
|
1115
|
-
chance.actions.p2.durations_thrash = true;
|
|
1116
|
-
for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
|
|
1117
|
-
if (i > 1) {
|
|
1118
|
-
chance.actions.p2.durations_confusion = @intCast(i);
|
|
1119
|
-
try chance.confusion(.P2, 0);
|
|
1120
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1121
|
-
try expectValue(0, chance.actions.p2.durations_confusion);
|
|
1122
|
-
try expectValue(true, chance.actions.p2.durations_thrash);
|
|
1123
|
-
|
|
1124
|
-
chance.reset();
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
if (i < 3) {
|
|
1128
|
-
chance.actions.p2.durations_confusion = @intCast(i);
|
|
1129
|
-
try chance.confusion(.P2, 1);
|
|
1130
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1131
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations_confusion);
|
|
1132
|
-
try expectValue(true, chance.actions.p2.durations_thrash);
|
|
1133
|
-
|
|
1134
|
-
chance.reset();
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
test "Chance.disable" {
|
|
1140
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1141
|
-
if (showdown) {
|
|
1142
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1143
|
-
if (i > 1) {
|
|
1144
|
-
chance.actions.p2.durations_disable = @intCast(i);
|
|
1145
|
-
try chance.disable(.P2, 0);
|
|
1146
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1147
|
-
try expectValue(0, chance.actions.p2.durations_disable);
|
|
1148
|
-
|
|
1149
|
-
chance.reset();
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
if (i < 5) {
|
|
1153
|
-
chance.actions.p2.durations_disable = @intCast(i);
|
|
1154
|
-
try chance.disable(.P2, 1);
|
|
1155
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1156
|
-
try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p2.durations_disable);
|
|
1157
|
-
|
|
1158
|
-
chance.reset();
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
} else {
|
|
1162
|
-
for ([_]u8{ 1, 7, 6, 5, 4, 3, 2, 1 }, 1..9) |d, i| {
|
|
1163
|
-
if (i > 1) {
|
|
1164
|
-
chance.actions.p2.durations_disable = @intCast(i);
|
|
1165
|
-
try chance.disable(.P2, 0);
|
|
1166
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1167
|
-
try expectValue(0, chance.actions.p2.durations_disable);
|
|
1168
|
-
|
|
1169
|
-
chance.reset();
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
if (i < 8) {
|
|
1173
|
-
chance.actions.p2.durations_disable = @intCast(i);
|
|
1174
|
-
try chance.disable(.P2, 1);
|
|
1175
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1176
|
-
try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p2.durations_disable);
|
|
1177
|
-
|
|
1178
|
-
chance.reset();
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
test "Chance.attacking" {
|
|
1185
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1186
|
-
|
|
1187
|
-
for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
|
|
1188
|
-
if (i > 1) {
|
|
1189
|
-
chance.actions.p2.durations_attacking = @intCast(i);
|
|
1190
|
-
try chance.attacking(.P2, 0);
|
|
1191
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1192
|
-
try expectValue(0, chance.actions.p2.durations_attacking);
|
|
1193
|
-
|
|
1194
|
-
chance.reset();
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
if (i < 3) {
|
|
1198
|
-
chance.actions.p2.durations_attacking = @intCast(i);
|
|
1199
|
-
try chance.attacking(.P2, 1);
|
|
1200
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1201
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations_attacking);
|
|
1202
|
-
|
|
1203
|
-
chance.reset();
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
test "Chance.binding" {
|
|
1209
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1210
|
-
|
|
1211
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1212
|
-
if (i > 1) {
|
|
1213
|
-
chance.actions.p2.durations_binding = @intCast(i);
|
|
1214
|
-
try chance.binding(.P2, 0);
|
|
1215
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1216
|
-
try expectValue(0, chance.actions.p2.durations_binding);
|
|
1217
|
-
|
|
1218
|
-
chance.reset();
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
if (i < 5) {
|
|
1222
|
-
chance.actions.p2.durations_binding = @intCast(i);
|
|
1223
|
-
try chance.binding(.P2, 1);
|
|
1224
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1225
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations_binding);
|
|
1226
|
-
|
|
1227
|
-
chance.reset();
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
test "Chance.encore" {
|
|
1233
|
-
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
1234
|
-
|
|
1235
|
-
for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
|
|
1236
|
-
if (i > 1) {
|
|
1237
|
-
chance.actions.p2.durations_encore = @intCast(i);
|
|
1238
|
-
try chance.encore(.P2, 0);
|
|
1239
|
-
try expectProbability(&chance.probability, 1, d);
|
|
1240
|
-
try expectValue(0, chance.actions.p2.durations_encore);
|
|
1241
|
-
|
|
1242
|
-
chance.reset();
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
if (i < 5) {
|
|
1246
|
-
chance.actions.p2.durations_encore = @intCast(i);
|
|
1247
|
-
try chance.encore(.P2, 1);
|
|
1248
|
-
try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
|
|
1249
|
-
try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations_encore);
|
|
1250
|
-
|
|
1251
|
-
chance.reset();
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
780
|
+
chance.duration(.P1, 2);
|
|
781
|
+
try expectValue(@as(u3, 2), chance.actions.p1.duration);
|
|
1254
782
|
}
|
|
1255
783
|
|
|
1256
784
|
pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
@@ -1292,12 +820,12 @@ const Null = struct {
|
|
|
1292
820
|
_ = .{ self, player, ok, accuracy };
|
|
1293
821
|
}
|
|
1294
822
|
|
|
1295
|
-
pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
|
|
1296
|
-
_ = .{ self, player, crit, rate };
|
|
823
|
+
pub fn criticalHit(self: Null, player: Player, i: u3, crit: bool, rate: u8) Error!void {
|
|
824
|
+
_ = .{ self, player, i, crit, rate };
|
|
1297
825
|
}
|
|
1298
826
|
|
|
1299
|
-
pub fn damage(self: Null, player: Player, roll: u8) Error!void {
|
|
1300
|
-
_ = .{ self, player, roll };
|
|
827
|
+
pub fn damage(self: Null, player: Player, i: u3, roll: u8) Error!void {
|
|
828
|
+
_ = .{ self, player, i, roll };
|
|
1301
829
|
}
|
|
1302
830
|
|
|
1303
831
|
pub fn confused(self: Null, player: Player, ok: bool) Error!void {
|
|
@@ -1368,37 +896,7 @@ const Null = struct {
|
|
|
1368
896
|
_ = .{ self, player, move, n };
|
|
1369
897
|
}
|
|
1370
898
|
|
|
1371
|
-
pub fn duration(
|
|
1372
|
-
self: Null,
|
|
1373
|
-
comptime field: Duration.Field,
|
|
1374
|
-
player: Player,
|
|
1375
|
-
target: Player,
|
|
1376
|
-
turns: u4,
|
|
1377
|
-
) void {
|
|
1378
|
-
_ = .{ self, field, player, target, turns };
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
pub fn sleep(self: Null, player: Player, turns: u4) Error!void {
|
|
1382
|
-
_ = .{ self, player, turns };
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
pub fn confusion(self: Null, player: Player, turns: u4) Error!void {
|
|
1386
|
-
_ = .{ self, player, turns };
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
pub fn disable(self: Null, player: Player, turns: u4) Error!void {
|
|
1390
|
-
_ = .{ self, player, turns };
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
pub fn attacking(self: Null, player: Player, turns: u4) Error!void {
|
|
1394
|
-
_ = .{ self, player, turns };
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
pub fn binding(self: Null, player: Player, turns: u4) Error!void {
|
|
1398
|
-
_ = .{ self, player, turns };
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
pub fn encore(self: Null, player: Player, turns: u4) Error!void {
|
|
899
|
+
pub fn duration(self: Null, player: Player, turns: u3) void {
|
|
1402
900
|
_ = .{ self, player, turns };
|
|
1403
901
|
}
|
|
1404
902
|
};
|