isleep2late Posted May 27 Posted May 27 (edited) Hello everyone! So full disclosure - I've spent many years trying to figure out how to crack the Gen 7 code, and with our current age of technology it was made possible. I was able to reverse engineer a lot of the USUM battle engine with heavy use of an AI assistant for some of the grunt work, including decompiling, scanning the save-state RAM, and cross-checking. I drove the project, supplied the save states, and verified every step in-game myself. What I've outlined here is reproducible, so you don't have to take my word for any of it. This post is for research purposes. So my goal was to Gen 6 Prankster behavior in Ultra Sun / Ultra Moon - status moves from a Prankster user can once again affect Dark-types (no more "It doesn't affect…"). Tested and working. --- The fix (if you just want it) In `Battle.cro` (from the RomFS), change one byte: Offset: 0x24B14 Before: D1 FF FF 0A After: D1 FF FF EA (Only the last byte changes: 0x24B17, 0A → EA.) That's it. This flips a conditional branch to an unconditional one so the engine stops failing Prankster-boosted status moves against Dark-types. It does not touch any other immunity (powder/Grass, trapping/Ghost, type-chart immunities all still work). Installing it — two options: LayeredFS (easy, no repacking): put the patched `Battle.cro` at `%APPDATA%\Azahar\load\mods\00040000001B5100\romfs\Battle.cro`, fully quit and relaunch Azahar. Repack the CIA: splice the patched `Battle.cro` back in and rebuild the RomFS IVFC hash tree + the NCCH romfs hash (signatures can stay broken; Azahar/Citra accept that). Big gotcha: test on a fresh battle after a clean boot, NOT by loading a save state. A save state is a snapshot of RAM that still contains the old unpatched code, so it'll always show the old behavior no matter how you patch the files. --- How it was found (short version) Gen 7 added: a Prankster-boosted status move that hits a Dark-type fails. I wanted that gone on the actual game, not just on a Showdown server. The hard part: the check isn't a simple `if (ability == Prankster)`. USUM's battle engine (`Battle.cro`) is a Showdown-style event-dispatch system, and its handler tables are filled in by the loader at runtime meaning they're blank in the file on disk. So static analysis in Ghidra just saw zeros where the logic should be. That blocked progress for a long time (and produced several "patches" that did nothing - including one that accidentally targeted the text formatter, because `158`/Prankster also shows up as a text token). What cracked it: a Citra/Azahar save state. A `.cst` is a zstd-compressed snapshot of console RAM - decompress it and you get ~302 MB with all the runtime relocations already applied. From a save state of Prankster Shuckle vs. Dark Tyranitar, I could: - read the real, populated dispatch tables for the first time; - find the actual battlers in memory and diff their type fields - that pinned the type cache at `battler+0x1E4/5/6`, with Dark = `0x10` (Tyranitar showed `05 10 12` = Rock/Dark/none; Shuckle showed `06 05 12` = Bug/Rock/none); - locate the engine's `hasType()` function and find the single place in the whole binary that calls `hasType(target, Dark)` — that's `FUN_05024868`, the per-target immunity filter. Its Dark branch is basically the Showdown rule: target is Dark AND move was Prankster-boosted AND it's an opponent → "It doesn't affect…" + the move fails on that target Patching the first branch of that check to always "keep" the target removes the immunity. Confirmed in a fresh battle: Thunder Wave / Will-O-Wisp / etc. from a Prankster user now land on Dark-types. --- ## Notes / credits - This is one piece of a broader "restore Gen 6 abilities" project (Gale Wings, Parental Bond, Soul Dew are next). - Prankster's +1 priority is separate (it lives in `code.bin`); this patch only removes the Dark immunity, leaving the priority boost intact — i.e. true Gen 6 Prankster. - Method that made it possible, in one line: when a binary's tables are loader-relocated, stop fighting the static image and read a save state instead. Happy to answer questions or share tooling. If you're interested in learning more here's a thread I made on hackmons.com that details more information. Edited yesterday at 01:13 PM by isleep2late I finally figured out how to do it but I didn't want to make a second post that would clog the forums.
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now