Discussion in 'Engineering & Reverse Engineering' started by Tweaker, May 29, 2008.

1. ### AppleSauce

It's now illegal to use your meme! Member
44
2
8
K, so I want to add a teleport function to Sonic 1 (think void wispon), by hitting A on the controller. I already know how to utilise button presses, but I don't know how to move the sprite in the direction the dpad is being pushed. Could anyone point me in the right direction and tell me what to do?

2. ### MarkeyJester

Nothing's Impossible Resident Jester
2,164
334
63
Japan
I don't know much about wisps, having never played forces, but I assume based on a video I've watched, it's more or less a jump dash with different directions, so I'll assume it'd be speed based rather than positional (again, never played it so I cannot guarantee you the effect you desire entirely). You said you already know how to handle button presses, so I'll leave that out.

Sonic's direction/speed is controlled via two axis, and X (horizontal) and a Y (vertical), to move diagonally requires a combination of X and Y together. Once more, I don't know what disassembly you're using so I don't know what equates you have (if any) so I'll use the raw RAM addresses for these examples.

To move Sonic in any direction you have to move positive or negative numbers to his X and Y speeds, here is an example:
Code (Text):
1.        move.w   #\$800,\$10(a0)

The \$10(a0) will be Sonic's horizontal speed, and the 800 is what you'll be setting that speed to. This will cause Sonic to move right 8 pixels every frame, the reason it is an extra x100 the size, is the lower two digits are the fractions, so moving \$880 would be moving 8 and a half pixels per frame.

To move Sonic left, you make sure the value is negative:
Code (Text):
1.         move.w  #-\$800,\$10(a0)

Sonic will move left 8 pixels per frame. Y speeds are the same, though it'll be the \$12(a0) you will want to manipulate, for example:
Code (Text):
1.         move.w  #\$800,\$12(a0)

This will cause Sonic to move down 8 pixels per frame. Likewise:
Code (Text):
1.         move.w  #-\$800,\$12(a0)

This will cause Sonic to move up 8 pixels per frame.

Using a combination of the two will allow you to move Sonic diagonally in various ways, for example:
Code (Text):
1.         move.w  #\$0800,\$10(a0)
2.         move.w  #-\$800,\$12(a0)

Here, the first instruction will cause Sonic to move right 8 pixels per frame, then the next instruction processed afterwards will cause Sonic to move up 8 pixels per frame. Sonic will effectively be moving both right and up 8 pixels per frame, and thus will move diagonally up/right.

Keep in mind, these are speed settings, once you've put the values into them, they will remain in there and Sonic will continue moving in that direction until acted upon by an outside force (gravity, collision, etc). Judging by the videos I've seen of the void wisp in action, it looks as though it is boosting Sonic in a particular continuous direction and then stopping him again once he reaches a destination, if you wanna replicate this, I would suggest adding values to his X and Y positions (not speeds) in a controlled manner, probably using inverse trigonometry to ensure a proper 360 speed consistency. But again, I don't know exactly what it does in the game, never played it, it's simply observations, so I won't waste time writing code to do exactly that for you and I get the feeling you generally want to learn how to do it yourself (which I admire =3).

3. ### Childish

Pigs wiggle when they walk Member
241
103
43
Sonic 4 Blast Processed
I have been hacking sonic 2 recently and was wondering what different methods I could use to achieve a pseudo 3D / multiple layered effect to my backgrounds. I think Sonic 3 achieved the effect by swapping tiles into VRAM depending on the camera position but I have no idea how to do that. Also does the background need to be repetitive vertically for that to work?

4. ### MarkeyJester

Nothing's Impossible Resident Jester
2,164
334
63
Japan
You are 100% spot on with your understanding of how it works in a general sense.

The problem is, to explain it we'd have to explain how to transfer graphics in "general", either manually or by DMA. In fact, I am so certain I have already explained in this very thread at some point in the past 12 years, I really don't want to explain it again =(

I would advise looking at the manual transfers of Sonic 1/2 which animate tiles for the level, like the flowers or waterfalls of GHZ in Sonic 1 for instance for an idea on manual transfer, or perhaps later games for more DMA transfer related ideas. But really, it's just an annoyance to explain at this point, you end up having to explain how the machine works in order to explain how something simply as tile swapping works in order to create the illusion of depth or effects (I mean, like, more power to someone who wants to reiterate the information yet again, definitely, if it helps, but don't be surprised if your information gets buried years later in this thread).

