Hacking the ST rom

People already have networked HDD and CF card setups for Naomi and people enabling Atomiswave games to run on Naomi as well. Not to mention Dumping Union team is doing a redumping Naomi with correct keys so games like the arcade version of Akatsuki Blitzkampf can be fixed privately.

Legit. As Jed mentioned, people have been working on this stuff a lot (seems the last year or so). From what I understand there are 3 popular ways to load games onto your NAOMI:

Netboot - NAOMI loads games from your PC
CF Card loader - NAOMI loads games from Compact Flash Card
Raspberry Pi Netboot - similar to first option, but rather than NAOMI loading files from a PC, it loads from a Raspberry Pi with an SD card (which stores all your games)

There’s some discussion in this thread:


-ud

I would sure like a rom dump of this.

No, it is part of the game but WW dictator hardly, if ever uses it. It’s just like Shang Tsung has a superman punch in MK1 arcade versions, but he hardly uses it if ever. Maybe he used it in the prototype versions or something. Also, Kintaro has a kick in MK2 arcade versions, but same thing, the CPU never uses it if ever. Claw also has an airthrow in WW. I have seen the CPU use the airthrow on me about 22 years ago on an arcade cab in a Mountain Mike’s Pizza place. I like your sig. It is the best thread ever!

EDIT: has anyone played SFA3 Upper in an arcade?

I believe it was a Japanese only release. Not only did the players hate the changes. CvS was literally around the counter.

I think i found a very ugly mistake on the routine that determine how much frames each character have to special cancel normals…
Discovered by accident cuz i wanted to nerf O.Gat’s special cancel window by 1 frame…
Watch point used: wp ff85e3,1,w
Address ff85e3 contains how much special cancel frames are left.
Here is the routine, from the rom itself:



07F02E: 4A2E 03B6                  tst.b   ($3b6,A6)                        //Tests for Old character
07F032: 6708                       beq     $7f03c                             //Branches to 07F03C if not
07F034: 1D7B 0016 0195             move.b  ($16,PC,D0.w), ($195,A6)        //Update special cancel value, if Old Character
07F03A: 4E75                       rts
07F03C: D000                       add.b   D0, D0
07F03E: 1D7B 000C 0195             move.b  ($c,PC,D0.w), ($195,A6)        //Update special cancel value, if New Character
07F044: 1D7B 0007 02B0             move.b  ($7,PC,D0.w), ($2b0,A6)        //Same thing but for Super cancel ??
07F04A: 4E75                       rts
07F04C: 0607 0506                  addi.b  #$6, D7
07F050: 0607 0607                  addi.b  #$7, D7
07F054: 0607 0607                  addi.b  #$7, D7
07F058: 0506                       btst    D2, D6
07F05A: 0607 0607                  addi.b  #$7, D7
07F05E: 0607 0607                  addi.b  #$7, D7
07F062: 0607 0607                  addi.b  #$7, D7
07F066: 0506                       btst    D2, D6
07F068: 0506                       btst    D2, D6
07F06A: 0607 0607                  addi.b  #$7, D7


First line simply tests if the current character is Old or not.
So, if its a old character, it executes the line at 07F034, else it executes 07F03E and 07F044
As you can see, both 07F034 and 07F03E is modifying the value at ff85e3 (address register A6 contains 0xFF844e (if P1), + 0x195 = ff85e3, which is the special cancel address).
From 07F04C to 07F069 there are 32 different values (1 byte long each) for special cancel. Even though they are shown as ADD instructions by the debugger, they never get executed. Since i am not really an ASM programmer, it took me a while to understand this, the programmer just left the values on the code itself, but they are never interpreted as instructions, they just work as a table of values…
Anyway, before branching on 07F032, D0 contains the character ID (Ryu = 0, Honda = 1, Blanka =2, Guile = 3, … etc)
At that point, its easy to notice that the instruction on 07F03C that was supposed to “update” the value for New characters is faulty: even though the table has 32 values, it reuses some values and others are never used.

Lets examine that:

At this point we can define the formulas used to determine the address to pick a value from:
For old characters: PC + 0x16 + D0
For new characters:PC + 0xC + (D0+D0)

