News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: Speed hack for Hook on SNES (to make it faster like Skyblazer)  (Read 1285 times)

RetroProf

  • Full Member
  • ***
  • Posts: 134
    • View Profile
Speed hack for Hook on SNES (to make it faster like Skyblazer)
« on: October 28, 2017, 03:03:10 pm »
Skyblazer is one of my favourite SNES games. Hook was by the same developer, using what appears to be the same engine, so I've repeatedly tried to get into it. However, the character's movement is painfully slow compared to Skyblazer.

At first I thought the solution would be to swap in code from Skyblazer, assuming they were similar enough, but then I decided it's probably possible just to hack Hook to be faster. So I did that, and have almost cracked it.

I just need some help fixing it, and also an explanation (or link to reading material) on how to make an IPS patch that changes hex values.

When playing Hook:
The character seems to have 4 movement states:
1) Standing still
2) Walking slow
3) Jogging
4) Running

Only the running movement is anywhere near decent, the rest are slow as molasses. But to start running he needs to build momentum, meaning I suspect there's an internal value which counts up or down until it reaches a specified max/min value, whereupon your animation and movement speed end up "locked" into running mode.

My hope was to find this value and permanently set it to run, so that simply pushing the d-pad makes you run, just like in Skyblazer. I was using SNES9X's built-in cheat search to find this, by moving at various speeds (or standing still) and seeing what numbers changed.

The two main hex codes I've found are:

3000 F301 00?? (C0 or 80)
3000 F341 0002


Or to write them differently:
Adr: 0xF301 Val: ?? (192 or 128)
Adr: 0xF341 Val: 2


F341 relates to overall movement speed, including how fast the screen moves. Setting it to 2 is perfect. The character runs at a nice clip and the scrolls fast and everything feels much more like SKyblazer. Maybe it's a bit too fast, in which case 1 will suffice too. A value of "0" seems to be the stationary speed. Sadly with this activated, once you start running you can't stop - the character just keeps running until he hits a wall, and then just keeps running on the spot.

My concern is that this is directly tied to the fastest running speed, and rather than some kind of momentum counter, the game actually just changes this specific value. In which case a speed hack probably wouldn't work. Ideally I'd like the game's movement to function as if F341 was set to a value of 2, but with the ability to stop when needed - or at least have the run button "Y" automatically force it up to a value of 2 rather than the slow-asses build up that currently happens.

Anyway...

It gets confusing for me when we factor in F301. This appears to be the momentum counter. The standing hex value is C0, or 192 in decimal. At full pelt the hex value becomes 80 or 128 in decimal.

I had hoped that by locking this to a hex value of 80 this would permanently put him in run mode, but it actually seems to prevent him from running...? I tried screwing around with the F301 value, from 00 (0) up to FF (255), but anything outside the two preset values the game adjusts it to causes all kinds of weird crap to happen, including the screen flying violently in different directions.

Also address F321 seems to relate to the kind of animation cycle used (standing, walking, running etc).

I feel like I'm close, but maybe I'm way out of my depth here. I've tried viewing the memory dump in different states of movement, but too many things seem to change. However, the most noticeable events are around/between the F301 and F341 addresses.

Anyone have any ideas? Is this feasible? Are we on the brink of a patch that makes the game actually playable?

FAST6191

  • Hero Member
  • *****
  • Posts: 2621
    • View Profile
Re: Speed hack for Hook on SNES (to make it faster like Skyblazer)
« Reply #1 on: October 29, 2017, 05:54:55 am »
Is this feasible? Are we on the brink of a patch that makes the game actually playable?
It seems well within the capabilities of the system, and moreover it is already in the game* and you seem like you have much of the code. Yes on both counts. Whether it might break, or otherwise render far more difficult, a puzzle, boss or similar I will leave for later discussion.

*I could probably spend the time to make the game into a version of Tetris with RPG elements but it would be a lot of work.

I am a bit surprised at the cheat searching working as well as it did. It is a simple and effective way for devs to do it but I would not expect it to work on all games. Were I doing something like this I would probably have gone directly to the sprites set a breakpoint to get handling code and gone from there, either fine tuning the build up/cool off functions or doing something like what I am about to cover.

I assume your cheat is merely of the "hold value at ? as *" type. Endless running is not then an unexpected result.
A button activator cheat would be the easy way out, assuming the emulator's/cheat device cheat capabilities support such a thing ( http://doc.kodewerx.org/hacking_snes.html is a bit basic but if it is accurate then seemingly not) or you are willing to hack such a thing into them. Easy in this case is not bad though and even if the cheat options don't directly support it then it is still a viable choice for the hack (the other main one being the fine tuning thing I was on about earlier).
Anyway you are probably going to want to find the code handling the movement after all, fortunately you already have some relevant addresses so a bpr (break point read) set on them should find you it fairly quickly.
This will likely involve some assembly but, extra button activator aside, you are not going to be asked to have to dream up some new code so it could make a nice intro to it all. It will be more it says add 8 to this value and then this bit checks if it is above this and will do this as a result. Or indeed if start to walk is pressed do walk until run and you just skip right to run or something.

