@pkmn/engine 0.1.0-dev.a1fcc5d9 → 0.1.0-dev.a27b3ff3

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 (68) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +51 -5
  3. package/build/pkg/addon/browser.d.ts +1 -1
  4. package/build/pkg/addon/browser.js +6 -2
  5. package/build/pkg/addon/browser.js.map +1 -1
  6. package/build/pkg/addon/node.js +22 -8
  7. package/build/pkg/addon/node.js.map +1 -1
  8. package/build/pkg/addon/wasm.d.ts +2 -0
  9. package/build/pkg/addon/wasm.js +53 -0
  10. package/build/pkg/addon/wasm.js.map +1 -0
  11. package/build/pkg/addon.d.ts +24 -4
  12. package/build/pkg/addon.js +8 -17
  13. package/build/pkg/addon.js.map +1 -1
  14. package/build/pkg/data/layout.json +15 -2
  15. package/build/pkg/data/protocol.json +23 -9
  16. package/build/pkg/gen1.d.ts +15 -18
  17. package/build/pkg/gen1.js +28 -19
  18. package/build/pkg/gen1.js.map +1 -1
  19. package/build/pkg/index.d.ts +37 -100
  20. package/build/pkg/index.js +23 -75
  21. package/build/pkg/index.js.map +1 -1
  22. package/build/tools/debug.js +18 -9
  23. package/build/tools/debug.js.map +1 -1
  24. package/build/tools/display/debug.jsx +18 -7
  25. package/build/tools/display/debug.jsx.map +1 -1
  26. package/build/tools/display/index.js +35 -15
  27. package/build/tools/display/index.js.map +1 -1
  28. package/build/tools/display/ui.jsx +17 -7
  29. package/build/tools/display/ui.jsx.map +1 -1
  30. package/build/tools/display/util.js +16 -1
  31. package/build/tools/display/util.js.map +1 -1
  32. package/build.zig +198 -85
  33. package/package.json +29 -125
  34. package/src/bin/install-pkmn-engine +3 -2
  35. package/src/lib/bindings/c.zig +255 -0
  36. package/src/lib/bindings/node.zig +117 -0
  37. package/src/lib/bindings/wasm.zig +59 -0
  38. package/src/lib/common/array.zig +1 -1
  39. package/src/lib/common/js.zig +1 -5
  40. package/src/lib/common/napi.zig +4 -0
  41. package/src/lib/common/optional.zig +1 -1
  42. package/src/lib/common/options.zig +2 -0
  43. package/src/lib/common/protocol.zig +4 -8
  44. package/src/lib/common/rational.zig +281 -270
  45. package/src/lib/common/rng.zig +1 -3
  46. package/src/lib/common/util.zig +17 -2
  47. package/src/lib/gen1/calc.zig +52 -69
  48. package/src/lib/gen1/chance.zig +34 -18
  49. package/src/lib/gen1/data/moves.zig +2 -4
  50. package/src/lib/gen1/data/species.zig +1 -3
  51. package/src/lib/gen1/data/types.zig +2 -3
  52. package/src/lib/gen1/data.zig +7 -11
  53. package/src/lib/gen1/helpers.zig +4 -10
  54. package/src/lib/gen1/mechanics.zig +76 -51
  55. package/src/lib/gen2/calc.zig +10 -18
  56. package/src/lib/gen2/data/items.zig +1 -3
  57. package/src/lib/gen2/data/moves.zig +2 -4
  58. package/src/lib/gen2/data/species.zig +1 -3
  59. package/src/lib/gen2/data/types.zig +7 -5
  60. package/src/lib/gen2/data.zig +14 -17
  61. package/src/lib/gen2/generated.zig +18 -23
  62. package/src/lib/gen2/helpers.zig +5 -12
  63. package/src/lib/gen2/mechanics.zig +42 -39
  64. package/src/lib/node.zig +4 -121
  65. package/src/lib/pkmn.zig +7 -2
  66. package/src/lib/wasm.zig +13 -9
  67. package/src/tools/display/dom.ts +5 -8
  68. package/src/tools/display/ui.css +0 -5
