@pkmn/engine 0.1.0-dev.3de821b9 → 0.1.0-dev.3ed876db
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 +44 -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 +97 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon/wasm.d.ts +2 -0
- package/build/pkg/addon/wasm.js +21 -0
- package/build/pkg/addon/wasm.js.map +1 -0
- package/build/pkg/addon.d.ts +22 -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 +23 -9
- package/build/pkg/index.js +17 -11
- 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 +141 -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 +249 -77
- package/package.json +51 -31
- 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 +4 -0
- package/src/lib/common/protocol.zig +44 -43
- package/src/lib/common/rational.zig +53 -51
- package/src/lib/common/rng.zig +5 -7
- package/src/lib/common/util.zig +50 -1
- package/src/lib/gen1/calc.zig +247 -108
- package/src/lib/gen1/chance.zig +130 -121
- package/src/lib/gen1/data/moves.zig +2 -4
- package/src/lib/gen1/data/species.zig +1 -3
- package/src/lib/gen1/data/types.zig +1 -2
- package/src/lib/gen1/data.zig +35 -38
- package/src/lib/gen1/helpers.zig +15 -27
- package/src/lib/gen1/mechanics.zig +112 -94
- package/src/lib/gen2/calc.zig +37 -27
- package/src/lib/gen2/chance.zig +86 -66
- package/src/lib/gen2/data/items.zig +1 -3
- package/src/lib/gen2/data/moves.zig +2 -4
- package/src/lib/gen2/data/species.zig +1 -3
- package/src/lib/gen2/data/types.zig +1 -2
- package/src/lib/gen2/data.zig +26 -29
- package/src/lib/gen2/generated.zig +18 -23
- package/src/lib/gen2/helpers.zig +9 -18
- package/src/lib/gen2/mechanics.zig +62 -73
- package/src/lib/node.zig +2 -4
- package/src/lib/pkmn.zig +11 -5
- package/src/lib/wasm.zig +1 -2
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +354 -0
- package/build/test/display.js +0 -405
- package/build/test/display.js.map +0 -1
- package/src/test/display/pkmn.html.tmpl +0 -368
package/src/lib/gen2/helpers.zig
CHANGED
|
@@ -1,31 +1,22 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
|
|
3
1
|
const common = @import("../common/data.zig");
|
|
2
|
+
const data = @import("data.zig");
|
|
3
|
+
const gen1 = @import("../gen1/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
|
-
|
|
8
|
-
const gen1 = @import("../gen1/data.zig");
|
|
9
|
-
|
|
10
|
-
const data = @import("data.zig");
|
|
6
|
+
const std = @import("std");
|
|
11
7
|
|
|
12
8
|
const assert = std.debug.assert;
|
|
13
|
-
|
|
14
|
-
const expectEqual = std.testing.expectEqual;
|
|
15
|
-
|
|
16
9
|
const Choice = common.Choice;
|
|
17
|
-
|
|
18
|
-
const showdown = options.showdown;
|
|
19
|
-
|
|
20
|
-
const PSRNG = rng.PSRNG;
|
|
21
|
-
|
|
22
10
|
const DVs = data.DVs;
|
|
23
11
|
const Item = data.Item;
|
|
24
12
|
const Move = data.Move;
|
|
25
13
|
const MoveSlot = data.MoveSlot;
|
|
14
|
+
const PSRNG = rng.PSRNG;
|
|
15
|
+
const showdown = options.showdown;
|
|
26
16
|
const Species = data.Species;
|
|
27
17
|
const Stats = data.Stats;
|
|
28
|
-
|
|
18
|
+
|
|
19
|
+
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
29
20
|
|
|
30
21
|
pub const Options = struct {
|
|
31
22
|
cleric: bool = showdown,
|
|
@@ -151,7 +142,7 @@ pub const Pokemon = struct {
|
|
|
151
142
|
var pokemon = data.Pokemon{};
|
|
152
143
|
pokemon.species = p.species;
|
|
153
144
|
const species = Species.get(p.species);
|
|
154
|
-
inline for (@typeInfo(@TypeOf(pokemon.stats))
|
|
145
|
+
inline for (@field(@typeInfo(@TypeOf(pokemon.stats)), @tagName(Struct)).fields) |field| {
|
|
155
146
|
const hp = comptime std.mem.eql(u8, field.name, "hp");
|
|
156
147
|
const spc =
|
|
157
148
|
comptime std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
|
|
@@ -192,7 +183,7 @@ pub const Pokemon = struct {
|
|
|
192
183
|
|
|
193
184
|
var stats: Stats(u16) = .{};
|
|
194
185
|
const dvs = gen1.DVs.random(rand);
|
|
195
|
-
inline for (@typeInfo(@TypeOf(stats))
|
|
186
|
+
inline for (@field(@typeInfo(@TypeOf(stats)), @tagName(Struct)).fields) |field| {
|
|
196
187
|
const hp = std.mem.eql(u8, field.name, "hp");
|
|
197
188
|
const spc = std.mem.eql(u8, field.name, "spa") or std.mem.eql(u8, field.name, "spd");
|
|
198
189
|
@field(stats, field.name) = Stats(u16).calc(
|
|
@@ -1,50 +1,36 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
|
|
3
|
-
const pkmn = @import("../pkmn.zig");
|
|
4
|
-
|
|
5
|
-
const common = @import("../common/data.zig");
|
|
6
1
|
const DEBUG = @import("../common/debug.zig").print;
|
|
7
|
-
const protocol = @import("../common/protocol.zig");
|
|
8
|
-
const rng = @import("../common/rng.zig");
|
|
9
|
-
const util = @import("../common/util.zig");
|
|
10
2
|
|
|
3
|
+
const common = @import("../common/data.zig");
|
|
11
4
|
const data = @import("data.zig");
|
|
12
5
|
const generated = @import("generated.zig");
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const expectEqualSlices = std.testing.expectEqualSlices;
|
|
18
|
-
const expectEqualStrings = std.testing.expectEqualStrings;
|
|
19
|
-
|
|
20
|
-
const showdown = pkmn.options.showdown;
|
|
21
|
-
|
|
22
|
-
const Choice = common.Choice;
|
|
23
|
-
const ID = common.ID;
|
|
24
|
-
const Player = common.Player;
|
|
25
|
-
const Result = common.Result;
|
|
6
|
+
const pkmn = @import("../pkmn.zig");
|
|
7
|
+
const protocol = @import("../common/protocol.zig");
|
|
8
|
+
const rng = @import("../common/rng.zig");
|
|
9
|
+
const std = @import("std");
|
|
26
10
|
|
|
27
11
|
const Activate = protocol.Activate;
|
|
12
|
+
const ActivePokemon = data.ActivePokemon;
|
|
13
|
+
const assert = std.debug.assert;
|
|
28
14
|
const Boost = protocol.Boost;
|
|
15
|
+
const Boosts = data.Boosts;
|
|
16
|
+
const Choice = common.Choice;
|
|
29
17
|
const Damage = protocol.Damage;
|
|
18
|
+
const Effectiveness = data.Effectiveness;
|
|
30
19
|
const End = protocol.End;
|
|
20
|
+
const expectEqual = std.testing.expectEqual;
|
|
21
|
+
const expectEqualSlices = std.testing.expectEqualSlices;
|
|
22
|
+
const expectEqualStrings = std.testing.expectEqualStrings;
|
|
31
23
|
const Fail = protocol.Fail;
|
|
32
|
-
const Heal = protocol.Heal;
|
|
33
|
-
const Start = protocol.Start;
|
|
34
|
-
|
|
35
24
|
const Gen12 = rng.Gen12;
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
const ActivePokemon = data.ActivePokemon;
|
|
40
|
-
const Boosts = data.Boosts;
|
|
41
|
-
const Effectiveness = data.Effectiveness;
|
|
25
|
+
const Heal = protocol.Heal;
|
|
26
|
+
const ID = common.ID;
|
|
42
27
|
const Item = data.Item;
|
|
43
28
|
const Move = data.Move;
|
|
44
|
-
const
|
|
45
|
-
const
|
|
29
|
+
const Player = common.Player;
|
|
30
|
+
const Result = common.Result;
|
|
31
|
+
const showdown = pkmn.options.showdown;
|
|
46
32
|
const Side = data.Side;
|
|
47
|
-
const
|
|
33
|
+
const Start = protocol.Start;
|
|
48
34
|
const Stats = data.Stats;
|
|
49
35
|
const Status = data.Status;
|
|
50
36
|
const TriAttack = data.TriAttack;
|
|
@@ -106,6 +92,7 @@ pub const State = struct {
|
|
|
106
92
|
type: Type, // BATTLE_VARS_MOVE_TYPE
|
|
107
93
|
accuracy: u8, // wEnemyMoveStruct + MOVE_ACC
|
|
108
94
|
move: Move, // wCurPlayerMove
|
|
95
|
+
hit: u3 = 0,
|
|
109
96
|
from: Move = .None,
|
|
110
97
|
mslot: u4, // wCurMoveNum
|
|
111
98
|
first: bool, // wEnemyGoesFirst
|
|
@@ -644,7 +631,7 @@ pub fn checkCriticalHit(battle: anytype, player: Player, state: *State, options:
|
|
|
644
631
|
}
|
|
645
632
|
assert(stage <= 4);
|
|
646
633
|
|
|
647
|
-
state.crit = try Rolls.criticalHit(battle, player, CRITICAL_HITS[stage], options);
|
|
634
|
+
state.crit = try Rolls.criticalHit(battle, player, state.hit, CRITICAL_HITS[stage], options);
|
|
648
635
|
}
|
|
649
636
|
|
|
650
637
|
pub fn calcDamage(
|
|
@@ -712,7 +699,7 @@ pub fn adjustDamage(battle: anytype, player: Player, state: *State, _: anytype)
|
|
|
712
699
|
|
|
713
700
|
pub fn randomizeDamage(battle: anytype, player: Player, state: *State, options: anytype) !void {
|
|
714
701
|
if (state.damage <= 1) return;
|
|
715
|
-
const random = try Rolls.damage(battle, player, options);
|
|
702
|
+
const random = try Rolls.damage(battle, player, state.hit, options);
|
|
716
703
|
options.calc.base(player.foe(), state.damage);
|
|
717
704
|
state.damage = @intCast(@as(u32, state.damage) *% random / 255);
|
|
718
705
|
options.calc.final(player.foe(), state.damage);
|
|
@@ -1205,7 +1192,7 @@ fn updateSideCondition(
|
|
|
1205
1192
|
fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result {
|
|
1206
1193
|
battle.turn += 1;
|
|
1207
1194
|
|
|
1208
|
-
if (
|
|
1195
|
+
if (pkmn.options.mod and battle.turn >= 1000) {
|
|
1209
1196
|
try options.log.tie(.{});
|
|
1210
1197
|
return Result.Tie;
|
|
1211
1198
|
} else if (battle.turn >= 65535) {
|
|
@@ -1711,7 +1698,7 @@ pub const Effects = struct {
|
|
|
1711
1698
|
if (!state.proc) return;
|
|
1712
1699
|
if (foe.conditions.Safeguard) return;
|
|
1713
1700
|
// Freeze Clause Mod
|
|
1714
|
-
if (
|
|
1701
|
+
if (pkmn.options.mod) for (foe.pokemon) |p| if (Status.is(p.status, .FRZ)) return;
|
|
1715
1702
|
|
|
1716
1703
|
foe_stored.status = Status.init(.FRZ);
|
|
1717
1704
|
try options.log.status(.{ foe_ident, foe_stored.status, .None });
|
|
@@ -2389,7 +2376,7 @@ pub const Effects = struct {
|
|
|
2389
2376
|
}
|
|
2390
2377
|
|
|
2391
2378
|
// Sleep Clause Mod
|
|
2392
|
-
if (
|
|
2379
|
+
if (pkmn.options.mod) {
|
|
2393
2380
|
for (foe.pokemon) |p| {
|
|
2394
2381
|
if (Status.is(p.status, .SLP) and !Status.is(p.status, .EXT)) return;
|
|
2395
2382
|
}
|
|
@@ -2849,7 +2836,7 @@ fn convertible(active: ActivePokemon, m: Move) bool {
|
|
|
2849
2836
|
|
|
2850
2837
|
pub const Rolls = struct {
|
|
2851
2838
|
fn speedTie(battle: anytype, options: anytype) !bool {
|
|
2852
|
-
const p1 = if (options.calc.overridden(.P1, .speed_tie)) |player|
|
|
2839
|
+
const p1 = if (options.calc.overridden(.P1, 0, .speed_tie)) |player|
|
|
2853
2840
|
player == .P1
|
|
2854
2841
|
else if (showdown)
|
|
2855
2842
|
battle.rng.range(u8, 0, 2) == 0
|
|
@@ -2861,7 +2848,7 @@ pub const Rolls = struct {
|
|
|
2861
2848
|
}
|
|
2862
2849
|
|
|
2863
2850
|
fn quickClaw(battle: anytype, player: Player, options: anytype) !bool {
|
|
2864
|
-
const qkc = if (options.calc.overridden(player, .quick_claw)) |val|
|
|
2851
|
+
const qkc = if (options.calc.overridden(player, 0, .quick_claw)) |val|
|
|
2865
2852
|
val == .true
|
|
2866
2853
|
else if (showdown)
|
|
2867
2854
|
battle.rng.chance(u8, 60, 256)
|
|
@@ -2873,7 +2860,7 @@ pub const Rolls = struct {
|
|
|
2873
2860
|
}
|
|
2874
2861
|
|
|
2875
2862
|
fn hit(battle: anytype, player: Player, accuracy: u8, options: anytype) !bool {
|
|
2876
|
-
const ok = if (options.calc.overridden(player, .hit)) |val|
|
|
2863
|
+
const ok = if (options.calc.overridden(player, 0, .hit)) |val|
|
|
2877
2864
|
val == .true
|
|
2878
2865
|
else if (showdown)
|
|
2879
2866
|
battle.rng.chance(u8, accuracy, 256)
|
|
@@ -2884,20 +2871,22 @@ pub const Rolls = struct {
|
|
|
2884
2871
|
return ok;
|
|
2885
2872
|
}
|
|
2886
2873
|
|
|
2887
|
-
fn criticalHit(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
|
|
2888
|
-
|
|
2874
|
+
fn criticalHit(battle: anytype, player: Player, i: u3, rate: u8, options: anytype) !bool {
|
|
2875
|
+
_ = .{ player, options };
|
|
2876
|
+
const crit = if (options.calc.overridden(player, i, .critical_hits)) |val|
|
|
2889
2877
|
val == .true
|
|
2890
2878
|
else if (showdown)
|
|
2891
2879
|
battle.rng.chance(u8, rate, 256)
|
|
2892
2880
|
else
|
|
2893
2881
|
battle.rng.next() < rate;
|
|
2894
2882
|
|
|
2895
|
-
try options.chance.criticalHit(player, crit, rate);
|
|
2883
|
+
try options.chance.criticalHit(player, i, crit, rate);
|
|
2896
2884
|
return crit;
|
|
2897
2885
|
}
|
|
2898
2886
|
|
|
2899
|
-
fn damage(battle: anytype, player: Player, options: anytype) !u8 {
|
|
2900
|
-
|
|
2887
|
+
fn damage(battle: anytype, player: Player, i: u3, options: anytype) !u8 {
|
|
2888
|
+
_ = .{ player, options };
|
|
2889
|
+
const roll = if (options.calc.overridden(player, i, .damages)) |val|
|
|
2901
2890
|
val
|
|
2902
2891
|
else roll: {
|
|
2903
2892
|
if (showdown) break :roll battle.rng.range(u8, 217, 256);
|
|
@@ -2908,12 +2897,12 @@ pub const Rolls = struct {
|
|
|
2908
2897
|
};
|
|
2909
2898
|
|
|
2910
2899
|
assert(roll >= 217 and roll <= 255);
|
|
2911
|
-
try options.chance.damage(player, roll);
|
|
2900
|
+
try options.chance.damage(player, i, roll);
|
|
2912
2901
|
return roll;
|
|
2913
2902
|
}
|
|
2914
2903
|
|
|
2915
2904
|
fn confused(battle: anytype, player: Player, options: anytype) !bool {
|
|
2916
|
-
const cfz = if (options.calc.overridden(player, .confused)) |val|
|
|
2905
|
+
const cfz = if (options.calc.overridden(player, 0, .confused)) |val|
|
|
2917
2906
|
val == .true
|
|
2918
2907
|
else if (showdown)
|
|
2919
2908
|
!battle.rng.chance(u8, 128, 256)
|
|
@@ -2925,7 +2914,7 @@ pub const Rolls = struct {
|
|
|
2925
2914
|
}
|
|
2926
2915
|
|
|
2927
2916
|
fn attract(battle: anytype, player: Player, options: anytype) !bool {
|
|
2928
|
-
const cant = if (options.calc.overridden(player, .attract)) |val|
|
|
2917
|
+
const cant = if (options.calc.overridden(player, 0, .attract)) |val|
|
|
2929
2918
|
val == .true
|
|
2930
2919
|
else if (showdown)
|
|
2931
2920
|
battle.rng.chance(u8, 1, 2)
|
|
@@ -2937,7 +2926,7 @@ pub const Rolls = struct {
|
|
|
2937
2926
|
}
|
|
2938
2927
|
|
|
2939
2928
|
fn paralyzed(battle: anytype, player: Player, options: anytype) !bool {
|
|
2940
|
-
const par = if (options.calc.overridden(player, .paralyzed)) |val|
|
|
2929
|
+
const par = if (options.calc.overridden(player, 0, .paralyzed)) |val|
|
|
2941
2930
|
val == .true
|
|
2942
2931
|
else if (showdown)
|
|
2943
2932
|
battle.rng.chance(u8, 63, 256)
|
|
@@ -2949,7 +2938,7 @@ pub const Rolls = struct {
|
|
|
2949
2938
|
}
|
|
2950
2939
|
|
|
2951
2940
|
fn defrost(battle: anytype, player: Player, options: anytype) !bool {
|
|
2952
|
-
const thaw = if (options.calc.overridden(player, .defrost)) |val|
|
|
2941
|
+
const thaw = if (options.calc.overridden(player, 0, .defrost)) |val|
|
|
2953
2942
|
val == .true
|
|
2954
2943
|
else if (showdown)
|
|
2955
2944
|
battle.rng.chance(u8, 25, 256)
|
|
@@ -2962,7 +2951,7 @@ pub const Rolls = struct {
|
|
|
2962
2951
|
|
|
2963
2952
|
fn secondaryChance(battle: anytype, player: Player, rate: u8, options: anytype) !bool {
|
|
2964
2953
|
// GLITCH: 100% secondary chance will still fail 1/256 of the time
|
|
2965
|
-
const proc = if (options.calc.overridden(player, .secondary_chance)) |val|
|
|
2954
|
+
const proc = if (options.calc.overridden(player, 0, .secondary_chance)) |val|
|
|
2966
2955
|
val == .true
|
|
2967
2956
|
else if (showdown)
|
|
2968
2957
|
battle.rng.chance(u8, rate, 256)
|
|
@@ -2974,7 +2963,7 @@ pub const Rolls = struct {
|
|
|
2974
2963
|
}
|
|
2975
2964
|
|
|
2976
2965
|
fn item(battle: anytype, player: Player, options: anytype) !bool {
|
|
2977
|
-
const proc = if (options.calc.overridden(player, .item)) |val|
|
|
2966
|
+
const proc = if (options.calc.overridden(player, 0, .item)) |val|
|
|
2978
2967
|
val == .true
|
|
2979
2968
|
else if (showdown)
|
|
2980
2969
|
battle.rng.chance(u8, 30, 256)
|
|
@@ -2986,7 +2975,7 @@ pub const Rolls = struct {
|
|
|
2986
2975
|
}
|
|
2987
2976
|
|
|
2988
2977
|
fn triAttack(battle: anytype, player: Player, options: anytype) !TriAttack {
|
|
2989
|
-
const status: TriAttack = if (options.calc.overridden(player, .tri_attack)) |val|
|
|
2978
|
+
const status: TriAttack = if (options.calc.overridden(player, 0, .tri_attack)) |val|
|
|
2990
2979
|
@enumFromInt(@intFromEnum(val) - 1)
|
|
2991
2980
|
else if (showdown)
|
|
2992
2981
|
@enumFromInt(battle.rng.range(u2, 0, 2))
|
|
@@ -3002,7 +2991,7 @@ pub const Rolls = struct {
|
|
|
3002
2991
|
}
|
|
3003
2992
|
|
|
3004
2993
|
fn present(battle: anytype, player: Player, options: anytype) !u8 {
|
|
3005
|
-
const power = if (options.calc.overridden(player, .present)) |val|
|
|
2994
|
+
const power = if (options.calc.overridden(player, 0, .present)) |val|
|
|
3006
2995
|
(val - 1) * 40
|
|
3007
2996
|
else if (showdown) power: {
|
|
3008
2997
|
const r = battle.rng.range(u8, 0, 10);
|
|
@@ -3024,7 +3013,7 @@ pub const Rolls = struct {
|
|
|
3024
3013
|
}
|
|
3025
3014
|
|
|
3026
3015
|
fn magnitude(battle: anytype, player: Player, options: anytype) !u8 {
|
|
3027
|
-
const num: u8 = if (options.calc.overridden(player, .magnitude)) |val|
|
|
3016
|
+
const num: u8 = if (options.calc.overridden(player, 0, .magnitude)) |val|
|
|
3028
3017
|
val + 3
|
|
3029
3018
|
else if (showdown) num: {
|
|
3030
3019
|
const r = battle.rng.range(u8, 0, 100);
|
|
@@ -3052,7 +3041,7 @@ pub const Rolls = struct {
|
|
|
3052
3041
|
}
|
|
3053
3042
|
|
|
3054
3043
|
fn tripleKick(battle: anytype, player: Player, options: anytype) !u2 {
|
|
3055
|
-
const hits = if (options.calc.overridden(player, .triple_kick)) |val|
|
|
3044
|
+
const hits = if (options.calc.overridden(player, 0, .triple_kick)) |val|
|
|
3056
3045
|
val
|
|
3057
3046
|
else if (showdown)
|
|
3058
3047
|
battle.rng.range(u2, 1, 4)
|
|
@@ -3070,7 +3059,7 @@ pub const Rolls = struct {
|
|
|
3070
3059
|
|
|
3071
3060
|
fn spite(battle: anytype, player: Player, options: anytype) !u3 {
|
|
3072
3061
|
assert(!showdown);
|
|
3073
|
-
const pp: u3 = if (options.calc.overridden(player, .spite)) |val|
|
|
3062
|
+
const pp: u3 = if (options.calc.overridden(player, 0, .spite)) |val|
|
|
3074
3063
|
val + 1
|
|
3075
3064
|
else
|
|
3076
3065
|
@intCast((battle.rng.next() & 3) + 2);
|
|
@@ -3087,7 +3076,7 @@ pub const Rolls = struct {
|
|
|
3087
3076
|
var i: u8 = 0;
|
|
3088
3077
|
const neutral = @intFromEnum(Effectiveness.Neutral);
|
|
3089
3078
|
assert(mtype != .@"???");
|
|
3090
|
-
const ty: Type = if (options.calc.overridden(player, .conversion_2)) |val|
|
|
3079
|
+
const ty: Type = if (options.calc.overridden(player, 0, .conversion_2)) |val|
|
|
3091
3080
|
@enumFromInt(@intFromEnum(val) - 1)
|
|
3092
3081
|
else if (showdown) ty: {
|
|
3093
3082
|
for (Type.SHOWDOWN) |t| {
|
|
@@ -3121,7 +3110,7 @@ pub const Rolls = struct {
|
|
|
3121
3110
|
assert(count <= 8);
|
|
3122
3111
|
const num = if (count == 8) 0 else @as(u8, 255) >> @intCast(count);
|
|
3123
3112
|
|
|
3124
|
-
const ok = if (options.calc.overridden(player, .protect)) |val|
|
|
3113
|
+
const ok = if (options.calc.overridden(player, 0, .protect)) |val|
|
|
3125
3114
|
val == .true
|
|
3126
3115
|
else if (showdown)
|
|
3127
3116
|
battle.rng.chance(u8, num, 255)
|
|
@@ -3143,7 +3132,7 @@ pub const Rolls = struct {
|
|
|
3143
3132
|
const moves = active.moves;
|
|
3144
3133
|
|
|
3145
3134
|
// TODO: consider throwing error instead of rerolling?
|
|
3146
|
-
const overridden = if (options.calc.overridden(player, .move_slot)) |val|
|
|
3135
|
+
const overridden = if (options.calc.overridden(player, 0, .move_slot)) |val|
|
|
3147
3136
|
if (convertible(active, moves[val - 1].id)) val else null
|
|
3148
3137
|
else
|
|
3149
3138
|
null;
|
|
@@ -3180,7 +3169,7 @@ pub const Rolls = struct {
|
|
|
3180
3169
|
const moves = active.moves;
|
|
3181
3170
|
|
|
3182
3171
|
// TODO: consider throwing error instead of rerolling?
|
|
3183
|
-
const overridden = if (options.calc.overridden(player, .move_slot)) |val|
|
|
3172
|
+
const overridden = if (options.calc.overridden(player, 0, .move_slot)) |val|
|
|
3184
3173
|
if (val != mslot and Move.get(moves[val - 1].id).extra.sleep_talk) val else null
|
|
3185
3174
|
else
|
|
3186
3175
|
null;
|
|
@@ -3224,7 +3213,7 @@ pub const Rolls = struct {
|
|
|
3224
3213
|
assert(n > 0 and n <= 6);
|
|
3225
3214
|
|
|
3226
3215
|
// TODO: consider throwing error instead of rerolling?
|
|
3227
|
-
const overridden = if (options.calc.overridden(player, .force_switch)) |val| val: {
|
|
3216
|
+
const overridden = if (options.calc.overridden(player, 0, .force_switch)) |val| val: {
|
|
3228
3217
|
for (slots) |slot| if (slot == val) break :val if (foe.get(slot).hp > 0) val else null;
|
|
3229
3218
|
break :val null;
|
|
3230
3219
|
} else null;
|
|
@@ -3250,7 +3239,7 @@ pub const Rolls = struct {
|
|
|
3250
3239
|
const DISTRIBUTION = [_]u3{ 2, 2, 2, 3, 3, 3, 4, 5 };
|
|
3251
3240
|
|
|
3252
3241
|
fn multiHit(battle: anytype, player: Player, options: anytype) !u3 {
|
|
3253
|
-
const n: u3 = if (options.calc.overridden(player, .multi_hit)) |val|
|
|
3242
|
+
const n: u3 = if (options.calc.overridden(player, 0, .multi_hit)) |val|
|
|
3254
3243
|
@intCast(val)
|
|
3255
3244
|
else if (showdown)
|
|
3256
3245
|
DISTRIBUTION[battle.rng.range(u3, 0, DISTRIBUTION.len)]
|
|
@@ -3265,7 +3254,7 @@ pub const Rolls = struct {
|
|
|
3265
3254
|
}
|
|
3266
3255
|
|
|
3267
3256
|
fn psywave(battle: anytype, player: Player, max: u8, options: anytype) !u8 {
|
|
3268
|
-
const power = if (options.calc.overridden(player, .psywave)) |val|
|
|
3257
|
+
const power = if (options.calc.overridden(player, 0, .psywave)) |val|
|
|
3269
3258
|
val
|
|
3270
3259
|
else if (showdown)
|
|
3271
3260
|
battle.rng.range(u8, 1, max)
|
|
@@ -3291,7 +3280,7 @@ pub const Rolls = struct {
|
|
|
3291
3280
|
}
|
|
3292
3281
|
|
|
3293
3282
|
// TODO: consider throwing error instead of rerolling?
|
|
3294
|
-
const overridden = if (options.calc.overridden(player, .metronome)) |val| val: {
|
|
3283
|
+
const overridden = if (options.calc.overridden(player, 0, .metronome)) |val| val: {
|
|
3295
3284
|
for (moves) |m| if (m.id == val) break :val null;
|
|
3296
3285
|
break :val val;
|
|
3297
3286
|
} else null;
|
|
@@ -3323,7 +3312,7 @@ pub const Rolls = struct {
|
|
|
3323
3312
|
}
|
|
3324
3313
|
|
|
3325
3314
|
fn sleepDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
3326
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
3315
|
+
const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3327
3316
|
@intCast(val)
|
|
3328
3317
|
else if (showdown)
|
|
3329
3318
|
battle.rng.range(u3, 1, 7)
|
|
@@ -3340,7 +3329,7 @@ pub const Rolls = struct {
|
|
|
3340
3329
|
}
|
|
3341
3330
|
|
|
3342
3331
|
fn confusionDuration(battle: anytype, player: Player, self: bool, options: anytype) u3 {
|
|
3343
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
3332
|
+
const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3344
3333
|
@intCast(val)
|
|
3345
3334
|
else if (showdown)
|
|
3346
3335
|
// Pokémon Showdown incorrectly uses the same duration for self-confusion
|
|
@@ -3354,11 +3343,11 @@ pub const Rolls = struct {
|
|
|
3354
3343
|
}
|
|
3355
3344
|
|
|
3356
3345
|
fn disableDuration(battle: anytype, player: Player, options: anytype) u4 {
|
|
3357
|
-
const duration:
|
|
3346
|
+
const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3358
3347
|
@intCast(val)
|
|
3359
3348
|
else if (showdown)
|
|
3360
3349
|
// Pokémon Showdown incorrectly inherits Generation III's Disable duration
|
|
3361
|
-
battle.rng.range(
|
|
3350
|
+
battle.rng.range(u3, 2, 6)
|
|
3362
3351
|
else duration: {
|
|
3363
3352
|
while (true) {
|
|
3364
3353
|
const r = battle.rng.next() & 7;
|
|
@@ -3372,7 +3361,7 @@ pub const Rolls = struct {
|
|
|
3372
3361
|
}
|
|
3373
3362
|
|
|
3374
3363
|
fn attackingDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
3375
|
-
const duration: u3 = if (options.calc.overridden(player, .duration)) |val|
|
|
3364
|
+
const duration: u3 = if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3376
3365
|
@intCast(val)
|
|
3377
3366
|
else if (showdown)
|
|
3378
3367
|
battle.rng.range(u3, 2, 4)
|
|
@@ -3385,7 +3374,7 @@ pub const Rolls = struct {
|
|
|
3385
3374
|
}
|
|
3386
3375
|
|
|
3387
3376
|
fn bindingDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
3388
|
-
const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
|
|
3377
|
+
const duration: u3 = (if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3389
3378
|
@intCast(val)
|
|
3390
3379
|
else if (showdown)
|
|
3391
3380
|
// TODO: PS does range(3, 6) here which after subtracting 1 is actually 2-4 not 2-5!
|
|
@@ -3400,7 +3389,7 @@ pub const Rolls = struct {
|
|
|
3400
3389
|
|
|
3401
3390
|
// TODO: consider sharing implementation with bindingDuration
|
|
3402
3391
|
fn encoreDuration(battle: anytype, player: Player, options: anytype) u3 {
|
|
3403
|
-
const duration: u3 = (if (options.calc.overridden(player, .duration)) |val|
|
|
3392
|
+
const duration: u3 = (if (options.calc.overridden(player, 0, .duration)) |val|
|
|
3404
3393
|
@intCast(val)
|
|
3405
3394
|
else if (showdown)
|
|
3406
3395
|
battle.rng.range(u3, 2, 6)
|
package/src/lib/node.zig
CHANGED
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;
|
|
@@ -93,6 +96,10 @@ pub const gen1 = struct {
|
|
|
93
96
|
/// though damage calculator support should additionally be turned off
|
|
94
97
|
/// entirely via `options.calc`.
|
|
95
98
|
pub const NULL = @import("gen1/calc.zig").NULL;
|
|
99
|
+
/// TODO
|
|
100
|
+
pub const MAX_FRONTIER = @import("gen1/calc.zig").MAX_FRONTIER;
|
|
101
|
+
/// TODO
|
|
102
|
+
pub const Rolls = @import("gen1/calc.zig").Rolls;
|
|
96
103
|
};
|
|
97
104
|
/// Provides helpers for initializing Generation I Pokémon battles.
|
|
98
105
|
pub const helpers = @import("gen1/helpers.zig");
|
|
@@ -111,7 +118,6 @@ pub const gen2 = struct {
|
|
|
111
118
|
};
|
|
112
119
|
pub const Calc = @import("gen2/calc.zig").Calc;
|
|
113
120
|
pub const calc = if (options.internal) @import("gen2/calc.zig") else struct {
|
|
114
|
-
pub const Overrides = @import("gen2/calc.zig").Overrides;
|
|
115
121
|
pub const Summaries = @import("gen2/calc.zig").Summaries;
|
|
116
122
|
pub const Summary = @import("gen2/calc.zig").Summary;
|
|
117
123
|
pub const NULL = @import("gen2/calc.zig").NULL;
|
|
@@ -121,8 +127,8 @@ pub const gen2 = struct {
|
|
|
121
127
|
|
|
122
128
|
// Internal APIs used by other pkmn libraries, not actually part of the public API.
|
|
123
129
|
// NOTE: `pub usingnamespace struct { ... }` here results in a (false?) dependency loop
|
|
124
|
-
pub const js = if (options.internal) @import("common/js.zig") else
|
|
130
|
+
pub const js = if (options.internal) @import("common/js.zig") else {};
|
|
125
131
|
pub const bindings = if (options.internal) struct {
|
|
126
132
|
pub const node = @import("node.zig");
|
|
127
133
|
pub const wasm = @import("wasm.zig");
|
|
128
|
-
} else
|
|
134
|
+
} else {};
|
package/src/lib/wasm.zig
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** @license MIT modified from Vadim Demedes's https://github.com/vadimdemedes/dom-chef */
|
|
2
|
+
type Attributes = JSX.IntrinsicElements['div'];
|
|
3
|
+
type DocumentFragmentConstructor = typeof DocumentFragment;
|
|
4
|
+
type ElementFunction = (props?: any) => HTMLElement;
|
|
5
|
+
|
|
6
|
+
declare global {
|
|
7
|
+
namespace JSX {
|
|
8
|
+
interface Element extends HTMLElement, DocumentFragment {
|
|
9
|
+
addEventListener: HTMLElement['addEventListener'];
|
|
10
|
+
removeEventListener: HTMLElement['removeEventListener'];
|
|
11
|
+
className: HTMLElement['className'];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface JSXElementClassDocumentFragment extends DocumentFragment, JSX.ElementClass { }
|
|
17
|
+
interface Fragment {
|
|
18
|
+
prototype: JSXElementClassDocumentFragment;
|
|
19
|
+
new(): JSXElementClassDocumentFragment;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// https://github.com/preactjs/preact/blob/1bbd687c/src/constants.js#L3
|
|
23
|
+
const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
|
|
24
|
+
|
|
25
|
+
const isFragment = (type: DocumentFragmentConstructor | ElementFunction):
|
|
26
|
+
type is DocumentFragmentConstructor => type === DocumentFragment;
|
|
27
|
+
|
|
28
|
+
const setCSSProps = (element: HTMLElement, style: CSSStyleDeclaration) => {
|
|
29
|
+
for (const [name, value] of Object.entries(style)) {
|
|
30
|
+
if (name.startsWith('-')) {
|
|
31
|
+
element.style.setProperty(name, value);
|
|
32
|
+
} else if (typeof value === 'number' && !IS_NON_DIMENSIONAL.test(name)) {
|
|
33
|
+
element.style[name as any] = `${value as string}px`;
|
|
34
|
+
} else {
|
|
35
|
+
element.style[name as any] = value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const setAttribute = (element: HTMLElement, name: string, value: string) => {
|
|
41
|
+
if (value !== undefined && value !== null) element.setAttribute(name, value);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const addChildren = (parent: Element | DocumentFragment, children: Node[]) => {
|
|
45
|
+
for (const child of children) {
|
|
46
|
+
if (child instanceof Node) {
|
|
47
|
+
parent.appendChild(child);
|
|
48
|
+
} else if (Array.isArray(child)) {
|
|
49
|
+
addChildren(parent, child);
|
|
50
|
+
} else if (typeof child !== 'boolean' && typeof child !== 'undefined' && child !== null) {
|
|
51
|
+
parent.appendChild(document.createTextNode(child));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// https://github.com/facebook/react/blob/3f899089/packages/react-dom/src/shared/DOMProperty.js#L288-L322
|
|
57
|
+
const FALSIFIABLE_ATTRIBUTES = ['contentEditable', 'draggable', 'spellCheck', 'value'];
|
|
58
|
+
|
|
59
|
+
export const h = (
|
|
60
|
+
type: DocumentFragmentConstructor | ElementFunction | string,
|
|
61
|
+
attributes?: Attributes,
|
|
62
|
+
...children: Node[]
|
|
63
|
+
) => {
|
|
64
|
+
if (typeof type !== 'string') {
|
|
65
|
+
const element = isFragment(type) ? document.createDocumentFragment() : type(attributes);
|
|
66
|
+
addChildren(element, children);
|
|
67
|
+
return element;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const element = document.createElement(type);
|
|
71
|
+
addChildren(element, children);
|
|
72
|
+
if (!attributes) return element;
|
|
73
|
+
|
|
74
|
+
for (let [name, value] of Object.entries(attributes)) {
|
|
75
|
+
if (name === 'htmlFor') name = 'for';
|
|
76
|
+
|
|
77
|
+
if (name === 'class' || name === 'className') {
|
|
78
|
+
const existingClassname = element.getAttribute('class') ?? '';
|
|
79
|
+
setAttribute(element, 'class', (existingClassname + ' ' + String(value)).trim());
|
|
80
|
+
} else if (name === 'style') {
|
|
81
|
+
setCSSProps(element, value);
|
|
82
|
+
} else if (name.startsWith('on')) {
|
|
83
|
+
const eventName = name.slice(2).toLowerCase().replace(/^-/, '');
|
|
84
|
+
element.addEventListener(eventName, value);
|
|
85
|
+
} else if (name === 'dangerouslySetInnerHTML' && '__html' in value) {
|
|
86
|
+
element.innerHTML = value.__html;
|
|
87
|
+
} else if (name !== 'key' && (FALSIFIABLE_ATTRIBUTES.includes(name) || value !== false)) {
|
|
88
|
+
setAttribute(element, name, value === true ? '' : value);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return element;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const Fragment =
|
|
96
|
+
(typeof DocumentFragment === 'function' ? DocumentFragment : () => {}) as Fragment;
|