@pkmn/engine 0.1.0-dev.8b83af6b → 0.1.0-dev.90d6c14c

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.
@@ -1,15 +1,19 @@
1
1
  const std = @import("std");
2
2
  const builtin = @import("builtin");
3
3
 
4
+ const pkmn = @import("../pkmn.zig");
5
+
4
6
  const data = @import("../common/data.zig");
5
- const options = @import("../common/options.zig");
6
7
  const protocol = @import("../common/protocol.zig");
7
8
  const rng = @import("../common/rng.zig");
9
+ const util = @import("../common/util.zig");
8
10
 
9
11
  const moves = @import("data/moves.zig");
10
12
  const species = @import("data/species.zig");
11
13
  const types = @import("data/types.zig");
12
14
 
15
+ const calc = @import("calc.zig");
16
+ const chance = @import("chance.zig");
13
17
  const mechanics = @import("mechanics.zig");
14
18
 
15
19
  const assert = std.debug.assert;
@@ -34,12 +38,17 @@ pub const LOGS_SIZE = if (builtin.mode == .ReleaseSmall)
34
38
  else
35
39
  std.math.ceilPowerOfTwo(usize, MAX_LOGS) catch unreachable;
36
40
 
41
+ /// Null object pattern implementation of pkmn.battle.Options for Generation I.
42
+ pub const NULL = pkmn.battle.options(protocol.NULL, chance.NULL, calc.NULL);
43
+
37
44
  const Choice = data.Choice;
38
45
  const ID = data.ID;
39
46
  const Player = data.Player;
40
47
  const Result = data.Result;
41
48
 
42
- const showdown = options.showdown;
49
+ const PointerType = util.PointerType;
50
+
51
+ const showdown = pkmn.options.showdown;
43
52
 
44
53
  /// The pseudo random number generator used by Generation I.
45
54
  pub const PRNG = rng.PRNG(1);
