Basic Questions and Answers Thread

Discussion in 'Discussion & Q&A' started by Malevolence, Jul 7, 2009.

  1. Clownacy

    Clownacy Negative Clownancy Staff

    Joined:
    Aug 15, 2014
    Messages:
    886
    For question 2, these are the instructions you're interested in:
    Code:
    	move.l	(a0,d0.w),(a1)+
    	move.l	4(a0,d0.w),(a1)	; copy palette data to RAM
    Each palette entry is two bytes in size. So, each instruction moves a longword (4 bytes), which means two colours. Combined, these instructions transfer four palette entries. Changing the last instruction to a 'move.w' will make it transfer only two bytes, so the total is reduced to three palette entries. But that's not all. Unless you want to pad out each 7/8th byte of Pal_GHZCyc, you need to change the code to treat it as a list of six bytes, rather than eight.
    Code:
    	lsl.w    #3,d0
    This instruction multiplies the index by eight. This is what needs changing. There are two ways we can go about this: we could use a 'mulu.w' multiplication instruction, but that instruction is very inefficient, so it may be optimal to use the alternative, shifts, like the current code does. Unfortunately, using shifts to multiply by six is harder than by eight, but not by a lot. It just requires a few more instructions.
    Code:
    	lsl.w	#1,d0	; multiply by 2
    	move.w	d0,d1	; save this
    	lsl.w	#1,d0	; multiply by 2 again, making it x4
    	add.w	d1,d0	; add both values, making it x6
    If we want our code to be even faster, we can use 'add.w' additions instead of actual shifts, since they're faster (at least, for shifts of 1 or 2).
    Code:
    	add.w	d0,d0	; multiply by 2
    	move.w	d0,d1	; save this
    	add.w	d0,d0	; multiply by 2 again, making it x4
    	add.w	d1,d0	; add both values, making it x6
    As for question 3... Scrap Brain Zone act 3 is actually Labyrinth Zone act 4, and Final Zone is Scrap Brain Zone act 3, using assets from act 2. Yes, each zone is actually 4 acts long, the last one is usually just skipped. The part of Green Hill Zone from the ending is actually another zone, but a lot of zone-specific data, such as offset tables, lack entries for it, meaning the zone is only partially-implemented.

    To add to the title screen problem you mentioned, the title screen, despite obviously not being a level, uses some level code to make its background work. This creates a bizarre reliance on Green Hill Zone act 1, which the title screen pretends to be. For example, if you change where Sonic spawns in act 1, the title screen will corrupt, with the emblem flying off-screen.
    [​IMG]
    (Seeing the post before me, just now) If we're gonna talk about disassemblies, the Hivebrain disasm doesn't correct the Z80-based DAC driver if the Sega Chant is moved, leading to a garbled mess playing instead. This was fixed in the Git disasm.

    EDIT: Quote for new page. Also, Ninja'd.
     
    Last edited: Jan 6, 2016
  2. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    802
    Location:
    Portland, Maine
    GenesisDoes:
    1. Changing the height of a Sonic 1 or 2 level would require the way the game loads chinks to be retooled. This feature is only for Sonic 3K and possibly the 1995 PC version of Sonic CD.

    4. If I want it to use a specific palette line, I make backups of the level's and Sonic's palette lines and replace every color except the ones in the line I'm using with a color completely distinct from image I'm importing (usually pink which is E0E) using either a hex editor or SonLVL. After importing the image, I replace the files with the backups. The problem with a color being replaced with the transparency slot is unavoidable but can easily be fixed using the tile editor.

    Raidein Slash:
    Nineko (and possibly others; I don't remember) has released a few in the now gone media section of the forums (including the soundtrack to his hack soniNeko. You could PM him for it. I don't recall it having the exact song you're looking for, though. You can also use converters like smps2asm, xm3smps/oerg, or xm4smps. Nineko has created a tutorial for xm3smps and xm3smps/oerg here.
     
  3. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    868
    levelwidthmax and levelheightmax are leftovers from older versions of SonLVL, before I had to rewrite some things to handle custom layout formats. If you have edited the level layout handling in your hack to handle larger levels, you may provide a custom level layout handler like this (replace "S2" with "S1").

    For importing images, I always tell everyone to make the image conform to the level's palette in your image editor, and save it as 4bpp (16 colors) or 8bpp (256 colors), then SonLVL will import the image using exactly the palette indexes in the image (the palette line for 16 color images is the selected line in the palette editor).
     
  4. GenesisDoes

    GenesisDoes Wizard of the Sonic Member

    Joined:
    Jan 2, 2016
    Messages:
    134
    Location:
    Pittsburgh, PA
    RaideinSlash:
    I actually asked and had user ValleyBall create a SMPS version of that exact song for a hack at RetroHack ~2012, though I lost it in a HDD crash. You should PM him if you can't find it elsewhere.

    I used Selbi's quick solution for the palette cycling (NOP'ing the move), which worked; thanks!

    A few other questions:
    1. Where is the general files/areas in S1 Git where the chunks are drawn and the S1 loop flag is processed (a few "andi $7F" ops in "Sonic Loops.asm" and elsewhere)? I applied the Load Chunks from ROM guide to load >$5F chunks, but found out that chunk IDs >$7F obviously overwrite the MSB $80 S1 loop flag and can't be used for unique chunks. I would be looking to conditionally ignore the loop system for levels with ROM-loaded chunks to get upto $FF chunks. (I could apply the Dynamic Tilesets guide, but I'm avoiding it, due to difficulty in implementation the final steps last time.)

    2. Along the lines of increasing the max level size, where is the code in S1 Git that handles the level size, and what is the best way to modify it?

    3. I'm working on a custom object $4F to act as a level warp object to warp Sonic between areas in zones (think SMB1's room system for levels). My hack will have 4 bonus stage levels, which can be entered from a normal zone via a particular door subtype in the main levels. At the end of the bonus stage levels are a door to return back to the previous level. I have coded 5 subtypes of doors: 0=return from bonus stage to previous zone (at a specified x,y position), 1-4=goto appropriate bonus stage, 5=warp within level at specified x,y position (to goto boss room in Act 3).

      However, the code to warp the player after hitting the custom object is crashing on real hardware, and in emulators, the warps partially work. On real hardware, the debugger appears and says "Address Error: $0000FBE18 $FFFFFEA1" (where $FFFFFEA1 is a new variable I allocated in unused RAM space, according to SCHG), while on emulators, although the bonus stage doors subtypes #1-4 do warp to the test level (Time Lord Zone, formerly Final Zone) and door subtype #5 works (except for new warping to new position), door subtype #0 always warps me to Emerald Forest Zone (previously GHZ) instead of Treasure Castle Zone (formerly Marble Zone).

      Posted below is the code. For the issue with subtype #0, I suspect that the new v_warp_zone and v_warp_act variables I created are not storing the proper values (see labels below Door_TypeIndex). What am I doing wrong?

    Video of $4F door issues
    Code:
    Code:
    SONIC 1 GITHUB disasm:
    
    Variables.asm:
    v_lamp_wtrstat:    = v_lastlamp+$23 ; water state at lamppost
    v_lamp_lives:    = v_lastlamp+$24 ; lives counter at lamppost
    
    f_warp:            = $FFFFFEA0 ; Used for Socket door warps flag action! !@
    v_warp_x:        = $FFFFFEA1 ; x position after level warp (2 bytes) !@
    v_warp_y:        = $FFFFFEA3 ; y position (2 bytes) !@
    v_warp_zone:    = $FFFFFEA5 ; zone prior to warping !@
    v_warp_act:        = $FFFFFEA6 ; act prior to warping !@
    
    incObj/4F.asm:
    
    ; ---------------------------------------------------------------------------
    ; Object 4F - blank.
    ;!@ Now Socket bonus stage Door!
    ;Using object $19 (unused switch) object as codebase to modify
    ; ---------------------------------------------------------------------------
    
    obj4F:
            moveq    #0,d0
            move.b    obRoutine(a0),d0
            move.w    Door_Index(pc,d0.w),d1
            jmp    Door_Index(pc,d1.w)
    ; ===========================================================================
    Door_Index:    dc.w Door_Main-Door_Index
            dc.w Door_Action-Door_Index
            dc.w Door_Delete-Door_Index
    
    ;origY:        = $30        ; original y-axis position
    ; ===========================================================================
    
    Door_Main:    ; Routine 0
            addq.b    #2,obRoutine(a0)
            ;move.l    #Map_Door,obMap(a0)
            ;move.w    #$4000,obGfx(a0)
            move.b    #4,obRender(a0)
            ;move.w    obY(a0),origY(a0) ; save position on y-axis
            move.b    #$10,obActWid(a0)
            move.b    #5,obPriority(a0)
    
    Door_Action:    ; Routine 2
            ;move.w    origY(a0),obY(a0) ; restore position on y-axis
            move.w    #$10,d1
            bsr.w    Door_ChkTouch    ; check if Sonic touches the Doortch
            beq.s    Door_ChkDel    ; if not, branch
    
            ;addq.w    #2,obY(a0)            ; move object 2    pixels
            ;moveq    #1,d0
            ;move.w    d0,(f_Doortch).w    ; set Doortch 0 as "pressed"
    
            moveq    #0,d0
            moveq    #0,d1
            move.b    obSubtype(a0),d0
            add.w    d0,d0
            move.w    Door_TypeIndex(pc,d0.w),d1
            jsr        Door_TypeIndex(pc,d1.w)
            bsr.w     DoLamppostWarp
            rts
           
    Door_ChkDel:
            bsr.w    DisplaySprite
            ;out_of_range    Door_Delete
            rts   
    ; ===========================================================================
    
    Door_Delete:    ; Routine 4
            ;bsr.w    DeleteObject
            rts   
    
    ; ---------------------------------------------------------------------------
    ; Subroutine to    check if Sonic touches the object
    ; ---------------------------------------------------------------------------
    
    ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    
    
    Door_ChkTouch:
            lea    (v_player).w,a1
            move.w    obX(a1),d0
            sub.w    obX(a0),d0
            add.w    d1,d0
            bmi.s    Door_NoTouch
            add.w    d1,d1
            cmp.w    d1,d0
            bcc.s    Door_NoTouch
            move.w    obY(a1),d2
            move.b    obHeight(a1),d1
            ext.w    d1
            add.w    d2,d1
            move.w    obY(a0),d0
            subi.w    #$10,d0
            sub.w    d1,d0
            bhi.s    Door_NoTouch
            cmpi.w    #-$10,d0
            bcs.s    Door_NoTouch
            moveq    #-1,d0        ; Sonic has touched it       
            rts   
    ; ===========================================================================
    
    Door_NoTouch:
            moveq    #0,d0        ; Sonic hasn't touched it
            rts   
    ; End of function Door_ChkTouch
    
    ; ===========================================================================
    
    Door_TypeIndex:
            dc.w Door_Type00-Door_TypeIndex, Door_Type01-Door_TypeIndex
            dc.w Door_Type02-Door_TypeIndex, Door_Type03-Door_TypeIndex
            dc.w Door_Type04-Door_TypeIndex, Door_Type05-Door_TypeIndex
            rts
    
    ;Bonus Stage return door
    ;Returns Sonic back to zone prior to warping to a bonus stage level
    Door_Type00:
            ;!@ Fetch hard-coded positions for each level to return to here into d2 and d3 from an array!
           
            ;move.w    #$550, (v_warp_x).w
            ;move.w    #$550, (v_warp_y).w
            ;move.b    #1,    (v_act).w        ;Act
            ;move.b    #id_MZ, (v_zone).w        ;Zone
            ;move.b    #2, (f_warp).w        ;Set warp flag!
            ;move.b    #1, (f_restart).w        ;Do the warp!
           
            ;Hard coded an arbity x,y coord for testing
            move.w    #$559, d2
            move.w    #$559, d3
            ;move.w    #0, d2
            ;move.w    #0, d3
            move.b    (v_warp_act).w, d4
            move.b    (v_warp_zone).w, d5
            move.b    #2, d6                    ;Set warp flag!
            rts
           
    ;Goes to Bonus stage levels
    ;Hack will have 4 bonus stage types
    ;Currently setting all to SBZ A3 (Final Zone) for testing
    Door_Type01:
    Door_Type02:
    Door_Type03:
    Door_Type04:
    
            ;move.w    #0, (v_warp_x).w
            ;move.w    #0, (v_warp_y).w
            ;move.b    #2,    (v_act).w        ;Act
            ;move.b    #id_SBZ, (v_zone).w        ;Zone
            ;move.b    #2, (f_warp).w        ;Set warp flag!
            ;move.b    #1, (f_restart).w        ;Do the warp!
    
            ;v_warp_zone/act hold zone/act prior to warping
            move.b    (v_zone).w, (v_warp_zone).w
            move.b    (v_act).w, (v_warp_act).w
            move.w    #0, d2
            move.w    #0, d3
            move.b    #2, d4            ;Act
            move.b    #id_SBZ, d5        ;Zone. !@ Final Zone for now
            move.b    #2, d6            ;Set warp flag!
            rts
           
    ;Goes to Act 3's Boss position
    ;(inter-level door)
    Door_Type05:
    
            ;move.w    #$1500, (v_warp_x).w
            ;move.w    #$1500, (v_warp_y).w
            ;move.b    #1,    (v_act).w        ;Act
            ;move.b    #id_MZ, (v_zone).w        ;Zone
            ;move.b    #1, (f_warp).w        ;Set warp flag!
            ;move.b    #1, (f_restart).w        ;Do the warp!
    
            ;!@ Fetch position for each zone here into d1 and d2 from an array!
            ;Hard-coding arbitrary position for testing
            move.w    #$1500, d2
            move.w    #$1500, d3
            move.b    (v_act).w, d4
            move.b    (v_zone).w, d5
            move.b    #1, d6            ;Set warp flag!
            rts
           
    ; ---------------------------------------------------------------------------
    ; Subroutine to apply warp params and do the warp
    ; ---------------------------------------------------------------------------
    DoLamppostWarp:
    
        ;Params for $4f obj:
        ;d1 - X coord to warp to
        ;d2 - Y coord to warp to
        ;d3 - Act to warp to
        ;d4 - Zone to warp to
        ;d5 - Warp type (1 or 2 value for f_warp)
       
        ;Move the data from regs to appropriate vars for warp
        move.w    d2, (v_warp_x).w
        move.w    d3, (v_warp_y).w
        move.b    d4,    (v_act).w            ;Act
        move.b    d5, (v_zone).w            ;Zone
        move.b    d6, (f_warp).w            ;Set warp flag!
        move.b    #1, (f_restart).w        ;Do the warp!
        rts
    
    ; ===========================================================================
     
  5. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    The 68k can't write words or longwords to odd addresses, only bytes, which is what gives you your address error. If you want to use those addresses, find an even address.
     
  6. Selbi

    Selbi Plug in, baby. Retired Staff

    Joined:
    Jul 20, 2008
    Messages:
    2,398
    Location:
    Northern Germany
    Or use Gens. :V

    I don't really know how the chunk loading stuff works, but the level size is set via an look-up table with various values for each act, six words each, which would define the four boundaries as camera offsets. The other two words are unused or pointless.

    In the 2005 disassembly this was a binary file called "lvl_size.bin" in the misc folder. Considering how much of a bullshitty mess this was to deal with, it wouldn't surprise me if this has been converted to a text-editor-friendly format for the Git disassembly. Unfortunately I'm on a phone right now, so I can't give you the exact name, but you should be able to look around with the keywords "size" or "boundary" to find something.

    Also, out of curiosity, what quick solution with NOP'ing are you referring to?
     
    Last edited: Jan 6, 2016
  7. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    868
    I think he meant the level layout size, not the camera boundaries. For the record though, the GitHub disassembly has not made it any easier to edit, it just renamed it to "Level Size Array.bin".

    If you want to increase the maximum level size, you would have to edit every piece of code that reads the level layout data, and find some way to add more space for it in RAM. Since you're using ROM-based chunks, you could probably move the layout data into the RAM that used to be used for chunks.

    I can't help you with disabling the loop flag in the ASM, but I can tell you that for SonLVL to read those levels properly, you will have to set those levels to use layoutfmt=S2NA, or a custom layout format based on S2NA's.
     
  8. HackGame

    HackGame The ROM Hacker Member

    Joined:
    Jul 18, 2014
    Messages:
    142
    Location:
    Green Hill Zone
    I need help trying to make Sonic lose only 20 rings, it's around Obj37_Reset Counter. But when I added the code to lose 20 rings, it passes the ring counter.
     
  9. Pacca

    Pacca Why succeed when you can profit off of failure? Member

    Joined:
    Jul 5, 2014
    Messages:
    1,149
    Location:
    Triton (Moon)
    There's some sort of flag that need to be set in order to update the ring counter. I forget what it's called, but I know it has "update" in the name. Just look around other bits of code that remove Sonics' rings, and you should find it.
     
  10. GenesisDoes

    GenesisDoes Wizard of the Sonic Member

    Joined:
    Jan 2, 2016
    Messages:
    134
    Location:
    Pittsburgh, PA
    I meant changing the .l .w on the 2nd move.l (it was a late night).

    Will try changing those RAM address constants to even ones.

    As for extending past $7F chunks, after looking at it more last night, I'm pretty sure the code is at "DrawBlocks" and "LocateBlock" in Sonic.asm (after doing the ROM-Chunk tutorial), with some changes also possibly needed in "_incObj/sub FindNearestTile.asm" later. The code to handle the collision for loop halves was in "Sonic Loops.asm" which I disabled out, since the hack won't be using loops or roll tunnels anyways. There is an "andi.w $7F, d3", where d3 is the chunk ID according to the code's comments, which seems to truncate the MSB (the loop flag) of the chunk ID byte, followed by rotating the bits right 7 (?). Commenting it out garbled the block graphics of chunks >$7F in my ROM-Chunk level, but kept all other chunks' graphics intact. So that changes needed are in that area most likely.

    Code:
    LocateBlock:
            move.b    (a4,d0.w),d3    ; load chunk ID in d3
            beq.s    LocateBlock_EmptyChunk
            subq.b    #1,d3
    
            andi.w    #$7F,d3    ; !@ AND $7F in order to truncate IDs >$80 for loop tile?
            ror.w    #7,d3
            add.w    d4,d4
            andi.w    #$1E0,d4
            andi.w    #$1E,d5
            add.w    d4,d3
            add.w    d5,d3
            rts
    ; ---------------------------------------------------------------------------
    
    LocateBlock_EmptyChunk:
            addq.w    #4,sp    ; pop a stack frame to leave a1 pointing at the first tile
            rts
    
    Other than that, I have no idea what the other registers and code there is doing...

    Thanks everybody for the help and suggestions so far!
     
  11. Clownacy

    Clownacy Negative Clownancy Staff

    Joined:
    Aug 15, 2014
    Messages:
    886
    At a glance, that 'ror.w #7,d3' discards the MSB, breaking chunks >$7F. Also, I imagine the 'andi.w #$7F,d3' was meant to clear, not just the MSB, but the upper byte of d3. Without it, the code will behave oddly if d3 contains anything >$FF. I'd recommend sticking a 'moveq #0,d3' at the start of LocateBlock, to make things safe.

    As for the 'ror.w', I'd replace that with this:
    Code:
    	lsl.l	#8,d3
    	add.l	d3,d3
    It does the same thing, but keeps the MSB. Since d3 now contains more than a word, 'add.w d4,d3' and 'add.w d5,d3' should be changed to 'add.l'.
     
    Last edited: Jan 7, 2016
  12. GenesisDoes

    GenesisDoes Wizard of the Sonic Member

    Joined:
    Jan 2, 2016
    Messages:
    134
    Location:
    Pittsburgh, PA
    I tried the changes above, but it corrupts all chunks's blocks with garbage. Will look into the level drawing code and extending level sizes later.

    After moving the warp variables to align with even word sizes and fixing the door code, got the doors to work better! (For door subtype #1 and #5, just need to make the camera not chase Sonic at his new position, and also implement graphics for the door object)

    Video

    One last dumb question, how can I get my palette cycle to not run backwards? I'm using LZ's waterfall palette cycle for the colors, but reversing the colors in the sequence still makes the waterfalls in my BG run backwards (see 0:50 of video). I think I will need to run that palette cycle code backwards for it to work properly.
     
  13. USSRSonic

    USSRSonic Newcomer In Limbo

    Joined:
    Jan 10, 2016
    Messages:
    12
    Location:
    Russia
    How make a timer in Specical stage in sonic 1 as Sonic 4 Episode 1 Special stage
     
  14. SaunicBoom

    SaunicBoom Well-Known Member Member

    Joined:
    Sep 14, 2007
    Messages:
    324
    There's a couple ways to do this. The longer way would be to go into the art itself and redraw the water by hand, but reversing the shades of water while doing so. The shorter way would be to find the location of the water palette cycle and rearrange the color values so that they give you the effect you're looking for. I'm not entirely familiar with how Sonic 1 handles palette cycles, but I'm sure it wouldn't be too difficult to locate if you do enough digging. Sorry if my reply seems too vague of an answer or if I'm slightly off here, it's been quite some time since I've dabbled with disassemblies myself.
     
  15. USSRSonic

    USSRSonic Newcomer In Limbo

    Joined:
    Jan 10, 2016
    Messages:
    12
    Location:
    Russia
    a week ago I started doing hack Sonic 4 Episode 1 but I need help to the file below which I did a week ago , and there is a problem how to add to the seventh Chaos Emerald
     

    Attached Files:

  16. nineko

    nineko I am the Holy Cat Member

    Joined:
    Mar 24, 2008
    Messages:
    1,773
    Location:
    italy
    Just so you know, reversing all the colors in a rotating palette (e.g. turning 123456789ABC into CBA987654321) won't give you the result you're looking for, it might even result in bizzarre things. That's because rotating palettes usually work on more than one palette index at the same time. I don't know how many indexes are involved in LZ's rotating palette, but let me clarify the concept with an example. If 4 indexes are updated at the same time, 123456789ABC should become 9ABC56781234. You might try looking at it with my palette editor which I specifically designed with rotating palettes in mind thanks to Varion's idea.
     
  17. GenesisDoes

    GenesisDoes Wizard of the Sonic Member

    Joined:
    Jan 2, 2016
    Messages:
    134
    Location:
    Pittsburgh, PA
    LZ's rotating palette uses 4 palettes indices, but in one of my earlier posts, I modified my palette cycling code (based off GHZ's IIRC) to do 3 entries instead, and am just using the LZ palette cycle binary file for the colors. Thanks for clarifying why reversing the palette wouldn't fix the issue, I was wondering what was going on. I ended up just swapping out 2 colors in the original art (only used in 4 chunks) to "fix" the issue, but will keep this in mind (and try out that application) for future palette cycling edits.
     
  18. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    802
    Location:
    Portland, Maine
    I had the same problem and the fix was changing this line in your PalCycle routine:

    addq.w #1,($FFFFF632).w

    To this:

    subq.w #1,($FFFFF632).w
     
  19. Giovanni

    Giovanni Well-Known Member Member

    Joined:
    Apr 16, 2015
    Messages:
    120
    Location:
    Vercelli, Italy
    Had a problem with Special Stages in Sonic 1.
    Trying to change the starting position of a special stage on SonED2 with the Sonic 1 GitHub disassembly caused me an incredible issue.
    Sonic spawns on a random mess of tiles where you can find randomly placed blocks, objects, rings and Chaos Emeralds.
    I tried fixing this, but loading the Special Stage again causes SonED2 to crash.
    Any help would be appreciated.
     
  20. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    802
    Location:
    Portland, Maine
    I had that same problem. Whenever you want to change the special stage in SonED2 you have to delete the special stage starting position file.