@pkmn/engine 0.1.0-dev.e5b5a998 → 0.1.0-dev.f6c1a379

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 (42) hide show
  1. package/README.md +53 -42
  2. package/build/pkg/addon.js +3 -2
  3. package/build/pkg/addon.js.map +1 -1
  4. package/build/pkg/data/ids.json +12 -12
  5. package/build/pkg/data/layout.json +24 -2
  6. package/build/pkg/data/protocol.json +69 -12
  7. package/build/pkg/data.d.ts +2 -2
  8. package/build/pkg/gen1.js +13 -16
  9. package/build/pkg/gen1.js.map +1 -1
  10. package/build/pkg/protocol.js +56 -37
  11. package/build/pkg/protocol.js.map +1 -1
  12. package/build.zig +82 -57
  13. package/package.json +33 -15
  14. package/src/bin/install-pkmn-engine +10 -5
  15. package/src/lib/binding/node.zig +46 -141
  16. package/src/lib/binding/wasm.zig +4 -2
  17. package/src/lib/common/battle.zig +17 -0
  18. package/src/lib/common/data.zig +15 -27
  19. package/src/lib/common/debug.zig +20 -11
  20. package/src/lib/common/js.zig +118 -0
  21. package/src/lib/common/optional.zig +60 -0
  22. package/src/lib/common/options.zig +9 -0
  23. package/src/lib/common/protocol.zig +646 -138
  24. package/src/lib/common/rational.zig +353 -0
  25. package/src/lib/common/rng.zig +15 -15
  26. package/src/lib/common/util.zig +12 -0
  27. package/src/lib/gen1/README.md +257 -177
  28. package/src/lib/gen1/calc.zig +426 -0
  29. package/src/lib/gen1/chance.zig +1058 -0
  30. package/src/lib/gen1/data/moves.zig +168 -170
  31. package/src/lib/gen1/data/types.zig +3 -3
  32. package/src/lib/gen1/data.zig +61 -51
  33. package/src/lib/gen1/helpers.zig +588 -17
  34. package/src/lib/gen1/mechanics.zig +776 -502
  35. package/src/lib/gen2/README.md +106 -85
  36. package/src/lib/gen2/data/items.zig +11 -17
  37. package/src/lib/gen2/data/moves.zig +639 -562
  38. package/src/lib/gen2/data/types.zig +127 -25
  39. package/src/lib/gen2/data.zig +104 -78
  40. package/src/lib/gen2/helpers.zig +15 -21
  41. package/src/lib/gen2/mechanics.zig +1444 -11
  42. package/src/lib/pkmn.zig +61 -2
@@ -32,35 +32,36 @@ The following information is required to simulate a Generation II Pokémon battl
32
32
  | `pokemon.species` | `party_struct.Species` | `pokemon.baseSpecies` |
33
33
  | `active.species` | `battle_struct.Species` | `pokemon.species` |
34
34
  | `active.stats` | `TODO modified` | `pokemon.storedStats` |
35
- | `active.trapped FIXME` | `PlayerTrappingMove` | `pokemon.trapped` |
36
- | `active.switching` | `PlayerIsSwitching` | `pokemon.switchFlag` |
37
35
  | `active.boosts` | `PlayerStatLevels` | `pokemon.boosts` |
38
36
  | `active.volatiles` | `PlayerBattleStatus{1,2,3}` | `pokemon.volatiles` |
