@pkmn/engine 0.1.0-dev.46307385 → 0.1.0-dev.49f6bf26

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 (48) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +37 -14
  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 +2 -2
  6. package/build/pkg/data/protocol.json +69 -12
  7. package/build/pkg/data.d.ts +3 -2
  8. package/build/pkg/data.js.map +1 -1
  9. package/build/pkg/gen1.js +2 -2
  10. package/build/pkg/gen1.js.map +1 -1
  11. package/build/pkg/index.d.ts +2 -1
  12. package/build/pkg/index.js.map +1 -1
  13. package/build/pkg/protocol.js +57 -38
  14. package/build/pkg/protocol.js.map +1 -1
  15. package/build/test/display.js.map +1 -1
  16. package/build/tools/debug.js +3 -1
  17. package/build/tools/debug.js.map +1 -1
  18. package/build.zig +84 -64
  19. package/package.json +43 -22
  20. package/src/bin/install-pkmn-engine +14 -14
  21. package/src/lib/common/data.zig +12 -24
  22. package/src/lib/common/optional.zig +9 -2
  23. package/src/lib/common/protocol.zig +792 -319
  24. package/src/lib/common/rational.zig +12 -8
  25. package/src/lib/common/rng.zig +20 -11
  26. package/src/lib/gen1/README.md +31 -29
  27. package/src/lib/gen1/calc.zig +9 -10
  28. package/src/lib/gen1/chance.zig +74 -58
  29. package/src/lib/gen1/data/moves.zig +192 -180
  30. package/src/lib/gen1/data/species.zig +2 -2
  31. package/src/lib/gen1/data/types.zig +7 -7
  32. package/src/lib/gen1/data.zig +47 -59
  33. package/src/lib/gen1/helpers.zig +33 -48
  34. package/src/lib/gen1/mechanics.zig +317 -368
  35. package/src/lib/gen2/README.md +93 -72
  36. package/src/lib/gen2/calc.zig +143 -0
  37. package/src/lib/gen2/chance.zig +1314 -0
  38. package/src/lib/gen2/data/items.zig +12 -18
  39. package/src/lib/gen2/data/moves.zig +663 -569
  40. package/src/lib/gen2/data/species.zig +1 -1
  41. package/src/lib/gen2/data/types.zig +134 -31
  42. package/src/lib/gen2/data.zig +106 -79
  43. package/src/lib/gen2/generated.zig +806 -0
  44. package/src/lib/gen2/helpers.zig +8 -12
  45. package/src/lib/gen2/mechanics.zig +3502 -9
  46. package/src/lib/{binding/node.zig → node.zig} +10 -13
  47. package/src/lib/pkmn.zig +26 -3
  48. package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
@@ -32,25 +32,26 @@ 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.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` |
52
51
  | | `PlayerCharging` | |
53
- | | `PlayerJustGotFrozen` | |
52
+ | `volatiles.switched` | `TODO` | `pokemon.switchFlag` |
53
+ | `volatiles.switching` | `PlayerIsSwitching` | `pokemon.switchFlag` |
54
+ | `volatiles.frozen` | `PlayerJustGotFrozen` | `volatiles.frozen` |
54
55
  | | | |
55
56
  | `active.last_used_move` | `PlayerUsedMove` | `side.lastMove` |
56
57
 
@@ -219,6 +220,81 @@ much overhead the preceding representations have after taking into consideration
219
220
  padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
220
221
  [denormalization](https://en.wikipedia.org/wiki/Denormalization):
221
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
+
222
298
  ==**TODO**==
223
299
 
224
300
  ## Protocol
@@ -226,62 +302,7 @@ padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
226
302
  TODO
227
303
 
228
304
  ```txt
