@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.
Files changed (84) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +66 -32
  3. package/build/pkg/addon/browser.d.ts +3 -0
  4. package/build/pkg/addon/browser.js +47 -0
  5. package/build/pkg/addon/browser.js.map +1 -0
  6. package/build/pkg/addon/node.d.ts +3 -0
  7. package/build/pkg/addon/node.js +110 -0
  8. package/build/pkg/addon/node.js.map +1 -0
  9. package/build/pkg/addon/wasm.d.ts +2 -0
  10. package/build/pkg/addon/wasm.js +53 -0
  11. package/build/pkg/addon/wasm.js.map +1 -0
  12. package/build/pkg/addon.d.ts +26 -4
  13. package/build/pkg/addon.js +39 -71
  14. package/build/pkg/addon.js.map +1 -1
  15. package/build/pkg/data/layout.json +15 -2
  16. package/build/pkg/data/protocol.json +23 -9
  17. package/build/pkg/data.d.ts +27 -5
  18. package/build/pkg/data.js.map +1 -1
  19. package/build/pkg/gen1.d.ts +15 -18
  20. package/build/pkg/gen1.js +28 -19
  21. package/build/pkg/gen1.js.map +1 -1
  22. package/build/pkg/index.d.ts +42 -91
  23. package/build/pkg/index.js +23 -70
  24. package/build/pkg/index.js.map +1 -1
  25. package/build/pkg/protocol.d.ts +29 -1
  26. package/build/pkg/protocol.js +109 -107
  27. package/build/pkg/protocol.js.map +1 -1
  28. package/build/tools/debug.js +84 -73
  29. package/build/tools/debug.js.map +1 -1
  30. package/build/tools/display/debug.jsx +66 -0
  31. package/build/tools/display/debug.jsx.map +1 -0
  32. package/build/tools/display/index.js +152 -0
  33. package/build/tools/display/index.js.map +1 -0
  34. package/build/tools/display/ui.jsx +360 -0
  35. package/build/tools/display/ui.jsx.map +1 -0
  36. package/build/tools/display/util.js +157 -0
  37. package/build/tools/display/util.js.map +1 -0
  38. package/build.zig +357 -135
  39. package/package.json +61 -132
  40. package/src/bin/install-pkmn-engine +47 -21
  41. package/src/bin/pkmn-debug +1 -1
  42. package/src/lib/bindings/c.zig +201 -0
  43. package/src/lib/{binding → bindings}/node.zig +15 -32
  44. package/src/lib/bindings/wasm.zig +51 -0
  45. package/src/lib/common/array.zig +70 -0
  46. package/src/lib/common/data.zig +4 -4
  47. package/src/lib/common/debug.zig +45 -29
  48. package/src/lib/common/js.zig +3 -7
  49. package/src/lib/common/optional.zig +27 -23
  50. package/src/lib/common/options.zig +6 -0
  51. package/src/lib/common/protocol.zig +565 -552
  52. package/src/lib/common/rational.zig +340 -253
  53. package/src/lib/common/rng.zig +7 -9
  54. package/src/lib/common/util.zig +53 -1
  55. package/src/lib/gen1/calc.zig +724 -175
  56. package/src/lib/gen1/chance.zig +486 -300
  57. package/src/lib/gen1/data/moves.zig +2 -4
  58. package/src/lib/gen1/data/species.zig +2 -4
  59. package/src/lib/gen1/data/types.zig +3 -4
  60. package/src/lib/gen1/data.zig +29 -32
  61. package/src/lib/gen1/helpers.zig +113 -561
  62. package/src/lib/gen1/mechanics.zig +611 -488
  63. package/src/lib/gen2/calc.zig +35 -28
  64. package/src/lib/gen2/chance.zig +111 -511
  65. package/src/lib/gen2/data/items.zig +1 -3
  66. package/src/lib/gen2/data/moves.zig +2 -4
  67. package/src/lib/gen2/data/species.zig +1 -3
  68. package/src/lib/gen2/data/types.zig +7 -5
  69. package/src/lib/gen2/data.zig +27 -29
  70. package/src/lib/gen2/generated.zig +22 -29
  71. package/src/lib/gen2/helpers.zig +68 -39
  72. package/src/lib/gen2/mechanics.zig +504 -430
  73. package/src/lib/napi.h +2 -0
  74. package/src/lib/node.zig +14 -0
  75. package/src/lib/pkmn.zig +125 -29
  76. package/src/lib/wasm.zig +13 -0
  77. package/src/tools/display/dom.ts +108 -0
  78. package/src/tools/display/ui.css +354 -0
  79. package/build/test/display.js +0 -400
  80. package/build/test/display.js.map +0 -1
  81. package/src/lib/binding/wasm.zig +0 -12
  82. package/src/lib/gen1/README.md +0 -894
  83. package/src/lib/gen2/README.md +0 -329
  84. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,329 +0,0 @@
