General knowledge and information thread

Discussion in 'Discussion & Q&A' started by SpirituInsanum, Sep 8, 2010.

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

    SpirituInsanum Well-Known Member Member

    Joined:
    Feb 11, 2010
    Messages:
    642
    Introduction





    This topic is meant to be used as a small database for details about Sonic games, design and assembly that may be hard to notice without extended and time consuming testing. The purpose is not to provide lengthy tutorials, but only to point at facts and issues and give directions about how to correct problems when necessary. It is essentially about debugging and optimizing, and collecting facts and statistics about the level design in the official games.





    You can post your informations for all Sonic games so they will be included in the main list. Only facts and data please, opinions do not belong here.






    Please PM me for comments, suggestions and feedbacks, they are welcome but could make the thread harder to read.



    Contents:


    Part 1 - Level Design


    1.1 Informations related to level design in the games


    1.2 Specific problems after changes in gameplay and levels


    1.2.1 Sonic 1


    1.2.1.1 Green Hill zone


    1.2.1.2 Marble zone


    1.2.1.3 Labyrinth zone


    1.2.1.5 Star Light zone


    1.2.1.6 Scrap Brain zone


    1.2.1.7 Special Stage


    1.2.2 Sonic 2


    1.2.2.2 Chemical Plant zone


    PART 2 - General problems in game


    2.1 Global


    2.2 Sonic 1


    PART 3 - General ASM informations


    3.1 Some vocabulary


    3.2 Assembly general fixes


    3.3 Assembly hints and tips

    ----PART 1----


    Level design






    This section contains informations related to gameplay elements pertaining to the design of the levels.

    ---1.1 Informations related to level design in the games---





    This subsection contains data and facts about the content of levels in Sonic games.


    Loops: Although loops are extremely popular, most of them are concentrated in a few levels in the main four megadrive/mega cd games. Not counting tubes:


    - there are 18 loops in Sonic 1 (GHz:3, SLz:15 )


    - there are 50 loops in Sonic 2 (EHz:9, CPz:22, ARz:7, CNz:7, HTz:5)


    - there are 20 loops in Sonic CD (PP:6, SS: 14)


    - there are 125 loops in Sonic 3 & Knuckles (AIz: 9, Hz: 21, MGz: 7, ICz: 33 (all in act 2), MHz: 31, FBz: 6, Sz: 18)


    Water: Only 10 zones out of 39 have underwater areas through the main four megadrive/mega cd games.


    - there are two zones with underwater areas in Sonic 1 (Lz: 3 acts, SBz: 1 act)


    - there are two zones with underwater areas in Sonic 2 (CPz, ARz)


    - there is one zone with underwater areas in Sonic CD (TT)


    - there are 5 zones with underwater areas in Sonic 3 & Knuckles (all in Sonic 3: AIz, Hz, CNz, ICz, LBz)

    ---1.2 Specific problems after changes in gameplay and levels---





    This subsection lists errors and glitches that can become visible when gameplay elements (like special moves or object placement) are being modified.

    --1.2.1 Sonic 1--





    New loops in levels: Add 80 (in hexadecimal) to the chunk's ID to make the game recognize it as a loop. In SonED2 this is done by pressing space on the chunk.

    -1.2.1.1 Green Hill Zone-




    Open chunks (act 1): There is nothing to block the player from entering the rightmost S tube's chunks from the above on the left.


    Open chunks (act 2): There is nothing to block the player from entering the chunk of the breakable walls on the left and on the right, and nothing either on the right side of the S tube at the end of the level.


    Lost crabmeat (act 2): There is a crabmeat out of the level's dynamic boundary at 10D0-370.


    Open chunks (act 3): There is nothing to block the player from entering the S tube's chunks from the above on the right.

    -1.2.1.2 Marble Zone-




    Shortcut (all acts): There is an upper path that allows the player to skip most of the level.


    Sprite walls and ceilings (all acts): The levels use sprites to fill gaps in the chunks, making actions such as climbing them impossible.


    - Reason: This was probably meant to save chunk space.


    - Solution: The empty chunk slots can be used without conflicting with anything.


    Lava wall (act 2): The lava wall will begin to move if you jump out of the corridor.


    - Reason: The object checks if you went out of its activation area,


    - Solution: Deactivate it when you're out of range vertically but not horizontally.


    Lava geysers: The lava geyser positions are to be modified in the pushable block routine.


    Last monitor in act 3: This monitor doesn't have its "remember state" bit set.

    -1.2.1.3 Labyrinth Zone-




    Current tunnels (or wind tunnels): The positions of those tunnels are set in an array after the tunnel's code in the disassembly.


    Rolling after the signpost at the end of act 2 will crash the game (no reason or solution proposed yet)

    -1.2.1.5 Star Light Zone-




    Death when leaving the screen after being hurt by an Orbinaut (act 1): This could actually happen in any level, but it's only known to be visible after being hurt by an Orbinaut at the top of Star Light zone act 1.


    - reason: the Sonic_HurtStop routine (as named in Hivebrain's disassembly) kills Sonic when he goes out of the screen.

    -1.2.1.6 Scrap Brain Zone-




    Hidden monitors (act 2): It seems these monitors are mistakenly replacing object 71.


    - There is an eggman monitor hidden in the wall at 710-1B0


    - There are 3 monitors (S, super sneakers and invincibility) hidden in the walls at A30-200, AD0-1E0, AD0-270


    - There are 6 invincibility monitors hidden at 4F0-3D0, 590-3D0, 5F0-3D0, 690-3D0, 5F0-4D0 and 690-4D0


    Cut scene (act 2): The chunk above Robotnik is empty and may be visible.

    -1.2.1.7 Special Stage-




    Goal blocks: The goal blocks won't be activated if Sonic pushes on them while standing on a wall. They will be activated only when Sonic is either falling (or bouncing) or jumping. (no reason or solution proposed yet)

    --1.2.2 Sonic 2--






    -1.2.2.2 Chemical Plant Zone-




    Warp pipes / spin tubes: A warp pipe won't correctly move the character when he falls in it after being hurt (video). (no reason or solution proposed yet)

    ----PART 2----


    General problems in game






    This section contains informations about issues that are not glitches or bugs but can negatively affect the gameplay.

    -2.1 Global-





    Sprites are flickering: This happens when more than 20 pieces of sprites (pieces as seen in sonmapEd) are on the same scanline (aligned horizontally) in 40 cell mode (regular gameplay), or 16 pieces on the same scanline in 32 cells mode (like Sonic 2's special stage).


    Slowdowns: Most common causes for slowdown are:


    - too many complex objects being processed


    - too many objects using "calcsine" or equivalent subroutines being processed


    - too many sprite pieces in objects on screen


    - creating many objects at the same time


    Incorrect background deformation when respawning at a checkpoint: When restarting at a checkpoint post, the deformation position is slightly incorrect, moving back to the beginning of the level shows the deformation position is out by a few pixels.


    - reason: Sonic's position is recorded as he touches the post, that position may not be the same as his position when he restarts at that post.


    Incorrect first plane when respawning at a checkpoint: A visual glitch (often an horizontal bar at the top of the screen) may appear if the lamppost's base is lower that the top of the ground's collision.

    -2.2 Sonic 1-




    Title screen not scrolling: When you drown and get a game over, the titlescreen won't scroll. This happens both with the original background deformations and rev01 deformations.


    - reason: When Sonic drowns, the game sets a flag (in $FFFFF744) to prevent the screen from scrolling, but that flag is not reset by the time the title screen should begin to scroll.


    - solution: Reset the flag when necessary.


    Landing on solid objects and platforms with a falling animation: If you add a falling animation, it may not reset properly when Sonic lands on a platform or solid object.


    - reason: the routine won't change the animation number immediately, it wasn't necessary in the original game.


    - solution: set the animation to "walk" in the two subroutines related to platforms and solid objects before "jsr Sonic_ResetOnFloor".


    Sprites as walls: Sonic 1 uses sprites to complete walls. Since those sprites don't use the same collision routines as walls, changes related to collisions may not affect them.


    GAME OVER on level end: If you get a "game over" during the "Sonic Got Through" scene, the "game over" text is messed up. If you can pass the level before the game restarts, you play with 0 lives and can't pause the game.

    ----PART 3----


    General ASM informations







    -3.1 Some vocabulary-





    This section explains some of the names and symbols to make assembly easier to read.


    The "d" in d0, d1, d2... d7: This "d" stands for "data register". It holds "immediate data" (numerical values), is 32 bits long and is stored in the cpu's memory, so changing it doesn't affect ram.


    The "a" in a0, a1, a2... a7: This "a" stands for "address register". What is being stored here is an address, and the numbers before it are to be seen as relative addressing. They don't modify the address in the address register.


    /! -(an) is a predecrement and (an)+ is a postincrement of the address, meaning the address in the address register will be changed.


    /! a7 can only use even addresses. Increments and decrements will automatically skip the odd address.


    eg: addi.b #$1C,$18(a0) ; this adds 1C to the value stored 24 (18 in hexadecimal) addresses from the address stored in a0.


    The "a" in adda, cmpa, lea, movea, pea, suba: This "a" stands for "address". The address is what is being processed here, not the data it contains.


    The "i" in addi, andi, cmpi, eori, ori, subi: This "i" stands for "immediate data", it means the first term (often an hexadecimal number) won't be an address but a number standing for its own value.


    eg: andi.b #$18,d0 ; this compares the hexadecimal value 18 with d0


    The "q" in addq, moveq, subq: This "q" stands for "quick". It can only be used for values of 3 bits or less for addq and subq, and 8 bits (one byte) for moveq (note: moveq can only be used on a data register).


    BNE / BEQ: Understanding BNE (Branch if Not Equal) and BEQ (Branch if EQual) only requires to know what those conditional tests do.


    They test the zero bit (Z-bit) of the condition code register. BNE branches when the Z-bit is clear, BEQ branches when the Z-bit is set.


    The Z-bit is set when the result of the operation equals zero.


    examples:




    cmpi.b #5, d0 ; subtracts 5 from d0 but doesn't save the result. It only sets the Condition Code Register.


    ; If d0 equals 5, the Z-bit is set (so it will "Branch if EQual").


    btst #2, d0 ; tests the 3rd bit in d0, if the bit is 0, it sets the Z-bit (so it will "Branch if EQual"),


    ; otherwise Z is clear (and will "Branch if Not Equal").


    tst.b d0 ; tests all bits in d0, if they're all 0, it sets the Z-bit, if one of them is set, it clears the Z-bit.



    -3.2 Assembly general fixes-





    This section is meant to provide simple solutions and explanations to common asm problems.





    "Out of range" error: You changed something in your disassembly (some code, art, anything), and receive "out of range" errors. The line of the error should be given in the error message.


    - reason: This error happens when an address is further than the branch operand can handle. When the error happens on BRA (BRAnch) or BSR (Branch to Sub Routine), check the size written after it (if nothing is written, consider it's a .w):


    .s can branch 127 bytes before or after itself,


    .w can branch 32767 bytes before or after itself.

    - solution: Increase the range of the branch: if it was a .s, try with a .w. But if it was a .w, you need to use a branching operand of higher level:


    BRA.w has to be replaced with JMP (Jump)

    BSR.w has to be replaced with JSR (Jump to Sub Routine)

    - to make it short:


    BRA.s < BRA.w < JMP

    BSR.s < BSR.w < JSR

    - note: While BRA and BSR are using relative addressing (you can read the value given after them, a "label", as a distance), JMP and JSR are using absolute addressing (the data following them is the "effective address"). This is why they aren't really equivalent.


    - For other cases, check this thread: http://sonicresearch...p?showtopic=857


    Garbled graphics after some changes and new additions: If you add some binary data or arrays to your asm, some graphics that were fine before may suddenly look wrong.


    - reason: the addresses for graphic data have to be even.


    - solution: add an "even" after "incbin" lines and arrays.

    --3.3 Assembly hints and tips--





    This section contains some basic asm tricks.


    Loading palettes:


    - PalLoad1 is used to load a palette to make it fade, otherwise it will not work.


    example:



    moveq #2,d0 ; load the second palette in the palette list.
    jsr PalLoad1


    jsr Pal_FadeTo



    - PalLoad2 is used to load palettes and apply them immediately. This one is not to be used if the palette has to fade.


    example:



    moveq #2,d0 ; load the second palette in the palette list.
    jsr PalLoad2



    Set and test several flags at the same address: You don't have to use a whole byte for a flag of 1 bit. The functions bchg, bclr, bset, andi and btst can save some RAM.


    examples:



    bset #5,($FFFFFF90).w ; sets the 6th bit at address FFFFFF90
    bchg #3,($FFFFFF90).w ; changes the 4th bit at address FFFFFF90, into a 0 if it was a 1 and vice versa


    andi.b #$28,($FFFFFF90).w ; resets all but 4th and 6th bits in FFFFFF90 ($28=0010 1000 in binary)



    Test multiple conditions at once with "or": When you're adding conditions in an existing routine, it may be easier to use "or" to test two bits rather than creating new branches.


    examples:



    ; (in this example, only the first bit is used in FFFFFF90 and FFFFFF92)
    move.b ($FFFFFF90).w,d0 ; load the first flag


    or.b ($FFFFFF92).w,d0 ; set the flag in d0 if either one of the flags in FFFFFF90 or FFFFFF92 is set



    Using d7: If you use the data register d7, the game will probably go wrong or crash.


    - reason: d7 is being used by the ObjectsLoad subroutine and stores the entry number of the next object to be processed. d7 is multiplied by 40 (in hex) and added to FFFFD000, which gives the address of the object in memory. The value at that address is used to determine which object should be processed, and the data after it is used by the program. If that data is not compatible with the object's program (especially the routine counter), the game will crash.


    - example of a solution:




    move.w d7,-(sp) ; ++ save d7 state into the stack


    ; your code involving a new d7 here


    ; ...


    ; ...


    move.w (sp)+,d7 ; ++ load saved d7 state



    See this post for more details.
     
    Last edited by a moderator: Dec 3, 2011
    Matt likes this.
  2. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    Rolling in Sonic 1 LZ at the end crashes the game.


    In SonED2, if you're adding loops, press space on a new loop in Sonic 1. For Sonic 2, use a path swapper.


    PS: Can we use this like the other knowledge thread on retro? :3
     
    Last edited by a moderator: Sep 8, 2010
  3. MarkeyJester

    MarkeyJester ♡ ! Member

    Joined:
    Jun 27, 2009
    Messages:
    2,867
    When passing a checkpoint post, dieing and then restarting at that post, the deformation position is slightly incorrect, moving back to the beginning of the level you'll notice the deformation position is out by a few pixels.


    This is caused because Sonic's position as he touches the post, may not be the same as his position when he restarts at that post (i.e. if you're moving passed the post at a fast enough speed, the recorded position will be not be exact identical to the position of the post).
     
  4. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    ">" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344">
     
  5. Hanoch

    Hanoch Well-Known Member Member

    Joined:
    Aug 3, 2008
    Messages:
    312
    Location:
    Israel
    How to use features in a sonic hack, without making it a piece of crap:


    When making a guide, people simply use it like it will make thier hack the best thing ever, except it wont. Take for example the bubble shield in S&K. I haven't found a bubble shield anywhere in that game, aside from the glowing orbs bonus stage. And even if there is, it serves no purpose for knuckles. Only giving sonic the bounce move.


    Now lets say someone adds the goggle monitor to their hack. It could be used as a proof of concept hack, sure but since selbi already made a guide there's no point in doing that. Nowdays people just take a spindash, goggles monitors and s3k sprites, horrible palettes and they replace the first shield in LZ with goggles and there you go, a hack.


    But the goggles aren't known for what they do, at first I thought it gives infinite air, but then I thought it changed the palette and adds up air. Some people go with the infinite air thing. That's the problem. Goggles aren't needed to finish LZ except for breaking it and making it easier than it used to be (easy mode anyone?).


    Its not that i'm saying the goggles suck, sure they can be good if used correctly. Infinite air can break all water levels, but adding up air that would subtract (like an air tank) is not only reasonable, but much more easier rather than game breaking. With that, people should also change the level layout to make good use of that feature and make it more challenging.


    The above was an example.


    Another thing is, dont only add stuff that makes the game rich of moves. Proof of concepts are really fine unless it has been done before (search the sonic retro forums and also the ssrg forums) a game with only new moves and nothing else new... is just shit. Hell, its 06 thats what it is.


    To sum this up: If you use guides, use them on a vanilla sonic 1 ROM and start editing from there before releasing the ROM. Dont just throw a spindash and a jump dash and barely edited level layouts and shitty palattes, its good as a start but nobody wants to play it.


    If you manage to port a feature urself (i.e insta shield) you could use it, but remember this: can you beat sonic 1/2 without the insta shield? How about instead of making it super easy, make the game harder, and the insta shield as a helping hand.


    On the second hand, if you make a move nobody saw coming, test it. A lot. Test it in every zone, on every boss (if its an air move) on every (breakable) object, check if it works on loops, check if it crashes the game upon breaking walls. Check if it works!


    Something like that, but then again dont add it if you didn't change anything in the game or else you will break everything!
     
  6. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    I've found loads in the game. you can find one right near the start of Mushroom Hill.

    Level layout edits? object edits?


    Back on topic: Goals dont affect you unless you're in the air.
     
    Last edited by a moderator: Sep 9, 2010
  7. Hanoch

    Hanoch Well-Known Member Member

    Joined:
    Aug 3, 2008
    Messages:
    312
    Location:
    Israel
    What's a goal? Do you mean the signpost in sonic1/2? Because the signpost affect you EVEN if you're in the air.


    And I mean enemy editing. A motobug can be killed by simply jumping on it or rolling into it, with the insta shield its just gives you an area range boost to kill it "faster". Besides a slz orbinaut, the insta shield serves no purpose in sonic 1.


    In sonic 2 there's: Shellcracker, fire orbinaut, the snakes in mcz, mz boss, cpz spiders and many more. So yea, in sonic 2 it will make your life easier, but people could still beat it without the instashield back then.


    Infact, someone should attempt doing a full s3k run without the insta shield.
     
  8. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    I meant special stage.


    The insta shield does serve a purpose: Marble zone has fire for the fire shield, sbz has electric traps for the electric shield and lz has water for the water shield. Loads of uses.
     
  9. Hanoch

    Hanoch Well-Known Member Member

    Joined:
    Aug 3, 2008
    Messages:
    312
    Location:
    Israel
    Insta shield is the white spark around sonic when you double jump without a shield.
     
  10. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    I thought it was the elemental shields! I've been misled! [​IMG]
     
  11. SpirituInsanum

    SpirituInsanum Well-Known Member Member

    Joined:
    Feb 11, 2010
    Messages:
    642
    Thanks to the contributors.


    Added a section about BNE and BEQ because it seems they're often misleading.
     
  12. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    Something I've noticed: When you drown and get a game over, the titlescreen won't scroll.
     
  13. vladikcomper

    vladikcomper Well-Known Member Member

    Joined:
    Dec 2, 2009
    Messages:
    415
    This can be a nice addition to ASM tips section:


    If you program objects, never use d7 register in their code. If you do so, it can end up with incredible glitches.


    Reason: It's being used in ObjectsLoad subroutine. Each object's code is called from there, while d7 is used as cycle counter. If you touch d7, wrong amount objects can be loaded, or wrong code will be executed, which crashes the game.


    This applies to both Sonic 1 and Sonic 2. I haven't checked S3 yet.


    If you wish, you can fix this, so you can use d7 freely. Just add few lines in ObjectsLoad code:



    ObjectsLoad: ; XREF: TitleScreen; et al
    lea ($FFFFD000).w,a0 ; set address for object RAM


    moveq #$7F,d7


    moveq #0,d0


    cmpi.b #6,($FFFFD024).w ; is Sonic dying?


    bcc.s loc_D362 ; if so, branch


    loc_D348:


    move.b (a0),d0 ; load object number from RAM


    beq.s loc_D358 ; if obj's empty, skip


    add.w d0,d0


    add.w d0,d0


    move.w d7,-(sp) ; ++ save d7 state into the stack


    movea.l Obj_Index-4(pc,d0.w),a1


    jsr (a1) ; run the object's code


    move.w (sp)+,d7 ; ++ load saved d7 state


    moveq #0,d0


    loc_D358:


    lea $40(a0),a0 ; next object


    dbf d7,loc_D348


    rts
     
    Last edited by a moderator: Mar 27, 2011
  14. FireRat

    FireRat Do Not Interact With This User, Anywhere!!! Exiled

    Joined:
    Oct 31, 2009
    Messages:
    535
    as I see, you recenctly tried to do an object with d7, right? XD


    I'm also writing another tip and Ill edit the post, wait...
     
    Last edited by a moderator: Mar 27, 2011
  15. vladikcomper

    vladikcomper Well-Known Member Member

    Joined:
    Dec 2, 2009
    Messages:
    415
    Yes, my object was very complicated, so one of its routines needed too many registers for calculations. I touched d7 and some objects started disappearing after that (their code wasn't called). Disappearing objects happen to be the ones controlled by my routine, which completely mislead me. I had a hard time figuring out what's wrong.


    I've tested my code in my tool, M68K SANDBOX, and the code turned out to be perfectly working. Only after that I found out that the problem's somewhere else and finally remembered about ObjectsLoad. =)
     
  16. MarkeyJester

    MarkeyJester ♡ ! Member

    Joined:
    Jun 27, 2009
    Messages:
    2,867
    Cool and useful stuff, once again.


    My only concern is that this is an extra two commands that have to be processed (10 (HEX) cycles in total) per object, wouldn't it make sense to just store d7 to the stack and reload it in the object routines you need it for, rather than all objects?


    Not that I'm questioning your methods, infact this is a clever and easy way to do it and I'm glad you've shared it with us =)
     
  17. SpirituInsanum

    SpirituInsanum Well-Known Member Member

    Joined:
    Feb 11, 2010
    Messages:
    642
    That's almost what I would do as well, though rather than using d7, I would probably save another data register I don't need immediately, or I would save some data in the object's scratch ram.


    @Vladikcomper: I'll probably limit the tip to your description/explanation and a more general solution, like:




    move.w d7,-(sp) ; ++ save d7 state into the stack


    ; your code involving a new d7 here


    ; ...


    ; ...


    move.w (sp)+,d7 ; ++ load saved d7 state



    and add a direct link to your post for further explanations.


    I'll update the first post later, I didn't have time to check the one Dandaman posted (though if someone has more details, it would help: revision involved, possible reasons, general guidelines to fix).
     
  18. vladikcomper

    vladikcomper Well-Known Member Member

    Joined:
    Dec 2, 2009
    Messages:
    415
    Heh, I just knew my way wasn't optimal, now I see it isn't optimal at all. That's why I haven't used it in my code, just came up with this suggestion when typing post. Too bad I couldn't think of a better solution, though it was so obvious. =(


    As for my code, where I touched d7, I solved it differently. I refused d7 and used another register to hold 2 different words. This is another good way, since M68K instruction set has swap instruction to swap the words in register.


    @SpirituInsanum: It looks clear and perfect now.
     
  19. SpirituInsanum

    SpirituInsanum Well-Known Member Member

    Joined:
    Feb 11, 2010
    Messages:
    642
    I finally had some time to check the problem with the title screen's background not scrolling and update the first post.


    The problem with the background not scrolling is easy to solve so I didn't give too specific guidelines.
     
  20. MarkeyJester

    MarkeyJester ♡ ! Member

    Joined:
    Jun 27, 2009
    Messages:
    2,867
    Nice work, I will point out though:

    If I recall (I could be wrong but), if that is the same issue on the Y axis as on the X axis, then it must also be based on Sonic's position (mainly Y), so in that case, having the lamppost at correct ground position won't do if Sonic is in the air and has touched the top of the lamppost, then his Y position won't be the same as the starting Y position on that lamppost, hence the draw position should remain fucked (of course, just speculating here in general as I haven't tried it, so apologies if you check this and it's incorrect =P).


    I'm pleased that you're engaging in this form of research though, it's interesting stuff to say the least, maybe one day we'll end up with a fully function and bugless Sonic 1 Rom =P
     
Thread Status:
Not open for further replies.