@pkmn/engine 0.1.0-dev.deda8593 → 0.1.0-dev.e0a786f8
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 +9 -6
- 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 +25 -3
- 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 +52 -76
- 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 +330 -85
- package/package.json +54 -135
- package/src/bin/install-pkmn-engine +10 -7
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/bindings/c.zig +255 -0
- package/src/lib/bindings/node.zig +121 -0
- package/src/lib/bindings/wasm.zig +59 -0
- 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 +4 -0
- package/src/lib/common/protocol.zig +45 -44
- package/src/lib/common/rational.zig +323 -157
- package/src/lib/common/rng.zig +5 -7
- package/src/lib/common/util.zig +60 -1
- package/src/lib/gen1/calc.zig +527 -161
- package/src/lib/gen1/chance.zig +366 -240
- 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 +1 -2
- package/src/lib/gen1/data.zig +35 -38
- package/src/lib/gen1/helpers.zig +17 -554
- package/src/lib/gen1/mechanics.zig +280 -193
- package/src/lib/gen2/calc.zig +37 -27
- package/src/lib/gen2/chance.zig +90 -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 +1 -2
- package/src/lib/gen2/data.zig +26 -29
- package/src/lib/gen2/generated.zig +18 -23
- package/src/lib/gen2/helpers.zig +9 -18
- package/src/lib/gen2/mechanics.zig +88 -115
- package/src/lib/node.zig +3 -116
- package/src/lib/pkmn.zig +14 -7
- package/src/lib/wasm.zig +13 -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,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,17 +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
50
|
/// Returns true if `a` is equal to `b`.
|
|
52
51
|
pub fn eql(a: Actions, b: Actions) bool {
|
|
53
52
|
return @as(u128, @bitCast(a.p1)) == @as(u128, @bitCast(b.p1)) and
|
|
@@ -58,24 +57,15 @@ pub const Actions = extern struct {
|
|
|
58
57
|
/// same shape if they have the same fields set (though those fields need not necessarily be
|
|
59
58
|
/// set to the same value).
|
|
60
59
|
pub fn matches(a: Actions, b: Actions) bool {
|
|
61
|
-
inline for (@typeInfo(Actions)
|
|
62
|
-
inline for (@typeInfo(Action)
|
|
60
|
+
inline for (@field(@typeInfo(Actions), @tagName(Struct)).fields) |player| {
|
|
61
|
+
inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
|
|
63
62
|
const a_val = @field(@field(a, player.name), field.name);
|
|
64
63
|
const b_val = @field(@field(b, player.name), field.name);
|
|
65
64
|
|
|
66
65
|
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))
|
|
66
|
+
Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
77
67
|
return false,
|
|
78
|
-
|
|
68
|
+
Int => if ((a_val > 0) != (b_val > 0)) return false,
|
|
79
69
|
else => unreachable,
|
|
80
70
|
}
|
|
81
71
|
}
|
|
@@ -97,17 +87,10 @@ pub const Actions = extern struct {
|
|
|
97
87
|
}
|
|
98
88
|
};
|
|
99
89
|
|
|
100
|
-
// TODO: ziglang/zig#19730
|
|
101
90
|
test Actions {
|
|
102
|
-
const a: Actions = .{ .p1 = .{ .hit = .true, .
|
|
103
|
-
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 } };
|
|
104
93
|
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
94
|
|
|
112
95
|
try expect(a.eql(a));
|
|
113
96
|
try expect(!a.eql(b));
|
|
@@ -120,17 +103,21 @@ test Actions {
|
|
|
120
103
|
try expect(b.matches(a));
|
|
121
104
|
try expect(!a.matches(c));
|
|
122
105
|
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
106
|
}
|
|
128
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
|
+
|
|
129
114
|
/// Information about the RNG that was observed during a Generation II battle `update` for a
|
|
130
115
|
/// single player.
|
|
131
116
|
pub const Action = packed struct(u128) {
|
|
132
|
-
///
|
|
133
|
-
|
|
117
|
+
/// TODO
|
|
118
|
+
damages: Damages.T = 0,
|
|
119
|
+
// TODO
|
|
120
|
+
critical_hits: Criticals.T = 0,
|
|
134
121
|
|
|
135
122
|
/// If not None, the Player to be returned by Rolls.speedTie.
|
|
136
123
|
speed_tie: Optional(Player) = .None,
|
|
@@ -138,50 +125,58 @@ pub const Action = packed struct(u128) {
|
|
|
138
125
|
quick_claw: Optional(bool) = .None,
|
|
139
126
|
/// If not None, the value to return for Rolls.hit.
|
|
140
127
|
hit: Optional(bool) = .None,
|
|
141
|
-
/// If not None, the value to be returned by Rolls.criticalHit.
|
|
142
|
-
critical_hit: Optional(bool) = .None,
|
|
143
|
-
|
|
144
128
|
/// If not None, the value to return for Rolls.confused.
|
|
145
129
|
confused: Optional(bool) = .None,
|
|
130
|
+
|
|
146
131
|
/// If not None, the value to return for Rolls.attract.
|
|
147
132
|
attract: Optional(bool) = .None,
|
|
148
133
|
/// If not None, the value to return for Rolls.paralyzed.
|
|
149
134
|
paralyzed: Optional(bool) = .None,
|
|
150
135
|
/// If not None, the value to return for Rolls.defrost.
|
|
151
136
|
defrost: Optional(bool) = .None,
|
|
152
|
-
|
|
153
137
|
/// If not None, the value to be returned for Rolls.secondaryChance.
|
|
154
138
|
secondary_chance: Optional(bool) = .None,
|
|
139
|
+
|
|
155
140
|
/// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
|
|
156
141
|
item: Optional(bool) = .None,
|
|
157
142
|
/// If not None, the value to be returned for Rolls.protect.
|
|
158
143
|
protect: Optional(bool) = .None,
|
|
159
144
|
/// If not None, the value to return for Rolls.triAttack.
|
|
160
145
|
tri_attack: Optional(TriAttack) = .None,
|
|
146
|
+
/// If not 0, the value to return for Rolls.tripleKick.
|
|
147
|
+
triple_kick: u2 = 0,
|
|
161
148
|
|
|
162
149
|
/// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
|
|
163
150
|
present: u3 = 0,
|
|
164
151
|
/// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
|
|
165
152
|
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.
|
|
153
|
+
/// If not 0, the amount of PP to deduct for Rolls.spite.
|
|
170
154
|
spite: u3 = 0,
|
|
171
|
-
/// If not None, the value to return for Rolls.conversion2.
|
|
172
|
-
conversion_2: Optional(Type) = .None,
|
|
173
|
-
|
|
174
155
|
/// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
|
|
175
156
|
/// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
|
|
176
|
-
move_slot:
|
|
157
|
+
move_slot: u3 = 0,
|
|
177
158
|
/// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
|
|
178
159
|
/// invalid values (eg. due to empty party slots or fainted members) will be ignored.
|
|
179
|
-
force_switch:
|
|
180
|
-
|
|
160
|
+
force_switch: u3 = 0,
|
|
181
161
|
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
182
|
-
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
|
+
|
|
183
176
|
/// If not 0, the value to by one of the Rolls.*Duration rolls.
|
|
184
|
-
duration:
|
|
177
|
+
duration: u3 = 0,
|
|
178
|
+
/// If not None, the value to return for Rolls.conversion2.
|
|
179
|
+
conversion_2: Optional(Type) = .None,
|
|
185
180
|
|
|
186
181
|
/// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
|
|
187
182
|
psywave: u8 = 0,
|
|
@@ -189,20 +184,8 @@ pub const Action = packed struct(u128) {
|
|
|
189
184
|
/// If not None, the Move to return for Rolls.metronome.
|
|
190
185
|
metronome: Move = .None,
|
|
191
186
|
|
|
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
187
|
pub const Field = std.meta.FieldEnum(Action);
|
|
200
188
|
|
|
201
|
-
/// Perform a reset by clearing fields which should not persist across updates.
|
|
202
|
-
pub fn reset(self: *Action) void {
|
|
203
|
-
self.* = @bitCast(@as(u128, @bitCast(self.*)) & DURATIONS);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
189
|
pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
|
|
207
190
|
_ = .{ f, o };
|
|
208
191
|
try fmt(a, w, false);
|
|
@@ -211,22 +194,10 @@ pub const Action = packed struct(u128) {
|
|
|
211
194
|
pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
|
|
212
195
|
try writer.writeByte('(');
|
|
213
196
|
var printed = false;
|
|
214
|
-
inline for (@typeInfo(Action)
|
|
197
|
+
inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
|
|
215
198
|
const val = @field(self, field.name);
|
|
216
199
|
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) {
|
|
200
|
+
Enum => if (val != .None) {
|
|
230
201
|
if (printed) try writer.writeAll(", ");
|
|
231
202
|
if (shape) {
|
|
232
203
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -240,7 +211,7 @@ pub const Action = packed struct(u128) {
|
|
|
240
211
|
}
|
|
241
212
|
printed = true;
|
|
242
213
|
},
|
|
243
|
-
|
|
214
|
+
Int => if (val != 0) {
|
|
244
215
|
if (printed) try writer.writeAll(", ");
|
|
245
216
|
if (shape) {
|
|
246
217
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -256,36 +227,6 @@ pub const Action = packed struct(u128) {
|
|
|
256
227
|
}
|
|
257
228
|
};
|
|
258
229
|
|
|
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
230
|
/// Tracks chance actions and their associated probability during a Generation II battle update when
|
|
290
231
|
/// `options.chance` is enabled.
|
|
291
232
|
pub fn Chance(comptime Rational: type) type {
|
|
@@ -298,37 +239,15 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
298
239
|
/// RNG events were observed during a battle `update`.
|
|
299
240
|
actions: Actions = .{},
|
|
300
241
|
|
|
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
242
|
/// Possible error returned by operations tracking chance probability.
|
|
310
243
|
pub const Error = Rational.Error;
|
|
311
244
|
|
|
312
245
|
/// Convenience helper to clear fields which typically should be cleared between updates.
|
|
313
246
|
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
247
|
if (!enabled) return;
|
|
321
248
|
|
|
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]);
|
|
249
|
+
self.probability.reset();
|
|
250
|
+
self.actions = .{};
|
|
332
251
|
}
|
|
333
252
|
|
|
334
253
|
pub fn speedTie(self: *Self, p1: bool) Error!void {
|
|
@@ -354,19 +273,21 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
354
273
|
self.actions.get(player).hit = if (ok) .true else .false;
|
|
355
274
|
}
|
|
356
275
|
|
|
357
|
-
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 {
|
|
358
277
|
if (!enabled) return;
|
|
359
278
|
|
|
360
279
|
const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
|
|
361
280
|
try self.probability.update(n, 256);
|
|
362
|
-
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);
|
|
363
283
|
}
|
|
364
284
|
|
|
365
|
-
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 {
|
|
366
286
|
if (!enabled) return;
|
|
367
287
|
|
|
368
288
|
try self.probability.update(1, 39);
|
|
369
|
-
self.actions.get(player)
|
|
289
|
+
var a = self.actions.get(player);
|
|
290
|
+
a.damages = Damages.set(a.damages, i, roll);
|
|
370
291
|
}
|
|
371
292
|
|
|
372
293
|
pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
|
|
@@ -518,122 +439,10 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
518
439
|
self.actions.get(player).multi_hit = n;
|
|
519
440
|
}
|
|
520
441
|
|
|
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 {
|
|
442
|
+
pub fn duration(self: *Self, player: Player, turns: u3) void {
|
|
591
443
|
if (!enabled) return;
|
|
592
444
|
|
|
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
|
-
}
|
|
445
|
+
self.actions.get(player).duration = if (options.key) 2 else turns;
|
|
637
446
|
}
|
|
638
447
|
};
|
|
639
448
|
}
|
|
@@ -685,22 +494,22 @@ test "Chance.hit" {
|
|
|
685
494
|
test "Chance.criticalHit" {
|
|
686
495
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
687
496
|
|
|
688
|
-
try chance.criticalHit(.P1, true, 17);
|
|
689
|
-
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));
|
|
690
499
|
try expectProbability(&chance.probability, 17, 256);
|
|
691
500
|
|
|
692
501
|
chance.reset();
|
|
693
502
|
|
|
694
|
-
try chance.criticalHit(.P2, false, 5);
|
|
503
|
+
try chance.criticalHit(.P2, 1, false, 5);
|
|
695
504
|
try expectProbability(&chance.probability, 251, 256);
|
|
696
|
-
try expectValue(Optional(bool).false, chance.actions.p2.
|
|
505
|
+
try expectValue(Optional(bool).false, Criticals.get(chance.actions.p2.critical_hits, 1));
|
|
697
506
|
}
|
|
698
507
|
|
|
699
508
|
test "Chance.damage" {
|
|
700
509
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
701
510
|
|
|
702
|
-
try chance.damage(.P1,
|
|
703
|
-
try expectValue(
|
|
511
|
+
try chance.damage(.P1, 0, 219);
|
|
512
|
+
try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
|
|
704
513
|
try expectProbability(&chance.probability, 1, 39);
|
|
705
514
|
}
|
|
706
515
|
|
|
@@ -825,7 +634,7 @@ test "Chance.present" {
|
|
|
825
634
|
} else {
|
|
826
635
|
try expectProbability(&chance.probability, 25, 256);
|
|
827
636
|
}
|
|
828
|
-
try expectValue(4, chance.actions.p2.present);
|
|
637
|
+
try expectValue(@as(u3, 4), chance.actions.p2.present);
|
|
829
638
|
|
|
830
639
|
chance.reset();
|
|
831
640
|
|
|
@@ -835,7 +644,7 @@ test "Chance.present" {
|
|
|
835
644
|
} else {
|
|
836
645
|
try expectProbability(&chance.probability, 51, 256);
|
|
837
646
|
}
|
|
838
|
-
try expectValue(1, chance.actions.p1.present);
|
|
647
|
+
try expectValue(@as(u3, 1), chance.actions.p1.present);
|
|
839
648
|
}
|
|
840
649
|
|
|
841
650
|
test "Chance.magnitude" {
|
|
@@ -847,7 +656,7 @@ test "Chance.magnitude" {
|
|
|
847
656
|
} else {
|
|
848
657
|
try expectProbability(&chance.probability, 13, 256);
|
|
849
658
|
}
|
|
850
|
-
try expectValue(7, chance.actions.p2.magnitude);
|
|
659
|
+
try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
|
|
851
660
|
|
|
852
661
|
chance.reset();
|
|
853
662
|
|
|
@@ -857,7 +666,7 @@ test "Chance.magnitude" {
|
|
|
857
666
|
} else {
|
|
858
667
|
try expectProbability(&chance.probability, 51, 256);
|
|
859
668
|
}
|
|
860
|
-
try expectValue(5, chance.actions.p1.magnitude);
|
|
669
|
+
try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
|
|
861
670
|
}
|
|
862
671
|
|
|
863
672
|
test "Chance.tripleKick" {
|
|
@@ -865,7 +674,7 @@ test "Chance.tripleKick" {
|
|
|
865
674
|
|
|
866
675
|
try chance.tripleKick(.P1, 2);
|
|
867
676
|
try expectProbability(&chance.probability, 1, 3);
|
|
868
|
-
try expectValue(2, chance.actions.p1.triple_kick);
|
|
677
|
+
try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
|
|
869
678
|
}
|
|
870
679
|
|
|
871
680
|
test "Chance.spite" {
|
|
@@ -873,7 +682,7 @@ test "Chance.spite" {
|
|
|
873
682
|
|
|
874
683
|
try chance.spite(.P1, 3);
|
|
875
684
|
try expectProbability(&chance.probability, 1, 4);
|
|
876
|
-
try expectValue(3, chance.actions.p1.spite);
|
|
685
|
+
try expectValue(@as(u3, 3), chance.actions.p1.spite);
|
|
877
686
|
}
|
|
878
687
|
|
|
879
688
|
test "Chance.conversion2" {
|
|
@@ -900,7 +709,7 @@ test "Chance.psywave" {
|
|
|
900
709
|
|
|
901
710
|
try chance.psywave(.P2, 100, 150);
|
|
902
711
|
try expectProbability(&chance.probability, 1, 150);
|
|
903
|
-
try expectValue(100, chance.actions.p2.psywave);
|
|
712
|
+
try expectValue(@as(u8, 100), chance.actions.p2.psywave);
|
|
904
713
|
}
|
|
905
714
|
|
|
906
715
|
test "Chance.metronome" {
|
|
@@ -916,19 +725,19 @@ test "Chance.moveSlot" {
|
|
|
916
725
|
|
|
917
726
|
try chance.moveSlot(.P2, 2, 2);
|
|
918
727
|
try expectProbability(&chance.probability, 1, 2);
|
|
919
|
-
try expectValue(2, chance.actions.p2.move_slot);
|
|
728
|
+
try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
|
|
920
729
|
|
|
921
730
|
chance.reset();
|
|
922
731
|
|
|
923
732
|
try chance.moveSlot(.P1, 1, 3);
|
|
924
733
|
try expectProbability(&chance.probability, 1, 3);
|
|
925
|
-
try expectValue(1, chance.actions.p1.move_slot);
|
|
734
|
+
try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
|
|
926
735
|
|
|
927
736
|
chance.reset();
|
|
928
737
|
|
|
929
738
|
try chance.moveSlot(.P1, 4, 1);
|
|
930
739
|
try expectProbability(&chance.probability, 1, 1);
|
|
931
|
-
try expectValue(4, chance.actions.p1.move_slot);
|
|
740
|
+
try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
|
|
932
741
|
}
|
|
933
742
|
|
|
934
743
|
test "Chance.forceSwitch" {
|
|
@@ -936,19 +745,19 @@ test "Chance.forceSwitch" {
|
|
|
936
745
|
|
|
937
746
|
try chance.forceSwitch(.P2, 2, 2);
|
|
938
747
|
try expectProbability(&chance.probability, 1, 2);
|
|
939
|
-
try expectValue(2, chance.actions.p2.force_switch);
|
|
748
|
+
try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
|
|
940
749
|
|
|
941
750
|
chance.reset();
|
|
942
751
|
|
|
943
752
|
try chance.forceSwitch(.P1, 1, 3);
|
|
944
753
|
try expectProbability(&chance.probability, 1, 3);
|
|
945
|
-
try expectValue(1, chance.actions.p1.force_switch);
|
|
754
|
+
try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
|
|
946
755
|
|
|
947
756
|
chance.reset();
|
|
948
757
|
|
|
949
758
|
try chance.forceSwitch(.P1, 4, 1);
|
|
950
759
|
try expectProbability(&chance.probability, 1, 1);
|
|
951
|
-
try expectValue(4, chance.actions.p1.force_switch);
|
|
760
|
+
try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
|
|
952
761
|
}
|
|
953
762
|
|
|
954
763
|
test "Chance.multiHit" {
|
|
@@ -956,212 +765,20 @@ test "Chance.multiHit" {
|
|
|
956
765
|
|
|
957
766
|
try chance.multiHit(.P1, 3);
|
|
958
767
|
try expectProbability(&chance.probability, 3, 8);
|
|
959
|
-
try expectValue(3, chance.actions.p1.multi_hit);
|
|
768
|
+
try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
|
|
960
769
|
|
|
961
770
|
chance.reset();
|
|
962
771
|
|
|
963
772
|
try chance.multiHit(.P2, 5);
|
|
964
773
|
try expectProbability(&chance.probability, 1, 8);
|
|
965
|
-
try expectValue(5, chance.actions.p2.multi_hit);
|
|
774
|
+
try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
|
|
966
775
|
}
|
|
967
776
|
|
|
968
777
|
test "Chance.duration" {
|
|
969
778
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
970
779
|
|
|
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
|
-
}
|
|
780
|
+
chance.duration(.P1, 2);
|
|
781
|
+
try expectValue(@as(u3, 2), chance.actions.p1.duration);
|
|
1165
782
|
}
|
|
1166
783
|
|
|
1167
784
|
pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
@@ -1203,12 +820,12 @@ const Null = struct {
|
|
|
1203
820
|
_ = .{ self, player, ok, accuracy };
|
|
1204
821
|
}
|
|
1205
822
|
|
|
1206
|
-
pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
|
|
1207
|
-
_ = .{ 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 };
|
|
1208
825
|
}
|
|
1209
826
|
|
|
1210
|
-
pub fn damage(self: Null, player: Player, roll: u8) Error!void {
|
|
1211
|
-
_ = .{ self, player, roll };
|
|
827
|
+
pub fn damage(self: Null, player: Player, i: u3, roll: u8) Error!void {
|
|
828
|
+
_ = .{ self, player, i, roll };
|
|
1212
829
|
}
|
|
1213
830
|
|
|
1214
831
|
pub fn confused(self: Null, player: Player, ok: bool) Error!void {
|
|
@@ -1279,37 +896,7 @@ const Null = struct {
|
|
|
1279
896
|
_ = .{ self, player, move, n };
|
|
1280
897
|
}
|
|
1281
898
|
|
|
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 {
|
|
899
|
+
pub fn duration(self: Null, player: Player, turns: u3) void {
|
|
1313
900
|
_ = .{ self, player, turns };
|
|
1314
901
|
}
|
|
1315
902
|
};
|