The first 2 values from each sum end up being the same (do the math, remember the implicit 0x2) which is 0x7F04C
For old characters: 0x7F04C + D0
For new characters:0x7F04C + D0*2

Proof that different characters may use the same value:
With character ID = 1 on D0 (Honda), for N.EHonda we get: 0x7F04C + 0x1*2 = 0x7F04C + 0x2 = 0x7F04E
Wich character ID = 2 on D0 (Blanka), for O.Blanka we get: 0x7F04C + 0x2 = 0x7F04E

So, both N.Honda and O.Blanka uses the value from the address 0x7F04E, which is 5.
(I have a table in excel format which contains the address for all characters, and a lot of them actually share values.)

Judging by how the values are arranged, if you consider that they are ordered by character ID, with 2 values each(First new, then old OR first special, then super), you’ll notice a very simple pattern: 6,7 5,6 6,7 6,7 6,7 … that is, the second value is always bigger by 1. My guess is that they planned as a general rule for O.Characters to always have 1 frame more for cancelling OR for Super cancel windows be bigger by 1 (notice that the instruction on 07F044 always picks the value that comes exactly after the value picked by the instruction that sets the special cancel value) and then Old charcters would always use one of these values for special cancels, but the routine on 07F03C is faulty and just doubles the value on D0 which is responsible for determining which valeu to use. It’s fair to assume that due to ST being rushed, some characters ended up having different cancellation windows than planned (O.Blanka having a vey mediocre one and O.Honda having a very good one), following the same logic though, its not possible to say that O.Gat having a larger cancelation window is a mistake, which i would really like to be true…

Anyway, its possible to fix this issue of values not used/valeus being shared, by changing the routine on 07F03C thep roblem is that it would require more rom space, 2 bytes is not enough AFAIK.

Yeah alot of data is shared in ST. So, cancel windows doesn’t surprise me at all.

Also, Assembly uses a ; for commenting

I did a little work on Vsav yesterday since nobody was having any problems on my Valkyrie Profile script.
Vsav uses a simple Subroutine to determine if you’re in the right place to be in a rival stage.

It’s that branch sub routine to $92be (bsr $92be)

Spoiler

http://i.imgur.com/Bhh3NjI.png

Looking at the code that is plenty enough room to put in a simple check on the global timer to check it’s odd or even then tell it to write the flag for the rival/vsav2 stages.
https://www.youtube.com/watch?v=L01fMyUlzM0

Let’s end it with some HSF2.
I’m beginning to toy with the of fixing HSF2 to “fix” it.
Turbo in the game is completely different than what is done in.
It’s stored at FFDF20 as 4 bytes. The high number the faster it goes which is the reverse of ST.
The table is at E8A76 starts with Normal speed.

(These are hexadecimal numbers)

0001 0000 Normal
0001 3000 T1
0001 5000 T2
0001 7000 T3
0001 8000 Unused

I find Unused speed too fast for To be ST’s T3 so the value I used is 0001 7800.

Hey jed, what would you do to discover if some part of code is executed at all?
I ask this because, i think near the routines i mentioned on my last post, there’s some unused bytes, and if thats true, then i’m planning to use 16 bytes for the old characters values and then just change the instruction:



07F034: 1D7B 0016 0195             move.b  ($16,PC,D0.w), ($195,A6) 


… to use another offset instead of 0x16, since the original table already works perfectly for New chars.

Here’s the code (inside spoiler tag), what you think?

Spoiler


