@pkmn/engine 0.1.0-dev.d56bdadd → 0.1.0-dev.d73cd76c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -3
- package/README.md +66 -32
- 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 +26 -4
- package/build/pkg/addon.js +39 -71
- 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 +27 -5
- 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 +42 -91
- package/build/pkg/index.js +23 -70
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +29 -1
- package/build/pkg/protocol.js +109 -107
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +84 -73
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +66 -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 +360 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +157 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +357 -135
- package/package.json +61 -132
- package/src/bin/install-pkmn-engine +47 -21
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/bindings/c.zig +201 -0
- package/src/lib/{binding → bindings}/node.zig +15 -32
- package/src/lib/bindings/wasm.zig +51 -0
- package/src/lib/common/array.zig +70 -0
- package/src/lib/common/data.zig +4 -4
- package/src/lib/common/debug.zig +45 -29
- package/src/lib/common/js.zig +3 -7
- package/src/lib/common/optional.zig +27 -23
- package/src/lib/common/options.zig +6 -0
- package/src/lib/common/protocol.zig +565 -552
- package/src/lib/common/rational.zig +340 -253
- package/src/lib/common/rng.zig +7 -9
- package/src/lib/common/util.zig +53 -1
- package/src/lib/gen1/calc.zig +724 -175
- package/src/lib/gen1/chance.zig +486 -300
- package/src/lib/gen1/data/moves.zig +2 -4
- package/src/lib/gen1/data/species.zig +2 -4
- package/src/lib/gen1/data/types.zig +3 -4
- package/src/lib/gen1/data.zig +29 -32
- package/src/lib/gen1/helpers.zig +113 -561
- package/src/lib/gen1/mechanics.zig +611 -488
- package/src/lib/gen2/calc.zig +35 -28
- package/src/lib/gen2/chance.zig +111 -511
- 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 +7 -5
- package/src/lib/gen2/data.zig +27 -29
- package/src/lib/gen2/generated.zig +22 -29
- package/src/lib/gen2/helpers.zig +68 -39
- package/src/lib/gen2/mechanics.zig +504 -430
- package/src/lib/napi.h +2 -0
- package/src/lib/node.zig +14 -0
- package/src/lib/pkmn.zig +125 -29
- package/src/lib/wasm.zig +13 -0
- package/src/tools/display/dom.ts +108 -0
- package/src/tools/display/ui.css +354 -0
- package/build/test/display.js +0 -400
- package/build/test/display.js.map +0 -1
- package/src/lib/binding/wasm.zig +0 -12
- package/src/lib/gen1/README.md +0 -894
- package/src/lib/gen2/README.md +0 -329
- package/src/test/display/pkmn.html.tmpl +0 -368
package/src/lib/napi.h
ADDED
package/src/lib/node.zig
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const c = @import("napi");
|
|
2
|
+
const js = @import("common/js.zig");
|
|
3
|
+
const node = @import("bindings/node.zig");
|
|
4
|
+
const std = @import("std");
|
|
5
|
+
|
|
6
|
+
const assert = std.debug.assert;
|
|
7
|
+
|
|
8
|
+
export fn napi_register_module_v1(env: c.napi_env, exports: c.napi_value) c.napi_value {
|
|
9
|
+
const properties = [_]c.napi_property_descriptor{
|
|
10
|
+
js.Property.init("engine", .{ .value = node.register(env) }),
|
|
11
|
+
};
|
|
12
|
+
assert(c.napi_define_properties(env, exports, properties.len, &properties) == c.napi_ok);
|
|
13
|
+
return exports;
|
|
14
|
+
}
|
package/src/lib/pkmn.zig
CHANGED
|
@@ -22,38 +22,88 @@ 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
|
+
/// Helpers for working with bit-packed arrays of non-powers-of-2 types.
|
|
26
|
+
pub const Array = @import("common/array.zig").Array;
|
|
27
|
+
/// Optimized optional representation which stores the empty None value as a sentinel.
|
|
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
|
|
|
28
33
|
/// Namespace for helpers related to protocol message logging.
|
|
29
|
-
pub const protocol = if (options.internal) struct {
|
|
30
|
-
|
|
31
|
-
} else struct {
|
|
32
|
-
/// Logs protocol information to its `Writer` during a battle update when
|
|
34
|
+
pub const protocol = if (options.internal) @import("common/protocol.zig") else struct {
|
|
35
|
+
/// Logs protocol information to its `WriterT` during a battle update when
|
|
33
36
|
/// `options.log` is enabled.
|
|
34
37
|
pub const Log = @import("common/protocol.zig").Log;
|
|
35
|
-
///
|
|
36
|
-
///
|
|
37
|
-
/// `ByteStream.Writer` is **not** a `std.io.Writer` and should not be
|
|
38
|
-
/// used for general purpose writing.
|
|
39
|
-
pub const ByteStream = @import("common/protocol.zig").ByteStream;
|
|
40
|
-
/// `Log` type backed by the optimized `ByteStream.Writer`. Intended to be
|
|
41
|
-
/// intialized with a `LOGS_SIZE`-sized buffer.
|
|
38
|
+
/// `Log` type backed by the optimized `Writer`. Intended to be intialized with
|
|
39
|
+
/// a `LOGS_SIZE`-sized buffer.
|
|
42
40
|
pub const FixedLog = @import("common/protocol.zig").FixedLog;
|
|
43
|
-
///
|
|
44
|
-
///
|
|
45
|
-
///
|
|
41
|
+
/// Minimal logging helper optimized for efficiently writing the individual
|
|
42
|
+
/// protocol bytes into a fixed buffer. Note that this is **not** a
|
|
43
|
+
/// `std.Io.Writer` and should not be used for general purpose writing.
|
|
44
|
+
pub const Writer = @import("common/protocol.zig").Writer;
|
|
45
|
+
/// Null object pattern implementation of `Log` backed by a null writer.
|
|
46
|
+
/// Ignores anything sent to it, though protocol logging should additionally
|
|
47
|
+
/// be turned off entirely with `options.log`.
|
|
46
48
|
pub const NULL = @import("common/protocol.zig").NULL;
|
|
47
49
|
};
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
/// Specialization of a rational number used by the engine to compute probabilties.
|
|
52
|
+
pub const Rational = @import("common/rational.zig").Rational;
|
|
50
53
|
|
|
51
54
|
/// Namespace for cross-generation battle-related types.
|
|
52
55
|
pub const battle = @import("common/battle.zig");
|
|
53
56
|
|
|
54
57
|
/// Namespace for Generation I Pokémon.
|
|
55
58
|
pub const gen1 = struct {
|
|
56
|
-
|
|
59
|
+
const data = @import("gen1/data.zig");
|
|
60
|
+
/// The minimum size in bytes required to hold all Generation I choice options.
|
|
61
|
+
pub const MAX_CHOICES = data.MAX_CHOICES;
|
|
62
|
+
/// The maximum number of bytes possibly logged by a single Generation I update.
|
|
63
|
+
pub const MAX_LOGS = data.MAX_LOGS;
|
|
64
|
+
/// The optimal size in bytes required to hold all Generation I choice options.
|
|
65
|
+
/// At least as large as MAX_CHOICES.
|
|
66
|
+
pub const CHOICES_SIZE = data.CHOICES_SIZE;
|
|
67
|
+
/// The optimal size in bytes required to hold the largest amount of log data possible from a
|
|
68
|
+
/// single Generation I update. At least as large as MAX_LOGS.
|
|
69
|
+
pub const LOGS_SIZE = data.LOGS_SIZE;
|
|
70
|
+
/// Null object pattern implementation of pkmn.battle.Options for Generation I.
|
|
71
|
+
pub const NULL = data.NULL;
|
|
72
|
+
/// The pseudo random number generator used by Generation I.
|
|
73
|
+
pub const PRNG = data.PRNG;
|
|
74
|
+
/// Representation of a Generation I battle.
|
|
75
|
+
pub const Battle = data.Battle;
|
|
76
|
+
/// Representation of one side of a Generation I Pokémon battle.
|
|
77
|
+
pub const Side = data.Side;
|
|
78
|
+
/// Representation of the state for single Generation I Pokémon while active in battle.
|
|
79
|
+
pub const ActivePokemon = data.ActivePokemon;
|
|
80
|
+
/// Representation of the state for single Generation I Pokémon while inactive in the party.
|
|
81
|
+
pub const Pokemon = data.Pokemon;
|
|
82
|
+
/// Representation of a Generation I Pokémon's move slot in a battle.
|
|
83
|
+
pub const MoveSlot = data.MoveSlot;
|
|
84
|
+
/// Details required to detect desyncs based on the move last selected/executed by players.
|
|
85
|
+
pub const MoveDetails = data.MoveDetails;
|
|
86
|
+
/// Bitfield representation of a Generation I & II Pokémon's major status condition.
|
|
87
|
+
pub const Status = data.Status;
|
|
88
|
+
/// Bitfield representation of volatile statuses and associated data in Generation I.
|
|
89
|
+
pub const Volatiles = data.Volatiles;
|
|
90
|
+
/// Representation of a Pokémon's stats in Generation I.
|
|
91
|
+
pub const Stats = data.Stats;
|
|
92
|
+
/// Representation of a Pokémon's boosts in Generation I.
|
|
93
|
+
pub const Boosts = data.Boosts;
|
|
94
|
+
/// Representation of a Generation I Pokémon move.
|
|
95
|
+
pub const Move = data.Move;
|
|
96
|
+
/// Representation of a Generation I Pokémon species.
|
|
97
|
+
pub const Species = data.Species;
|
|
98
|
+
/// Representation of a Generation I type in Pokémon.
|
|
99
|
+
pub const Type = data.Type;
|
|
100
|
+
/// Representation of a Generation I Pokémon's typing.
|
|
101
|
+
pub const Types = data.Types;
|
|
102
|
+
/// Modifiers for the effectiveness of a type vs. another type in Pokémon.
|
|
103
|
+
pub const Effectiveness = data.Effectiveness;
|
|
104
|
+
/// Representation of a Generation I Pokémon's determinant values.
|
|
105
|
+
pub const DVs = data.DVs;
|
|
106
|
+
|
|
57
107
|
/// Tracks chance actions and their associated probability during a
|
|
58
108
|
/// Generation I battle update when `options.chance` is enabled.
|
|
59
109
|
pub const Chance = @import("gen1/chance.zig").Chance;
|
|
@@ -82,32 +132,78 @@ pub const gen1 = struct {
|
|
|
82
132
|
/// via `overrides` and tracks `summaries` of information relevant to damage calculation.
|
|
83
133
|
pub const Calc = @import("gen1/calc.zig").Calc;
|
|
84
134
|
/// Namespace for types associated with supported Generation I Pokémon damage calc features.
|
|
85
|
-
pub const calc = if (options.internal) struct {
|
|
86
|
-
pub usingnamespace @import("gen1/calc.zig");
|
|
87
|
-
} else struct {
|
|
88
|
-
/// TODO
|
|
89
|
-
pub const Overrides = @import("gen1/calc.zig").Overrides;
|
|
135
|
+
pub const calc = if (options.internal) @import("gen1/calc.zig") else struct {
|
|
90
136
|
/// Information relevant to damage calculation that occured during a Generation I
|
|
91
137
|
/// battle `update`.
|
|
92
138
|
pub const Summaries = @import("gen1/calc.zig").Summaries;
|
|
93
139
|
/// Information relevant to damage calculation that occured during a Generation I
|
|
94
|
-
///
|
|
140
|
+
/// battle `update` for a single player.
|
|
95
141
|
pub const Summary = @import("gen1/calc.zig").Summary;
|
|
96
142
|
/// Null object pattern implementation of Generation I `Calc` which does nothing,
|
|
97
143
|
/// though damage calculator support should additionally be turned off
|
|
98
144
|
/// entirely via `options.calc`.
|
|
99
145
|
pub const NULL = @import("gen1/calc.zig").NULL;
|
|
146
|
+
/// TODO
|
|
147
|
+
pub const MAX_FRONTIER = @import("gen1/calc.zig").MAX_FRONTIER;
|
|
148
|
+
/// TODO
|
|
149
|
+
pub const Rolls = @import("gen1/calc.zig").Rolls;
|
|
100
150
|
};
|
|
101
151
|
/// Provides helpers for initializing Generation I Pokémon battles.
|
|
102
152
|
pub const helpers = @import("gen1/helpers.zig");
|
|
103
153
|
};
|
|
104
154
|
|
|
155
|
+
/// TODO
|
|
156
|
+
pub const gen2 = struct {
|
|
157
|
+
const data = @import("gen2/data.zig");
|
|
158
|
+
pub const MAX_CHOICES = data.MAX_CHOICES;
|
|
159
|
+
pub const MAX_LOGS = data.MAX_LOGS;
|
|
160
|
+
pub const CHOICES_SIZE = data.CHOICES_SIZE;
|
|
161
|
+
pub const LOGS_SIZE = data.LOGS_SIZE;
|
|
162
|
+
pub const NULL = data.NULL;
|
|
163
|
+
pub const PRNG = data.PRNG;
|
|
164
|
+
pub const Battle = data.Battle;
|
|
165
|
+
pub const Field = data.Field;
|
|
166
|
+
pub const Weather = data.Weather;
|
|
167
|
+
pub const Side = data.Side;
|
|
168
|
+
pub const ActivePokemon = data.ActivePokemon;
|
|
169
|
+
pub const Pokemon = data.Pokemon;
|
|
170
|
+
pub const Gender = data.Gender;
|
|
171
|
+
pub const DVs = data.DVs;
|
|
172
|
+
pub const MoveSlot = data.MoveSlot;
|
|
173
|
+
pub const Status = data.Status;
|
|
174
|
+
pub const TriAttack = data.TriAttack;
|
|
175
|
+
pub const Volatiles = data.Volatiles;
|
|
176
|
+
pub const Stats = data.Stats;
|
|
177
|
+
pub const Boosts = data.Boosts;
|
|
178
|
+
pub const Item = data.Item;
|
|
179
|
+
pub const Move = data.Move;
|
|
180
|
+
pub const Species = data.Species;
|
|
181
|
+
pub const Type = data.Type;
|
|
182
|
+
pub const Types = data.Types;
|
|
183
|
+
pub const Effectiveness = data.Effectiveness;
|
|
184
|
+
|
|
185
|
+
pub const Chance = @import("gen2/chance.zig").Chance;
|
|
186
|
+
pub const chance = struct {
|
|
187
|
+
pub const Actions = @import("gen2/chance.zig").Actions;
|
|
188
|
+
pub const Action = @import("gen2/chance.zig").Action;
|
|
189
|
+
pub const Durations = @import("gen2/chance.zig").Durations;
|
|
190
|
+
pub const Duration = @import("gen2/chance.zig").Duration;
|
|
191
|
+
pub const NULL = @import("gen2/chance.zig").NULL;
|
|
192
|
+
};
|
|
193
|
+
pub const Calc = @import("gen2/calc.zig").Calc;
|
|
194
|
+
pub const calc = if (options.internal) @import("gen2/calc.zig") else struct {
|
|
195
|
+
pub const Summaries = @import("gen2/calc.zig").Summaries;
|
|
196
|
+
pub const Summary = @import("gen2/calc.zig").Summary;
|
|
197
|
+
pub const NULL = @import("gen2/calc.zig").NULL;
|
|
198
|
+
};
|
|
199
|
+
pub const helpers = @import("gen2/helpers.zig");
|
|
200
|
+
};
|
|
201
|
+
|
|
105
202
|
// Internal APIs used by other pkmn libraries, not actually part of the public API.
|
|
106
|
-
|
|
107
|
-
pub const
|
|
108
|
-
pub usingnamespace @import("common/js.zig");
|
|
109
|
-
} else struct {};
|
|
203
|
+
pub const js = if (options.internal) @import("common/js.zig") else {};
|
|
204
|
+
pub const util = if (options.internal) @import("common/util.zig") else {};
|
|
110
205
|
pub const bindings = if (options.internal) struct {
|
|
111
|
-
pub const
|
|
112
|
-
pub const
|
|
113
|
-
|
|
206
|
+
pub const c = @import("bindings/c.zig");
|
|
207
|
+
pub const node = @import("bindings/node.zig");
|
|
208
|
+
pub const wasm = @import("bindings/wasm.zig");
|
|
209
|
+
} else {};
|
package/src/lib/wasm.zig
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const wasm = @import("bindings/wasm.zig");
|
|
3
|
+
|
|
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;
|
|
8
|
+
|
|
9
|
+
export const GEN1_CHOICES_SIZE = wasm.gen(1).CHOICES_SIZE;
|
|
10
|
+
export const GEN1_LOGS_SIZE = wasm.gen(1).LOGS_SIZE;
|
|
11
|
+
|
|
12
|
+
export const GEN1_update = wasm.gen(1).update;
|
|
13
|
+
export const GEN1_choices = wasm.gen(1).choices;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/** @license MIT modified from Vadim Demedes's https://github.com/vadimdemedes/dom-chef */
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
namespace JSX {
|
|
5
|
+
type Element = HTMLElement | DocumentFragment;
|
|
6
|
+
interface IntrinsicElements {
|
|
7
|
+
[elemName: string]: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type Child = Node | string | number | boolean | null | undefined | Child[];
|
|
13
|
+
|
|
14
|
+
type DocumentFragmentFunction = (props?: any) => DocumentFragment;
|
|
15
|
+
type ElementFunction = (props?: any) => HTMLElement;
|
|
16
|
+
|
|
17
|
+
// https://github.com/preactjs/preact/blob/1bbd687c/src/constants.js#L3
|
|
18
|
+
const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
|
|
19
|
+
|
|
20
|
+
const setCSSProps = (element: HTMLElement, style: CSSStyleDeclaration) => {
|
|
21
|
+
for (const [name, value] of Object.entries(style)) {
|
|
22
|
+
if (name.startsWith('-')) {
|
|
23
|
+
element.style.setProperty(name, value);
|
|
24
|
+
} else if (typeof value === 'number' && !IS_NON_DIMENSIONAL.test(name)) {
|
|
25
|
+
element.style[name as any] = `${value as string}px`;
|
|
26
|
+
} else {
|
|
27
|
+
element.style[name as any] = value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const setAttribute = (element: HTMLElement, name: string, value: string) => {
|
|
33
|
+
if (value !== undefined && value !== null) element.setAttribute(name, value);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const addChildren = (parent: Node, children: Child[]) => {
|
|
37
|
+
for (const child of children) {
|
|
38
|
+
if (child instanceof Node) {
|
|
39
|
+
parent.appendChild(child);
|
|
40
|
+
} else if (Array.isArray(child)) {
|
|
41
|
+
addChildren(parent, child);
|
|
42
|
+
} else if (typeof child !== 'boolean' && typeof child !== 'undefined' && child !== null) {
|
|
43
|
+
parent.appendChild(document.createTextNode(String(child)));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// https://github.com/facebook/react/blob/3f899089/packages/react-dom/src/shared/DOMProperty.js#L288-L322
|
|
49
|
+
const FALSIFIABLE_ATTRIBUTES = ['contentEditable', 'draggable', 'spellCheck', 'value'];
|
|
50
|
+
|
|
51
|
+
export function h<K extends keyof HTMLElementTagNameMap>(
|
|
52
|
+
type: K,
|
|
53
|
+
attributes?: any,
|
|
54
|
+
...children: Child[]
|
|
55
|
+
): HTMLElementTagNameMap[K];
|
|
56
|
+
export function h(
|
|
57
|
+
type: DocumentFragmentFunction,
|
|
58
|
+
attributes?: any,
|
|
59
|
+
...children: Child[]
|
|
60
|
+
): DocumentFragment;
|
|
61
|
+
export function h<T extends HTMLElement>(
|
|
62
|
+
type: (props: any) => T,
|
|
63
|
+
attributes?: any,
|
|
64
|
+
...children: Child[]
|
|
65
|
+
): T;
|
|
66
|
+
export function h(
|
|
67
|
+
type: string,
|
|
68
|
+
attributes?: any,
|
|
69
|
+
...children: Child[]
|
|
70
|
+
): HTMLElement;
|
|
71
|
+
export function h(
|
|
72
|
+
type: DocumentFragmentFunction | ElementFunction | string,
|
|
73
|
+
attributes?: any,
|
|
74
|
+
...children: Child[]
|
|
75
|
+
): JSX.Element {
|
|
76
|
+
if (typeof type !== 'string') {
|
|
77
|
+
const element = type(attributes);
|
|
78
|
+
addChildren(element, children);
|
|
79
|
+
return element;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const element = document.createElement(type);
|
|
83
|
+
addChildren(element, children);
|
|
84
|
+
if (!attributes) return element;
|
|
85
|
+
|
|
86
|
+
for (let [name, value] of Object.entries(attributes)) {
|
|
87
|
+
if (name === 'htmlFor') name = 'for';
|
|
88
|
+
|
|
89
|
+
if (name === 'class' || name === 'className') {
|
|
90
|
+
const existingClassname = element.getAttribute('class') ?? '';
|
|
91
|
+
setAttribute(element, 'class', (existingClassname + ' ' + String(value)).trim());
|
|
92
|
+
} else if (name === 'style') {
|
|
93
|
+
setCSSProps(element, value as CSSStyleDeclaration);
|
|
94
|
+
} else if (name.startsWith('on')) {
|
|
95
|
+
const eventName = name.slice(2).toLowerCase().replace(/^-/, '');
|
|
96
|
+
element.addEventListener(eventName, value as EventListenerOrEventListenerObject);
|
|
97
|
+
} else if (name === 'dangerouslySetInnerHTML' && value && (value as any).__html) {
|
|
98
|
+
element.innerHTML = (value as any).__html;
|
|
99
|
+
} else if (name !== 'key' && (FALSIFIABLE_ATTRIBUTES.includes(name) || value !== false)) {
|
|
100
|
+
setAttribute(element, name, value === true ? '' : String(value));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return element;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
108
|
+
export const Fragment = (unused?: any) => document.createDocumentFragment();
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
body {
|
|
2
|
+
background: white;
|
|
3
|
+
color: black;
|
|
4
|
+
}
|
|
5
|
+
code {
|
|
6
|
+
background: white;
|
|
7
|
+
color: black;
|
|
8
|
+
}
|
|
9
|
+
#content {
|
|
10
|
+
font-family: "Roboto", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
|
|
11
|
+
margin: 4em auto;
|
|
12
|
+
max-width: 1300px;
|
|
13
|
+
line-height: 1.4em;
|
|
14
|
+
--hp-bar: 151px;
|
|
15
|
+
--hp-text: 32px;
|
|
16
|
+
--radius: 10px;
|
|
17
|
+
}
|
|
18
|
+
details > summary {
|
|
19
|
+
list-style: none;
|
|
20
|
+
}
|
|
21
|
+
details > summary::-webkit-details-marker {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
24
|
+
.battle > .details {
|
|
25
|
+
background: #eee;
|
|
26
|
+
border-bottom: 3px solid black;
|
|
27
|
+
border-radius: var(--radius) var(--radius) 0 0;
|
|
28
|
+
padding: 0 1em;
|
|
29
|
+
display: flex;
|
|
30
|
+
justify-content: space-between;
|
|
31
|
+
}
|
|
32
|
+
.inner {
|
|
33
|
+
display: flex;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
}
|
|
37
|
+
.side > .details {
|
|
38
|
+
padding: 0.5em 1em;
|
|
39
|
+
display: flex;
|
|
40
|
+
justify-content: space-between;
|
|
41
|
+
text-align: center;
|
|
42
|
+
flex: 0 1 auto;
|
|
43
|
+
}
|
|
44
|
+
.active {
|
|
45
|
+
flex: 1 1 auto;
|
|
46
|
+
}
|
|
47
|
+
details {
|
|
48
|
+
flex: 0 1 auto;
|
|
49
|
+
}
|
|
50
|
+
.sides {
|
|
51
|
+
display: flex;
|
|
52
|
+
}
|
|
53
|
+
.side {
|
|
54
|
+
flex: 1;
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-flow: column;
|
|
57
|
+
}
|
|
58
|
+
.side.p1 {
|
|
59
|
+
border-right: 1px solid black;
|
|
60
|
+
}
|
|
61
|
+
.battle {
|
|
62
|
+
border: 3px solid black;
|
|
63
|
+
border-radius: var(--radius);
|
|
64
|
+
}
|
|
65
|
+
summary {
|
|
66
|
+
border-top: 1px solid #eee;
|
|
67
|
+
text-align: center;
|
|
68
|
+
padding: 0.25em;
|
|
69
|
+
}
|
|
70
|
+
.good {
|
|
71
|
+
color: green;
|
|
72
|
+
}
|
|
73
|
+
.bad {
|
|
74
|
+
color: red;
|
|
75
|
+
}
|
|
76
|
+
.pokemon {
|
|
77
|
+
position: relative;
|
|
78
|
+
padding: 0.5em 1em;
|
|
79
|
+
border-top: 1px solid black;
|
|
80
|
+
display: flex;
|
|
81
|
+
}
|
|
82
|
+
.active > .pokemon {
|
|
83
|
+
border-top: 1px solid #eee;
|
|
84
|
+
}
|
|
85
|
+
table {
|
|
86
|
+
border-collapse: collapse;
|
|
87
|
+
border-style: hidden;
|
|
88
|
+
border-spacing: 0px;
|
|
89
|
+
line-height: 1.5em;
|
|
90
|
+
}
|
|
91
|
+
th, td {
|
|
92
|
+
border: 1px solid black;
|
|
93
|
+
padding: 0 0.5em;
|
|
94
|
+
}
|
|
95
|
+
.statbar {
|
|
96
|
+
display: none;
|
|
97
|
+
width: calc(var(--hp-bar) + var(--hp-text));
|
|
98
|
+
padding: 2px 0;
|
|
99
|
+
line-height: normal;
|
|
100
|
+
}
|
|
101
|
+
.statbar .name {
|
|
102
|
+
display: block;
|
|
103
|
+
text-align: center;
|
|
104
|
+
line-height: 1.25em;
|
|
105
|
+
}
|
|
106
|
+
.statbar strong {
|
|
107
|
+
color: #222222;
|
|
108
|
+
text-shadow:
|
|
109
|
+
#FFFFFF 1px 1px 0, #FFFFFF 1px -1px 0,
|
|
110
|
+
#FFFFFF -1px 1px 0, #FFFFFF -1px -1px 0;
|
|
111
|
+
}
|
|
112
|
+
.statbar strong small {
|
|
113
|
+
font-weight: normal;
|
|
114
|
+
}
|
|
115
|
+
.statbar .hpbar {
|
|
116
|
+
position: relative;
|
|
117
|
+
border: 1px solid #777777;
|
|
118
|
+
background: #FCFEFF;
|
|
119
|
+
padding: 1px;
|
|
120
|
+
height: 8px;
|
|
121
|
+
margin: 0 0 0 0;
|
|
122
|
+
width: calc(var(--hp-bar) + var(--hp-text) + 1px);
|
|
123
|
+
border-radius: 4px;
|
|
124
|
+
}
|
|
125
|
+
.statbar .hpbar .hp {
|
|
126
|
+
height: 4px;
|
|
127
|
+
border-top: 2px solid #00dd60;
|
|
128
|
+
background: #00bb51;
|
|
129
|
+
border-bottom: 2px solid #007734;
|
|
130
|
+
border-right: 1px solid #007734;
|
|
131
|
+
border-radius: 3px;
|
|
132
|
+
}
|
|
133
|
+
.statbar .hpbar .hp-yellow {
|
|
134
|
+
border-top-color: #f8e379;
|
|
135
|
+
background-color: #f5d538;
|
|
136
|
+
border-bottom-color: #be9f0a;
|
|
137
|
+
border-right-color: #be9f0a;
|
|
138
|
+
}
|
|
139
|
+
.statbar .hpbar .hp-red {
|
|
140
|
+
border-top-color: #f37f67;
|
|
141
|
+
background-color: #ee4928;
|
|
142
|
+
border-bottom-color: #a3260d;
|
|
143
|
+
border-right-color: #a3260d;
|
|
144
|
+
}
|
|
145
|
+
.statbar .hpbar .prevhp {
|
|
146
|
+
background: #BBEECC;
|
|
147
|
+
height: 8px;
|
|
148
|
+
border-radius: 3px;
|
|
149
|
+
}
|
|
150
|
+
.statbar .hpbar .prevhp-yellow {
|
|
151
|
+
background-color: #fcf4ca;
|
|
152
|
+
}
|
|
153
|
+
.statbar .hpbar .prevhp-red {
|
|
154
|
+
background-color: #facec5;
|
|
155
|
+
}
|
|
156
|
+
.statbar .hpbar .hptext {
|
|
157
|
+
position: absolute;
|
|
158
|
+
background: #777777;
|
|
159
|
+
color: #EEEEEE;
|
|
160
|
+
text-shadow: #000000 0 1px 0;
|
|
161
|
+
font-size: 10px;
|
|
162
|
+
width: 32px;
|
|
163
|
+
height: 12px;
|
|
164
|
+
top: -1px;
|
|
165
|
+
text-align: center;
|
|
166
|
+
}
|
|
167
|
+
.status, .volatile {
|
|
168
|
+
padding: 0px 1px;
|
|
169
|
+
border: 1px solid #FF4400;
|
|
170
|
+
border-radius: 3px;
|
|
171
|
+
}
|
|
172
|
+
.status {
|
|
173
|
+
min-height: 10px;
|
|
174
|
+
font-size: 7pt;
|
|
175
|
+
vertical-align: middle;
|
|
176
|
+
padding: 1px 2px;
|
|
177
|
+
border: 0;
|
|
178
|
+
border-radius: 3px;
|
|
179
|
+
text-transform: uppercase;
|
|
180
|
+
margin: 0 2px;
|
|
181
|
+
}
|
|
182
|
+
.status.brn {
|
|
183
|
+
background: #EE5533;
|
|
184
|
+
color: #FFFFFF;
|
|
185
|
+
}
|
|
186
|
+
.status.psn {
|
|
187
|
+
background: #A4009A;
|
|
188
|
+
color: #FFFFFF;
|
|
189
|
+
}
|
|
190
|
+
.status.par {
|
|
191
|
+
background: #9AA400;
|
|
192
|
+
color: #FFFFFF;
|
|
193
|
+
}
|
|
194
|
+
.status.slp {
|
|
195
|
+
background: #AA77AA;
|
|
196
|
+
color: #FFFFFF;
|
|
197
|
+
}
|
|
198
|
+
.status.frz {
|
|
199
|
+
background: #009AA4;
|
|
200
|
+
color: #FFFFFF;
|
|
201
|
+
}
|
|
202
|
+
.volatile {
|
|
203
|
+
display: inline-block;
|
|
204
|
+
padding: 0 5px;
|
|
205
|
+
margin: 2px
|
|
206
|
+
}
|
|
207
|
+
.volatile.bad {
|
|
208
|
+
background: #FFE5E0;
|
|
209
|
+
color: #FF4400;
|
|
210
|
+
border-color: #FF4400;
|
|
211
|
+
}
|
|
212
|
+
.volatile.good {
|
|
213
|
+
background: #E5FFE0;
|
|
214
|
+
color: #33AA00;
|
|
215
|
+
border-color: #33AA00;
|
|
216
|
+
}
|
|
217
|
+
.volatile.neutral {
|
|
218
|
+
background: #F0F0F0;
|
|
219
|
+
color: #555555;
|
|
220
|
+
border-color: #555555;
|
|
221
|
+
}
|
|
222
|
+
.rstatbar .hpbar .hptext {
|
|
223
|
+
right: 0px;
|
|
224
|
+
border-radius: 0 4px 4px 0;
|
|
225
|
+
}
|
|
226
|
+
.moves ul {
|
|
227
|
+
display: grid;
|
|
228
|
+
grid-template-columns: repeat(2, auto);
|
|
229
|
+
gap: 0 2em;
|
|
230
|
+
}
|
|
231
|
+
.left {
|
|
232
|
+
padding-right: 32px;
|
|
233
|
+
display: flex;
|
|
234
|
+
flex-direction: column;
|
|
235
|
+
align-items: center;
|
|
236
|
+
}
|
|
237
|
+
.stats {
|
|
238
|
+
display: flex;
|
|
239
|
+
padding: 0 1em;
|
|
240
|
+
justify-content: space-between;
|
|
241
|
+
text-align: center;
|
|
242
|
+
width: 100%;
|
|
243
|
+
}
|
|
244
|
+
.boosts {
|
|
245
|
+
margin: 0 5px;
|
|
246
|
+
}
|
|
247
|
+
.types {
|
|
248
|
+
display: inherit;
|
|
249
|
+
}
|
|
250
|
+
.disabled {
|
|
251
|
+
color: #AAAAAA;
|
|
252
|
+
}
|
|
253
|
+
.position {
|
|
254
|
+
position: absolute;
|
|
255
|
+
right: 10px;
|
|
256
|
+
color: #AAAAAA;
|
|
257
|
+
}
|
|
258
|
+
.left .position {
|
|
259
|
+
display: none;
|
|
260
|
+
}
|
|
261
|
+
.right .position {
|
|
262
|
+
display: block;
|
|
263
|
+
}
|
|
264
|
+
.teamicons {
|
|
265
|
+
display: inline-block;
|
|
266
|
+
}
|
|
267
|
+
@media(max-width: 1300px) {
|
|
268
|
+
#content {
|
|
269
|
+
font-size: 0.85em;
|
|
270
|
+
max-width: 95%;
|
|
271
|
+
margin: 2em auto;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
@media(max-width: 1200px) {
|
|
275
|
+
.moves ul {
|
|
276
|
+
grid-template-columns: repeat(1, auto);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
@media(max-width: 1100px) {
|
|
280
|
+
.pokemon {
|
|
281
|
+
flex-direction: column;
|
|
282
|
+
}
|
|
283
|
+
.stats {
|
|
284
|
+
justify-content: center;
|
|
285
|
+
padding: 0;
|
|
286
|
+
}
|
|
287
|
+
.moves ul {
|
|
288
|
+
grid-template-columns: repeat(2, auto);
|
|
289
|
+
}
|
|
290
|
+
.left {
|
|
291
|
+
padding-right: 0;
|
|
292
|
+
}
|
|
293
|
+
.right {
|
|
294
|
+
padding-top: 1em;
|
|
295
|
+
}
|
|
296
|
+
.volatiles {
|
|
297
|
+
display: flex;
|
|
298
|
+
justify-content: center;
|
|
299
|
+
flex-wrap: wrap;
|
|
300
|
+
}
|
|
301
|
+
.left .position {
|
|
302
|
+
display: block;
|
|
303
|
+
}
|
|
304
|
+
.right .position {
|
|
305
|
+
display: none;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
@media(max-width: 800px) {
|
|
309
|
+
.moves {
|
|
310
|
+
display: flex;
|
|
311
|
+
justify-content: center;
|
|
312
|
+
}
|
|
313
|
+
.moves ul {
|
|
314
|
+
display: inline-block;
|
|
315
|
+
padding: 0;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
@media(max-width: 680px) {
|
|
319
|
+
.stats {
|
|
320
|
+
flex-direction: column;
|
|
321
|
+
padding: 0;
|
|
322
|
+
}
|
|
323
|
+
.boosts {
|
|
324
|
+
display: flex;
|
|
325
|
+
justify-content: space-between;
|
|
326
|
+
margin: 0.5em 0 0 0;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
@media(max-width: 550px) {
|
|
330
|
+
#content {
|
|
331
|
+
font-size: 0.65em;
|
|
332
|
+
max-width: 95%;
|
|
333
|
+
margin: 1em auto;
|
|
334
|
+
--hp-bar: 101px;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
@media(max-width: 425px) {
|
|
338
|
+
.stats {
|
|
339
|
+
font-size: 0.9em;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
h1 {
|
|
343
|
+
text-align: center;
|
|
344
|
+
}
|
|
345
|
+
.error {
|
|
346
|
+
overflow: auto;
|
|
347
|
+
scrollbar-width: none;
|
|
348
|
+
padding: 10px 20px;
|
|
349
|
+
border: 3px solid #DD4422;
|
|
350
|
+
background: #FFF8F2;
|
|
351
|
+
}
|
|
352
|
+
.error::-webkit-scrollbar {
|
|
353
|
+
display: none;
|
|
354
|
+
}
|