Banner
Views: 236,117,970
Time: 2013-05-21 03:00:25 AM
10 users online: Deoxys594, o Hadron, K1ngHacks, Kazeshin, Lui37, ManuMaster654, MarioFan22, Nesquik Bunny, Qwholl, shrine - Guests: 15 - Bots: 14Users: 22,855 (1,292 active)
Latest: Reaper
Tip: If you use custom music, make sure your ROM has been expanded to at least 1MB.
Routine Hacking/Creating Patches
Forum Index - SMW Hacking - General SMW Hacking Help - Tutorials - Routine Hacking/Creating Patches
Pages: « 1 »

Routine Hacking/Patch Creating Tutorial


Have you ever been interested in making your own health systems? Maybe you want to add a few more custom ASM hacks into your ROM, like custom status bars and counters, or maybe implement some powerups into your hack?

This is basically what Routine Hacking means - it's a way to create your own patches into SMW. I hope you find this tutorial useful.

What You Will Need


All.log
Notepad
Xkas
Snes Emulator
ASM Knowledge, of course.
Patience
Snes9x Debugger

(NOTE: This tutorial does NOT cover ASM, it just tells you how to create patches.)

Now, before actually starting to create a patch, you need to think about what you're trying to do.

- First of all, think about what you're trying to accomplish. What are you trying to do the game? Are you going to add a custom counter or what?

- Figure out where in the ROM you need want to replace a code with. Suppose if you want to create a custom death, then you obviously need to hook up the death routine, not the status bar routine and check if Mario's dead, that's just stupid, isn't it?

- Study the part of the routine you want to modify. If you're going to hack the hurt routine, then you obviously need to know what the orginal hurt routine does, and of course, how it works.

- You need to create a proper working code, and then debug it to see if there are any side effects. If there are, you're going to have to fix those which hopefully will not be much of an issue.

- If you want to create some heavy modifications or add something which looks hard, the more complex it'll be to create your patch. In other words, the more complex your code, the harder the patch will be to create.

Lesson 1: Creating An .ASM File


To start things off, you'll need to create an empty text document (.TXT file) in your hack's folder. Rename it to patch.asm where patch is the name of your patch. The name can be anything, just make sure it does NOT have any spaces in it. As you can also notice, the extension should be .ASM.

Open up your empty .ASM file. There are 2 main things you need to do before you start coding a patch:

- Identify the header
- Specify ROM format

A ROM should always have a header. To tell xkas that our ROM has a header, we write header at the beginning of the file. If you remove the header from your ROM, it's not necessary to write header.

The next thing is to specify the ROM format; SMW ROMs are usually in a LoROM format, so on the next line after header, write lorom. As opposed to HiROM, LoROM means that the rom is less than 4MB. HiROMs are greater than 4MB and LM cannot open them.

So your file should start like:

header
lorom


Pretty easy, wasn't it? Just 2 lines of code.

Lesson 2: Hex-Editing Through Patches


First, you might ask "What's the point of hex-editing through an xkas patch when you simply do it through a hex editor?" Well, I have a good point here. Imagine if you made a bunch of hex-edits in your rom, and somehow all of a sudden your rom crashed and doesn't work anymore. You've lost all of your hex-edits, and you're going to have to do them all over again. Annoying, isn't it? Worse it that you could forget a few hex-edits which you might have done. With an xkas patch, you can keep track of all of your hex edits and just patch to get all of them done at once. Pretty cool, right?

In a hex-editor, you "jump" to a PC Address (0x1F800 for example) in the ROM, change a value, and then save.

In a patch, we don't "jump" to a PC Address, but a SNES Address ($148000 for example) instead.

How exactly do you jump to an address in a patch though? Simple, you use a directive. org is a directive statement, which means it can let you jump to a SNES Address. The format is as follows:

org $xxxxxx

Where $xxxxxx is the address to jump to, in SNES Format of course. Don't try to put a PC Address there, otherwise you'll end up modifying some other code instead!

Anyway, here is an example of jumping to offset 0x2167 in a patch:

header
lorom
org $009F67 ; 0x2167 in PC is $009F67.