07EFFA: 1F0B                       dc.w    $1f0b; ILLEGAL
07EFFC: 8A15                       or.b    (A5), D5
07EFFE: 3515                       move.w  (A5), -(A2)
07F000: 553A                       dc.w    $553a; ILLEGAL
07F002: 4506                       dc.w    $4506; ILLEGAL
07F004: EED4                       dc.w    $eed4; ILLEGAL
07F006: 2B66 0505                  move.l  -(A6), ($505,A5)
07F00A: 0505                       btst    D2, D5
07F00C: 0505                       btst    D2, D5
07F00E: 0505                       btst    D2, D5
07F010: 0505                       btst    D2, D5
07F012: 0505                       btst    D2, D5
07F014: 0505                       btst    D2, D5
07F016: 0505                       btst    D2, D5
07F018: 7000                       moveq   #$0, D0
07F01A: 102E 0391                  move.b  ($391,A6), D0
07F01E: 4A2E 03BD                  tst.b   ($3bd,A6)
07F022: 6704                       beq     $7f028
07F024: 103C 0010                  move.b  #$10, D0
07F028: 4A2E 038E                  tst.b   ($38e,A6)
07F02C: 670E                       beq     $7f03c
07F02E: 4A2E 03B6                  tst.b   ($3b6,A6)                                ; Start of code shown on my last post
07F032: 6708                       beq     $7f03c
07F034: 1D7B 0016 0195             move.b  ($16,PC,D0.w), ($195,A6)
07F03A: 4E75                       rts
07F03C: D000                       add.b   D0, D0
07F03E: 1D7B 000C 0195             move.b  ($c,PC,D0.w), ($195,A6)
07F044: 1D7B 0007 02B0             move.b  ($7,PC,D0.w), ($2b0,A6)
07F04A: 4E75                       rts
07F04C: 0607 0506                  addi.b  #$6, D7
07F050: 0607 0607                  addi.b  #$7, D7
07F054: 0607 0607                  addi.b  #$7, D7
07F058: 0506                       btst    D2, D6
07F05A: 0607 0607                  addi.b  #$7, D7
07F05E: 0607 0607                  addi.b  #$7, D7
07F062: 0607 0607                  addi.b  #$7, D7
07F066: 0506                       btst    D2, D6
07F068: 0506                       btst    D2, D6
07F06A: 0607 0607                  addi.b  #$7, D7                                 ; End of code show on my last post
07F06E: 4A6E 01F2                  tst.w   ($1f2,A6)
07F072: 6702                       beq     $7f076
07F074: 4E75                       rts
07F076: 3B6E 005E A8EA             move.w  ($5e,A6), (-$5716,A5)
07F07C: 426D A8EC                  clr.w   (-$5714,A5)
07F080: 4A2E 0049                  tst.b   ($49,A6)
07F084: 6626                       bne     $7f0ac
07F086: 4A2E 0123                  tst.b   ($123,A6)
07F08A: 6600 0188                  bne     $7f214
07F08E: 4A2E 01FC                  tst.b   ($1fc,A6)
07F092: 6600 00F4                  bne     $7f188
07F096: 4A2E 02A0                  tst.b   ($2a0,A6)
07F09A: 6600 00BC                  bne     $7f158
07F09E: 102E 0055                  move.b  ($55,A6), D0
07F0A2: 4880                       ext.w   D0
07F0A4: 323B 0008                  move.w  ($8,PC,D0.w), D1
07F0A8: 4EFB 1004                  jmp     ($4,PC,D1.w)
07F0AC: 4E75                       rts
07F0AE: 004C                       dc.w    $004c; ILLEGAL
07F0B0: 004C                       dc.w    $004c; ILLEGAL
07F0B2: 004C                       dc.w    $004c; ILLEGAL
07F0B4: 0072 0072 004C             ori.w   #$72, ($4c,A2,D0.w)
07F0BA: 0074 009A 004C             ori.w   #$9a, ($4c,A4,D0.w)
07F0C0: 004C                       dc.w    $004c; ILLEGAL
07F0C2: 004C                       dc.w    $004c; ILLEGAL
07F0C4: 004C                       dc.w    $004c; ILLEGAL
07F0C6: 004C                       dc.w    $004c; ILLEGAL
07F0C8: 004C                       dc.w    $004c; ILLEGAL
07F0CA: 004C                       dc.w    $004c; ILLEGAL
07F0CC: 004C                       dc.w    $004c; ILLEGAL
07F0CE: 004C                       dc.w    $004c; ILLEGAL
07F0D0: 004C                       dc.w    $004c; ILLEGAL
07F0D2: 004C                       dc.w    $004c; ILLEGAL
07F0D4: 004C                       dc.w    $004c; ILLEGAL
07F0D6: 004C                       dc.w    $004c; ILLEGAL
07F0D8: 004C                       dc.w    $004c; ILLEGAL
07F0DA: 004C                       dc.w    $004c; ILLEGAL
07F0DC: 004C                       dc.w    $004c; ILLEGAL
07F0DE: 004C                       dc.w    $004c; ILLEGAL
07F0E0: 004C                       dc.w    $004c; ILLEGAL
07F0E2: 004C                       dc.w    $004c; ILLEGAL
07F0E4: 004C                       dc.w    $004c; ILLEGAL
07F0E6: 004C                       dc.w    $004c; ILLEGAL
07F0E8: 004C                       dc.w    $004c; ILLEGAL
07F0EA: 004C                       dc.w    $004c; ILLEGAL
07F0EC: 004C                       dc.w    $004c; ILLEGAL
07F0EE: 004C                       dc.w    $004c; ILLEGAL
07F0F0: 004C                       dc.w    $004c; ILLEGAL
07F0F2: 004C                       dc.w    $004c; ILLEGAL
07F0F4: 004C                       dc.w    $004c; ILLEGAL
07F0F6: 004C                       dc.w    $004c; ILLEGAL
07F0F8: 004C                       dc.w    $004c; ILLEGAL
07F0FA: 102E 01FD                  move.b  ($1fd,A6), D0