39
- | `volatiles.data.bide` | `PlayerDamageTaken` | `volatiles.bide.totalDamage` |
40
- | `volatiles.data.substitute` | `PlayerSubstituteHP` | `volatiles.substitute.hp` |
41
- | `volatiles.data.rollout` | `PlayerRolloutCount` | `volatiles.rollout.hitCount` |
42
- | `volatiles.data.confusion` | `PlayerConfuseCount` | `volatiles.confusion.duration` |
43
- | `volatiles.data.toxic` | `PlayerToxicCount` | `volatiles.residualdmg.counter` |
44
- | `volatiles.data.disabled` | `PlayerDisableCount` | `moveSlots.disabled` |
45
- | `volatiles.data.encore` | `PlayerEncoreCount` | `volatiles.encore.duration` |
46
- | `volatiles.data.perish_song` | `PlayerPerishCount` | `volatiles.perishsong.duration` |
47
- | `volatiles.data.fury_cutter` | `PlayerFuryCutterCount` | `volatiles.furycutter.multiplier` |
48
- | `volatiles.data.protect` | `PlayerProtectCount` | `volatiles.stall.counter` |
49
- | `volatiles.data.future_sight` | `PlayerFutureSight{Damage,Count}` | `slotConditions[i].futuremove` |
50
- | `volatiles.data.rage` | `PlayerRageCounter` | **BUG** |
51
- | `volatiles.data.bind` | `PlayerWrapCount` | `volatiles.partiallytrapped.duration` |
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.disabled` | `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` |
52
51
  | | `PlayerCharging` | |
53
- | | `PlayerJustGotFrozen` | |
52
+ | `volatiles.trapped FIXME` | `FIXME` | `pokemon.trapped` |
53
+ | `volatiles.switched` | `TODO` | `pokemon.switchFlag` |
54
+ | `volatiles.switching` | `PlayerIsSwitching` | `pokemon.switchFlag` |
55
+ | `volatiles.frozen` | `PlayerJustGotFrozen` | `volatiles.frozen` |
54
56
  | | | |
55
57
  | `active.last_used_move` | `PlayerUsedMove` | `side.lastMove` |
56
58
 
57
- - Pokémon Showdown does not implement the correct Generation II RNG and as such its `seed` is
59
+ - Pokémon Showdown doesn't implement the correct Generation II RNG and as such its `seed` is
58
60
  different
59
- - `battle.turn` only needs to be tracked in order to be compatible with the Pokémon Showdown
60
- protocol
61
+ - `battle.turn` only needs to be tracked to be compatible with the Pokémon Showdown protocol
61
62
  - Battle results (win, lose, draw) or request states are communicated via the return code of
62
63
  `Battle.update`
63
- - Nicknames (`BattleMonNick`/`pokemon.name`) are not handled by the pkmn engine as they are expected
64
+ - Nicknames (`BattleMonNick`/`pokemon.name`) aren't handled by the pkmn engine as they're expected
64
65
  to be handled by driver code if required
65
66
 
66
67
  ==**TODO**==
@@ -77,9 +78,9 @@ between the data structure for the "active" Pokémon and its party members (see
77
78
 
78
79
  ### `Pokemon` / `ActivePokemon`
79
80
 
80
- Similar to the cartridge, in order to save space different information is stored depending on
81
- whether a [Pokémon](https://pkmn.cc/bulba/Pok%c3%a9mon_data_structure_%28Generation_II%29) is
82
- actively participating in battle vs. is switched out (pret's [`battle_struct` vs.
81
+ Similar to the cartridge, to save space different information is stored depending on whether a
82
+ [Pokémon](https://pkmn.cc/bulba/Pok%c3%a9mon_data_structure_%28Generation_II%29) is actively
83
+ participating in battle vs. is switched out (pret's [`battle_struct` vs.
83
84
  `party_struct`](https://pkmn.cc/pokecrystal/macros/ram.asm)). In Pokémon Showdown, all the Pokemon
84
85
  are represented by the same
85
86
  [`Pokemon`](https://github.com/smogon/pokemon-showdown/blob/master/sim/pokemon.ts) class, and static
@@ -93,14 +94,14 @@ A `MoveSlot` is a data-type for a `(move, current pp)` pair. A pared down versio
93
94
  Showdown's `Pokemon#moveSlot`, it also stores data from the cartridge's `battle_struct::Move` macro
94
95
  and can be used to replace the `PlayerMove*` data. Move PP is stored as a full byte instead of how
95
96
  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 do not actually need to be stored on move slot
97
+ to store the number of applied PP Ups). PP Up bits don't actually need to be stored on move slot
97
98
  as max PP is never relevant in Generation II (the Mystery Berry always increases PP from 0 -> 5).
98
99
 
99
100
  #### `Status`
100
101
 
101
102
  Bitfield representation of a Pokémon's major [status
102
- condition](https://pkmn.cc/bulba/Status_condition), mirroring how it is stored on the cartridge. A
103
- value of `0x00` means that the Pokémon is not affected by any major status, otherwise the lower 3
103
+ condition](https://pkmn.cc/bulba/Status_condition), mirroring how it's stored on the cartridge. A
104
+ value of `0x00` means that the Pokémon isn't affected by any major status, otherwise the lower 3
104
105
  bits represent the remaining duration for Sleep. Other status are denoted by the presence of
105
106
  individual bits - at most one status should be set at any given time.
106
107
 
@@ -161,7 +162,7 @@ boosts should always range from `-6`...`6` instead of `1`...`13` as on the cartr
161
162
 
162
163
  `Moves` serves as an identifier for a unique [Pokémon move](https://pkmn.cc/bulba/Move) that can be
163
164
  used to retrieve a `Move` with information regarding base power, accuracy and type. As covered
164
- above, PP information isn't strictly necessary in Generation I, but fits neatly into the 4 bits of
165
+ earlier, PP information isn't strictly necessary in Generation I, but fits neatly into the 4 bits of
165
166
  padding after noticing that all PP values are multiples of 5. `Moves.None` exists as a special
166
167
  sentinel value to indicate `null`.
167
168
 
@@ -215,11 +216,86 @@ entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory))) is as foll
215
216
  | **wrap** | 0...5 | 3 | | **perish song** | 0...4 | 3 |