This is like jumping to offset 0x2167 in a hex editor. Now we want to change the value there. You can easily do this by putting a db on the next line, followed by a 2-digit hex value. For example, if we wanted to make $009F67 00, then we just do this:

header
lorom
org $009F67 ; 0x2167 in PC is $009F67.
db $00 ; <- Changes the value at $009F67 to 00.


Now what if you want to change the bytes following one address? I mean like this:

2C9BC $05:C7BC 3 bytes Misc. Change to A9 08 EA and the background will start scrolling fast with generator F4 without having to touch platform C1

For this address, you need to change 3 bytes - $05C7BC, $05C7BD and $05C7BE (the addresses are one after each other). Just like a table, you can set values for the next addresses:

header
lorom
org $05C7BC
db $A9,$08,$EA ; Change address 1, 2 and 3.


The second hex value corresponds to $05B7BC+1 ($05B7BD) and the second hex value corresponds to $05B7BC+2 ($05B7BE). In this way, you can change the bytes following an address.

Of course, you can make 2 separate hex edits in just one file. Try it out:

header
lorom
org $05C7BC
db $A9,$08,$EA

org $009F67
db $00


Additionally, instead of using hex values, you can write raw assembly code:

org $009F66
LDA #$20 ; Replace the instructions here with LDA #$20.


Pretty easy, no?

All.log


In case you don't know already, all.log is a disassembly of Super Mario World. It's a document with all of the raw ASM code in SMW. If you don't have it, download it from the link provided at the top of the thread.

So in what way is this useful? It's extremely helpful when you want to hack into a routine. If you want to create your custom death routine, all.log can help you locate where the death routine is. You can also use the ROM Map and the debugger, but we'll get to them later.

Open up all.log. You'll see stuff like:



It doesn't look nice, does it?

The CODE_XXXXXX tells you where in the ROM the code is. For example, you can tell from the picture that STZ $4200 is at $008001.

Then you'll see 2 digit hex numbers and the raw ASM code. The 2 digit hex numbers is basically the raw ASM code assembled into a hex-format, and it tells you how many bytes the line uses. For example:


CODE_00800A: 9C 40 21 STZ.W $2140 ; \ ; APU I/O Port

There are 3 2-digit hex numbers there, meaning that STZ $2140 takes up 3 bytes.

..then there are just some comments on the right. Not all of all.log is commented, though.

Lesson 3: Hacking A Routine


So now you know what all.log is. Are you ready to start your first routine hack?

As I said before, think about what you're trying to accomplish. For this patch, I will store the ON/OFF switch counter somewhere to the status bar. This means that if the switch is ON (01), it'll display 01 on the status bar, and if the switch is OFF (00), it'll display 0 on the status bar.

Now the first question is: when is my code going to be run?