As you see, before the routine itself, there are 7 btst isntructions which aren’t even used… atleast apparently. Though they could be just values thrown on the code(like on the special cancel values), but they’re are all the same so i think its unlikelly… They wouldnt give me enough space though…
Also, starting on 07F0C0 theres a lot of ILLEGAL instructions thing, so this is surelly not executed at all, they could be values left near the code, but why would they exist if they’re are all the same ?? Do you think its safe to insert the values on that region?

The only idea i have is to set a watchpoint on write mode on the addresses that hold the actual X and Y positions and analyse where the values come from. You can get these addresses from Pasky’s ST HUD lua script, so its easy to start messing with that.

I just mess with till it crashes.So, if a opcode is changed and it crashs then I don’t touch it if not I will till it crashes.

But, what you’re showing could be a tile map, another table, or literally garbage. You don’t have to use the move PC+D#.w+$X read a table unless you want it encrypted.

This makes it so easy to keep track of hitbox changes. I only have it for A2,A3, and Vsav.

http://i.imgur.com/g8N1qwM.png

Also, if anybody wants to mess with colors. Give a shout I’ll explain how to use it.
My color viewer script. Supports CPS1, CPS2, CPS3, Groove on Fight, Old School MK, Jackie Chan in Fists of Fire, and Neo Geo

A script like that for ST would be very useful man!
I was wondering some time ago, would a lua script to preview changes on hitboxes possible?
Of course, to actually persist the changes, an hex editor would still be needed, but, would it be possible to change parameters of a hitbox, given its address, via lua scirpting? So its possible to preview the changes and then modify with the hex editor only once, instead of having to hex edit multiple times till you get its properties perfect.

Yeah, switch the memory view to “Region ‘maincpu’” and edit away they stay until you hard reset or load a state with out the changes.

I tested putting the old character special cancel values in that region with the ILLEGAL instructions, but no luck… the game crashes when the opponent gets hit… Must be a table of something… Damn!!

What exactly is the code you’re trying to do?

Since the existing table works as expected for new characters, what i tried to do was: create a new table with the specific values for old chars and then point to it, instead of using the same table for both, this way i could change the special cancel window from O.Gat without messing with Ken’s suepr cancel data (they are sharing). I just wanted to fix the issue of the shared values… the problem is, the place i thought that was filled with garbage data is actually used for something related to characters being hit, i dont know… when i whiffed the normals i was getting the expected values so its not a problem with my modifications… but as soon as a normal hit, the game crashed. what i did exactly was: change the first of these 004c 004c (the ILLEGAL “instructions”) with 0607 0506 0607 0607 0607 0607 0506 0607 and then change the 0x16 on the move instruction with the correct offset.

I was thinking about a different method though: since the Super cancels are already always equals to special cancel +1, instead of having a value specific for them, i could just have the value for special cancel, and then add 1 to it to have the super cancel value… that gives me extra 16 bytes on the table to use for the old chars… Though i would still need some bytes for the additional instructions… meh… ill try to mess with these repeated btst instructions next time, though i am starting to think that wont work as well…

