Language…
14 users online:  Ahrion, crocodileman94, DasFueller,  Fernap, Foxy_9000_, Gamet2004, hoangng,  MarkAlarm, playagmes169, pnaha, Scags, sinseiga, Sweetdude, Tsquare07 - Guests: 254 - Bots: 256
Users: 64,795 (2,376 active)
Latest user: mathew

Making a patch (xkas)

Patch Tutorial



So this is a tutorial on how to make a xkas patch. I know the backup of the SmwWiki has one, but using that, I didn't like it at all. Too much context. So instead, I decided to write one just for beginners.

You'll need:


A knowledge of ASM (the level varies, but you should be able to code blocks well and sprites maybe)
Xkas
A SMW Rom (Saved once in Lunar Magic)
Notepad (++ if you wish)
All.log (can be found in the documents section)
Geiger's SNES Debugger (usually, sometimes using the ROM map you can wing it)
Just so we are on the same page:
All opcodes use "bytes" of data. Open up all.log and you'll see stuff like this:
ODE_008064: A9 03 LDA.B #$03
or this:
CODE_008061: 20 50 92 JSR.W CODE_009250

Those numbers in the middle are the bytes. They correspond with the code, in hex. For instance, LDA in hex is A9. And since it's loading 03, the next byte is 03. The JSR is a total of three bytes- one for the opcode- 20- and then two for the number that shows where the code will jump. You'd think it would be 92 50, since that is where the code jumps, but actually the code is fed in backwards, so it's 50 92. JSLs- the ones we will be working with the most- are four bytes, one for the JSL itself and then 3 bytes to identify where to go.
Also, the ROM map IS the coding of SMW. It's the never-changing basic code of this game, and so we can use it and all.log to find places where you want to change the code.
So patches, as I think you know, go into the code of SMW and "hijack" one part of the code, and then replace it. Sometimes in several places. To do this, they use a JSL, a four byte opcode that makes the code jump. I'll include a tutorial on how to use Geiger's Debugger to find code later, but for now let's just use the ROM map, which is where you will always be hijacking.
So, let's say you want to change the way mario dies. Well, look in the ROM map:
$00:F606 34 bytes Subroutine Death Subroutine (JSL to it to kill Mario)
It's at $F606! We can find this directly in all.log.

KillMario: A9 90 LDA.B #$90 ; \ Mario Y speed = #$90
CODE_00F608: 85 7D STA RAM_MarioSpeedY ; /

And here it is, even conviently labeled. To get around all.log, I like to use Ctrl+F and then type in the code number I am looking for. If it can't find it, then I just have to get there manually. Ah well.

So now you've found the death subroutine. So what? You still need to hijack it, right? Well, there is an easy way to do this.
Look for a place where 4 bytes are nice and tidy together, and the fourth byte is the end of the line, and the first byte is the beginning of a line. For instance:


KillMario: A9 90 LDA.B #$90 ; \ Mario Y speed = #$90
CODE_00F608: 85 7D STA RAM_MarioSpeedY ; /


Four bytes. Easy. We could put in a JSL there and bam, no problem. Of course, the only catch is that we need to replace that code inside the JSL we just did. Still, not a problem.

However, often you will come across places where you can't do this. For instance:


CODE_00F618: 9C 0D 14 STZ.W RAM_IsSpinJump ; Spin jump flag = 0
CODE_00F61B: A9 30 LDA.B #$30


Sure, you can have 4 bytes here, but if you replace the first four bytes, all of a sudden you've got this random "30" sticking out in the open. To fix this, we use NOP. NOP is a opcode that stand for "No Operation." If we use this, we can erase that annoying 30. You'll see exactly what to do in the code when we discuss it later on.

Alright, so now you know where to put your JSL. Now, to simply get it in there.
First, open up notepad.
Type this:


header ; this starts the header part
lorom ; lorom is the format SMW is in, and we need to say that

org $00F618 ; just as a note, we could get rid of the 00 because it's assumed. ORG means where the code should start at. We chose to start it here:
CODE_00F618: 9C 0D 14 STZ.W RAM_IsSpinJump ; Spin jump flag = 0
CODE_00F61B: A9 30 LDA.B #$30


However, if you'll notice, four bytes leaves a 30 out in the open. that will crash the game. We need to get rid of it- and to that, we add in a NOP, one byte of useless. So:

header
lorom