I need this hack to run every frame in a level, so a routine that runs every frame in a level should be "hacked". The status bar is a good example of a routine that runs every frame in a level. There are other routines which can be hacked too, like the routine that checks if Mario presses start (check if he's pausing) - that's also run all the time in a level.

The ROM Map can also help you find a routine:

0117E $00:8F7E 6 bytes Misc. Writes coins to status bar. Changing to [EA EA EA EA EA EA] will disable the coins from being written to the status bar.

In all.log, look at the routine at $008F7E:

CODE_008F7E: 8D 14 0F STA.W $0F14 ; \ Write coins to status bar
CODE_008F81: 8E 13 0F STX.W $0F13 ; /


And yes it does store the coins to the status bar; this is a good place to hack a routine to put our custom code.

First, you need to jump to this address, using org:

org $8F7E ; <- NOTE: No need to specify the bank if it's bank 00.

Now you need to understand how Routine Hacking works. What we will do is replace this code (STA $0F14 STX $0F13) with a JSL to our custom code. The custom code will be stored in an empty area in the ROM (freespace), and the "replaced" code is also put back into our code.

The second thing to do, after jumping to the address, is to see the number of bytes present in that line. The line with STA $0F14 contains just 3 bytes. For a routine hack, you need 4 bytes (I'll tell why later).

Because we don't have enough bytes (we need 1 more), we also take bytes from the next line which is STX $0F13. So we've now got 6 bytes:

CODE_008F7E: 8D 14 0F STA.W $0F14 ; \ Write coins to status bar
CODE_008F81: 8E 13 0F STX.W $0F13 ; /


Note the number of bytes we have, it's important and as I said, I'll tell why later.

Now after the org $008F7E, we need to make this routine jump to our own code - we use a JSL here:

org $008F7E
JSL CustomCode


As you can see, we've accessed the code at $008F7E, and made it jump to a label called CustomCode, where our code will go. We haven't made it yet.

A JSL will take up 4 bytes, that's why a routine hack needs to use 4 bytes. What it does is overwrite the 4 bytes with its own code. This means that these 4 bytes are now gone:

CODE_008F7E: XX XX XX STA.W $0F14 ; \ Write coins to status bar
CODE_008F81: XX 13 0F STX.W $0F13 ; /


We now remain with just 13 and 0F - 2 extra bytes which we don't need and are useless. To get rid of them, we place 2 NOPs after the JSL:

org $008F7E
JSL CustomCode
NOP #2 ; <- 2 NOPs -> Get rid of extra bytes


Not all the time will you come across 6 byte routines though. Sometimes you might see 4 byte routines - in those cases, you don't need to add any NOPs because there are no extra bytes. If you hacked a routine with 5 bytes, then you would need to get rid of (5-4) = 1 byte. It's important to NOP out those extra bytes, because it can cause your game to crash!

In case you don't know what NOP means - it's basically an opcode which disables a byte and does nothing, so it's useful here. A NOP is also EA in hex, so you might already know it by seeing stuff like "Change to EA EA EA to disable ..." in the ROM Map.

Anyway, by now, the code should look like this.

Now we need to point our code to some empty space in the ROM. To do this, we need to use another org $xxxxxx, this one being a freespace address. This will make the entire CustomCode routine use an empty area in the ROM:

org $008F7E
JSL CustomCode
NOP #2 ; <- 2 NOPs -> Get rid of extra bytes
org $168000 ; Any free space area in the ROM


You probably already know how to find freespace - using Translhexation and Lunar Address or using Slogger. The freespace should NEVER be below $xx8000 (7FFF or below) because that area is NOT ROM.

After setting up freespace, you have a create your routine label (CustomCode) and write your custom routine there:

org $008F7E
JSL CustomCode
NOP #2 ; <- 2 NOPs -> Get rid of extra bytes
org $168000 ; Any free space area in the ROM
CustomCode: ; <- New routine


Now remember that after the JSL and 2 NOPs, the 6 bytes got overwritten right?

CODE_008F7E: XX XX XX STA.W $0F14 ; \ Write coins to status bar
CODE_008F81: XX XX XX STX.W $0F13 ; /


Before writing our custom code, we need to restore that overwritten code. If we don't put it back, then that code won't be executed! That means the coins won't be stored to the status bar! Always put the hacked code into your routine!

The code I need to put back is STA $0F14 and STX $0F13, so I'll put it at the beginning of the routine:

org $008F7E
JSL CustomCode
NOP #2 ; <- 2 NOPs -> Get rid of extra bytes
org $168000 ; Any free space area in the ROM
CustomCode: ; <- New routine
STA $0F14 ;/ Put hacked code back.
STX $0F13 ;\


It's important to know what kind of code you've hacked though. If it's something that loads a value/address, then you obviously need to put the hacked code at the end of your routine.

The code to store the ON/OFF switch to the status bar is simple, it's just 2 lines of code so add it in:

LDA $14AF ; <- Load ON/OFF switch.
STA $0EF9 ; <- Store to status bar, first tile.
RTL ; <- End routine. Uses RTL because routine was hacked with a JSL.


The final code should look like this. It's quite small because our routine is just 2 lines of code.

Lesson 4: Applying/Testing The Patch


The code is ready, but we need to apply the patch with xkas to our ROM. But as always, BACKUP YOUR ROM! You don't want your ROM to die if the patch was unsuccessful, do you?

Place cmd.exe (you can find this in your C:\Windows\System32 directory), xkas.exe and your patch file in your hack folder. Then open up the command prompt, and type this:

xkas.exe patch.asm rom.smc

Where patch and rom are the names of the patch and rom respectively. Press the enter button and test the ROM in an emulator. If everything went successful, you'll notice a 0 on the first tile of the status bar. If you hit the switch, it should be 1.

If your ROM crashes: the freespace you used was vital data and overwritten by the patch. If this happens, it's not easy fixing your ROM so it's best to revert to a backup.

Lesson 5: RATS Tag


I am sure you've seen most patches with db "STAR" written after writing the freespace. This thing is called a RATS Tag.

A RATS (RAT Allocation Tag System) is extremely useful and important to put in patches because at some point, Lunar Magic or any other tool can overwrite your patch data. When this happens, your patch probably won't function anymore or something bad might happen like the ROM crashing.

To set up a RATS Tag, you protect each and every byte in your routine. It is set up RIGHT after the org $freespace, like this:

JSL CustomCode
org $168000 ; <- Freespace.
!CodeSize = End-Start ; <- RATS Tag define.
db "STAR"
dw !CodeSize-$01
dw !CodeSize-$01^$FFFF
Start: <- Beginning of RATS Tag, and bytes to protect.
;=========;
;PATCH CODE GOES HERE
;=========;
End: ; <- End of RATS Tag and number of bytes to protect..


As you can see, you mark the ending and beginning of the RATS Tag in the !CodeSize define. This can be done directly in the dw part of the tag, but I like to do it this way. The start of my RATS Tag is called Start and the end of my RATS Tag is called End.

You can also notice that unlike labels, you put a colon (:) when making the RATS labels. It is Start: and End:, not Start and End!

So our code with a RATS Tag will look like this.

Don't forget putting RATS Tags inside your code, it's even been made a rule to submit patches with a RATS Tag. If you find it difficult to make one, just copy/paste from another patch ;)

Re-apply the patch, this time with a RATS Tag, and your code is now safe in the ROM. Hooray or something.

Multiple Hacks In One Patch


It is very possible and simple to create multiple hacks in just one .ASM file. If you want to hijack 2 routines, you would do it this way:

org $xxxxxx ; <- Routine #1.
JSL CustomRt1 ; <- Put our code there.

org $xxxxxx ; <- Routine #2.
JSL CustRt2 ; <- Put our code there.

org $xxxxxx ; <- !Freespace!


First you put all of the hijacks and in the end you put the org $freespace. The RATS Tag isn't altered, it just goes after the freespace as usual.

Normally health patches require you to hijack many routines, like the "Get Mushroom" routine, the hurt routine, the death routine etc.

Lesson 6: Using The Snes9x Debugger


In some cases, the ROM Map doesn't tell you about a routine you want to hijack. All.log is an extremely big document, about 12,000 lines, so it's going to be problematic to look through that whole file to find the routine you want. Sometimes you might not even be able to find it them.

This is where the debugger becomes useful. Using the RAM Map (which is 99% complete) and the debugger, you can find almost any routine you want easily. If you haven't already downloaded the debugger, get it here.

The debugger likes to remove the header of your ROM for some reason so make a backup of it.

Open your ROM through the debugger (File -> Open ROM). It'll ask you to remove the header. Click Yes because you have it remove it to use the program.

The window looks like this:


We're only concerned with 1, 2 and 3.

1) You press this to start your ROM. After triggering some breakpoints, you press this again. (We'll come to that later).

2) The breakpoints tab. What you do here is input a RAM Address and then run your code. The debugger will use that RAM Address to locate where in the ROM the routine is.

