@pkmn/engine 0.1.0-dev.d716e940 → 0.1.0-dev.da4a0515
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -3
- package/README.md +90 -56
- package/build/pkg/addon.js +9 -9
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/ids.json +12 -12
- package/build/pkg/data/layout.json +26 -4
- package/build/pkg/data/protocol.json +69 -12
- package/build/pkg/data.d.ts +4 -4
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +15 -18
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +2 -1
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.js +61 -42
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js +2 -2
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js +5 -4
- package/build/tools/debug.js.map +1 -1
- package/build.zig +154 -116
- package/package.json +53 -24
- package/src/bin/install-pkmn-engine +35 -22
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/data.zig +19 -31
- package/src/lib/common/debug.zig +20 -11
- package/src/lib/common/js.zig +118 -0
- package/src/lib/common/optional.zig +67 -0
- package/src/lib/common/options.zig +9 -0
- package/src/lib/common/protocol.zig +906 -367
- package/src/lib/common/rational.zig +357 -0
- package/src/lib/common/rng.zig +35 -26
- package/src/lib/common/util.zig +12 -0
- package/src/lib/gen1/calc.zig +426 -0
- package/src/lib/gen1/chance.zig +1061 -0
- package/src/lib/gen1/data/moves.zig +202 -190
- package/src/lib/gen1/data/species.zig +5 -5
- package/src/lib/gen1/data/types.zig +10 -10
- package/src/lib/gen1/data.zig +99 -87
- package/src/lib/gen1/helpers.zig +599 -23
- package/src/lib/gen1/mechanics.zig +978 -710
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1315 -0
- package/src/lib/gen2/data/items.zig +14 -20
- package/src/lib/gen2/data/moves.zig +664 -570
- package/src/lib/gen2/data/species.zig +2 -2
- package/src/lib/gen2/data/types.zig +137 -34
- package/src/lib/gen2/data.zig +130 -92
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +16 -22
- package/src/lib/gen2/mechanics.zig +3591 -12
- package/src/lib/node.zig +131 -0
- package/src/lib/pkmn.zig +84 -2
- package/src/lib/wasm.zig +13 -0
- package/src/lib/binding/node.zig +0 -229
- package/src/lib/binding/wasm.zig +0 -10
- package/src/lib/gen1/README.md +0 -812
- package/src/lib/gen2/README.md +0 -309
|
@@ -0,0 +1,1315 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
|
|
3
|
+
const assert = std.debug.assert;
|
|
4
|
+
const print = std.debug.print;
|
|
5
|
+
|
|
6
|
+
const expect = std.testing.expect;
|
|
7
|
+
const expectEqual = std.testing.expectEqual;
|
|
8
|
+
|
|
9
|
+
const options = @import("../common/options.zig");
|
|
10
|
+
const rational = @import("../common/rational.zig");
|
|
11
|
+
const rng = @import("../common/rng.zig");
|
|
12
|
+
const util = @import("../common/util.zig");
|
|
13
|
+
|
|
14
|
+
const Player = @import("../common/data.zig").Player;
|
|
15
|
+
const Optional = @import("../common/optional.zig").Optional;
|
|
16
|
+
|
|
17
|
+
const data = @import("data.zig");
|
|
18
|
+
|
|
19
|
+
const enabled = options.chance;
|
|
20
|
+
const showdown = options.showdown;
|
|
21
|
+
|
|
22
|
+
const Gen12 = rng.Gen12;
|
|
23
|
+
|
|
24
|
+
const Move = data.Move;
|
|
25
|
+
const Type = data.Type;
|
|
26
|
+
const Effectiveness = data.Effectiveness;
|
|
27
|
+
const TriAttack = data.TriAttack;
|
|
28
|
+
|
|
29
|
+
/// Actions taken by a hypothetical "chance player" that convey information about which RNG events
|
|
30
|
+
/// were observed during a Generation II battle `update`. This can additionally be provided as input
|
|
31
|
+
/// to the `update` call to override the normal behavior of the RNG in order to force specific
|
|
32
|
+
/// outcomes.
|
|
33
|
+
pub const Actions = extern struct {
|
|
34
|
+
/// Information about the RNG activity for Player 1.
|
|
35
|
+
p1: Action = .{},
|
|
36
|
+
/// Information about the RNG activity for Player 2.
|
|
37
|
+
p2: Action = .{},
|
|
38
|
+
|
|
39
|
+
/// Returns the `Action` for the given `player`.
|
|
40
|
+
pub fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Action) {
|
|
41
|
+
assert(@typeInfo(@TypeOf(self)).Pointer.child == Actions);
|
|
42
|
+
return if (player == .P1) &self.p1 else &self.p2;
|
|
43
|
+
}
|
|
44
|
+
|
|
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
|
+
/// Returns true if `a` is equal to `b`.
|
|
52
|
+
pub fn eql(a: Actions, b: Actions) bool {
|
|
53
|
+
return @as(u128, @bitCast(a.p1)) == @as(u128, @bitCast(b.p1)) and
|
|
54
|
+
@as(u128, @bitCast(a.p2)) == @as(u128, @bitCast(b.p2));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Returns true if `a` has the same "shape" as `b`, where `Actions` are defined to have the
|
|
58
|
+
/// same shape if they have the same fields set (though those fields need not necessarily be
|
|
59
|
+
/// set to the same value).
|
|
60
|
+
pub fn matches(a: Actions, b: Actions) bool {
|
|
61
|
+
inline for (@typeInfo(Actions).Struct.fields) |player| {
|
|
62
|
+
inline for (@typeInfo(Action).Struct.fields) |field| {
|
|
63
|
+
const a_val = @field(@field(a, player.name), field.name);
|
|
64
|
+
const b_val = @field(@field(b, player.name), field.name);
|
|
65
|
+
|
|
66
|
+
switch (@typeInfo(@TypeOf(a_val))) {
|
|
67
|
+
.Struct => inline for (@typeInfo(@TypeOf(a_val)).Struct.fields) |f| {
|
|
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))
|
|
77
|
+
return false,
|
|
78
|
+
.Int => if ((a_val > 0) != (b_val > 0)) return false,
|
|
79
|
+
else => unreachable,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
pub fn fmt(self: Actions, writer: anytype, shape: bool) !void {
|
|
87
|
+
try writer.writeAll("<P1 = ");
|
|
88
|
+
try self.p1.fmt(writer, shape);
|
|
89
|
+
try writer.writeAll(", P2 = ");
|
|
90
|
+
try self.p2.fmt(writer, shape);
|
|
91
|
+
try writer.writeAll(">");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
pub fn format(a: Actions, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
|
|
95
|
+
_ = .{ f, o };
|
|
96
|
+
try fmt(a, w, false);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// TODO: ziglang/zig#19730
|
|
101
|
+
test Actions {
|
|
102
|
+
const a: Actions = .{ .p1 = .{ .hit = .true, .critical_hit = .false, .damage = 245 } };
|
|
103
|
+
const b: Actions = .{ .p1 = .{ .hit = .false, .critical_hit = .true, .damage = 246 } };
|
|
104
|
+
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
|
+
|
|
112
|
+
try expect(a.eql(a));
|
|
113
|
+
try expect(!a.eql(b));
|
|
114
|
+
try expect(!b.eql(a));
|
|
115
|
+
try expect(!a.eql(c));
|
|
116
|
+
try expect(!c.eql(a));
|
|
117
|
+
|
|
118
|
+
try expect(a.matches(a));
|
|
119
|
+
try expect(a.matches(b));
|
|
120
|
+
try expect(b.matches(a));
|
|
121
|
+
try expect(!a.matches(c));
|
|
122
|
+
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
|
+
}
|
|
128
|
+
|
|
129
|
+
/// Information about the RNG that was observed during a Generation II battle `update` for a
|
|
130
|
+
/// single player.
|
|
131
|
+
pub const Action = packed struct(u128) {
|
|
132
|
+
/// If not 0, the roll to be returned Rolls.damage.
|
|
133
|
+
damage: u8 = 0,
|
|
134
|
+
|
|
135
|
+
/// If not None, the Player to be returned by Rolls.speedTie.
|
|
136
|
+
speed_tie: Optional(Player) = .None,
|
|
137
|
+
/// If not None, the value to be returned for Rolls.quickClaw.
|
|
138
|
+
quick_claw: Optional(bool) = .None,
|
|
139
|
+
/// If not None, the value to return for Rolls.hit.
|
|
140
|
+
hit: Optional(bool) = .None,
|
|
141
|
+
/// If not None, the value to be returned by Rolls.criticalHit.
|
|
142
|
+
critical_hit: Optional(bool) = .None,
|
|
143
|
+
|
|
144
|
+
/// If not None, the value to return for Rolls.confused.
|
|
145
|
+
confused: Optional(bool) = .None,
|
|
146
|
+
/// If not None, the value to return for Rolls.attract.
|
|
147
|
+
attract: Optional(bool) = .None,
|
|
148
|
+
/// If not None, the value to return for Rolls.paralyzed.
|
|
149
|
+
paralyzed: Optional(bool) = .None,
|
|
150
|
+
/// If not None, the value to return for Rolls.defrost.
|
|
151
|
+
defrost: Optional(bool) = .None,
|
|
152
|
+
|
|
153
|
+
/// If not None, the value to be returned for Rolls.secondaryChance.
|
|
154
|
+
secondary_chance: Optional(bool) = .None,
|
|
155
|
+
/// If not None, the value to be returned for Rolls.item (Focus Band / King's Rock).
|
|
156
|
+
item: Optional(bool) = .None,
|
|
157
|
+
/// If not None, the value to be returned for Rolls.protect.
|
|
158
|
+
protect: Optional(bool) = .None,
|
|
159
|
+
/// If not None, the value to return for Rolls.triAttack.
|
|
160
|
+
tri_attack: Optional(TriAttack) = .None,
|
|
161
|
+
|
|
162
|
+
/// If not 0, (present - 1) * 40 should be returned as the base power for Rolls.present.
|
|
163
|
+
present: u3 = 0,
|
|
164
|
+
/// If not 0, magnitude + 3 should be returned as the number for Rolls.magnitude.
|
|
165
|
+
magnitude: u3 = 0,
|
|
166
|
+
/// If not 0, the value to return for Rolls.tripleKick.
|
|
167
|
+
triple_kick: u2 = 0,
|
|
168
|
+
|
|
169
|
+
/// If not 0, the amount of PP to deduct for Rolls.spite.
|
|
170
|
+
spite: u3 = 0,
|
|
171
|
+
/// If not None, the value to return for Rolls.conversion2.
|
|
172
|
+
conversion_2: Optional(Type) = .None,
|
|
173
|
+
|
|
174
|
+
/// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
|
|
175
|
+
/// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
|
|
176
|
+
move_slot: u4 = 0,
|
|
177
|
+
/// If not 0, the party slot (1-6) to return in Rolls.forceSwitch. If present as an override,
|
|
178
|
+
/// invalid values (eg. due to empty party slots or fainted members) will be ignored.
|
|
179
|
+
force_switch: u4 = 0,
|
|
180
|
+
|
|
181
|
+
/// If not 0, the value (2-5) to return for Rolls.distribution for multi hit.
|
|
182
|
+
multi_hit: u4 = 0,
|
|
183
|
+
/// If not 0, the value to by one of the Rolls.*Duration rolls.
|
|
184
|
+
duration: u4 = 0,
|
|
185
|
+
|
|
186
|
+
/// If not 0, psywave should be returned as the damage roll for Rolls.psywave.
|
|
187
|
+
psywave: u8 = 0,
|
|
188
|
+
|
|
189
|
+
/// If not None, the Move to return for Rolls.metronome.
|
|
190
|
+
metronome: Move = .None,
|
|
191
|
+
|
|
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
|
+
pub const Field = std.meta.FieldEnum(Action);
|
|
200
|
+
|
|
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
|
+
pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
|
|
207
|
+
_ = .{ f, o };
|
|
208
|
+
try fmt(a, w, false);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
|
|
212
|
+
try writer.writeByte('(');
|
|
213
|
+
var printed = false;
|
|
214
|
+
inline for (@typeInfo(Action).Struct.fields) |field| {
|
|
215
|
+
const val = @field(self, field.name);
|
|
216
|
+
switch (@typeInfo(@TypeOf(val))) {
|
|
217
|
+
.Struct => inline for (@typeInfo(@TypeOf(val)).Struct.fields) |f| {
|
|
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) {
|
|
230
|
+
if (printed) try writer.writeAll(", ");
|
|
231
|
+
if (shape) {
|
|
232
|
+
try writer.print("{s}:?", .{field.name});
|
|
233
|
+
} else if (@TypeOf(val) == Optional(bool)) {
|
|
234
|
+
try writer.print("{s}{s}", .{
|
|
235
|
+
if (val == .false) "!" else "",
|
|
236
|
+
field.name,
|
|
237
|
+
});
|
|
238
|
+
} else {
|
|
239
|
+
try writer.print("{s}:{s}", .{ field.name, @tagName(val) });
|
|
240
|
+
}
|
|
241
|
+
printed = true;
|
|
242
|
+
},
|
|
243
|
+
.Int => if (val != 0) {
|
|
244
|
+
if (printed) try writer.writeAll(", ");
|
|
245
|
+
if (shape) {
|
|
246
|
+
try writer.print("{s}:?", .{field.name});
|
|
247
|
+
} else {
|
|
248
|
+
try writer.print("{s}:{d}", .{ field.name, val });
|
|
249
|
+
}
|
|
250
|
+
printed = true;
|
|
251
|
+
},
|
|
252
|
+
else => unreachable,
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
try writer.writeByte(')');
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
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
|
+
/// Tracks chance actions and their associated probability during a Generation II battle update when
|
|
290
|
+
/// `options.chance` is enabled.
|
|
291
|
+
pub fn Chance(comptime Rational: type) type {
|
|
292
|
+
return struct {
|
|
293
|
+
const Self = @This();
|
|
294
|
+
|
|
295
|
+
/// The probability of the actions taken by a hypothetical "chance player" occurring.
|
|
296
|
+
probability: Rational,
|
|
297
|
+
/// The actions taken by a hypothetical "chance player" that convey information about which
|
|
298
|
+
/// RNG events were observed during a battle `update`.
|
|
299
|
+
actions: Actions = .{},
|
|
300
|
+
|
|
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
|
+
/// Possible error returned by operations tracking chance probability.
|
|
310
|
+
pub const Error = Rational.Error;
|
|
311
|
+
|
|
312
|
+
/// Convenience helper to clear fields which typically should be cleared between updates.
|
|
313
|
+
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
|
+
if (!enabled) return;
|
|
321
|
+
|
|
322
|
+
assert(in >= 1 and in <= 6);
|
|
323
|
+
assert(out >= 1 and out <= 6);
|
|
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]);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
pub fn speedTie(self: *Self, p1: bool) Error!void {
|
|
335
|
+
if (!enabled) return;
|
|
336
|
+
|
|
337
|
+
try self.probability.update(1, 2);
|
|
338
|
+
self.actions.p1.speed_tie = if (p1) .P1 else .P2;
|
|
339
|
+
self.actions.p2.speed_tie = self.actions.p1.speed_tie;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
pub fn quickClaw(self: *Self, player: Player, proc: bool) Error!void {
|
|
343
|
+
if (!enabled) return;
|
|
344
|
+
|
|
345
|
+
try self.probability.update(@as(u8, if (proc) 60 else 196), 256);
|
|
346
|
+
self.actions.get(player).quick_claw = if (proc) .true else .false;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
pub fn hit(self: *Self, player: Player, ok: bool, accuracy: u8) Error!void {
|
|
350
|
+
if (!enabled) return;
|
|
351
|
+
|
|
352
|
+
const p = if (ok) accuracy else @as(u8, @intCast(256 - @as(u9, accuracy)));
|
|
353
|
+
try self.probability.update(p, 256);
|
|
354
|
+
self.actions.get(player).hit = if (ok) .true else .false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
pub fn criticalHit(self: *Self, player: Player, crit: bool, rate: u8) Error!void {
|
|
358
|
+
if (!enabled) return;
|
|
359
|
+
|
|
360
|
+
const n = if (crit) rate else @as(u8, @intCast(256 - @as(u9, rate)));
|
|
361
|
+
try self.probability.update(n, 256);
|
|
362
|
+
self.actions.get(player).critical_hit = if (crit) .true else .false;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
pub fn damage(self: *Self, player: Player, roll: u8) Error!void {
|
|
366
|
+
if (!enabled) return;
|
|
367
|
+
|
|
368
|
+
try self.probability.update(1, 39);
|
|
369
|
+
self.actions.get(player).damage = roll;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
pub fn confused(self: *Self, player: Player, cfz: bool) Error!void {
|
|
373
|
+
if (!enabled) return;
|
|
374
|
+
|
|
375
|
+
try self.probability.update(1, 2);
|
|
376
|
+
self.actions.get(player).confused = if (cfz) .true else .false;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
pub fn attract(self: *Self, player: Player, cant: bool) Error!void {
|
|
380
|
+
if (!enabled) return;
|
|
381
|
+
|
|
382
|
+
try self.probability.update(1, 2);
|
|
383
|
+
self.actions.get(player).attract = if (cant) .true else .false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
pub fn paralyzed(self: *Self, player: Player, par: bool) Error!void {
|
|
387
|
+
if (!enabled) return;
|
|
388
|
+
|
|
389
|
+
try self.probability.update(@as(u8, if (par) 1 else 3), 4);
|
|
390
|
+
self.actions.get(player).paralyzed = if (par) .true else .false;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
pub fn defrost(self: *Self, player: Player, thaw: bool) Error!void {
|
|
394
|
+
if (!enabled) return;
|
|
395
|
+
|
|
396
|
+
try self.probability.update(@as(u8, if (thaw) 25 else 231), 256);
|
|
397
|
+
self.actions.get(player).defrost = if (thaw) .true else .false;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
pub fn secondaryChance(self: *Self, player: Player, proc: bool, rate: u8) Error!void {
|
|
401
|
+
if (!enabled) return;
|
|
402
|
+
|
|
403
|
+
const n = if (proc) rate else @as(u8, @intCast(256 - @as(u9, rate)));
|
|
404
|
+
try self.probability.update(n, 256);
|
|
405
|
+
self.actions.get(player).secondary_chance = if (proc) .true else .false;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
pub fn item(self: *Self, player: Player, proc: bool) Error!void {
|
|
409
|
+
if (!enabled) return;
|
|
410
|
+
|
|
411
|
+
try self.probability.update(@as(u8, if (proc) 30 else 226), 256);
|
|
412
|
+
self.actions.get(player).item = if (proc) .true else .false;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
pub fn protect(self: *Self, player: Player, num: u8, ok: bool) Error!void {
|
|
416
|
+
if (!enabled) return;
|
|
417
|
+
|
|
418
|
+
try self.probability.update(@as(u8, if (ok) num + 1 else 255 - num - 1), 255);
|
|
419
|
+
self.actions.get(player).protect = if (ok) .true else .false;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
pub fn triAttack(self: *Self, player: Player, status: TriAttack) Error!void {
|
|
423
|
+
if (!enabled) return;
|
|
424
|
+
|
|
425
|
+
try self.probability.update(1, 3);
|
|
426
|
+
self.actions.get(player).tri_attack = @enumFromInt(@intFromEnum(status) + 1);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const PRESENT: [4]u8 = if (showdown) .{ 2, 4, 3, 1 } else .{ 51, 103, 77, 25 };
|
|
430
|
+
|
|
431
|
+
pub fn present(self: *Self, player: Player, power: u8) Error!void {
|
|
432
|
+
if (!enabled) return;
|
|
433
|
+
|
|
434
|
+
const index = power / 40;
|
|
435
|
+
try self.probability.update(PRESENT[index], if (showdown) 10 else 256);
|
|
436
|
+
self.actions.get(player).present = @intCast(index + 1);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const MAGNITUDE: [7]u8 = if (showdown)
|
|
440
|
+
.{ 5, 10, 20, 30, 20, 10, 5 }
|
|
441
|
+
else
|
|
442
|
+
.{ 14, 26, 50, 77, 51, 25, 13 };
|
|
443
|
+
|
|
444
|
+
pub fn magnitude(self: *Self, player: Player, num: u8) Error!void {
|
|
445
|
+
if (!enabled) return;
|
|
446
|
+
|
|
447
|
+
const index = num - 4;
|
|
448
|
+
try self.probability.update(MAGNITUDE[index], if (showdown) 100 else 256);
|
|
449
|
+
self.actions.get(player).magnitude = @intCast(index + 1);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
pub fn tripleKick(self: *Self, player: Player, hits: u2) Error!void {
|
|
453
|
+
if (!enabled) return;
|
|
454
|
+
|
|
455
|
+
try self.probability.update(1, 3);
|
|
456
|
+
self.actions.get(player).triple_kick = hits;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
pub fn spite(self: *Self, player: Player, pp: u3) Error!void {
|
|
460
|
+
if (!enabled) return;
|
|
461
|
+
|
|
462
|
+
try self.probability.update(1, 4);
|
|
463
|
+
self.actions.get(player).spite = pp;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
pub fn conversion2(self: *Self, player: Player, ty: Type, mtype: Type, num: u8) Error!void {
|
|
467
|
+
if (!enabled) return;
|
|
468
|
+
|
|
469
|
+
assert(showdown or num == 0);
|
|
470
|
+
const n = if (num != 0)
|
|
471
|
+
num
|
|
472
|
+
else n: {
|
|
473
|
+
const neutral = @intFromEnum(Effectiveness.Neutral);
|
|
474
|
+
var i: u8 = 0;
|
|
475
|
+
for (0..Type.size) |t| {
|
|
476
|
+
if (@intFromEnum(mtype.effectiveness(@enumFromInt(t))) < neutral) i += 1;
|
|
477
|
+
}
|
|
478
|
+
assert(i > 0 and i <= 7);
|
|
479
|
+
break :n i;
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
try self.probability.update(1, n);
|
|
483
|
+
self.actions.get(player).conversion_2 = @enumFromInt(@intFromEnum(ty) + 1);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
pub fn moveSlot(self: *Self, player: Player, slot: u4, n: u4) Error!void {
|
|
487
|
+
if (!enabled) return;
|
|
488
|
+
|
|
489
|
+
if (n != 1) try self.probability.update(1, n);
|
|
490
|
+
self.actions.get(player).move_slot = @intCast(slot);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
pub fn forceSwitch(self: *Self, player: Player, slot: u4, n: u4) Error!void {
|
|
494
|
+
if (!enabled) return;
|
|
495
|
+
|
|
496
|
+
if (n != 1) try self.probability.update(1, n);
|
|
497
|
+
self.actions.get(player).force_switch = @intCast(slot);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
pub fn psywave(self: *Self, player: Player, power: u8, max: u8) Error!void {
|
|
501
|
+
if (!enabled) return;
|
|
502
|
+
|
|
503
|
+
try self.probability.update(1, max);
|
|
504
|
+
self.actions.get(player).psywave = power;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
pub fn metronome(self: *Self, player: Player, move: Move, n: u2) Error!void {
|
|
508
|
+
if (!enabled) return;
|
|
509
|
+
|
|
510
|
+
try self.probability.update(1, Move.METRONOME.len - @as(u8, n));
|
|
511
|
+
self.actions.get(player).metronome = move;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
pub fn multiHit(self: *Self, player: Player, n: u3) Error!void {
|
|
515
|
+
if (!enabled) return;
|
|
516
|
+
|
|
517
|
+
try self.probability.update(@as(u8, if (n > 3) 1 else 3), 8);
|
|
518
|
+
self.actions.get(player).multi_hit = n;
|
|
519
|
+
}
|
|
520
|
+
|
|
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 {
|
|
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
|
+
}
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
test "Chance.speedTie" {
|
|
642
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
643
|
+
|
|
644
|
+
try chance.speedTie(true);
|
|
645
|
+
try expectProbability(&chance.probability, 1, 2);
|
|
646
|
+
try expectValue(Optional(Player).P1, chance.actions.p1.speed_tie);
|
|
647
|
+
try expectValue(chance.actions.p1.speed_tie, chance.actions.p2.speed_tie);
|
|
648
|
+
|
|
649
|
+
chance.reset();
|
|
650
|
+
|
|
651
|
+
try chance.speedTie(false);
|
|
652
|
+
try expectProbability(&chance.probability, 1, 2);
|
|
653
|
+
try expectValue(Optional(Player).P2, chance.actions.p1.speed_tie);
|
|
654
|
+
try expectValue(chance.actions.p1.speed_tie, chance.actions.p2.speed_tie);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
test "Chance.quickClaw" {
|
|
658
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
659
|
+
|
|
660
|
+
try chance.quickClaw(.P1, false);
|
|
661
|
+
try expectProbability(&chance.probability, 49, 64);
|
|
662
|
+
try expectValue(Optional(bool).false, chance.actions.p1.quick_claw);
|
|
663
|
+
|
|
664
|
+
chance.reset();
|
|
665
|
+
|
|
666
|
+
try chance.quickClaw(.P2, true);
|
|
667
|
+
try expectProbability(&chance.probability, 15, 64);
|
|
668
|
+
try expectValue(Optional(bool).true, chance.actions.p2.quick_claw);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
test "Chance.hit" {
|
|
672
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
673
|
+
|
|
674
|
+
try chance.hit(.P1, true, 229);
|
|
675
|
+
try expectValue(Optional(bool).true, chance.actions.p1.hit);
|
|
676
|
+
try expectProbability(&chance.probability, 229, 256);
|
|
677
|
+
|
|
678
|
+
chance.reset();
|
|
679
|
+
|
|
680
|
+
try chance.hit(.P2, false, 229);
|
|
681
|
+
try expectValue(Optional(bool).false, chance.actions.p2.hit);
|
|
682
|
+
try expectProbability(&chance.probability, 27, 256);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
test "Chance.criticalHit" {
|
|
686
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
687
|
+
|
|
688
|
+
try chance.criticalHit(.P1, true, 17);
|
|
689
|
+
try expectValue(Optional(bool).true, chance.actions.p1.critical_hit);
|
|
690
|
+
try expectProbability(&chance.probability, 17, 256);
|
|
691
|
+
|
|
692
|
+
chance.reset();
|
|
693
|
+
|
|
694
|
+
try chance.criticalHit(.P2, false, 5);
|
|
695
|
+
try expectProbability(&chance.probability, 251, 256);
|
|
696
|
+
try expectValue(Optional(bool).false, chance.actions.p2.critical_hit);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
test "Chance.damage" {
|
|
700
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
701
|
+
|
|
702
|
+
try chance.damage(.P1, 217);
|
|
703
|
+
try expectValue(217, chance.actions.p1.damage);
|
|
704
|
+
try expectProbability(&chance.probability, 1, 39);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
test "Chance.confused" {
|
|
708
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
709
|
+
|
|
710
|
+
try chance.confused(.P1, false);
|
|
711
|
+
try expectProbability(&chance.probability, 1, 2);
|
|
712
|
+
try expectValue(Optional(bool).false, chance.actions.p1.confused);
|
|
713
|
+
|
|
714
|
+
chance.reset();
|
|
715
|
+
|
|
716
|
+
try chance.confused(.P2, true);
|
|
717
|
+
try expectProbability(&chance.probability, 1, 2);
|
|
718
|
+
try expectValue(Optional(bool).true, chance.actions.p2.confused);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
test "Chance.attract" {
|
|
722
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
723
|
+
|
|
724
|
+
try chance.attract(.P1, false);
|
|
725
|
+
try expectProbability(&chance.probability, 1, 2);
|
|
726
|
+
try expectValue(Optional(bool).false, chance.actions.p1.attract);
|
|
727
|
+
|
|
728
|
+
chance.reset();
|
|
729
|
+
|
|
730
|
+
try chance.attract(.P2, true);
|
|
731
|
+
try expectProbability(&chance.probability, 1, 2);
|
|
732
|
+
try expectValue(Optional(bool).true, chance.actions.p2.attract);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
test "Chance.paralyzed" {
|
|
736
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
737
|
+
|
|
738
|
+
try chance.paralyzed(.P1, false);
|
|
739
|
+
try expectProbability(&chance.probability, 3, 4);
|
|
740
|
+
try expectValue(Optional(bool).false, chance.actions.p1.paralyzed);
|
|
741
|
+
|
|
742
|
+
chance.reset();
|
|
743
|
+
|
|
744
|
+
try chance.paralyzed(.P2, true);
|
|
745
|
+
try expectProbability(&chance.probability, 1, 4);
|
|
746
|
+
try expectValue(Optional(bool).true, chance.actions.p2.paralyzed);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
test "Chance.defrost" {
|
|
750
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
751
|
+
|
|
752
|
+
try chance.defrost(.P1, false);
|
|
753
|
+
try expectProbability(&chance.probability, 231, 256);
|
|
754
|
+
try expectValue(Optional(bool).false, chance.actions.p1.defrost);
|
|
755
|
+
|
|
756
|
+
chance.reset();
|
|
757
|
+
|
|
758
|
+
try chance.defrost(.P2, true);
|
|
759
|
+
try expectProbability(&chance.probability, 25, 256);
|
|
760
|
+
try expectValue(Optional(bool).true, chance.actions.p2.defrost);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
test "Chance.secondaryChance" {
|
|
764
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
765
|
+
|
|
766
|
+
try chance.secondaryChance(.P1, true, 25);
|
|
767
|
+
try expectProbability(&chance.probability, 25, 256);
|
|
768
|
+
try expectValue(Optional(bool).true, chance.actions.p1.secondary_chance);
|
|
769
|
+
|
|
770
|
+
chance.reset();
|
|
771
|
+
|
|
772
|
+
try chance.secondaryChance(.P2, false, 77);
|
|
773
|
+
try expectProbability(&chance.probability, 179, 256);
|
|
774
|
+
try expectValue(Optional(bool).false, chance.actions.p2.secondary_chance);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
test "Chance.item" {
|
|
778
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
779
|
+
|
|
780
|
+
try chance.item(.P1, false);
|
|
781
|
+
try expectProbability(&chance.probability, 113, 128);
|
|
782
|
+
try expectValue(Optional(bool).false, chance.actions.p1.item);
|
|
783
|
+
|
|
784
|
+
chance.reset();
|
|
785
|
+
|
|
786
|
+
try chance.item(.P2, true);
|
|
787
|
+
try expectProbability(&chance.probability, 15, 128);
|
|
788
|
+
try expectValue(Optional(bool).true, chance.actions.p2.item);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
test "Chance.protect" {
|
|
792
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
793
|
+
|
|
794
|
+
try chance.protect(.P1, 15, false);
|
|
795
|
+
try expectProbability(&chance.probability, 239, 255);
|
|
796
|
+
try expectValue(Optional(bool).false, chance.actions.p1.protect);
|
|
797
|
+
|
|
798
|
+
chance.reset();
|
|
799
|
+
|
|
800
|
+
try chance.protect(.P2, 63, true);
|
|
801
|
+
try expectProbability(&chance.probability, 64, 255);
|
|
802
|
+
try expectValue(Optional(bool).true, chance.actions.p2.protect);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
test "Chance.triAttack" {
|
|
806
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
807
|
+
|
|
808
|
+
try chance.triAttack(.P1, .BRN);
|
|
809
|
+
try expectProbability(&chance.probability, 1, 3);
|
|
810
|
+
try expectValue(Optional(TriAttack).BRN, chance.actions.p1.tri_attack);
|
|
811
|
+
|
|
812
|
+
chance.reset();
|
|
813
|
+
|
|
814
|
+
try chance.triAttack(.P2, .FRZ);
|
|
815
|
+
try expectProbability(&chance.probability, 1, 3);
|
|
816
|
+
try expectValue(Optional(TriAttack).FRZ, chance.actions.p2.tri_attack);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
test "Chance.present" {
|
|
820
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
821
|
+
|
|
822
|
+
try chance.present(.P2, 120);
|
|
823
|
+
if (showdown) {
|
|
824
|
+
try expectProbability(&chance.probability, 1, 10);
|
|
825
|
+
} else {
|
|
826
|
+
try expectProbability(&chance.probability, 25, 256);
|
|
827
|
+
}
|
|
828
|
+
try expectValue(4, chance.actions.p2.present);
|
|
829
|
+
|
|
830
|
+
chance.reset();
|
|
831
|
+
|
|
832
|
+
try chance.present(.P1, 0);
|
|
833
|
+
if (showdown) {
|
|
834
|
+
try expectProbability(&chance.probability, 1, 5);
|
|
835
|
+
} else {
|
|
836
|
+
try expectProbability(&chance.probability, 51, 256);
|
|
837
|
+
}
|
|
838
|
+
try expectValue(1, chance.actions.p1.present);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
test "Chance.magnitude" {
|
|
842
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
843
|
+
|
|
844
|
+
try chance.magnitude(.P2, 10);
|
|
845
|
+
if (showdown) {
|
|
846
|
+
try expectProbability(&chance.probability, 1, 20);
|
|
847
|
+
} else {
|
|
848
|
+
try expectProbability(&chance.probability, 13, 256);
|
|
849
|
+
}
|
|
850
|
+
try expectValue(7, chance.actions.p2.magnitude);
|
|
851
|
+
|
|
852
|
+
chance.reset();
|
|
853
|
+
|
|
854
|
+
try chance.magnitude(.P1, 8);
|
|
855
|
+
if (showdown) {
|
|
856
|
+
try expectProbability(&chance.probability, 1, 5);
|
|
857
|
+
} else {
|
|
858
|
+
try expectProbability(&chance.probability, 51, 256);
|
|
859
|
+
}
|
|
860
|
+
try expectValue(5, chance.actions.p1.magnitude);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
test "Chance.tripleKick" {
|
|
864
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
865
|
+
|
|
866
|
+
try chance.tripleKick(.P1, 2);
|
|
867
|
+
try expectProbability(&chance.probability, 1, 3);
|
|
868
|
+
try expectValue(2, chance.actions.p1.triple_kick);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
test "Chance.spite" {
|
|
872
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
873
|
+
|
|
874
|
+
try chance.spite(.P1, 3);
|
|
875
|
+
try expectProbability(&chance.probability, 1, 4);
|
|
876
|
+
try expectValue(3, chance.actions.p1.spite);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
test "Chance.conversion2" {
|
|
880
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
881
|
+
|
|
882
|
+
if (showdown) {
|
|
883
|
+
try chance.conversion2(.P1, .Normal, .Ghost, 3);
|
|
884
|
+
try expectProbability(&chance.probability, 1, 3);
|
|
885
|
+
try expectValue(Optional(Type).Normal, chance.actions.p1.conversion_2);
|
|
886
|
+
} else {
|
|
887
|
+
try chance.conversion2(.P2, .Normal, .Ghost, 0);
|
|
888
|
+
try expectProbability(&chance.probability, 1, 3);
|
|
889
|
+
try expectValue(Optional(Type).Normal, chance.actions.p2.conversion_2);
|
|
890
|
+
}
|
|
891
|
+
chance.reset();
|
|
892
|
+
|
|
893
|
+
try chance.conversion2(.P2, .Fire, .Bug, 0);
|
|
894
|
+
try expectProbability(&chance.probability, 1, 6);
|
|
895
|
+
try expectValue(Optional(Type).Fire, chance.actions.p2.conversion_2);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
test "Chance.psywave" {
|
|
899
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
900
|
+
|
|
901
|
+
try chance.psywave(.P2, 100, 150);
|
|
902
|
+
try expectProbability(&chance.probability, 1, 150);
|
|
903
|
+
try expectValue(100, chance.actions.p2.psywave);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
test "Chance.metronome" {
|
|
907
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
908
|
+
|
|
909
|
+
try chance.metronome(.P1, Move.HornAttack, 1);
|
|
910
|
+
try expectProbability(&chance.probability, 1, 238);
|
|
911
|
+
try expectValue(Move.HornAttack, chance.actions.p1.metronome);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
test "Chance.moveSlot" {
|
|
915
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
916
|
+
|
|
917
|
+
try chance.moveSlot(.P2, 2, 2);
|
|
918
|
+
try expectProbability(&chance.probability, 1, 2);
|
|
919
|
+
try expectValue(2, chance.actions.p2.move_slot);
|
|
920
|
+
|
|
921
|
+
chance.reset();
|
|
922
|
+
|
|
923
|
+
try chance.moveSlot(.P1, 1, 3);
|
|
924
|
+
try expectProbability(&chance.probability, 1, 3);
|
|
925
|
+
try expectValue(1, chance.actions.p1.move_slot);
|
|
926
|
+
|
|
927
|
+
chance.reset();
|
|
928
|
+
|
|
929
|
+
try chance.moveSlot(.P1, 4, 1);
|
|
930
|
+
try expectProbability(&chance.probability, 1, 1);
|
|
931
|
+
try expectValue(4, chance.actions.p1.move_slot);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
test "Chance.forceSwitch" {
|
|
935
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
936
|
+
|
|
937
|
+
try chance.forceSwitch(.P2, 2, 2);
|
|
938
|
+
try expectProbability(&chance.probability, 1, 2);
|
|
939
|
+
try expectValue(2, chance.actions.p2.force_switch);
|
|
940
|
+
|
|
941
|
+
chance.reset();
|
|
942
|
+
|
|
943
|
+
try chance.forceSwitch(.P1, 1, 3);
|
|
944
|
+
try expectProbability(&chance.probability, 1, 3);
|
|
945
|
+
try expectValue(1, chance.actions.p1.force_switch);
|
|
946
|
+
|
|
947
|
+
chance.reset();
|
|
948
|
+
|
|
949
|
+
try chance.forceSwitch(.P1, 4, 1);
|
|
950
|
+
try expectProbability(&chance.probability, 1, 1);
|
|
951
|
+
try expectValue(4, chance.actions.p1.force_switch);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
test "Chance.multiHit" {
|
|
955
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
956
|
+
|
|
957
|
+
try chance.multiHit(.P1, 3);
|
|
958
|
+
try expectProbability(&chance.probability, 3, 8);
|
|
959
|
+
try expectValue(3, chance.actions.p1.multi_hit);
|
|
960
|
+
|
|
961
|
+
chance.reset();
|
|
962
|
+
|
|
963
|
+
try chance.multiHit(.P2, 5);
|
|
964
|
+
try expectProbability(&chance.probability, 1, 8);
|
|
965
|
+
try expectValue(5, chance.actions.p2.multi_hit);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
test "Chance.duration" {
|
|
969
|
+
var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
|
|
970
|
+
|
|
971
|
+
chance.duration(.sleep, .P1, .P2, 2);
|
|
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
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
|
|
1168
|
+
if (!enabled) return;
|
|
1169
|
+
|
|
1170
|
+
r.reduce();
|
|
1171
|
+
if (r.p != p or r.q != q) {
|
|
1172
|
+
print("expected {d}/{d}, found {}\n", .{ p, q, r });
|
|
1173
|
+
return error.TestExpectedEqual;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
pub fn expectValue(a: anytype, b: anytype) !void {
|
|
1178
|
+
if (!enabled) return;
|
|
1179
|
+
|
|
1180
|
+
try expectEqual(a, b);
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
/// Null object pattern implementation of Generation II `Chance` which does nothing, though chance
|
|
1184
|
+
/// tracking should additionally be turned off entirely via `options.chance`.
|
|
1185
|
+
pub const NULL: Null = .{};
|
|
1186
|
+
|
|
1187
|
+
const Null = struct {
|
|
1188
|
+
pub const Error = error{};
|
|
1189
|
+
|
|
1190
|
+
pub fn switched(self: Null, player: Player, in: u8, out: u8) void {
|
|
1191
|
+
_ = .{ self, player, in, out };
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
pub fn speedTie(self: Null, p1: bool) Error!void {
|
|
1195
|
+
_ = .{ self, p1 };
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
pub fn quickClaw(self: Null, player: Player, proc: bool) Error!void {
|
|
1199
|
+
_ = .{ self, player, proc };
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
pub fn hit(self: Null, player: Player, ok: bool, accuracy: u8) Error!void {
|
|
1203
|
+
_ = .{ self, player, ok, accuracy };
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
pub fn criticalHit(self: Null, player: Player, crit: bool, rate: u8) Error!void {
|
|
1207
|
+
_ = .{ self, player, crit, rate };
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
pub fn damage(self: Null, player: Player, roll: u8) Error!void {
|
|
1211
|
+
_ = .{ self, player, roll };
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
pub fn confused(self: Null, player: Player, ok: bool) Error!void {
|
|
1215
|
+
_ = .{ self, player, ok };
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
pub fn attract(self: Null, player: Player, cant: bool) Error!void {
|
|
1219
|
+
_ = .{ self, player, cant };
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
pub fn paralyzed(self: Null, player: Player, par: bool) Error!void {
|
|
1223
|
+
_ = .{ self, player, par };
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
pub fn defrost(self: Null, player: Player, thaw: bool) Error!void {
|
|
1227
|
+
_ = .{ self, player, thaw };
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
pub fn secondaryChance(self: Null, player: Player, proc: bool, rate: u8) Error!void {
|
|
1231
|
+
_ = .{ self, player, proc, rate };
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
pub fn item(self: Null, player: Player, proc: bool) Error!void {
|
|
1235
|
+
_ = .{ self, player, proc };
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
pub fn protect(self: Null, player: Player, num: u8, ok: bool) Error!void {
|
|
1239
|
+
_ = .{ self, player, num, ok };
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
pub fn triAttack(self: Null, player: Player, status: TriAttack) Error!void {
|
|
1243
|
+
_ = .{ self, player, status };
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
pub fn present(self: Null, player: Player, power: u8) Error!void {
|
|
1247
|
+
_ = .{ self, player, power };
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
pub fn magnitude(self: Null, player: Player, num: u8) Error!void {
|
|
1251
|
+
_ = .{ self, player, num };
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
pub fn spite(self: Null, player: Player, pp: u3) Error!void {
|
|
1255
|
+
_ = .{ self, player, pp };
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
pub fn conversion2(self: Null, player: Player, ty: Type, mtype: Type, num: u8) Error!void {
|
|
1259
|
+
_ = .{ self, player, ty, mtype, num };
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
pub fn moveSlot(self: Null, player: Player, slot: u4, n: u4) Error!void {
|
|
1263
|
+
_ = .{ self, player, slot, n };
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
pub fn forceSwitch(self: Null, player: Player, slot: u4, n: u4) Error!void {
|
|
1267
|
+
_ = .{ self, player, slot, n };
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
pub fn multiHit(self: Null, player: Player, n: u3) Error!void {
|
|
1271
|
+
_ = .{ self, player, n };
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
pub fn psywave(self: Null, player: Player, power: u8, max: u8) Error!void {
|
|
1275
|
+
_ = .{ self, player, power, max };
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
pub fn metronome(self: Null, player: Player, move: Move, n: u2) Error!void {
|
|
1279
|
+
_ = .{ self, player, move, n };
|
|
1280
|
+
}
|
|
1281
|
+
|
|
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 {
|
|
1313
|
+
_ = .{ self, player, turns };
|
|
1314
|
+
}
|
|
1315
|
+
};
|