I would suggest looking into the hardware itself, you seem like a very clever man to me, so I have no doubts you'll wanna look into the hardware side of things and maybe even write your own routines for transferring new tiles to create the illusion of depth. I would strongly suggest looking at Megadrive.org and railgun.org (iirc previously known as squee) for more information. Perhaps I would also suggest looking at the art cycling/rendering/loading routines of Sonic 1, 2, and onwards for more clarity. But really, this requires knowing how to setup the VDP, set the VDP write/read mode and address, and so on, it's a huge amount of information (don't be discouraged, it's actually really simply to understand, just really difficult to explain without creating huge walls of text which look overwhelming).

My sensor apologies for not providing you with exact information and for being somewhat vague, but I've explained this so many times it feels like I'm on some sort of constant repeat. But judging by your post, I think you already know what you need to know, you don't seem like a stupid person to me, I have no doubts in my mind you'll figure it out on your own =3

5. ### Devon

1,040
1,052
93
If you want to see a specific example of Sonic 3 doing it in action alongside that, may I suggest you examine something like AnimateTiles_HCZ2 in the Sonic 3K disassembly. Sonic 2 also does something similar for Hill Top Zone, but the way it sets up its tileset is a bit on the weird side.

6. ### Dulappy

koronesuki Member
48
7
8
Greece
sonic
So this one is a really basic and slightly dumb one, but which way of loading DPLCs is faster (even if it’s so slight that it doesn’t even matter), Sonic 1 (with DMA Queue) or Sonic 2/S3K? I was looking at some code today and saw that S1 DPLCs are processed using byte-sized data, while the S2/S3K DPLCs are processed using word-sized data.

7. ### MarkeyJester

Nothing's Impossible Resident Jester
2,164
334
63
Japan
Bytes and words usually take about the same CPU time, the reason is because of the 16-bit BUS, specifically, and 8-bit byte is read through 16-bit but with the 8-bits ignored.

The word version would often be more efficient because it takes the same CPU time, but more data is read. Basically, this is a size vs speed situation, whereby S2/S3K sacrifice ROM space in exchange for CPU speed. So to answer your question, the latter is usually quicker, but it's all circumstantial at the end of the day. Faster is not always better.

8. ### Devon

1,040
1,052
93
The DPLC formats between the games aren't really all that much different. The only real difference is that Sonic 1 uses a byte for the entry count while Sonic 2/3K use a word. All entry data are made up of words.

Because in Sonic 1 it's a byte, that means that they couldn't easily read the DPLC data word by word due to the possibility of them starting at an odd address, so they split up the word read into 2 byte reads. In Sonic 2 and 3K, it's pretty much guaranteed to be aligned on an even address, so they went ahead and did the straight word reading.

Sonic 1:
Code (Text):
1.        moveq    #0,d5         ; Get number of DPLC entries
2.        move.b    (a2)+,d5
3.        ...
4.        move.b    (a2)+,d1     ; Read DPLC data
5.        lsl.w    #8,d1
6.        move.b    (a2)+,d1

Sonic 2/3K:
Code (Text):
1.        move.w    (a2)+,d5       ; Get number of DPLC entries
2.        ...
3.        move.w    (a2)+,d1       ; Read DPLC data

At the end of the day, Sonic 2/3K still pad out the DPLC data a bit to make the entry count a word, so it can still take up more ROM space.

Last edited: Jun 14, 2020
9. ### ashthedragon

1,426
68
28
Spain
Hello!
I'm tweaking around Sonic 1 for Master system, trying to change the credits text in hex. I think I have the hang of it, but when I try to run the rom at KEGA Fusion, it just doesnt run. I've used headerreader to ckeck if the checksum is OK, and it is not. But I don't know how to fix the checksum. Found a checksum fixer but doesn't work.

Does anyone have any idea or knows of any checksum fixer for SMS games?

10. ### Wafer

255
75
28
You can use a hex editor to enter the updated checksum, but since the checksum only matters on real hardware (as in, using a homebrew cart) in my experience, I strongly suspect that the checksum is unrelated.

Anyway, here's the SMSPower page that describes the ROM header, when entering the checksum you need to reverse the order of the bytes compared to what the header reader displays, since the Z80 is little-endian.

Also, I recommend using a better emulator, like Emulicious or MEKA.

