Zelda Item code hacking

Started by kenobi, October 03, 2008, 07:16:11 PM

Previous topic - Next topic

kenobi

Panda on Smack asked me to make some explanations on how I made the item code for Zelda, so it can be useful for other hackers.
So I decided to make it.
Just be aware that this might not help you to hack an item selection code for another game. Each game is different.
However, it might help you understand the use of some codes types (like goto, if timer, or gr codes), and what you can get by putting all these codes together.
Also I'm sorry if everything is not very clear. It's not for real beginners. You should already know how to use wiird/gui, how to make searches....

Here we go :

Before I start, I of course used the items addresses found by James0x57 (0x8047A8C4).
I also found a place where the pad data was stored (0x80433AF6)

First thing I did was trying to find where the 'highlighted' item in the inventory was stored.
So I point to an item, start an unknown search, point another item, make a different search, and so on.
I find an address in MEM1. It doesn't store the actual item number, but it's "position" on the inventory.
The topmost item is #1, then the one right to it is #2, and so on. It's an 8bits value.

I load another save, and I check if the address is the same. It is not. So I search for it again, get the new address. I make another full ram dump of mem1, and I use the pointer tab of wiirdgui to find the
pointer address.

Wiirdgui finds some. I choosed to use [0x8048085C]+0x6A0.
So [0x8048085C]+0x6A0 is where the item number on the inventory screen is stored.

I made some tests and found out it is not the item number in the internal item list (at 0x8047A8C4).
There must be some table somewhere that allows the game to translate between item selected on screen to item in inventory.

To find it out, I put a bpr on [0x8048085C]+0x6A0.
After some analyzing of the asm, I find there is a table near from the item number on the inventory screen, at [0x8048085C]+0x688.


Now I have all the informations I need to make the code.
And I need to make it work like this :
- Get the on-screen item number at [[0x8048085C]+0x6A0] (=J).
- Load the data at [[0x8048085C]+0x688+J] (=K), to translate the on screen item to internal inventory.
- Load the data at [0x8047A8C4+K] (=L), to get the actual item value.
- Then I check if 1 or 2 is pressed, if so I add 1 or -1 to L, and then I store back the value.


I made that code, and then I realized it was working all the time (even when not on the item screen).
So I had to find a value that was only avaible when on the item screen. I found it at 0x80480674.

32480674 00000000 // if on item screen
48000000 8048085C // pointer = [0x8048085C]
DE000000 80008180 // check if pointer is valid
92010000 000006A0 // gr0 = 8bits at [[0x8048085C]+0x6A0] (=J)
5A011000 00000688 // Pointer = [0x8048085C]+0x688+gr0
92010000 00000000 // gr0 = 8bits at [[0x8048085C]+0x688+gr0] (=K)
4A001000 8047A8C4 // Pointer = 0x8047A8C4 + gr0
92010000 00000000 // gr0 = 8bits at [0x8047A8C4+gr0] (=L) (=item value)
2A433AF6 FCFF0000 // if 1 or 2 is pressed
A8000000 FFF80000 // use if... timer (= code execution delay, so you can "humanly" choose the item you want)
28433AF6 FCFF0200 // if 1 is pressed
86000000 00000001 // item# = item#+1
28433AF7 FCFF0100 // endif, if 2 is pressed
86000000 FFFFFFFF // item# = item#-1
E2000002 00000000 // 2 endifs
94010000 00000000 // write back the item value (8bits)
E0000000 80008000 // endif all, reset ba/po



Now about the other code. I found that the items with no names were annoying, so I wanted to add a way to automatically skip them.
The "easiest" way to do it would be to check the item name. If it's a no name item, continue to increase/decrease the item value until an item with a name is found.

So I start by searching the name of the item. After some searches, and the use of the pointer in pointer search, I found it was stored at [[0x804806F4]+0xB4]+0x242.
And an item with no name has actually "00000000" instead of its name.

So took the "old" code, added some stuff, and made this code :

32480674 00000000 // if on item screen
48000000 8048085C // pointer = [0x8048085C]
DE000000 80008180 // check if pointer is valid
92010000 000006A0 // gr0 = 8bits at [[0x8048085C]+0x6A0] (=J)
5A011000 00000688 // Pointer = [0x8048085C]+0x688+gr0
92010000 00000000 // gr0 = 8bits at [[0x8048085C]+0x688+gr0] (=K)
4A001000 8047A8C4 // Pointer = 0x8047A8C4 + gr0
92010000 00000000 // gr0 = 8bits at [0x8047A8C4+gr0] (=L) (=item value)
90010002 00000000 // gr2 = pointer (I save the pointer, so I'm able to load it back later on)

48000000 804806F4 // pointer = [804806F4]
DE000000 80008180 // check if pointer is valid
58010000 000000B4 // pointer = [[0x804806F4]+0xB4]
DE000000 80008180 // check if pointer is valid
38000242 00FF0000 // check if first letter of the item name (at [[0x804806F4]+0xB4]+242) is 00.
A8000000 FFFE0001 // use if... timer (= code execution delay, so the codes are executed one time out of two (to make sure the item name is updated correctly by the game between 2 code execution)).
66000008 00000000 // (if first letter of the item name is 0) jump over the next 8 lines of codes (jumps to 88000000 00000001) (= autoskip of the noname item)
E2000004 80000000 // executes 4 endifs

2A433AF6 FCFF0000 // if 1 or 2 is pressed

A8000000 FFF80000 // use if... timer (= code execution delay, so you can "humanly" choose the item you want)
28433AF6 FCFF0200 // if 1 is pressed
80000001 00000001 // gr1 = 1
28433AF7 FCFF0100 // endif, if 2 is pressed
80000001 FFFFFFFF // gr1 = -1
E2000001 00000000 // one endif

88000000 00000001 // gr0 = gr0+gr1
4A001002 00000000 // pointer = gr2
94010000 00000000 // write back the item value (8bits)
E0000000 80008000 // endif all, reset ba/po

Romaap

thx, it looks interesting, but I still don't understand :(
can you make a tut about the basics of ASM? :)

Panda On Smack

Thanks Ken

Was just about to ask you if I can post it for everyone else :)