@pkmn/engine 0.1.0-dev.f3aaee39 → 0.1.0-dev.fc150752
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/package.json +11 -11
- package/src/lib/common/data.zig +3 -15
- package/src/lib/common/protocol.zig +79 -25
- package/src/lib/common/rng.zig +1 -1
- package/src/lib/gen1/README.md +3 -1
- package/src/lib/gen1/calc.zig +0 -1
- package/src/lib/gen1/chance.zig +2 -10
- package/src/lib/gen1/data/moves.zig +168 -170
- package/src/lib/gen1/data.zig +6 -18
- package/src/lib/gen1/mechanics.zig +19 -23
- package/src/lib/gen2/README.md +75 -0
- package/src/lib/gen2/data/moves.zig +634 -562
- package/src/lib/gen2/data.zig +67 -48
- package/src/lib/gen2/helpers.zig +8 -12
- package/src/lib/gen2/mechanics.zig +911 -7
package/src/lib/gen1/data.zig
CHANGED
|
@@ -214,7 +214,7 @@ pub const Pokemon = extern struct {
|
|
|
214
214
|
}
|
|
215
215
|
};
|
|
216
216
|
|
|
217
|
-
/// Representation of a Generation I
|
|
217
|
+
/// Representation of a Generation I Pokémon's move slot in a battle.
|
|
218
218
|
pub const MoveSlot = extern struct {
|
|
219
219
|
/// The identifier for the move.
|
|
220
220
|
id: Move = .None,
|
|
@@ -222,20 +222,16 @@ pub const MoveSlot = extern struct {
|
|
|
222
222
|
pp: u8 = 0,
|
|
223
223
|
|
|
224
224
|
comptime {
|
|
225
|
-
assert(@sizeOf(MoveSlot) ==
|
|
225
|
+
assert(@sizeOf(MoveSlot) == 2);
|
|
226
226
|
}
|
|
227
227
|
};
|
|
228
228
|
|
|
229
229
|
/// Details required to detect desyncs based on the move last selected/executed by players.
|
|
230
|
-
pub const MoveDetails = packed struct {
|
|
230
|
+
pub const MoveDetails = packed struct(if (showdown) u16 else u8) {
|
|
231
231
|
/// The move slot index of the last move selected in the battle menu.
|
|
232
232
|
index: if (showdown) u8 else u4 = 0,
|
|
233
233
|
/// Whether the last move executed was counterable.
|
|
234
234
|
counterable: if (showdown) u8 else u4 = 0,
|
|
235
|
-
|
|
236
|
-
comptime {
|
|
237
|
-
assert(@sizeOf(MoveDetails) == if (showdown) 2 else 1);
|
|
238
|
-
}
|
|
239
235
|
};
|
|
240
236
|
|
|
241
237
|
/// Bitfield representation of a Generation I & II Pokémon's major status condition.
|
|
@@ -329,7 +325,7 @@ test Status {
|
|
|
329
325
|
}
|
|
330
326
|
|
|
331
327
|
/// Bitfield representation of volatile statuses and associated data in Generation I.
|
|
332
|
-
pub const Volatiles = packed struct {
|
|
328
|
+
pub const Volatiles = packed struct(u64) {
|
|
333
329
|
/// Whether the "Bide" volatile status is present.
|
|
334
330
|
Bide: bool = false,
|
|
335
331
|
/// Whether the "Thrashing" volatile status is present.
|
|
@@ -387,10 +383,6 @@ pub const Volatiles = packed struct {
|
|
|
387
383
|
disabled_move: u3 = 0,
|
|
388
384
|
/// The number of turns toxic damage has been accumulating.
|
|
389
385
|
toxic: u5 = 0,
|
|
390
|
-
|
|
391
|
-
comptime {
|
|
392
|
-
assert(@sizeOf(Volatiles) == 8);
|
|
393
|
-
}
|
|
394
386
|
};
|
|
395
387
|
|
|
396
388
|
test Volatiles {
|
|
@@ -456,7 +448,7 @@ test Stats {
|
|
|
456
448
|
}
|
|
457
449
|
|
|
458
450
|
/// Representation of a Pokémon's boosts in Generation I.
|
|
459
|
-
pub const Boosts = packed struct {
|
|
451
|
+
pub const Boosts = packed struct(u32) {
|
|
460
452
|
/// A Pokémon's Attack boosts.
|
|
461
453
|
atk: i4 = 0,
|
|
462
454
|
/// A Pokémon's Defense boosts.
|
|
@@ -471,10 +463,6 @@ pub const Boosts = packed struct {
|
|
|
471
463
|
evasion: i4 = 0,
|
|
472
464
|
|
|
473
465
|
_: u8 = 0,
|
|
474
|
-
|
|
475
|
-
comptime {
|
|
476
|
-
assert(@sizeOf(Boosts) == 4);
|
|
477
|
-
}
|
|
478
466
|
};
|
|
479
467
|
|
|
480
468
|
test Boosts {
|
|
@@ -490,7 +478,7 @@ test Move {
|
|
|
490
478
|
try expectEqual(2, @intFromEnum(Move.KarateChop));
|
|
491
479
|
const move = Move.get(.Fissure);
|
|
492
480
|
try expectEqual(Move.Effect.OHKO, move.effect);
|
|
493
|
-
try expectEqual(
|
|
481
|
+
try expectEqual(rng.Gen12.percent(30), move.accuracy);
|
|
494
482
|
try expectEqual(Type.Ground, move.type);
|
|
495
483
|
|
|
496
484
|
try expect(!Move.Effect.onBegin(.None));
|
|
@@ -62,10 +62,6 @@ const MAX_STAT_VALUE = 999;
|
|
|
62
62
|
const DISTRIBUTION = [_]u3{ 2, 2, 2, 3, 3, 3, 4, 5 };
|
|
63
63
|
|
|
64
64
|
pub fn update(battle: anytype, c1: Choice, c2: Choice, options: anytype) !Result {
|
|
65
|
-
// FIXME
|
|
66
|
-
// std.debug.print("\n", .{});
|
|
67
|
-
// DEBUG(battle.turn);
|
|
68
|
-
// std.debug.print("// ", .{});
|
|
69
65
|
assert(c1.type != .Pass or c2.type != .Pass or battle.turn == 0);
|
|
70
66
|
if (battle.turn == 0) return start(battle, options);
|
|
71
67
|
|
|
@@ -214,12 +210,9 @@ fn selectMove(
|
|
|
214
210
|
}
|
|
215
211
|
break :ok true;
|
|
216
212
|
};
|
|
217
|
-
|
|
218
213
|
assert(struggle);
|
|
219
|
-
saveMove(battle, player, choice);
|
|
220
|
-
} else {
|
|
221
|
-
saveMove(battle, player, choice);
|
|
222
214
|
}
|
|
215
|
+
saveMove(battle, player, choice);
|
|
223
216
|
|
|
224
217
|
return null;
|
|
225
218
|
}
|
|
@@ -1438,7 +1431,7 @@ fn moveHit(
|
|
|
1438
1431
|
const overwritten = overwrite and state > 0;
|
|
1439
1432
|
assert(!overwritten or (0 < state and state <= 255 and !side.active.volatiles.Bide));
|
|
1440
1433
|
|
|
1441
|
-
var accuracy = if (overwritten) state else @as(u16,
|
|
1434
|
+
var accuracy = if (overwritten) state else @as(u16, move.accuracy);
|
|
1442
1435
|
var boost = BOOSTS[@as(u4, @intCast(@as(i8, side.active.boosts.accuracy) + 6))];
|
|
1443
1436
|
accuracy = accuracy * boost[0] / boost[1];
|
|
1444
1437
|
boost = BOOSTS[@as(u4, @intCast(@as(i8, -foe.active.boosts.evasion) + 6))];
|
|
@@ -1548,21 +1541,19 @@ fn handleResidual(battle: anytype, player: Player, options: anytype) !void {
|
|
|
1548
1541
|
var volatiles = &side.active.volatiles;
|
|
1549
1542
|
|
|
1550
1543
|
const brn = Status.is(stored.status, .BRN);
|
|
1551
|
-
if (brn or Status.is(stored.status, .PSN))
|
|
1544
|
+
if (brn or Status.is(stored.status, .PSN)) {
|
|
1552
1545
|
var damage = @max(stored.stats.hp / 16, 1);
|
|
1553
|
-
|
|
1554
1546
|
if (volatiles.Toxic) {
|
|
1555
1547
|
volatiles.toxic += 1;
|
|
1556
1548
|
damage *= volatiles.toxic;
|
|
1557
1549
|
}
|
|
1550
|
+
damage = @min(damage, stored.hp);
|
|
1558
1551
|
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
// Pokémon Showdown uses damageOf here but its not relevant in Generation I
|
|
1565
|
-
try options.log.damage(ident, stored, if (brn) Damage.Burn else Damage.Poison);
|
|
1552
|
+
if (!showdown or damage > 0) {
|
|
1553
|
+
stored.hp -= damage;
|
|
1554
|
+
// Pokémon Showdown uses damageOf here but its not relevant in Generation I
|
|
1555
|
+
try options.log.damage(ident, stored, if (brn) Damage.Burn else Damage.Poison);
|
|
1556
|
+
}
|
|
1566
1557
|
}
|
|
1567
1558
|
|
|
1568
1559
|
if (volatiles.LeechSeed) {
|
|
@@ -2395,12 +2386,17 @@ pub const Effects = struct {
|
|
|
2395
2386
|
}
|
|
2396
2387
|
|
|
2397
2388
|
fn switchAndTeleport(battle: anytype, player: Player, move: Move.Data, options: anytype) !void {
|
|
2398
|
-
if (!showdown or battle.side(player).last_selected_move == .Teleport) return;
|
|
2399
|
-
|
|
2400
2389
|
// Whirlwind/Roar should not roll to hit/reset damage but Pokémon Showdown does anyway
|
|
2401
|
-
if (
|
|
2402
|
-
|
|
2403
|
-
|
|
2390
|
+
if (showdown) {
|
|
2391
|
+
if (battle.side(player).last_selected_move == .Teleport) return;
|
|
2392
|
+
if (try checkHit(battle, player, move, options)) {
|
|
2393
|
+
try options.chance.commit(player, .hit);
|
|
2394
|
+
}
|
|
2395
|
+
battle.last_damage = 0;
|
|
2396
|
+
} else {
|
|
2397
|
+
try options.log.fail(battle.active(player), .None);
|
|
2398
|
+
try options.log.laststill();
|
|
2399
|
+
}
|
|
2404
2400
|
}
|
|
2405
2401
|
|
|
2406
2402
|
fn thrashing(battle: anytype, player: Player, options: anytype) void {
|
package/src/lib/gen2/README.md
CHANGED
|
@@ -219,6 +219,81 @@ much overhead the preceding representations have after taking into consideration
|
|
|
219
219
|
padding](https://en.wikipedia.org/wiki/Data_structure_alignment) and
|
|
220
220
|
[denormalization](https://en.wikipedia.org/wiki/Denormalization):
|
|
221
221
|
|
|
222
|
+
## Details
|
|
223
|
+
|
|
224
|
+
| pkmn | Pokémon Crystal (pret) |
|
|
225
|
+
| ------------------------- | ------------------------------------------------- |
|
|
226
|
+
| `start` | `DoBattle` |
|
|
227
|
+
| `update` | `BattleTurn` |
|
|
228
|
+
| `selectMove` / `saveMove` | `CheckPlayerLockedIn` / `ParsePlayerAction` |
|
|
229
|
+
| `switchIn` | `SwitchPlayerMon` / `SendOutPlayerMon` |
|
|
230
|
+
| `turnOrder` | `DetermineMoveOrder` |
|
|
231
|
+
| `doTurn` | `DoTurn` |
|
|
232
|
+
| `executeMove` | `DoMove` |
|
|
233
|
+
| `beforeMove` | `CheckTurn` |
|
|
234
|
+
| `canMove` | |
|
|
235
|
+
| `decrementPP` | |
|
|
236
|
+
| `doMove` | |
|
|
237
|
+
| `checkCriticalHit` | `BattleCommand_Critical` |
|
|
238
|
+
| `calcDamage` | `BattleCommand_DamageCalc` / `PlayerAttackDamage` |
|
|
239
|
+
| `adjustDamage` | `BattleCommand_Stab` |
|
|
240
|
+
| `randomizeDamage` | `BattleCommand_DamageVariation` |
|
|
241
|
+
| `specialDamage` | `BattleCommand_ConstantDamage` |
|
|
242
|
+
| `applyDamage` | `BattleCommand_ApplyDamage` |
|
|
243
|
+
| `checkHit` | `BattleCommand_CheckHit` |
|
|
244
|
+
| `checkFaint` | `CheckFaint` |
|
|
245
|
+
| `handleResidual` | `ResidualDamage` |
|
|
246
|
+
| `endTurn` | `EndTurn` |
|
|
247
|
+
|
|
248
|
+
DoBattle
|
|
249
|
+
BattleTurn
|
|
250
|
+
- HandleBerserkGene
|
|
251
|
+
- CheckPlayerLockedIn
|
|
252
|
+
- BattleMenu
|
|
253
|
+
- ParsePlayerAction
|
|
254
|
+
- DetermineMoveOrder
|
|
255
|
+
- CompareMovePriority
|
|
256
|
+
- GetMovePriority
|
|
257
|
+
- Battle_*
|
|
258
|
+
- Handle*Switch
|
|
259
|
+
- SwitchPlayerMon
|
|
260
|
+
- BreakAttraction
|
|
261
|
+
- SendOutPlayerMon
|
|
262
|
+
- SpikesDamage
|
|
263
|
+
- *Turn_EndOpponentProtectEndureDestinyBond
|
|
264
|
+
- EndUserDestinyBond
|
|
265
|
+
- Do*Turn
|
|
266
|
+
- EndOpponentProtectEndureDestinyBond
|
|
267
|
+
- ResidualDamage
|
|
268
|
+
- CheckFaint_*
|
|
269
|
+
- HandleBetweenTurnEffects
|
|
270
|
+
- HandleFutureSight
|
|
271
|
+
- HandleWeather
|
|
272
|
+
- HandleWrap
|
|
273
|
+
- HandlePerishSong
|
|
274
|
+
- HandleLeftovers
|
|
275
|
+
- HandleMysteryBerry
|
|
276
|
+
- HandleDefrost
|
|
277
|
+
- HandleSafeguard
|
|
278
|
+
- HandleScreens
|
|
279
|
+
- HandleStatBoostingHeldItems
|
|
280
|
+
- HandleHealingItems
|
|
281
|
+
- HandleEncore
|
|
282
|
+
|
|
283
|
+
DoTurn
|
|
284
|
+
DoMove = executeMove
|
|
285
|
+
CheckTurn = beforeMove
|
|
286
|
+
BattleCommand_Critical = checkCriticalHit
|
|
287
|
+
BattleCommand_Stab = adjustDamage
|
|
288
|
+
BattleCommand_DamageVariation = randomizeDamage
|
|
289
|
+
BattleCommand_CheckHit = checkHit
|
|
290
|
+
BattleCommand_ApplyDamage = applyDamage
|
|
291
|
+
BattleCommand_CheckFaint
|
|
292
|
+
BattleCommand_BuildOpponentRage = buildRage
|
|
293
|
+
BattleCommand_DamageCalc (PlayerAttackDamage / EnemyAttackDamage) = calcDamage
|
|
294
|
+
BattleCommand_ConstantDamage = specialDamage
|
|
295
|
+
DoEnemyDamage / DoPlayerDamage / DoSubstituteDamage
|
|
296
|
+
|
|
222
297
|
==**TODO**==
|
|
223
298
|
|
|
224
299
|
## Protocol
|