don't click here

Some S3K Hex questions

Discussion in 'Engineering & Reverse Engineering' started by Upthorn, Oct 23, 2006.

Thread Status:
Not open for further replies.
  1. Upthorn

    Upthorn

    TAS Tech Member
    239
    0
    0
    Hey, a few guys and myself, who aren't really from the hacking scene, are planning an S3&K hack.

    Mostly it's going to focus on level designs, which, thanks to SonED (or SonED2, depending), shouldn't be a problem.

    However there's one feature we need to add for our ideas to work.
    We need to add monitors to switch between characters, midlevel.

    Obviously, this is a hell of a job for hacking noobs like us to take on, but we're willing to learn.

    However, skimming through the (rather sparse) offering of Sonic 3 & Knuckles hacking guides, I haven't been able to find answers to the following questions.
    1. What pointer tables would to be invalidated by adding a monitor item type, and where are they?
    2. Where in the rom are the monitor item routines stored?
    3. Is the last checkpoint you hit stored by Checkpoint #, or by X/Y location?
    4. What RAM addresses hold the checkpoint values?
    5. What does a write to RAM (@ address) instruction look like in hex? Edit: I realized that I can disassemble/reassemble myself as long as I know what offsets I'm looking for. *facepalm*
    6. Where in the rom is the routine that gets called when you restart the level (from a checkpoint or otherwise)?
    7. Can the checkpoint restart routines be called without decrementing the life counter as a result?
    Also, we would like to modify the debug monitor somewhat, and answers to the following questions would help us with that
    1. Where in the rom is the routine for the Debug monitor stored?
    2. What does a "jump" instruction look like in hex? Yeah... This is also unnecessary if I'm going to disassemble S3K and reassemble it myself.
    3. Where is the routine which checks for emeralds before calling transformation sequences?
    4. Does this run before, or after, the 50 ring check?
    5. Could it easily be made to kill the player on test failure
    Any answers to any of these questions, or any direction to any guides which could help in any way would be appreciated.
     
  2. Robjoe

    Robjoe

    Member
    This is really over your head. If anything, you should try this in S1 or S2, where you actually have a disassembly to work with. But even so, something like that'd be pretty damn difficult.
     
  3. stormislandgal

    stormislandgal

    It's not a phase! Tech Member
    4,534
    10
    18
    Married life <3
    Hmm.... While I haven't looked deeply into Sonic3K's character handling code, I do know that Sonic, Tails, and Knuckles are entirely seperate objects. This means that in order for this to work, you would have to "create" an object containing your character of choice, then "delete" the one that's already there. However, this would probably lead to MASSIVE errors in the game code.

    Not to mention, you'd need to load the character palettes, art, mappings, and such. In short: I don't think anyone has the balls to try it. =P

    * NOTE: This post is pure speculation that I pulled outta my ass, so anyone with more knowledge on S3K, please correct me.

    1. I don't think any pointer tables would be "invalidated", as, if the monitor types work like the do in S1 and S2, the effect is based on the animation. So if you wanted to add a monitor, you would need to extend the offset table of the monitor animations, add new mappings/art etc.
    2. The monitor item routine data itself... I don't remember where they were. I was messing with them a while ago through hex, but I failed to take down any locations.
    3. The last checkpoint you hit is stored by a checkpoint counter. That is why if you skip ahead through the level, hit a starpost, and then go back to another one, that one is active.
    4. I haven't looked into this one.
    5. Again, I haven't looked. But if this works a bit like Sonic 1 and 2, there are a few locations that are called when you restart the level.
    6. I would assume so, with some minor recoding of the restart routines.

    EDIT: For some of you other questions...

    1. The debug monitor is actually one of the monitor types, but as I said before, I didn't take down any locations, so can't help you there.
    3 and 4. I found this somewhere in the rom. However, when I was haxing, I didn't take note of the locations. And, for your second question: The emerald check happens AFTER the 50 ring check.
    5. I would assume so, but you would have to edit the 'double jump' code to not make it so that Sonic/Tails/Knux would die if they became Super.

    I think that answers all of your questions. I'll say this though: Not much is known about S3K, so you're practically walking into the frontier of hacking. Also, if you plan to disassemble S3K, I hope you have a LOT of free time on your hands, as disassembling something like Sonic 1 would take possible months. Sonic 1 is 512 KB, and S3K is 4096 KB... I could only imagine how much time it would take. =P
     
  4. twix

    twix

    Pending Member
    26
    0
    0
    fuck that, knuckles has different paths in the game so I don't know how you're going to tackle that one, I'd reccomend hacking sonic 2 for your first hack as it is much easier and theres more info on sonic 2, not to mention the disassemblies.
     
  5. C. Shyguy

    C. Shyguy

    Member
    221
    0
    0
    Edit: Wrong topic.
     
  6. SadisticMystic

    SadisticMystic

    a user Member
    163
    0
    16
    I'd like to point out that I envisioned the hack that's being planned here a long time ago, and made a topic at that time. The point of the hack is is to exploit all the oddball mechanics available in the game, to create something that requires near-perfect knowledge of the game mechanics and bugs in order to get through. The S3K engine has far more things to make use of than the older games, so its use is a given.

    I originally designed the game to be Sonic-only, but that would leave out the possibility of having Knuckles- or Tails-specific challenges incorporated into the game. Eventually I hit on the idea of somehow porting the character swap monitor over from Chaotix, and using that so that all three characters could be required at times over the course of a single game.

    This project may be difficult, but since the goal of the hack is to create something really difficult anyway, I don't see anything wrong with that.
     
  7. Upthorn

    Upthorn

    TAS Tech Member
    239
    0
    0
    The idea behind the hack is to make sort of a puzzle game using the S3K engine. The way to advance won't be obvious, and will rely on specific character abilitites.
    Problem is, if we make a puzzle designed for Sonic, Tails will just be able to fly over the damn thing, and Knuckles might not be able to jump high enough to get through at all. But if we restrict the player to just one character, we cut down greatly on the amount of variety we can use.
    Hence mid-level character swap.
    For the same reason, using Sonic 2 doesn't really work, unless we want to port Tails w/ flight, and shield actions, for our first hack. Seems like that would be even more work than hacking S3K.

    This is why I asked where the code is that runs when the player restarts a level. (But not during act changes).
    Fooling around with pro action replay codes in Gens, I can change the player-character number on the fly. Interestingly enough, changes to the player number take effect whenever the "restart level from checkpoint" code is called. Whether it's from death, or from entering and leaving a bonus stage.
    As a dirty work around, we could make the monitor set a checkpoint, change the character number, restart from checkpoint, and then clear the checkpoint.
    More ideally, though, we could copy the code that runs when the level restarts (As it already does everything we need), and remove the "lock player control", "show title card", "reset time", "reset position" and "unlock player control" parts, then use what remains as the bulk of the monitor code.

    1. I read somewhere that the monitor data format changed between Sonic 2 and Sonic 3, so that might no longer be the case. The question about pointer tables was kind of assuming that there's no buffer after the end of the monitor data before the next data block begins, or that there's not enough of a buffer to add all the routines. Hence causing movement of the next block of data (and possibly any block after that...)
    2. How did you find it originally? I'd look for this tuff myself, but I really don't know how or where to start.
    3. I know that this behavior is true for Sonic 2. I'm not sure if it's the same for sonic 3 and later.
    4. I can probably find it myself, but I thought I'd see if someone already knew.
    5. Well, if I knew the common techniques to find instruction offsets, I'd search for this myself. But the only place I can think to start would be modifying each byte in hex, one by one, and testing what changes. In a 4 mb file, that could take more than a year.
    6. Yeah, it occured to me that this is exactly what happens when you exit a bonus stage.

    EDIT: For some of you other questions...

    1. I know the debug monitor is one of the monitor types. And, presumably, if I new where monitor data/code was stored, I could find this just by its object sub-type. But I don't know its sub-type.
    3. Yeah, I'll have to look for this myself. But any tips on how to do so would be appreciated.
    4. Awesome. That means, we can have the monitor call the transformation routine, and only give say, 2 rings.
    5. Actually, probably the better way would be to make it do damage if the check fails. There's going to be a minimum of rings in this, so if you're hitting one of the debug monitors, you'll probably just die.

    Well, I was planning on using one of those programs that automatically disassembles roms. Rather than doing it by hand, so it shouldn't take months, or even hours. Documenting all the code, though, probably would.
     
  8. Tweaker

    Tweaker

    Banned
    12,387
    2
    0
    A program can't differenciate code and data when disassembling something like a Megadrive program, so you'll have no choice BUT to do it manually.
     
  9. Upthorn

    Upthorn

    TAS Tech Member
    239
    0
    0
    It doesn't matter if the program can differentiate code and data if I already know the offsets of the code I want to be changing. After all, shouldn't data that's been disassembled, once reassembled, be an exact copy of the data that wasn't disassembled in the first place?
    And I'd expect the data would stand out pretty quickly as the disassembled sections that have a jump or a return instruction right in front of them.

    I think the only thing I'd need to worry about with data after reassembling is if I screwed up the offsets, invalidating the pointers.
    And that should be fixed pretty easily (if tediously) by manually adjusting the affected pointers.
     
  10. stormislandgal

    stormislandgal

    It's not a phase! Tech Member
    4,534
    10
    18
    Married life <3
    I just searched for the Machine code that adds 10 to the ring ammount variable. I don't remember where the ring variable in RAM is in Sonic 3K though, although it might be the same as Sonic 1/2, FFFFFE20.

    I congradulate you for your dedication to this, but I'd recommend you try this in Sonic 2 to make sure this actually works. If it works, then you could try custom coding this into S3K through machine code.
     
  11. Upthorn

    Upthorn

    TAS Tech Member
    239
    0
    0
    There seems to be some weird stuff going on here. Using Gens Tracer and logging what happens when I hit a ring monitor, there's at least two different memory locations addressed in the procedure.
    One of them is, indeed, $FFFE20, which holds the ring counter. But #$0A isn't added directly to that. #$0A Is added to $FFFEC8 (Note: My computer doesn't have internet right now, and I don't have my notes in front of me so this address may be somewhat incorrect). I think that $FFFEC8 is the place that's checked to determine if the 1UP routine needs to be called, as the Debug monitors don't seem to be calling it.
    Anyway, I cant seem to figure out where the addition to $FFFEC8 makes its way back to $FFFE20. But perhaps if I search for code that increments $FFFE20 by #$0032, I can track down the debug monitor directly.


    That makes sense, and is certainly a more useful suggestion than (to paraphrase) 'lol S3K is hard, do s2 insted.' However, Sonic 2's character loading routines might not work the same way as S3K's, so it may not be entirely feasible.
    Finding that out, though, and testing on a ROM that won't need room cleared out first is definitely a good idea. I'll do that..
     
  12. nineko

    nineko

    I am the Holy Cat Tech Member
    6,298
    475
    63
    italy
    mmmh, interesting. also, don't forget that the debug box ignores the 999 rings limit, and if you hit a 10 ring monitor when you have more than 999 rings, they will be set back to 999. this doesn't happen if you grab a single ring: the counter won't go up, but won't go down. I think you are right, the 10 ring monitor is handled in a different way.
     
  13. Upthorn

    Upthorn

    TAS Tech Member
    239
    0
    0
    Okay, here are my findings so far:
    Mostly RAM values, because genstrace's "frame advance" mode advances at least 8 frames at a time. Not very helpful for finding precise ROM offsets for the start of a subroutine.

    Is the last checkpoint you hit stored by Checkpoint #, or by X/Y location?
    Both.
    What RAM addresses hold the checkpoint values?
    $FFFE2A (1 byte) Number of last checkpoint hit in current act
    $FFFE2B (1 byte) Number of last checkpoint hit.
    $FFFE2C (1 byte) Number of Zone last checkpoint was hit in. (Is reset when level select is used)
    Zone numbers:
    • 0: Angel Island
    • 1: Hydrocity
    • 2: Marble Garden
    • 3: Carnival Night
    • 4: Flying Battery
    • 5: Ice Cap
    • 6: Launch Base
    • 7: Mushroom Hill
    • 8: Sandopolis
    • 9: Lava Reef
    • 10: Sky Sanctuary
    • 11: Death Egg
    • 12: The Doomsday
    • 22: Hidden Palace
    • 23: Final Boss
    $FFFE2D (1 byte) Number of act last checkpoint was hit in. (Starts at 0) (Is set properly when level select is used)
    $FFFE2E (2 bytes, little Endian) X Position of restart point. (Set on zone change, level select, checkpoint hit, or first death in Act 2)
    $FFFE30 (2 bytes, little Endian) Y Position of restart point. (Set on zone change, level select, checkpoint hit, or first death in Act 2)
    Can the checkpoint restart routines be called without decrementing the life counter as a result?
    Yes. But it might be easier to use the code called on return from Special Stage.
    ($FFFE4C: Special Stage Return X
    $FFFE4E: Special Stage Return Y)
    [*]Does [the Emerald check] run before, or after, the 50 ring check?
    Before. But the debug monitor bypasses both. Still, this only complicates matters mildly.
    [*]Could it easily be made to kill the player on test failure
    Probably, just add a branch and a jump.

    Emerald related RAM Values
    $FFFFB0 Chaos Emerald Count (byte)
    $FFFFB1 Super Emerald Count (byte)
    $FFFFB2 Green (1st) Emerald Flags (01b = collected, 10b = super emerald available) (bitwise)
    $FFFFB3 Orange (2nd) Emerald Flags (01b = collected, 10b = super emerald available) (bitwise)
    $FFFFB4 Purple (3rd) Emerald Flags (01b = collected, 10b = super emerald available) (bitwise)
    $FFFFB5 Blue (4th) Emerald Flags (01b = collected, 10b = super emerald available) (bitwise)
    $FFFFB6 Grey (5th) Emerald Flags (01b = collected, 10b = super emerald available) (bitwise)
    $FFFFB7 Red (6th) Emerald Flags (01b = collected, 10b = super emerald available) (bitwise)
    $FFFFB8 SkyBlue(7th) Emerald Flags (01b = collected, 10b = super emerald available) (bitwise)
    $FFFFB9 Gold (8th) Emerald Flags (01b = collected, 10b = super emerald available) (bitwise)
    $FFFFBA Emerald Check modifier (0 = Check Chaos Emerald count, FF = Check Super Emerald count) (byte)
    $FFFFBB Unknown flag (starts at 0, is set to 1 when first Super Emerald stage is entered. Possibly sets whether giant rings are "super" or not?)

    Ring related RAM Values
    $FFFE20 Ring count (word)
    $FFFEC8 Capped Ring count . (Ring count is copied here when a ring, or ring monitor is collected. It is then incremented by the appropriate value and then capped off at 999 before being copied back to $FFFE20)
     
  14. Hayate

    Hayate

    Tech Member
    You probably know this already, but the game needs two stored values to know whether to award an extra life or not: the amount of rings you currently have, and the amount of rings you used to have. If there is only one value, the game won't know whether you just got 100 rings and deserve the extra life, or whether you already had 100 rings and already got the extra life. The code for actually checking the "current" ring count, capping it and copying it to the "previous" ring count is probably somewhere completely different to the code to increment the "current" ring count.

    Still, I can't figure out why the programmers decided not to make the debug monitor increase the "current" ring count. It should only make a byte of difference.
     
  15. Mr. Fox

    Mr. Fox

    Member
    559
    9
    18
    I've found a lot of RAM values in S3K. Here.
     
Thread Status:
Not open for further replies.