3) This is the output display. The location of your code (e.g. $018650) will be shown here, along with the breakpoints.

Now we want to locate the "Get Mushroom" code. To do this, first be close to touch a Mushroom:



Now click on the Debug Console window to pause the emulator. Go to the breakpoint tab. It looks like this:



The RAM Address(es) to work with are written at the left most tab (where it says 000000). We'll come to this in a bit.

There are 3 checkboxes - Exec, Read and Write. You almost never need to work with Exec, so we won't go through that one.

Read - Triggers a breakpoint when the specified (RAM) address gets read. For example, if I read $0DBF during a level, whenever it is read (usually by an LDA, CMP etc.), it'll trigger a breakpoint.

Write - Triggers a breakpoint when the specified (RAM) address is written to. If I write $7E0071, then the breakpoint is triggered if something gets stored to it (STA).

The "Get Mushroom" action is 02 in $71:

Mario Action trigger
02=get mushroom animation

This means our breakpoint will be $7E0071. 02 will be written to it when we get a Mushroom, so we'll check the "Write" box as well:



Now press the OK button. A breakpoint has been made, so press Run to start the ROM again. When you get a Mushroom, what do you notice on the display?



$01/C563, the address on the left, tells you where the Get Mushroom code is! To confirm it....

GiveMarioMushroom: A9 02 LDA.B #$02 ; \ Set growing action
CODE_01C563: 85 71 STA RAM_MarioAnimation ; /
CODE_01C565: A9 2F LDA.B #$2F ; \
CODE_01C567: 99 96 14 STA.W $1496,Y ; | Set animation timer
CODE_01C56A: 85 9D STA RAM_SpritesLocked ; / Set lock sprites timer