@@ -61,24 +70,27 @@ pub fn Battle(comptime RNG: anytype) type {
61
70
  rng: RNG,
62
71
 
63
72
  /// Returns the `Side` for the given `player`.
64
- pub inline fn side(self: *Self, player: Player) *Side {
73
+ pub inline fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
74
+ assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
65
75
  return &self.sides[@intFromEnum(player)];
66
76
  }
67
77
 
68
78
  /// Returns the `Side` of the opponent for the given `player`
69
- pub inline fn foe(self: *Self, player: Player) *Side {
79
+ pub inline fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
80
+ assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
70
81
  return &self.sides[@intFromEnum(player.foe())];
71
82
  }
72
83
 
73
84
  /// Returns an identifier for the active Pokémon of `player`.
74
- pub inline fn active(self: *Self, player: Player) ID {
85
+ pub inline fn active(self: *const Self, player: Player) ID {
75
86
  return player.ident(@intCast(self.side(player).order[0]));
76
87
  }
77
88
 
78
89
  /// Returns the result of applying Player 1's choice `c1` and Player 2's choice `c2` to the
79
- /// battle, optionally writing protocol message logs to `log` if `options.log` is enabled.
80
- pub fn update(self: *Self, c1: Choice, c2: Choice, log: anytype) !Result {
81
- return mechanics.update(self, c1, c2, log);
90
+ /// battle, optionally writing protocol message logs to `options.log` if `pkmn.options.log`
91
+ /// is enabled.
92
+ pub fn update(self: *Self, c1: Choice, c2: Choice, options: anytype) !Result {
93
+ return mechanics.update(self, c1, c2, options);
82
94
  }
83
95
 
84
96
  /// Fills in at most `out.len` possible choices for the `player` given the previous `result`
@@ -90,7 +102,7 @@ pub fn Battle(comptime RNG: anytype) type {
90
102
  /// interacts with Disable, in which case there are no possible choices for the player to
91
103
  /// make (i.e. on the cartridge a soft-lock occurs).
92
104
  ///
93
- /// This function will always return a number of choices > 0 if options.showdown is true.
105
+ /// This function will always return choices > 0 if `pkmn.options.showdown` is true.
94
106
  pub fn choices(self: *Self, player: Player, request: Choice.Type, out: []Choice) u8 {
95
107
  return mechanics.choices(self, player, request, out);
96
108
  }
@@ -120,7 +132,8 @@ pub const Side = extern struct {
120
132
  }
121
133
 
122
134
  /// Returns the stored `Pokemon` corresponding to the one-indexed party `slot`.
123
- pub inline fn get(self: *Side, slot: u8) *Pokemon {
135
+ pub inline fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
136
+ assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
124
137
  assert(slot > 0 and slot <= 6);
125
138
  const id = self.order[slot - 1];
126
139
  assert(id > 0 and id <= 6);
@@ -128,7 +141,8 @@ pub const Side = extern struct {
128
141
  }
129
142
 
130
143
  /// Returns the stored `Pokemon` corresponding to the `active` Pokémon (slot 1).
131
- pub inline fn stored(self: *Side) *Pokemon {
144
+ pub inline fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
145
+ assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
132
146
  return self.get(1);
133
147
  }
134
148
  };
@@ -153,7 +167,8 @@ pub const ActivePokemon = extern struct {
153
167
  }
154
168
 
155
169
  /// Returns the active Pokémon's current move slot located at the one-indexed `mslot`.
156
- pub inline fn move(self: *ActivePokemon, mslot: u8) *MoveSlot {
170
+ pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
171
+ assert(@typeInfo(@TypeOf(self)).Pointer.child == ActivePokemon);
157
172
  assert(mslot > 0 and mslot <= 4);
158
173
  assert(self.moves[mslot - 1].id != .None);
159
174
  return &self.moves[mslot - 1];
@@ -182,7 +197,8 @@ pub const Pokemon = extern struct {
182
197
  }
183
198
 
184
199
  /// Returns the Pokémon's original move slot located at the one-indexed `mslot`.
185
- pub inline fn move(self: *Pokemon, mslot: u8) *MoveSlot {
200
+ pub inline fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
201
+ assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
186
202
  assert(mslot > 0 and mslot <= 4);
187
203
  assert(self.moves[mslot - 1].id != .None);
188
204
  return &self.moves[mslot - 1];
@@ -204,16 +220,16 @@ pub const MoveSlot = extern struct {
204
220
  /// Details required to detect desyncs based on the move last selected/executed by players.
205
221
  pub const MoveDetails = packed struct {
206
222
  /// The move slot index of the last move selected in the battle menu by Player 1
207
- p1_index: if (showdown) u8 else u3 = 0,
223
+ p1_index: if (showdown) u8 else u4 = 0,
208
224
  /// Whether the last move executed by Player 1 was counterable.
209
- p1_counterable: if (showdown) u8 else u1 = 0,
225
+ p1_counterable: if (showdown) u8 else u4 = 0,
210
226
  /// The move slot index of the last move selected in the battle menu by Player 2
211
- p2_index: if (showdown) u8 else u3 = 0,
227
+ p2_index: if (showdown) u8 else u4 = 0,
212
228
  /// Whether the last move executed by Player 2 was counterable.
213
- p2_counterable: if (showdown) u8 else u1 = 0,
229
+ p2_counterable: if (showdown) u8 else u4 = 0,
214
230
 
215
231
  comptime {
216
- assert(@sizeOf(MoveDetails) == if (showdown) 4 else 1);
232
+ assert(@sizeOf(MoveDetails) == if (showdown) 4 else 2);
217
233
  }
218
234
  };
219
235
 
@@ -414,7 +430,7 @@ pub fn Stats(comptime T: type) type {
414
430
  pub fn calc(comptime stat: []const u8, base: T, dv: u4, exp: u16, level: u8) T {
415
431
  assert(level > 0 and level <= 100);
416
432
  const float: f32 = @floatFromInt(exp);
417
- const evs = @min(255, @as(u16, @intFromFloat(@ceil(@sqrt(float)))));
433
+ const evs: u16 = @min(255, @as(u16, @intFromFloat(@ceil(@sqrt(float)))));
418
434
  const core: u32 = (2 *% (@as(u32, base) +% dv)) +% (evs / 4);
419
435
  const factor: u32 = if (std.mem.eql(u8, stat, "hp")) level + 10 else 5;
420
436
  return @intCast(core *% @as(u32, level) / 100 +% factor);