Jump to content

Recommended Posts

Posted

Hello everyone!

I've been working on restoring Gen 6 ability behavior in USUM (Gale Wings always +1 priority, Prankster status moves not Dark-immune, Parental Bond 50% second hit, Soul Dew flat 50%). At first I thought that the Gen 7 battle mechanics were in code.bin - I believe they're actually in a separately-loaded CRO module called Battle.cro inside the RomFS, and it still has C++ Itanium-ABI mangled symbols, which makes static analysis way easier than most 3DS engine work. (I think Kaphotics might have mentioned that this type of stuff lives in CRO somewhere in the past but I don't remember where that got posted.)

What I've mapped so far:

- Battle.cro is 1.29 MB, has 892 named imports (with full mangled names), 177 anonymous imports, and the standard CRO0 structure.
- I had to fix a SegmentOffset bit-layout error in the existing CRO docs (segment is the low 4 bits, not the high 4) to get the import patch addresses right. Once corrected, every named import resolves cleanly to a 4-byte PLT stub address.
- Wrote a Ghidra Java script that parses the CRO header directly from the file and labels every named-import PLT stub in the loaded program, so the listing shows `bl imp__ZN3pml8pokepara9CoreParam12GetTokuseiNoEv` instead of `bl FUN_05001130`.
- Confirmed that GetAbilityID is only called 6 times across all of Battle.cro — all at battler init. The per-move ability checks read a cached value from a battler struct field, not by calling the import each time. Same for GetMaxHp (4 callers), GetMoveCategory (14), GetMoveType (16). The engine caches everything.

What's still open:

The Prankster-Dark immunity check isn't where the obvious pattern-matching suggests. The three `cmp r?, #0x9e` sites in Battle.cro turn out to be inside the in-battle text formatter — they're checking format-tag indices, not ability IDs. (I patched one of them and the result was corrupted battle messages, which is how I found out.)

I set hardware breakpoints at four suspected Prankster-related function entries in Battle.cro and ran Spore on a Tyranitar in Azahar with the GDB stub attached - none of them fired. The PC during move execution was in an address range that's past code.bin's normal end and not in Battle.cro either, suggesting another CRO module is loaded there. USUM has 10+ CRO files in romfs and the Prankster check probably lives in one of them.

If anyone:
- has a working USUM debug setup (real 3DS + Luma + NTR debugger, or a Citra build with reliable GDB)
- has mapped the active battler struct layout from prior Sun/Moon work
- recognizes the `bl 0x7f250` ability-handler registration pattern from Game Freak's CRO conventions
- has done parallel work on this and wants to compare notes

Let me know! I have full technical notes, the Ghidra script, Python RSP-protocol scripts for driving Azahar's GDB stub, and disassembly notes.

If you're interested in learning more here's a thread I made on hackmons.com that details more information.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...