Port the Smart AI effect handlers (#28)
Translate every AI_Smart_EffectHandlers entry, so trainers with the Smart layer are no longer refused. The AI's type checks keep the CheckTypeMatchup bug: they read the move type and Foresight flag through hBattleTurn, and Conversion2's write to the player's move type persists. The reference emulator runs the unmodified AI_Smart routine over 6,024 states per browser, comparing scores, Random consumption, hBattleTurn and the player's move type. Validated with 579 unit tests, 151 browser tests, native/reference builds and reference/vendor/release checks. Kurt's balls, Park and Safari balls and special battle types remain on #28. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
32d736ecae
commit
77704fe848
11 files changed
+682
-71
No files matched your search
@@ -283,26 +283,23 @@ describe.skipIf(!existsSync(romPath))("trainer battles", () => {
|
||||
expect(result.texts).toContain("was defeated!");
|
||||
},
|
||||
);
|
||||
it("refuses untranslated Smart effects, including reserves, and empty parties before mutation", () => {
|
||||
for (const kind of ["empty", "ai", "reserve"] as const) {
|
||||
const { options } = setup();
|
||||
if (kind === "empty") options.trainer!.party = [];
|
||||
else {
|
||||
options.trainer!.aiFlags |= 1 << 4;
|
||||
const unsupported = structuredClone(options.trainer!.party[0]);
|
||||
unsupported.moves = [115, 0, 0, 0]; // Reflect has an untranslated Smart handler.
|
||||
if (kind === "reserve") options.trainer!.party.push(unsupported);
|
||||
else options.trainer!.party[0] = unsupported;
|
||||
}
|
||||
const before = structuredClone(options.party);
|
||||
const enemyBefore = structuredClone(options.trainer!.party);
|
||||
let draws = 0;
|
||||
options.random = () => { draws++; return 0; };
|
||||
expect(() => new Battle(options).run().next()).toThrow(UnsupportedBattle);
|
||||
expect(options.party).toEqual(before);
|
||||
expect(options.trainer!.party).toEqual(enemyBefore);
|
||||
expect(options.pokedex.seen.size).toBe(0);
|
||||
expect(draws).toBe(0);
|
||||
}
|
||||
it("refuses an empty trainer party before mutation", () => {
|
||||
const { options } = setup();
|
||||
options.trainer!.party = [];
|
||||
const before = structuredClone(options.party);
|
||||
let draws = 0;
|
||||
options.random = () => { draws++; return 0; };
|
||||
expect(() => new Battle(options).run().next()).toThrow(UnsupportedBattle);
|
||||
expect(options.party).toEqual(before);
|
||||
expect(options.pokedex.seen.size).toBe(0);
|
||||
expect(draws).toBe(0);
|
||||
});
|
||||
it("completes a battle against Smart AI with a handled status move", () => {
|
||||
const { options } = setup();
|
||||
options.trainer!.aiFlags |= 1 << 4;
|
||||
options.trainer!.party[0].moves = [115, 33, 0, 0]; // Reflect, Tackle
|
||||
const result = finish(new Battle(options));
|
||||
expect(result.result).toBe(0);
|
||||
expect(result.texts).toContain("was defeated!");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user