@@ -1,36 +1,29 @@
1
- const std = @import("std");
2
-
3
- const pkmn = @import("../pkmn.zig");
1
+ const DEBUG = @import("../common/debug.zig").print;
4
2
 
3
+ const builtin = @import("builtin");
4
+ const chance = @import("chance.zig");
5
5
  const common = @import("../common/data.zig");
6
- const DEBUG = @import("../common/debug.zig").print;
6
+ const data = @import("data.zig");
7
+ const pkmn = @import("../pkmn.zig");
7
8
  const protocol = @import("../common/protocol.zig");
8
9
  const rng = @import("../common/rng.zig");
9
-
10
- const data = @import("data.zig");
11
- const chance = @import("chance.zig");
10
+ const std = @import("std");
12
11
 
13
12
  const assert = std.debug.assert;
14
-
15
- const expectEqual = std.testing.expectEqual;
16
-
17
- const showdown = pkmn.options.showdown;
18
-
19
- const Choice = common.Choice;
20
- const ID = common.ID;
21
- const Player = common.Player;
22
- const Result = common.Result;
23
-
24
13
  const Boost = protocol.Boost;
14
+ const Choice = common.Choice;
25
15
  const Damage = protocol.Damage;
16
+ const Effectiveness = data.Effectiveness;
17
+ const expectEqual = std.testing.expectEqual;
26
18
  const Fail = protocol.Fail;
27
- const Heal = protocol.Heal;
28
-
29
19
  const Gen12 = rng.Gen12;
30
-
31
- const Effectiveness = data.Effectiveness;
20
+ const Heal = protocol.Heal;
21
+ const ID = common.ID;
32
22
  const Move = data.Move;
33
23
  const MoveSlot = data.MoveSlot;
24
+ const Player = common.Player;
25
+ const Result = common.Result;
26
+ const showdown = pkmn.options.showdown;
34
27
  const Side = data.Side;
35
28
  const Species = data.Species;
36
29
  const Stats = data.Stats;
@@ -173,7 +166,10 @@ fn selectMove(
173
166
  if (foe_choice.type == .Switch) {
174
167
  const last = side.active.move(battle.lastMove(player).index);
175
168
  if (last.id == .Metronome) side.last_selected_move = last.id;
176
- if (last.id == .MirrorMove) return Result.Error;
169
+ if (last.id == .MirrorMove) {
170
+ if (!pkmn.options.mod) return Result.Error;
171
+ side.last_selected_move = last.id;
172
+ }
177
173
  }
178
174
  }
179
175
  return null;
