Basic Questions and Answers Thread

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

  1. chaos_soul

    chaos_soul opa opa! Member

    Joined:
    May 3, 2012
    Messages:
    29
    Possibly a dumb question (but it's quite specific and I can't find anything about it); Regarding SMPS 68k, if you want to create a track that serves as a 1UP jingle, do all tracks need to end with an E4 flag, or just one?
     
    Last edited: May 1, 2018
  2. Ralakimus

    Ralakimus "I want to die alone tonight~" Member

    Joined:
    Aug 26, 2013
    Messages:
    1,000
    Location:
    Assville, Shittucky
    Just one.

    Also, @Samey
    Because that's the command for the sound driver to set the music's tempo back to normal.
     
    Last edited: May 1, 2018
    Niko and chaos_soul like this.
  3. Roxurface

    Roxurface Well-Known Member Member

    Joined:
    Oct 5, 2014
    Messages:
    69
    Okay, this almost warrants a post, but I'll start here. I'm in the middle of porting Super Sonic to Sonic 1 Github Disasm/ReadySonic, and I'm using the Sonic Retro guide by Shadow05 (mostly as a guideline since it's a mess and was written for the hivebrain) and I've reached a bug that has seemingly no cause. This is what my code looks like right now:

    upload_2018-5-1_2-7-50.png

    This builds perfectly fine. However, as soon as I remove the comments from the 3 move commands, suddenly a error crops up at Line 52. It says:
    Error : Illegal value (-134)
    beq.s @exit

    Why does this line get loused up? Also, if I add in the corresponding code to restore Super Sonic's speed once he leaves the water, even more errors pop up, some of them even in other objects' code.

    what could possibly be causing these errors?
     
  4. nineko

    nineko I am the Holy Cat Member

    Joined:
    Mar 24, 2008
    Messages:
    1,774
    Location:
    italy
    It looks like that adding those 3 lines makes the branch distance bigger than the maximum allowed (-134 opposed to -128), without looking at the full code I can only guess that there is an "exit" label somewhere above the snippet you posted. Try changing the beq.s on line 52 to a beq.w. The one on line 45 is probably fine.
     
  5. Roxurface

    Roxurface Well-Known Member Member

    Joined:
    Oct 5, 2014
    Messages:
    69
    Ah, this makes sense. I'll give it a try once I get home. Thanks

    Edit: Worked great, I'm getting pretty close now. Thanks!
     
    Last edited: May 2, 2018
    nineko likes this.
  6. Ashuro

    Ashuro Anti-Cosmic Metal Of Death Member

    Joined:
    Sep 27, 2014
    Messages:
    528
    Location:
    France
    Hello. I am currently importing the Sonic 2 option menu to my hack (Hivebrain), and I have an error during the built i've ever had:
    "Warning : Forward reference to redefinable symbol"

    Concerning all these lines:

    Code:
    TextOptScr_PlayerSelect:    dc.b    $10,_st,_P,_L,_A,_Y,_E,_R,__,_S,_E,_L,_E,_C,_T,_st
    TextOptScr_Sonic:            dc.b    $0E,__,__,__,__,_S,_O,_N,_I,_C,__,__,__,__,__,__
    TextOptScr_Miles:            dc.b    $0E,__,__,__,__,_M,_I,_L,_E,_S,__,__,__,__,__,__
    TextOptScr_Tails:            dc.b    $0E,__,__,__,__,_T,_A,_I,_L,_S,__,__,__,__,__,__
    TextOptScr_Knuckles:        dc.b    $0E,__,__,__,__,_K,_N,_U,_C,_K,_L,_E,_S,__,__,__
    TextOptScr_VsModeItems:        dc.b    $10,_st,__,_I,_N,__,_M,_O,_N,_I,_T,_O,_R,_S,__,_st
    TextOptScr_AllKindsItems:    dc.b    $0E,_A,_L,_L,__,_K,_I,_N,_D,_S,__,_I,_T,_E,_M,_S
    TextOptScr_TeleportOnly:    dc.b    $0E,_I,_T,_E,_M,__,_S,__,_O,_N,_L,_Y,__,__,__,__
    TextOptScr_SoundTest:        dc.b    $10,_st,__,_S,_O,_U,_N,_D,__,_T,_E,_S,_T,__,__,_st
    TextOptScr_0:                dc.b    $10,__,__,__,__,__,__,_0,__,__,__,__,__,__,__,__
    I don't know what it is, someone to help me please?
     
  7. vladikcomper

    vladikcomper Well-Known Member Member

    Joined:
    Dec 2, 2009
    Messages:
    384
    Location:
    Russia
    Ashuro, a "forward reference" means you refer to a variable that has not been defined (initialized) by this point.
    The warning is issued because you're essentially breaking your program flow, trying to use something that hasn't been set yet. The assembler is still able to resolve and substitute your variable's value into the expression, but the lastly set value from the previous pass will be used (explained below), which may break your logic entirely.

    Consider the following example:
    Code:
    PositionData:
       dc.w   _MyXPos, _MyYPos
     
    _MyXPos:   =   $1200
    _MyYPos:   =   $040C
    
    ; <<OVER 9000 lines later>>
    
    ; Let's redefine them!
    _MyXPos:   =   $FFFF
    _MyYPos:   =   $FFFF
    
    Try to guess what will "dc.w _MyXPos, _MyYPos" resolve into? Should it be "dc.w $0120, $040C" or "dc.w $FFFF, $FFFF"?
    The answer is "dc.w $FFFF, $FFFF", which is why this behavior is potentially dangerous, and assembler wisely warns you.

    This example essentially has "forward references" to the symbols _MyXPos and _MyYPos, since by the time dc.w is assembled, these symbols are not known to the assembler, as they are defined later.
    During the first pass, all references to unknown (at the time of assembly) symbols are considered "forward references" and marked to be resolved at the second (also last) pass.
    In our case, the dc.w reserves space for two yet unknown values, so the assembler attempts to resolve them later, when the full assembly source is processed and all symbols are known. Interestingly, the assembler won't issue any warning or errors at this point.

    The second pass is when all "forward references" are resolved. When it comes "dc.w _MyXPos, _MyYPos" again, it performs various checks to ensure anything can be substituted and assembled correctly:
    1. Are symbols _MyXPos and _MyYPos defined anywhere in the source? If not => "Error: Symbol 'X' not defined"
    2. Are symbols redefinable (defined with directives "=" or "set", so the value can be altered anywhere in the source)? If yes => "Warning: Forward reference to redefinable symbol"
    3. Finally, can their values fit into the respective operands (dc.w's in this example)? If not => "Error: Illegal value (X)"
    When symbols are redefinable and are not initialized (forward reference) before referenced to, their remaining values after the first pass are used. Which is why it assembles into "dc.w $FFFF, $FFFF" and not the first "forwardly-initialized" values.

    There are two ways you can eliminate this warning.
    The first, and usually, the preferable one, is to change redefinable symbols into constants:

    Code:
    PositionData:
       dc.w   _MyXPos, _MyYPos
     
    _MyXPos:   equ   $1200
    _MyYPos:   equ   $040C
    
    ; <<OVER 9000 lines later>>
    
    ; Cannot redefine constants!
    ;_MyXPos:   equ   $FFFF        ; ERROR!
    ;_MyYPos:   equ   $FFFF        ; ERROR!
    
    This is still technically a forward reference, but assembler will resolve it without any warnings (since clause 2 of the above list is eliminated).

    The second way is to simply define variables before they are initially referenced to, removing forward references per se:
    Code:
    _MyXPos:   =   $1200
    _MyYPos:   =   $040C
    
    PositionData:
       dc.w   _MyXPos, _MyYPos
    
    ; <<OVER 9000 lines later>>
    
    ; Let's redefine them!
    _MyXPos:   =   $FFFF
    _MyYPos:   =   $FFFF
    
     
    Niko, ProjectFM, Iso Kilo and 3 others like this.
  8. chaos_soul

    chaos_soul opa opa! Member

    Joined:
    May 3, 2012
    Messages:
    29
    I'm not very experienced with ASM, but, I've managed to disable the countdown music (LZ/SBZ3), and I've replaced it with a vocal counter instead. However, the vocal samples are playing twice, since it doesn't know to check if it's already been played or not. So, I tried to add more code that writes to /checks $F751 for the ID of the last sample played. I'm able to write to the address with no problem, but whenever I try to add code to check the address and branch on a certain condition, the game crashes. Here's my code (only the countdown number for 5 has the extra code that breaks):
    Code:
    locret_1408C:
            cmpi.w    #$B,($FFFFFE14).w
            beq.s Obj0A_narr5
            cmpi.w    #$9,($FFFFFE14).w
            beq.s Obj0A_narr4
            cmpi.w    #$7,($FFFFFE14).w
            beq.s Obj0A_narr3
            cmpi.w    #$5,($FFFFFE14).w
            beq.s Obj0A_narr2
            cmpi.w    #$3,($FFFFFE14).w
            beq.s Obj0A_narr1
            cmpi.w    #$1,($FFFFFE14).w
            beq.s Obj0A_narr0
            rts  
          
    Obj0A_narr5:  
            cmpi.w    #$97,($FFFFF751).w    ;compare, (equals 97)?
            bne.s Obj0A_narr5play ;branch if not already 97
            rts
    Obj0A_narr5play:
            moveq    #$FFFFFF97,d0
            jsr    PlaySample    ;play "5" sample
            move.b    #$97,($FFFFF751).w    ;write 97 into RAM
            rts
    
    Obj0A_narr4:
            moveq    #$FFFFFF96,d0
            jsr    PlaySample    ;play "4" sample
            move.b    #$96,($FFFFF751).w    ;write 96 into RAM
            rts
          
    Obj0A_narr3:
            moveq    #$FFFFFF95,d0
            jsr    PlaySample    ;play "3" sample
            move.b    #$95,($FFFFF751).w    ;write 95 into RAM
            rts
          
    Obj0A_narr2:
            moveq    #$FFFFFF94,d0
            jsr    PlaySample    ;play "2" sample
            move.b    #$94,($FFFFF751).w    ;write 94 into RAM
            rts
          
    Obj0A_narr1:
            moveq    #$FFFFFF93,d0
            jsr    PlaySample    ;play "1" sample
            move.b    #$93,($FFFFF751).w    ;write 93 into RAM
            rts
          
    Obj0A_narr0:
            moveq    #$FFFFFF92,d0
            jsr    PlaySample    ;play "0" sample
            move.b    #$92,($FFFFF751).w    ;write 92 into RAM
            rts
    
    I'm a bit confused about why it's causing the game to crash.
     
    Last edited: May 2, 2018
  9. Pacca

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

    Joined:
    Jul 5, 2014
    Messages:
    1,149
    Location:
    Triton (Moon)
    You write to the address as a byte, but your check reads it as a word. The address is odd, so a word sized check crashes with an address error. Just change the ".w" in the check to ".b", and it will work just fine.
     
    chaos_soul likes this.
  10. Roxurface

    Roxurface Well-Known Member Member

    Joined:
    Oct 5, 2014
    Messages:
    69
    When I change the length of time that the Marble Zone boss remains invincible after being hit, he hovers in place until the invincibility frames have ended. I've compared the code to the Green Hill Zone boss and I can't figure out what causes this. Any ideas?
     
  11. TheFieldWarrior

    TheFieldWarrior Well-Known Member Member

    Joined:
    Oct 9, 2015
    Messages:
    91
    Location:
    United Kingdom
    Eggman stopping after getting hit during the MZ boss is how it works in the original game, he'll only move once the invincibility frames end so naturally if the frames are extended Eggman will stay in the air longer
     
  12. Roxurface

    Roxurface Well-Known Member Member

    Joined:
    Oct 5, 2014
    Messages:
    69
    but do you know what causes this? There is nothing in the code I can find that causes him to do this. There is only one line I can find that seems out of place that clears his x velocity, but commenting that line out doesn't change the boss from what I can tell.
     
  13. MarkeyJester

    MarkeyJester ♡ ! Member

    Joined:
    Jun 27, 2009
    Messages:
    2,808
    Code:
    loc_183FE:
    		cmpi.b	#$18,$3E(a0)
    		bcc.s	Obj73_MakeLava
    		bsr.w	BossMove
    		subq.w	#4,$12(a0)
    
    Obj73_MakeLava:
    Comment out the top two instructions.
     
  14. Roxurface

    Roxurface Well-Known Member Member

    Joined:
    Oct 5, 2014
    Messages:
    69
    That did it, big thanks!
     
  15. ROM hacking

    ROM hacking Newcomer Trialist

    Joined:
    May 5, 2018
    Messages:
    6
    SonEd2/s1disasm. I started with a short GHZ1 edit, extending the level vertically, adding two other paths to the map and repositioning the start location. Although as soon as it gets to the level, the sprite glitches out, multiple players show up at different positions and the emulator stops with an illegal instruction error at some areas. I've tried everything I could find on this thread and no luck. If it's related to object limit, how to get around it?
     
    Last edited: May 7, 2018
  16. Pacca

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

    Joined:
    Jul 5, 2014
    Messages:
    1,149
    Location:
    Triton (Moon)
    Are there any invalid objects floating around your layout? Object 01 is Sonic, and placing one in the level will cause multiple Sonics' to appear. Make sure there are no instances of Object 01 floating around, and that should fix most of your problems (I'm not 100% sure about the illegal instruction error though; either its' an issue caused by having multiple Sonics, another different invalid object, or some haphazard code edit; I don't have enough info to tell).
     
    ROM hacking and MarkeyJester like this.
  17. MarkeyJester

    MarkeyJester ♡ ! Member

    Joined:
    Jun 27, 2009
    Messages:
    2,808
    The illegal instruction error occurs because both Sonic objects touch the same ring on the same frame.

    When Sonic's code is running, he will check through all objects and find those that have a touch response value set in $20, if this is 0, Sonic will ignore it, otherwise Sonic will interact with it in a specific way. The ring object when touched gets its routine counter increased, so that when the ring's code is running, it'll run down the "collection" routine instead of the normal idle routine. This collection routine will clear $20 so that the ring cannot be touched and collected again on the next frame.

    With two Sonic's involved, and being in the same place at the same time, one Sonic will touch the ring and increase its routine counter. If the second Sonic is ran before the ring is, then the second Sonic will be able to touch the ring, because the ring hasn't had the chance to run its "collection" routine and clear the $20 byte to prevent itself from being touched again. The second Sonic will increase its routine counter so it's running the "sparkling" animation routine. This routine does not clear $20, so the ring can be touched again on the next frame. Since the two Sonic's are still touching the ring on the next frame, the first Sonic will increase its routine counter again to run the deletion routine, but of course, the ring doesn't get the chance to run that because the second Sonic increases the ring's routine counter a second time. The routine counter is then larger than the offset table of routines for the ring, so it'll attempt to read the word after the table (which happens to be $1000). If out of sheer dumb luck the ring luckily lands in correct instructions that don't mess the game up, then on the next frame and the next two word's, it likely will, or the next, because the routine counter will keep increasing every frame as long as $20 has not been cleared, and as long as both Sonic's are touching it.

    When you say you "re-positioned the start location", I'm thinking that you've done exactly what Pacguy suggested, and by that I mean accidentally created an object 01, thinking it was a start location marker, when it's the object itself.
     
  18. ROM hacking

    ROM hacking Newcomer Trialist

    Joined:
    May 5, 2018
    Messages:
    6
    Thanks for the info. That error was caused by a malfunctioning swinging object. Now after that, the level was stable until I made a few changes to some chunks in the tile editor -fixing unusual tiles- and now the act stops before showing up on the screen, resulting a line 1010 emulator error.
     
    Last edited: May 7, 2018
  19. Roxurface

    Roxurface Well-Known Member Member

    Joined:
    Oct 5, 2014
    Messages:
    69
    So I decided to attempt to do Dynamic palettes into Sonic 1 Github. I've been following this tutorial: http://sonicresearch.org/community/index.php?threads/sonic-1-dynamic-palletes-in-s1.48/ which was obviously written for the hivebrain disassembly, not the github. This didn't stop me from adding dynamic music and Super Sonic, though, so I gave it my best shot. After getting it to build, I had high hopes, and simply copied the default palettes to the act 2 and 3 variants just to make sure everything was working. Act 1 loaded normally, but act 2 got a little funky. . .
    Capture.PNG Capture2.PNG
    I've included my palette pointer files and sonic.asm for you guys to take a look at. I'm sure the solution is simple, I just haven't gotten the hang of "bruteforcing code" so to speak yet I guess.
     

    Attached Files:

  20. vladikcomper

    vladikcomper Well-Known Member Member

    Joined:
    Dec 2, 2009
    Messages:
    384
    Location:
    Russia
    Roxurface, you almost got it right.
    But your newly added "PalPointers2" and "PalPointers3" data arrays happen to have different entry indexes for the same zones (because you shifted everything by commenting out certain palette entries). Which is why wrong palette data is being loaded.

    The "palette pointers" from you files can be thought of as arrays of 8-byte entries:
    Code:
    ptr_Pal_SegaBG:     palp   Pal_SegaBG,$FB00,$40      ; index 0, offset $00
    ptr_Pal_Title:      palp   Pal_Title,$FB00,$20       ; index 1, offset $08
    ptr_Pal_LevelSel:   palp   Pal_LevelSel,$FB00,$40    ; index 2, offset $10
    ptr_Pal_Sonic:      palp   Pal_Sonic,$FB00,$10       ; index 3, offset $18
    ptr_Pal_SuperSonic: palp   Pal_SuperSonic,$FB00,$10  ; index 4, offset $20
    ptr_Pal_GHZ:        palp   Pal_GHZ,$FB20, $30        ; index 5, offset $28
    <...>
    
    Why 8 bytes exactly? Because the "palp" macro used here expands into 8 bytes of data:
    Code:
    palp:   macro paladdress,ramaddress,colours
       dc.l paladdress   ; 4 bytes
       dc.w ramaddress, (colours>>1)-1 ; 2+2 = 4 bytes
    ; total: 8 bytes
       endm
    
    On a side note, this is the reason I don't particularly like the newer Sonic 1 disassembly. It pretends to be smarter than you, abusing macros, expressions and unnecessary labels to the point of complete redundancy. It doesn't help to make assembly source more flexible and relocatable anymore, but rather hides otherwise apparent and easy to read data structures from you, making a learning curve much steeper at times...

    What the new logic does is basically to hook every palette loading routine to load "PalPointers", "PalPointers2" and "PalPointers3" depending on the current act (variable $FFFFFE11). This isn't the best solution to say at least, but fair enough to get yourself started with the assembly, because it's really straight-forward.
    Code:
    PalLoad4_Water:
           move.b $FFFFFE11,d1               ; d1 = Act number
           lea (PalPointers).l,a1           ; try pointers for Act 1
           cmp.b #0,d1                       ; is it Act 1?
           beq.w PalLoad4_Continue           ; if yes, branch
           lea (PalPointers2).l,a1           ; try pointers for Act 2
           cmp.b #1,d1                       ; is it Act 2?
           beq.w PalLoad4_Continue           ; if yes, branch
           lea (PalPointers3).l,a1           ; try pointers for Act 3
    
    PalLoad4_Continue:
           lsl.w   #3,d0                   ; multiply index by 8, to calculate offset inside pointers array
           adda.w   d0,a1                   ; add offset to the beginning of the pointers array
    Each palette is loaded by its index, which is a number telling the expected palette data position inside PalPointers array. But since you commented out the redundant palettes in PalPointers2 and PalPointers3, the remaining palettes do not have the same indexes anymore:
    Code:
    ptr_Pal_SegaBG2:     palp   Pal_SegaBG,$FB00,$40      ; index 0, offset $00
    ;ptr_Pal_Title:      palp   Pal_Title,$FB00,$20       ; <<removed>>
    ;ptr_Pal_LevelSel:   palp   Pal_LevelSel,$FB00,$40    ; <<removed>>
    ptr_Pal_Sonic2:      palp   Pal_Sonic,$FB00,$10       ; index 1, offset $08
    ;ptr_Pal_SuperSonic: palp   Pal_SuperSonic,$FB00,$10  ; <<removed>>
    ptr_Pal_GHZ:         palp   Pal_GHZ,$FB20, $30        ; index 2, offset $10
    <...>
    Sonic's palette has the index of 1 in "PalPointers2" and "PalPointers3", but the game will load whatever is at index 3 instead, because it's the expected index for Sonic's palette as seen in "PalPointers".
    The same applies basically to any zone and other palette entries. Since all pointers are shifted, wrong or corrupt data will be loaded in Acts 2 and 3.