@pkmn/engine 0.1.0-dev.62399ed5 → 0.1.0-dev.6be9a775
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/index.d.ts +1 -1
- package/build/pkg/index.js.map +1 -1
- package/build/test/display.js +6 -1
- package/build/test/display.js.map +1 -1
- package/build.zig +199 -66
- package/package.json +4 -1
- package/src/bin/install-pkmn-engine +7 -5
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/js.zig +4 -2
- package/src/lib/common/optional.zig +13 -9
- package/src/lib/common/protocol.zig +41 -36
- package/src/lib/common/rational.zig +46 -46
- package/src/lib/common/rng.zig +4 -4
- package/src/lib/common/util.zig +50 -1
- package/src/lib/gen1/calc.zig +329 -119
- package/src/lib/gen1/chance.zig +332 -224
- package/src/lib/gen1/data.zig +28 -27
- package/src/lib/gen1/helpers.zig +13 -534
- package/src/lib/gen1/mechanics.zig +178 -109
- package/src/lib/gen2/calc.zig +34 -16
- package/src/lib/gen2/chance.zig +91 -501
- package/src/lib/gen2/data.zig +15 -14
- package/src/lib/gen2/helpers.zig +4 -2
- package/src/lib/gen2/mechanics.zig +47 -71
- package/src/lib/pkmn.zig +7 -5
package/src/lib/gen2/chance.zig
CHANGED
|
@@ -11,6 +11,7 @@ const rational = @import("../common/rational.zig");
|
|
|
11
11
|
const rng = @import("../common/rng.zig");
|
|
12
12
|
const util = @import("../common/util.zig");
|
|
13
13
|
|
|
14
|
+
const Array = @import("../common/array.zig").Array;
|
|
14
15
|
const Player = @import("../common/data.zig").Player;
|
|
15
16
|
const Optional = @import("../common/optional.zig").Optional;
|
|
16
17
|
|
|
@@ -21,11 +22,18 @@ const showdown = options.showdown;
|
|
|
21
22
|
|
|
22
23
|
const Gen12 = rng.Gen12;
|
|
23
24
|
|
|
25
|
+
const PointerType = util.PointerType;
|
|
26
|
+
const isPointerTo = util.isPointerTo;
|
|
27
|
+
|
|
24
28
|
const Move = data.Move;
|
|
25
29
|
const Type = data.Type;
|
|
26
30
|
const Effectiveness = data.Effectiveness;
|
|
27
31
|
const TriAttack = data.TriAttack;
|
|
28
32
|
|
|
33
|
+
const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
|
|
34
|
+
const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
|
|
35
|
+
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
36
|
+
|
|
29
37
|
/// Actions taken by a hypothetical "chance player" that convey information about which RNG events
|
|
30
38
|
/// were observed during a Generation II battle `update`. This can additionally be provided as input
|
|
31
39
|
/// to the `update` call to override the normal behavior of the RNG in order to force specific
|
|
@@ -37,17 +45,11 @@ pub const Actions = extern struct {
|
|
|
37
45
|
p2: Action = .{},
|
|
38
46
|
|
|
39
47
|
/// Returns the `Action` for the given `player`.
|
|
40
|
-
pub fn get(self: anytype, player: Player)
|
|
41
|
-
assert(
|
|
48
|
+
pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Action) {
|
|
49
|
+
assert(isPointerTo(self, Actions));
|
|
42
50
|
return if (player == .P1) &self.p1 else &self.p2;
|
|
43
51
|
}
|
|
44
52
|
|
|
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
53
|
/// Returns true if `a` is equal to `b`.
|
|
52
54
|
pub fn eql(a: Actions, b: Actions) bool {
|
|
53
55
|
return @as(u128, @bitCast(a.p1)) == @as(u128, @bitCast(b.p1)) and
|
|
@@ -58,24 +60,15 @@ pub const Actions = extern struct {
|
|
|
58
60
|
/// same shape if they have the same fields set (though those fields need not necessarily be
|
|
59
61
|
/// set to the same value).
|
|
60
62
|
pub fn matches(a: Actions, b: Actions) bool {
|
|
61
|
-
inline for (@typeInfo(Actions)
|
|
62
|
-
inline for (@typeInfo(Action)
|
|
63
|
+
inline for (@field(@typeInfo(Actions), @tagName(Struct)).fields) |player| {
|
|
64
|
+
inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
|
|
63
65
|
const a_val = @field(@field(a, player.name), field.name);
|
|
64
66
|
const b_val = @field(@field(b, player.name), field.name);
|
|
65
67
|
|
|
66
68
|
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))
|
|
69
|
+
Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
|
|
77
70
|
return false,
|
|
78
|
-
|
|
71
|
+
Int => if ((a_val > 0) != (b_val > 0)) return false,
|
|
79
72
|
else => unreachable,
|
|
80
73
|
}
|
|
81
74
|
}
|
|
@@ -97,17 +90,10 @@ pub const Actions = extern struct {
|
|
|
97
90
|
}
|
|
98
91
|
};
|
|
99
92
|
|
|
100
|
-
// TODO: ziglang/zig#19730
|
|
101
93
|
test Actions {
|
|
102
|
-
const a: Actions = .{ .p1 = .{ .hit = .true, .
|
|
103
|
-
const b: Actions = .{ .p1 = .{ .hit = .false, .
|
|
94
|
+
const a: Actions = .{ .p1 = .{ .hit = .true, .confused = .false, .damages = 245 } };
|
|
95
|
+
const b: Actions = .{ .p1 = .{ .hit = .false, .confused = .true, .damages = 246 } };
|
|
104
96
|
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
97
|
|
|
112
98
|
try expect(a.eql(a));
|
|
113
99
|
try expect(!a.eql(b));
|
|
@@ -120,17 +106,21 @@ test Actions {
|
|
|
120
106
|
try expect(b.matches(a));
|
|
121
107
|
try expect(!a.matches(c));
|
|
122
108
|
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
109
|
}
|
|
128
110
|
|
|
111
|
+
/// Observation made about a duration - whether the duration has started, been continued, or ended.
|
|
112
|
+
pub const Observation = enum { started, continuing, ended };
|
|
113
|
+
|
|
114
|
+
pub const Damages = Array(5, u8);
|
|
115
|
+
pub const Criticals = Array(5, Optional(bool));
|
|
116
|
+
|
|
129
117
|
/// Information about the RNG that was observed during a Generation II battle `update` for a
|
|
130
118
|
/// single player.
|
|
131
119
|
pub const Action = packed struct(u128) {
|
|
132
|
-
///
|
|
133
|
-
|
|
120
|
+
/// TODO
|
|
121
|
+
damages: Damages.T = 0,
|
|
122
|
+
// TODO
|
|
123
|
+
critical_hits: Criticals.T = 0,
|
|
134
124
|
|
|
135
125
|
/// If not None, the Player to be returned by Rolls.speedTie.
|
|
136
126
|
speed_tie: Optional(Player) = .None,
|
|
@@ -138,50 +128,58 @@ pub const Action = packed struct(u128) {
|
|
|
138
128
|
quick_claw: Optional(bool) = .None,
|
|
139
129
|
/// If not None, the value to return for Rolls.hit.
|
|
140
130
|
hit: Optional(bool) = .None,
|
|
141
|
-
/// If not None, the value to be returned by Rolls.criticalHit.
|
|
142
|
-
critical_hit: Optional(bool) = .None,
|
|
143
|
-
|
|
144
131
|
/// If not None, the value to return for Rolls.confused.
|
|
145
132
|
confused: Optional(bool) = .None,
|
|
133
|
+
|
|
146
134
|
/// If not None, the value to return for Rolls.attract.
|
|
147
135
|
attract: Optional(bool) = .None,
|
|
148
136
|
/// If not None, the value to return for Rolls.paralyzed.
|
|
149
137
|
paralyzed: Optional(bool) = .None,
|
|
150
138
|
/// If not None, the value to return for Rolls.defrost.
|
|
151
139
|
defrost: Optional(bool) = .None,
|
|
152
|
-
|
|
153
140
|
/// If not None, the value to be returned for Rolls.secondaryChance.
|
|
154
141
|
secondary_chance: Optional(bool) = .None,
|
|
142
|
+
|
|
155
143
|
/// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
|
|
156
144
|
item: Optional(bool) = .None,
|
|
157
145
|
/// If not None, the value to be returned for Rolls.protect.
|
|
158
146
|
protect: Optional(bool) = .None,
|
|
159
147
|
/// If not None, the value to return for Rolls.triAttack.
|
|
160
148
|
tri_attack: Optional(TriAttack) = .None,
|
|
149
|
+
/// If not 0, the value to return for Rolls.tripleKick.
|
|
150
|
+
triple_kick: u2 = 0,
|
|
161
151
|
|
|
162
152
|
/// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
|
|
163
153
|
present: u3 = 0,
|
|
164
154
|
/// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
|
|
165
155
|
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.
|
|
156
|
+
/// If not 0, the amount of PP to deduct for Rolls.spite.
|
|
170
157
|
spite: u3 = 0,
|
|
171
|
-
/// If not None, the value to return for Rolls.conversion2.
|
|
172
|
-
conversion_2: Optional(Type) = .None,
|
|
173
|
-
|
|
174
158
|
/// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
|
|
175
159
|
/// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
|
|
176
|
-
move_slot:
|
|
160
|
+
move_slot: u3 = 0,
|
|
177
161
|
/// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
|
|
178
162
|
/// invalid values (eg. due to empty party slots or fainted members) will be ignored.
|
|
179
|
-
force_switch:
|
|
180
|
-
|
|
163
|
+
force_switch: u3 = 0,
|
|
181
164
|
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
182
|
-
multi_hit:
|
|
165
|
+
multi_hit: u3 = 0,
|
|
166
|
+
|
|
167
|
+
sleep: Optional(Observation) = .None,
|
|
168
|
+
/// TODO
|
|
169
|
+
confusion: Optional(Observation) = .None,
|
|
170
|
+
/// TODO
|
|
171
|
+
disable: Optional(Observation) = .None,
|
|
172
|
+
/// TODO
|
|
173
|
+
attacking: Optional(Observation) = .None,
|
|
174
|
+
/// TODO
|
|
175
|
+
binding: Optional(Observation) = .None,
|
|
176
|
+
/// TODO
|
|
177
|
+
encore: Optional(Observation) = .None,
|
|
178
|
+
|
|
183
179
|
/// If not 0, the value to by one of the Rolls.*Duration rolls.
|
|
184
|
-
duration:
|
|
180
|
+
duration: u3 = 0,
|
|
181
|
+
/// If not None, the value to return for Rolls.conversion2.
|
|
182
|
+
conversion_2: Optional(Type) = .None,
|
|
185
183
|
|
|
186
184
|
/// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
|
|
187
185
|
psywave: u8 = 0,
|
|
@@ -189,20 +187,8 @@ pub const Action = packed struct(u128) {
|
|
|
189
187
|
/// If not None, the Move to return for Rolls.metronome.
|
|
190
188
|
metronome: Move = .None,
|
|
191
189
|
|
|
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
190
|
pub const Field = std.meta.FieldEnum(Action);
|
|
200
191
|
|
|
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
192
|
pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
|
|
207
193
|
_ = .{ f, o };
|
|
208
194
|
try fmt(a, w, false);
|
|
@@ -211,22 +197,10 @@ pub const Action = packed struct(u128) {
|
|
|
211
197
|
pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
|
|
212
198
|
try writer.writeByte('(');
|
|
213
199
|
var printed = false;
|
|
214
|
-
inline for (@typeInfo(Action)
|
|
200
|
+
inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
|
|
215
201
|
const val = @field(self, field.name);
|
|
216
202
|
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) {
|
|
203
|
+
Enum => if (val != .None) {
|
|
230
204
|
if (printed) try writer.writeAll(", ");
|
|
231
205
|
if (shape) {
|
|
232
206
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -240,7 +214,7 @@ pub const Action = packed struct(u128) {
|
|
|
240
214
|
}
|
|
241
215
|
printed = true;
|
|
242
216
|
},
|
|
243
|
-
|
|
217
|
+
Int => if (val != 0) {
|
|
244
218
|
if (printed) try writer.writeAll(", ");
|
|
245
219
|
if (shape) {
|
|
246
220
|
try writer.print("{s}:?", .{field.name});
|
|
@@ -256,36 +230,6 @@ pub const Action = packed struct(u128) {
|
|
|
256
230
|
}
|
|
257
231
|
};
|
|
258
232
|
|
|
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
233
|
/// Tracks chance actions and their associated probability during a Generation II battle update when
|
|
290
234
|
/// `options.chance` is enabled.
|
|
291
235
|
pub fn Chance(comptime Rational: type) type {
|
|
@@ -298,37 +242,15 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
298
242
|
/// RNG events were observed during a battle `update`.
|
|
299
243
|
actions: Actions = .{},
|
|
300
244
|
|
|
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
245
|
/// Possible error returned by operations tracking chance probability.
|
|
310
246
|
pub const Error = Rational.Error;
|
|
311
247
|
|
|
312
248
|
/// Convenience helper to clear fields which typically should be cleared between updates.
|
|
313
249
|
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
250
|
if (!enabled) return;
|
|
321
251
|
|
|
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]);
|
|
252
|
+
self.probability.reset();
|
|
253
|
+
self.actions = .{};
|
|
332
254
|
}
|
|
333
255
|
|
|
334
256
|
pub fn speedTie(self: *Self, p1: bool) Error!void {
|
|
@@ -354,19 +276,21 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
354
276
|
self.actions.get(player).hit = if (ok) .true else .false;
|
|
355
277
|
}
|
|
356
278
|
|
|
357
|
-
pub fn criticalHit(self: *Self, player: Player, crit: bool, rate: u8) Error!void {
|
|
279
|
+
pub fn criticalHit(self: *Self, player: Player, i: u3, crit: bool, rate: u8) Error!void {
|
|
358
280
|
if (!enabled) return;
|
|
359
281
|
|
|
360
282
|
const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
|
|
361
283
|
try self.probability.update(n, 256);
|
|
362
|
-
self.actions.get(player)
|
|
284
|
+
var a = self.actions.get(player);
|
|
285
|
+
a.critical_hits = Criticals.set(a.critical_hits, i, if (crit) .true else .false);
|
|
363
286
|
}
|
|
364
287
|
|
|
365
|
-
pub fn damage(self: *Self, player: Player, roll: u8) Error!void {
|
|
288
|
+
pub fn damage(self: *Self, player: Player, i: u3, roll: u8) Error!void {
|
|
366
289
|
if (!enabled) return;
|
|
367
290
|
|
|
368
291
|
try self.probability.update(1, 39);
|
|
369
|
-
self.actions.get(player)
|
|
292
|
+
var a = self.actions.get(player);
|
|
293
|
+
a.damages = Damages.set(a.damages, i, roll);
|
|
370
294
|
}
|
|
371
295
|
|
|
372
296
|
pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
|
|
@@ -518,122 +442,10 @@ pub fn Chance(comptime Rational: type) type {
|
|
|
518
442
|
self.actions.get(player).multi_hit = n;
|
|
519
443
|
}
|
|
520
444
|
|
|
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 {
|
|
445
|
+
pub fn duration(self: *Self, player: Player, turns: u3) void {
|
|
539
446
|
if (!enabled) return;
|
|
540
447
|
|
|
541
|
-
|
|
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 {
|
|
591
|
-
if (!enabled) return;
|
|
592
|
-
|
|
593
|
-
var durations = &self.actions.get(player).durations;
|
|
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
|
-
}
|
|
448
|
+
self.actions.get(player).duration = if (options.key) 2 else turns;
|
|
637
449
|
}
|
|
638
450
|
};
|
|
639
451
|
}
|
|
@@ -685,22 +497,22 @@ test "Chance.hit" {
|
|
|
685
497
|
test "Chance.criticalHit" {
|
|
686
498
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
687
499
|
|
|
688
|
-
try chance.criticalHit(.P1, true, 17);
|
|
689
|
-
try expectValue(Optional(bool).true, chance.actions.p1.
|
|
500
|
+
try chance.criticalHit(.P1, 0, true, 17);
|
|
501
|
+
try expectValue(Optional(bool).true, Criticals.get(chance.actions.p1.critical_hits, 0));
|
|
690
502
|
try expectProbability(&chance.probability, 17, 256);
|
|
691
503
|
|
|
692
504
|
chance.reset();
|
|
693
505
|
|
|
694
|
-
try chance.criticalHit(.P2, false, 5);
|
|
506
|
+
try chance.criticalHit(.P2, 1, false, 5);
|
|
695
507
|
try expectProbability(&chance.probability, 251, 256);
|
|
696
|
-
try expectValue(Optional(bool).false, chance.actions.p2.
|
|
508
|
+
try expectValue(Optional(bool).false, Criticals.get(chance.actions.p2.critical_hits, 1));
|
|
697
509
|
}
|
|
698
510
|
|
|
699
511
|
test "Chance.damage" {
|
|
700
512
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
701
513
|
|
|
702
|
-
try chance.damage(.P1,
|
|
703
|
-
try expectValue(
|
|
514
|
+
try chance.damage(.P1, 0, 219);
|
|
515
|
+
try expectValue(@as(u8, 219), Damages.get(chance.actions.p1.damages, 0));
|
|
704
516
|
try expectProbability(&chance.probability, 1, 39);
|
|
705
517
|
}
|
|
706
518
|
|
|
@@ -825,7 +637,7 @@ test "Chance.present" {
|
|
|
825
637
|
} else {
|
|
826
638
|
try expectProbability(&chance.probability, 25, 256);
|
|
827
639
|
}
|
|
828
|
-
try expectValue(4, chance.actions.p2.present);
|
|
640
|
+
try expectValue(@as(u3, 4), chance.actions.p2.present);
|
|
829
641
|
|
|
830
642
|
chance.reset();
|
|
831
643
|
|
|
@@ -835,7 +647,7 @@ test "Chance.present" {
|
|
|
835
647
|
} else {
|
|
836
648
|
try expectProbability(&chance.probability, 51, 256);
|
|
837
649
|
}
|
|
838
|
-
try expectValue(1, chance.actions.p1.present);
|
|
650
|
+
try expectValue(@as(u3, 1), chance.actions.p1.present);
|
|
839
651
|
}
|
|
840
652
|
|
|
841
653
|
test "Chance.magnitude" {
|
|
@@ -847,7 +659,7 @@ test "Chance.magnitude" {
|
|
|
847
659
|
} else {
|
|
848
660
|
try expectProbability(&chance.probability, 13, 256);
|
|
849
661
|
}
|
|
850
|
-
try expectValue(7, chance.actions.p2.magnitude);
|
|
662
|
+
try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
|
|
851
663
|
|
|
852
664
|
chance.reset();
|
|
853
665
|
|
|
@@ -857,7 +669,7 @@ test "Chance.magnitude" {
|
|
|
857
669
|
} else {
|
|
858
670
|
try expectProbability(&chance.probability, 51, 256);
|
|
859
671
|
}
|
|
860
|
-
try expectValue(5, chance.actions.p1.magnitude);
|
|
672
|
+
try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
|
|
861
673
|
}
|
|
862
674
|
|
|
863
675
|
test "Chance.tripleKick" {
|
|
@@ -865,7 +677,7 @@ test "Chance.tripleKick" {
|
|
|
865
677
|
|
|
866
678
|
try chance.tripleKick(.P1, 2);
|
|
867
679
|
try expectProbability(&chance.probability, 1, 3);
|
|
868
|
-
try expectValue(2, chance.actions.p1.triple_kick);
|
|
680
|
+
try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
|
|
869
681
|
}
|
|
870
682
|
|
|
871
683
|
test "Chance.spite" {
|
|
@@ -873,7 +685,7 @@ test "Chance.spite" {
|
|
|
873
685
|
|
|
874
686
|
try chance.spite(.P1, 3);
|
|
875
687
|
try expectProbability(&chance.probability, 1, 4);
|
|
876
|
-
try expectValue(3, chance.actions.p1.spite);
|
|
688
|
+
try expectValue(@as(u3, 3), chance.actions.p1.spite);
|
|
877
689
|
}
|
|
878
690
|
|
|
879
691
|
test "Chance.conversion2" {
|
|
@@ -900,7 +712,7 @@ test "Chance.psywave" {
|
|
|
900
712
|
|
|
901
713
|
try chance.psywave(.P2, 100, 150);
|
|
902
714
|
try expectProbability(&chance.probability, 1, 150);
|
|
903
|
-
try expectValue(100, chance.actions.p2.psywave);
|
|
715
|
+
try expectValue(@as(u8, 100), chance.actions.p2.psywave);
|
|
904
716
|
}
|
|
905
717
|
|
|
906
718
|
test "Chance.metronome" {
|
|
@@ -916,19 +728,19 @@ test "Chance.moveSlot" {
|
|
|
916
728
|
|
|
917
729
|
try chance.moveSlot(.P2, 2, 2);
|
|
918
730
|
try expectProbability(&chance.probability, 1, 2);
|
|
919
|
-
try expectValue(2, chance.actions.p2.move_slot);
|
|
731
|
+
try expectValue(@as(u3, 2), chance.actions.p2.move_slot);
|
|
920
732
|
|
|
921
733
|
chance.reset();
|
|
922
734
|
|
|
923
735
|
try chance.moveSlot(.P1, 1, 3);
|
|
924
736
|
try expectProbability(&chance.probability, 1, 3);
|
|
925
|
-
try expectValue(1, chance.actions.p1.move_slot);
|
|
737
|
+
try expectValue(@as(u3, 1), chance.actions.p1.move_slot);
|
|
926
738
|
|
|
927
739
|
chance.reset();
|
|
928
740
|
|
|
929
741
|
try chance.moveSlot(.P1, 4, 1);
|
|
930
742
|
try expectProbability(&chance.probability, 1, 1);
|
|
931
|
-
try expectValue(4, chance.actions.p1.move_slot);
|
|
743
|
+
try expectValue(@as(u3, 4), chance.actions.p1.move_slot);
|
|
932
744
|
}
|
|
933
745
|
|
|
934
746
|
test "Chance.forceSwitch" {
|
|
@@ -936,19 +748,19 @@ test "Chance.forceSwitch" {
|
|
|
936
748
|
|
|
937
749
|
try chance.forceSwitch(.P2, 2, 2);
|
|
938
750
|
try expectProbability(&chance.probability, 1, 2);
|
|
939
|
-
try expectValue(2, chance.actions.p2.force_switch);
|
|
751
|
+
try expectValue(@as(u3, 2), chance.actions.p2.force_switch);
|
|
940
752
|
|
|
941
753
|
chance.reset();
|
|
942
754
|
|
|
943
755
|
try chance.forceSwitch(.P1, 1, 3);
|
|
944
756
|
try expectProbability(&chance.probability, 1, 3);
|
|
945
|
-
try expectValue(1, chance.actions.p1.force_switch);
|
|
757
|
+
try expectValue(@as(u3, 1), chance.actions.p1.force_switch);
|
|
946
758
|
|
|
947
759
|
chance.reset();
|
|
948
760
|
|
|
949
761
|
try chance.forceSwitch(.P1, 4, 1);
|
|
950
762
|
try expectProbability(&chance.probability, 1, 1);
|
|
951
|
-
try expectValue(4, chance.actions.p1.force_switch);
|
|
763
|
+
try expectValue(@as(u3, 4), chance.actions.p1.force_switch);
|
|
952
764
|
}
|
|
953
765
|
|
|
954
766
|
test "Chance.multiHit" {
|
|
@@ -956,212 +768,20 @@ test "Chance.multiHit" {
|
|
|
956
768
|
|
|
957
769
|
try chance.multiHit(.P1, 3);
|
|
958
770
|
try expectProbability(&chance.probability, 3, 8);
|
|
959
|
-
try expectValue(3, chance.actions.p1.multi_hit);
|
|
771
|
+
try expectValue(@as(u3, 3), chance.actions.p1.multi_hit);
|
|
960
772
|
|
|
961
773
|
chance.reset();
|
|
962
774
|
|
|
963
775
|
try chance.multiHit(.P2, 5);
|
|
964
776
|
try expectProbability(&chance.probability, 1, 8);
|
|
965
|
-
try expectValue(5, chance.actions.p2.multi_hit);
|
|
777
|
+
try expectValue(@as(u3, 5), chance.actions.p2.multi_hit);
|
|
966
778
|
}
|
|
967
779
|
|
|
968
780
|
test "Chance.duration" {
|
|
969
781
|
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
970
782
|
|
|
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
|
-
}
|
|
783
|
+
chance.duration(.P1, 2);
|
|
784
|
+
try expectValue(@as(u3, 2), chance.actions.p1.duration);
|
|
1165
785
|
}
|
|
1166
786
|
|
|
1167
787
|
pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
@@ -1203,12 +823,12 @@ const Null = struct {
|
|
|
1203
823
|
_ = .{ self, player, ok, accuracy };
|
|
1204
824
|
}
|
|
1205
825
|
|
|
1206
|
-
pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
|
|
1207
|
-
_ = .{ self, player, crit, rate };
|
|
826
|
+
pub fn criticalHit(self: Null, player: Player, i: u3, crit: bool, rate: u8) Error!void {
|
|
827
|
+
_ = .{ self, player, i, crit, rate };
|
|
1208
828
|
}
|
|
1209
829
|
|
|
1210
|
-
pub fn damage(self: Null, player: Player, roll: u8) Error!void {
|
|
1211
|
-
_ = .{ self, player, roll };
|
|
830
|
+
pub fn damage(self: Null, player: Player, i: u3, roll: u8) Error!void {
|
|
831
|
+
_ = .{ self, player, i, roll };
|
|
1212
832
|
}
|
|
1213
833
|
|
|
1214
834
|
pub fn confused(self: Null, player: Player, ok: bool) Error!void {
|
|
@@ -1279,37 +899,7 @@ const Null = struct {
|
|
|
1279
899
|
_ = .{ self, player, move, n };
|
|
1280
900
|
}
|
|
1281
901
|
|
|
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 {
|
|
902
|
+
pub fn duration(self: Null, player: Player, turns: u3) void {
|
|
1313
903
|
_ = .{ self, player, turns };
|
|
1314
904
|
}
|
|
1315
905
|
};
|