Yep, that's the code we want!

Now what if we want to know where the routine is when Mario gets a coin?

You first need to make Mario almost touch a coin, like this:



$7E0DBF is the coin RAM, and it gets INC'd when you get a coin. Set that as the breakpoint and check the "Write" box. Press Run and the display should be like this:



So $008F25 it is. Let's check that in all.log...

CODE_008F25: EE BF 0D INC.W RAM_StatusCoins ; Increase coins by 1

Yep, that's definitely it. That's how simple finding a routine is in the debugger.

Here are some commonly hijacked routines:

$00F5B7 (Hurt Mario)
$00F606 (Mario Death)
$009E2C (Load Game)
$009BCC (Save Game)
$00F2E0 (Get Midway Point)
$008F25 (Get Coin)

Some status bar routines can be found at $00/8Fxx.

..and that's the end of the tutorial. I hope you find this to be useful.

If you have any questions/suggestions/etc. then please post them here! If you find any lesson difficult, want me to include some more pictures, then feel free to ask!
Last edited on 2009-12-28 01:28:32 AM by Nesquik Bunny.
Okay I keep making an asm file but even if I name it insertnamehere.asm it still isn't an asm file.It's still a text file and xkas doesn't recognize it.Heres the patch.

header
lorom
org $00D8EA
db $04

org $00D805
db $04
Either go to View, Folder Options, (or something) and disable "hide known file types", or do File, Save As, and change the setting to All Files.
The only thing under view is status bar,and if I name it something.asm and save as all files like you said.It is still jsut a text document.I'm using windows XP
By text document, do you mean .txt, or it opens in Notepad? It should still have the same icon and open in Notepad.