"including how fast the screen moves"
Not amazingly relevant as again you are seemingly working within the confines of the game but you may want to be more aware of cameras
https://docs.google.com/document/d/1iNSQIyNpVGHeak6isbP6AHdHD50gs8MNXF1GCf08efg/pub?embedded=true
Such a thing could actually change the camera type.

"how to make an IPS patch"
Download patch making program of choice, for IPS I like https://www.romhacking.net/utilities/13/ but others like other things.
Open modified ROM and base ROM in relevant sections, press make patch.
If you mean you want the memory addresses above as an IPS patch change then no. Share the cheat instead.

RetroProf

  • Full Member
  • ***
  • Posts: 134
    • View Profile
Re: Speed hack for Hook on SNES (to make it faster like Skyblazer)
« Reply #2 on: November 01, 2017, 01:46:10 pm »
Thank you very much!  ;D

At the moment the cheats do indeed just hold the value at a specific number (setting it to zero disables run entirely).

I didn't know about button activating cheats - so that's not only interesting, but probably the easier route.

Cheers for the links to info and tools - something to work on this weekend.  :)

VicVergil

  • Hero Member
  • *****
  • Posts: 715
    • View Profile
Re: Speed hack for Hook on SNES (to make it faster like Skyblazer)
« Reply #3 on: November 01, 2017, 09:52:21 pm »
Instead of trying to use the cheat engine to find a speed value which might or might not exist, why don't you search for the player character's horizontal coordinates on the screen?
Usually there's "fake" ones for the scrolling background, or where the game draws the sprite, and there's the "real" one where changing it really warps the character there and updates the "fake" ones, though the camera might still be independent sometimes.
Then when you find it, you put a write breakpoint on it and disassemble any code that triggers the breakpoint, until you get what causes it to change, and how to make it increase at acceptable rates (in other terms, make it faster).

Quote
Anyway...

It gets confusing for me when we factor in F301. This appears to be the momentum counter. The standing hex value is C0, or 192 in decimal. At full pelt the hex value becomes 80 or 128 in decimal.

I had hoped that by locking this to a hex value of 80 this would permanently put him in run mode, but it actually seems to prevent him from running...? I tried screwing around with the F301 value, from 00 (0) up to FF (255), but anything outside the two preset values the game adjusts it to causes all kinds of weird crap to happen, including the screen flying violently in different directions.

I remember when I was making a cheat code for Tengai Makyou Zero to remove encounters, I found the value that would decrease until it reaches 0 which triggers the encounter. I noticed that freezing it at 0 causes no encounters to happen forever, while forcing it to 1 causes encounters to happen every single step, like on the Mega Man Battle Network anti-piracy mode.
It seems the game does the check only when the value changes, not constantly. What seems to happen is that while the cheat is active, the value is at 1, you take a step, the game substracts from that value, compare it against 0, test returns true, the emulator forcing the value again to 1 doesn't happen until a few milliseconds (next VBlank, or next frame, I dunno).

Same goes for this value too.

Here's my notes. I guess the code and checks for the addresses you found might be in here.

Just one piece of advice:
The addresses you found (F301, F341) are RAM. So they're internally 7EF301 and 7EF341.
You eventually want to do a permanent edit, so not these addresses but some data on ROM will need to be changed.

Quote
Simple tap on the direction pad; these instructions all modify the putative "momentum" value.

$00/A57B 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:0080 X:0001 Y:0000 P:eNvMxdizc
$00/A6D2 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:0078 X:0001 Y:000C P:enVMxdizC
$00/A6EE 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00C0 X:0001 Y:000C P:eNvMxdizc
$00/A6D2 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00B8 X:0001 Y:000C P:eNvMxdizC
$00/A6EE 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00C0 X:0001 Y:000C P:eNvMxdizc
$00/A6D2 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00B8 X:0001 Y:000C P:eNvMxdizC
$00/A6EE 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00C0 X:0001 Y:000C P:eNvMxdizc
$00/A6D2 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00B8 X:0001 Y:000C P:eNvMxdizC
$00/A6EE 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00C0 X:0001 Y:000C P:eNvMxdizc

==

$00/A57B 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00C0 X:0001 Y:0000 P:eNvMxdizc

I disassembled around it a bit -

