@pkmn/engine 0.1.0-dev.a0167a9d → 0.1.0-dev.a0447192
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 +4 -2
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +43 -0
- package/build/pkg/addon/browser.js.map +1 -0
- package/build/pkg/addon/node.d.ts +3 -0
- package/build/pkg/addon/node.js +96 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon.d.ts +2 -0
- package/build/pkg/addon.js +29 -51
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +23 -1
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +1 -1
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +22 -9
- package/build/pkg/index.js +15 -10
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +20 -1
- package/build/pkg/protocol.js +105 -103
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +35 -68
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +141 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +132 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +349 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +18 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +199 -66
- package/package.json +46 -29
- package/src/bin/install-pkmn-engine +7 -5
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/debug.zig +39 -8
- package/src/lib/common/js.zig +4 -2
- package/src/lib/common/optional.zig +13 -9
- package/src/lib/common/options.zig +2 -0
- package/src/lib/common/protocol.zig +41 -36
- package/src/lib/common/rational.zig +53 -51
- package/src/lib/common/rng.zig +4 -4
- package/src/lib/common/util.zig +50 -1
- package/src/lib/gen1/calc.zig +508 -127
- package/src/lib/gen1/chance.zig +316 -173
- package/src/lib/gen1/data.zig +28 -27
- package/src/lib/gen1/helpers.zig +15 -450
- package/src/lib/gen1/mechanics.zig +216 -145
- package/src/lib/gen2/calc.zig +34 -16
- package/src/lib/gen2/chance.zig +90 -592
- package/src/lib/gen2/data.zig +15 -14
- package/src/lib/gen2/helpers.zig +4 -6
- package/src/lib/gen2/mechanics.zig +47 -77
- package/src/lib/pkmn.zig +7 -5
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +359 -0
- package/build/test/display.js +0 -400
- package/build/test/display.js.map +0 -1
- package/src/test/display/pkmn.html.tmpl +0 -368
package/src/lib/gen2/data.zig
CHANGED
|
@@ -45,6 +45,7 @@ const Player = data.Player;
|
|
|
45
45
|
const Result = data.Result;
|
|
46
46
|
|
|
47
47
|
const PointerType = util.PointerType;
|
|
48
|
+
const isPointerTo = util.isPointerTo;
|
|
48
49
|
|
|
49
50
|
const showdown = pkmn.options.showdown;
|
|
50
51
|
|
|
@@ -63,12 +64,12 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
63
64
|
_: [padding]u8 = .{0} ** padding,
|
|
64
65
|
|
|
65
66
|
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
66
|
-
assert(
|
|
67
|
+
assert(isPointerTo(self, Self));
|
|
67
68
|
return &self.sides[@intFromEnum(player)];
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
71
|
-
assert(
|
|
72
|
+
assert(isPointerTo(self, Self));
|
|
72
73
|
return &self.sides[@intFromEnum(player.foe())];
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -134,7 +135,7 @@ pub const Side = extern struct {
|
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
137
|
-
assert(
|
|
138
|
+
assert(isPointerTo(self, Side));
|
|
138
139
|
assert(slot > 0 and slot <= 6);
|
|
139
140
|
const id = self.pokemon[slot - 1].position;
|
|
140
141
|
assert(id > 0 and id <= 6);
|
|
@@ -142,7 +143,7 @@ pub const Side = extern struct {
|
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
145
|
-
assert(
|
|
146
|
+
assert(isPointerTo(self, Side));
|
|
146
147
|
return self.get(1);
|
|
147
148
|
}
|
|
148
149
|
|
|
@@ -176,7 +177,7 @@ pub const ActivePokemon = extern struct {
|
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
179
|
-
assert(
|
|
180
|
+
assert(isPointerTo(self, Pokemon));
|
|
180
181
|
assert(mslot > 0 and mslot <= 4);
|
|
181
182
|
assert(self.moves[mslot - 1].id != .None);
|
|
182
183
|
return &self.moves[mslot - 1];
|
|
@@ -201,7 +202,7 @@ pub const Pokemon = extern struct {
|
|
|
201
202
|
}
|
|
202
203
|
|
|
203
204
|
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
204
|
-
assert(
|
|
205
|
+
assert(isPointerTo(self, Pokemon));
|
|
205
206
|
assert(mslot > 0 and mslot <= 4);
|
|
206
207
|
assert(self.moves[mslot - 1].id != .None);
|
|
207
208
|
return &self.moves[mslot - 1];
|
|
@@ -248,12 +249,12 @@ test DVs {
|
|
|
248
249
|
var dvs = DVs.from(.Mewtwo, .{ .def = 13 });
|
|
249
250
|
try expectEqual(Gender.Unknown, dvs.gender);
|
|
250
251
|
try expectEqual(Type.Ice, dvs.type);
|
|
251
|
-
try expectEqual(70, dvs.power());
|
|
252
|
+
try expectEqual(@as(u8, 70), dvs.power());
|
|
252
253
|
|
|
253
254
|
dvs = DVs.from(.Pikachu, .{ .spc = 14 });
|
|
254
255
|
try expectEqual(Gender.Male, dvs.gender);
|
|
255
256
|
try expectEqual(Type.Dark, dvs.type);
|
|
256
|
-
try expectEqual(69, dvs.power());
|
|
257
|
+
try expectEqual(@as(u8, 69), dvs.power());
|
|
257
258
|
|
|
258
259
|
dvs = DVs.from(.Cyndaquil, .{ .atk = 1, .def = 3, .spe = 10, .spc = 9 });
|
|
259
260
|
try expectEqual(Gender.Female, dvs.gender);
|
|
@@ -380,9 +381,9 @@ test Stats {
|
|
|
380
381
|
try expectEqual(0, stats.def);
|
|
381
382
|
|
|
382
383
|
var base = Species.get(.Gyarados).stats;
|
|
383
|
-
try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
384
|
+
try expectEqual(@as(u16, 127), Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
384
385
|
base = Species.get(.Pidgeot).stats;
|
|
385
|
-
try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
386
|
+
try expectEqual(@as(u16, 279), Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
386
387
|
}
|
|
387
388
|
|
|
388
389
|
pub const Boosts = packed struct(u32) {
|
|
@@ -428,8 +429,8 @@ test Move {
|
|
|
428
429
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
429
430
|
try expectEqual(rng.Gen12.percent(50), move.accuracy);
|
|
430
431
|
try expectEqual(rng.Gen12.percent(100), move.chance);
|
|
431
|
-
try expectEqual(5, Move.pp(.DynamicPunch));
|
|
432
|
-
try expectEqual(-1, Move.get(.Counter).priority);
|
|
432
|
+
try expectEqual(@as(u8, 5), Move.pp(.DynamicPunch));
|
|
433
|
+
try expectEqual(@as(i8, -1), Move.get(.Counter).priority);
|
|
433
434
|
try expect(!move.effect.isHighCritical());
|
|
434
435
|
try expect(Move.get(.KarateChop).effect.isHighCritical());
|
|
435
436
|
try expect(Move.get(.RazorWind).effect.isHighCritical());
|
|
@@ -439,7 +440,7 @@ pub const Species = species.Species;
|
|
|
439
440
|
|
|
440
441
|
test Species {
|
|
441
442
|
try expectEqual(152, @intFromEnum(Species.Chikorita));
|
|
442
|
-
try expectEqual(100, Species.get(.Celebi).stats.spd);
|
|
443
|
+
try expectEqual(@as(u8, 100), Species.get(.Celebi).stats.spd);
|
|
443
444
|
}
|
|
444
445
|
|
|
445
446
|
pub const Type = types.Type;
|
|
@@ -452,7 +453,7 @@ test Types {
|
|
|
452
453
|
try expect(!Type.Steel.special());
|
|
453
454
|
try expect(Type.Dark.special());
|
|
454
455
|
|
|
455
|
-
try expectEqual(3, Type.Water.precedence());
|
|
456
|
+
try expectEqual(@as(u8, 3), Type.Water.precedence());
|
|
456
457
|
try expect(Type.Bug.precedence() > Type.Poison.precedence());
|
|
457
458
|
|
|
458
459
|
try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
|
package/src/lib/gen2/helpers.zig
CHANGED
|
@@ -2,7 +2,6 @@ const std = @import("std");
|
|
|
2
2
|
|
|
3
3
|
const common = @import("../common/data.zig");
|
|
4
4
|
const options = @import("../common/options.zig");
|
|
5
|
-
const protocol = @import("../common/protocol.zig");
|
|
6
5
|
const rng = @import("../common/rng.zig");
|
|
7
6
|
|
|
8
7
|
const gen1 = @import("../gen1/data.zig");
|
|
@@ -11,8 +10,6 @@ const data = @import("data.zig");
|
|
|
11
10
|
|
|
12
11
|
const assert = std.debug.assert;
|
|
13
12
|
|
|
14
|
-
const expectEqual = std.testing.expectEqual;
|
|
15
|
-
|
|
16
13
|
const Choice = common.Choice;
|
|
17
14
|
|
|
18
15
|
const showdown = options.showdown;
|
|
@@ -25,7 +22,8 @@ const Move = data.Move;
|
|
|
25
22
|
const MoveSlot = data.MoveSlot;
|
|
26
23
|
const Species = data.Species;
|
|
27
24
|
const Stats = data.Stats;
|
|
28
|
-
|
|
25
|
+
|
|
26
|
+
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
29
27
|
|
|
30
28
|
pub const Options = struct {
|
|
31
29
|
cleric: bool = showdown,
|
|
@@ -151,7 +149,7 @@ pub const Pokemon = struct {
|
|
|
151
149
|
var pokemon = data.Pokemon{};
|
|
152
150
|
pokemon.species = p.species;
|
|
153
151
|
const species = Species.get(p.species);
|
|
154
|
-
inline for (@typeInfo(@TypeOf(pokemon.stats))
|
|
152
|
+
inline for (@field(@typeInfo(@TypeOf(pokemon.stats)), @tagName(Struct)).fields) |field| {
|
|
155
153
|
const hp = comptime std.mem.eql(u8, field.name, "hp");
|
|
156
154
|
const spc =
|
|
157
155
|
comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
|
|
@@ -192,7 +190,7 @@ pub const Pokemon = struct {
|
|
|
192
190
|
|
|
193
191
|
var stats: Stats(u16) = .{};
|
|
194
192
|
const dvs = gen1.DVs.random(rand);
|
|
195
|
-
inline for (@typeInfo(@TypeOf(stats))
|
|
193
|
+
inline for (@field(@typeInfo(@TypeOf(stats)), @tagName(Struct)).fields) |field| {
|
|
196
194
|
const hp = std.mem.eql(u8, field.name, "hp");
|
|
197
195
|
const spc = std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
|
|
198
196
|
@field(stats, field.name) = Stats(u16).calc(
|
|
@@ -6,7 +6,6 @@ const common = @import("../common/data.zig");
|
|
|
6
6
|
const DEBUG = @import("../common/debug.zig").print;
|
|
7
7
|
const protocol = @import("../common/protocol.zig");
|
|
8
8
|
const rng = @import("../common/rng.zig");
|
|
9
|
-
const util = @import("../common/util.zig");
|
|
10
9
|
|
|
11
10
|
const data = @import("data.zig");
|
|
12
11
|
const generated = @import("generated.zig");
|
|
@@ -34,17 +33,12 @@ const Start = protocol.Start;
|
|
|
34
33
|
|
|
35
34
|
const Gen12 = rng.Gen12;
|
|
36
35
|
|
|
37
|
-
const PointerType = util.PointerType;
|
|
38
|
-
|
|
39
36
|
const ActivePokemon = data.ActivePokemon;
|
|
40
37
|
const Boosts = data.Boosts;
|
|
41
38
|
const Effectiveness = data.Effectiveness;
|
|
42
39
|
const Item = data.Item;
|
|
43
40
|
const Move = data.Move;
|
|
44
|
-
const MoveSlot = data.MoveSlot;
|
|
45
|
-
const Pokemon = data.Pokemon;
|
|
46
41
|
const Side = data.Side;
|
|
47
|
-
const Species = data.Species;
|
|
48
42
|
const Stats = data.Stats;
|
|
49
43
|
const Status = data.Status;
|
|
50
44
|
const TriAttack = data.TriAttack;
|
|
@@ -106,6 +100,7 @@ pub const State = struct {
|
|
|
106
100
|
type: Type, // BATTLE_VARS_MOVE_TYPE
|
|
107
101
|
accuracy: u8, // wEnemyMoveStruct + MOVE_ACC
|
|
108
102
|
move: Move, // wCurPlayerMove
|
|
103
|
+
hit: u3 = 0,
|
|
109
104
|
from: Move = .None,
|
|
110
105
|
mslot: u4, // wCurMoveNum
|
|
111
106
|
first: bool, // wEnemyGoesFirst
|
|
@@ -256,7 +251,6 @@ fn switchIn(battle: anytype, player: Player, slot: u8, kind: SwitchIn, options:
|
|
|
256
251
|
} else {
|
|
257
252
|
try options.log.switched(.{ battle.active(player), incoming });
|
|
258
253
|
}
|
|
259
|
-
options.chance.switched(player, side.pokemon[0].position, out);
|
|
260
254
|
|
|
261
255
|
if (side.conditions.Spikes and !active.types.includes(.Flying)) {
|
|
262
256
|
incoming.hp -|= @max(incoming.stats.hp / 8, 1);
|
|
@@ -442,18 +436,9 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
442
436
|
if (Status.is(stored.status, .SLP)) slp: {
|
|
443
437
|
const before = stored.status;
|
|
444
438
|
// Even if the EXT bit is set this will still correctly modify the sleep duration
|
|
445
|
-
// if (options.calc.modify(player, .sleep)) |extend| {
|
|
446
|
-
// if (!extend) stored.status = 0;
|
|
447
|
-
// } else {
|
|
448
439
|
stored.status -= 1;
|
|
449
|
-
// }
|
|
450
440
|
|
|
451
|
-
|
|
452
|
-
if (!Status.is(stored.status, .EXT)) {
|
|
453
|
-
try options.chance.sleep(player, duration);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (duration == 0) {
|
|
441
|
+
if (Status.duration(stored.status) == 0) {
|
|
457
442
|
try log.curestatus(.{ ident, before, .Message });
|
|
458
443
|
stored.status = 0; // clears EXT if present
|
|
459
444
|
resetCant(volatiles);
|
|
@@ -483,12 +468,7 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
483
468
|
}
|
|
484
469
|
|
|
485
470
|
if (volatiles.disable.duration > 0) {
|
|
486
|
-
// if (options.calc.modify(player, .disable)) |extend| {
|
|
487
|
-
// if (!extend) volatiles.disable.duration = 0;
|
|
488
|
-
// } else {
|
|
489
471
|
volatiles.disable.duration -= 1;
|
|
490
|
-
// }
|
|
491
|
-
try options.chance.disable(player, volatiles.disable.duration);
|
|
492
472
|
|
|
493
473
|
if (volatiles.disable.duration == 0) {
|
|
494
474
|
volatiles.disable.move = 0;
|
|
@@ -498,13 +478,7 @@ fn beforeMove(battle: anytype, player: Player, move: Move, options: anytype) !bo
|
|
|
498
478
|
|
|
499
479
|
if (volatiles.Confusion) {
|
|
500
480
|
assert(volatiles.confusion > 0);
|
|
501
|
-
|
|
502
|
-
// if (options.calc.modify(player, .confusion)) |extend| {
|
|
503
|
-
// if (!extend) volatiles.confusion = 0;
|
|
504
|
-
// } else {
|
|
505
481
|
volatiles.confusion -= 1;
|
|
506
|
-
// }
|
|
507
|
-
try options.chance.confusion(player, volatiles.confusion);
|
|
508
482
|
|
|
509
483
|
if (volatiles.confusion == 0) {
|
|
510
484
|
volatiles.Confusion = false;
|
|
@@ -665,7 +639,7 @@ pub fn checkCriticalHit(battle: anytype, player: Player, state: *State, options:
|
|
|
665
639
|
}
|
|
666
640
|
assert(stage <= 4);
|
|
667
641
|
|
|
668
|
-
state.crit = try Rolls.criticalHit(battle, player, CRITICAL_HITS[stage], options);
|
|
642
|
+
state.crit = try Rolls.criticalHit(battle, player, state.hit, CRITICAL_HITS[stage], options);
|
|
669
643
|
}
|
|
670
644
|
|
|
671
645
|
pub fn calcDamage(
|
|
@@ -733,7 +707,7 @@ pub fn adjustDamage(battle: anytype, player: Player, state: *State, _: anytype)
|
|
|
733
707
|
|
|
734
708
|
pub fn randomizeDamage(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
735
709
|
if (state.damage <= 1) return;
|
|
736
|
-
const random = try Rolls.damage(battle, player, options);
|
|
710
|
+
const random = try Rolls.damage(battle, player, state.hit, options);
|
|
737
711
|
options.calc.base(player.foe(), state.damage);
|
|
738
712
|
state.damage = @intCast(@as(u32, state.damage) *% random / 255);
|
|
739
713
|
options.calc.final(player.foe(), state.damage);
|
|
@@ -1341,13 +1315,7 @@ pub const Effects = struct {
|
|
|
1341
1315
|
|
|
1342
1316
|
if (!volatiles.Bide) return;
|
|
1343
1317
|
|
|
1344
|
-
// if (options.calc.modify(player, .attacking)) |extend| {
|
|
1345
|
-
// if (!extend) volatiles.attacks = 0;
|
|
1346
|
-
// } else {
|
|
1347
1318
|
volatiles.attacks -= 1;
|
|
1348
|
-
// }
|
|
1349
|
-
try options.chance.attacking(player, volatiles.attacks);
|
|
1350
|
-
|
|
1351
1319
|
if (volatiles.attacks != 0) return options.log.activate(.{ ident, .Bide });
|
|
1352
1320
|
|
|
1353
1321
|
volatiles.Bide = false;
|
|
@@ -2876,7 +2844,7 @@ fn convertible(active: ActivePokemon, m: Move) bool {
|
|
|
2876
2844
|
|
|
2877
2845
|
pub const Rolls = struct {
|
|
2878
2846
|
fn speedTie(battle: anytype, options: anytype) !bool {
|
|
2879
|
-
const p1 = if (options.calc.overridden(.P1, .speed_tie)) |player|
|
|
2847
|
+
const p1 = if (options.calc.overridden(.P1, 0, .speed_tie)) |player|
|
|
2880
2848
|
player == .P1
|
|
2881
2849
|
else if (showdown)
|
|
2882
2850
|
battle.rng.range(u8, 0, 2) == 0
|
|
@@ -2888,7 +2856,7 @@ pub const Rolls = struct {
|
|
|
2888
2856
|
}
|
|
2889
2857
|
|
|
2890
2858
|
fn quickClaw(battle: anytype, player: Player, options: anytype) !bool {
|
|
2891
|
-
const qkc = if (options.calc.overridden(player, .quick_claw)) |val|
|
|
2859
|
+
const qkc = if (options.calc.overridden(player, 0, .quick_claw)) |val|
|
|
2892
2860
|
val == .true
|
|
2893
2861
|
else if (showdown)
|
|
2894
2862
|
battle.rng.chance(u8, 60, 256)
|
|
@@ -2900,7 +2868,7 @@ pub const Rolls = struct {
|
|
|
2900
2868
|
}
|
|
2901
2869
|
|
|
2902
2870
|
fn hit(battle: anytype, player: Player, accuracy: u8, options: anytype) !bool {
|
|
2903
|
-
const ok = if (options.calc.overridden(player, .hit)) |val|
|
|
2871
|
+
const ok = if (options.calc.overridden(player, 0, .hit)) |val|
|
|
2904
2872
|
val == .true
|
|
2905
2873
|
else if (showdown)
|
|
2906
2874
|
battle.rng.chance(u8, accuracy, 256)
|
|
@@ -2911,20 +2879,22 @@ pub const Rolls = struct {
|
|
|
2911
2879
|
return ok;
|
|
2912
2880
|
}
|
|
2913
2881
|
|
|
2914
|
-
fn criticalHit(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
|
|
2915
|
-
|
|
2882
|
+
fn criticalHit(battle: anytype, player: Player, i: u3, rate: u8, options: anytype) !bool {
|
|
2883
|
+
_ = .{ player, options };
|
|
2884
|
+
const crit = if (options.calc.overridden(player, i, .critical_hits)) |val|
|
|
2916
2885
|
val == .true
|
|
2917
2886
|
else if (showdown)
|
|
2918
2887
|
battle.rng.chance(u8, rate, 256)
|
|
2919
2888
|
else
|
|
2920
2889
|
battle.rng.next() < rate;
|
|
2921
2890
|
|
|
2922
|
-
try options.chance.criticalHit(player, crit, rate);
|
|
2891
|
+
try options.chance.criticalHit(player, i, crit, rate);
|
|
2923
2892
|
return crit;
|
|
2924
2893
|
}
|
|
2925
2894
|
|
|
2926
|
-
fn damage(battle: anytype, player: Player, options: anytype) !u8 {
|
|
2927
|
-
|
|
2895
|
+
fn damage(battle: anytype, player: Player, i: u3, options: anytype) !u8 {
|
|
2896
|
+
_ = .{ player, options };
|
|
2897
|
+
const roll = if (options.calc.overridden(player, i, .damages)) |val|
|
|
2928
2898
|
val
|
|
2929
2899
|
else roll: {
|
|
2930
2900
|
if (showdown) break :roll battle.rng.range(u8, 217, 256);
|
|
@@ -2935,12 +2905,12 @@ pub const Rolls = struct {
|
|
|
2935
2905
|
};
|
|
2936
2906
|
|
|
2937
2907
|
assert(roll >= 217 and roll <= 255);
|
|
2938
|
-
try options.chance.damage(player, roll);
|
|
2908
|
+
try options.chance.damage(player, i, roll);
|
|
2939
2909
|
return roll;
|
|
2940
2910
|
}
|
|
2941
2911
|
|
|
2942
2912
|
fn confused(battle: anytype, player: Player, options: anytype) !bool {
|
|
2943
|
-
const cfz = if (options.calc.overridden(player, .confused)) |val|
|
|
2913
|
+
const cfz = if (options.calc.overridden(player, 0, .confused)) |val|
|
|
2944
2914
|
val == .true
|
|
2945
2915
|
else if (showdown)
|
|
2946
2916
|
!battle.rng.chance(u8, 128, 256)
|
|
@@ -2952,7 +2922,7 @@ pub const Rolls = struct {
|
|
|
2952
2922
|
}
|
|
2953
2923
|
|
|
2954
2924
|
fn attract(battle: anytype, player: Player, options: anytype) !bool {
|
|
2955
|
-
const cant = if (options.calc.overridden(player, .attract)) |val|
|
|
2925
|
+
const cant = if (options.calc.overridden(player, 0, .attract)) |val|
|
|
2956
2926
|
val == .true
|
|
2957
2927
|
else if (showdown)
|
|
2958
2928
|
battle.rng.chance(u8, 1, 2)
|
|
@@ -2964,7 +2934,7 @@ pub const Rolls = struct {
|
|
|
2964
2934
|
}
|
|
2965
2935
|
|
|
2966
2936
|
fn paralyzed(battle: anytype, player: Player, options: anytype) !bool {
|
|
2967
|
-
const par = if (options.calc.overridden(player, .paralyzed)) |val|
|
|
2937
|
+
const par = if (options.calc.overridden(player, 0, .paralyzed)) |val|
|
|
2968
2938
|
val == .true
|
|
2969
2939
|
else if (showdown)
|
|
2970
2940
|
battle.rng.chance(u8, 63, 256)
|
|
@@ -2976,7 +2946,7 @@ pub const Rolls = struct {
|
|
|
2976
2946
|
}
|
|
2977
2947
|
|
|
2978
2948
|
fn defrost(battle: anytype, player: Player, options: anytype) !bool {
|
|
2979
|
-
const thaw = if (options.calc.overridden(player, .defrost)) |val|
|
|
2949
|
+
const thaw = if (options.calc.overridden(player, 0, .defrost)) |val|
|
|
2980
2950
|
val == .true
|
|
2981
2951
|
else if (showdown)
|
|
2982
2952
|
battle.rng.chance(u8, 25, 256)
|
|
@@ -2989,7 +2959,7 @@ pub const Rolls = struct {
|
|
|
2989
2959
|
|
|
2990
2960
|
fn secondaryChance(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
|
|
2991
2961
|
// GLITCH: 100% secondary chance will still fail 1/256 of the time
|
|
2992
|
-
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2962
|
+
const proc = if (options.calc.overridden(player, 0, .secondary_chance)) |val|
|
|
2993
2963
|
val == .true
|
|
2994
2964
|
else if (showdown)
|
|
2995
2965
|
battle.rng.chance(u8, rate, 256)
|
|
@@ -3001,7 +2971,7 @@ pub const Rolls = struct {
|
|
|
3001
2971
|
}
|
|
3002
2972
|
|
|
3003
2973
|
fn item(battle: anytype, player: Player, options: anytype) !bool {
|
|
3004
|
-
const proc = if (options.calc.overridden(player, .item)) |val|
|
|
2974
|
+
const proc = if (options.calc.overridden(player, 0, .item)) |val|
|
|
3005
2975
|
val == .true
|
|
3006
2976
|
else if (showdown)
|
|
3007
2977
|
battle.rng.chance(u8, 30, 256)
|
|
@@ -3013,7 +2983,7 @@ pub const Rolls = struct {
|
|
|
3013
2983
|
}
|
|
3014
2984
|
|
|
3015
2985
|
fn triAttack(battle: anytype, player: Player, options: anytype) !TriAttack {
|
|
3016
|
-
const status: TriAttack = if (options.calc.overridden(player, .tri_attack)) |val|
|
|
2986
|
+
const status: TriAttack = if (options.calc.overridden(player, 0, .tri_attack)) |val|
|
|
3017
2987
|
@enumFromInt(@intFromEnum(val) - 1)
|
|
3018
2988
|
else if (showdown)
|
|
3019
2989
|
@enumFromInt(battle.rng.range(u2, 0, 2))
|
|
@@ -3029,7 +2999,7 @@ pub const Rolls = struct {
|
|
|
3029
2999
|
}
|
|
3030
3000
|
|
|
3031
3001
|
fn present(battle: anytype, player: Player, options: anytype) !u8 {
|
|
3032
|
-
const power = if (options.calc.overridden(player, .present)) |val|
|
|
3002
|
+
const power = if (options.calc.overridden(player, 0, .present)) |val|
|
|
3033
3003
|
(val - 1) * 40
|
|
3034
3004
|
else if (showdown) power: {
|
|
3035
3005
|
const r = battle.rng.range(u8, 0, 10);
|
|
@@ -3051,7 +3021,7 @@ pub const Rolls = struct {
|
|
|
3051
3021
|
}
|
|
3052
3022
|
|
|
3053
3023
|
fn magnitude(battle: anytype, player: Player, options: anytype) !u8 {
|
|
3054
|
-
const num: u8 = if (options.calc.overridden(player, .magnitude)) |val|
|
|
3024
|
+
const num: u8 = if (options.calc.overridden(player, 0, .magnitude)) |val|
|
|
3055
3025
|
val + 3
|
|
3056
3026
|
else if (showdown) num: {
|
|
3057
3027
|
const r = battle.rng.range(u8, 0, 100);
|
|
@@ -3079,7 +3049,7 @@ pub const Rolls = struct {
|
|
|
3079
3049
|
}
|
|
3080
3050
|
|
|
3081
3051
|
fn tripleKick(battle: anytype, player: Player, options: anytype) !u2 {
|
|
3082
|
-
const hits = if (options.calc.overridden(player, .triple_kick)) |val|
|
|
3052
|
+
const hits = if (options.calc.overridden(player, 0, .triple_kick)) |val|
|
|
3083
3053
|
val
|
|
3084
3054
|
else if (showdown)
|
|
3085
3055
|
battle.rng.range(u2, 1, 4)
|
|
@@ -3097,7 +3067,7 @@ pub const Rolls = struct {
|
|
|
3097
3067
|
|
|
3098
3068
|
fn spite(battle: anytype, player: Player, options: anytype) !u3 {
|
|
3099
3069
|
assert(!showdown);
|
|
3100
|
-
const pp: u3 = if (options.calc.overridden(player, .spite)) |val|
|
|
3070
|
+
const pp: u3 = if (options.calc.overridden(player, 0, .spite)) |val|
|
|
3101
3071
|
val + 1
|
|
3102
3072
|
else
|
|
3103
3073
|
@intCast((battle.rng.next() & 3) + 2);
|
|
@@ -3114,7 +3084,7 @@ pub const Rolls = struct {
|
|
|
3114
3084
|
var i: u8 = 0;
|
|
3115
3085
|
const neutral = @intFromEnum(Effectiveness.Neutral);
|
|
3116
3086
|
assert(mtype != .@"???");
|
|
3117
|
-
const ty: Type = if (options.calc.overridden(player, .conversion_2)) |val|
|
|
3087
|
+
const ty: Type = if (options.calc.overridden(player, 0, .conversion_2)) |val|
|
|
3118
3088
|
@enumFromInt(@intFromEnum(val) - 1)
|
|
3119
3089
|
else if (showdown) ty: {
|
|
3120
3090
|
for (Type.SHOWDOWN) |t| {
|
|
@@ -3148,7 +3118,7 @@ pub const Rolls = struct {
|
|
|
3148
3118
|
assert(count <= 8);
|
|
3149
3119
|
const num = if (count == 8) 0 else @as(u8, 255) >> @intCast(count);
|
|
3150
3120
|
|
|
3151
|
-
const ok = if (options.calc.overridden(player, .protect)) |val|
|
|
3121
|
+
const ok = if (options.calc.overridden(player, 0, .protect)) |val|
|
|
3152
3122
|
val == .true
|
|
3153
3123
|
else if (showdown)
|
|
3154
3124
|
battle.rng.chance(u8, num, 255)
|
|
@@ -3170,7 +3140,7 @@ pub const Rolls = struct {
|
|
|
3170
3140
|
const moves = active.moves;
|
|
3171
3141
|
|
|
3172
3142
|
// TODO: consider throwing error instead of rerolling?
|
|
3173
|
-
const overridden = if (options.calc.overridden(player, .move_slot)) |val|
|
|
3143
|
+
const overridden = if (options.calc.overridden(player, 0, .move_slot)) |val|
|
|
3174
3144
|
if (convertible(active, moves[val - 1].id)) val else null
|
|
3175
3145
|
else
|
|
3176
3146
|
null;
|
|
@@ -3207,7 +3177,7 @@ pub const Rolls = struct {
|
|
|
3207
3177
|
const moves = active.moves;
|
|
3208
3178
|
|
|
3209
3179
|
// TODO: consider throwing error instead of rerolling?
|
|
3210
|
-
const overridden = if (options.calc.overridden(player, .move_slot)) |val|
|
|
3180
|
+
const overridden = if (options.calc.overridden(player, 0, .move_slot)) |val|
|
|
3211
3181
|
if (val != mslot and Move.get(moves[val - 1].id).extra.sleep_talk) val else null
|
|
3212
3182
|
else
|
|
3213
3183
|
null;
|
|
@@ -3251,7 +3221,7 @@ pub const Rolls = struct {
|
|
|
3251
3221
|
assert(n > 0 and n <= 6);
|
|
3252
3222
|
|
|
3253
3223
|
// TODO: consider throwing error instead of rerolling?
|
|
3254
|
-
const overridden = if (options.calc.overridden(player, .force_switch)) |val| val: {
|
|
3224
|
+
const overridden = if (options.calc.overridden(player, 0, .force_switch)) |val| val: {
|
|
3255
3225
|
for (slots) |slot| if (slot == val) break :val if (foe.get(slot).hp > 0) val else null;
|
|
3256
3226
|
break :val null;
|
|
3257
3227
|
} else null;
|
|
@@ -3277,7 +3247,7 @@ pub const Rolls = struct {
|
|
|
3277
3247
|
const DISTRIBUTION = [_]u3{ 2, 2, 2, 3, 3, 3, 4, 5 };
|
|
3278
3248
|
|
|
3279
3249
|
fn multiHit(battle: anytype, player: Player, options: anytype) !u3 {
|
|
3280
|
-
const n: u3 = if (options.calc.overridden(player, .multi_hit)) |val|
|
|
3250
|
+
const n: u3 = if (options.calc.overridden(player, 0, .multi_hit)) |val|
|
|
3281
3251
|
@intCast(val)
|
|
3282
3252
|
else if (showdown)
|
|
3283
3253
|
DISTRIBUTION[battle.rng.range(u3, 0, DISTRIBUTION.len)]
|
|
@@ -3292,7 +3262,7 @@ pub const Rolls = struct {
|
|
|
3292
3262
|
}
|
|
3293
3263
|
|
|
3294
3264
|
fn psywave(battle: anytype, player: Player, max: u8, options: anytype) !u8 {
|
|
3295
|
-
const power = if (options.calc.overridden(player, .psywave)) |val|
|
|
3265
|
+
const power = if (options.calc.overridden(player, 0, .psywave)) |val|
|
|
3296
3266
|
val
|
|
3297
3267
|
else if (showdown)
|
|
3298
3268
|
battle.rng.range(u8, 1, max)
|
|
@@ -3318,7 +3288,7 @@ pub const Rolls = struct {
|
|
|
3318
3288
|
}
|
|
3319
3289
|
|
|
3320
3290
|
// TODO: consider throwing error instead of rerolling?
|
|
3321
|
-
const overridden = if (options.calc.overridden(player, .metronome)) |val| val: {
|
|
3291
|
+
const overridden = if (options.calc.overridden(player, 0, .metronome)) |val| val: {
|
|
3322
3292
|
for (moves) |m| if (m.id == val) break :val null;
|
|
3323
3293
|
break :val val;
|
|
3324
3294
|
} else null;
|
|
@@ -3350,7 +3320,7 @@ pub const Rolls = struct {
|
|
|
3350
3320
|
}
|
|
3351
3321
|
|
|
3352
3322
|
fn sleepDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
3353
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
3323
|
+
const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3354
3324
|
@intCast(val)
|
|
3355
3325
|
else if (showdown)
|
|
3356
3326
|
battle.rng.range(u3, 1, 7)
|
|
@@ -3362,12 +3332,12 @@ pub const Rolls = struct {
|
|
|
3362
3332
|
};
|
|
3363
3333
|
|
|
3364
3334
|
assert(duration >= 1 and duration <= 6);
|
|
3365
|
-
options.chance.duration(
|
|
3335
|
+
options.chance.duration(player, duration);
|
|
3366
3336
|
return duration + 1;
|
|
3367
3337
|
}
|
|
3368
3338
|
|
|
3369
3339
|
fn confusionDuration(battle: anytype, player: Player, self: bool, options: anytype) u3 {
|
|
3370
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
3340
|
+
const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3371
3341
|
@intCast(val)
|
|
3372
3342
|
else if (showdown)
|
|
3373
3343
|
// Pokémon Showdown incorrectly uses the same duration for self-confusion
|
|
@@ -3376,16 +3346,16 @@ pub const Rolls = struct {
|
|
|
3376
3346
|
@intCast((battle.rng.next() & if (self) 1 else 3) + 2);
|
|
3377
3347
|
|
|
3378
3348
|
assert(duration >= 2 and duration <= if (!showdown and self) 3 else 5);
|
|
3379
|
-
options.chance.duration(
|
|
3349
|
+
options.chance.duration(player, duration);
|
|
3380
3350
|
return duration;
|
|
3381
3351
|
}
|
|
3382
3352
|
|
|
3383
3353
|
fn disableDuration(battle: anytype, player: Player, options: anytype) u4 {
|
|
3384
|
-
const duration:
|
|
3354
|
+
const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3385
3355
|
@intCast(val)
|
|
3386
3356
|
else if (showdown)
|
|
3387
3357
|
// Pokémon Showdown incorrectly inherits Generation III's Disable duration
|
|
3388
|
-
battle.rng.range(
|
|
3358
|
+
battle.rng.range(u3, 2, 6)
|
|
3389
3359
|
else duration: {
|
|
3390
3360
|
while (true) {
|
|
3391
3361
|
const r = battle.rng.next() & 7;
|
|
@@ -3394,12 +3364,12 @@ pub const Rolls = struct {
|
|
|
3394
3364
|
};
|
|
3395
3365
|
|
|
3396
3366
|
assert(duration >= 2 and duration <= (if (showdown) 5 else 7));
|
|
3397
|
-
options.chance.duration(
|
|
3367
|
+
options.chance.duration(player, duration);
|
|
3398
3368
|
return duration;
|
|
3399
3369
|
}
|
|
3400
3370
|
|
|
3401
3371
|
fn attackingDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
3402
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
3372
|
+
const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3403
3373
|
@intCast(val)
|
|
3404
3374
|
else if (showdown)
|
|
3405
3375
|
battle.rng.range(u3, 2, 4)
|
|
@@ -3407,12 +3377,12 @@ pub const Rolls = struct {
|
|
|
3407
3377
|
@intCast((battle.rng.next() & 1) + 2); // BUG: thrash is + 1 not +2
|
|
3408
3378
|
|
|
3409
3379
|
assert(duration >= 2 and duration <= 3);
|
|
3410
|
-
options.chance.duration(
|
|
3380
|
+
options.chance.duration(player, duration);
|
|
3411
3381
|
return duration;
|
|
3412
3382
|
}
|
|
3413
3383
|
|
|
3414
3384
|
fn bindingDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
3415
|
-
const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
|
|
3385
|
+
const duration: u3 = (if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3416
3386
|
@intCast(val)
|
|
3417
3387
|
else if (showdown)
|
|
3418
3388
|
// TODO: PS does range(3, 6) here which after subtracting 1 is actually 2-4 not 2-5!
|
|
@@ -3421,13 +3391,13 @@ pub const Rolls = struct {
|
|
|
3421
3391
|
@intCast(battle.rng.next() & 3 + 2));
|
|
3422
3392
|
|
|
3423
3393
|
assert(duration >= 2 and duration <= 5);
|
|
3424
|
-
options.chance.duration(
|
|
3394
|
+
options.chance.duration(player, duration);
|
|
3425
3395
|
return duration + 1;
|
|
3426
3396
|
}
|
|
3427
3397
|
|
|
3428
3398
|
// TODO: consider sharing implementation with bindingDuration
|
|
3429
3399
|
fn encoreDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
3430
|
-
const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
|
|
3400
|
+
const duration: u3 = (if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3431
3401
|
@intCast(val)
|
|
3432
3402
|
else if (showdown)
|
|
3433
3403
|
battle.rng.range(u3, 2, 6)
|
|
@@ -3435,7 +3405,7 @@ pub const Rolls = struct {
|
|
|
3435
3405
|
@intCast(battle.rng.next() & 3 + 2));
|
|
3436
3406
|
|
|
3437
3407
|
assert(duration >= 2 and duration <= 5);
|
|
3438
|
-
options.chance.duration(
|
|
3408
|
+
options.chance.duration(player, duration);
|
|
3439
3409
|
return duration + 1;
|
|
3440
3410
|
}
|
|
3441
3411
|
};
|
package/src/lib/pkmn.zig
CHANGED
|
@@ -22,6 +22,11 @@ pub const Choice = @import("common/data.zig").Choice;
|
|
|
22
22
|
/// considered terminal.
|
|
23
23
|
pub const Result = @import("common/data.zig").Result;
|
|
24
24
|
|
|
25
|
+
// TODO
|
|
26
|
+
pub const Array = @import("common/array.zig").Array;
|
|
27
|
+
// TODO
|
|
28
|
+
pub const Optional = @import("common/optional.zig").Optional;
|
|
29
|
+
|
|
25
30
|
/// Pokémon Showdown's RNG (backed by a Generation V & VI RNG).
|
|
26
31
|
pub const PSRNG = @import("common/rng.zig").PSRNG;
|
|
27
32
|
|
|
@@ -81,8 +86,6 @@ pub const gen1 = struct {
|
|
|
81
86
|
pub const Calc = @import("gen1/calc.zig").Calc;
|
|
82
87
|
/// Namespace for types associated with supported Generation I Pokémon damage calc features.
|
|
83
88
|
pub const calc = if (options.internal) @import("gen1/calc.zig") else struct {
|
|
84
|
-
/// TODO
|
|
85
|
-
pub const Overrides = @import("gen1/calc.zig").Overrides;
|
|
86
89
|
/// Information relevant to damage calculation that occured during a Generation I
|
|
87
90
|
/// battle `update`.
|
|
88
91
|
pub const Summaries = @import("gen1/calc.zig").Summaries;
|
|
@@ -111,7 +114,6 @@ pub const gen2 = struct {
|
|
|
111
114
|
};
|
|
112
115
|
pub const Calc = @import("gen2/calc.zig").Calc;
|
|
113
116
|
pub const calc = if (options.internal) @import("gen2/calc.zig") else struct {
|
|
114
|
-
pub const Overrides = @import("gen2/calc.zig").Overrides;
|
|
115
117
|
pub const Summaries = @import("gen2/calc.zig").Summaries;
|
|
116
118
|
pub const Summary = @import("gen2/calc.zig").Summary;
|
|
117
119
|
pub const NULL = @import("gen2/calc.zig").NULL;
|
|
@@ -121,8 +123,8 @@ pub const gen2 = struct {
|
|
|
121
123
|
|
|
122
124
|
// Internal APIs used by other pkmn libraries, not actually part of the public API.
|
|
123
125
|
// NOTE: `pub usingnamespace struct { ... }` here results in a (false?) dependency loop
|
|
124
|
-
pub const js = if (options.internal) @import("common/js.zig") else
|
|
126
|
+
pub const js = if (options.internal) @import("common/js.zig") else {};
|
|
125
127
|
pub const bindings = if (options.internal) struct {
|
|
126
128
|
pub const node = @import("node.zig");
|
|
127
129
|
pub const wasm = @import("wasm.zig");
|
|
128
|
-
} else
|
|
130
|
+
} else {};
|