(Perhaps it's Tools, not View)
I don't quite under stand this tutorial.

What I want to do is make a patch that will cause, when you hit a switch palace and activate it, you to exit the level without activating events.

$7E:0100
0B Fade to Overworld
0C Load Overworld
0D Overworld: Fade in
0E Overworld
0F Fade to Level

I was figuring I would have to do something that replaces the switch palaces code that causes you to exit the level and activate a normal exit after you're done hitting the message block.

What I want to do is make my switch palaces actual levels by using the fact that the switch disappears after you hit it, and you can move through it, by doing something like putting an exit enabled pipe under it or something. (it works)
Normally if you hit it, it activates a normal exit. I want it to still do what it does but not activate the normal exit so I figure I'd be using that ram address. This way I can put in a goal tape or something at the end of the level for you to actually beat it.

I basically don't understand...
PC Address, but a SNES Address ($148000 for example) instead.
How exactly do I find the number I'd put after org
edit: Actually reading that again I figured it out. I was just confused how he had three dif numbers or something.
Last edited on 2009-12-04 06:28:32 AM by Fakescaper.
Old thread, new post :D!

I've bumped this thread because I could use some information about a problem I have with my first patch I've made. Here's the code:

header
lorom

!FreeSpace = $03FE20

org $028AD2
JSL Code
NOP #2

org !FreeSpace

!CodeSize = CodeEnd-CodeStart
db "STAR"
dw !CodeSize-$01
dw !CodeSize-$01^$FFFF

CodeStart:
Code:
INC $0DBE ; Replaced code
LDA $0DBE
CMP #$01
BMI Skip
LDA #$01 ;\ Change frame of Manual event #0 to Frame 1
STA $7FC070 ;/
LDA $0DBE
CMP #$02
BMI Skip
LDA #$01 ;\ Change frame of Manual event #1 to Frame 1
STA $7FC071 ;/
LDA $0DBE
CMP #$03
BMI Skip
LDA #$01 ;\ Change frame of Manual event #2 to Frame 1
STA $7FC072 ;/
Skip:
LDA $1490 ; Replaced code
RTL
CodeEnd:


This patch triggers Manual ExAnimation Events 0 - 2 based on the number of 1ups collected w/o the need to touch any custom blocks. Once I applied it, it worked just the way I like it, but for some odd reason, Mario wouldn't stop sparkling, even if I didn't grab any 1ups. The only way I've stopped the side effect was to change org $028AD2 to org $8E6F (and properly restore its respective lines of code).

Can anyone please tell me what happened here?
From what I can gather, you simply used too many NOPs =P

Unless I remember wrong, JSL Code NOP #2 is four bytes long while INC $0DBE is three bytes, so you NOPed a neccesary byte in the hijacked code

Simply remove the #2 to fix the problem ^_^
Hmm... well I did follow the procedures shown in this tutorial...
It looks like this in all.log:

CODE_028AD2: EE BE 0D INC.W RAM_StatusLives
CODE_028AD5: AD 90 14 LDA.W $1490


Since JSL Code is supposed to take 4 bytes, it should be like this, right?:

CODE_028AD2: XX XX XX INC.W RAM_StatusLives
CODE_028AD5: XX 90 14 LDA.W $1490


And that's why I have the #2 after NOP to rid of the last two bytes. Yet something still appears to be amiss.

I'm confused... there really shouldn't be any flaws... Is there a mistake in this tut, or must I always replace some line of code that runs in every frame when it comes to hacking routines?
Sind - Remember that a JSL takes up 4 bytes so he takes away the INC $0DBE and LDA, then NOP's out 90 14.

anyway, you do know that $0DBE is the current amount of lives the player has so if the player started with 5 lives, it would skip to the end of the code. You might need to set up a patch that would count how many lives the player has gotten and increase a random freeram address when he has got a 1-up and then you would check if the freeram address is 1, 2, or 3
Actually Ramp202, I already edited my hack I've been working on for a while to have the player start with #$00 lives, and had those lives set to zero whenever the player dies. I have a personal exit block that also sets the lives to zero, so that wouldn't be a problem.
Yeah I noticed that right after I posted the post, but the editing is still not reenabled >-<

Looking at the code again, I am just as confused... it really should be working o_O


---------

After writing the above, I checked through the all log before submitting my reply just in case, and I think I found the problem =P

CODE_028AB7: F0 1C BEQ CODE_028AD5
CODE_028AB9: AD E5 18 LDA.W $18E5
CODE_028ABC: F0 05 BEQ CODE_028AC3
CODE_028ABE: CE E5 18 DEC.W $18E5
CODE_028AC1: 80 12 BRA CODE_028AD5


Two parts of this code jump to 028AD5, which you now have edited to pretty much nothing but NOPs...

Yeah, that should be your problem, heh
Yes, that's DEFINITELY what it is! Thanks a lot for your help Sind ^_^!

I guess from now on, I should check for any branch codes when considering which org locations to use. This warning should've been mentioned in this tut.
No problem DuskSpark ^-^


Also, speaking of the tut, I just noticed I haven't actually commented it yet:

I admit this guide is awesome! It teaches you in mere minutes what I back in the days needed weeks to learn, and some of it I still struggled with till I read this =P
For example the RATS tags. I love how you set them up, it's so simple <3
Pages: « 1 »
Forum Index - SMW Hacking - General SMW Hacking Help - Tutorials - Routine Hacking/Creating Patches

The purpose of this site is not to distribute copyrighted material, but to honor one of our favourite games.

Copyright © 2005 - 2013 - SMW Central
Legal Information - Link To Us


Total queries: 29

Menu