216
217
  | **item** | TODO | 5? | | **gender** | 0..1 | 1 |
217
218
 
218
- From this we can determine the minimum bits required to store each data structure to determine how
219
- much overhead the representations above have after taking into consideration [alignment &
219
+ From this one can determine the minimum bits required to store each data structure to determine how
220
+ much overhead the preceding representations have after taking into consideration [alignment &
220
221
  padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
221
222
  [denormalization](https://en.wikipedia.org/wiki/Denormalization):
222
223
 
224
+ ## Details
225
+
226
+ | pkmn | Pokémon Crystal (pret) |
227
+ | ------------------------- | ------------------------------------------------- |
228
+ | `start` | `DoBattle` |
229
+ | `update` | `BattleTurn` |
230
+ | `selectMove` / `saveMove` | `CheckPlayerLockedIn` / `ParsePlayerAction` |
231
+ | `switchIn` | `SwitchPlayerMon` / `SendOutPlayerMon` |
232
+ | `turnOrder` | `DetermineMoveOrder` |
233
+ | `doTurn` | `DoTurn` |
234
+ | `executeMove` | `DoMove` |
235
+ | `beforeMove` | `CheckTurn` |
236
+ | `canMove` | |
237
+ | `decrementPP` | |
238
+ | `doMove` | |
239
+ | `checkCriticalHit` | `BattleCommand_Critical` |
240
+ | `calcDamage` | `BattleCommand_DamageCalc` / `PlayerAttackDamage` |
241
+ | `adjustDamage` | `BattleCommand_Stab` |
242
+ | `randomizeDamage` | `BattleCommand_DamageVariation` |
243
+ | `specialDamage` | `BattleCommand_ConstantDamage` |
244
+ | `applyDamage` | `BattleCommand_ApplyDamage` |
245
+ | `checkHit` | `BattleCommand_CheckHit` |
246
+ | `checkFaint` | `CheckFaint` |
247
+ | `handleResidual` | `ResidualDamage` |
248
+ | `endTurn` | `EndTurn` |
249
+
250
+ DoBattle
251
+ BattleTurn
252
+ - HandleBerserkGene
253
+ - CheckPlayerLockedIn
254
+ - BattleMenu
255
+ - ParsePlayerAction
256
+ - DetermineMoveOrder
257
+ - CompareMovePriority
258
+ - GetMovePriority
259
+ - Battle_*
260
+ - Handle*Switch
261
+ - SwitchPlayerMon
262
+ - BreakAttraction
263
+ - SendOutPlayerMon
264
+ - SpikesDamage
265
+ - *Turn_EndOpponentProtectEndureDestinyBond
266
+ - EndUserDestinyBond
267
+ - Do*Turn
268
+ - EndOpponentProtectEndureDestinyBond
269
+ - ResidualDamage
270
+ - CheckFaint_*
271
+ - HandleBetweenTurnEffects
272
+ - HandleFutureSight
273
+ - HandleWeather
274
+ - HandleWrap
275
+ - HandlePerishSong
276
+ - HandleLeftovers
277
+ - HandleMysteryBerry
278
+ - HandleDefrost
279
+ - HandleSafeguard
280
+ - HandleScreens
281
+ - HandleStatBoostingHeldItems
282
+ - HandleHealingItems
283
+ - HandleEncore
284
+
285
+ DoTurn
286
+ DoMove = executeMove
287
+ CheckTurn = beforeMove
288
+ BattleCommand_Critical = checkCriticalHit
289
+ BattleCommand_Stab = adjustDamage
290
+ BattleCommand_DamageVariation = randomizeDamage
291
+ BattleCommand_CheckHit = checkHit
292
+ BattleCommand_ApplyDamage = applyDamage
293
+ BattleCommand_CheckFaint
294
+ BattleCommand_BuildOpponentRage = buildRage
295
+ BattleCommand_DamageCalc (PlayerAttackDamage / EnemyAttackDamage) = calcDamage
296
+ BattleCommand_ConstantDamage = specialDamage
297
+ DoEnemyDamage / DoPlayerDamage / DoSubstituteDamage
298
+
223
299
  ==**TODO**==
224
300
 
225
301
  ## Protocol
@@ -227,62 +303,7 @@ padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
227
303
  TODO
228
304
 
229
305
  ```txt
230
- -activate: _, damage, move, name, number, of
231
- -anim: _
232
- -block: _
233
- -boost: _, from, silent
234
- -clearallboost: _
235
- -copyboost: from
236
- -crit: _
237
- -curestatus: msg
238
- -cureteam: from
239
- -damage: _, from, of, partiallytrapped
240
- -end: _, from, of, partiallytrapped, silent
241
- -enditem: _, eat
242
- -fail: _, block, weak
243
- -fieldactivate: _
244
- -heal: _, from, of, silent
245
- -hint: _
246
- -hitcount: _
247
- -immune: _, ohko
248
- -item: from, of
249
- -miss: _
250
- -mustrecharge: _
251
- -ohko: _
252
- -prepare: _
253
- -resisted: _
254
- -setboost: from
255
- -sethp: from, silent
256
- -sideend: _, from, of
257
- -sidestart: _
258
- -singlemove: _
259
- -singleturn: _
260
- -start: _, of, silent
261
- -status: _, from, silent
262
- -supereffective: _
263
- -transform: _
264
- -unboost: _
265
- -weather: _, upkeep
266
- cant: _
267
- debug: _
268
- done: _
269
- drag: _
270
- faint: _
271
- gametype: _
272
- gen: _
273
- move: _, from, miss, still
274
- player: _
275
- request: _
276
- rule: _
277
- start: _
278
- switch: _, from
279
- t:: _
280
- teamsize: _
281
- tie: _
282
- tier: _
283
- turn: _
284
- upkeep: _
285
- win: _
306
+ -activate: _, move, name, number
286
307
  ```
287
308
 
288
309
  ## Bugs
@@ -11,15 +11,15 @@ const Type = data.Type;
11
11
  /// Representation of a held item in Generation II Pokémon.
12
12
  pub const Item = enum(u8) {
13
13
  None,
14
+ SoftSand, // Ground
15
+ HardStone, // Rock
16
+ MetalCoat, // Steel
14
17
  PinkBow, // Normal
15
18
  BlackBelt, // Fighting
16
19
  SharpBeak, // Flying
17
20
  PoisonBarb, // Poison
18
- SoftSand, // Ground
19
- HardStone, // Rock
20
21
  SilverPowder, // Bug
21
22
  SpellTag, // Ghost
22
- MetalCoat, // Steel
23
23
  PolkadotBow, // ??? (Normal)
24
24
  Charcoal, // Fire
25
25
  MysticWater, // Water
@@ -36,21 +36,21 @@ pub const Item = enum(u8) {
36
36
  Stick,
37
37
  ThickClub,
38
38
  FocusBand, // FocusBand
39
- BerryJuice, // Berry
40
39
  ScopeLens, // CriticalUp
41
40
  Leftovers, // Leftovers
42
41
  BerserkGene,
43
42
  LightBall,
43
+ Berry, // Berry
44
+ BerryJuice, // Berry
45
+ GoldBerry, // Berry
46
+ MintBerry, // HealSleep
44
47
  PSNCureBerry, // HealPoison
45
48
  PRZCureBerry, // HealParalyze
46
- BurntBerry, // HealFreeze
47
49
  IceBerry, // HealBurn
48
- BitterBerry, // HealConfusion
49
- MintBerry, // HealSleep
50
+ BurntBerry, // HealFreeze
50
51
  MiracleBerry, // HealStatus
52
+ BitterBerry, // HealConfusion
51
53
  MysteryBerry, // RestorePP
52
- Berry, // Berry
53
- GoldBerry, // Berry
54
54
  MasterBall,
55
55
  UltraBall,
56
56
  GreatBall,
@@ -219,17 +219,11 @@ pub const Item = enum(u8) {
219
219
  pub inline fn boost(item: Item) ?Type {
220
220
  assert(item != .None);
221
221
  if (item == .PolkadotBow) return .Normal;
222
- return if (@intFromEnum(item) <= 18) @enumFromInt(Type, @intFromEnum(item) - 1) else null;
223
- }
224
-
225
- /// Whether or not this item is a Berry.
226
- pub inline fn berry(item: Item) bool {
227
- assert(item != .None);
228
- return @intFromEnum(item) > 30 and @intFromEnum(item) <= 40;
222
+ return if (@intFromEnum(item) <= 18) @enumFromInt(@intFromEnum(item) - 1) else null;
229
223
  }
230
224
 
231
225
  /// Whether or not this item is Mail.
232
- pub inline fn mail(item: Item) bool {
226
+ pub inline fn isMail(item: Item) bool {
233
227
  assert(item != .None);
234
228
  return @intFromEnum(item) > 60 and @intFromEnum(item) <= 70;
235
229
  }