@pkmn/engine 0.1.0-dev.9f75c7ae → 0.1.0-dev.a0167a9d
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 +44 -19
- package/build/pkg/addon.js +6 -7
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +4 -4
- package/build/pkg/data.js.map +1 -1
- 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 +5 -5
- 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 +82 -90
- package/package.json +31 -23
- package/src/bin/install-pkmn-engine +26 -18
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/debug.zig +2 -2
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/options.zig +2 -0
- package/src/lib/common/protocol.zig +393 -396
- package/src/lib/common/rational.zig +109 -15
- package/src/lib/common/rng.zig +11 -11
- package/src/lib/gen1/calc.zig +269 -97
- package/src/lib/gen1/chance.zig +126 -160
- package/src/lib/gen1/data/species.zig +1 -1
- package/src/lib/gen1/data.zig +21 -21
- package/src/lib/gen1/helpers.zig +191 -206
- package/src/lib/gen1/mechanics.zig +308 -285
- package/src/lib/gen2/chance.zig +211 -121
- package/src/lib/gen2/data.zig +13 -11
- package/src/lib/gen2/generated.zig +15 -24
- package/src/lib/gen2/helpers.zig +37 -7
- package/src/lib/gen2/mechanics.zig +855 -413
- package/src/lib/{binding/node.zig → node.zig} +9 -12
- package/src/lib/pkmn.zig +27 -12
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
- package/src/test/display/pkmn.html.tmpl +5 -5
- package/src/lib/gen1/README.md +0 -894
- package/src/lib/gen2/README.md +0 -330
package/src/lib/gen2/data.zig
CHANGED
|
@@ -239,7 +239,7 @@ pub const DVs = packed struct(u16) {
|
|
|
239
239
|
};
|
|
240
240
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
241
241
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
242
|
-
|
|
242
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
243
|
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
244
244
|
}
|
|
245
245
|
};
|
|
@@ -248,12 +248,12 @@ test DVs {
|
|
|
248
248
|
var dvs = DVs.from(.Mewtwo, .{ .def = 13 });
|
|
249
249
|
try expectEqual(Gender.Unknown, dvs.gender);
|
|
250
250
|
try expectEqual(Type.Ice, dvs.type);
|
|
251
|
-
try expectEqual(
|
|
251
|
+
try expectEqual(70, dvs.power());
|
|
252
252
|
|
|
253
253
|
dvs = DVs.from(.Pikachu, .{ .spc = 14 });
|
|
254
254
|
try expectEqual(Gender.Male, dvs.gender);
|
|
255
255
|
try expectEqual(Type.Dark, dvs.type);
|
|
256
|
-
try expectEqual(
|
|
256
|
+
try expectEqual(69, dvs.power());
|
|
257
257
|
|
|
258
258
|
dvs = DVs.from(.Cyndaquil, .{ .atk = 1, .def = 3, .spe = 10, .spc = 9 });
|
|
259
259
|
try expectEqual(Gender.Female, dvs.gender);
|
|
@@ -314,16 +314,18 @@ pub const Volatiles = packed struct(u128) {
|
|
|
314
314
|
Encore: bool = false,
|
|
315
315
|
LockOn: bool = false,
|
|
316
316
|
DestinyBond: bool = false,
|
|
317
|
+
Trapped: bool = false,
|
|
317
318
|
|
|
318
|
-
trapped: bool = false,
|
|
319
319
|
switched: bool = false,
|
|
320
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
320
321
|
switching: bool = false,
|
|
322
|
+
// TODO: simply store both last moves on side
|
|
321
323
|
dirty: bool = false,
|
|
322
324
|
|
|
323
325
|
frozen: bool = false,
|
|
324
326
|
minimized: bool = false,
|
|
325
327
|
_: u10 = 0,
|
|
326
|
-
// TODO?
|
|
328
|
+
// TODO: is this needed for unmodified stats?
|
|
327
329
|
transform: u4 = 0,
|
|
328
330
|
|
|
329
331
|
bide: u16 = 0,
|
|
@@ -378,9 +380,9 @@ test Stats {
|
|
|
378
380
|
try expectEqual(0, stats.def);
|
|
379
381
|
|
|
380
382
|
var base = Species.get(.Gyarados).stats;
|
|
381
|
-
try expectEqual(
|
|
383
|
+
try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
382
384
|
base = Species.get(.Pidgeot).stats;
|
|
383
|
-
try expectEqual(
|
|
385
|
+
try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
384
386
|
}
|
|
385
387
|
|
|
386
388
|
pub const Boosts = packed struct(u32) {
|
|
@@ -426,8 +428,8 @@ test Move {
|
|
|
426
428
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
427
429
|
try expectEqual(rng.Gen12.percent(50), move.accuracy);
|
|
428
430
|
try expectEqual(rng.Gen12.percent(100), move.chance);
|
|
429
|
-
try expectEqual(
|
|
430
|
-
try expectEqual(
|
|
431
|
+
try expectEqual(5, Move.pp(.DynamicPunch));
|
|
432
|
+
try expectEqual(-1, Move.get(.Counter).priority);
|
|
431
433
|
try expect(!move.effect.isHighCritical());
|
|
432
434
|
try expect(Move.get(.KarateChop).effect.isHighCritical());
|
|
433
435
|
try expect(Move.get(.RazorWind).effect.isHighCritical());
|
|
@@ -437,7 +439,7 @@ pub const Species = species.Species;
|
|
|
437
439
|
|
|
438
440
|
test Species {
|
|
439
441
|
try expectEqual(152, @intFromEnum(Species.Chikorita));
|
|
440
|
-
try expectEqual(
|
|
442
|
+
try expectEqual(100, Species.get(.Celebi).stats.spd);
|
|
441
443
|
}
|
|
442
444
|
|
|
443
445
|
pub const Type = types.Type;
|
|
@@ -450,7 +452,7 @@ test Types {
|
|
|
450
452
|
try expect(!Type.Steel.special());
|
|
451
453
|
try expect(Type.Dark.special());
|
|
452
454
|
|
|
453
|
-
try expectEqual(
|
|
455
|
+
try expectEqual(3, Type.Water.precedence());
|
|
454
456
|
try expect(Type.Bug.precedence() > Type.Poison.precedence());
|
|
455
457
|
|
|
456
458
|
try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
|
|
@@ -7,8 +7,6 @@ const common = @import("../common/data.zig");
|
|
|
7
7
|
const data = @import("data.zig");
|
|
8
8
|
const mechanics = @import("mechanics.zig");
|
|
9
9
|
|
|
10
|
-
const assert = std.debug.assert;
|
|
11
|
-
|
|
12
10
|
const Player = common.Player;
|
|
13
11
|
const Result = common.Result;
|
|
14
12
|
|
|
@@ -42,7 +40,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
42
40
|
var log = options.log;
|
|
43
41
|
|
|
44
42
|
var side = battle.side(player);
|
|
45
|
-
|
|
43
|
+
const volatiles = &side.active.volatiles;
|
|
46
44
|
|
|
47
45
|
const ident = battle.active(player);
|
|
48
46
|
const foe_ident = battle.active(player.foe());
|
|
@@ -175,7 +173,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
175
173
|
if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
|
|
176
174
|
// TODO rampage
|
|
177
175
|
// usedmovetext
|
|
178
|
-
try log.move(ident, state.move, foe_ident); // FIXME self? from?
|
|
176
|
+
try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
|
|
179
177
|
try checkHit(battle, player, state, options);
|
|
180
178
|
try checkCriticalHit(battle, player, state, options);
|
|
181
179
|
try calcDamage(battle, player, state, options);
|
|
@@ -260,7 +258,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
260
258
|
try Effects.hyperBeam(battle, player, state, options);
|
|
261
259
|
_ = try afterMove(!KINGS, battle, player, state, options);
|
|
262
260
|
},
|
|
263
|
-
.Counter => {
|
|
261
|
+
.MirrorCoat, .Counter => {
|
|
264
262
|
if (!try canMove(battle, player, state, options)) return;
|
|
265
263
|
try Effects.counter(battle, player, state, options);
|
|
266
264
|
try applyDamage(battle, player, state, options);
|
|
@@ -344,13 +342,17 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
344
342
|
if (!try canMove(battle, player, state, options)) return;
|
|
345
343
|
try Effects.heal(battle, player, state, options);
|
|
346
344
|
},
|
|
345
|
+
.LightScreen => {
|
|
346
|
+
if (!try canMove(battle, player, state, options)) return;
|
|
347
|
+
try Effects.lightScreen(battle, player, state, options);
|
|
348
|
+
},
|
|
347
349
|
.Haze => {
|
|
348
350
|
if (!try canMove(battle, player, state, options)) return;
|
|
349
351
|
try Effects.haze(battle, player, state, options);
|
|
350
352
|
},
|
|
351
|
-
.
|
|
353
|
+
.Reflect => {
|
|
352
354
|
if (!try canMove(battle, player, state, options)) return;
|
|
353
|
-
try Effects.
|
|
355
|
+
try Effects.reflect(battle, player, state, options);
|
|
354
356
|
},
|
|
355
357
|
.FocusEnergy => {
|
|
356
358
|
if (!try canMove(battle, player, state, options)) return;
|
|
@@ -364,7 +366,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
364
366
|
(volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
|
|
365
367
|
if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
|
|
366
368
|
// usedmovetext
|
|
367
|
-
try log.move(ident, state.move, foe_ident); // FIXME self? from?
|
|
369
|
+
try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
|
|
368
370
|
try Effects.bide.unleash(battle, player, state, options);
|
|
369
371
|
|
|
370
372
|
if (state.immune()) {
|
|
@@ -544,19 +546,19 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
544
546
|
try Effects.sandstorm(battle, player, state, options);
|
|
545
547
|
},
|
|
546
548
|
.Rollout => {
|
|
547
|
-
|
|
549
|
+
try Effects.rollout.check(battle, player, state, options);
|
|
548
550
|
// doturn
|
|
549
551
|
const charging = false; // TODO
|
|
550
552
|
const skip_pp = charging or state.move == .Struggle or
|
|
551
553
|
(volatiles.BeatUp or volatiles.Thrashing or volatiles.Bide);
|
|
552
554
|
if (!skip_pp) _ = decrementPP(side, state.move, state.mslot); // TODO if no pp return
|
|
553
555
|
// usedmovetext
|
|
554
|
-
try log.move(ident, state.move, foe_ident); // FIXME self? from?
|
|
556
|
+
try log.move(.{ ident, state.move, foe_ident }); // FIXME self? from?
|
|
555
557
|
try checkCriticalHit(battle, player, state, options);
|
|
556
558
|
try calcDamage(battle, player, state, options);
|
|
557
559
|
try adjustDamage(battle, player, state, options);
|
|
558
560
|
try checkHit(battle, player, state, options);
|
|
559
|
-
|
|
561
|
+
try Effects.rollout.power(battle, player, state, options);
|
|
560
562
|
try randomizeDamage(battle, player, state, options);
|
|
561
563
|
try applyDamage(battle, player, state, options);
|
|
562
564
|
try reportOutcome(battle, player, state, options);
|
|
@@ -577,12 +579,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
577
579
|
.Swagger => {
|
|
578
580
|
if (!try canMove(battle, player, state, options)) return;
|
|
579
581
|
try checkHit(battle, player, state, options);
|
|
580
|
-
|
|
581
|
-
// TODO attackup2
|
|
582
|
-
// TODO switchturn
|
|
583
|
-
// TODO failuretext
|
|
584
|
-
// TODO switchturn
|
|
585
|
-
// TODO switchturn
|
|
582
|
+
try Effects.boost(battle, player.foe(), state, options);
|
|
586
583
|
try Effects.confusionChance(battle, player, state, options);
|
|
587
584
|
},
|
|
588
585
|
.FuryCutter => {
|
|
@@ -656,7 +653,7 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
656
653
|
.Magnitude => {
|
|
657
654
|
if (!try canMove(battle, player, state, options)) return;
|
|
658
655
|
try checkCriticalHit(battle, player, state, options);
|
|
659
|
-
|
|
656
|
+
try Effects.magnitude(battle, player, state, options);
|
|
660
657
|
try calcDamage(battle, player, state, options);
|
|
661
658
|
try adjustDamage(battle, player, state, options);
|
|
662
659
|
try randomizeDamage(battle, player, state, options);
|
|
@@ -731,12 +728,6 @@ pub fn runMove(battle: anytype, player: Player, state: *State, options: anytype)
|
|
|
731
728
|
if (!try canMove(battle, player, state, options)) return;
|
|
732
729
|
try Effects.sunnyDay(battle, player, state, options);
|
|
733
730
|
},
|
|
734
|
-
.MirrorCoat => {
|
|
735
|
-
if (!try canMove(battle, player, state, options)) return;
|
|
736
|
-
try Effects.mirrorCoat(battle, player, state, options);
|
|
737
|
-
try applyDamage(battle, player, state, options);
|
|
738
|
-
_ = try afterMove(KINGS, battle, player, state, options);
|
|
739
|
-
},
|
|
740
731
|
.PsychUp => {
|
|
741
732
|
if (!try canMove(battle, player, state, options)) return;
|
|
742
733
|
try Effects.psychUp(battle, player, state, options);
|
package/src/lib/gen2/helpers.zig
CHANGED
|
@@ -65,17 +65,47 @@ pub const Battle = struct {
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
pub fn prng(rand: *PSRNG) data.PRNG {
|
|
68
|
-
// FIXME: what is max range in gen2?
|
|
69
68
|
return .{
|
|
70
69
|
.src = .{
|
|
71
70
|
.seed = if (showdown)
|
|
72
71
|
rand.newSeed()
|
|
73
|
-
else
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
else seed: {
|
|
73
|
+
// GLITCH: The initial RNG seed in Gen II link battles is heavily constrained
|
|
74
|
+
// https://www.smogon.com/forums/threads/rng-in-rby-link-battles.3746779
|
|
75
|
+
var seed = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
76
|
+
|
|
77
|
+
// Bytes in seed can only range from 0-252, not 0-255
|
|
78
|
+
const max: u8 = 253;
|
|
79
|
+
// Instructions take multiples of 4 cycles to execute
|
|
80
|
+
var timer: u16 = 4 * rand.range(u16, 0, 16384);
|
|
81
|
+
var add: u8 = rand.range(u8, 0, 256);
|
|
82
|
+
var sub: u8 = rand.range(u8, 0, 256);
|
|
83
|
+
var carry: u8 = 0;
|
|
84
|
+
var div: u8 = 0;
|
|
85
|
+
|
|
86
|
+
var i: u8 = 0;
|
|
87
|
+
while (i < seed.len) {
|
|
88
|
+
div = @intCast(timer >> 8);
|
|
89
|
+
// This is effectively @addWithOverflow but with three operands
|
|
90
|
+
const result = @as(u16, add) + @as(u16, div) + @as(u16, carry);
|
|
91
|
+
add = @intCast(result & 255);
|
|
92
|
+
carry = @intFromBool(result > 255);
|
|
93
|
+
timer +%= 44;
|
|
94
|
+
div = @intCast(timer >> 8);
|
|
95
|
+
sub -%= div +% carry;
|
|
96
|
+
|
|
97
|
+
if (sub < max) {
|
|
98
|
+
seed[i] = sub;
|
|
99
|
+
i += 1;
|
|
100
|
+
timer +%= 152;
|
|
101
|
+
carry = 1;
|
|
102
|
+
} else {
|
|
103
|
+
timer +%= 132;
|
|
104
|
+
carry = 0;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
break :seed seed;
|
|
108
|
+
},
|
|
79
109
|
},
|
|
80
110
|
};
|
|
81
111
|
}
|