$00/A575 9F 80 F8 7E STA $7EF880,x[$7E:F881] A:00C0 X:0001 Y:0000 P:eNvMxdizc
$00/A579 A9 C0       LDA #$C0                A:00C0 X:0001 Y:0000 P:eNvMxdizc
$00/A57B 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00C0 X:0001 Y:0000 P:eNvMxdizc

and

$00/A6EE 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:00C0 X:0001 Y:000C P:eNvMxdizc

Disassembly:
$00/A6DE F3 7E       SBC ($7E,s),y[$00:25CD] A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6E0 C9 01       CMP #$01                A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6E2 10 10       BPL $10    [$A6F4]      A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6E4 BF 00 F3 7E LDA $7EF300,x[$7E:F32F] A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6E8 C9 C0       CMP #$C0                A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6EA 10 08       BPL $08    [$A6F4]      A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6EC A9 C0       LDA #$C0                A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6EE 9F 00 F3 7E STA $7EF300,x[$7E:F32F] A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6F2 80 14       BRA $14    [$A708]      A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6F4 BF 40 F2 7E LDA $7EF240,x[$7E:F26F] A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6F8 C9 02       CMP #$02                A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6FA F0 24       BEQ $24    [$A720]      A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6FC A9 02       LDA #$02                A:0000 X:002F Y:0001 P:envMXdiZc
$00/A6FE 9F 40 F2 7E STA $7EF240,x[$7E:F26F] A:0000 X:002F Y:0001 P:envMXdiZc

------------------

7EF341

$00/A6DC 9F 40 F3 7E STA $7EF340,x[$7E:F341] A:0001 X:0001 Y:000C P:envMxdizC (h movement)
$00/A5EA 9F 40 F3 7E STA $7EF340,x[$7E:F341] A:0001 X:0001 Y:000C P:envMxdizc (fall)
$00/ACC5 9F 40 F3 7E STA $7EF340,x[$7E:F341] A:0000 X:0001 Y:0018 P:envMxdiZC (v movement)


Disassembly:
$00/A6CC F3 7E       SBC ($7E,s),y[$00:25CF] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6CE 38          SEC                     A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6CF ED 00 00    SBC $0000  [$00:0000]   A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6D2 9F 00 F3 7E STA $7EF300,x[$7E:F334] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6D6 BF 40 F3 7E LDA $7EF340,x[$7E:F341] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6DA E9 00       SBC #$00                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6DC 9F 40 F3 7E STA $7EF340,x[$7E:F341] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6E0 C9 01       CMP #$01                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6E2 10 10       BPL $10    [$A6F4]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6E4 BF 00 F3 7E LDA $7EF300,x[$7E:F301] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6E8 C9 C0       CMP #$C0                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6EA 10 08       BPL $08    [$A6F4]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6EC A9 80       LDA #$80                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6EE 9F 00 F3 7E STA $7EF300,x[$7E:F301] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6F2 80 14       BRA $14    [$A708]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6F4 BF 40 F2 7E LDA $7EF240,x[$7E:F274] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6F8 C9 02       CMP #$02                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6FA F0 24       BEQ $24    [$A720]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6FC A9 02       LDA #$02                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A6FE 9F 40 F2 7E STA $7EF240,x[$7E:F274] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A702 22 00 80 01 JSL $018000[$01:8000]   A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A706 80 18       BRA $18    [$A720]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A708 BF 40 F2 7E LDA $7EF240,x[$7E:F274] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A70C C9 02       CMP #$02                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A70E F0 0A       BEQ $0A    [$A71A]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A710 A9 02       LDA #$02                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A712 9F 40 F2 7E STA $7EF240,x[$7E:F274] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A716 22 00 80 01 JSL $018000[$01:8000]   A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A71A BF 80 F8 7E LDA $7EF880,x[$7E:F8B4] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A71E F0 0E       BEQ $0E    [$A72E]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A720 BF 80 F0 7E LDA $7EF080,x[$7E:F0B4] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A724 29 40       AND #$40                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A726 D0 03       BNE $03    [$A72B]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A728 4C DE A7    JMP $A7DE  [$02:A7DE]   A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A72B 4C C5 A8    JMP $A8C5  [$02:A8C5]   A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A72E A9 01       LDA #$01                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A730 9F 80 F2 7E STA $7EF280,x[$7E:F2B4] A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A734 60          RTS                     A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A735 AD 71 00    LDA $0071  [$00:0071]   A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A738 29 03       AND #$03                A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A73A F0 03       BEQ $03    [$A73F]      A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A73C 4C AD A9    JMP $A9AD  [$02:A9AD]   A:0000 X:0034 Y:0001 P:envMXdiZc
$00/A73F AD 25 00    LDA $0025  [$00:0025]   A:0000 X:0034 Y:0001 P:envMXdiZc