@pkmn/engine 0.1.0-dev.dc33f678 → 0.1.0-dev.deda8593
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.
- package/LICENSE +1 -3
- package/README.md +44 -19
- package/build/pkg/addon.js +6 -7
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data.d.ts +4 -4
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +2 -1
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.js +5 -5
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js +2 -2
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js +5 -4
- package/build/tools/debug.js.map +1 -1
- package/build.zig +100 -102
- package/package.json +33 -22
- package/src/bin/install-pkmn-engine +26 -18
- package/src/lib/common/data.zig +8 -8
- package/src/lib/common/debug.zig +2 -2
- package/src/lib/common/optional.zig +1 -1
- package/src/lib/common/options.zig +2 -0
- package/src/lib/common/protocol.zig +397 -384
- package/src/lib/common/rational.zig +11 -8
- package/src/lib/common/rng.zig +20 -11
- package/src/lib/gen1/calc.zig +217 -47
- package/src/lib/gen1/chance.zig +91 -92
- package/src/lib/gen1/data/moves.zig +10 -10
- package/src/lib/gen1/data/species.zig +3 -3
- package/src/lib/gen1/data/types.zig +5 -5
- package/src/lib/gen1/data.zig +35 -35
- package/src/lib/gen1/helpers.zig +136 -55
- package/src/lib/gen1/mechanics.zig +333 -312
- package/src/lib/gen2/calc.zig +143 -0
- package/src/lib/gen2/chance.zig +1315 -0
- package/src/lib/gen2/data/items.zig +3 -3
- package/src/lib/gen2/data/moves.zig +5 -5
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +10 -10
- package/src/lib/gen2/data.zig +27 -37
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +37 -7
- package/src/lib/gen2/mechanics.zig +1621 -456
- package/src/lib/{binding/node.zig → node.zig} +9 -12
- package/src/lib/pkmn.zig +27 -12
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
- package/src/test/display/pkmn.html.tmpl +5 -5
- package/src/lib/gen1/README.md +0 -894
- package/src/lib/gen2/README.md +0 -330
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//! Code generated by `tools/generate` - manual edits will be overwritten
|
|
1
|
+
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
3
|
const std = @import("std");
|
|
4
4
|
|
|
@@ -216,14 +216,14 @@ pub const Item = enum(u8) {
|
|
|
216
216
|
pub const size = 196;
|
|
217
217
|
|
|
218
218
|
/// Returns a `Type` boosted by this item or `null` if the item is not a type-boosting item.
|
|
219
|
-
pub
|
|
219
|
+
pub fn boost(item: Item) ?Type {
|
|
220
220
|
assert(item != .None);
|
|
221
221
|
if (item == .PolkadotBow) return .Normal;
|
|
222
222
|
return if (@intFromEnum(item) <= 18) @enumFromInt(@intFromEnum(item) - 1) else null;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
/// Whether or not this item is Mail.
|
|
226
|
-
pub
|
|
226
|
+
pub fn isMail(item: Item) bool {
|
|
227
227
|
assert(item != .None);
|
|
228
228
|
return @intFromEnum(item) > 60 and @intFromEnum(item) <= 70;
|
|
229
229
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//! Code generated by `tools/generate` - manual edits will be overwritten
|
|
1
|
+
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
3
|
const std = @import("std");
|
|
4
4
|
|
|
@@ -938,7 +938,7 @@ pub const Move = enum(u8) {
|
|
|
938
938
|
},
|
|
939
939
|
// SolarBeam
|
|
940
940
|
.{
|
|
941
|
-
.effect = .
|
|
941
|
+
.effect = .SolarBeam,
|
|
942
942
|
.bp = 120,
|
|
943
943
|
.type = .Grass,
|
|
944
944
|
.accuracy = percent(100),
|
|
@@ -2529,7 +2529,7 @@ pub const Move = enum(u8) {
|
|
|
2529
2529
|
Sleep,
|
|
2530
2530
|
SleepTalk,
|
|
2531
2531
|
Snore,
|
|
2532
|
-
|
|
2532
|
+
SolarBeam,
|
|
2533
2533
|
SpAtkUp1,
|
|
2534
2534
|
SpDefDownChance,
|
|
2535
2535
|
SpDefUp2,
|
|
@@ -2562,7 +2562,7 @@ pub const Move = enum(u8) {
|
|
|
2562
2562
|
}
|
|
2563
2563
|
|
|
2564
2564
|
/// Whether this effect has a high critical rate.
|
|
2565
|
-
pub
|
|
2565
|
+
pub fn isHighCritical(effect: Effect) bool {
|
|
2566
2566
|
return effect == .HighCritical or effect == .RazorWind;
|
|
2567
2567
|
}
|
|
2568
2568
|
};
|
|
@@ -2865,7 +2865,7 @@ pub const Move = enum(u8) {
|
|
|
2865
2865
|
};
|
|
2866
2866
|
|
|
2867
2867
|
/// Returns the `Data` corresponding to the move.
|
|
2868
|
-
pub
|
|
2868
|
+
pub fn get(id: Move) Data {
|
|
2869
2869
|
assert(id != .None);
|
|
2870
2870
|
return DATA[@intFromEnum(id) - 1];
|
|
2871
2871
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//! Code generated by `tools/generate` - manual edits will be overwritten
|
|
1
|
+
//! Code generated by `tools/generate` - manual edits will be overwritten.
|
|
2
2
|
|
|
3
3
|
const std = @import("std");
|
|
4
4
|
|
|
@@ -164,27 +164,27 @@ pub const Type = enum(u8) {
|
|
|
164
164
|
pub const size = 18;
|
|
165
165
|
|
|
166
166
|
/// Whether or not this type is considered to be special as opposed to physical.
|
|
167
|
-
pub
|
|
167
|
+
pub fn special(self: Type) bool {
|
|
168
168
|
return @intFromEnum(self) >= @intFromEnum(Type.Fire);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
/// The `Effectiveness` of type `t2` vs. type `t1`.
|
|
172
|
-
pub
|
|
172
|
+
pub fn effectiveness(t1: Type, t2: Type) Effectiveness {
|
|
173
173
|
return CHART[@intFromEnum(t1)][@intFromEnum(t2)];
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
/// The precedence order of Type `type`.
|
|
177
|
-
pub
|
|
177
|
+
pub fn precedence(self: Type) u8 {
|
|
178
178
|
return PRECEDENCE[@intFromEnum(self)];
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
/// The internal index of this Type used by Present.
|
|
182
|
-
pub
|
|
182
|
+
pub fn present(self: Type) u8 {
|
|
183
183
|
return INDEXES[@intFromEnum(self)];
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
/// The Type corresponding to a random roll of `num` for Conversion 2.
|
|
187
|
-
pub
|
|
187
|
+
pub fn conversion2(num: u8) Type {
|
|
188
188
|
assert(num != 6);
|
|
189
189
|
assert(num < 10 or num >= 20);
|
|
190
190
|
assert(num <= 27);
|
|
@@ -192,7 +192,7 @@ pub const Type = enum(u8) {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
/// The Type corresponding to a Hidden Power `index`.
|
|
195
|
-
pub
|
|
195
|
+
pub fn hiddenPower(index: u8) Type {
|
|
196
196
|
return HIDDEN_POWER[index];
|
|
197
197
|
}
|
|
198
198
|
};
|
|
@@ -209,17 +209,17 @@ pub const Types = extern struct {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
/// Whether this typing is immune to type `t`.
|
|
212
|
-
pub
|
|
212
|
+
pub fn immune(self: Types, t: Type) bool {
|
|
213
213
|
return t.effectiveness(self.type1) == I or t.effectiveness(self.type2) == I;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
/// Whether this typing includes type `t`.
|
|
217
|
-
pub
|
|
217
|
+
pub fn includes(self: Types, t: Type) bool {
|
|
218
218
|
return self.type1 == t or self.type2 == t;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
/// Whether this typing is immune to damage from Sandstorm.
|
|
222
|
-
pub
|
|
222
|
+
pub fn sandstormImmune(self: Types) bool {
|
|
223
223
|
return @intFromEnum(self.type1) <= @intFromEnum(Type.Steel) or
|
|
224
224
|
@intFromEnum(self.type2) <= @intFromEnum(Type.Steel);
|
|
225
225
|
}
|
package/src/lib/gen2/data.zig
CHANGED
|
@@ -62,17 +62,17 @@ pub fn Battle(comptime RNG: anytype) type {
|
|
|
62
62
|
|
|
63
63
|
_: [padding]u8 = .{0} ** padding,
|
|
64
64
|
|
|
65
|
-
pub
|
|
65
|
+
pub fn side(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
66
66
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
67
67
|
return &self.sides[@intFromEnum(player)];
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
pub
|
|
70
|
+
pub fn foe(self: anytype, player: Player) PointerType(@TypeOf(self), Side) {
|
|
71
71
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Self);
|
|
72
72
|
return &self.sides[@intFromEnum(player.foe())];
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
pub
|
|
75
|
+
pub fn active(self: *const Self, player: Player) ID {
|
|
76
76
|
return player.ident(@intCast(self.side(player).pokemon[0].position));
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -133,7 +133,7 @@ pub const Side = extern struct {
|
|
|
133
133
|
assert(@sizeOf(Side) == 248);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
pub
|
|
136
|
+
pub fn get(self: anytype, slot: u8) PointerType(@TypeOf(self), Pokemon) {
|
|
137
137
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
138
138
|
assert(slot > 0 and slot <= 6);
|
|
139
139
|
const id = self.pokemon[slot - 1].position;
|
|
@@ -141,19 +141,19 @@ pub const Side = extern struct {
|
|
|
141
141
|
return &self.pokemon[id - 1];
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
pub
|
|
144
|
+
pub fn stored(self: anytype) PointerType(@TypeOf(self), Pokemon) {
|
|
145
145
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Side);
|
|
146
146
|
return self.get(1);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
pub
|
|
149
|
+
pub fn lastMove(self: anytype, encore: bool) Move {
|
|
150
150
|
assert(self.last_used_move != .None or !self.active.volatiles.dirty);
|
|
151
151
|
if (encore) return self.last_used_move;
|
|
152
152
|
return if (self.active.volatiles.dirty) .None else self.last_used_move;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// TODO
|
|
156
|
-
// pub
|
|
156
|
+
// pub fn useMove(self: anytype) void {
|
|
157
157
|
// assert(side.last_selected_move != .None);
|
|
158
158
|
// self.last_used_move = side.last_selected_move;
|
|
159
159
|
// self.active.volatiles.dirty = false;
|
|
@@ -175,7 +175,7 @@ pub const ActivePokemon = extern struct {
|
|
|
175
175
|
assert(@sizeOf(ActivePokemon) == 44);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
pub
|
|
178
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
179
179
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
180
180
|
assert(mslot > 0 and mslot <= 4);
|
|
181
181
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -200,7 +200,7 @@ pub const Pokemon = extern struct {
|
|
|
200
200
|
assert(@sizeOf(Pokemon) == 32);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
pub
|
|
203
|
+
pub fn move(self: anytype, mslot: u8) PointerType(@TypeOf(self), MoveSlot) {
|
|
204
204
|
assert(@typeInfo(@TypeOf(self)).Pointer.child == Pokemon);
|
|
205
205
|
assert(mslot > 0 and mslot <= 4);
|
|
206
206
|
assert(self.moves[mslot - 1].id != .None);
|
|
@@ -225,7 +225,7 @@ pub const DVs = packed struct(u16) {
|
|
|
225
225
|
return .{ .gender = g, .pow = p, .type = t };
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
pub
|
|
228
|
+
pub fn power(dvs: DVs) u8 {
|
|
229
229
|
return @as(u8, dvs.pow) + 30;
|
|
230
230
|
}
|
|
231
231
|
|
|
@@ -239,7 +239,7 @@ pub const DVs = packed struct(u16) {
|
|
|
239
239
|
};
|
|
240
240
|
const p: u6 = @intCast(1 + ((5 * @as(u8, (dvs.atk & 0b1000) | ((dvs.def & 0b1000)) >> 1 |
|
|
241
241
|
((dvs.spe & 0b1000)) >> 2 | ((dvs.spc & 0b1000)) >> 3) + (dvs.spc & 0b0011)) >> 1));
|
|
242
|
-
|
|
242
|
+
const t = @as(u8, dvs.def & 0b0011) + (@as(u8, dvs.atk & 0b0011) << 2);
|
|
243
243
|
return .{ .gender = g, .pow = p, .type = Type.hiddenPower(t) };
|
|
244
244
|
}
|
|
245
245
|
};
|
|
@@ -248,12 +248,12 @@ test DVs {
|
|
|
248
248
|
var dvs = DVs.from(.Mewtwo, .{ .def = 13 });
|
|
249
249
|
try expectEqual(Gender.Unknown, dvs.gender);
|
|
250
250
|
try expectEqual(Type.Ice, dvs.type);
|
|
251
|
-
try expectEqual(
|
|
251
|
+
try expectEqual(70, dvs.power());
|
|
252
252
|
|
|
253
253
|
dvs = DVs.from(.Pikachu, .{ .spc = 14 });
|
|
254
254
|
try expectEqual(Gender.Male, dvs.gender);
|
|
255
255
|
try expectEqual(Type.Dark, dvs.type);
|
|
256
|
-
try expectEqual(
|
|
256
|
+
try expectEqual(69, dvs.power());
|
|
257
257
|
|
|
258
258
|
dvs = DVs.from(.Cyndaquil, .{ .atk = 1, .def = 3, .spe = 10, .spc = 9 });
|
|
259
259
|
try expectEqual(Gender.Female, dvs.gender);
|
|
@@ -280,22 +280,7 @@ pub const MoveSlot = extern struct {
|
|
|
280
280
|
pub const Status = gen1.Status;
|
|
281
281
|
|
|
282
282
|
/// TODO
|
|
283
|
-
pub const TriAttack = enum(u2) {
|
|
284
|
-
PAR,
|
|
285
|
-
FRZ,
|
|
286
|
-
BRN,
|
|
287
|
-
|
|
288
|
-
/// TODO
|
|
289
|
-
pub inline fn status(self: TriAttack) u8 {
|
|
290
|
-
return Status.init(@enumFromInt(6 - @as(u8, @intFromEnum(self))));
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
test TriAttack {
|
|
295
|
-
try expectEqual(Status.init(.PAR), TriAttack.PAR.status());
|
|
296
|
-
try expectEqual(Status.init(.FRZ), TriAttack.FRZ.status());
|
|
297
|
-
try expectEqual(Status.init(.BRN), TriAttack.BRN.status());
|
|
298
|
-
}
|
|
283
|
+
pub const TriAttack = enum(u2) { PAR, FRZ, BRN };
|
|
299
284
|
|
|
300
285
|
pub const Volatiles = packed struct(u128) {
|
|
301
286
|
Bide: bool = false,
|
|
@@ -329,14 +314,19 @@ pub const Volatiles = packed struct(u128) {
|
|
|
329
314
|
Encore: bool = false,
|
|
330
315
|
LockOn: bool = false,
|
|
331
316
|
DestinyBond: bool = false,
|
|
317
|
+
Trapped: bool = false,
|
|
332
318
|
|
|
333
|
-
trapped: bool = false,
|
|
334
319
|
switched: bool = false,
|
|
320
|
+
// TODO: replace with simply looking at Choice on Battle
|
|
335
321
|
switching: bool = false,
|
|
322
|
+
// TODO: simply store both last moves on side
|
|
336
323
|
dirty: bool = false,
|
|
337
324
|
|
|
338
325
|
frozen: bool = false,
|
|
339
|
-
|
|
326
|
+
minimized: bool = false,
|
|
327
|
+
_: u10 = 0,
|
|
328
|
+
// TODO: is this needed for unmodified stats?
|
|
329
|
+
transform: u4 = 0,
|
|
340
330
|
|
|
341
331
|
bide: u16 = 0,
|
|
342
332
|
bind: Bind = .{},
|
|
@@ -390,9 +380,9 @@ test Stats {
|
|
|
390
380
|
try expectEqual(0, stats.def);
|
|
391
381
|
|
|
392
382
|
var base = Species.get(.Gyarados).stats;
|
|
393
|
-
try expectEqual(
|
|
383
|
+
try expectEqual(127, Stats(u16).calc("hp", base.hp, 0, 5120, 38));
|
|
394
384
|
base = Species.get(.Pidgeot).stats;
|
|
395
|
-
try expectEqual(
|
|
385
|
+
try expectEqual(279, Stats(u16).calc("spe", base.spe, 15, 63001, 100));
|
|
396
386
|
}
|
|
397
387
|
|
|
398
388
|
pub const Boosts = packed struct(u32) {
|
|
@@ -438,8 +428,8 @@ test Move {
|
|
|
438
428
|
try expectEqual(Move.Effect.ConfusionChance, move.effect);
|
|
439
429
|
try expectEqual(rng.Gen12.percent(50), move.accuracy);
|
|
440
430
|
try expectEqual(rng.Gen12.percent(100), move.chance);
|
|
441
|
-
try expectEqual(
|
|
442
|
-
try expectEqual(
|
|
431
|
+
try expectEqual(5, Move.pp(.DynamicPunch));
|
|
432
|
+
try expectEqual(-1, Move.get(.Counter).priority);
|
|
443
433
|
try expect(!move.effect.isHighCritical());
|
|
444
434
|
try expect(Move.get(.KarateChop).effect.isHighCritical());
|
|
445
435
|
try expect(Move.get(.RazorWind).effect.isHighCritical());
|
|
@@ -449,7 +439,7 @@ pub const Species = species.Species;
|
|
|
449
439
|
|
|
450
440
|
test Species {
|
|
451
441
|
try expectEqual(152, @intFromEnum(Species.Chikorita));
|
|
452
|
-
try expectEqual(
|
|
442
|
+
try expectEqual(100, Species.get(.Celebi).stats.spd);
|
|
453
443
|
}
|
|
454
444
|
|
|
455
445
|
pub const Type = types.Type;
|
|
@@ -462,7 +452,7 @@ test Types {
|
|
|
462
452
|
try expect(!Type.Steel.special());
|
|
463
453
|
try expect(Type.Dark.special());
|
|
464
454
|
|
|
465
|
-
try expectEqual(
|
|
455
|
+
try expectEqual(3, Type.Water.precedence());
|
|
466
456
|
try expect(Type.Bug.precedence() > Type.Poison.precedence());
|
|
467
457
|
|
|
468
458
|
try expectEqual(Effectiveness.Super, Type.effectiveness(.Ghost, .Psychic));
|