org $00F618
JSL Main ; this will jump to "Main" in this code- we'll put that in in a second
NOP ; this makes sure that we don't have that extra 30 sitting around!


if we were to leave it like this, well it would crash because there was no main- but let's assume there was. The code in SMW would actually look like this:


CODE_00F614: A9 09 LDA.B #$09 ; \ Animation sequence = Kill Mario
CODE_00F616: 85 71 STA RAM_MarioAnimation ; /
CODE_00F618: 01 02 03 04 JSL Main ;
CODE_00F61C: EA NOP
CODE_00F61D: 8D 96 14 STA.W $1496 ; Set hurt frame timer
CODE_00F620: 85 9D STA RAM_SpritesLocked ; set lock sprite timer



(The 01, 02, 03, 04 are not the actually bytes, I'm just using them to represent the 4 bytes.
And so as you can see, it's a clear cut, with no other opcodes sliced off.
Now, back to our code:


header ; this is the header...
lorom ; and the game we are changing is a lorom format
org $00F618 ; start at $00F618
JSL Main ; and jump to the "Main" part of this code
NOP ; this makes sure we don't have that 30 there
; leaving a space here for orginisational purposes..
org $FREESPACE ; Freespace. See, we can't keep the code where it is at right now- we'll start overwriting things in the code. So, we make it where there is some extra space in the ROM. The ROM map documents it here:
$0E:F0F0 3,856 bytes Empty Empty
$0F:EF90 4,208 bytes Empty Empty
cool. That's more than enough space. So pick a address somewhere in there for free space.
Main: ; now we are at the "Main" part of our code.

okay, just to recap.

header
lorom

org $00F618
JSL Main
NOP

org $0F2356 ; random address I picked.
Main: ; well now, we can run wild.
LDA #$0D ;\
STA $0DAE ;/lowering the brightness, for effect...
LDA #$04 ;\
STA $1DF9 ;/makes a sound, heck if I know what sound
LDA #$10 ;\
STA $1DFB ;/I know that this subroutine sets the music earlier in the code, but this will overwrite that. 4 bytes won't kill the code, so..
RTL ; and now I'm returning. Woo yay.


BUT!
If you'll remember, we just hijacked part of the code, right?

CODE_00F618: 9C 0D 14 STZ.W RAM_IsSpinJump ; Spin jump flag = 0
CODE_00F61B: A9 30 LDA.B #$30

yeah, that. Well, we still need it in the code! Otherwise this won't work properly.

So, our final result:

header
lorom

org $00F618
JSL Main
NOP

org $0F2356 ; random address I picked.
Main: ; well now, we can run wild.
LDA #$0D ;\
STA $0DAE ;/lowering the brightness, for effect...
LDA #$04 ;\
STA $1DF9 ;/makes a sound, heck if I know what sound
LDA #$10 ;\
STA $1DFB ;/I know that this subroutine sets the music earlier in the code, but this will overwrite that. 4 bytes won't kill the code, so..
STZ $140D ;\
LDA #$30 ;/ I have to preserve the original code!
RTL ; and now I'm returning. Woo yay.

And there you are, a nice patch. Just save it as a .asm file and apply.

Using the Debugger


However, there are cases when the ROM map is not documented enough to give you what you want. What if you want to hijack the "get mushroom" routine? Well, you could use what the ROM map says and guess if that code is included with the rest of the routine, but there is a safer way- just use the debugger! Geiger's SNES Debugger is a awesome tool that allows you to find out what is running where. Using it is easy.
After downloading the program, open up a SMW ROM that has been saved once in LM. (so it's 1,024 kb.)
Here's what it looks like:




Yep, the nice little debug window. you can read the help file if you want, but the only button we're concerned with is #1. This is the breakpoints tab.
#2 is the output area- when the breakpoint is triggered, you'll see where it was triggered here.
#3 is the "run" button. You'll want to press this just after you opened the ROM and every time it hits the breakpoint.



Here it is, the breakpoint tab.
#1: This RAM address to work with. We'll talk about this in a minute.
#2: Here are the checkboxes to determine WHAT will set off the breakpoint. "Exec" means when it is excecuted. Don't worry about that, you'll almost never have to bother with it.
#3 "Read"- if the RAM address is ever, ever looked at by the code- weather through LDA, or CMP- that will set off the breakpoint.
#4 "Write" if the ram address is ever altered, like STA, usually.

Okay, so we need to find a RAM address that, when you get a mushroom, is read to written to. $71 is the mario action, and 02 is get a mushroom- so there must be a LDA #$02 STA $71, or something of that sort, when you get a mushroom. So, I'll set the breakpoint at 7E0071.



That's what it should look like. I would check the read button, but chances are that address is read from all the time, so it would keep triggering the breakpoint.
TIP- I would not set the breakpoint until you are close to the point where the code you want would be run. In this case, do not set the breakpoint until you are about to get a mushroom.
So now, run your code...
until you get to a mushroom!
Now set the breakpoint...

and bam.



There you are! That's where the code is run!
And sure enough...

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

There it is, right where it should be!




And there you have it. That's how you make a patch. Please, please give me critisism or suggestions. For instance, if you want me to elaborate on something, include pictures more, correct something, etc. I'm more than happy to.
You should probably add something on using the STAR/RATS tag to prevent Lunar Magic and other tools from overwriting your stuff.

I particularly like the way ObjecTool does it:

Code
!ObjecToolsize = ObjecToolend-ObjecToolstart

db "STAR"		; Write RATS tag
dw !ObjecToolsize-$01
dw !ObjecToolsize-$01^$FFFF

ObjecToolstart:

... ;your code here.

ObjecToolend:
I hope this is not considered a bump.

I want to ask you something:


CODE_00F618: 9C 0D 14 STZ.W RAM_IsSpinJump ; Spin jump flag = 0
CODE_00F61B: A9 30 LDA.B #$30

STZ $140D ;\
LDA #$30 ;/ I have to preserve the original code!

So, you use STZ $140D, but in the original code its says: CODE_00F618, so how do you know that it has to be 140D??

Thanks

And I also wanna thank you for this Tutorial, Im learning day by day more ASM and I hope one day I can bring you an awesome ASM hack :)
Mega Mario:
CODE_00F618: 9C 0D 14 STZ.W RAM_IsSpinJump ; Spin jump flag = 0

Check out the part in bold. We're STZ'ing the RAM_IsSpinJump define, which happens to be $140D (see the bottom of all.log). You can also disassemble the hex code to get the same result; STZ $140D.

The CODE_00F618 just tells you which part of the code it is. It has nothing to do with the actual coding.
Originally posted by Iceguy
CODE_00F618: 9C 0D 14 STZ.W RAM_IsSpinJump ; Spin jump flag = 0

Check out the part in bold. We're STZ'ing the RAM_IsSpinJump define, which happens to be $140D (see the bottom of all.log). You can also disassemble the hex code to get the same result; STZ $140D.

The CODE_00F618 just tells you which part of the code it is. It has nothing to do with the actual coding.


Ok thanks!

To make a custom power up, I need to look at, for example, Fire Ball power up, and edit the physics and all that stuff, and then I can insert that ASM hack in an empty address in the Rom, so I can have a new custom power up. I can do the same process to make another, and by that, I can have 2 custom power ups, right? Or is not posible?
Mega Mario:
Of course, you could hookup the original powerup routine to make $19 use values up to #$FF for custom powerups, although that may be a bit hard. I think rubixcuber did that though, who hasn't been active for quite some time.

A better way would be to create your custom powerup through a generator and sprite. Bascially, the sprite just sets a RAM Address, and the generator checks whether the RAM Address is set. If it is, it branches to the routine which the powerup does. And if Mario get's hit, simply reset that RAM Address. That's what ICB did with his hammer and boomerang powerups. Here's a small example:

The sprite does this:

LDA #$04
STA $0DC6 ; this RAM Addresses = #$04 when you have the sprite.

The generator does this:

LDA $0DC6
CMP #$04 ; if the powerup has been collected..
BEQ ExCode ; execute code.
LDA $19
BNE Skip
STZ $0DC6
Skip:
RTL
Oh great, this is back from the dead! :p

Although I recall you are making a Megaman hack, so you won't want your unused address to ever STZ, since Megaman never "loses" his powerups. Also, I would make the generator one sprite and place it every level (or hook the base of the level code, which is easier) and make that one unused RAM address handle ALL the powerups by making each bit determine if he has the powerup or not.

If that didn't make any sense, you need to read up on bitwise commands. The ASM Workshop Summary is a good place to start.
Hello I am new to Patches so i probably do a huge mistake :(
it crashes my game. here is the code:

header
lorom

org $00F618
JSL Main
NOP

org $1fb000
Main:
LDA #$02
STA $19
LDA #$30
RTL ;