Since I'm not sure of your skill level, please don't be offended by this observation: you won't be able to ADD new text with a hex editor, you'll only be able to REPLACE the existing text. You need to make sure you're entering exactly as many characters as there were to begin with. If the ROM increases or decreases in size, you'll run into problems.

Last edited: Jun 15, 2020
11. ### AppleSauce

It's now illegal to use your meme! Member
44
2
8
Dang, I wasn't expecting a reply from the Jester himself!
Anyway, I wrote two subroutines in s1.asm, one of them checking if C had been pressed, if so it branches to the next subroutine which executes the teleport function itself. I did put the subroutines in Obj01_MdNormal, but alas there are build errors when I try to build the file. I think it may have something to do with the fact that I used raw RAM addresses instead of equates, and I don't know what the equates are in my disassembly. Speaking of which, I do apologise for not stating which disasm I'm using. I think (the word 'think' is greatly exaggerated) I'm using the HG disassembly.

But let's forget Void Wispon teleportation. Let's say I want something simple like plopping the character object somewhere else (but still being affected by solidity) instead of making them dash. Perhaps with an animation for disappearing, then that animation reversed for reappearing. It sounds a lot simpler (which I assume it is) and I have never heard of inverse trigonometry. It sure does sound complicated though... I'm sure you of all people can help, but like you said I want to learn it myself, so I don't really need a copy-paste.

When I said I knew how to utilise button presses, I meant I read Selbi's guide and I'm not really an expert, so how would I check which way the player is facing (up, down, left, right, etc) in a subroutine?

12. ### Wafer

255
75
28
If you don't even know for sure what disassembly you're using, start from scratch with the GitHub disassembly, and I very much suspect that you need to invest some time in following some how-tos and reading the wiki so that you can understand the code that you're working with.

Anyway, by "facing" I'm guessing you mean the direction pushed on the d-pad, since you mention up and down. You can find the state of the controller in \$F602 and \$F603, the format is SACBRLDU.

If you actually mean whether Sonic is facing left or right, that's offset \$22 in his object status table entry.

Last edited: Jun 15, 2020
13. ### Aerosol

Not here. Moderator
11,117
520
93
Not where I want to be.
Sonic (?): Coming summer of 2055...?
So still trying to get this object code working for Sonic 2.

In the original, Sonic's physics are turned off by moving \$81 to \$F7C8, which the wiki states is a flag to ignore all player control. The same flag in Sonic 2 is \$F7CC, but when Sonic touches the object, he enters his pushing animation and just drops to the floor.

I managed to hit the object at the right angle such that I was able to observe Sonic slowly sliding on the ground, so I'm guessing that the object's code is still trying to move Sonic. But I guess writing \$81 there doesn't have the same effect that it does in Sonic 1.

Here's a pastebin: https://pastebin.com/kt8VZVrz

Not sure how close I got to fixing it, but I'm out of ideas. I have the code move that value to \$F7C8 so that I could still move Sonic around after it failed to align him, and go off screen and try again. Sonic still slides veeeery slowly on the ground if I stand still though, so it's the same problem either way.

14. ### Devon

1,040
1,052
93
Nope, in Sonic 1 and 2, that flag locks your controls. In Sonic 2, \$F7C8 was changed to be an SST for Sonic (obj_control(aN)/\$2A(aN)), which is what disables the movement and stuff.

Sonic 1:
Code (Text):
1.
2.         btst    #0,(\$FFFFF7C8).w ; are controls    locked?
3.         bne.s    loc_12C7E    ; if yes, branch
4.         moveq    #0,d0
5.         move.b    \$22(a0),d0
6.         andi.w    #6,d0
7.         move.w    Obj01_Modes(pc,d0.w),d1
8.         jsr    Obj01_Modes(pc,d1.w)
9.
10. loc_12C7E:

Sonic 2:
Code (Text):
1.
2.     btst    #0,obj_control(a0)    ; is Sonic interacting with another object that holds him in place or controls his movement somehow?
3.     bne.s    +            ; if yes, branch to skip Sonic's control
4.     moveq    #0,d0
5.     move.b    status(a0),d0
6.     andi.w    #6,d0    ; %0000 %0110
7.     move.w    Obj01_Modes(pc,d0.w),d1
8.     jsr    Obj01_Modes(pc,d1.w)    ; run Sonic's movement control code
9. +

15. ### Aerosol

Not here. Moderator
11,117
520
93
Not where I want to be.
Sonic (?): Coming summer of 2055...?
Then why does it work for Sonic 1?

