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.