@pkmn/engine 0.1.0-dev.6195e056 → 0.1.0-dev.6e63f5e4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -62
- package/build/pkg/addon.d.ts +7 -0
- package/build/pkg/addon.js +112 -0
- package/build/pkg/addon.js.map +1 -0
- package/build/pkg/data/layout.json +25 -3
- package/build/pkg/data/protocol.json +22 -4
- package/build/pkg/data.d.ts +1 -2
- package/build/pkg/data.js +3 -5
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +5 -4
- package/build/pkg/gen1.js +47 -31
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +16 -13
- package/build/pkg/index.js +1 -1
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +4 -2
- package/build/pkg/protocol.js +5 -3
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js +400 -0
- package/build/test/display.js.map +1 -0
- package/build/tools/debug.js +133 -0
- package/build/tools/debug.js.map +1 -0
- package/build.zig +104 -90
- package/package.json +57 -36
- package/src/bin/install-pkmn-engine +68 -36
- package/src/bin/pkmn-debug +62 -0
- package/src/lib/binding/node.zig +47 -142
- package/src/lib/binding/wasm.zig +6 -4
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/data.zig +15 -27
- package/src/lib/common/debug.zig +74 -0
- package/src/lib/common/js.zig +118 -0
- package/src/lib/common/optional.zig +60 -0
- package/src/lib/common/options.zig +12 -3
- package/src/lib/common/protocol.zig +416 -198
- package/src/lib/common/rational.zig +353 -0
- package/src/lib/common/rng.zig +15 -15
- package/src/lib/common/util.zig +12 -0
- package/src/lib/gen1/README.md +282 -165
- package/src/lib/gen1/calc.zig +426 -0
- package/src/lib/gen1/chance.zig +1058 -0
- package/src/lib/gen1/data/moves.zig +178 -180
- package/src/lib/gen1/data/species.zig +2 -2
- package/src/lib/gen1/data/types.zig +4 -4
- package/src/lib/gen1/data.zig +79 -65
- package/src/lib/gen1/helpers.zig +592 -36
- package/src/lib/gen1/mechanics.zig +1097 -662
- package/src/lib/gen2/README.md +87 -13
- package/src/lib/gen2/data/items.zig +3 -3
- package/src/lib/gen2/data/moves.zig +635 -563
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +4 -4
- package/src/lib/gen2/data.zig +109 -77
- package/src/lib/gen2/helpers.zig +16 -22
- package/src/lib/gen2/mechanics.zig +1160 -11
- package/src/lib/pkmn.zig +68 -9
- package/src/test/display/pkmn.html.tmpl +368 -0
|
@@ -7,7 +7,7 @@ const options = @import("./options.zig");
|
|
|
7
7
|
const assert = std.debug.assert;
|
|
8
8
|
const print = std.debug.print;
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const enabled = options.log;
|
|
11
11
|
|
|
12
12
|
const Player = data.Player;
|
|
13
13
|
const ID = data.ID;
|
|
@@ -102,6 +102,9 @@ pub const ArgType = enum(u8) {
|
|
|
102
102
|
// Gen 8
|
|
103
103
|
CanDynamax,
|
|
104
104
|
SwapSideConditions,
|
|
105
|
+
|
|
106
|
+
// Gen 9
|
|
107
|
+
Terastallize,
|
|
105
108
|
};
|
|
106
109
|
|
|
107
110
|
pub const Move = enum(u8) {
|
|
@@ -124,6 +127,8 @@ pub const Heal = enum(u8) {
|
|
|
124
127
|
None,
|
|
125
128
|
Silent,
|
|
126
129
|
Drain,
|
|
130
|
+
|
|
131
|
+
Leftovers,
|
|
127
132
|
};
|
|
128
133
|
|
|
129
134
|
pub const Damage = enum(u8) {
|
|
@@ -133,6 +138,8 @@ pub const Damage = enum(u8) {
|
|
|
133
138
|
Confusion,
|
|
134
139
|
LeechSeed,
|
|
135
140
|
RecoilOf,
|
|
141
|
+
|
|
142
|
+
Spikes,
|
|
136
143
|
};
|
|
137
144
|
|
|
138
145
|
pub const Status = enum(u8) {
|
|
@@ -177,6 +184,8 @@ pub const Activate = enum(u8) {
|
|
|
177
184
|
Struggle,
|
|
178
185
|
Substitute,
|
|
179
186
|
Splash,
|
|
187
|
+
|
|
188
|
+
Attract,
|
|
180
189
|
};
|
|
181
190
|
|
|
182
191
|
pub const Start = enum(u8) {
|
|
@@ -202,6 +211,9 @@ pub const End = enum(u8) {
|
|
|
202
211
|
Bide,
|
|
203
212
|
Substitute,
|
|
204
213
|
|
|
214
|
+
FutureSight,
|
|
215
|
+
Encore,
|
|
216
|
+
|
|
205
217
|
// Silent
|
|
206
218
|
DisableSilent,
|
|
207
219
|
ConfusionSilent,
|
|
@@ -219,8 +231,27 @@ pub const Immune = enum(u8) {
|
|
|
219
231
|
OHKO,
|
|
220
232
|
};
|
|
221
233
|
|
|
234
|
+
pub const SideStart = enum(u8) {
|
|
235
|
+
Safeguard,
|
|
236
|
+
Reflect,
|
|
237
|
+
LightScreen,
|
|
238
|
+
Spikes,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
pub const SideEnd = enum(u8) {
|
|
242
|
+
Safeguard,
|
|
243
|
+
Reflect,
|
|
244
|
+
LightScreen,
|
|
245
|
+
|
|
246
|
+
Spikes,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
/// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
|
|
250
|
+
/// Ignores anything sent to it, though protocol logging should additionally be turned off
|
|
251
|
+
/// entirely with `options.log`.
|
|
222
252
|
pub const NULL = Log(@TypeOf(std.io.null_writer)){ .writer = std.io.null_writer };
|
|
223
253
|
|
|
254
|
+
/// Logs protocol information to its `Writer` during a battle update when `options.log` is enabled.
|
|
224
255
|
pub fn Log(comptime Writer: type) type {
|
|
225
256
|
return struct {
|
|
226
257
|
const Self = @This();
|
|
@@ -230,91 +261,108 @@ pub fn Log(comptime Writer: type) type {
|
|
|
230
261
|
pub const Error = Writer.Error;
|
|
231
262
|
|
|
232
263
|
pub fn move(self: Self, source: ID, m: anytype, target: ID, from: anytype) Error!void {
|
|
233
|
-
if (!
|
|
264
|
+
if (!enabled) return;
|
|
265
|
+
|
|
234
266
|
assert(m != .None);
|
|
235
267
|
try self.writer.writeAll(&.{
|
|
236
|
-
@
|
|
237
|
-
@
|
|
238
|
-
@
|
|
239
|
-
@
|
|
268
|
+
@intFromEnum(ArgType.Move),
|
|
269
|
+
@as(u8, @bitCast(source)),
|
|
270
|
+
@intFromEnum(m),
|
|
271
|
+
@as(u8, @bitCast(target)),
|
|
240
272
|
});
|
|
241
|
-
const none = &[_]u8{@
|
|
273
|
+
const none = &[_]u8{@intFromEnum(Move.None)};
|
|
242
274
|
try self.writer.writeAll(switch (@typeInfo(@TypeOf(from))) {
|
|
243
275
|
.Null => none,
|
|
244
276
|
.Optional => if (from) |f| blk: {
|
|
245
|
-
assert(@
|
|
246
|
-
break :blk &[_]u8{ @
|
|
277
|
+
assert(@intFromEnum(f) != 0);
|
|
278
|
+
break :blk &[_]u8{ @intFromEnum(Move.From), @intFromEnum(f) };
|
|
247
279
|
} else none,
|
|
248
280
|
else => blk: {
|
|
249
|
-
assert(@
|
|
250
|
-
break :blk &[_]u8{ @
|
|
281
|
+
assert(@intFromEnum(from) != 0);
|
|
282
|
+
break :blk &[_]u8{ @intFromEnum(Move.From), @intFromEnum(from) };
|
|
251
283
|
},
|
|
252
284
|
});
|
|
253
285
|
}
|
|
254
286
|
|
|
255
287
|
pub fn switched(self: Self, ident: ID, pokemon: anytype) Error!void {
|
|
256
|
-
if (!
|
|
257
|
-
|
|
258
|
-
try self.writer.writeAll(&.{ @
|
|
288
|
+
if (!enabled) return;
|
|
289
|
+
|
|
290
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @as(u8, @bitCast(ident)) });
|
|
291
|
+
if (@hasField(@TypeOf(pokemon.*), "dvs")) {
|
|
292
|
+
try self.writer.writeAll(&.{
|
|
293
|
+
@intFromEnum(pokemon.species),
|
|
294
|
+
@intFromEnum(pokemon.dvs.gender),
|
|
295
|
+
pokemon.level,
|
|
296
|
+
});
|
|
297
|
+
} else {
|
|
298
|
+
try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
|
|
299
|
+
}
|
|
259
300
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
260
301
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
261
302
|
try self.writer.writeAll(&.{pokemon.status});
|
|
262
303
|
}
|
|
263
304
|
|
|
264
305
|
pub fn cant(self: Self, ident: ID, reason: Cant) Error!void {
|
|
265
|
-
if (!
|
|
306
|
+
if (!enabled) return;
|
|
307
|
+
|
|
266
308
|
assert(reason != .Disable);
|
|
267
309
|
try self.writer.writeAll(&.{
|
|
268
|
-
@
|
|
269
|
-
@
|
|
270
|
-
@
|
|
310
|
+
@intFromEnum(ArgType.Cant),
|
|
311
|
+
@as(u8, @bitCast(ident)),
|
|
312
|
+
@intFromEnum(reason),
|
|
271
313
|
});
|
|
272
314
|
}
|
|
273
315
|
|
|
274
316
|
pub fn disabled(self: Self, ident: ID, m: anytype) Error!void {
|
|
275
|
-
if (!
|
|
317
|
+
if (!enabled) return;
|
|
318
|
+
|
|
276
319
|
try self.writer.writeAll(&.{
|
|
277
|
-
@
|
|
278
|
-
@
|
|
279
|
-
@
|
|
280
|
-
@
|
|
320
|
+
@intFromEnum(ArgType.Cant),
|
|
321
|
+
@as(u8, @bitCast(ident)),
|
|
322
|
+
@intFromEnum(Cant.Disable),
|
|
323
|
+
@intFromEnum(m),
|
|
281
324
|
});
|
|
282
325
|
}
|
|
283
326
|
|
|
284
327
|
pub fn faint(self: Self, ident: ID, done: bool) Error!void {
|
|
285
|
-
if (!
|
|
286
|
-
|
|
287
|
-
|
|
328
|
+
if (!enabled) return;
|
|
329
|
+
|
|
330
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @as(u8, @bitCast(ident)) });
|
|
331
|
+
if (done) try self.writer.writeByte(@intFromEnum(ArgType.None));
|
|
288
332
|
}
|
|
289
333
|
|
|
290
334
|
pub fn turn(self: Self, num: u16) Error!void {
|
|
291
|
-
if (!
|
|
292
|
-
|
|
335
|
+
if (!enabled) return;
|
|
336
|
+
|
|
337
|
+
try self.writer.writeByte(@intFromEnum(ArgType.Turn));
|
|
293
338
|
try self.writer.writeIntNative(u16, num);
|
|
294
|
-
try self.writer.writeByte(@
|
|
339
|
+
try self.writer.writeByte(@intFromEnum(ArgType.None));
|
|
295
340
|
}
|
|
296
341
|
|
|
297
342
|
pub fn win(self: Self, player: Player) Error!void {
|
|
298
|
-
if (!
|
|
343
|
+
if (!enabled) return;
|
|
344
|
+
|
|
299
345
|
try self.writer.writeAll(&.{
|
|
300
|
-
@
|
|
301
|
-
@
|
|
302
|
-
@
|
|
346
|
+
@intFromEnum(ArgType.Win),
|
|
347
|
+
@intFromEnum(player),
|
|
348
|
+
@intFromEnum(ArgType.None),
|
|
303
349
|
});
|
|
304
350
|
}
|
|
305
351
|
|
|
306
352
|
pub fn tie(self: Self) Error!void {
|
|
307
|
-
if (!
|
|
308
|
-
|
|
353
|
+
if (!enabled) return;
|
|
354
|
+
|
|
355
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Tie), @intFromEnum(ArgType.None) });
|
|
309
356
|
}
|
|
310
357
|
|
|
311
358
|
pub fn damage(self: Self, ident: ID, pokemon: anytype, reason: Damage) Error!void {
|
|
312
|
-
if (!
|
|
313
|
-
|
|
314
|
-
|
|
359
|
+
if (!enabled) return;
|
|
360
|
+
|
|
361
|
+
assert(@intFromEnum(reason) <= @intFromEnum(Damage.LeechSeed));
|
|
362
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
|
|
315
363
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
316
364
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
317
|
-
try self.writer.writeAll(&.{ pokemon.status, @
|
|
365
|
+
try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
|
|
318
366
|
}
|
|
319
367
|
|
|
320
368
|
pub fn damageOf(
|
|
@@ -324,227 +372,311 @@ pub fn Log(comptime Writer: type) type {
|
|
|
324
372
|
reason: Damage,
|
|
325
373
|
source: ID,
|
|
326
374
|
) Error!void {
|
|
327
|
-
if (!
|
|
328
|
-
|
|
329
|
-
|
|
375
|
+
if (!enabled) return;
|
|
376
|
+
|
|
377
|
+
assert(@intFromEnum(reason) == @intFromEnum(Damage.RecoilOf));
|
|
378
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
|
|
330
379
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
331
380
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
332
381
|
try self.writer.writeAll(&.{
|
|
333
382
|
pokemon.status,
|
|
334
|
-
@
|
|
335
|
-
@
|
|
383
|
+
@intFromEnum(reason),
|
|
384
|
+
@as(u8, @bitCast(source)),
|
|
336
385
|
});
|
|
337
386
|
}
|
|
338
387
|
|
|
339
388
|
pub fn heal(self: Self, ident: ID, pokemon: anytype, reason: Heal) Error!void {
|
|
340
|
-
if (!
|
|
389
|
+
if (!enabled) return;
|
|
390
|
+
|
|
341
391
|
assert(reason != .Drain);
|
|
342
|
-
try self.writer.writeAll(&.{ @
|
|
392
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(ident)) });
|
|
343
393
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
344
394
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
345
|
-
try self.writer.writeAll(&.{ pokemon.status, @
|
|
395
|
+
try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
|
|
346
396
|
}
|
|
347
397
|
|
|
348
398
|
pub fn drain(self: Self, source: ID, pokemon: anytype, target: ID) Error!void {
|
|
349
|
-
if (!
|
|
350
|
-
|
|
399
|
+
if (!enabled) return;
|
|
400
|
+
|
|
401
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(source)) });
|
|
351
402
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
352
403
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
353
404
|
try self.writer.writeAll(&.{
|
|
354
405
|
pokemon.status,
|
|
355
|
-
@
|
|
356
|
-
@
|
|
406
|
+
@intFromEnum(Heal.Drain),
|
|
407
|
+
@as(u8, @bitCast(target)),
|
|
357
408
|
});
|
|
358
409
|
}
|
|
359
410
|
|
|
360
411
|
pub fn status(self: Self, ident: ID, value: u8, reason: Status) Error!void {
|
|
361
|
-
if (!
|
|
412
|
+
if (!enabled) return;
|
|
413
|
+
|
|
362
414
|
assert(reason != .From);
|
|
363
415
|
try self.writer.writeAll(&.{
|
|
364
|
-
@
|
|
365
|
-
@
|
|
416
|
+
@intFromEnum(ArgType.Status),
|
|
417
|
+
@as(u8, @bitCast(ident)),
|
|
366
418
|
value,
|
|
367
|
-
@
|
|
419
|
+
@intFromEnum(reason),
|
|
368
420
|
});
|
|
369
421
|
}
|
|
370
422
|
|
|
371
423
|
pub fn statusFrom(self: Self, ident: ID, value: u8, m: anytype) Error!void {
|
|
372
|
-
if (!
|
|
424
|
+
if (!enabled) return;
|
|
425
|
+
|
|
373
426
|
try self.writer.writeAll(&.{
|
|
374
|
-
@
|
|
375
|
-
@
|
|
427
|
+
@intFromEnum(ArgType.Status),
|
|
428
|
+
@as(u8, @bitCast(ident)),
|
|
376
429
|
value,
|
|
377
|
-
@
|
|
378
|
-
@
|
|
430
|
+
@intFromEnum(Status.From),
|
|
431
|
+
@intFromEnum(m),
|
|
379
432
|
});
|
|
380
433
|
}
|
|
381
434
|
|
|
382
435
|
pub fn curestatus(self: Self, ident: ID, value: u8, reason: CureStatus) Error!void {
|
|
383
|
-
if (!
|
|
436
|
+
if (!enabled) return;
|
|
437
|
+
|
|
384
438
|
try self.writer.writeAll(&.{
|
|
385
|
-
@
|
|
386
|
-
@
|
|
439
|
+
@intFromEnum(ArgType.CureStatus),
|
|
440
|
+
@as(u8, @bitCast(ident)),
|
|
387
441
|
value,
|
|
388
|
-
@
|
|
442
|
+
@intFromEnum(reason),
|
|
389
443
|
});
|
|
390
444
|
}
|
|
391
445
|
|
|
392
446
|
pub fn boost(self: Self, ident: ID, reason: Boost, num: i8) Error!void {
|
|
393
|
-
if (!
|
|
447
|
+
if (!enabled) return;
|
|
448
|
+
|
|
394
449
|
assert(num != 0 and (reason != .Rage or num > 0));
|
|
395
450
|
try self.writer.writeAll(&.{
|
|
396
|
-
@
|
|
397
|
-
@
|
|
398
|
-
@
|
|
399
|
-
@
|
|
451
|
+
@intFromEnum(ArgType.Boost),
|
|
452
|
+
@as(u8, @bitCast(ident)),
|
|
453
|
+
@intFromEnum(reason),
|
|
454
|
+
@as(u8, @intCast(num + 6)),
|
|
400
455
|
});
|
|
401
456
|
}
|
|
402
457
|
|
|
403
458
|
pub fn clearallboost(self: Self) Error!void {
|
|
404
|
-
if (!
|
|
405
|
-
|
|
459
|
+
if (!enabled) return;
|
|
460
|
+
|
|
461
|
+
try self.writer.writeAll(&.{@intFromEnum(ArgType.ClearAllBoost)});
|
|
406
462
|
}
|
|
407
463
|
|
|
408
464
|
pub fn fail(self: Self, ident: ID, reason: Fail) Error!void {
|
|
409
|
-
if (!
|
|
465
|
+
if (!enabled) return;
|
|
466
|
+
|
|
410
467
|
try self.writer.writeAll(&.{
|
|
411
|
-
@
|
|
412
|
-
@
|
|
413
|
-
@
|
|
468
|
+
@intFromEnum(ArgType.Fail),
|
|
469
|
+
@as(u8, @bitCast(ident)),
|
|
470
|
+
@intFromEnum(reason),
|
|
414
471
|
});
|
|
415
472
|
}
|
|
416
473
|
|
|
417
474
|
pub fn miss(self: Self, source: ID) Error!void {
|
|
418
|
-
if (!
|
|
419
|
-
|
|
475
|
+
if (!enabled) return;
|
|
476
|
+
|
|
477
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @as(u8, @bitCast(source)) });
|
|
420
478
|
}
|
|
421
479
|
|
|
422
480
|
pub fn hitcount(self: Self, ident: ID, num: u8) Error!void {
|
|
423
|
-
if (!
|
|
424
|
-
|
|
481
|
+
if (!enabled) return;
|
|
482
|
+
|
|
483
|
+
try self.writer.writeAll(&.{
|
|
484
|
+
@intFromEnum(ArgType.HitCount),
|
|
485
|
+
@as(u8, @bitCast(ident)),
|
|
486
|
+
num,
|
|
487
|
+
});
|
|
425
488
|
}
|
|
426
489
|
|
|
427
490
|
pub fn prepare(self: Self, source: ID, m: anytype) Error!void {
|
|
428
|
-
if (!
|
|
491
|
+
if (!enabled) return;
|
|
492
|
+
|
|
429
493
|
try self.writer.writeAll(&.{
|
|
430
|
-
@
|
|
431
|
-
@
|
|
432
|
-
@
|
|
494
|
+
@intFromEnum(ArgType.Prepare),
|
|
495
|
+
@as(u8, @bitCast(source)),
|
|
496
|
+
@intFromEnum(m),
|
|
433
497
|
});
|
|
434
498
|
}
|
|
435
499
|
|
|
436
500
|
pub fn mustrecharge(self: Self, ident: ID) Error!void {
|
|
437
|
-
if (!
|
|
438
|
-
|
|
501
|
+
if (!enabled) return;
|
|
502
|
+
|
|
503
|
+
try self.writer.writeAll(&.{
|
|
504
|
+
@intFromEnum(ArgType.MustRecharge),
|
|
505
|
+
@as(u8, @bitCast(ident)),
|
|
506
|
+
});
|
|
439
507
|
}
|
|
440
508
|
|
|
441
509
|
pub fn activate(self: Self, ident: ID, reason: Activate) Error!void {
|
|
442
|
-
if (!
|
|
510
|
+
if (!enabled) return;
|
|
511
|
+
|
|
443
512
|
try self.writer.writeAll(&.{
|
|
444
|
-
@
|
|
445
|
-
@
|
|
446
|
-
@
|
|
513
|
+
@intFromEnum(ArgType.Activate),
|
|
514
|
+
@as(u8, @bitCast(ident)),
|
|
515
|
+
@intFromEnum(reason),
|
|
447
516
|
});
|
|
448
517
|
}
|
|
449
518
|
|
|
450
519
|
pub fn fieldactivate(self: Self) Error!void {
|
|
451
|
-
if (!
|
|
452
|
-
|
|
520
|
+
if (!enabled) return;
|
|
521
|
+
|
|
522
|
+
try self.writer.writeAll(&.{@intFromEnum(ArgType.FieldActivate)});
|
|
453
523
|
}
|
|
454
524
|
|
|
455
525
|
pub fn start(self: Self, ident: ID, reason: Start) Error!void {
|
|
456
|
-
if (!
|
|
457
|
-
|
|
526
|
+
if (!enabled) return;
|
|
527
|
+
|
|
528
|
+
assert(@intFromEnum(reason) < @intFromEnum(Start.TypeChange));
|
|
458
529
|
try self.writer.writeAll(&.{
|
|
459
|
-
@
|
|
460
|
-
@
|
|
461
|
-
@
|
|
530
|
+
@intFromEnum(ArgType.Start),
|
|
531
|
+
@as(u8, @bitCast(ident)),
|
|
532
|
+
@intFromEnum(reason),
|
|
462
533
|
});
|
|
463
534
|
}
|
|
464
535
|
|
|
465
536
|
pub fn typechange(self: Self, source: ID, types: anytype, target: ID) Error!void {
|
|
466
|
-
if (!
|
|
537
|
+
if (!enabled) return;
|
|
538
|
+
|
|
467
539
|
try self.writer.writeAll(&.{
|
|
468
|
-
@
|
|
469
|
-
@
|
|
470
|
-
@
|
|
471
|
-
@
|
|
472
|
-
@
|
|
540
|
+
@intFromEnum(ArgType.Start),
|
|
541
|
+
@as(u8, @bitCast(source)),
|
|
542
|
+
@intFromEnum(Start.TypeChange),
|
|
543
|
+
@as(u8, @bitCast(types)),
|
|
544
|
+
@as(u8, @bitCast(target)),
|
|
473
545
|
});
|
|
474
546
|
}
|
|
475
547
|
|
|
476
548
|
pub fn startEffect(self: Self, ident: ID, reason: Start, m: anytype) Error!void {
|
|
477
|
-
if (!
|
|
478
|
-
|
|
549
|
+
if (!enabled) return;
|
|
550
|
+
|
|
551
|
+
assert(@intFromEnum(reason) > @intFromEnum(Start.TypeChange));
|
|
479
552
|
try self.writer.writeAll(&.{
|
|
480
|
-
@
|
|
481
|
-
@
|
|
482
|
-
@
|
|
483
|
-
@
|
|
553
|
+
@intFromEnum(ArgType.Start),
|
|
554
|
+
@as(u8, @bitCast(ident)),
|
|
555
|
+
@intFromEnum(reason),
|
|
556
|
+
@intFromEnum(m),
|
|
484
557
|
});
|
|
485
558
|
}
|
|
486
559
|
|
|
487
560
|
pub fn end(self: Self, ident: ID, reason: End) Error!void {
|
|
488
|
-
if (!
|
|
561
|
+
if (!enabled) return;
|
|
562
|
+
|
|
489
563
|
try self.writer.writeAll(&.{
|
|
490
|
-
@
|
|
491
|
-
@
|
|
492
|
-
@
|
|
564
|
+
@intFromEnum(ArgType.End),
|
|
565
|
+
@as(u8, @bitCast(ident)),
|
|
566
|
+
@intFromEnum(reason),
|
|
493
567
|
});
|
|
494
568
|
}
|
|
495
569
|
|
|
496
570
|
pub fn ohko(self: Self) Error!void {
|
|
497
|
-
if (!
|
|
498
|
-
|
|
571
|
+
if (!enabled) return;
|
|
572
|
+
|
|
573
|
+
try self.writer.writeAll(&.{@intFromEnum(ArgType.OHKO)});
|
|
499
574
|
}
|
|
500
575
|
|
|
501
576
|
pub fn crit(self: Self, ident: ID) Error!void {
|
|
502
|
-
if (!
|
|
503
|
-
|
|
577
|
+
if (!enabled) return;
|
|
578
|
+
|
|
579
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @as(u8, @bitCast(ident)) });
|
|
504
580
|
}
|
|
505
581
|
|
|
506
582
|
pub fn supereffective(self: Self, ident: ID) Error!void {
|
|
507
|
-
if (!
|
|
508
|
-
|
|
583
|
+
if (!enabled) return;
|
|
584
|
+
|
|
585
|
+
try self.writer.writeAll(&.{
|
|
586
|
+
@intFromEnum(ArgType.SuperEffective),
|
|
587
|
+
@as(u8, @bitCast(ident)),
|
|
588
|
+
});
|
|
509
589
|
}
|
|
510
590
|
|
|
511
591
|
pub fn resisted(self: Self, ident: ID) Error!void {
|
|
512
|
-
if (!
|
|
513
|
-
|
|
592
|
+
if (!enabled) return;
|
|
593
|
+
|
|
594
|
+
try self.writer.writeAll(&.{
|
|
595
|
+
@intFromEnum(ArgType.Resisted),
|
|
596
|
+
@as(u8, @bitCast(ident)),
|
|
597
|
+
});
|
|
514
598
|
}
|
|
515
599
|
|
|
516
600
|
pub fn immune(self: Self, ident: ID, reason: Immune) Error!void {
|
|
517
|
-
if (!
|
|
601
|
+
if (!enabled) return;
|
|
602
|
+
|
|
518
603
|
try self.writer.writeAll(&.{
|
|
519
|
-
@
|
|
520
|
-
@
|
|
521
|
-
@
|
|
604
|
+
@intFromEnum(ArgType.Immune),
|
|
605
|
+
@as(u8, @bitCast(ident)),
|
|
606
|
+
@intFromEnum(reason),
|
|
522
607
|
});
|
|
523
608
|
}
|
|
524
609
|
|
|
525
610
|
pub fn transform(self: Self, source: ID, target: ID) Error!void {
|
|
526
|
-
if (!
|
|
611
|
+
if (!enabled) return;
|
|
612
|
+
|
|
613
|
+
try self.writer.writeAll(&.{
|
|
614
|
+
@intFromEnum(ArgType.Transform),
|
|
615
|
+
@as(u8, @bitCast(source)),
|
|
616
|
+
@as(u8, @bitCast(target)),
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
pub fn sidestart(self: Self, ident: ID, reason: SideStart) Error!void {
|
|
621
|
+
if (!enabled) return;
|
|
622
|
+
|
|
623
|
+
try self.writer.writeAll(&.{
|
|
624
|
+
@intFromEnum(ArgType.SideStart),
|
|
625
|
+
@as(u8, @bitCast(ident)),
|
|
626
|
+
@intFromEnum(reason),
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
pub fn sideend(self: Self, ident: ID, reason: SideEnd) Error!void {
|
|
631
|
+
if (!enabled) return;
|
|
632
|
+
|
|
633
|
+
assert(@intFromEnum(reason) != @intFromEnum(SideEnd.Spikes));
|
|
527
634
|
try self.writer.writeAll(&.{
|
|
528
|
-
@
|
|
529
|
-
@
|
|
530
|
-
@
|
|
635
|
+
@intFromEnum(ArgType.SideEnd),
|
|
636
|
+
@as(u8, @bitCast(ident)),
|
|
637
|
+
@intFromEnum(reason),
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
pub fn sideendFromOf(
|
|
642
|
+
self: Self,
|
|
643
|
+
ident: ID,
|
|
644
|
+
reason: SideEnd,
|
|
645
|
+
m: anytype,
|
|
646
|
+
source: ID,
|
|
647
|
+
) Error!void {
|
|
648
|
+
if (!enabled) return;
|
|
649
|
+
|
|
650
|
+
assert(@intFromEnum(reason) == @intFromEnum(SideEnd.Spikes));
|
|
651
|
+
try self.writer.writeAll(&.{
|
|
652
|
+
@intFromEnum(ArgType.SideEnd),
|
|
653
|
+
@as(u8, @bitCast(ident)),
|
|
654
|
+
@intFromEnum(reason),
|
|
655
|
+
@intFromEnum(m),
|
|
656
|
+
@as(u8, @bitCast(source)),
|
|
531
657
|
});
|
|
532
658
|
}
|
|
533
659
|
|
|
534
660
|
pub fn laststill(self: Self) Error!void {
|
|
535
|
-
if (!
|
|
536
|
-
|
|
661
|
+
if (!enabled) return;
|
|
662
|
+
|
|
663
|
+
try self.writer.writeAll(&.{@intFromEnum(ArgType.LastStill)});
|
|
537
664
|
}
|
|
538
665
|
|
|
539
666
|
pub fn lastmiss(self: Self) Error!void {
|
|
540
|
-
if (!
|
|
541
|
-
|
|
667
|
+
if (!enabled) return;
|
|
668
|
+
|
|
669
|
+
try self.writer.writeAll(&.{@intFromEnum(ArgType.LastMiss)});
|
|
542
670
|
}
|
|
543
671
|
};
|
|
544
672
|
}
|
|
545
673
|
|
|
674
|
+
/// `Log` type backed by the optimized `ByteStream.Writer`.
|
|
546
675
|
pub const FixedLog = Log(ByteStream.Writer);
|
|
547
676
|
|
|
677
|
+
/// Stripped down version of `std.io.FixedBufferStream` optimized for efficiently writing the
|
|
678
|
+
/// individual protocol bytes. Note that the `ByteStream.Writer` is **not** a `std.io.Writer` and
|
|
679
|
+
/// should not be used for general purpose writing.
|
|
548
680
|
pub const ByteStream = struct {
|
|
549
681
|
buffer: []u8,
|
|
550
682
|
pos: usize = 0,
|
|
@@ -586,14 +718,18 @@ pub const ByteStream = struct {
|
|
|
586
718
|
};
|
|
587
719
|
|
|
588
720
|
pub const Kind = enum { Move, Species, Type, Status };
|
|
589
|
-
pub const Formatter = fn (Kind, u8) []const u8;
|
|
590
721
|
|
|
591
|
-
pub fn format(
|
|
722
|
+
pub fn format(
|
|
723
|
+
comptime gen: anytype,
|
|
724
|
+
a: []const u8,
|
|
725
|
+
b: ?[]const u8,
|
|
726
|
+
color: bool,
|
|
727
|
+
) void {
|
|
592
728
|
print("\n", .{});
|
|
593
729
|
|
|
594
730
|
var i: usize = 0;
|
|
595
731
|
while (i < a.len) {
|
|
596
|
-
const arg = @
|
|
732
|
+
const arg: ArgType = @enumFromInt(a[i]);
|
|
597
733
|
const name = switch (arg) {
|
|
598
734
|
.None => if (color) "\x1b[2m-\x1b[0m" else "-",
|
|
599
735
|
.LastStill => "|[still]",
|
|
@@ -626,6 +762,8 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
626
762
|
.Resisted => "|-resisted|",
|
|
627
763
|
.Immune => "|-immune|",
|
|
628
764
|
.Transform => "|-transform|",
|
|
765
|
+
.SideStart => "|-sidestart|",
|
|
766
|
+
.SideEnd => "|-sideend|",
|
|
629
767
|
else => unreachable,
|
|
630
768
|
};
|
|
631
769
|
printc("{s}", .{name}, a, b, &i, 1, color);
|
|
@@ -639,19 +777,29 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
639
777
|
.OHKO,
|
|
640
778
|
=> {},
|
|
641
779
|
.Move => {
|
|
642
|
-
const source = ID.from(@intCast(
|
|
780
|
+
const source = ID.from(@intCast(a[i]));
|
|
643
781
|
printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
|
|
644
|
-
printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
|
|
645
|
-
const target = ID.from(@intCast(
|
|
782
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
783
|
+
const target = ID.from(@intCast(a[i]));
|
|
646
784
|
printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
|
|
647
|
-
const reason = @
|
|
785
|
+
const reason: Move = @enumFromInt(a[i]);
|
|
648
786
|
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
649
|
-
if (reason == .From)
|
|
787
|
+
if (reason == .From) {
|
|
788
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
789
|
+
}
|
|
650
790
|
},
|
|
651
791
|
.Switch => {
|
|
652
|
-
const id = ID.from(@intCast(
|
|
792
|
+
const id = ID.from(@intCast(a[i]));
|
|
653
793
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
654
|
-
printc(" {s}", .{formatter(.Species, a[i])}, a, b, &i, 1, color);
|
|
794
|
+
printc(" {s}", .{formatter(gen, .Species, a[i])}, a, b, &i, 1, color);
|
|
795
|
+
if (@hasDecl(gen, "Gender")) {
|
|
796
|
+
if (a[i] == N(gen.Gender.Unknown)) {
|
|
797
|
+
i += 1;
|
|
798
|
+
} else {
|
|
799
|
+
var gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
|
|
800
|
+
printc(", {s}", .{gender}, a, b, &i, 1, color);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
655
803
|
printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
|
|
656
804
|
switch (endian) {
|
|
657
805
|
.Big => {
|
|
@@ -667,15 +815,15 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
667
815
|
printc("/{d}", .{hp}, a, b, &i, 2, color);
|
|
668
816
|
},
|
|
669
817
|
}
|
|
670
|
-
printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
|
|
818
|
+
printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
|
|
671
819
|
},
|
|
672
820
|
.Cant => {
|
|
673
|
-
const id = ID.from(@intCast(
|
|
821
|
+
const id = ID.from(@intCast(a[i]));
|
|
674
822
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
675
|
-
const reason = @
|
|
823
|
+
const reason: Cant = @enumFromInt(a[i]);
|
|
676
824
|
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
677
825
|
if (reason == .Disable) {
|
|
678
|
-
printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
|
|
826
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
679
827
|
}
|
|
680
828
|
},
|
|
681
829
|
.Faint,
|
|
@@ -685,7 +833,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
685
833
|
.SuperEffective,
|
|
686
834
|
.Resisted,
|
|
687
835
|
=> {
|
|
688
|
-
const id = ID.from(@intCast(
|
|
836
|
+
const id = ID.from(@intCast(a[i]));
|
|
689
837
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
690
838
|
},
|
|
691
839
|
.Turn => {
|
|
@@ -695,9 +843,11 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
695
843
|
};
|
|
696
844
|
printc(" {d}", .{turn}, a, b, &i, 2, color);
|
|
697
845
|
},
|
|
698
|
-
.Win =>
|
|
846
|
+
.Win => {
|
|
847
|
+
printc(" {s}", .{@tagName(@as(Player, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
848
|
+
},
|
|
699
849
|
.Damage, .Heal => {
|
|
700
|
-
var id = ID.from(@intCast(
|
|
850
|
+
var id = ID.from(@intCast(a[i]));
|
|
701
851
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
702
852
|
switch (endian) {
|
|
703
853
|
.Big => {
|
|
@@ -713,95 +863,114 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
713
863
|
printc("/{d}", .{hp}, a, b, &i, 2, color);
|
|
714
864
|
},
|
|
715
865
|
}
|
|
716
|
-
printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
|
|
866
|
+
printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
|
|
717
867
|
if (arg == .Damage) {
|
|
718
|
-
const reason = a[i];
|
|
719
|
-
printc(" {s}", .{@tagName(
|
|
720
|
-
if (reason ==
|
|
721
|
-
id = ID.from(@intCast(
|
|
868
|
+
const reason: Damage = @enumFromInt(a[i]);
|
|
869
|
+
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
870
|
+
if (reason == .RecoilOf) {
|
|
871
|
+
id = ID.from(@intCast(a[i]));
|
|
722
872
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
723
873
|
}
|
|
724
874
|
} else {
|
|
725
|
-
const reason = @
|
|
875
|
+
const reason: Heal = @enumFromInt(a[i]);
|
|
726
876
|
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
727
877
|
if (reason == .Drain) {
|
|
728
|
-
id = ID.from(@intCast(
|
|
878
|
+
id = ID.from(@intCast(a[i]));
|
|
729
879
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
730
880
|
}
|
|
731
881
|
}
|
|
732
882
|
},
|
|
733
883
|
.Status => {
|
|
734
|
-
const id = ID.from(@intCast(
|
|
884
|
+
const id = ID.from(@intCast(a[i]));
|
|
735
885
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
736
|
-
printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
|
|
737
|
-
const reason = @
|
|
886
|
+
printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
|
|
887
|
+
const reason: Status = @enumFromInt(a[i]);
|
|
738
888
|
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
739
|
-
if (reason == .From)
|
|
889
|
+
if (reason == .From) {
|
|
890
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
891
|
+
}
|
|
740
892
|
},
|
|
741
893
|
.CureStatus => {
|
|
742
|
-
const id = ID.from(@intCast(
|
|
894
|
+
const id = ID.from(@intCast(a[i]));
|
|
743
895
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
744
|
-
printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
|
|
745
|
-
|
|
896
|
+
printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
|
|
897
|
+
const reason: CureStatus = @enumFromInt(a[i]);
|
|
898
|
+
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
746
899
|
},
|
|
747
900
|
.Boost => {
|
|
748
|
-
const id = ID.from(@intCast(
|
|
901
|
+
const id = ID.from(@intCast(a[i]));
|
|
749
902
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
750
|
-
printc(" {s}", .{@tagName(@
|
|
903
|
+
printc(" {s}", .{@tagName(@as(Boost, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
751
904
|
printc(" {d}", .{a[i]}, a, b, &i, 1, color);
|
|
752
905
|
},
|
|
753
906
|
.Fail => {
|
|
754
|
-
const id = ID.from(@intCast(
|
|
907
|
+
const id = ID.from(@intCast(a[i]));
|
|
755
908
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
756
|
-
printc(" {s}", .{@tagName(@
|
|
909
|
+
printc(" {s}", .{@tagName(@as(Fail, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
757
910
|
},
|
|
758
911
|
.HitCount => {
|
|
759
|
-
const id = ID.from(@intCast(
|
|
912
|
+
const id = ID.from(@intCast(a[i]));
|
|
760
913
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
761
914
|
printc(" {d}", .{a[i]}, a, b, &i, 1, color);
|
|
762
915
|
},
|
|
763
916
|
.Prepare => {
|
|
764
|
-
const id = ID.from(@intCast(
|
|
917
|
+
const id = ID.from(@intCast(a[i]));
|
|
765
918
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
766
|
-
printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
|
|
919
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
767
920
|
},
|
|
768
921
|
.Activate => {
|
|
769
|
-
const id = ID.from(@intCast(
|
|
922
|
+
const id = ID.from(@intCast(a[i]));
|
|
770
923
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
771
|
-
printc(" {s}", .{@tagName(@
|
|
924
|
+
printc(" {s}", .{@tagName(@as(Activate, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
772
925
|
},
|
|
773
926
|
.Start => {
|
|
774
|
-
const id = ID.from(@intCast(
|
|
927
|
+
const id = ID.from(@intCast(a[i]));
|
|
775
928
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
776
929
|
const reason = a[i];
|
|
777
|
-
printc(" {s}", .{@tagName(@
|
|
778
|
-
if (@
|
|
779
|
-
const types = @
|
|
930
|
+
printc(" {s}", .{@tagName(@as(Start, @enumFromInt(reason)))}, a, b, &i, 1, color);
|
|
931
|
+
if (@as(Start, @enumFromInt(reason)) == .TypeChange) {
|
|
932
|
+
const types = @as(gen1.Types, @bitCast(a[i]));
|
|
780
933
|
const args = .{
|
|
781
|
-
formatter(.Type, @
|
|
782
|
-
formatter(.Type, @
|
|
934
|
+
formatter(gen, .Type, @intFromEnum(types.type1)),
|
|
935
|
+
formatter(gen, .Type, @intFromEnum(types.type2)),
|
|
783
936
|
};
|
|
784
937
|
printc(" {s}/{s}", args, a, b, &i, 1, color);
|
|
785
|
-
} else if (reason >= @
|
|
786
|
-
printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
|
|
938
|
+
} else if (reason >= @intFromEnum(Start.Disable)) {
|
|
939
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
787
940
|
}
|
|
788
941
|
},
|
|
789
942
|
.End => {
|
|
790
|
-
const id = ID.from(@intCast(
|
|
943
|
+
const id = ID.from(@intCast(a[i]));
|
|
791
944
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
792
|
-
printc(" {s}", .{@tagName(@
|
|
945
|
+
printc(" {s}", .{@tagName(@as(End, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
793
946
|
},
|
|
794
947
|
.Immune => {
|
|
795
|
-
const id = ID.from(@intCast(
|
|
948
|
+
const id = ID.from(@intCast(a[i]));
|
|
796
949
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
797
|
-
printc(" {s}", .{@tagName(@
|
|
950
|
+
printc(" {s}", .{@tagName(@as(Immune, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
798
951
|
},
|
|
799
952
|
.Transform => {
|
|
800
|
-
const source = ID.from(@intCast(
|
|
953
|
+
const source = ID.from(@intCast(a[i]));
|
|
801
954
|
printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
|
|
802
|
-
const target = ID.from(@intCast(
|
|
955
|
+
const target = ID.from(@intCast(a[i]));
|
|
803
956
|
printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
|
|
804
957
|
},
|
|
958
|
+
.SideStart => {
|
|
959
|
+
const id = ID.from(@intCast(a[i]));
|
|
960
|
+
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
961
|
+
printc(" {s}", .{@tagName(@as(SideStart, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
962
|
+
},
|
|
963
|
+
.SideEnd => {
|
|
964
|
+
var id = ID.from(@intCast(a[i]));
|
|
965
|
+
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
966
|
+
const reason: SideEnd = @enumFromInt(a[i]);
|
|
967
|
+
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
968
|
+
if (reason == .Spikes) {
|
|
969
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
970
|
+
id = ID.from(@intCast(a[i]));
|
|
971
|
+
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
972
|
+
}
|
|
973
|
+
},
|
|
805
974
|
else => unreachable,
|
|
806
975
|
}
|
|
807
976
|
print("\n", .{});
|
|
@@ -833,12 +1002,13 @@ fn printc(
|
|
|
833
1002
|
}
|
|
834
1003
|
|
|
835
1004
|
pub fn expectLog(
|
|
836
|
-
comptime
|
|
1005
|
+
comptime gen: anytype,
|
|
837
1006
|
expected: []const u8,
|
|
838
1007
|
actual: []const u8,
|
|
839
1008
|
offset: usize,
|
|
840
1009
|
) !void {
|
|
841
|
-
if (!
|
|
1010
|
+
if (!enabled) return;
|
|
1011
|
+
|
|
842
1012
|
const color = color: {
|
|
843
1013
|
if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
|
|
844
1014
|
break :color true;
|
|
@@ -851,8 +1021,8 @@ pub fn expectLog(
|
|
|
851
1021
|
|
|
852
1022
|
expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
|
|
853
1023
|
error.TestExpectedEqual => {
|
|
854
|
-
format(
|
|
855
|
-
format(
|
|
1024
|
+
format(gen, expected, null, color);
|
|
1025
|
+
format(gen, actual, expected, color);
|
|
856
1026
|
return err;
|
|
857
1027
|
},
|
|
858
1028
|
else => return err,
|
|
@@ -881,7 +1051,7 @@ fn expectEqualBytes(expected: []const u8, actual: []const u8, offset: usize) !vo
|
|
|
881
1051
|
const endian = builtin.target.cpu.arch.endian();
|
|
882
1052
|
|
|
883
1053
|
fn N(e: anytype) u8 {
|
|
884
|
-
return @
|
|
1054
|
+
return @intFromEnum(e);
|
|
885
1055
|
}
|
|
886
1056
|
|
|
887
1057
|
const p1 = Player.P1;
|
|
@@ -892,23 +1062,32 @@ const gen1 = struct {
|
|
|
892
1062
|
pub const helpers = @import("../gen1/helpers.zig");
|
|
893
1063
|
};
|
|
894
1064
|
|
|
1065
|
+
const gen2 = struct {
|
|
1066
|
+
pub usingnamespace @import("../gen2/data.zig");
|
|
1067
|
+
pub const helpers = @import("../gen2/helpers.zig");
|
|
1068
|
+
};
|
|
1069
|
+
|
|
895
1070
|
var buf: [gen1.LOGS_SIZE]u8 = undefined;
|
|
896
|
-
var stream =
|
|
1071
|
+
var stream: ByteStream = .{ .buffer = &buf };
|
|
897
1072
|
var log: FixedLog = .{ .writer = stream.writer() };
|
|
898
1073
|
|
|
899
1074
|
const M = gen1.Move;
|
|
900
1075
|
const S = gen1.Species;
|
|
901
1076
|
|
|
902
1077
|
fn expectLog1(expected: []const u8, actual: []const u8) !void {
|
|
903
|
-
return expectLog(
|
|
1078
|
+
return expectLog(gen1, expected, actual, 0);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
fn expectLog2(expected: []const u8, actual: []const u8) !void {
|
|
1082
|
+
return expectLog(gen2, expected, actual, 0);
|
|
904
1083
|
}
|
|
905
1084
|
|
|
906
|
-
fn
|
|
1085
|
+
fn formatter(comptime gen: anytype, kind: Kind, byte: u8) []const u8 {
|
|
907
1086
|
return switch (kind) {
|
|
908
|
-
.Move => @tagName(@
|
|
909
|
-
.Species => @tagName(@
|
|
910
|
-
.Type => @tagName(@
|
|
911
|
-
.Status =>
|
|
1087
|
+
.Move => @tagName(@as(gen.Move, @enumFromInt(byte))),
|
|
1088
|
+
.Species => @tagName(@as(gen.Species, @enumFromInt(byte))),
|
|
1089
|
+
.Type => @tagName(@as(gen.Type, @enumFromInt(byte))),
|
|
1090
|
+
.Status => gen.Status.name(byte),
|
|
912
1091
|
};
|
|
913
1092
|
}
|
|
914
1093
|
|
|
@@ -993,6 +1172,25 @@ test "|switch|" {
|
|
|
993
1172
|
};
|
|
994
1173
|
try expectLog1(expected, buf[0..9]);
|
|
995
1174
|
stream.reset();
|
|
1175
|
+
|
|
1176
|
+
var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.Splash} });
|
|
1177
|
+
blissey.level = 91;
|
|
1178
|
+
blissey.hp = 200;
|
|
1179
|
+
blissey.stats.hp = 400;
|
|
1180
|
+
blissey.status = gen2.Status.init(.PAR);
|
|
1181
|
+
try log.switched(p2.ident(3), &blissey);
|
|
1182
|
+
expected = &(.{
|
|
1183
|
+
N(ArgType.Switch),
|
|
1184
|
+
0b1011,
|
|
1185
|
+
N(gen2.Species.Blissey),
|
|
1186
|
+
N(gen2.Gender.Female),
|
|
1187
|
+
91,
|
|
1188
|
+
} ++ switch (endian) {
|
|
1189
|
+
.Big => .{ 0, 200, 1, 144, par },
|
|
1190
|
+
.Little => .{ 200, 0, 144, 1, par },
|
|
1191
|
+
});
|
|
1192
|
+
try expectLog2(expected, buf[0..10]);
|
|
1193
|
+
stream.reset();
|
|
996
1194
|
}
|
|
997
1195
|
|
|
998
1196
|
test "|cant|" {
|
|
@@ -1295,3 +1493,23 @@ test "|-transform|" {
|
|
|
1295
1493
|
try expectLog1(&.{ N(ArgType.Transform), 0b1100, 0b0101 }, buf[0..3]);
|
|
1296
1494
|
stream.reset();
|
|
1297
1495
|
}
|
|
1496
|
+
test "|-sidestart|" {
|
|
1497
|
+
try log.sidestart(p2.ident(6), .Reflect);
|
|
1498
|
+
try expectLog2(&.{ N(ArgType.SideStart), 0b1110, N(SideStart.Reflect) }, buf[0..3]);
|
|
1499
|
+
stream.reset();
|
|
1500
|
+
}
|
|
1501
|
+
test "|-sideend|" {
|
|
1502
|
+
try log.sideend(p2.ident(6), .LightScreen);
|
|
1503
|
+
try expectLog2(&.{ N(ArgType.SideEnd), 0b1110, N(SideEnd.LightScreen) }, buf[0..3]);
|
|
1504
|
+
stream.reset();
|
|
1505
|
+
|
|
1506
|
+
try log.sideendFromOf(p1.ident(2), .Spikes, gen2.Move.RapidSpin, p1.ident(3));
|
|
1507
|
+
try expectLog2(&.{
|
|
1508
|
+
N(ArgType.SideEnd),
|
|
1509
|
+
0b0010,
|
|
1510
|
+
N(SideEnd.Spikes),
|
|
1511
|
+
N(gen2.Move.RapidSpin),
|
|
1512
|
+
0b0011,
|
|
1513
|
+
}, buf[0..5]);
|
|
1514
|
+
stream.reset();
|
|
1515
|
+
}
|