Code (Text):
1. move.b  #\$81,(\$FFFFF7C8).w
Is exactly how it's written in the original object code Markey wrote some 7 pages ago. I've got the object working in Sonic 1 without any trouble at all.

16. ### Devon

1,040
1,052
93
\$F7CC is a different flag altogether for disabling controller input for the player, and also existed in Sonic 1. It wasn't changed in Sonic 2. \$F7C8 is what handles stopping the player from physically moving and interacting with objects, which is what was changed into that SST.

17. ### Aerosol

Not here. Moderator
11,117
520
93
Not where I want to be.
Sonic (?): Coming summer of 2055...?
Oh ok, so \$F7C8 in Sonic 1 is equivalent to \$B02A in Sonic 2, at least for this purpose?

EDIT: I keep doing this today. I accidentally over some words....the answer to my question is yes. Cheers!

Last edited: Jun 15, 2020
18. ### Devon

1,040
1,052
93
It is for all purposes related to that flag in Sonic 2.

19. ### Aerosol

Not here. Moderator
11,117
520
93
Not where I want to be.
Sonic (?): Coming summer of 2055...?
I'm happy to report that I've got the object working as God MarkeyJester intended in Sonic 2. Yay!

One small weird thing though and if this'll take forever to explain, don't worry about it. But...

Well unless I comment out the line setting Sonic's animation to rolling, he enters his pushing animation, from "cannon capture" to "firing". My best guess is that Sonic 2 changed a few things and his animations are controlled via setting his status bits rather than setting his animation directly but that feels like an incomplete understanding.

For reference, I'll share the complete, working object code I have now: https://pastebin.com/iwVaVVtH

20. ### Devon

1,040
1,052
93
You forgot to put a "#" before "AniIDSonAni_Roll". Without it, it thinks AniIDSonAni_Roll is an address, and reads the byte at address \$000002 (since AniIDSonAni_Roll = 2), in which that byte is \$FE. Here's how it takes that as the "pushing animation":

It takes the ID (\$FE), multiplies it by 2 to get the offset within the animation pointer table for Sonic to grab the pointer to the current animation. In our case, it ends up reading "\$FFFF", which to the game means that the animation is located at "SonicAniData - 1" in the ROM. It then tries to grab the animation speed value, which so happens to be \$94 in stock Sonic 2. Any animation speed > \$7F is parsed as a special animation flag, so then it goes into SAnim_WalkRun. It checks if that flag was \$FF. Since it's not, it goes into SAnim_Roll and checks if it's \$FE, then it finally reaches SAnim_Push, where it performs no additional flag ID checks and defaults to there, and hence, runs the pushing animation.

Here's also something I noticed. Your collision ID for your object is \$4F, right? In Sonic 1, TouchResponse handles it like so:
Code (Text):
1. ; touch    response is \$40-\$7F
2.
3.         move.b    \$20(a1),d0
4.         andi.b    #\$3F,d0
5.         cmpi.b    #6,d0        ; is touch response \$46    ?
6.         beq.s    Touch_Monitor    ; if yes, branch
7.         cmpi.w    #\$5A,\$30(a0)
8.         bcc.w    locret_1AEF2

In Sonic 2, it's this:
Code (Text):
1.     ; touch response is \$40-\$7F
2.     move.b    collision_flags(a1),d0
3.     andi.b    #\$3F,d0
4.     cmpi.b    #6,d0            ; is touch response \$46 ?
5.     beq.s    Touch_Monitor        ; if yes, branch
6.     move.w    (MainCharacter+invulnerable_time).w,d0
7.     tst.w    (Two_player_mode).w
8.     beq.s    +
9.     move.w    invulnerable_time(a0),d0
10. +
11.     cmpi.w    #90,d0
12.     bhs.w    +
13.     move.b    #4,routine(a1)    ; set the object's routine counter
14.     move.w    a0,parent(a1)

Note the addition of "move.w a0,parent(a1)". "parent" in Sonic 2 = \$3E, and in your object, \$3E is used to saving it's original Y position. You should make the following changes to the above code: change the register in the lines where it grabs "invulnerable_time" to d1, and check if d1 is 90 instead of d0, and then check if d0 = \$F before the "parent" line and skip over if it is \$F. You may also want to skip the "90" check, too, since that was meant for making Sonic not be able to collect rings if he just got hurt. Just make sure it still sets the routine to 4.

Last edited: Jun 15, 2020