1
- # Pokémon Generation II: GSC
2
-
3
- ## Data Structures
4
-
5
- The following information is required to simulate a Generation II Pokémon battle:
6
-
7
- ==**TODO**==
8
-
9
- | pkmn | Pokémon Crystal (pret) | Pokémon Showdown |
10
- | ------------------------------ | --------------------------------- | ------------------------------------- |
11
- | `battle.seed` | `Random{Add,Sub}` | `battle.seed` |
12
- | `battle.turn` | | `battle.turn` |
13
- | `field.weather.id` | `BattleWeather` | `field.weather` |
14
- | `field.weather.duration` | `WeatherCount` | `field.weatherState.duration` |
15
- | `side.{active,pokemon}` | `BattleMon` | `side.active` |
16
- | `side.team` | `PartyMons`/`PartySpecies` | `side.pokemon` |
17
- | `side.conditions` | `PlayerScreens` | `side.sideConditions` |
18
- | `conditions.data.safeguard` | `PlayerSafeguardCount` | `sideConditions.safeguard.duration` |
19
- | `conditions.data.light_screen` | `PlayerLightScreenCount` | `sideConditions.lightscreen.duration` |
20
- | `conditions.data.reflect` | `PlayerReflectCount` | `sideConditions.reflect.duration` |
21
- | `pokemon.stats` | `TODO unmodified` | `pokemon.baseStoredStats` |
22
- | `pokemon.position` | `TODO` | `pokemon.position` |
23
- | `pokemon.moves` | `party_struct.{Moves,PP}` | `pokemon.baseMoveSlots` |
24
- | `{pokemon,active}.hp` | `{party,battle}_struct.HP` | `pokemon.hp` |
25
- | `{pokemon,active}.status` | `{party,battle}_struct.Status` | `pokemon.status` |
26
- | `{pokemon,active}.level` | `TODO unmodified` | `pokemon.level` |
27
- | `{pokemon,active}.happiness` | `{box,battle}_struct.Happiness` | `pokemon.happiness` |
28
- | `{pokemon,active}.ivs.gender` | `{box,battle}_struct.DVs` | `pokemon.gender` |
29
- | `{pokemon,active}.ivs.type` | `{box,battle}_struct.DVs` | `pokemon.hpType` |
30
- | `{pokemon,active}.ivs.power` | `{box,battle}_struct.DVs` | `pokemon.hpPower` |
31
- | `{pokemon,active}.item` | `{box,battle}_struct.Item` | `pokemon.item` |
32
- | `pokemon.species` | `party_struct.Species` | `pokemon.baseSpecies` |
33
- | `active.species` | `battle_struct.Species` | `pokemon.species` |
34
- | `active.stats` | `TODO modified` | `pokemon.storedStats` |
35
- | `active.boosts` | `PlayerStatLevels` | `pokemon.boosts` |
36
- | `active.volatiles` | `PlayerBattleStatus{1,2,3}` | `pokemon.volatiles` |
37
- | `volatiles.bide` | `PlayerDamageTaken` | `volatiles.bide.totalDamage` |
38
- | `volatiles.substitute` | `PlayerSubstituteHP` | `volatiles.substitute.hp` |
39
- | `volatiles.rollout` | `PlayerRolloutCount` | `volatiles.rollout.hitCount` |
40
- | `volatiles.confusion` | `PlayerConfuseCount` | `volatiles.confusion.duration` |
41
- | `volatiles.toxic` | `PlayerToxicCount` | `volatiles.residualdmg.counter` |
42
- | `volatiles.disable` | `PlayerDisableCount` | `moveSlots.disabled` |
43
- | `volatiles.encore` | `PlayerEncoreCount` | `volatiles.encore.duration` |
44
- | `volatiles.perish_song` | `PlayerPerishCount` | `volatiles.perishsong.duration` |
45
- | `volatiles.fury_cutter` | `PlayerFuryCutterCount` | `volatiles.furycutter.multiplier` |
46
- | `volatiles.protect` | `PlayerProtectCount` | `volatiles.stall.counter` |
47
- | `volatiles.future_sight` | `PlayerFutureSight{Damage,Count}` | `slotConditions[i].futuremove` |
48
- | `volatiles.rage` | `PlayerRageCounter` | **BUG** |
49
- | `volatiles.bind` | `PlayerWrapCount` | `volatiles.partiallytrapped.duration` |
50
- | `volatiles.bind_reason` | `PlayerTrappingMove` | `volatiles.effectState.sourceEffect` |
51
- | | `PlayerCharging` | |
52
- | `volatiles.switched` | `TODO` | `pokemon.switchFlag` |
53
- | `volatiles.switching` | `PlayerIsSwitching` | `pokemon.switchFlag` |
54
- | `volatiles.frozen` | `PlayerJustGotFrozen` | `volatiles.frozen` |
55
- | | | |
56
- | `active.last_used_move` | `PlayerUsedMove` | `side.lastMove` |
57
-
58
- - Pokémon Showdown doesn't implement the correct Generation II RNG and as such its `seed` is
59
- different
60
- - `battle.turn` only needs to be tracked to be compatible with the Pokémon Showdown protocol
61
- - Battle results (win, lose, draw) or request states are communicated via the return code of
62
- `Battle.update`
63
- - Nicknames (`BattleMonNick`/`pokemon.name`) aren't handled by the pkmn engine as they're expected
64
- to be handled by driver code if required
65
-
66
- ==**TODO**==
67
-
68
- wPlayerMinimized
69
-
70
- ### `Battle` / `Side`
71
-
72
- `Battle` and `Side` are analogous to the classes of the
73
- [same](https://github.com/smogon/pokemon-showdown/blob/master/sim/battle.ts)
74
- [name](https://github.com/smogon/pokemon-showdown/blob/master/sim/side.ts) in Pokémon Showdown and
75
- store general information about the battle. Unlike in Pokémon Showdown there is a distinction
76
- between the data structure for the "active" Pokémon and its party members (see below).
77
-
78
- ### `Pokemon` / `ActivePokemon`
79
-
80
- Similar to the cartridge, to save space different information is stored depending on whether a
81
- [Pokémon](https://pkmn.cc/bulba/Pok%c3%a9mon_data_structure_%28Generation_II%29) is actively
82
- participating in battle vs. is switched out (pret's [`battle_struct` vs.
83
- `party_struct`](https://pkmn.cc/pokecrystal/macros/ram.asm)). In Pokémon Showdown, all the Pokemon
84
- are represented by the same
85
- [`Pokemon`](https://github.com/smogon/pokemon-showdown/blob/master/sim/pokemon.ts) class, and static
86
- party information is saved in fields beginning with "`stored`" or "`base`".
87
-
88
- ==**TODO**==
89
-
90
- #### `MoveSlot`
91
-
92
- A `MoveSlot` is a data-type for a `(move, current pp)` pair. A pared down version of Pokémon
93
- Showdown's `Pokemon#moveSlot`, it also stores data from the cartridge's `battle_struct::Move` macro
94
- and can be used to replace the `PlayerMove*` data. Move PP is stored as a full byte instead of how
95
- the cartridge (`battle_struct::PP`) stores it (6 bits for current PP and the remaining 2 bits used
96
- to store the number of applied PP Ups). PP Up bits don't actually need to be stored on move slot
97
- as max PP is never relevant in Generation II (the Mystery Berry always increases PP from 0 -> 5).
98
-
99
- #### `Status`
100
-
101
- Bitfield representation of a Pokémon's major [status
102
- condition](https://pkmn.cc/bulba/Status_condition), mirroring how it's stored on the cartridge. A
103
- value of `0x00` means that the Pokémon isn't affected by any major status, otherwise the lower 3
104
- bits represent the remaining duration for Sleep. Other status are denoted by the presence of
105
- individual bits - at most one status should be set at any given time.
106
-
107
- In Generation I & II, the "badly poisoned" status (Toxic) is instead treated as a volatile (see
108
- below).
109
-
110
- #### `Volatile` / `VolatileData`
111
-
112
- Active Pokémon can have ["volatile" status
113
- conditions](https://pkmn.cc/bulba/Status_condition#Volatile_status) (called ['sub
114
- status'](https://pkmn.cc/pokecrystal/constants/battle_constants.asm#L166-L212) bits in pret), all of
115
- which are boolean flags that are cleared when the Pokémon faints or switches out:
116
-
117
- | pkmn | Pokémon Crystal (pret) | Pokémon Showdown |
118
- | ------------- | ----------------------- | ---------------- |
119
- | `Bide` | `BIDE` | `bide` |
120
- | `Thrashing` | `RAMPAGE` | `lockedmove` |
121
- | `Flinch` | `FLINCHED` | `flinch` |
122
- | `Charging` | `CHARGED` | `twoturnmove` |
123
- | `Underground` | `UNDERGROUND` | `dig` |
124
- | `Flying` | `FLYING` | `fly` |
125
- | `Confusion` | `CONFUSED` | `confusion` |
126
- | `Mist` | `MIST` | `mist` |
127
- | `FocusEnergy` | `FOCUS_ENERGY` | `focusenergy` |
128
- | `Substitute` | `SUBSTITUTE` | `substitute` |
129
- | `Recharging` | `RECHARGE` | `mustrecharge` |
130
- | `Rage` | `RAGE` | `rage` |
131
- | `LeechSeed` | `LEECH_SEED` | `leechseed` |
132
- | `Toxic` | `TOXIC` | `toxic` |
133
- | `Transform` | `TRANSFORMED` | `transform` |
134
- | | | |
135
- | `Nightmare` | `NIGHTMARE` | `nightmare` |
136
- | `Cure` | `CURSE` | `curse` |
137
- | `Protect` | `PROTECT` | `protect` |
138
- | `Foresight` | `IDENTIFIED` | `foresight` |
139
- | `PerishSong` | `PERISH` | `perishsong` |
140
- | `Endure` | `ENDURE` | `endure` |
141
- | `Rollout` | `ROLLOUT` | `rollout` |
142
- | `Attract` | `IN_LOVE` | `attract` |
143
- | `DefenseCurl` | `CURLED` | `defensecurl` |
144
- | `Encore` | `ENCORED` | `encore` |
145
- | `LockOn` | `LOCK_ON` | `lockon` |
146
- | `DestinyBond` | `DESTINY_BOND` | `destinybond` | |
147
-
148
- ==**TODO**==
149
-
150
- - `IN_LOOP` (beatup)
151
-
152
- #### `Stats` / `Boosts`
153
-
154
- [Stats](https://pkmn.cc/bulba/Stat) and [boosts (stat
155
- modifiers)](https://pkmn.cc/bulba/Stat#Stat_modifiers) are stored logically, with the exception that
156
- boosts should always range from `-6`...`6` instead of `1`...`13` as on the cartridge.
157
-
158
- ==**TODO**==
159
-
160
- ### `Move` / `Moves`
161
-
162
- `Moves` serves as an identifier for a unique [Pokémon move](https://pkmn.cc/bulba/Move) that can be
163
- used to retrieve a `Move` with information regarding base power, accuracy and type. As covered
164
- earlier, PP information isn't strictly necessary in Generation I, but fits neatly into the 4 bits of
165
- padding after noticing that all PP values are multiples of 5. `Moves.None` exists as a special
166
- sentinel value to indicate `null`.
167
-
168
- ### `Species`
169
-
170
- `Species` just serves as an identifier for a unique [Pokémon
171
- species](https://pkmn.cc/bulba/Pokémon_species_data_structure_(Generation_II)) as the base
172
- stats of a species are already accounted for in the computed stats in the `Pokemon` structure and
173
- nothing in battle requires these to be recomputed. Similarly, Type is unnecessary to include as it
174
- is also already present in the `Pokemon` struct. `Species.None` exists as a special sentinel value
175
- to indicate `null`.
176
-
177
- ### `Type` / `Types` / `Effectiveness`
178
-
179
- The [Pokémon types](https://pkmn.cc/bulba/Type) are enumerated by `Type`. `Types` represents a tuple
180
- of 2 types, which takes the form of a packed struct instead of `[2]Type` for symmetry with
181
- Generation I. `Effectiveness` serves as an enum for tracking a moves effectiveness - like the
182
- cartridge, effectiveness is stored as `0`, `5`, `10`, and `20` (technically only a 4-bit value is
183
- required, but Zig only allows a minimum of a byte to be stored at each address of an array).
184
-
185
- Type effectiveness modifiers are applied based off of the ordering of the effectiveness table as
186
- opposed to first applying modifiers for a species's first type and then second type. The engine
187
- maintains a `Type.PRECEDENCE` table to allow for reordering type effectiveness modifier application
188
- where necessary.
189
-
190
- ## Information
191
-
192
- The information of each field (in terms of [bits of
193
- entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory))) is as follows:
194
-
195
- ==**TODO**==
196
-
197
- | Data | Range | Bits | | Data | Range | Bits |
198
- | -------------- | ------- | ---- | --- | ----------------- | -------- | ---- |
199
- | **seed** | 0...255 | 8 | | **turn** | 1...1000 | 7 |
200
- | **team index** | 1...6 | 3 | | **move index** | 1...4 | 2 |
201
- | **species** | 1...251 | 8 | | **move** | 1...251 | 8 |
202
- | **stat** | 1...999 | 10 | | **boost** | 0...13 | 4 |
203
- | **level** | 1...100 | 7 | | **volatiles** | *27* | 27 |
204
- | **bide** | 0...703 | 11 | | **substitute** | 0...179 | 8 |
205
- | **multi hits** | 0...5 | 3 | | **base power** | 0...50 | 6 |
206
- | **base PP** | 1...8 | 3 | | **PP Ups** | 0...3 | 2 |
207
- | **PP** | 0...64 | 7 | | **HP / damage** | 0...704 | 10 |
208
- | **status** | 0...10 | 4 | | **effectiveness** | 0...3 | 2 |
209
- | **type** | 0...18 | 5 | | **accuracy** | 6...20 | 4 |
210
- | **disabled** | 0...7 | 3 | | **DVs** | 0...15 | 4 |
211
- | **rollout** | 0...5 | 3 | | **fury cutter** | 0..4 | 3 |
212
- | **confusion** | 0...5 | 3 | | **toxic** | 0...15 | 4 |
213
- | **encore** | 0...6 | 3 | | **future sight** | 0...2 | 2 |
214
- | **protect** | 0...9 | 4 | | **rage** | 0...255 | 8 |
215
- | **wrap** | 0...5 | 3 | | **perish song** | 0...4 | 3 |
216
- | **item** | TODO | 5? | | **gender** | 0..1 | 1 |
217
-
218
- From this one can determine the minimum bits required to store each data structure to determine how
219
- much overhead the preceding representations have after taking into consideration [alignment &
220
- padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
221
- [denormalization](https://en.wikipedia.org/wiki/Denormalization):
222
-
223
- ## Details
224
-
225
- | pkmn | Pokémon Crystal (pret) |
226
- | ------------------------- | ------------------------------------------------- |
227
- | `start` | `DoBattle` |
228
- | `update` | `BattleTurn` |
229
- | `selectMove` / `saveMove` | `CheckPlayerLockedIn` / `ParsePlayerAction` |
230
- | `switchIn` | `SwitchPlayerMon` / `SendOutPlayerMon` |
231
- | `turnOrder` | `DetermineMoveOrder` |
232
- | `doTurn` | `DoTurn` |
233
- | `executeMove` | `DoMove` |
234
- | `beforeMove` | `CheckTurn` |
235
- | `canMove` | |
236
- | `decrementPP` | |
237
- | `doMove` | |
238
- | `checkCriticalHit` | `BattleCommand_Critical` |
239
- | `calcDamage` | `BattleCommand_DamageCalc` / `PlayerAttackDamage` |
240
- | `adjustDamage` | `BattleCommand_Stab` |
241
- | `randomizeDamage` | `BattleCommand_DamageVariation` |
242
- | `specialDamage` | `BattleCommand_ConstantDamage` |
243
- | `applyDamage` | `BattleCommand_ApplyDamage` |
244
- | `checkHit` | `BattleCommand_CheckHit` |
245
- | `checkFaint` | `CheckFaint` |
246
- | `handleResidual` | `ResidualDamage` |
247
- | `endTurn` | `EndTurn` |
248
-
249
- DoBattle
250
- BattleTurn
251
- - HandleBerserkGene
252
- - CheckPlayerLockedIn
253
- - BattleMenu
254
- - ParsePlayerAction
255
- - DetermineMoveOrder
256
- - CompareMovePriority
257
- - GetMovePriority
258
- - Battle_*
259
- - Handle*Switch
260
- - SwitchPlayerMon
261
- - BreakAttraction
262
- - SendOutPlayerMon
263
- - SpikesDamage
264
- - *Turn_EndOpponentProtectEndureDestinyBond
265
- - EndUserDestinyBond
266
- - Do*Turn
267
- - EndOpponentProtectEndureDestinyBond
268
- - ResidualDamage
269
- - CheckFaint_*
270
- - HandleBetweenTurnEffects
271
- - HandleFutureSight
272
- - HandleWeather
273
- - HandleWrap
274
- - HandlePerishSong
275
- - HandleLeftovers
276
- - HandleMysteryBerry
277
- - HandleDefrost
278
- - HandleSafeguard
279
- - HandleScreens
280
- - HandleStatBoostingHeldItems
281
- - HandleHealingItems
282
- - HandleEncore
283
-
284
- DoTurn
285
- DoMove = executeMove
286
- CheckTurn = beforeMove
287
- BattleCommand_Critical = checkCriticalHit
288
- BattleCommand_Stab = adjustDamage
289
- BattleCommand_DamageVariation = randomizeDamage
290
- BattleCommand_CheckHit = checkHit
291
- BattleCommand_ApplyDamage = applyDamage
292
- BattleCommand_CheckFaint
293
- BattleCommand_BuildOpponentRage = buildRage
294
- BattleCommand_DamageCalc (PlayerAttackDamage / EnemyAttackDamage) = calcDamage
295
- BattleCommand_ConstantDamage = specialDamage
296
- DoEnemyDamage / DoPlayerDamage / DoSubstituteDamage
297
-
298
- ==**TODO**==
299
-
300
- ## Protocol
301
-
302
- TODO
303
-
304
- ```txt
305
- -activate: _, move, name, number
306
- ```
307
-
308
- ## Bugs
309
-
310
- - TODO: randomChance rate different than gen 1?
311
- - Twineedle shouldn't be able to inflict poison if it breaks a substitute
312
- - Mail should not be stolen by Thief
313
- - RNG for crit is 1/16 and not 17/256?
314
- - Struggle recoil into Substitute only 1 HP
315
- - Substitute "activates" even though doesnt take damage for jump crash damage
316
- - Pokémon specific items after Transform
317
- - OHKO moves that miss should be Counterable
318
- - Defense lowering after breaking Substitute glitch
319
- - Beserk Gene copies previous mons confusion counter
320
- - Type boosting items w/ Confusion self-hit
321
- - Spikes 0 HP glitch
322
- - PP Up + Disable freeze
323
- - Beat Up partyless should fail but should still be able to trigger Kings Rock
324
- - Beat Up desync
325
- - Lock-on accuracy should be 100 not true, should be passed
326
- - Pain Split 100 accuracy not true
327
- - Foresight ignoring accuracy/evasiveness stages
328
- - Disable duration?
329
- - type effectiveness precedence
@@ -1,368 +0,0 @@
1
- <!doctype html>
2
- <html lang=en>
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <link rel="icon" href="https://pkmn.cc/favicon.ico">
7
- <title>@pkmn/engine</title>
8
- <style>
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
- }
17
- details > summary {
18
- list-style: none;
19
- }
20
- details > summary::-webkit-details-marker {
21
- display: none;
22
- }
23
- .battle > .details {
24
- background: #eee;
25
- border-bottom: 3px solid black;
26
- padding: 0 0.5em;
27
- display: flex;
28
- justify-content: space-between;
29
- }
30
- .inner {
31
- display: flex;
32
- justify-content: center;
33
- flex-direction: column;
34
- }
35
- .side > .details {
36
- padding: 0.5em;
37
- display: flex;
38
- justify-content: space-between;
39
- text-align: center;
40
- flex: 0 1 auto;
41
- }
42
- .active {
43
- flex: 1 1 auto;
44
- }
45
- details {
46
- flex: 0 1 auto;
47
- }
48
- .sides {
49
- display: flex;
50
- }
51
- .side {
52
- flex: 1;
53
- display: flex;
54
- flex-flow: column;
55
- }
56
- .side.p1 {
57
- border-right: 1px solid black;
58
- }
59
- .battle {
60
- border: 3px solid black;
61
- }
62
- summary {
63
- border-top: 1px solid black;
64
- text-align: center;
65
- padding: 0.25em;
66
- }
67
- .good {
68
- color: green;
69
- }
70
- .bad {
71
- color: red;
72
- }
73
- .pokemon {
74
- position: relative;
75
- padding: 0.5em;
76
- border-top: 1px solid black;
77
- display: flex;
78
- }
79
- table {
80
- border-collapse: collapse;
81
- border-style: hidden;
82
- border-spacing: 0px;
83
- line-height: 1.5em;
84
- }
85
- th, td {
86
- border: 1px solid black;
87
- padding: 0 0.5em;
88
- }
89
- .statbar {
90
- display: none;
91
- width: calc(var(--hp-bar) + var(--hp-text));
92
- padding: 2px 0;
93
- line-height: normal;
94
- }
95
- .statbar .name {
96
- display: block;
97
- text-align: center;
98
- line-height: 1.25em;
99
- }
100
- .statbar strong {
101
- color: #222222;
102
- text-shadow:
103
- #FFFFFF 1px 1px 0, #FFFFFF 1px -1px 0,
104
- #FFFFFF -1px 1px 0, #FFFFFF -1px -1px 0;
105
- }
106
- .statbar strong small {
107
- font-weight: normal;
108
- }
109
- .statbar .hpbar {
110
- position: relative;
111
- border: 1px solid #777777;
112
- background: #FCFEFF;
113
- padding: 1px;
114
- height: 8px;
115
- margin: 0 0 0 0;
116
- width: calc(var(--hp-bar) + var(--hp-text) + 1px);
117
- border-radius: 4px;
118
- }
119
- .statbar .hpbar .hp {
120
- height: 4px;
121
- border-top: 2px solid #00dd60;
122
- background: #00bb51;
123
- border-bottom: 2px solid #007734;
124
- border-right: 1px solid #007734;
125
- border-radius: 3px;
126
- }
127
- .statbar .hpbar .hp-yellow {
128
- border-top-color: #f8e379;
129
- background-color: #f5d538;
130
- border-bottom-color: #be9f0a;
131
- border-right-color: #be9f0a;
132
- }
133
- .statbar .hpbar .hp-red {
134
- border-top-color: #f37f67;
135
- background-color: #ee4928;
136
- border-bottom-color: #a3260d;
137
- border-right-color: #a3260d;
138
- }
139
- .statbar .hpbar .prevhp {
140
- background: #BBEECC;
141
- height: 8px;
142
- border-radius: 3px;
143
- }
144
- .statbar .hpbar .prevhp-yellow {
145
- background-color: #fcf4ca;
146
- }
147
- .statbar .hpbar .prevhp-red {
148
- background-color: #facec5;
149
- }
150
- .statbar .hpbar .hptext {
151
- position: absolute;
152
- background: #777777;
153
- color: #EEEEEE;
154
- text-shadow: #000000 0 1px 0;
155
- font-size: 10px;
156
- width: 32px;
157
- height: 12px;
158
- top: -1px;
159
- text-align: center;
160
- }
161
- .status, .volatile {
162
- padding: 0px 1px;
163
- border: 1px solid #FF4400;
164
- border-radius: 3px;
165
- }
166
- .status {
167
- min-height: 10px;
168
- font-size: 7pt;
169
- vertical-align: middle;
170
- padding: 1px 2px;
171
- border: 0;
172
- border-radius: 3px;
173
- text-transform: uppercase;
174
- margin: 0 2px;
175
- }
176
- .status.brn {
177
- background: #EE5533;
178
- color: #FFFFFF;
179
- }
180
- .status.psn {
181
- background: #A4009A;
182
- color: #FFFFFF;
183
- }
184
- .status.par {
185
- background: #9AA400;
186
- color: #FFFFFF;
187
- }
188
- .status.slp {
189
- background: #AA77AA;
190
- color: #FFFFFF;
191
- }
192
- .status.frz {
193
- background: #009AA4;
194
- color: #FFFFFF;
195
- }
196
- .volatile {
197
- display: inline-block;
198
- padding: 0 5px;
199
- margin: 2px
200
- }
201
- .volatile.bad {
202
- background: #FFE5E0;
203
- color: #FF4400;
204
- border-color: #FF4400;
205
- }
206
- .volatile.good {
207
- background: #E5FFE0;
208
- color: #33AA00;
209
- border-color: #33AA00;
210
- }
211
- .volatile.neutral {
212
- background: #F0F0F0;
213
- color: #555555;
214
- border-color: #555555;
215
- }
216
- .rstatbar .hpbar .hptext {
217
- right: 0px;
218
- border-radius: 0 4px 4px 0;
219
- }
220
- .moves ul {
221
- column-count: 2;
222
- column-gap: 2em;
223
- }
224
- .left {
225
- padding-right: 32px;
226
- display: flex;
227
- flex-direction: column;
228
- align-items: center;
229
- }
230
- .stats {
231
- display: flex;
232
- padding: 0 1em;
233
- justify-content: space-between;
234
- text-align: center;
235
- width: 100%;
236
- }
237
- .types {
238
- display: inherit;
239
- }
240
- .disabled {
241
- color: #AAAAAA;
242
- }
243
- .log {
244
- display: flex;
245
- justify-content: center;
246
- padding-bottom: 2em;
247
- }
248
- .position {
249
- position: absolute;
250
- right: 10px;
251
- color: #AAAAAA;
252
- }
253
- .left .position {
254
- display: none;
255
- }
256
- .right .position {
257
- display: block;
258
- }
259
- .teamicons {
260
- display: inline-block;
261
- }
262
- @media(max-width: 1300px) {
263
- #content {
264
- font-size: 0.85em;
265
- max-width: 95%;
266
- margin: 2em auto;
267
- }
268
- }
269
- @media(max-width: 1200px) {
270
- .moves ul {
271
- column-count: 1;
272
- }
273
- }
274
- @media(max-width: 1100px) {
275
- .pokemon {
276
- flex-direction: column;
277
- }
278
- .stats {
279
- justify-content: center;
280
- padding: 0;
281
- }
282
- .boosts {
283
- margin-left: 5px;
284
- }
285
- .moves ul {
286
- column-count: 2;
287
- }
288
- .left {
289
- padding-right: 0;
290
- }
291
- .right {
292
- padding-top: 1em;
293
- }
294
- .volatiles {
295
- display: flex;
296
- justify-content: center;
297
- flex-wrap: wrap;
298
- }
299
- .left .position {
300
- display: block;
301
- }
302
- .right .position {
303
- display: none;
304
- }
305
- }
306
- @media(max-width: 800px) {
307
- .moves {
308
- display: flex;
309
- justify-content: center;
310
- }
311
- .moves ul {
312
- column-count: 1;
313
- display: inline-block;
314
- padding: 0;
315
- }
316
- }
317
- @media(max-width: 680px) {
318
- .stats {
319
- flex-direction: column;
320
- padding: 0;
321
- }
322
- .boosts {
323
- display: flex;
324
- justify-content: space-between;
325
- margin-top: 0.5em;
326
- }
327
- }
328
- @media(max-width: 550px) {
329
- #content {
330
- font-size: 0.65em;
331
- max-width: 95%;
332
- margin: 1em auto;
333
- --hp-bar: 101px;
334
- }
335
- }
336
- @media(max-width: 425px) {
337
- .stats {
338
- font-size: 0.9em;
339
- }
340
- }
341
- h1 {
342
- text-align: center;
343
- }
344
- .error {
345
- overflow: auto;
346
- scrollbar-width: none;
347
- padding: 10px 20px;
348
- border: 3px solid #DD4422;
349
- background: #FFF8F2;
350
- }
351
- .error::-webkit-scrollbar {
352
- display: none;
353
- }
354
- </style>
355
- </head>
356
- <body>
357
- <div id="content">{{{ content }}}</div>
358
- <script>
359
- for (const details of document.getElementsByTagName('details')) {
360
- details.addEventListener('toggle', e => {
361
- for (const d of details.parentElement.parentElement.getElementsByTagName('details')) {
362
- if (d.open !== details.open) d.open = details.open;
363
- }
364
- });
365
- }
366
- </script>
367
- </body>
368
- </html>