@pkmn/engine 0.1.0-dev.f4ba6ebd → 0.1.0-dev.f6545544
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 +5 -4
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +47 -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 +110 -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 +53 -0
- package/build/pkg/addon/wasm.js.map +1 -0
- package/build/pkg/addon.d.ts +25 -3
- package/build/pkg/addon.js +34 -65
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/layout.json +15 -2
- package/build/pkg/data/protocol.json +23 -9
- package/build/pkg/data.d.ts +23 -1
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.d.ts +15 -18
- package/build/pkg/gen1.js +28 -19
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +39 -89
- package/build/pkg/index.js +23 -70
- 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 +52 -76
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +152 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +152 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +359 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +33 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +196 -84
- package/package.json +51 -135
- package/src/bin/install-pkmn-engine +3 -2
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/bindings/c.zig +255 -0
- package/src/lib/bindings/node.zig +121 -0
- package/src/lib/bindings/wasm.zig +59 -0
- package/src/lib/common/array.zig +1 -1
- package/src/lib/common/debug.zig +39 -8
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/options.zig +4 -0
- package/src/lib/common/protocol.zig +4 -8
- package/src/lib/common/rational.zig +7 -5
- package/src/lib/common/rng.zig +1 -3
- package/src/lib/common/util.zig +1 -1
- package/src/lib/gen1/calc.zig +208 -61
- package/src/lib/gen1/chance.zig +40 -22
- 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 +9 -13
- package/src/lib/gen1/helpers.zig +5 -21
- package/src/lib/gen1/mechanics.zig +107 -82
- package/src/lib/gen2/calc.zig +9 -17
- package/src/lib/gen2/chance.zig +0 -3
- 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 +11 -15
- package/src/lib/gen2/generated.zig +18 -23
- package/src/lib/gen2/helpers.zig +5 -16
- package/src/lib/gen2/mechanics.zig +41 -44
- package/src/lib/node.zig +3 -116
- package/src/lib/pkmn.zig +7 -2
- package/src/lib/wasm.zig +13 -9
- package/src/tools/display/dom.ts +95 -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,20 @@
|
|
|
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
|
-
const Status = data.Status;
|
|
29
18
|
|
|
30
19
|
const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
|
|
31
20
|
|
|
@@ -1,50 +1,37 @@
|
|
|
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 builtin = @import("builtin");
|
|
4
|
+
const common = @import("../common/data.zig");
|
|
11
5
|
const data = @import("data.zig");
|
|
12
6
|
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;
|
|
7
|
+
const pkmn = @import("../pkmn.zig");
|
|
8
|
+
const protocol = @import("../common/protocol.zig");
|
|
9
|
+
const rng = @import("../common/rng.zig");
|
|
10
|
+
const std = @import("std");
|
|
26
11
|
|
|
27
12
|
const Activate = protocol.Activate;
|
|
13
|
+
const ActivePokemon = data.ActivePokemon;
|
|
14
|
+
const assert = std.debug.assert;
|
|
28
15
|
const Boost = protocol.Boost;
|
|
16
|
+
const Boosts = data.Boosts;
|
|
17
|
+
const Choice = common.Choice;
|
|
29
18
|
const Damage = protocol.Damage;
|
|
19
|
+
const Effectiveness = data.Effectiveness;
|
|
30
20
|
const End = protocol.End;
|
|
21
|
+
const expectEqual = std.testing.expectEqual;
|
|
22
|
+
const expectEqualSlices = std.testing.expectEqualSlices;
|
|
23
|
+
const expectEqualStrings = std.testing.expectEqualStrings;
|
|
31
24
|
const Fail = protocol.Fail;
|
|
32
|
-
const Heal = protocol.Heal;
|
|
33
|
-
const Start = protocol.Start;
|
|
34
|
-
|
|
35
25
|
const Gen12 = rng.Gen12;
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
const ActivePokemon = data.ActivePokemon;
|
|
40
|
-
const Boosts = data.Boosts;
|
|
41
|
-
const Effectiveness = data.Effectiveness;
|
|
26
|
+
const Heal = protocol.Heal;
|
|
27
|
+
const ID = common.ID;
|
|
42
28
|
const Item = data.Item;
|
|
43
29
|
const Move = data.Move;
|
|
44
|
-
const
|
|
45
|
-
const
|
|
30
|
+
const Player = common.Player;
|
|
31
|
+
const Result = common.Result;
|
|
32
|
+
const showdown = pkmn.options.showdown;
|
|
46
33
|
const Side = data.Side;
|
|
47
|
-
const
|
|
34
|
+
const Start = protocol.Start;
|
|
48
35
|
const Stats = data.Stats;
|
|
49
36
|
const Status = data.Status;
|
|
50
37
|
const TriAttack = data.TriAttack;
|
|
@@ -1206,7 +1193,7 @@ fn updateSideCondition(
|
|
|
1206
1193
|
fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result {
|
|
1207
1194
|
battle.turn += 1;
|
|
1208
1195
|
|
|
1209
|
-
if (
|
|
1196
|
+
if (pkmn.options.mod and battle.turn >= 1000) {
|
|
1210
1197
|
try options.log.tie(.{});
|
|
1211
1198
|
return Result.Tie;
|
|
1212
1199
|
} else if (battle.turn >= 65535) {
|
|
@@ -1440,7 +1427,8 @@ pub const Effects = struct {
|
|
|
1440
1427
|
if (move.type.special() != (last == .MirrorCoat)) return;
|
|
1441
1428
|
if (state.damage == 0) return;
|
|
1442
1429
|
|
|
1443
|
-
|
|
1430
|
+
// NOTE: llvm/llvm-project#58557
|
|
1431
|
+
state.damage = smul(state.damage, 2);
|
|
1444
1432
|
state.miss = false;
|
|
1445
1433
|
}
|
|
1446
1434
|
|
|
@@ -1535,15 +1523,18 @@ pub const Effects = struct {
|
|
|
1535
1523
|
|
|
1536
1524
|
pub const double = struct {
|
|
1537
1525
|
pub fn flying(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
1538
|
-
if (battle.foe(player).active.volatiles.Flying)
|
|
1526
|
+
if (!battle.foe(player).active.volatiles.Flying) return;
|
|
1527
|
+
state.damage = smul(state.damage, 2);
|
|
1539
1528
|
}
|
|
1540
1529
|
|
|
1541
1530
|
pub fn underground(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
1542
|
-
if (battle.foe(player).active.volatiles.Underground)
|
|
1531
|
+
if (!battle.foe(player).active.volatiles.Underground) return;
|
|
1532
|
+
state.damage = smul(state.damage, 2);
|
|
1543
1533
|
}
|
|
1544
1534
|
|
|
1545
1535
|
pub fn minimize(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
1546
|
-
if (battle.foe(player).active.volatiles.minimized)
|
|
1536
|
+
if (!battle.foe(player).active.volatiles.minimized) return;
|
|
1537
|
+
state.damage = smul(state.damage, 2);
|
|
1547
1538
|
}
|
|
1548
1539
|
};
|
|
1549
1540
|
|
|
@@ -1712,7 +1703,7 @@ pub const Effects = struct {
|
|
|
1712
1703
|
if (!state.proc) return;
|
|
1713
1704
|
if (foe.conditions.Safeguard) return;
|
|
1714
1705
|
// Freeze Clause Mod
|
|
1715
|
-
if (
|
|
1706
|
+
if (pkmn.options.mod) for (foe.pokemon) |p| if (Status.is(p.status, .FRZ)) return;
|
|
1716
1707
|
|
|
1717
1708
|
foe_stored.status = Status.init(.FRZ);
|
|
1718
1709
|
try options.log.status(.{ foe_ident, foe_stored.status, .None });
|
|
@@ -1741,7 +1732,7 @@ pub const Effects = struct {
|
|
|
1741
1732
|
state.bp *= 2;
|
|
1742
1733
|
assert(state.bp <= 160);
|
|
1743
1734
|
} else {
|
|
1744
|
-
state.damage
|
|
1735
|
+
state.damage = smul(state.damage, 2);
|
|
1745
1736
|
}
|
|
1746
1737
|
}
|
|
1747
1738
|
|
|
@@ -2212,7 +2203,7 @@ pub const Effects = struct {
|
|
|
2212
2203
|
|
|
2213
2204
|
pub fn pursuit(battle: anytype, player: Player, state: *State, _: anytype) !void {
|
|
2214
2205
|
// TODO: remove switching variable and just look at Choice saved in Battle struct?
|
|
2215
|
-
if (battle.foe(player).active.volatiles.switching) state.damage
|
|
2206
|
+
if (battle.foe(player).active.volatiles.switching) state.damage = smul(state.damage, 2);
|
|
2216
2207
|
}
|
|
2217
2208
|
|
|
2218
2209
|
pub const rage = struct {
|
|
@@ -2225,7 +2216,7 @@ pub const Effects = struct {
|
|
|
2225
2216
|
const side = battle.side(player);
|
|
2226
2217
|
|
|
2227
2218
|
assert(side.active.volatiles.Rage);
|
|
2228
|
-
state.damage
|
|
2219
|
+
state.damage = smul(state.damage, (side.active.volatiles.rage +| 1)); // TODO: |+
|
|
2229
2220
|
}
|
|
2230
2221
|
};
|
|
2231
2222
|
|
|
@@ -2320,7 +2311,7 @@ pub const Effects = struct {
|
|
|
2320
2311
|
side.active.volatiles.attacks += 1;
|
|
2321
2312
|
side.active.volatiles.Rollout = side.active.volatiles.attacks != 5;
|
|
2322
2313
|
|
|
2323
|
-
if (side.active.volatiles.DefenseCurl) state.damage
|
|
2314
|
+
if (side.active.volatiles.DefenseCurl) state.damage = smul(state.damage, 2);
|
|
2324
2315
|
}
|
|
2325
2316
|
};
|
|
2326
2317
|
|
|
@@ -2390,7 +2381,7 @@ pub const Effects = struct {
|
|
|
2390
2381
|
}
|
|
2391
2382
|
|
|
2392
2383
|
// Sleep Clause Mod
|
|
2393
|
-
if (
|
|
2384
|
+
if (pkmn.options.mod) {
|
|
2394
2385
|
for (foe.pokemon) |p| {
|
|
2395
2386
|
if (Status.is(p.status, .SLP) and !Status.is(p.status, .EXT)) return;
|
|
2396
2387
|
}
|
|
@@ -2848,6 +2839,12 @@ fn convertible(active: ActivePokemon, m: Move) bool {
|
|
|
2848
2839
|
return t != .@"???" and !active.types.includes(t);
|
|
2849
2840
|
}
|
|
2850
2841
|
|
|
2842
|
+
// NOTE: llvm/llvm-project#58557
|
|
2843
|
+
fn smul(a: anytype, b: @TypeOf(a)) @TypeOf(a) {
|
|
2844
|
+
if (!comptime builtin.target.isWasm()) return a *| b;
|
|
2845
|
+
return @max(a *% b, std.math.maxInt(@TypeOf(a)));
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2851
2848
|
pub const Rolls = struct {
|
|
2852
2849
|
fn speedTie(battle: anytype, options: anytype) !bool {
|
|
2853
2850
|
const p1 = if (options.calc.overridden(.P1, 0, .speed_tie)) |player|
|
package/src/lib/node.zig
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
|
|
3
|
-
const pkmn = @import("pkmn.zig");
|
|
4
|
-
|
|
5
1
|
const js = @import("common/js.zig");
|
|
2
|
+
const node = @import("bindings/node.zig");
|
|
3
|
+
const std = @import("std");
|
|
6
4
|
|
|
7
5
|
const assert = std.debug.assert;
|
|
8
6
|
|
|
@@ -13,119 +11,8 @@ const c = @cImport({
|
|
|
13
11
|
|
|
14
12
|
export fn napi_register_module_v1(env: c.napi_env, exports: c.napi_value) c.napi_value {
|
|
15
13
|
const properties = [_]c.napi_property_descriptor{
|
|
16
|
-
js.Property.init("engine", .{ .value = register(env) }),
|
|
14
|
+
js.Property.init("engine", .{ .value = node.register(env) }),
|
|
17
15
|
};
|
|
18
16
|
assert(c.napi_define_properties(env, exports, properties.len, &properties) == c.napi_ok);
|
|
19
17
|
return exports;
|
|
20
18
|
}
|
|
21
|
-
|
|
22
|
-
pub fn register(env: c.napi_env) c.napi_value {
|
|
23
|
-
const object = js.Object.init(env);
|
|
24
|
-
const properties = [_]c.napi_property_descriptor{
|
|
25
|
-
js.Property.init("options", .{ .value = options(env) }),
|
|
26
|
-
js.Property.init("bindings", .{ .value = bindings(env) }),
|
|
27
|
-
};
|
|
28
|
-
assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
|
|
29
|
-
return object;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
fn options(env: c.napi_env) c.napi_value {
|
|
33
|
-
const object = js.Object.init(env);
|
|
34
|
-
const properties = [_]c.napi_property_descriptor{
|
|
35
|
-
js.Property.init("showdown", .{ .value = js.Boolean.init(env, pkmn.options.showdown) }),
|
|
36
|
-
js.Property.init("log", .{ .value = js.Boolean.init(env, pkmn.options.log) }),
|
|
37
|
-
js.Property.init("chance", .{ .value = js.Boolean.init(env, pkmn.options.chance) }),
|
|
38
|
-
js.Property.init("calc", .{ .value = js.Boolean.init(env, pkmn.options.calc) }),
|
|
39
|
-
};
|
|
40
|
-
assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
|
|
41
|
-
return object;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
fn bindings(env: c.napi_env) c.napi_value {
|
|
45
|
-
const array = js.Array.init(env, .{ .length = 1 });
|
|
46
|
-
js.Array.set(env, array, 0, bind(env, pkmn.gen1));
|
|
47
|
-
return array;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
fn bind(env: c.napi_env, gen: anytype) c.napi_value {
|
|
51
|
-
const choices_size: u32 = @intCast(gen.CHOICES_SIZE);
|
|
52
|
-
const logs_size: u32 = @intCast(gen.LOGS_SIZE);
|
|
53
|
-
const object = js.Object.init(env);
|
|
54
|
-
const properties = [_]c.napi_property_descriptor{
|
|
55
|
-
js.Property.init("CHOICES_SIZE", .{ .value = js.Number.init(env, choices_size) }),
|
|
56
|
-
js.Property.init("LOGS_SIZE", .{ .value = js.Number.init(env, logs_size) }),
|
|
57
|
-
js.Property.init("update", .{ .method = update(gen) }),
|
|
58
|
-
js.Property.init("choices", .{ .method = choices(gen) }),
|
|
59
|
-
};
|
|
60
|
-
assert(c.napi_define_properties(env, object, properties.len, &properties) == c.napi_ok);
|
|
61
|
-
return object;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
fn update(gen: anytype) c.napi_callback {
|
|
65
|
-
return struct {
|
|
66
|
-
fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
|
|
67
|
-
var argc: usize = 4;
|
|
68
|
-
var argv: [4]c.napi_value = undefined;
|
|
69
|
-
assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
|
|
70
|
-
assert(argc == 4);
|
|
71
|
-
|
|
72
|
-
var data: ?*anyopaque = undefined;
|
|
73
|
-
var len: usize = 0;
|
|
74
|
-
assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
|
|
75
|
-
assert(len == @sizeOf(gen.Battle(gen.PRNG)));
|
|
76
|
-
|
|
77
|
-
var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
|
|
78
|
-
const c1: pkmn.Choice = @bitCast(js.Number.get(env, argv[1], u8));
|
|
79
|
-
const c2: pkmn.Choice = @bitCast(js.Number.get(env, argv[2], u8));
|
|
80
|
-
|
|
81
|
-
var vtype: c.napi_valuetype = undefined;
|
|
82
|
-
assert(c.napi_typeof(env, argv[3], &vtype) == c.napi_ok);
|
|
83
|
-
const result = switch (vtype) {
|
|
84
|
-
c.napi_undefined, c.napi_null => battle.update(c1, c2, &gen.NULL),
|
|
85
|
-
else => result: {
|
|
86
|
-
assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
|
|
87
|
-
assert(len == gen.LOGS_SIZE);
|
|
88
|
-
|
|
89
|
-
const buf = @as([*]u8, @ptrCast(data.?))[0..gen.LOGS_SIZE];
|
|
90
|
-
var stream: pkmn.protocol.ByteStream = .{ .buffer = buf };
|
|
91
|
-
// TODO: extract out
|
|
92
|
-
var opts = pkmn.battle.options(
|
|
93
|
-
pkmn.protocol.FixedLog{ .writer = stream.writer() },
|
|
94
|
-
gen.chance.NULL,
|
|
95
|
-
gen.calc.NULL,
|
|
96
|
-
);
|
|
97
|
-
break :result battle.update(c1, c2, &opts);
|
|
98
|
-
},
|
|
99
|
-
} catch unreachable;
|
|
100
|
-
|
|
101
|
-
return js.Number.init(env, @as(u8, @bitCast(result)));
|
|
102
|
-
}
|
|
103
|
-
}.call;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
fn choices(gen: anytype) c.napi_callback {
|
|
107
|
-
return struct {
|
|
108
|
-
fn call(env: c.napi_env, info: c.napi_callback_info) callconv(.C) c.napi_value {
|
|
109
|
-
var argc: usize = 4;
|
|
110
|
-
var argv: [4]c.napi_value = undefined;
|
|
111
|
-
assert(c.napi_get_cb_info(env, info, &argc, &argv, null, null) == c.napi_ok);
|
|
112
|
-
assert(argc == 4);
|
|
113
|
-
|
|
114
|
-
var data: ?*anyopaque = undefined;
|
|
115
|
-
var len: usize = 0;
|
|
116
|
-
assert(c.napi_get_arraybuffer_info(env, argv[0], &data, &len) == c.napi_ok);
|
|
117
|
-
assert(len == @sizeOf(gen.Battle(gen.PRNG)));
|
|
118
|
-
|
|
119
|
-
var battle: *gen.Battle(gen.PRNG) = @alignCast(@ptrCast(data.?));
|
|
120
|
-
const player: pkmn.Player = @enumFromInt(js.Number.get(env, argv[1], u8));
|
|
121
|
-
const request: pkmn.Choice.Type = @enumFromInt(js.Number.get(env, argv[2], u8));
|
|
122
|
-
|
|
123
|
-
assert(c.napi_get_arraybuffer_info(env, argv[3], &data, &len) == c.napi_ok);
|
|
124
|
-
assert(len == gen.CHOICES_SIZE);
|
|
125
|
-
|
|
126
|
-
const out = @as([*]pkmn.Choice, @ptrCast(data.?))[0..gen.CHOICES_SIZE];
|
|
127
|
-
const n = battle.choices(player, request, out);
|
|
128
|
-
return js.Number.init(env, @as(u8, @bitCast(n)));
|
|
129
|
-
}
|
|
130
|
-
}.call;
|
|
131
|
-
}
|
package/src/lib/pkmn.zig
CHANGED
|
@@ -96,6 +96,10 @@ pub const gen1 = struct {
|
|
|
96
96
|
/// though damage calculator support should additionally be turned off
|
|
97
97
|
/// entirely via `options.calc`.
|
|
98
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;
|
|
99
103
|
};
|
|
100
104
|
/// Provides helpers for initializing Generation I Pokémon battles.
|
|
101
105
|
pub const helpers = @import("gen1/helpers.zig");
|
|
@@ -125,6 +129,7 @@ pub const gen2 = struct {
|
|
|
125
129
|
// NOTE: `pub usingnamespace struct { ... }` here results in a (false?) dependency loop
|
|
126
130
|
pub const js = if (options.internal) @import("common/js.zig") else {};
|
|
127
131
|
pub const bindings = if (options.internal) struct {
|
|
128
|
-
pub const
|
|
129
|
-
pub const
|
|
132
|
+
pub const c = @import("bindings/c.zig");
|
|
133
|
+
pub const node = @import("bindings/node.zig");
|
|
134
|
+
pub const wasm = @import("bindings/wasm.zig");
|
|
130
135
|
} else {};
|
package/src/lib/wasm.zig
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
|
+
const wasm = @import("bindings/wasm.zig");
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
+
export const SHOWDOWN = wasm.options.showdown;
|
|
5
|
+
export const LOG = wasm.options.log;
|
|
6
|
+
export const CHANCE = wasm.options.chance;
|
|
7
|
+
export const CALC = wasm.options.calc;
|
|
4
8
|
|
|
5
|
-
export const
|
|
6
|
-
export const
|
|
7
|
-
export const CHANCE = pkmn.options.chance;
|
|
8
|
-
export const CALC = pkmn.options.calc;
|
|
9
|
+
export const GEN1_CHOICES_SIZE = wasm.gen(1).CHOICES_SIZE;
|
|
10
|
+
export const GEN1_LOGS_SIZE = wasm.gen(1).LOGS_SIZE;
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const exportable = @hasDecl(std.zig, "Zir") and !@hasField(std.zig.Zir.Inst.Tag, "export_value");
|
|
13
|
+
|
|
14
|
+
usingnamespace if (exportable) struct {
|
|
15
|
+
export const GEN1_update = wasm.gen(1).update;
|
|
16
|
+
export const GEN1_choices = wasm.gen(1).choices;
|
|
17
|
+
} else wasm.exports();
|
|
@@ -0,0 +1,95 @@
|
|
|
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 = (props: {children: any}) => props.children as Fragment;
|