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