I’m asking for the code take a screen shot of the disassembly window(Ctrl+D) if you still have it available.

If you’re going to try and fixed the shared values for all characters and the versions. it’s going to be a lot harder than that as you have to rewrite the checks.

Here is an example what I would
move.b playeradr + CharID, D0
add D0,D0
move pc+anumber+D0, D0
jmp pc+anumber+D0

;after the jump
tst.b playeradr + oldslot
beq oldcancel; branch to the old character cancels
;New character cancels

I dont have it anymore… but my modification wasvery simple.
EDIT: Ok here they are:

Spoiler

Before:

http://i.imgur.com/vYpiZi1.png

After:

http://i.imgur.com/2RjHxs1.png

I dont understand what you meant by rewrite the checks… the code already has an if-else construction:
if its old character, then 07F034 is executed
else, 07F03E and 07F044 are executed.

My idea was to just modify the offset (0x16) on 07F034 to point to a new table i would create (0x16 points to the same table as newchars). Though i would be limited to a offset of 0x7f for the offset, cuz 0x80 to 0xff are for negative representations. The first or so bytes on these ILLEGAL instructions are “reachable” but they are already used for something so it wont be possible to throw my table there. The btst above are probably used as well, since the branch that goes to this subroutine starts on 07F018, and sicne theres no branch or rts before it, then these btst are garbage or a table of some sort… have to test that though.

Do you know addresses of some unused areas? i think i will just jump to a new location if its old character, and put my table there, before an rts, of course.

EDIT: Ok i tested modifying the values on the btst “instructions”… i tried some absurd values like 55 and 78, and it didnt crashed. Not that it means much but thats a start… i think ill just place my table in that area, and if something strange happens i 'll just revert it.

Yet another edit:
Okay, it works! Setting the offset to 0xD2, and changing all the 16 bytes with 0x05 as value to “0607 0506 0607 0607 0607 0607 0506 0607” ( these bsts “isntructions”) works, and the game didnt crashed. Though i dont know if something strange is hapening.

This is all very interesting! Imagine how the old characters would have turned out if they were implemented correctly:

Chun, Dhalsim, Zangief, Fei Long, DeeJay, Claw, and Sagat all work as intended; that is, they cancel one frame after their new counterparts. (Dictator might, but he holds the distinction of not mattering much either way, so long as his window is either 6 or 7 frames.)

Blanka and Cammy are actually worse than their new counterparts, canceling only within 5 frames instead of 6 (where it should actually be 7 for them). Imagine being able to cancel Blanka’s far standing strong, or better yet, Cammy’s far standing forward or the tip of her far standing fierce! This would be in addition to all of the cancels they “lost” from their new counterparts as well.

As far as I can tell, Ryu, Ken, Guile, T.Hawk, and Boxer cancel in the same number of frames as their new counterparts, making them a single frame “worse” than they should be. For the shotos, Guile, and T.Hawk, this would add a few cancels, but nothing groundbreaking for them. Boxer, on the other hand, would be able to cancel close strong, and more importantly, crouching forward!

E.Honda is actually better than he should be (cancels in 7 frames instead of 6, or two frames better than his new counterpart), but it only really seems to affect crouching fierce.

I love seeing what everyone keeps coming up with here. Keep up the good work!

Oh I think i was wrong with that hipothesis though. I now think that CAPCOM wanted to make the Super cancels to be 1 frame after, since the routine makes a lot of sense for new cahracters, but for old characters it just gets values in sequence which doesnt make sense. The thing with the old characters using the same valeus is just a big mess and I dont really know what was their real intention… I think they didnt wanted to give old characters a buff at all, and it was simply just a mistake. All in all it was a nice addition though, with the exception of Old Sagat of course. And some people dont think ST was rushed… lol.

I thought there was some RNG in the command is the reason I thought of it weird code. That’s what I get for not reading

Also, that move function moves another two bytes 7A is actually 7C. What I used was 7E so PC + 0x80 + D0 it worked as well. It has to do with the operation some reason it doesn’t like it moving to something ending in 0xA.

Hopefully, you can see the values in the video.