@@ -424,7 +420,7 @@ fn executeMove(
424
420
  mslot = @intCast(battle.lastMove(player).index);
425
421
  const stored = side.stored();
426
422
  // GLITCH: Struggle bypass PP underflow via Hyper Beam / Trapping-switch auto selection
427
- auto = isForced(&side.active) or
423
+ auto = pkmn.options.mod or isForced(&side.active) or
428
424
  side.active.volatiles.Binding or side.active.volatiles.Bide or
429
425
  side.last_selected_move == .HyperBeam or
430
426
  Status.is(stored.status, .FRZ) or Status.is(stored.status, .SLP);
@@ -457,6 +453,25 @@ fn executeMove(
457
453
  .err => return @as(?Result, Result.Error),
458
454
  }
459
455
 
456
+ // Pokémon Showdown incorrectly implements PP deduction when handling the Hyper Beam automatic
457
+ // selection glitch - if the move was proced due to Metronome / Mirror Move it either subtracts
458
+ // from the Hyper Beam slot if present or skips PP deduction entirely...
459
+ if (showdown and !skip_pp and side.last_selected_move == .HyperBeam and
460
+ side.last_selected_move != side.active.move(mslot).id)
461
+ {
462
+ assert(mslot == 1);
463
+ const has_beam = has_beam: {
464
+ for (side.active.moves, 0..) |m, i| {
465
+ if (m.id == .HyperBeam) {
466
+ mslot = @intCast(i + 1);
467
+ break :has_beam true;
468
+ }
469
+ }
470
+ break :has_beam false;
471
+ };
472
+ if (!has_beam) skip_pp = true;
473
+ }
474
+
460
475
  const can = skip_can or
461
476
  try canMove(battle, player, mslot, auto, skip_pp, .None, residual, options);
462
477
  if (!can) return null;
@@ -554,7 +569,7 @@ fn beforeMove(
554
569
  // This can only happen if a Pokémon started the battle frozen/sleeping and was thawed/woken
555
570
  // before the side had a selected a move - we simply need to assume this leads to a desync
556
571
  if (side.last_selected_move == .None) {
557
- assert(!showdown);
572
+ assert(!pkmn.options.mod);
558
573
  return .err;
559
574
  }
560
575
 
@@ -603,17 +618,10 @@ fn beforeMove(
603
618
  return .err;
604
619
  }
605
620
  }
606
- // Pokémon Showdown incorrectly changes the "target" of the confusion self-hit based
607
- // on the targeting behavior of the confused Pokémon's selected move which results
608
- // in the wrong behavior with respect to the Substitute + Confusion glitch
609
- const target = if (showdown and Move.get(side.last_selected_move).target == .Self)
610
- player
611
- else
612
- player.foe();
613
621
 
614
622
  const uncapped = battle.last_damage;
615
623
  // Skipping adjustDamage / randomizeDamage / checkHit
616
- _ = try applyDamage(battle, player, target, .Confusion, options);
624
+ _ = try applyDamage(battle, player, player.foe(), .Confusion, options);
617
625
  // Pokémon Showdown thinks that confusion damage is uncapped ¯\_(ツ)_/¯
618
626
  if (showdown) battle.last_damage = uncapped;
619
627
 
@@ -773,9 +781,14 @@ fn canMove(
773
781
 
774
782
  if (move.effect == .Thrashing) {
775
783
  Effects.thrashing(battle, player, options);
776
- } else if (!showdown and move.effect == .Binding) {
777
- // Pokémon Showdown handles this after hit/miss checks and damage calculation
778
- try Effects.binding(battle, player, false, options);
784
+ } else if (move.effect == .Binding) {
785
+ // Pokémon Showdown handles this after hit/miss checks and damage calculation, though clears
786
+ // Recharging in onTryMove (required for the Hyper Beam automatic selection glitch)
787
+ if (showdown) {
788
+ battle.foe(player).active.volatiles.Recharging = false;
789
+ } else {
790
+ try Effects.binding(battle, player, false, options);
791
+ }
779
792
  }
780
793
 
781
794
  return true;
@@ -1129,7 +1142,7 @@ fn calcDamage(
1129
1142
  if ((!showdown or !cfz) and (atk > 255 or def > 255)) {
1130
1143
  atk = @max((atk / 4) & 255, 1);
1131
1144
  // GLITCH: not adjusted to be a min of 1 on cartridge (can lead to division-by-zero freeze)
1132
- def = @max((def / 4) & 255, if (showdown) 1 else 0);
1145
+ def = @max((def / 4) & 255, if (pkmn.options.mod) 1 else 0);
1133
1146
  }
1134
1147
 
1135
1148
  const lvl: u32 = side.stored().level * @as(u2, if (crit) 2 else 1);
@@ -1150,7 +1163,7 @@ fn calcDamage(
1150
1163
  // encountered so we need to make sure that in the event of a miss we commit the status of the
1151
1164
  // crit roll. The alternative to doing this extra work is to *always* commit the crit roll but
1152
1165
  // that results in counter intuitive probabilities in the common case
1153
- if (pkmn.options.chance and !showdown) {
1166
+ if (pkmn.options.chance and !pkmn.options.mod and move.effect != .Explode) {
1154
1167
  atk = attack(side, !crit, special);
1155
1168
  def = defense(target, !crit, special, false);
1156
1169
  if ((atk > 255 or def > 255) and (def / 4) & 255 == 0) options.chance.glitch();
@@ -1235,13 +1248,13 @@ fn specialDamage(battle: anytype, player: Player, move: Move.Data, options: anyt
1235
1248
  .Psywave => power: {
1236
1249
  const max: u8 = @intCast(@as(u16, side.stored().level) * 3 / 2);
1237
1250
  // GLITCH: Psywave infinite glitch loop
1238
- if (!showdown and max <= 1) return Result.Error;
1251
+ if (!pkmn.options.mod and max <= 1) return Result.Error;
1239
1252
  break :power try Rolls.psywave(battle, player, max, options);
1240
1253
  },
1241
1254
  else => unreachable,
1242
1255
  };
1243
1256
 
1244
- if (battle.last_damage == 0) return if (showdown) null else Result.Error;
1257
+ if (battle.last_damage == 0) return if (pkmn.options.mod) null else Result.Error;
1245
1258
 
1246
1259
  const sub = showdown and foe.active.volatiles.Substitute;
1247
1260
  _ = try applyDamage(battle, player.foe(), player.foe(), .None, options);
@@ -1278,12 +1291,16 @@ fn counterDamage(battle: anytype, player: Player, move: Move.Data, options: anyt
1278
1291
 
1279
1292
  if (!used or !selected) {
1280
1293
  // GLITCH: Counter desync (covered by Desync Clause Mod on Pokémon Showdown)
1281
- if (!showdown) return Result.Error;
1294
+ if (!pkmn.options.mod) return Result.Error;
1282
1295
  try options.log.fail(.{ battle.active(player), .None });
1283
1296
  return null;
1284
1297
  }
1285
1298
 
1286
- battle.last_damage *|= 2;
1299
+ // NOTE: llvm/llvm-project#58557
1300
+ battle.last_damage = if (comptime builtin.target.cpu.arch.isWasm())
1301
+ @max(battle.last_damage *% 2, std.math.maxInt(u16))
1302
+ else
1303
+ battle.last_damage *| 2;
1287
1304
 
1288
1305
  // Pokémon Showdown calls moveHit before Counter
1289
1306
  if (!showdown and !try checkHit(battle, player, move, options)) return null;
@@ -1429,7 +1446,16 @@ fn moveHit(
1429
1446
  break :miss true;
1430
1447
  }
1431
1448
  if (!showdown) {
1432
- if (move.effect == .Swift) return true;
1449
+ if (move.effect == .Swift) {
1450
+ // If Swift could cause a division-by-zero freeze (which doesn't exist on Pokémon
1451
+ // Showdown, hence why the block above doesn't include this code), we need the
1452
+ // damage roll to be committed. However, the commit code will not save this roll if
1453
+ // the glitch occurs and the move was not marked as having hit. To work around this
1454
+ // we flag that the move hit (as Swift trivially does), but pass the probability of
1455
+ // the hit as zero to ensure it doesn't actually get saved.
1456
+ try options.chance.hit(player, true, 0);
1457
+ return true;
1458
+ }
1433
1459
  if (foe.active.volatiles.Invulnerable) break :miss true;
1434
1460
  }
1435
1461
 
@@ -1525,7 +1551,7 @@ fn faint(battle: anytype, player: Player, done: bool, cap: bool, options: anytyp
1525
1551
  assert(!foe_volatiles.MultiHit);
1526
1552
  if (foe_volatiles.Bide) {
1527
1553
  assert(!foe_volatiles.Thrashing and !foe_volatiles.Rage);
1528
- foe_volatiles.state = if (showdown) 0 else foe_volatiles.state & 255;
1554
+ foe_volatiles.state = if (pkmn.options.mod) 0 else foe_volatiles.state & 255;
1529
1555
  if (foe_volatiles.state != 0) return Result.Error;
1530
1556
  }
1531
1557
 
@@ -1616,12 +1642,12 @@ fn endTurn(battle: anytype, options: anytype) @TypeOf(options.log).Error!Result
1616
1642
 
1617
1643
  battle.turn += 1;
1618
1644
 
1619
- if (showdown and pkmn.options.ebc and checkEBC(battle)) {
1645
+ if (pkmn.options.mod and pkmn.options.ebc and checkEBC(battle)) {
1620
1646
  try options.log.tie(.{});
1621
1647
  return Result.Tie;
1622
1648
  }
1623
1649
 
1624
- if (showdown and battle.turn >= 1000) {
1650
+ if (pkmn.options.mod and battle.turn >= 1000) {
1625
1651
  try options.log.tie(.{});
1626
1652
  return Result.Tie;
1627
1653
  } else if (battle.turn >= 65535) {
@@ -1916,12 +1942,11 @@ pub const Effects = struct {
1916
1942
 
1917
1943
  // Technically this is still considered simply a "miss" on the cartridge,
1918
1944
  // but diverging from Pokémon Showdown here would mostly just be pedantic
1919
- if (n == 0) {
1945
+ if (n == 0 or (pkmn.options.mod and err)) {
1920
1946
  try options.log.fail(.{ foe_ident, .None });
1921
1947
  return null;
1922
1948
  } else if (err) {
1923
1949
  // GLITCH: Transform + Mirror Move / Metronome PP softlock
1924
- assert(!showdown);
1925
1950
  return Result.Error;
1926
1951
  }
1927
1952
 
@@ -1999,7 +2024,7 @@ pub const Effects = struct {
1999
2024
  if (foe.active.types.includes(move.type)) return;
2000
2025
  if (!try Rolls.secondaryChance(battle, player, true, options)) return;
2001
2026
  // Freeze Clause Mod
2002
- if (showdown) for (foe.pokemon) |p| if (Status.is(p.status, .FRZ)) return;
2027
+ if (pkmn.options.mod) for (foe.pokemon) |p| if (Status.is(p.status, .FRZ)) return;
2003
2028
 
2004
2029
  foe_stored.status = Status.init(.FRZ);
2005
2030
  // GLITCH: Hyper Beam recharging status is not cleared
@@ -2340,7 +2365,7 @@ pub const Effects = struct {
2340
2365
  }
2341
2366
 
2342
2367
  // Sleep Clause Mod
2343
- if (showdown) {
2368
+ if (pkmn.options.mod) {
2344
2369
  for (foe.pokemon) |p| {
2345
2370
  if (Status.is(p.status, .SLP) and !Status.is(p.status, .EXT)) return;
2346
2371
  }
@@ -2446,7 +2471,7 @@ pub const Effects = struct {
2446
2471
  if (side.active.volatiles.Binding) return;
2447
2472
  side.active.volatiles.Binding = true;
2448
2473
  // GLITCH: Hyper Beam automatic selection glitch if Recharging gets cleared on miss
2449
- // (Pokémon Showdown unitentionally patches this glitch, preventing automatic selection)
2474
+ // (Pokémon Showdown clears Recharging in onTryMove instead)
2450
2475
  if (!showdown) {
2451
2476
  foe.active.volatiles.Recharging = false;
2452
2477
  } else if (foe.stored().hp == 0) return if (!rewrap) battle.rng.advance(1);
@@ -3212,7 +3237,7 @@ pub fn choices(battle: anytype, player: Player, request: Choice.Type, out: []Cho
3212
3237
  // Struggle (Pokémon Showdown would use 'move 1' here)
3213
3238
  if (n == before) {
3214
3239
  // GLITCH: Transform + Mirror Move / Metronome PP softlock
3215
- if (!showdown) {
3240
+ if (!pkmn.options.mod) {
3216
3241
  while (slot <= 4) : (slot += 1) {
3217
3242
  if (active.moves[slot - 1].pp != 0) return n;
3218
3243
  }
@@ -1,27 +1,19 @@
1
- const std = @import("std");
2
-
3
- const pkmn = @import("../pkmn.zig");
4
-
1
+ const chance = @import("chance.zig");
5
2
  const common = @import("../common/data.zig");
6
- const util = @import("../common/util.zig");
7
-
8
3
  const Optional = @import("../common/optional.zig").Optional;
4
+ const pkmn = @import("../pkmn.zig");
5
+ const std = @import("std");
6
+ const util = @import("../common/util.zig");
9
7
 
10
- const chance = @import("chance.zig");
11
-
8
+ const Action = chance.Action;
9
+ const Actions = chance.Actions;
12
10
  const assert = std.debug.assert;
13
-
11
+ const Criticals = chance.Criticals;
12
+ const Damages = chance.Damages;
14
13
  const enabled = pkmn.options.calc;
15
-
14
+ const isPointerTo = util.isPointerTo;
16
15
  const Player = common.Player;
17
-
18
16
  const PointerType = util.PointerType;
19
- const isPointerTo = util.isPointerTo;
20
-
21
- const Actions = chance.Actions;
22
- const Action = chance.Action;
23
- const Criticals = chance.Criticals;
24
- const Damages = chance.Damages;
25
17
 
26
18
  const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
27
19
  const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
@@ -156,6 +148,6 @@ fn ReturnType(comptime field: Action.Field) type {
156
148
  return ?(switch (field) {
157
149
  .damages => u8,
158
150
  .critical_hits => Optional(bool),
159
- else => std.meta.FieldType(Action, field),
151
+ else => util.FieldType(Action, field),
160
152
  });
161
153
  }
@@ -1,11 +1,9 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const data = @import("../../gen2/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
-
9
7
  const Type = data.Type;
10
8
 
11
9
  /// Representation of a held item in Generation II Pokémon.
@@ -1,12 +1,10 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
- const rng = @import("../../common/rng.zig");
6
3
  const gen2 = @import("../../gen2/data.zig");
4
+ const rng = @import("../../common/rng.zig");
5
+ const std = @import("std");
7
6
 
8
7
  const assert = std.debug.assert;
9
-
10
8
  const percent = rng.Gen12.percent;
11
9
  const Type = gen2.Type;
12
10
 
@@ -1,11 +1,9 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const gen2 = @import("../../gen2/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
-
9
7
  const Stats = gen2.Stats;
10
8
  const Types = gen2.Types;
11
9
 
@@ -1,8 +1,7 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const gen1 = @import("../../gen1/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
7
  const Effectiveness = gen1.Effectiveness;
@@ -173,9 +172,12 @@ pub const Type = enum(u8) {
173
172
  return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
174
173
  }
175
174
 
176
- /// The precedence order of Type `type`.
177
- pub fn precedence(self: Type) u8 {
178
- return PRECEDENCE[@intFromEnum(self)];
175
+ /// The precedence order of Type `t1` vs. Type `t2`.
176
+ pub fn precedence(t1: Type, t2: Type) u8 {
177
+ // The Ice vs. Fire matchup is out of order - return a higher
178
+ // number than anything else so that it sorts last correctly
179
+ if (t1 == .Ice and t2 == .Fire) return 18;
180
+ return PRECEDENCE[@intFromEnum(t2)];
179
181
  }
180
182
 
181
183
  /// The internal index of this Type used by Present.
@@ -1,24 +1,20 @@
1
- const std = @import("std");
2
- const builtin = @import("builtin");
3
-
4
- const pkmn = @import("../pkmn.zig");
5
-
6
- const data = @import("../common/data.zig");
7
1
  const DEBUG = @import("../common/debug.zig").print;
8
- const protocol = @import("../common/protocol.zig");
9
- const rng = @import("../common/rng.zig");
10
- const util = @import("../common/util.zig");
11
2
 
3
+ const builtin = @import("builtin");
4
+ const calc = @import("calc.zig");
5
+ const chance = @import("chance.zig");
6
+ const data = @import("../common/data.zig");
7
+ const gen1 = @import("../gen1/data.zig");
12
8
  const items = @import("data/items.zig");
9
+ const mechanics = @import("mechanics.zig");
13
10
  const moves = @import("data/moves.zig");
11
+ const pkmn = @import("../pkmn.zig");
12
+ const protocol = @import("../common/protocol.zig");
13
+ const rng = @import("../common/rng.zig");
14
14
  const species = @import("data/species.zig");
15
+ const std = @import("std");
15
16
  const types = @import("data/types.zig");
16
-
17
- const gen1 = @import("../gen1/data.zig");
18
-
19
- const calc = @import("calc.zig");
20
- const chance = @import("chance.zig");
21
- const mechanics = @import("mechanics.zig");
17
+ const util = @import("../common/util.zig");
22
18
 
23
19
  const assert = std.debug.assert;
24
20
  const expectEqual = std.testing.expectEqual;
@@ -453,8 +449,9 @@ test Types {
453
449
  try expect(!Type.Steel.special());
454
450
  try expect(Type.Dark.special());
455
451
 
456
- try expectEqual(@as(u8, 3), Type.Water.precedence());
457
- try expect(Type.Bug.precedence() > Type.Poison.precedence());
452
+ try expectEqual(@as(u8, 3), Type.precedence(.Water, .Water));
453
+ try expect(Type.precedence(.Poison, .Bug) > Type.precedence(.Poison, .Poison));
454
+ try expect(Type.precedence(.Ice, .Fire) > Type.precedence(.Ice, .Water));
458
455
 
459
456
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
460
457
  try expectEqual(Effectiveness.Super, Type.effectiveness(.Water, .Fire));
@@ -1,37 +1,32 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const common = @import("../common/data.zig");
6
-
7
4
  const data = @import("data.zig");
8
5
  const mechanics = @import("mechanics.zig");
6
+ const std = @import("std");
9
7
 
10
- const Player = common.Player;
11
- const Result = common.Result;
12
-
13
- const Effectiveness = data.Effectiveness;
14
- const Move = data.Move;
15
-
16
- const Effects = mechanics.Effects;
17
- const State = mechanics.State;
18
-
19
- const canMove = mechanics.canMove;
8
+ const adjustDamage = mechanics.adjustDamage;
9
+ const afterMove = mechanics.afterMove;
10
+ const applyDamage = mechanics.applyDamage;
11
+ const buildRage = mechanics.buildRage;
12
+ const calcDamage = mechanics.calcDamage;
20
13
  const canCharge = mechanics.canCharge;
14
+ const canMove = mechanics.canMove;
15
+ const checkCriticalHit = mechanics.checkCriticalHit;
16
+ const checkHit = mechanics.checkHit;
21
17
  const decrementPP = mechanics.decrementPP;
18
+ const destinyBond = mechanics.destinyBond;
22
19
  const doMove = mechanics.doMove;
23
- const checkHit = mechanics.checkHit;
24
- const checkCriticalHit = mechanics.checkCriticalHit;
25
- const calcDamage = mechanics.calcDamage;
26
- const adjustDamage = mechanics.adjustDamage;
27
- const randomizeDamage = mechanics.randomizeDamage;
28
- const applyDamage = mechanics.applyDamage;
29
- const reportOutcome = mechanics.reportOutcome;
30
20
  const effectChance = mechanics.effectChance;
31
- const afterMove = mechanics.afterMove;
32
- const buildRage = mechanics.buildRage;
21
+ const Effectiveness = data.Effectiveness;
22
+ const Effects = mechanics.Effects;
33
23
  const kingsRock = mechanics.kingsRock;
34
- const destinyBond = mechanics.destinyBond;
24
+ const Move = data.Move;
25
+ const Player = common.Player;
26
+ const randomizeDamage = mechanics.randomizeDamage;
27
+ const reportOutcome = mechanics.reportOutcome;
28
+ const Result = common.Result;
29
+ const State = mechanics.State;
35
30
 
36
31
  const SECONDARY = true;
37
32
  const KINGS = true;
@@ -1,25 +1,18 @@
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
5
  const rng = @import("../common/rng.zig");
6
-
7
- const gen1 = @import("../gen1/data.zig");
8
-
9
- const data = @import("data.zig");
6
+ const std = @import("std");
10
7
 
11
8
  const assert = std.debug.assert;
12
-
13
9
  const Choice = common.Choice;
14
-
15
- const showdown = options.showdown;
16
-
17
- const PSRNG = rng.PSRNG;
18
-
19
10
  const DVs = data.DVs;
20
11
  const Item = data.Item;
21
12
  const Move = data.Move;
22
13
  const MoveSlot = data.MoveSlot;
14
+ const PSRNG = rng.PSRNG;
15
+ const showdown = options.showdown;
23
16
  const Species = data.Species;
24
17
  const Stats = data.Stats;
25
18