Basic Questions and Answers Thread

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

  1. Tanner

    Tanner I play video games and do computer stuff! Member

    Joined:
    Dec 23, 2016
    Messages:
    40
    This is exactly what I meant.
    Thank you for explaining that.
     
  2. Pacca

    Pacca Level 1 inflatable otter thing Member

    Joined:
    Jul 5, 2014
    Messages:
    1,107
    Location:
    Twinleaf Town
    I've run into an odd issue with the Aquatic Ruin Zone boss in every major Sonic 2 hack I've ever worked on. It seems to happen naturally whenever code/data/etc. is shifted around enough, and it has happened in both the Xenowhirl and GitHub disassemblies. I've been unable to figure out where the problem lies for quite some time now, and it's really starting to get on my nerves...

    The issue is that the Arrows the boss should shoot never appear; the spawn code for them runs, and it appears to work as intended, but there's no arrow after the fact; "Obj89_Arrow" (the routine for the entire arrow object) never even runs.

    I figured out the source of the problem while writing this post, but it still leaves me somewhat confused. Here's the code in question:
    Code:
    ; ===========================================================================
    ; loc_309A8:
    Obj89_Pillar:
        moveq    #0,d0
        movea.l    obj89_pillar_parent(a0),a1 ; a1=object
    
    ;These two lines were added by me, and fix the problem
        cmp.b        #6,routine_secondary(a0)    ;are we an arrow?
        beq.s        Obj89_Pillar_Normal        ;if so, skip pillar only check
    
        cmpi.b    #8,boss_routine(a1)        ; has boss been defeated?
        blt.s    Obj89_Pillar_Normal        ; if not, branch
        move.b    #4,routine_secondary(a0)
    
    ; loc_309BC:
    Obj89_Pillar_Normal:
    
    The arrows run the pillar code by mistake because of the extra check that happens before the routine is run.

    Why the heck was this check programmed like this? And why does this code suddenly stop working when rebuilding? This issue has followed me over the years (It's the reason the Aquatic Ruin Zone boss doesn't appear in Robotnik Returns 2), so I'm really curious as to what's going on here...
     
    ProjectFM likes this.
  3. MarkeyJester

    MarkeyJester !%#@ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,638
    The pillars have the parent object (Robotnik) stored in their object RAM slot at 2A - 2D (obj89_pillar_parent), a long-word address pointing to the Robotnik object. The arrows (and the eyes of the stone) do not get the parent's address put into that slot location, so the arrows (and stone eyes) have the parent object address set to offset: 000000 (ala, the beginning of the ROM).

    That code above which the pillar, the arrow, and the stone eyes, run down, reads the parent object address (which in the arrow's case is 000000), and then accesses the 26th (boss_routine) byte from it. The 26th byte from the beginning of the ROM is the 68k vector table, containing pointers to error handler routines:

    [​IMG]

    The error handlers all point to an error trap loop (the blue box addresses), however, the object will be reading from 26 of the start of ROM (that red box) which is 02, and according to signed logic it is lower than 8. Therefore it gets through the comparison without a hitch.

    If you happen to have installed a new error handler, or put the "Error Trap" routine somewhere else, or put something between it and the header information, you will change the address of those 00000200's. Perhaps you have installed either flamewing's or vladikcomper's error handler nearer to the end of the ROM where the address is much higher, and that particular byte happens to be larger than 8. And then, it's secondary routine byte will be changed from 6 to 4, and the 4th routine happens to be the pillar moving down.

    You could point the parent object to a specific address, where the 26th byte will always be lower than 8, probably something like:
    Code:
    DummyObj:	dc.w	$0000
    ...and then:
    Code:
    movea.l	#DummyObj-boss_routine,obj89_pillar_parent(a1)
    I would suggest putting the actual Robotnik object address in there, but that seems like bad practice.

    Your method seems cover the problem very well, so I wouldn't bother with the above, just stick with what you have.
     
  4. Pacca

    Pacca Level 1 inflatable otter thing Member

    Joined:
    Jul 5, 2014
    Messages:
    1,107
    Location:
    Twinleaf Town
    Are their equivalents to cmp or the various branch instructions (bgt, ble, etc.) that don't factor in negative numbers? I keep having values higher then $7F break my byte checks, and I usually just work around them with excess checks, which just looks and feels messy.
     
  5. Novedicus

    Novedicus Well-Known Member Member

    Joined:
    Aug 26, 2013
    Messages:
    817
    Yes, there are.

    bcc/bhs = bge
    bcs/blo = blt
    bhi = bgt
    bls = ble

    Difference being they handled numbers as unsigned.
     
  6. Pacca

    Pacca Level 1 inflatable otter thing Member

    Joined:
    Jul 5, 2014
    Messages:
    1,107
    Location:
    Twinleaf Town
    Hm, bhs or bcc don't seem to work quite as I hoped. Here's the check in question:
    Code:
        cmpi.b    #$6A,(Current_Zone).w    ;are we in Zone $6A?
        bge.s        LoadSomethingElse        ;if we're in zone $6A or higher, load something different instead.
        ;Something loads here I guess
    
    bhs and bcc seem to work in place of bge when Current_Zone is $6A, but when its' $A0, they both don't branch. Even bhi doesn't branch when Current_Zone is $A0.
     
  7. vladikcomper

    vladikcomper Well-Known Member Member

    Joined:
    Dec 2, 2009
    Messages:
    382
    Location:
    Russia
    Pacguy, $6A is not higher or the same as $A0, which is why branches are not taken.

    Code:
        move.b   #$A0, (CurrentZone).w   ; CurrentZone = $A0
       ;<...>
       cmp.b   #$6A, (CurrentZone).w   ; compare $6A with $A0
       bhs.s   LoadSomethingElse       ; if $6A >= $A0 (FALSE), branch
    
    The CMP opcode compares the source (left) operand with the destination (right) operand, in that order.
    As a generalized rule, the subject to a certain operation (opcode) is always the destination and the object is always the source. In other words: MOVE X, Y moves X to Y, not Y to X; SUB X, Y subtracts X from Y, not Y from X. Similarly, CMP X, Y compares X with Y, not Y with X.

    Internally, CMP subtracts source operand from the destination and sets conditional flags (CCR register) accordingly. This operation is almost identical to the SUB opcode, except the result is not stored in the destination, only conditional flags are affected.
     
    ProjectFM, Novedicus and Natsumi like this.
  8. Nat The Porcupine

    Nat The Porcupine Newcomer Member

    Joined:
    Jun 23, 2017
    Messages:
    21
    Location:
    Harrisburg, Pennsylvania (USA)
    After starting work on a clean disassembly of Sonic 1 (the MapMacros branch), I've run into a game-breaking issue that I honestly can't figure out how to solve. Basically, when moving right, objects will load in normally and the game play as expected. However, when attempting to back-track, most objects will just straight up fail to load. Here's a video of the oddity in action:



    The kicker is that I've barely even started adding new code. In fact, the only changes I've made to the code so far is the addition of a new subroutine, which I placed between the "JoypadInit" & "ReadJoypads" subroutines (a fitting place considering that the new subroutine is related to input), as well as a "bsr.w" to said subroutine just before the main game loop. This new subroutine maybe takes up a maximum of $190 bytes total when assembled and has absolutely nothing to do with the object manager. What in the blue hell is going on here?
     
  9. Clownacy

    Clownacy UP - ON - CPU Staff

    Joined:
    Aug 15, 2014
    Messages:
    823
    RAM or registers being overwritten maybe? I don't think anyone can figure it out without seeing the code.
     
  10. Nat The Porcupine

    Nat The Porcupine Newcomer Member

    Joined:
    Jun 23, 2017
    Messages:
    21
    Location:
    Harrisburg, Pennsylvania (USA)
    Right, my apologies. Here's the only place that the "MouseDetect" routine is called:

    Code:
    GameInit:
            lea    ($FF0000).l,a6
            moveq    #0,d7
            move.w    #$3F7F,d6
        @clearRAM:
            move.l    d7,(a6)+
            dbf    d6,@clearRAM    ; clear RAM ($0000-$FDFF)
    
            bsr.w    VDPSetupGame
            bsr.w    SoundDriverLoad
            bsr.w    JoypadInit
            bsr.w    MouseDetect
            move.b    #id_Sega,(v_gamemode).w ; set Game Mode to Sega Screen
    
    MainGameLoop:
            move.b    (v_gamemode).w,d0 ; load Game Mode
            andi.w    #$1C,d0
            jsr    GameModeArray(pc,d0.w) ; jump to apt location in ROM
            bra.s    MainGameLoop
    And here's the routine at its designated location (the routine was written by gasega68k, in case you were curious):

    Code:
    ; ---------------------------------------------------------------------------
    ; Subroutine to    initialise joypads
    ; ---------------------------------------------------------------------------
    
    ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    
    
    JoypadInit:
            stopZ80
            waitZ80
            moveq    #$40,d0
            move.b    d0,($A10009).l    ; init port 1 (joypad 1)
            move.b    #$60,($A1000B).l    ; init port 2 (mouse)
            move.b    d0,($A1000D).l    ; init port 3 (expansion)
            startZ80
            rts
    ; End of function JoypadInit
    
    ; ---------------------------------------------------------------------------
    ; Subroutine to    detect mouse
    ; ---------------------------------------------------------------------------
    
    ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    
    
    MouseDetect:
            lea    ($A10005).l,a0    ; second joypad port
            move.w  sr,d2
            move.w  #0x2700,sr      ;/* disable ints */
    
            move.b    #0x60,6(a0)     ;/* set direction bits */
            nop
            nop
            move.b  #0x60,(a0)      ;/* first phase of mouse packet */
            nop
            nop
    La0:
            btst    #4,(a0)
            beq.b   La0              ;/* wait on handshake */
            move.b  (a0),d0
            andi.b  #15,d0
            bne     mky_err         ;/* not 0 means not mouse */
    
            move.b  #0x20,(a0)      ;/* next phase */
            move.w  #254,d1         ;/* number retries before timeout */
    La1:
            btst    #4,(a0)
            bne.b   La2              ;/* handshake */
            dbra    d1,La1
            bra     timeout_err
    La2:
            move.b  (a0),d0
            andi.b  #15,d0
            move.b  #0,(a0)         ;/* next phase */
            cmpi.b  #11,d0
            bne     mky_err         ;/* not 11 means not mouse */
    La3:
            btst    #4,(a0)
            beq.b   La4               ;/* handshake */
            dbra    d1,La3
            bra     timeout_err
    La4:
            move.b  (a0),d0         ;/* specs say should be 15 */
            nop
            nop
            move.b  #0x20,(a0)      ;/* next phase */
            nop
            nop
    La5:
            btst    #4,(a0)
            bne.b   La6
            dbra    d1,La5
            bra     timeout_err
    La6:
            move.b  (a0),d0         ;/* specs say should be 15 */
            nop
            nop
            move.b  #0,(a0)         ;/* next phase */
            moveq   #0,d0           ;/* clear reg to hold packet */
            nop
    La7:
            btst    #4,(a0)
            beq.b   La8               ;/* handshake */
            dbra    d1,La7
            bra     timeout_err
    La8:
            move.b  (a0),d0         ;/* YO XO YS XS */
            move.b  #0x20,(a0)      ;/* next phase */
            lsl.w   #8,d0           ;/* save nibble */
    La9:
            btst    #4,(a0)
            bne.b   La10              ;/* handshake */
            dbra    d1,La9
            bra     timeout_err
    La10:
            move.b  (a0),d0         ;/* S  M  R  L */
            move.b  #0,(a0)         ;/* next phase */
            lsl.b   #4,d0           ;/* YO XO YS XS S  M  R  L  0  0  0  0 */
            lsl.l   #4,d0           ;/* YO XO YS XS S  M  R  L  0  0  0  0  0  0  0  0 */
    La11:
            btst    #4,(a0)
            beq.b   La12              ;/* handshake */
            dbra    d1,La11
            bra     timeout_err
    La12:
            move.b  (a0),d0         ;/* X7 X6 X5 X4 */
            move.b  #0x20,(a0)      ;/* next phase */
            lsl.b   #4,d0           ;/* YO XO YS XS S  M  R  L  X7 X6 X5 X4 0  0  0  0 */
            lsl.l   #4,d0           ;/* YO XO YS XS S  M  R  L  X7 X6 X5 X4 0  0  0  0  0  0  0  0 */
    La13:
            btst    #4,(a0)
            bne.b   La14              ;/* handshake */
            dbra    d1,La13
            bra     timeout_err
    La14:
            move.b  (a0),d0         ;/* X3 X2 X1 X0 */
            move.b  #0,(a0)         ;/* next phase */
            lsl.b   #4,d0           ;/* YO XO YS XS S  M  R  L  X7 X6 X5 X4 X3 X2 X1 X0 0  0  0  0 */
            lsl.l   #4,d0           ;/* YO XO YS XS S  M  R  L  X7 X6 X5 X4 X3 X2 X1 X0 0  0  0  0  0  0  0  0 */
    La15:
            btst    #4,(a0)
            beq.b   La16              ;/* handshake */
            dbra    d1,La15
            bra     timeout_err
    La16:
            move.b  (a0),d0         ;/* Y7 Y6 Y5 Y4 */
            move.b  #0x20,(a0)      ;/* next phase */
            lsl.b   #4,d0           ;/* YO XO YS XS S  M  R  L  X7 X6 X5 X4 X3 X2 X1 X0 Y7 Y6 Y5 Y4 0  0  0  0 */
            lsl.l   #4,d0           ;/* YO XO YS XS S  M  R  L  X7 X6 X5 X4 X3 X2 X1 X0 Y7 Y6 Y5 Y4 0  0  0  0  0  0  0  0*/
    La17:
            btst    #4,(a0)
            beq.b   La18              ;/* handshake */
            dbra    d1,La17
            bra     timeout_err
    La18:
            move.b  (a0),d0         ;/* Y3 Y2 Y1 Y0 */
            move.b  #0x60,(a0)      ;/* first phase */
            lsl.b   #4,d0           ;/* YO XO YS XS S  M  R  L  X7 X6 X5 X4 X3 X2 X1 X0 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 0  0  0  0 */
            lsr.l   #4,d0           ;/* YO XO YS XS S  M  R  L  X7 X6 X5 X4 X3 X2 X1 X0 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 */
    La19:
            btst    #4,(a0)
            beq.b   La19             ;/* wait on handshake */
    
            move.w  d2,sr           ;/* restore int status */
            move.l d0,(v_mouse_detected).w
            rts
    
    
    timeout_err:
            move.b  #0x60,(a0)      ;/* first phase */
            nop
            nop
    La0b:
            btst    #4,(a0)
            beq.b   La0b              ;/* wait on handshake */
    
            move.w  d2,sr           ;/* restore int status */
            moveq   #-2,d0
            move.l d0,(v_mouse_detected).w
            rts
    
    mky_err:
            move.b  #0x40,6(a0)     ;/* set direction bits */
            nop
            nop
            move.b  #0x40,(a0)
    
            move.w  d2,sr           ;/* restore int status */
            moveq   #-1,d0
            move.l d0,(v_mouse_detected).w
            rts
        
    ; End of function MouseDetect
    
    ; ---------------------------------------------------------------------------
    ; Subroutine to    read joypad input, and send it to the RAM
    ; ---------------------------------------------------------------------------
    
    ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    
    
    ReadJoypads:
            lea    (v_jpadhold1).w,a0 ; address where joypad states are written
            lea    ($A10003).l,a1    ; first    joypad port
            bsr.s    @read        ; do the first joypad
            addq.w    #2,a1        ; do the second    joypad
    
        @read:
            move.b    #0,(a1)
            nop
            nop
            move.b    (a1),d0
            lsl.b    #2,d0
            andi.b    #$C0,d0
            move.b    #$40,(a1)
            nop
            nop
            move.b    (a1),d1
            andi.b    #$3F,d1
            or.b    d1,d0
            not.b    d0
            move.b    (a0),d1
            eor.b    d0,d1
            move.b    d0,(a0)+
            and.b    d0,d1
            move.b    d1,(a0)+
            rts
    ; End of function ReadJoypads
    
    And now, the variables (currently, only "v_mouse_detected" is used):

    Code:
    v_mouse_raw:    equ    $FFFFF5C0
    
    v_mousex_value:    equ    $FFFFF5C4
    v_mousey_value:    equ    $FFFFF5C6
    
    f_mousex_signed:    equ $FFFFF5C8
    f_mousey_signed:    equ $FFFFF5CA
    
    f_mousex_overflow:    equ $FFFFF5CC
    f_mousey_overflow:    equ $FFFFF5CE
    
    v_mouse_detected:    equ    $FFFFF5D0
    As stated previously, I have not made any other changes to the code. From what I can see, RAM/Register values getting trashed isn't the issue, as the routine is called before the initial game mode has even been set. I should probably also mention that this has happened to me in past disassembles of Sonic 1 under similar circumstances; I'd try to add new code or data within the upper portions of the ROM only to have this object vanishing nonsense occur.

    EDIT: Found the issue. Apparently, somewhere along the way, I duplicated an instruction in the Object Manager and it broke everything. I fixed it and things work as expected.
     
    Last edited: Apr 26, 2018
  11. Ashuro

    Ashuro Well-Known Member Member

    Joined:
    Sep 27, 2014
    Messages:
    513
    Location:
    France
    Why all the thread in the Tutorial section disappeared?
     
    jubbalub likes this.
  12. Novedicus

    Novedicus Well-Known Member Member

    Joined:
    Aug 26, 2013
    Messages:
    817
    Because of the eventual move to XenForo 2.
     
  13. LazloPsylus

    LazloPsylus A Certain Scientific Railgun The Railgun

    Joined:
    Nov 25, 2009
    Messages:
    Location:
    Academy City
    There's a lot to sort through, and it was originally intended we get it done, sorted, and released again. Things got tied up, though, and I'm working on it. There's only so much of me to go around, though...
     
  14. Gemini2003

    Gemini2003 Something about the Caravan buggin' you? Trialist

    Joined:
    Sep 2, 2016
    Messages:
    3
    I'm having a small issue with an attempt at porting the Wall Jump from ReadySonic into the 2005 Hivebrain disassembly. Basically, it only partially works. What I mean by this is that while clinging to a wall, I can float away from it by holding in the opposite direction. (shown in image) Also, the "jump" part of the Wall Jump just plain doesn't work at all. I have to use the double jump to replicate the "jump" part, and that just won't cut it.
    On an unrelated note, the rolling and Peelout release sounds sometimes extend and become ear rape after the original sound when I add code, and it's not pleasant on the ears at all. Anyone know how to fix this?
     

    Attached Files:

  15. Iso Kilo

    Iso Kilo Queen of Monitors Member

    Joined:
    Oct 9, 2017
    Messages:
    22
    Location:
    Small Town in BC, Canada
    See, Gemini. There's a bit of a problem here when you're asking this question. You're not giving anyone any code to look at. It's like having a blind person help you pick out what color you should paint your house. Before you know it, you'll have a neon green house, or rather, more issues. If you were to paste the routine, however. You might get a bit of luck. Just saying, :p
     
  16. Gemini2003

    Gemini2003 Something about the Caravan buggin' you? Trialist

    Joined:
    Sep 2, 2016
    Messages:
    3
    Yeah, let me just paste the entire wall jump code that's spread throughout the entirety of sonic1.asm, Kilo. Actually, what am I doing? Now that I've defined BtnL and BtnR, might as well re-copy it from ReadySonic.
     
  17. TheInvisibleSun

    TheInvisibleSun Visible Member

    Joined:
    Jul 2, 2013
    Messages:
    268
    Location:
    Buffalo, NY, USA
    Hey, that was actually sound advice! It's a lot easier to figure out what's going on if you show us the code you added and where.
     
    Pokepunch, Novedicus, Pacca and 3 others like this.
  18. Pacca

    Pacca Level 1 inflatable otter thing Member

    Joined:
    Jul 5, 2014
    Messages:
    1,107
    Location:
    Twinleaf Town
    Or at least explain what you added. If the code differences are really too large, you can use a pastebin link or a spoiler tag so they don't intrude on the readers eyes. A lot of us are happy to help, but without any genuinely useful information, nothing will happen.
     
    Last edited: Apr 27, 2018
  19. Gemini2003

    Gemini2003 Something about the Caravan buggin' you? Trialist

    Joined:
    Sep 2, 2016
    Messages:
    3
    Nevermind, all I had to do was copy an edit of the code from Sonic Retro. It also works in a better way now, so that's cool.
     
  20. Samey

    Samey Newcomer Member

    Joined:
    May 3, 2017
    Messages:
    13
    Alright, I decided to add MegaPcm once more and tried fixing the speedshoes after signpost and fm6 not restoring glitches again.
    I managed to have the speedshoes fix work (albeit, it ends up going to normal speed a couple seconds after you pass the sign post... >->)

    But I'm having trouble trying to fix the fm6 restoration bug. I followed the guide that was on Sonic Retro (Which didn't work...) and then I looked at the guide for MegaPcm to see if there was a specific command Vlad put in to turn it off (If its hidden somewhere, I can't seem to find it). So I'm kinda stumped. ._. Would someone point me in the right direction please?

    Edit: .,. nvm... I figured it out...
    Though I still wonder why the speedshoes doesn't speed down without me having to put in:
    move.w #$E3,d0
    jsr (PlaySound_Special).l ; make Music normal speed
     
    Last edited: May 1, 2018