@pkmn/engine 0.1.0-dev.942dbfa4 → 0.1.0-dev.954f650d
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 +53 -42
- package/build/pkg/addon.js +3 -2
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/layout.json +24 -2
- package/build/pkg/gen1.js +13 -16
- package/build/pkg/gen1.js.map +1 -1
- package/build.zig +79 -54
- package/package.json +24 -15
- package/src/bin/install-pkmn-engine +10 -5
- package/src/lib/binding/node.zig +45 -140
- package/src/lib/binding/wasm.zig +4 -2
- package/src/lib/common/battle.zig +17 -0
- package/src/lib/common/data.zig +14 -26
- package/src/lib/common/debug.zig +20 -11
- package/src/lib/common/js.zig +118 -0
- package/src/lib/common/optional.zig +60 -0
- package/src/lib/common/options.zig +9 -0
- package/src/lib/common/protocol.zig +209 -98
- package/src/lib/common/rational.zig +353 -0
- package/src/lib/common/rng.zig +11 -11
- package/src/lib/common/util.zig +12 -0
- package/src/lib/gen1/README.md +257 -177
- package/src/lib/gen1/calc.zig +426 -0
- package/src/lib/gen1/chance.zig +1036 -0
- package/src/lib/gen1/data/moves.zig +168 -170
- package/src/lib/gen1/data/types.zig +1 -1
- package/src/lib/gen1/data.zig +56 -46
- package/src/lib/gen1/helpers.zig +588 -17
- package/src/lib/gen1/mechanics.zig +769 -489
- package/src/lib/gen2/README.md +87 -13
- package/src/lib/gen2/data/items.zig +1 -1
- package/src/lib/gen2/data/moves.zig +623 -562
- package/src/lib/gen2/data.zig +94 -64
- package/src/lib/gen2/helpers.zig +15 -21
- package/src/lib/gen2/mechanics.zig +814 -11
- package/src/lib/pkmn.zig +61 -2
|
@@ -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) {
|
|
@@ -133,6 +136,8 @@ pub const Damage = enum(u8) {
|
|
|
133
136
|
Confusion,
|
|
134
137
|
LeechSeed,
|
|
135
138
|
RecoilOf,
|
|
139
|
+
|
|
140
|
+
Spikes,
|
|
136
141
|
};
|
|
137
142
|
|
|
138
143
|
pub const Status = enum(u8) {
|
|
@@ -219,8 +224,12 @@ pub const Immune = enum(u8) {
|
|
|
219
224
|
OHKO,
|
|
220
225
|
};
|
|
221
226
|
|
|
227
|
+
/// Null object pattern implementation of `Log` backed by a `std.io.null_writer`.
|
|
228
|
+
/// Ignores anything sent to it, though protocol logging should additionally be turned off
|
|
229
|
+
/// entirely with `options.log`.
|
|
222
230
|
pub const NULL = Log(@TypeOf(std.io.null_writer)){ .writer = std.io.null_writer };
|
|
223
231
|
|
|
232
|
+
/// Logs protocol information to its `Writer` during a battle update when `options.log` is enabled.
|
|
224
233
|
pub fn Log(comptime Writer: type) type {
|
|
225
234
|
return struct {
|
|
226
235
|
const Self = @This();
|
|
@@ -231,12 +240,13 @@ pub fn Log(comptime Writer: type) type {
|
|
|
231
240
|
|
|
232
241
|
pub fn move(self: Self, source: ID, m: anytype, target: ID, from: anytype) Error!void {
|
|
233
242
|
if (!enabled) return;
|
|
243
|
+
|
|
234
244
|
assert(m != .None);
|
|
235
245
|
try self.writer.writeAll(&.{
|
|
236
246
|
@intFromEnum(ArgType.Move),
|
|
237
|
-
@
|
|
247
|
+
@as(u8, @bitCast(source)),
|
|
238
248
|
@intFromEnum(m),
|
|
239
|
-
@
|
|
249
|
+
@as(u8, @bitCast(target)),
|
|
240
250
|
});
|
|
241
251
|
const none = &[_]u8{@intFromEnum(Move.None)};
|
|
242
252
|
try self.writer.writeAll(switch (@typeInfo(@TypeOf(from))) {
|
|
@@ -254,8 +264,17 @@ pub fn Log(comptime Writer: type) type {
|
|
|
254
264
|
|
|
255
265
|
pub fn switched(self: Self, ident: ID, pokemon: anytype) Error!void {
|
|
256
266
|
if (!enabled) return;
|
|
257
|
-
|
|
258
|
-
try self.writer.writeAll(&.{ @intFromEnum(
|
|
267
|
+
|
|
268
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Switch), @as(u8, @bitCast(ident)) });
|
|
269
|
+
if (@hasField(@TypeOf(pokemon.*), "dvs")) {
|
|
270
|
+
try self.writer.writeAll(&.{
|
|
271
|
+
@intFromEnum(pokemon.species),
|
|
272
|
+
@intFromEnum(pokemon.dvs.gender),
|
|
273
|
+
pokemon.level,
|
|
274
|
+
});
|
|
275
|
+
} else {
|
|
276
|
+
try self.writer.writeAll(&.{ @intFromEnum(pokemon.species), pokemon.level });
|
|
277
|
+
}
|
|
259
278
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
260
279
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
261
280
|
try self.writer.writeAll(&.{pokemon.status});
|
|
@@ -263,19 +282,21 @@ pub fn Log(comptime Writer: type) type {
|
|
|
263
282
|
|
|
264
283
|
pub fn cant(self: Self, ident: ID, reason: Cant) Error!void {
|
|
265
284
|
if (!enabled) return;
|
|
285
|
+
|
|
266
286
|
assert(reason != .Disable);
|
|
267
287
|
try self.writer.writeAll(&.{
|
|
268
288
|
@intFromEnum(ArgType.Cant),
|
|
269
|
-
@
|
|
289
|
+
@as(u8, @bitCast(ident)),
|
|
270
290
|
@intFromEnum(reason),
|
|
271
291
|
});
|
|
272
292
|
}
|
|
273
293
|
|
|
274
294
|
pub fn disabled(self: Self, ident: ID, m: anytype) Error!void {
|
|
275
295
|
if (!enabled) return;
|
|
296
|
+
|
|
276
297
|
try self.writer.writeAll(&.{
|
|
277
298
|
@intFromEnum(ArgType.Cant),
|
|
278
|
-
@
|
|
299
|
+
@as(u8, @bitCast(ident)),
|
|
279
300
|
@intFromEnum(Cant.Disable),
|
|
280
301
|
@intFromEnum(m),
|
|
281
302
|
});
|
|
@@ -283,12 +304,14 @@ pub fn Log(comptime Writer: type) type {
|
|
|
283
304
|
|
|
284
305
|
pub fn faint(self: Self, ident: ID, done: bool) Error!void {
|
|
285
306
|
if (!enabled) return;
|
|
286
|
-
|
|
307
|
+
|
|
308
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Faint), @as(u8, @bitCast(ident)) });
|
|
287
309
|
if (done) try self.writer.writeByte(@intFromEnum(ArgType.None));
|
|
288
310
|
}
|
|
289
311
|
|
|
290
312
|
pub fn turn(self: Self, num: u16) Error!void {
|
|
291
313
|
if (!enabled) return;
|
|
314
|
+
|
|
292
315
|
try self.writer.writeByte(@intFromEnum(ArgType.Turn));
|
|
293
316
|
try self.writer.writeIntNative(u16, num);
|
|
294
317
|
try self.writer.writeByte(@intFromEnum(ArgType.None));
|
|
@@ -296,6 +319,7 @@ pub fn Log(comptime Writer: type) type {
|
|
|
296
319
|
|
|
297
320
|
pub fn win(self: Self, player: Player) Error!void {
|
|
298
321
|
if (!enabled) return;
|
|
322
|
+
|
|
299
323
|
try self.writer.writeAll(&.{
|
|
300
324
|
@intFromEnum(ArgType.Win),
|
|
301
325
|
@intFromEnum(player),
|
|
@@ -305,13 +329,15 @@ pub fn Log(comptime Writer: type) type {
|
|
|
305
329
|
|
|
306
330
|
pub fn tie(self: Self) Error!void {
|
|
307
331
|
if (!enabled) return;
|
|
332
|
+
|
|
308
333
|
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Tie), @intFromEnum(ArgType.None) });
|
|
309
334
|
}
|
|
310
335
|
|
|
311
336
|
pub fn damage(self: Self, ident: ID, pokemon: anytype, reason: Damage) Error!void {
|
|
312
337
|
if (!enabled) return;
|
|
338
|
+
|
|
313
339
|
assert(@intFromEnum(reason) <= @intFromEnum(Damage.LeechSeed));
|
|
314
|
-
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @
|
|
340
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
|
|
315
341
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
316
342
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
317
343
|
try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
|
|
@@ -325,21 +351,23 @@ pub fn Log(comptime Writer: type) type {
|
|
|
325
351
|
source: ID,
|
|
326
352
|
) Error!void {
|
|
327
353
|
if (!enabled) return;
|
|
354
|
+
|
|
328
355
|
assert(@intFromEnum(reason) == @intFromEnum(Damage.RecoilOf));
|
|
329
|
-
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @
|
|
356
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Damage), @as(u8, @bitCast(ident)) });
|
|
330
357
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
331
358
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
332
359
|
try self.writer.writeAll(&.{
|
|
333
360
|
pokemon.status,
|
|
334
361
|
@intFromEnum(reason),
|
|
335
|
-
@
|
|
362
|
+
@as(u8, @bitCast(source)),
|
|
336
363
|
});
|
|
337
364
|
}
|
|
338
365
|
|
|
339
366
|
pub fn heal(self: Self, ident: ID, pokemon: anytype, reason: Heal) Error!void {
|
|
340
367
|
if (!enabled) return;
|
|
368
|
+
|
|
341
369
|
assert(reason != .Drain);
|
|
342
|
-
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @
|
|
370
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(ident)) });
|
|
343
371
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
344
372
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
345
373
|
try self.writer.writeAll(&.{ pokemon.status, @intFromEnum(reason) });
|
|
@@ -347,22 +375,24 @@ pub fn Log(comptime Writer: type) type {
|
|
|
347
375
|
|
|
348
376
|
pub fn drain(self: Self, source: ID, pokemon: anytype, target: ID) Error!void {
|
|
349
377
|
if (!enabled) return;
|
|
350
|
-
|
|
378
|
+
|
|
379
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Heal), @as(u8, @bitCast(source)) });
|
|
351
380
|
try self.writer.writeIntNative(u16, pokemon.hp);
|
|
352
381
|
try self.writer.writeIntNative(u16, pokemon.stats.hp);
|
|
353
382
|
try self.writer.writeAll(&.{
|
|
354
383
|
pokemon.status,
|
|
355
384
|
@intFromEnum(Heal.Drain),
|
|
356
|
-
@
|
|
385
|
+
@as(u8, @bitCast(target)),
|
|
357
386
|
});
|
|
358
387
|
}
|
|
359
388
|
|
|
360
389
|
pub fn status(self: Self, ident: ID, value: u8, reason: Status) Error!void {
|
|
361
390
|
if (!enabled) return;
|
|
391
|
+
|
|
362
392
|
assert(reason != .From);
|
|
363
393
|
try self.writer.writeAll(&.{
|
|
364
394
|
@intFromEnum(ArgType.Status),
|
|
365
|
-
@
|
|
395
|
+
@as(u8, @bitCast(ident)),
|
|
366
396
|
value,
|
|
367
397
|
@intFromEnum(reason),
|
|
368
398
|
});
|
|
@@ -370,9 +400,10 @@ pub fn Log(comptime Writer: type) type {
|
|
|
370
400
|
|
|
371
401
|
pub fn statusFrom(self: Self, ident: ID, value: u8, m: anytype) Error!void {
|
|
372
402
|
if (!enabled) return;
|
|
403
|
+
|
|
373
404
|
try self.writer.writeAll(&.{
|
|
374
405
|
@intFromEnum(ArgType.Status),
|
|
375
|
-
@
|
|
406
|
+
@as(u8, @bitCast(ident)),
|
|
376
407
|
value,
|
|
377
408
|
@intFromEnum(Status.From),
|
|
378
409
|
@intFromEnum(m),
|
|
@@ -381,9 +412,10 @@ pub fn Log(comptime Writer: type) type {
|
|
|
381
412
|
|
|
382
413
|
pub fn curestatus(self: Self, ident: ID, value: u8, reason: CureStatus) Error!void {
|
|
383
414
|
if (!enabled) return;
|
|
415
|
+
|
|
384
416
|
try self.writer.writeAll(&.{
|
|
385
417
|
@intFromEnum(ArgType.CureStatus),
|
|
386
|
-
@
|
|
418
|
+
@as(u8, @bitCast(ident)),
|
|
387
419
|
value,
|
|
388
420
|
@intFromEnum(reason),
|
|
389
421
|
});
|
|
@@ -391,98 +423,113 @@ pub fn Log(comptime Writer: type) type {
|
|
|
391
423
|
|
|
392
424
|
pub fn boost(self: Self, ident: ID, reason: Boost, num: i8) Error!void {
|
|
393
425
|
if (!enabled) return;
|
|
426
|
+
|
|
394
427
|
assert(num != 0 and (reason != .Rage or num > 0));
|
|
395
428
|
try self.writer.writeAll(&.{
|
|
396
429
|
@intFromEnum(ArgType.Boost),
|
|
397
|
-
@
|
|
430
|
+
@as(u8, @bitCast(ident)),
|
|
398
431
|
@intFromEnum(reason),
|
|
399
|
-
@
|
|
432
|
+
@as(u8, @intCast(num + 6)),
|
|
400
433
|
});
|
|
401
434
|
}
|
|
402
435
|
|
|
403
436
|
pub fn clearallboost(self: Self) Error!void {
|
|
404
437
|
if (!enabled) return;
|
|
438
|
+
|
|
405
439
|
try self.writer.writeAll(&.{@intFromEnum(ArgType.ClearAllBoost)});
|
|
406
440
|
}
|
|
407
441
|
|
|
408
442
|
pub fn fail(self: Self, ident: ID, reason: Fail) Error!void {
|
|
409
443
|
if (!enabled) return;
|
|
444
|
+
|
|
410
445
|
try self.writer.writeAll(&.{
|
|
411
446
|
@intFromEnum(ArgType.Fail),
|
|
412
|
-
@
|
|
447
|
+
@as(u8, @bitCast(ident)),
|
|
413
448
|
@intFromEnum(reason),
|
|
414
449
|
});
|
|
415
450
|
}
|
|
416
451
|
|
|
417
452
|
pub fn miss(self: Self, source: ID) Error!void {
|
|
418
453
|
if (!enabled) return;
|
|
419
|
-
|
|
454
|
+
|
|
455
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Miss), @as(u8, @bitCast(source)) });
|
|
420
456
|
}
|
|
421
457
|
|
|
422
458
|
pub fn hitcount(self: Self, ident: ID, num: u8) Error!void {
|
|
423
459
|
if (!enabled) return;
|
|
460
|
+
|
|
424
461
|
try self.writer.writeAll(&.{
|
|
425
462
|
@intFromEnum(ArgType.HitCount),
|
|
426
|
-
@
|
|
463
|
+
@as(u8, @bitCast(ident)),
|
|
427
464
|
num,
|
|
428
465
|
});
|
|
429
466
|
}
|
|
430
467
|
|
|
431
468
|
pub fn prepare(self: Self, source: ID, m: anytype) Error!void {
|
|
432
469
|
if (!enabled) return;
|
|
470
|
+
|
|
433
471
|
try self.writer.writeAll(&.{
|
|
434
472
|
@intFromEnum(ArgType.Prepare),
|
|
435
|
-
@
|
|
473
|
+
@as(u8, @bitCast(source)),
|
|
436
474
|
@intFromEnum(m),
|
|
437
475
|
});
|
|
438
476
|
}
|
|
439
477
|
|
|
440
478
|
pub fn mustrecharge(self: Self, ident: ID) Error!void {
|
|
441
479
|
if (!enabled) return;
|
|
442
|
-
|
|
480
|
+
|
|
481
|
+
try self.writer.writeAll(&.{
|
|
482
|
+
@intFromEnum(ArgType.MustRecharge),
|
|
483
|
+
@as(u8, @bitCast(ident)),
|
|
484
|
+
});
|
|
443
485
|
}
|
|
444
486
|
|
|
445
487
|
pub fn activate(self: Self, ident: ID, reason: Activate) Error!void {
|
|
446
488
|
if (!enabled) return;
|
|
489
|
+
|
|
447
490
|
try self.writer.writeAll(&.{
|
|
448
491
|
@intFromEnum(ArgType.Activate),
|
|
449
|
-
@
|
|
492
|
+
@as(u8, @bitCast(ident)),
|
|
450
493
|
@intFromEnum(reason),
|
|
451
494
|
});
|
|
452
495
|
}
|
|
453
496
|
|
|
454
497
|
pub fn fieldactivate(self: Self) Error!void {
|
|
455
498
|
if (!enabled) return;
|
|
499
|
+
|
|
456
500
|
try self.writer.writeAll(&.{@intFromEnum(ArgType.FieldActivate)});
|
|
457
501
|
}
|
|
458
502
|
|
|
459
503
|
pub fn start(self: Self, ident: ID, reason: Start) Error!void {
|
|
460
504
|
if (!enabled) return;
|
|
505
|
+
|
|
461
506
|
assert(@intFromEnum(reason) < @intFromEnum(Start.TypeChange));
|
|
462
507
|
try self.writer.writeAll(&.{
|
|
463
508
|
@intFromEnum(ArgType.Start),
|
|
464
|
-
@
|
|
509
|
+
@as(u8, @bitCast(ident)),
|
|
465
510
|
@intFromEnum(reason),
|
|
466
511
|
});
|
|
467
512
|
}
|
|
468
513
|
|
|
469
514
|
pub fn typechange(self: Self, source: ID, types: anytype, target: ID) Error!void {
|
|
470
515
|
if (!enabled) return;
|
|
516
|
+
|
|
471
517
|
try self.writer.writeAll(&.{
|
|
472
518
|
@intFromEnum(ArgType.Start),
|
|
473
|
-
@
|
|
519
|
+
@as(u8, @bitCast(source)),
|
|
474
520
|
@intFromEnum(Start.TypeChange),
|
|
475
|
-
@
|
|
476
|
-
@
|
|
521
|
+
@as(u8, @bitCast(types)),
|
|
522
|
+
@as(u8, @bitCast(target)),
|
|
477
523
|
});
|
|
478
524
|
}
|
|
479
525
|
|
|
480
526
|
pub fn startEffect(self: Self, ident: ID, reason: Start, m: anytype) Error!void {
|
|
481
527
|
if (!enabled) return;
|
|
528
|
+
|
|
482
529
|
assert(@intFromEnum(reason) > @intFromEnum(Start.TypeChange));
|
|
483
530
|
try self.writer.writeAll(&.{
|
|
484
531
|
@intFromEnum(ArgType.Start),
|
|
485
|
-
@
|
|
532
|
+
@as(u8, @bitCast(ident)),
|
|
486
533
|
@intFromEnum(reason),
|
|
487
534
|
@intFromEnum(m),
|
|
488
535
|
});
|
|
@@ -490,68 +537,84 @@ pub fn Log(comptime Writer: type) type {
|
|
|
490
537
|
|
|
491
538
|
pub fn end(self: Self, ident: ID, reason: End) Error!void {
|
|
492
539
|
if (!enabled) return;
|
|
540
|
+
|
|
493
541
|
try self.writer.writeAll(&.{
|
|
494
542
|
@intFromEnum(ArgType.End),
|
|
495
|
-
@
|
|
543
|
+
@as(u8, @bitCast(ident)),
|
|
496
544
|
@intFromEnum(reason),
|
|
497
545
|
});
|
|
498
546
|
}
|
|
499
547
|
|
|
500
548
|
pub fn ohko(self: Self) Error!void {
|
|
501
549
|
if (!enabled) return;
|
|
550
|
+
|
|
502
551
|
try self.writer.writeAll(&.{@intFromEnum(ArgType.OHKO)});
|
|
503
552
|
}
|
|
504
553
|
|
|
505
554
|
pub fn crit(self: Self, ident: ID) Error!void {
|
|
506
555
|
if (!enabled) return;
|
|
507
|
-
|
|
556
|
+
|
|
557
|
+
try self.writer.writeAll(&.{ @intFromEnum(ArgType.Crit), @as(u8, @bitCast(ident)) });
|
|
508
558
|
}
|
|
509
559
|
|
|
510
560
|
pub fn supereffective(self: Self, ident: ID) Error!void {
|
|
511
561
|
if (!enabled) return;
|
|
562
|
+
|
|
512
563
|
try self.writer.writeAll(&.{
|
|
513
564
|
@intFromEnum(ArgType.SuperEffective),
|
|
514
|
-
@
|
|
565
|
+
@as(u8, @bitCast(ident)),
|
|
515
566
|
});
|
|
516
567
|
}
|
|
517
568
|
|
|
518
569
|
pub fn resisted(self: Self, ident: ID) Error!void {
|
|
519
570
|
if (!enabled) return;
|
|
520
|
-
|
|
571
|
+
|
|
572
|
+
try self.writer.writeAll(&.{
|
|
573
|
+
@intFromEnum(ArgType.Resisted),
|
|
574
|
+
@as(u8, @bitCast(ident)),
|
|
575
|
+
});
|
|
521
576
|
}
|
|
522
577
|
|
|
523
578
|
pub fn immune(self: Self, ident: ID, reason: Immune) Error!void {
|
|
524
579
|
if (!enabled) return;
|
|
580
|
+
|
|
525
581
|
try self.writer.writeAll(&.{
|
|
526
582
|
@intFromEnum(ArgType.Immune),
|
|
527
|
-
@
|
|
583
|
+
@as(u8, @bitCast(ident)),
|
|
528
584
|
@intFromEnum(reason),
|
|
529
585
|
});
|
|
530
586
|
}
|
|
531
587
|
|
|
532
588
|
pub fn transform(self: Self, source: ID, target: ID) Error!void {
|
|
533
589
|
if (!enabled) return;
|
|
590
|
+
|
|
534
591
|
try self.writer.writeAll(&.{
|
|
535
592
|
@intFromEnum(ArgType.Transform),
|
|
536
|
-
@
|
|
537
|
-
@
|
|
593
|
+
@as(u8, @bitCast(source)),
|
|
594
|
+
@as(u8, @bitCast(target)),
|
|
538
595
|
});
|
|
539
596
|
}
|
|
540
597
|
|
|
541
598
|
pub fn laststill(self: Self) Error!void {
|
|
542
599
|
if (!enabled) return;
|
|
600
|
+
|
|
543
601
|
try self.writer.writeAll(&.{@intFromEnum(ArgType.LastStill)});
|
|
544
602
|
}
|
|
545
603
|
|
|
546
604
|
pub fn lastmiss(self: Self) Error!void {
|
|
547
605
|
if (!enabled) return;
|
|
606
|
+
|
|
548
607
|
try self.writer.writeAll(&.{@intFromEnum(ArgType.LastMiss)});
|
|
549
608
|
}
|
|
550
609
|
};
|
|
551
610
|
}
|
|
552
611
|
|
|
612
|
+
/// `Log` type backed by the optimized `ByteStream.Writer`.
|
|
553
613
|
pub const FixedLog = Log(ByteStream.Writer);
|
|
554
614
|
|
|
615
|
+
/// Stripped down version of `std.io.FixedBufferStream` optimized for efficiently writing the
|
|
616
|
+
/// individual protocol bytes. Note that the `ByteStream.Writer` is **not** a `std.io.Writer` and
|
|
617
|
+
/// should not be used for general purpose writing.
|
|
555
618
|
pub const ByteStream = struct {
|
|
556
619
|
buffer: []u8,
|
|
557
620
|
pos: usize = 0,
|
|
@@ -593,14 +656,18 @@ pub const ByteStream = struct {
|
|
|
593
656
|
};
|
|
594
657
|
|
|
595
658
|
pub const Kind = enum { Move, Species, Type, Status };
|
|
596
|
-
pub const Formatter = fn (Kind, u8) []const u8;
|
|
597
659
|
|
|
598
|
-
pub fn format(
|
|
660
|
+
pub fn format(
|
|
661
|
+
comptime gen: anytype,
|
|
662
|
+
a: []const u8,
|
|
663
|
+
b: ?[]const u8,
|
|
664
|
+
color: bool,
|
|
665
|
+
) void {
|
|
599
666
|
print("\n", .{});
|
|
600
667
|
|
|
601
668
|
var i: usize = 0;
|
|
602
669
|
while (i < a.len) {
|
|
603
|
-
const arg = @enumFromInt(
|
|
670
|
+
const arg: ArgType = @enumFromInt(a[i]);
|
|
604
671
|
const name = switch (arg) {
|
|
605
672
|
.None => if (color) "\x1b[2m-\x1b[0m" else "-",
|
|
606
673
|
.LastStill => "|[still]",
|
|
@@ -646,19 +713,29 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
646
713
|
.OHKO,
|
|
647
714
|
=> {},
|
|
648
715
|
.Move => {
|
|
649
|
-
const source = ID.from(@intCast(
|
|
716
|
+
const source = ID.from(@intCast(a[i]));
|
|
650
717
|
printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
|
|
651
|
-
printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
|
|
652
|
-
const target = ID.from(@intCast(
|
|
718
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
719
|
+
const target = ID.from(@intCast(a[i]));
|
|
653
720
|
printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
|
|
654
|
-
const reason = @enumFromInt(
|
|
721
|
+
const reason: Move = @enumFromInt(a[i]);
|
|
655
722
|
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
656
|
-
if (reason == .From)
|
|
723
|
+
if (reason == .From) {
|
|
724
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
725
|
+
}
|
|
657
726
|
},
|
|
658
727
|
.Switch => {
|
|
659
|
-
const id = ID.from(@intCast(
|
|
728
|
+
const id = ID.from(@intCast(a[i]));
|
|
660
729
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
661
|
-
printc(" {s}", .{formatter(.Species, a[i])}, a, b, &i, 1, color);
|
|
730
|
+
printc(" {s}", .{formatter(gen, .Species, a[i])}, a, b, &i, 1, color);
|
|
731
|
+
if (@hasDecl(gen, "Gender")) {
|
|
732
|
+
if (a[i] == N(gen.Gender.Unknown)) {
|
|
733
|
+
i += 1;
|
|
734
|
+
} else {
|
|
735
|
+
var gender = if (a[i] == N(gen.Gender.Male)) "M" else "F";
|
|
736
|
+
printc(", {s}", .{gender}, a, b, &i, 1, color);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
662
739
|
printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
|
|
663
740
|
switch (endian) {
|
|
664
741
|
.Big => {
|
|
@@ -674,15 +751,15 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
674
751
|
printc("/{d}", .{hp}, a, b, &i, 2, color);
|
|
675
752
|
},
|
|
676
753
|
}
|
|
677
|
-
printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
|
|
754
|
+
printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
|
|
678
755
|
},
|
|
679
756
|
.Cant => {
|
|
680
|
-
const id = ID.from(@intCast(
|
|
757
|
+
const id = ID.from(@intCast(a[i]));
|
|
681
758
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
682
|
-
const reason = @enumFromInt(
|
|
759
|
+
const reason: Cant = @enumFromInt(a[i]);
|
|
683
760
|
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
684
761
|
if (reason == .Disable) {
|
|
685
|
-
printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
|
|
762
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
686
763
|
}
|
|
687
764
|
},
|
|
688
765
|
.Faint,
|
|
@@ -692,7 +769,7 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
692
769
|
.SuperEffective,
|
|
693
770
|
.Resisted,
|
|
694
771
|
=> {
|
|
695
|
-
const id = ID.from(@intCast(
|
|
772
|
+
const id = ID.from(@intCast(a[i]));
|
|
696
773
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
697
774
|
},
|
|
698
775
|
.Turn => {
|
|
@@ -702,9 +779,11 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
702
779
|
};
|
|
703
780
|
printc(" {d}", .{turn}, a, b, &i, 2, color);
|
|
704
781
|
},
|
|
705
|
-
.Win =>
|
|
782
|
+
.Win => {
|
|
783
|
+
printc(" {s}", .{@tagName(@as(Player, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
784
|
+
},
|
|
706
785
|
.Damage, .Heal => {
|
|
707
|
-
var id = ID.from(@intCast(
|
|
786
|
+
var id = ID.from(@intCast(a[i]));
|
|
708
787
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
709
788
|
switch (endian) {
|
|
710
789
|
.Big => {
|
|
@@ -720,93 +799,96 @@ pub fn format(comptime formatter: Formatter, a: []const u8, b: ?[]const u8, colo
|
|
|
720
799
|
printc("/{d}", .{hp}, a, b, &i, 2, color);
|
|
721
800
|
},
|
|
722
801
|
}
|
|
723
|
-
printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
|
|
802
|
+
printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
|
|
724
803
|
if (arg == .Damage) {
|
|
725
|
-
const reason = a[i];
|
|
726
|
-
printc(" {s}", .{@tagName(
|
|
727
|
-
if (reason ==
|
|
728
|
-
id = ID.from(@intCast(
|
|
804
|
+
const reason: Damage = @enumFromInt(a[i]);
|
|
805
|
+
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
806
|
+
if (reason == .RecoilOf) {
|
|
807
|
+
id = ID.from(@intCast(a[i]));
|
|
729
808
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
730
809
|
}
|
|
731
810
|
} else {
|
|
732
|
-
const reason = @enumFromInt(
|
|
811
|
+
const reason: Heal = @enumFromInt(a[i]);
|
|
733
812
|
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
734
813
|
if (reason == .Drain) {
|
|
735
|
-
id = ID.from(@intCast(
|
|
814
|
+
id = ID.from(@intCast(a[i]));
|
|
736
815
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
737
816
|
}
|
|
738
817
|
}
|
|
739
818
|
},
|
|
740
819
|
.Status => {
|
|
741
|
-
const id = ID.from(@intCast(
|
|
820
|
+
const id = ID.from(@intCast(a[i]));
|
|
742
821
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
743
|
-
printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
|
|
744
|
-
const reason = @enumFromInt(
|
|
822
|
+
printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
|
|
823
|
+
const reason: Status = @enumFromInt(a[i]);
|
|
745
824
|
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
746
|
-
if (reason == .From)
|
|
825
|
+
if (reason == .From) {
|
|
826
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
827
|
+
}
|
|
747
828
|
},
|
|
748
829
|
.CureStatus => {
|
|
749
|
-
const id = ID.from(@intCast(
|
|
830
|
+
const id = ID.from(@intCast(a[i]));
|
|
750
831
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
751
|
-
printc(" {s}", .{formatter(.Status, a[i])}, a, b, &i, 1, color);
|
|
752
|
-
|
|
832
|
+
printc(" {s}", .{formatter(gen, .Status, a[i])}, a, b, &i, 1, color);
|
|
833
|
+
const reason: CureStatus = @enumFromInt(a[i]);
|
|
834
|
+
printc(" {s}", .{@tagName(reason)}, a, b, &i, 1, color);
|
|
753
835
|
},
|
|
754
836
|
.Boost => {
|
|
755
|
-
const id = ID.from(@intCast(
|
|
837
|
+
const id = ID.from(@intCast(a[i]));
|
|
756
838
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
757
|
-
printc(" {s}", .{@tagName(@
|
|
839
|
+
printc(" {s}", .{@tagName(@as(Boost, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
758
840
|
printc(" {d}", .{a[i]}, a, b, &i, 1, color);
|
|
759
841
|
},
|
|
760
842
|
.Fail => {
|
|
761
|
-
const id = ID.from(@intCast(
|
|
843
|
+
const id = ID.from(@intCast(a[i]));
|
|
762
844
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
763
|
-
printc(" {s}", .{@tagName(@
|
|
845
|
+
printc(" {s}", .{@tagName(@as(Fail, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
764
846
|
},
|
|
765
847
|
.HitCount => {
|
|
766
|
-
const id = ID.from(@intCast(
|
|
848
|
+
const id = ID.from(@intCast(a[i]));
|
|
767
849
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
768
850
|
printc(" {d}", .{a[i]}, a, b, &i, 1, color);
|
|
769
851
|
},
|
|
770
852
|
.Prepare => {
|
|
771
|
-
const id = ID.from(@intCast(
|
|
853
|
+
const id = ID.from(@intCast(a[i]));
|
|
772
854
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
773
|
-
printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
|
|
855
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
774
856
|
},
|
|
775
857
|
.Activate => {
|
|
776
|
-
const id = ID.from(@intCast(
|
|
858
|
+
const id = ID.from(@intCast(a[i]));
|
|
777
859
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
778
|
-
printc(" {s}", .{@tagName(@
|
|
860
|
+
printc(" {s}", .{@tagName(@as(Activate, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
779
861
|
},
|
|
780
862
|
.Start => {
|
|
781
|
-
const id = ID.from(@intCast(
|
|
863
|
+
const id = ID.from(@intCast(a[i]));
|
|
782
864
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
783
865
|
const reason = a[i];
|
|
784
|
-
printc(" {s}", .{@tagName(@
|
|
785
|
-
if (@
|
|
786
|
-
const types = @
|
|
866
|
+
printc(" {s}", .{@tagName(@as(Start, @enumFromInt(reason)))}, a, b, &i, 1, color);
|
|
867
|
+
if (@as(Start, @enumFromInt(reason)) == .TypeChange) {
|
|
868
|
+
const types = @as(gen1.Types, @bitCast(a[i]));
|
|
787
869
|
const args = .{
|
|
788
|
-
formatter(.Type, @intFromEnum(types.type1)),
|
|
789
|
-
formatter(.Type, @intFromEnum(types.type2)),
|
|
870
|
+
formatter(gen, .Type, @intFromEnum(types.type1)),
|
|
871
|
+
formatter(gen, .Type, @intFromEnum(types.type2)),
|
|
790
872
|
};
|
|
791
873
|
printc(" {s}/{s}", args, a, b, &i, 1, color);
|
|
792
874
|
} else if (reason >= @intFromEnum(Start.Disable)) {
|
|
793
|
-
printc(" {s}", .{formatter(.Move, a[i])}, a, b, &i, 1, color);
|
|
875
|
+
printc(" {s}", .{formatter(gen, .Move, a[i])}, a, b, &i, 1, color);
|
|
794
876
|
}
|
|
795
877
|
},
|
|
796
878
|
.End => {
|
|
797
|
-
const id = ID.from(@intCast(
|
|
879
|
+
const id = ID.from(@intCast(a[i]));
|
|
798
880
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
799
|
-
printc(" {s}", .{@tagName(@
|
|
881
|
+
printc(" {s}", .{@tagName(@as(End, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
800
882
|
},
|
|
801
883
|
.Immune => {
|
|
802
|
-
const id = ID.from(@intCast(
|
|
884
|
+
const id = ID.from(@intCast(a[i]));
|
|
803
885
|
printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
|
|
804
|
-
printc(" {s}", .{@tagName(@
|
|
886
|
+
printc(" {s}", .{@tagName(@as(Immune, @enumFromInt(a[i])))}, a, b, &i, 1, color);
|
|
805
887
|
},
|
|
806
888
|
.Transform => {
|
|
807
|
-
const source = ID.from(@intCast(
|
|
889
|
+
const source = ID.from(@intCast(a[i]));
|
|
808
890
|
printc(" {s}({d})", .{ @tagName(source.player), source.id }, a, b, &i, 1, color);
|
|
809
|
-
const target = ID.from(@intCast(
|
|
891
|
+
const target = ID.from(@intCast(a[i]));
|
|
810
892
|
printc(" {s}({d})", .{ @tagName(target.player), target.id }, a, b, &i, 1, color);
|
|
811
893
|
},
|
|
812
894
|
else => unreachable,
|
|
@@ -840,12 +922,13 @@ fn printc(
|
|
|
840
922
|
}
|
|
841
923
|
|
|
842
924
|
pub fn expectLog(
|
|
843
|
-
comptime
|
|
925
|
+
comptime gen: anytype,
|
|
844
926
|
expected: []const u8,
|
|
845
927
|
actual: []const u8,
|
|
846
928
|
offset: usize,
|
|
847
929
|
) !void {
|
|
848
930
|
if (!enabled) return;
|
|
931
|
+
|
|
849
932
|
const color = color: {
|
|
850
933
|
if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
|
|
851
934
|
break :color true;
|
|
@@ -858,8 +941,8 @@ pub fn expectLog(
|
|
|
858
941
|
|
|
859
942
|
expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
|
|
860
943
|
error.TestExpectedEqual => {
|
|
861
|
-
format(
|
|
862
|
-
format(
|
|
944
|
+
format(gen, expected, null, color);
|
|
945
|
+
format(gen, actual, expected, color);
|
|
863
946
|
return err;
|
|
864
947
|
},
|
|
865
948
|
else => return err,
|
|
@@ -899,6 +982,11 @@ const gen1 = struct {
|
|
|
899
982
|
pub const helpers = @import("../gen1/helpers.zig");
|
|
900
983
|
};
|
|
901
984
|
|
|
985
|
+
const gen2 = struct {
|
|
986
|
+
pub usingnamespace @import("../gen2/data.zig");
|
|
987
|
+
pub const helpers = @import("../gen2/helpers.zig");
|
|
988
|
+
};
|
|
989
|
+
|
|
902
990
|
var buf: [gen1.LOGS_SIZE]u8 = undefined;
|
|
903
991
|
var stream = ByteStream{ .buffer = &buf };
|
|
904
992
|
var log: FixedLog = .{ .writer = stream.writer() };
|
|
@@ -907,15 +995,19 @@ const M = gen1.Move;
|
|
|
907
995
|
const S = gen1.Species;
|
|
908
996
|
|
|
909
997
|
fn expectLog1(expected: []const u8, actual: []const u8) !void {
|
|
910
|
-
return expectLog(
|
|
998
|
+
return expectLog(gen1, expected, actual, 0);
|
|
911
999
|
}
|
|
912
1000
|
|
|
913
|
-
fn
|
|
1001
|
+
fn expectLog2(expected: []const u8, actual: []const u8) !void {
|
|
1002
|
+
return expectLog(gen2, expected, actual, 0);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
fn formatter(comptime gen: anytype, kind: Kind, byte: u8) []const u8 {
|
|
914
1006
|
return switch (kind) {
|
|
915
|
-
.Move => @tagName(@
|
|
916
|
-
.Species => @tagName(@
|
|
917
|
-
.Type => @tagName(@
|
|
918
|
-
.Status =>
|
|
1007
|
+
.Move => @tagName(@as(gen.Move, @enumFromInt(byte))),
|
|
1008
|
+
.Species => @tagName(@as(gen.Species, @enumFromInt(byte))),
|
|
1009
|
+
.Type => @tagName(@as(gen.Type, @enumFromInt(byte))),
|
|
1010
|
+
.Status => gen.Status.name(byte),
|
|
919
1011
|
};
|
|
920
1012
|
}
|
|
921
1013
|
|
|
@@ -1000,6 +1092,25 @@ test "|switch|" {
|
|
|
1000
1092
|
};
|
|
1001
1093
|
try expectLog1(expected, buf[0..9]);
|
|
1002
1094
|
stream.reset();
|
|
1095
|
+
|
|
1096
|
+
var blissey = gen2.helpers.Pokemon.init(.{ .species = .Blissey, .moves = &.{.Splash} });
|
|
1097
|
+
blissey.level = 91;
|
|
1098
|
+
blissey.hp = 200;
|
|
1099
|
+
blissey.stats.hp = 400;
|
|
1100
|
+
blissey.status = gen2.Status.init(.PAR);
|
|
1101
|
+
try log.switched(p2.ident(3), &blissey);
|
|
1102
|
+
expected = &(.{
|
|
1103
|
+
N(ArgType.Switch),
|
|
1104
|
+
0b1011,
|
|
1105
|
+
N(gen2.Species.Blissey),
|
|
1106
|
+
N(gen2.Gender.Female),
|
|
1107
|
+
91,
|
|
1108
|
+
} ++ switch (endian) {
|
|
1109
|
+
.Big => .{ 0, 200, 1, 144, par },
|
|
1110
|
+
.Little => .{ 200, 0, 144, 1, par },
|
|
1111
|
+
});
|
|
1112
|
+
try expectLog2(expected, buf[0..10]);
|
|
1113
|
+
stream.reset();
|
|
1003
1114
|
}
|
|
1004
1115
|
|
|
1005
1116
|
test "|cant|" {
|