229
- -activate: _, damage, move, name, number, of
230
- -anim: _
231
- -block: _
232
- -boost: _, from, silent
233
- -clearallboost: _
234
- -copyboost: from
235
- -crit: _
236
- -curestatus: msg
237
- -cureteam: from
238
- -damage: _, from, of, partiallytrapped
239
- -end: _, from, of, partiallytrapped, silent
240
- -enditem: _, eat
241
- -fail: _, block, weak
242
- -fieldactivate: _
243
- -heal: _, from, of, silent
244
- -hint: _
245
- -hitcount: _
246
- -immune: _, ohko
247
- -item: from, of
248
- -miss: _
249
- -mustrecharge: _
250
- -ohko: _
251
- -prepare: _
252
- -resisted: _
253
- -setboost: from
254
- -sethp: from, silent
255
- -sideend: _, from, of
256
- -sidestart: _
257
- -singlemove: _
258
- -singleturn: _
259
- -start: _, of, silent
260
- -status: _, from, silent
261
- -supereffective: _
262
- -transform: _
263
- -unboost: _
264
- -weather: _, upkeep
265
- cant: _
266
- debug: _
267
- done: _
268
- drag: _
269
- faint: _
270
- gametype: _
271
- gen: _
272
- move: _, from, miss, still
273
- player: _
274
- request: _
275
- rule: _
276
- start: _
277
- switch: _, from
278
- t:: _
279
- teamsize: _
280
- tie: _
281
- tier: _
282
- turn: _
283
- upkeep: _
284
- win: _
305
+ -activate: _, move, name, number
285
306
  ```
286
307
 
287
308
  ## Bugs
@@ -0,0 +1,143 @@
1
+ const std = @import("std");
2
+
3
+ const pkmn = @import("../pkmn.zig");
4
+
5
+ const common = @import("../common/data.zig");
6
+ const util = @import("../common/util.zig");
7
+
8
+ const chance = @import("chance.zig");
9
+
10
+ const assert = std.debug.assert;
11
+
12
+ const enabled = pkmn.options.calc;
13
+
14
+ const Player = common.Player;
15
+
16
+ const PointerType = util.PointerType;
17
+
18
+ const Actions = chance.Actions;
19
+ const Action = chance.Action;
20
+
21
+ /// Information relevant to damage calculation that occured during a Generation II battle `update`.
22
+ pub const Summaries = extern struct {
23
+ /// Relevant information for Player 1.
24
+ p1: Summary = .{},
25
+ /// Relevant information for Player 2.
26
+ p2: Summary = .{},
27
+
28
+ comptime {
29
+ assert(@sizeOf(Summaries) == 12);
30
+ }
31
+
32
+ /// Returns the `Summary` for the given `player`.
33
+ pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Summary) {
34
+ assert(@typeInfo(@TypeOf(self)).Pointer.child == Summaries);
35
+ return if (player == .P1) &self.p1 else &self.p2;
36
+ }
37
+ };
38
+
39
+ /// Information relevant to damage calculation that occured during a Generation II battle `update`
40
+ /// for a single player.
41
+ pub const Summary = extern struct {
42
+ /// The computed raw damage values.
43
+ damage: Damage = .{},
44
+
45
+ /// Intermediate raw damage values computed during a calculation.
46
+ pub const Damage = extern struct {
47
+ /// The base computed damage before the damage roll is applied.
48
+ base: u16 = 0,
49
+ /// The final computed damage that gets applied to the Pokémon. May exceed the target's HP
50
+ // (to determine the *actual* damage done compare the target's stored HP before and after).
51
+ final: u16 = 0,
52
+ /// Whether higher damage will saturate / result in the same outcome (e.g. additional damage
53
+ /// gets ignored due to it already breaking a Substitute or causing the target to faint).
54
+ capped: bool = false,
55
+
56
+ // NOTE: 15 bits padding
57
+
58
+ comptime {
59
+ assert(@sizeOf(Damage) == 6);
60
+ }
61
+ };
62
+
63
+ comptime {
64
+ assert(@sizeOf(Summary) == 6);
65
+ }
66
+ };
67
+
68
+ /// TODO
69
+ pub const Overrides = extern struct {
70
+ /// TODO
71
+ actions: Actions = .{},
72
+ };
73
+
74
+ /// Allows for forcing the value of specific RNG events during a Generation II battle `update` via
75
+ /// `overrides` and tracks `summaries` of information relevant to damage calculation.
76
+ pub const Calc = struct {
77
+ /// Overrides the normal behavior of the RNG during an `update` to force specific outcomes.
78
+ overrides: Overrides = .{},
79
+ /// Information relevant to damage calculation.
80
+ summaries: Summaries = .{},
81
+
82
+ pub fn overridden(
83
+ self: Calc,
84
+ player: Player,
85
+ comptime field: Action.Field,
86
+ ) ?std.meta.FieldType(Action, field) {
87
+ if (!enabled) return null;
88
+
89
+ const overrides =
90
+ if (player == .P1) self.overrides.actions.p1 else self.overrides.actions.p2;
91
+ const val = @field(overrides, @tagName(field));
92
+ return if (switch (@typeInfo(@TypeOf(val))) {
93
+ .Enum => val != .None,
94
+ .Int => val != 0,
95
+ else => unreachable,
96
+ }) val else null;
97
+ }
98
+
99
+ pub fn base(self: *Calc, player: Player, val: u16) void {
100
+ if (!enabled) return;
101
+
102
+ self.summaries.get(player).damage.base = val;
103
+ }
104
+
105
+ pub fn final(self: *Calc, player: Player, val: u16) void {
106
+ if (!enabled) return;
107
+
108
+ self.summaries.get(player).damage.final = val;
109
+ }
110
+
111
+ pub fn capped(self: *Calc, player: Player) void {
112
+ if (!enabled) return;
113
+
114
+ self.summaries.get(player).damage.capped = true;
115
+ }
116
+ };
117
+
118
+ /// Null object pattern implementation of Generation II `Calc` which does nothing, though damage
119
+ /// calculator support should additionally be turned off entirely via `options.calc`.
120
+ pub const NULL: Null = .{};
121
+
122
+ const Null = struct {
123
+ pub fn overridden(
124
+ self: Null,
125
+ player: Player,
126
+ comptime field: Action.Field,
127
+ ) ?std.meta.FieldType(Action, field) {
128
+ _ = .{ self, player };
129
+ return null;
130
+ }
131
+
132
+ pub fn base(self: Null, player: Player, val: u16) void {
133
+ _ = .{ self, player, val };
134
+ }
135
+
136
+ pub fn final(self: Null, player: Player, val: u16) void {
137
+ _ = .{ self, player, val };
138
+ }
139
+
140
+ pub fn capped(self: Null, player: Player) void {
141
+ _ = .{ self, player };
142
+ }
143
+ };