Basic Questions and Answers Thread

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

  1. Sinkdude

    Sinkdude He looked much leaner on TV Member

    Joined:
    May 6, 2008
    Messages:
    41
    Location:
    Michigan
    Okay. I got almost all of this figured out (part of it thanks to Clownacy and CrazyMonkey16's help). Now the only thing left is to figure out about where "ObjFloorDist2" works in Sonic 2. Normally, the original ObjFloorDist in Sonic 1 is ObjCheckFloorDist in Sonic 2. If ObjFloorDist2 exists in Sonic 1, then where would the other be in Sonic 2, as I couldn't find ObjCheckFloorDist2 in the main .ASM of the Sonic 2 disassembly?
     
  2. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    922
    Everyone just uses the S3K sprites. If it's good enough for Sonic Team, it ought to be good enough for you, right?

    My guide for porting Knuckles to Sonic 2 includes instructions for getting Knuckles' sprite mappings into Sonic 2 format, and a file of Knuckles' art converted for Sonic 2's palette.
     
  3. Clownacy

    Clownacy Retired Staff lolololo Member

    Joined:
    Aug 15, 2014
    Messages:
    1,016
    Isn't it obvious?

    S1
    Code:
    ObjFloorDist:
    		move.w	obX(a0),d3
    
    
    ObjFloorDist2:
    		move.w	obY(a0),d2
    S2
    Code:
    ObjCheckFloorDist:
    	move.w	x_pos(a0),d3
    	move.w	y_pos(a0),d2
    S2 just never used the label (it was only used twice in S1, as is), so the label was never restored during the disassembly process. Just add the label yourself.
     
  4. warr1or2

    warr1or2 I AM CLG Member

    Joined:
    Apr 7, 2008
    Messages:
    416
    Location:
    Town Creek, AL
    Question Concerning Level Porting.
    all this time I was setting HPZ at first to slot 7, then EHZ. I looked through the tutorials & found this http://sonicresearch.org/community/index.php?threads/sonic-1-extending-level-ids.67/ upon reading i found
    is this what i was doing wrong?
     
  5. Sinkdude

    Sinkdude He looked much leaner on TV Member

    Joined:
    May 6, 2008
    Messages:
    41
    Location:
    Michigan
    Very well, and if I'm gonna add the new label, I'll probably have to also port the "ObjFloorDist" and "ObjFloorDis2" from Sonic 1 as well, if necessary.
     
  6. StephenUK

    StephenUK Working on a Quackshot disassembly Member

    Joined:
    Aug 5, 2007
    Messages:
    1,026
    Why? You don't need to port anything, it's already there for you. What Clownacy is saying is turn this:

    Code:
    ObjCheckFloorDist:
        move.w    x_pos(a0),d3
        move.w    y_pos(a0),d2
    Into this:

    Code:
    ObjCheckFloorDist:
        move.w    x_pos(a0),d3
    
    ObjCheckFloorDist2:
        move.w    y_pos(a0),d2
    And then point any references to ObjFloorDist2 from S1 towards ObjCheckFloorDist2 in your S2 disassembly if you port things over that require it. It's not hard really.
     
  7. Sinkdude

    Sinkdude He looked much leaner on TV Member

    Joined:
    May 6, 2008
    Messages:
    41
    Location:
    Michigan
    Alrighty, I've made the change, added the Burrobot object in the beginning of Act 1 of Emerald Hill Zone as a test-out, and built the rom. Now I've got a big problem: after the title card for this level comes up, it just freezes the game right there. What am I doing wrong from there? Maybe the problem lies somewhere in the code. In case you're wondering, here's the object's code (with coding for its mappings and animation):

    Code:
    ; ---------------------------------------------------------------------------
    ; Object 4C - Burrobot enemy (LZ)
    ; ---------------------------------------------------------------------------
    
    Obj4C:
            moveq    #0,d0
            move.b    routine(a0),d0
            move.w    Burro_Index(pc,d0.w),d1
            jmp    Burro_Index(pc,d1.w)
    ; ===========================================================================
    Burro_Index:    dc.w Burro_Main-Burro_Index
            dc.w Burro_Action-Burro_Index
    
    timedelay:    = $30        ; time between direction changes
    ; ===========================================================================
    
    Burro_Main:    ; Routine 0
            addq.b    #2,routine(a0)
            move.b    #$13,y_radius(a0)
            move.b    #8,x_radius(a0)
            move.l    #Map_Burro,mappings(a0)
            move.w    #$4A6,art_tile(a0)
            ori.b    #4,render_flags(a0)
            move.b    #4,priority(a0)
            move.b    #5,collision_flags(a0)
            move.b    #$C,width_pixels(a0)
            addq.b    #6,routine_secondary(a0) ; run "Burro_ChkSonic" routine
            move.b    #2,anim(a0)
    
    Burro_Action:    ; Routine 2
            moveq    #0,d0
            move.b    routine_secondary(a0),d0
            move.w    index(pc,d0.w),d1
            jsr    index(pc,d1.w)
            lea    (Ani_Burro).l,a1
            jsr    AnimateSprite
            jmp    MarkObjGone
    ; ===========================================================================
    index:        dc.w changedir-index
            dc.w Burro_Move-index
            dc.w Burro_Jump-index
            dc.w Burro_ChkSonic-index
    ; ===========================================================================
    
    changedir:
            subq.w    #1,timedelay(a0)
            bpl.s    nochg
            addq.b    #2,routine_secondary(a0)
            move.w    #255,timedelay(a0)
            move.w    #$80,x_vel(a0)
            move.b    #1,anim(a0)
            bchg    #0,status(a0)    ; change direction the Burrobot    is facing
            beq.s    nochg
            neg.w    x_vel(a0)    ; change direction the Burrobot    is moving
    
        nochg:
            rts  
    ; ===========================================================================
    
    Burro_Move:
            subq.w    #1,timedelay(a0)
            bmi.s    loc_100338
            jsr    ObjectMove
            bchg    #0,$32(a0)
            bne.s    loc_10032C
            move.w    x_pos(a0),d3
            addi.w    #$C,d3
            btst    #0,status(a0)
            bne.s    loc_10031E
            subi.w    #$18,d3
    
    loc_10031E:
            jsr    ObjCheckFloorDist2
            cmpi.w    #$C,d1
            bge.s    loc_100338
            rts  
    ; ===========================================================================
    
    loc_10032C:
            jsr    ObjCheckFloorDist
            add.w    d1,y_pos(a0)
            rts  
    ; ===========================================================================
    
    loc_100338:
            btst    #2,(Vint_runcount+3).w
            beq.s    loc_100358
            subq.b    #2,routine_secondary(a0)
            move.w    #59,timedelay(a0)
            move.w    #0,x_vel(a0)
            move.b    #0,anim(a0)
            rts  
    ; ===========================================================================
    
    loc_100358:
            addq.b    #2,routine_secondary(a0)
            move.w    #-$400,y_vel(a0)
            move.b    #2,anim(a0)
            rts  
    ; ===========================================================================
    
    Burro_Jump:
            jsr    ObjectMove
            addi.w    #$18,y_vel(a0)
            bmi.s    locret_1003A4
            move.b    #3,anim(a0)
            jsr    ObjCheckFloorDist
            tst.w    d1
            bpl.s    locret_1003A4
            add.w    d1,y_pos(a0)
            move.w    #0,y_vel(a0)
            move.b    #1,anim(a0)
            move.w    #255,timedelay(a0)
            subq.b    #2,routine_secondary(a0)
            bsr.w    Burro_ChkSonic2
    
    locret_1003A4:
            rts  
    ; ===========================================================================
    
    Burro_ChkSonic:
            move.w    #$60,d2
            bsr.w    Burro_ChkSonic2
            bcc.s    locret_1003D4
            move.w    (MainCharacter+y_pos).w,d0
            sub.w    y_pos(a0),d0
            bcc.s    locret_1003D4
            cmpi.w    #-$80,d0
            bcs.s    locret_1003D4
            tst.w    (Debug_placement_mode).w
            bne.s    locret_1003D4
            subq.b    #2,routine_secondary(a0)
            move.w    d1,x_vel(a0)
            move.w    #-$400,y_vel(a0)
    
    locret_1003D4:
            rts  
    
    ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    
    
    Burro_ChkSonic2:
            move.w    #$80,d1
            bset    #0,status(a0)
            move.w    (MainCharacter+x_pos).w,d0
            sub.w    x_pos(a0),d0
            bcc.s    loc_1003F4
            neg.w    d0
            neg.w    d1
            bclr    #0,status(a0)
    
    loc_1003F4:
            cmp.w    d2,d0
            rts  
    ; End of function Burro_ChkSonic2
    
    ; ---------------------------------------------------------------------------
    ; Sprite mappings - Burrobot enemy (LZ)
    ; ---------------------------------------------------------------------------
    Map_Burro:    dc.w walk1-Map_Burro
            dc.w walk2-Map_Burro
            dc.w digging1-Map_Burro
            dc.w digging2-Map_Burro
            dc.w fall-Map_Burro
            dc.w facedown-Map_Burro
            dc.w walk3-Map_Burro
    walk1:        dc.b 2
            dc.b $EC, $A, 0, 0, $F0    ; walking
            dc.b 4,    9, 0, 9, $F4
    walk2:        dc.b 2
            dc.b $EC, $A, 0, $F, $F0
            dc.b 4,    9, 0, $18, $F4
    digging1:    dc.b 2
            dc.b $E8, $A, 0, $1E, $F4 ; digging
            dc.b 0,    $A, 0, $27, $F4
    digging2:    dc.b 2
            dc.b $E8, $A, 0, $30, $F4
            dc.b 0,    $A, 0, $39, $F4
    fall:        dc.b 2
            dc.b $E8, $A, 0, $F, $F0 ; falling after jumping up
            dc.b 0,    $A, 0, $42, $F4
    facedown:    dc.b 2
            dc.b $F4, 6, 0,    $4B, $E8 ; facing down (unused)
            dc.b $F4, $A, 0, $51, $F8
    walk3:        dc.b 2
            dc.b $EC, $A, 0, $F, $F0
            dc.b 4,    9, 0, 9, $F4
            even
          
    ; ---------------------------------------------------------------------------
    ; Animation script - Burrobot enemy
    ; ---------------------------------------------------------------------------
    Ani_Burro:    dc.w _walk1-Ani_Burro
            dc.w _walk2-Ani_Burro
            dc.w _digging-Ani_Burro
            dc.w _fall-Ani_Burro
    _walk1:        dc.b 3,    0, 6, $FF
    _walk2:        dc.b 3,    0, 1, $FF
    _digging:    dc.b 3,    2, 3, $FF
    _fall:        dc.b 3,    4, $FF
            even
     
  8. Devon

    Devon Down you're going... down you're going... Member

    Joined:
    Aug 26, 2013
    Messages:
    1,372
    Location:
    your mom
    Have you converted the mappings to Sonic 2 format?
     
  9. Clownacy

    Clownacy Retired Staff lolololo Member

    Joined:
    Aug 15, 2014
    Messages:
    1,016
    Since each piece is five bytes, I'm pretty sure they're still in S1's format. @Sinkdude, if you want to convert them yourself, you can compare this and this, or do it automatically.

    If you want to do it automatically, you'd be best off 'splitting' the mapping data into its own file, done by simply cutting and pasting the mapping data into its own text file, then filling the space where it used to be with a 'binclude'. You can load this new file into SonMapEd, and convert it using that, or use MainMemory's MappingsConverter.
     
    Last edited: Mar 15, 2016
  10. Sinkdude

    Sinkdude He looked much leaner on TV Member

    Joined:
    May 6, 2008
    Messages:
    41
    Location:
    Michigan
    Formats for the mappings are now changed, I built the rom again, and the game no longer freezes after the level title card. This object is now successfully functional. Just need to change the object's VRAM mappings location (which shouldn't be hard to do) and I'm good to go. Thanks for helping me out with most of the code, Clownacy. Not to mention StephenUK and CrazyMonkey16 for a couple parts, too.
     
  11. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    So I actually got Sonic 3's Object Manager working in Sonic 1 and I plan on making a guide for it in the future but for some reason low numbered objects (Player characters and title screen elements) start spawning and eventually cause the game to crash. Replacing a level's object list with ObjPos_Null won't spawn anything at all (including unwanted objects) and commenting out lines that load an object's id will still make the unwanted objects spawn. Also, Something must be interfering with the subtypes because ring groups sometimes appear in different formations than intended. These things happen on clean disassemblies and the hack I'm currently working on.

    Here is the code:
    Code:
    ; ---------------------------------------------------------------------------
    ; Objects Manager
    ; Subroutine to load objects whenever they are close to the screen. Unlike in
    ; normal s2, in this version every object gets an entry in the respawn table.
    ; This is necessary to get the additional y-range checks to work.
    ;
    ; input variables:
    ;  -none-
    ;
    ; writes:
    ;  d0, d1, d2
    ;  d3 = upper boundary to load object
    ;  d4 = lower boundary to load object
    ;  d5 = #$FFF, used to filter out object's y position
    ;  d6 = camera position
    ;
    ;  a0 = address in object placement list
    ;  a3 = address in object respawn table
    ;  a6 = object loading routine
    ; ---------------------------------------------------------------------------
    ; loc_17AA4
    ObjPosLoad:
            moveq    #0,d0
            move.b    ($FFFFF76C).w,d0
            jmp    ObjPosLoad_States(pc,d0.w)
    ; ============== JUMP TABLE    =============================================
    ObjPosLoad_States:
            bra.w    ObjPosLoad_Init        ; 0
            bra.w    ObjPosLoad_Main        ; 2
            bra.w    ObjPosLoad_Main        ; 4
    ; ============== END JUMP TABLE    =============================================
    ObjPosLoad_Init:
            addq.b    #4,($FFFFF76C).w
    
            lea     ($FFFFF000).w,a0
            moveq   #0,d0
            move.w  #$BF,d1 ; set loop counter
    OPL1:
            move.l  d0,(a0)+
            dbf     d1,OPL1
            move.w    ($FFFFFE10).w,d0
    ;
    ;    ror.b    #1,d0            ; this is from s3k
    ;    lsr.w    #5,d0
    ;    lea    (ObjPos_Index).l,a0
    ;    movea.l    (a0,d0.w),a0
    ;
            lsl.b    #6,d0            ; then this yields $87...
            lsr.w    #4,d0            ; and this yields $0002.
            lea    (ObjPos_Index).l,a0    ; load the first pointer in the object layout list pointer index,
            adda.w    (a0,d0.w),a0        ; load the pointer to the current object layout
            ; initialize each object load address with the first object in the layout
            move.l    a0,($FFFFF770).w
            move.l    a0,($FFFFF774).w
            lea    ($FFFFF000).w,a3
            move.w    ($FFFFF700).w,d6
            subi.w    #$80,d6    ; look one chunk to the left
            bcc.s    OPL2    ; if the result was negative,
            moveq    #0,d6    ; cap at zero
    OPL2:    andi.w    #$FF80,d6    ; limit to increments of $80 (width of a chunk)
            movea.l    ($FFFFF770).w,a0    ; get first object in layout
    OPL3:    ; at the beginning of a level this gives respawn table entries to any object that is one chunk
            ; behind the left edge of the screen that needs to remember its state (Monitors, Badniks, etc.)
            cmp.w    (a0),d6        ; is object's x position >= d6?
            bls.s    OPL4        ; if yes, branch
            addq.w    #6,a0    ; next object
            addq.w    #1,a3    ; respawn index of next object going right
            bra.s    OPL3
    ; ===========================================================================
    OPL4:    move.l    a0,($FFFFF770).w    ; remember rightmost object that has been processed, so far (we still need to look forward)
            move.w    a3,($FFFFF778).w    ; and its respawn table index
            lea    ($FFFFF000).w,a3    ; reset a3
            movea.l    ($FFFFF774).w,a0    ; reset a0
            subi.w    #$80,d6        ; look even farther left (any object behind this is out of range)
            bcs.s    OPL6        ; branch, if camera position would be behind level's left boundary
    OPL5:    ; count how many objects are behind the screen that are not in range and need to remember their state
            cmp.w    (a0),d6        ; is object's x position >= d6?
            bls.s    OPL6        ; if yes, branch
            addq.w    #6,a0
            addq.w    #1,a3    ; respawn index of next object going left
            bra.s    OPL5    ; continue with next object
    ; ===========================================================================
    OPL6:    move.l    a0,($FFFFF774).w    ; remember current object from the left
            move.w    a3,($FFFFF77C).w    ; and its respawn table index
            move.w    #-1,($FFFFF76E).w    ; make sure ObjPosLoad_GoingForward is run
            move.w    ($FFFFF704).w,d0
            andi.w    #$FF80,d0
            move.w    d0,($FFFFFE2A).w    ; make sure the Y check isn't run unnecessarily during initialization
    ; ===========================================================================
    ObjPosLoad_Main:
            ; get coarse camera position
    
            move.w    ($FFFFF700).w,d1
            subi.w    #$80,d1
            andi.w    #$FF80,d1
            move.w    d1,($FFFFFFEA).w
            tst.w    ($FFFFF72E).w    ; does this level y-wrap?
            bpl.s    ObjMan_Main_NoYWrap    ; if not, branch
            lea    (ChkLoadObj_YWrap).l,a6    ; set object loading routine
            move.w    ($FFFFF704).w,d3
            andi.w    #$FF80,d3    ; get coarse value
            move.w    d3,d4
            addi.w    #$200,d4    ; set lower boundary
            subi.w    #$80,d3        ; set upper boundary
            bpl.s    OPL7        ; branch, if upper boundary > 0
            andi.w    #$7FF,d3    ; wrap value
            bra.s    ObjMan_Main_Cont
    ; ===========================================================================
    OPL7:    move.w    #$7FF,d0
            addq.w    #1,d0
            cmp.w    d0,d4
            bls.s    OPL8        ; branch, if lower boundary < $7FF
            andi.w    #$7FF,d4    ; wrap value
            bra.s    ObjMan_Main_Cont
    ; ===========================================================================
    ObjMan_Main_NoYWrap:
            move.w    ($FFFFF704).w,d3
            andi.w    #$FF80,d3    ; get coarse value
            move.w    d3,d4
            addi.w    #$200,d4    ; set lower boundary
            subi.w    #$80,d3        ; set upper boundary
            bpl.s    OPL8
            moveq    #0,d3    ; no negative values allowed
    OPL8:   lea    (ChkLoadObj).l,a6    ; set object loading routine
    ObjMan_Main_Cont:
            move.w    #$FFF,d5    ; this will be used later when we load objects
            move.w    ($FFFFF700).w,d6
            andi.w    #$FF80,d6
            cmp.w    ($FFFFF76E).w,d6    ; is the X range the same as last time?
            beq.w    ObjPosLoad_SameXRange    ; if yes, branch
            bge.s    ObjPosLoad_GoingForward    ; if new pos is greater than old pos, branch
            ; if the player is moving back
            move.w    d6,($FFFFF76E).w    ; remember current position for next time
            movea.l    ($FFFFF774).w,a0    ; get current object going left
            movea.w    ($FFFFF77C).w,a3    ; and its respawn table index
            subi.w    #$80,d6            ; look one chunk to the left
            bcs.s    ObjMan_GoingBack_Part2    ; branch, if camera position would be behind level's left boundary
            jsr    (SingleObjLoad).l        ; find an empty object slot
            bne.s    ObjMan_GoingBack_Part2        ; branch, if there are none
    OPL9:    ; load all objects left of the screen that are now in range
            cmp.w    -6(a0),d6        ; is the previous object's X pos less than d6?
            bge.s    ObjMan_GoingBack_Part2    ; if it is, branch
            subq.w    #6,a0        ; get object's address
            subq.w    #1,a3        ; and respawn table index
            jsr    (a6)        ; load object
            bne.s    OPL10        ; branch, if SST is full
            subq.w    #6,a0
            bra.s    OPL9    ; continue with previous object
    ; ===========================================================================
    OPL10:    ; undo a few things, if the object couldn't load
            addq.w    #6,a0    ; go back to last object
            addq.w    #1,a3    ; since we didn't load the object, undo last change
    ObjMan_GoingBack_Part2:
            move.l    a0,($FFFFF774).w    ; remember current object going left
            move.w    a3,($FFFFF77C).w    ; and its respawn table index
            movea.l    ($FFFFF770).w,a0    ; get next object going right
            movea.w    ($FFFFF778).w,a3    ; and its respawn table index
            addi.w    #$300,d6    ; look two chunks beyond the right edge of the screen
    OPL11:    ; subtract number of objects that have been moved out of range (from the right side)
            cmp.w    -6(a0),d6    ; is the previous object's X pos less than d6?
            bgt.s    OPL12        ; if it is, branch
            subq.w    #6,a0        ; get object's address
            subq.w    #1,a3        ; and respawn table index
            bra.s    OPL11    ; continue with previous object
    ; ===========================================================================
    OPL12:    move.l    a0,($FFFFF770).w    ; remember next object going right
            move.w    a3,($FFFFF778).w    ; and its respawn table index
            bra.s    ObjPosLoad_SameXRange
    ; ===========================================================================
    ObjPosLoad_GoingForward:
            move.w    d6,($FFFFF76E).w
            movea.l    ($FFFFF770).w,a0    ; get next object from the right
            movea.w ($FFFFF778).w,a3    ; and its respawn table index
            addi.w    #$280,d6    ; look two chunks forward
            jsr    (SingleObjLoad).l        ; find an empty object slot
            bne.s    ObjMan_GoingForward_Part2    ; branch, if there are none
    OPL13:    ; load all objects right of the screen that are now in range
            cmp.w    (a0),d6                ; is object's x position >= d6?
            bls.s    ObjMan_GoingForward_Part2    ; if yes, branch
            jsr    (a6)        ; load object (and get address of next object)
            addq.w    #1,a3        ; respawn index of next object to the right
            beq.s    OPL13    ; continue loading objects, if the SST isn't full
    ObjMan_GoingForward_Part2:
            move.l    a0,($FFFFF770).w    ; remember next object from the right
            move.w    a3,($FFFFF778).w    ; and its respawn table index
            movea.l    ($FFFFF774).w,a0    ; get current object from the left
            movea.w    ($FFFFF77C).w,a3    ; and its respawn table index
            subi.w    #$300,d6        ; look one chunk behind the left edge of the screen
            bcs.s    ObjMan_GoingForward_End    ; branch, if camera position would be behind level's left boundary
    OPL14:    ; subtract number of objects that have been moved out of range (from the left)
            cmp.w    (a0),d6            ; is object's x position >= d6?
            bls.s    ObjMan_GoingForward_End    ; if yes, branch
            addq.w    #6,a0    ; next object
            addq.w    #1,a3    ; respawn index of next object to the left
            bra.s    OPL14    ; continue with next object
    ; ===========================================================================
    
    ObjMan_GoingForward_End:
            move.l    a0,($FFFFF774).w    ; remember current object from the left
            move.w    a3,($FFFFF77C).w    ; and its respawn table index
    ObjPosLoad_SameXRange:
            move.w    ($FFFFF704).w,d6
            andi.w    #$FF80,d6
            move.w    d6,d3
            cmp.w    ($FFFFFE2A).w,d6    ; is the y range the same as last time?
            beq.w    ObjPosLoad_SameYRange    ; if yes, branch
            bge.s    ObjPosLoad_GoingDown    ; if the player is moving down
            ; if the player is moving up
            tst.w    ($FFFFF72E).w    ; does the level y-wrap?
            bpl.s    ObjMan_GoingUp_NoYWrap    ; if not, branch
            tst.w    d6
            bne.s    ObjMan_GoingUp_YWrap
            cmpi.w    #$80,($FFFFFE2A).w
            bne.s    ObjMan_GoingDown_YWrap
    ObjMan_GoingUp_YWrap:
            subi.w    #$80,d3            ; look one chunk up
            bpl.s    ObjPosLoad_YCheck    ; go to y check, if camera y position >= $80
            andi.w    #$7FF,d3        ; else, wrap value
            bra.s    ObjPosLoad_YCheck
    ; ===========================================================================
    ObjMan_GoingUp_NoYWrap:
            subi.w    #$80,d3                ; look one chunk up
            bmi.w    ObjPosLoad_SameYRange    ; don't do anything if camera y position is < $80
            bra.s    ObjPosLoad_YCheck
    ; ===========================================================================
    ObjPosLoad_GoingDown:
            tst.w    ($FFFFF72E).w        ; does the level y-wrap?
            bpl.s    ObjMan_GoingDown_NoYWrap    ; if not, branch
            tst.w    ($FFFFFE2A).w
            bne.s    ObjMan_GoingDown_YWrap
            cmpi.w    #$80,d6
            bne.s    ObjMan_GoingUp_YWrap
    ObjMan_GoingDown_YWrap:
            addi.w    #$180,d3        ; look one chunk down
            cmpi.w    #$7FF,d3
            bcs.s    ObjPosLoad_YCheck    ; go to  check, if camera y position < $7FF
            andi.w    #$7FF,d3        ; else, wrap value
            bra.s    ObjPosLoad_YCheck
    ; ===========================================================================
    ObjMan_GoingDown_NoYWrap:
            addi.w    #$180,d3            ; look one chunk down
            cmpi.w    #$7FF,d3
            bhi.s    ObjPosLoad_SameYRange    ; don't do anything, if camera is too close to bottom
    ObjPosLoad_YCheck:
            jsr    (SingleObjLoad).l        ; get an empty object slot
            bne.s    ObjPosLoad_SameYRange    ; branch, if there are none
            move.w    d3,d4
            addi.w    #$80,d4
            move.w    #$FFF,d5    ; this will be used later when we load objects
            movea.l    ($FFFFF774).w,a0    ; get next object going left
            movea.w    ($FFFFF77C).w,a3    ; and its respawn table index
            move.l    ($FFFFF770).w,d7    ; get next object going right
            sub.l    a0,d7    ; d7 = number of objects between the left and right boundaries * 6
            beq.s    ObjPosLoad_SameYRange    ; branch if there are no objects inbetween
            addq.w    #2,a0    ; align to object's y position
    OPL15:    ; check, if current object needs to be loaded
            tst.b    (a3)    ; is object already loaded?
            bmi.s    OPL16    ; if yes, branch
            move.w    (a0),d1
            and.w    d5,d1    ; get object's y position
            cmp.w    d3,d1
            bcs.s    OPL16    ; branch, if object is out of range from the top
            cmp.w    d4,d1
            bhi.s    OPL16    ; branch, if object is out of range from the bottom
            bset    #7,(a3)    ; mark object as loaded
            ; load object
            move.w    -4(a0),8(a1)
            move.w    (a0),d1
            move.w    d1,d2
            and.w    d5,d1    ; get object's y position
            move.w    d1,$C(a1)
            rol.w    #3,d2
            andi.w    #3,d2    ; get object's render flags and status
            move.b    d2,1(a1)
            move.b    d2,$22(a1)
            move.b    4(a0),0(a1)
            move.b    3(a0),$28(a1)
            move.w    a3,$1E(a1)
            jsr    (SingleObjLoad).l    ; find new object slot
            bne.s    ObjPosLoad_SameYRange    ; brach, if there are none left
    OPL16:
            addq.w    #6,a0    ; address of next object
            addq.w    #1,a3    ; and its respawn index
            subq.w    #6,d7    ; subtract from size of remaining objects
            bne.s    OPL15    ; branch, if there are more
    ObjPosLoad_SameYRange:
            move.w    d6,($FFFFFE2A).w
            rts
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Subroutines to check if an object needs to be loaded,
    ; with and without y-wrapping enabled.
    ;
    ; input variables:
    ;  d3 = upper boundary to load object
    ;  d4 = lower boundary to load object
    ;  d5 = #$FFF, used to filter out object's y position
    ;
    ;  a0 = address in object placement list
    ;  a1 = object
    ;  a3 = address in object respawn table
    ;
    ; writes:
    ;  d1, d2, d7
    ; ---------------------------------------------------------------------------
    ChkLoadObj_YWrap:
            tst.b    (a3)    ; is object already loaded?
            bpl.s    OPL17    ; if not, branch
            addq.w    #6,a0    ; address of next object
            moveq    #0,d1    ; let the objects manager know that it can keep going
            rts
    ; ===========================================================================
    OPL17:    move.w    (a0)+,d7    ; x_pos
            move.w    (a0)+,d1    ; there are three things stored in this word
            move.w    d1,d2    ; does this object skip y-Checks?
            bmi.s    OPL18    ; if yes, branch
            and.w    d5,d1    ; y_pos
            cmp.w    d3,d1
            bcc.s    LoadObj_YWrap
            cmp.w    d4,d1
            bls.s    LoadObj_YWrap
            addq.w    #2,a0    ; address of next object
            moveq    #0,d1    ; let the objects manager know that it can keep going
            rts
    ; ===========================================================================
    OPL18:    and.w    d5,d1    ; y_pos
    LoadObj_YWrap:
            bset    #7,(a3)    ; mark object as loaded
            move.w    d7,8(a1)
            move.w    d1,$C(a1)
            rol.w    #3,d2    ; adjust bits
            andi.w    #3,d2    ; get render flags and status
            move.b    d2,1(a1)
            move.b    d2,$22(a1)
            move.b    (a0)+,d0
            bpl.s    loc_DA80
            andi.b    #$7F,d0
    
    loc_DA80:
            move.b    d0,0(a1)
            move.b    (a0)+,$28(a1)
            move.w    a3,$1E(a1)
            bra.s    SingleObjLoad    ; find new object slot
    ;loc_17F36
    ChkLoadObj:
            tst.b    (a3)    ; is object already loaded?
            bpl.s    OPL19    ; if not, branch
            addq.w    #6,a0    ; address of next object
            moveq    #0,d1    ; let the objects manager know that it can keep going
            rts
    ; ===========================================================================
    OPL19:    move.w    (a0)+,d7    ; x_pos
            move.w    (a0)+,d1    ; there are three things stored in this word
            move.w    d1,d2    ; does this object skip y-Checks?    ;*6
            bmi.s    OPL21    ; if yes, branch
            and.w    d5,d1    ; y_pos
            cmp.w    d3,d1
            bcs.s    OPL20    ; branch, if object is out of range from the top
            cmp.w    d4,d1
            bls.s    LoadObj    ; branch, if object is in range from the bottom
    OPL20:
            addq.w    #2,a0    ; address of next object
            moveq    #0,d1
            rts
    ; ===========================================================================
    OPL21:    and.w    d5,d1    ; y_pos
    LoadObj:
            bset    #7,(a3)    ; mark object as loaded
            move.w    d7,8(a1)
            move.w    d1,$C(a1)
            rol.w    #2,d2    ; adjust bits
            andi.w    #3,d2    ; get render flags and status
            move.b    d2,1(a1)
            move.b    d2,$22(a1)
            move.b    (a0)+,d0
            bpl.s    loc_DA802
            andi.b    #$7F,d0
    
    loc_DA802:
            move.b    d0,0(a1)
            move.b    (a0)+,$28(a1)
            move.w    a3,$1E(a1)
            ; continue straight to SingleObjLoad
    ; End of function ChkLoadObj
    $FFFFF000 is the respawn table and is $300 bytes long.
    $1E(a0) is the SST entry for each object's respawn index and is a word.
    $FFFFF770 and $FFFFF774 are the right and left load addresses respectively and are both long words.
    $FFFFF778 and $FFFFF77C are the right and left respawn indexes respectively and are both long words.

    Edit: The code is ported from this guide: http://info.sonicretro.org/SCHG_How-to:Port_S3K_Object_Manager_into_Sonic_2
     
    Last edited: Mar 18, 2016
  12. FireRat

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

    Joined:
    Oct 31, 2009
    Messages:
    535
    Maybe you need to either convert from the original file formats or edit the manager to work with your current? It seems to be going out of bounds. Do not forget to fix the formatting of the bytes at the start and end of array of included files; these are meant to act like "bounds" for the manager too.
     
    Last edited: Mar 18, 2016
  13. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    The file formats for each object position list is the same between both Sonic 2 and Sonic 1 aside from the bits used for mirroring, flipping, and saving an object's state and those still work the way they originally did in Sonic 1. ObjPos_Index, which is what I assume is the array you're talking about, is exactly the same as in Sonic 1 so it can't be the problem. Unless you're talking about something different, those aren't likely to be the case.
     
  14. ProjectFM

    ProjectFM Optimistic and self-dependent Member

    Joined:
    Oct 4, 2014
    Messages:
    912
    Location:
    Orono, Maine
    Sorry for double posting. I found the section of code that causes unwanted objects to spawn but I can't figure out how to fix it. It is an different version of the ChkLoadObj routine used in certain situations.
    Code:
    OPL15:    ; check, if current object needs to be loaded
            tst.b    (a3)    ; is object already loaded?
            bmi.s    OPL16    ; if yes, branch
            move.w    (a0),d1
            and.w    d5,d1    ; get object's y position
            cmp.w    d3,d1
            bcs.s    OPL16    ; branch, if object is out of range from the top
            cmp.w    d4,d1
            bhi.s    OPL16    ; branch, if object is out of range from the bottom
            bset    #7,(a3)    ; mark object as loaded
            ; load object
            move.w    -4(a0),8(a1)
            move.w    (a0),d1
            move.w    d1,d2
            and.w    d5,d1    ; get object's y position
            move.w    d1,$C(a1)
            rol.w    #2,d2
            andi.w    #3,d2    ; get object's render flags and status
            move.b    d2,1(a1)
            move.b    d2,$22(a1)
            move.b    4(a0),0(a1) ; this is the line that is spawning unwanted stuff and I can't figure out why it doesn't work right
            move.b    5(a0),$28(a1)
            move.w    a3,$1E(a1)
            jsr    (SingleObjLoad).l    ; find new object slot
            bne.s    ObjPosLoad_SameYRange    ; brach, if there are none left
    OPL16:
            addq.w    #6,a0    ; address of next object
            addq.w    #1,a3    ; and its respawn index
            subq.w    #6,d7    ; subtract from size of remaining objects
            bne.s    OPL15    ; branch, if there are more
    ObjPosLoad_SameYRange:
            move.w    d6,($FFFFFE2A).w
            rts   
    Edit: Fixed!
     
    Last edited: Mar 20, 2016
  15. Pokepunch

    Pokepunch That guy who posts on occasion Member

    Joined:
    Aug 7, 2009
    Messages:
    270
    Location:
    UK
    How would I check if the game is being played on a US Genesis?
     
  16. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    The I/O chip has a version register mapped to the address $A10001, with the bitfield:

    RPD0VVVV

    Where:-

    R - Region. 0 for a domestic console, 1 for an overseas model.
    P - Set to 1 if the system is a PAL console.
    D - Detects the Sega CD.
    V - Console version.

    The bits you want will be both the R and P bits, set to 1 and 0, respectively (NTSC overseas); You can do a compare for them, Like this:

    Code:
    move.b ($A10001).l,d0            ; Load the version register bit status into d0.
    andi.b   #$C0,d0                      ; Clear unnecessary bits.
    cmpi.b  #$80,d0                       ; Are bits R = 1 and P = 0?
    beq/bne label                           ; If they are/aren't, branch.
    
     
    Pokepunch likes this.
  17. Devon

    Devon Down you're going... down you're going... Member

    Joined:
    Aug 26, 2013
    Messages:
    1,372
    Location:
    your mom
    The byte located at $A10001 holds information about the system version of the console on which the ROM runs on. Bit 7 indicates whether it's a domestic system or an overseas system. If set, it indicates that it's an overseas system. Bit 6 indicates whether it's in PAL format or NTSC format. If set, it indicates that it's in PAL format. You can use this bit to distinguish a USA system from a European system.

    You can AND this byte with $C0, to mask out the lower 6 bits. You can use this to do cmp instructions instead of 2 btst instructions. In Sonic 1, the byte is AND'd and stored into $FFFFFFF8.

    EDIT: Dandaman, how dare you ninja me.
     
    Last edited: Mar 21, 2016
    Pokepunch likes this.
  18. Pokepunch

    Pokepunch That guy who posts on occasion Member

    Joined:
    Aug 7, 2009
    Messages:
    270
    Location:
    UK
    Thanks for the help guys.
     
  19. GenesisDoes

    GenesisDoes What Nintendont Member

    Joined:
    Jan 2, 2016
    Messages:
    159
    Location:
    Pittsburgh, PA
    Two questions about S1 Github:

    1. How can I make BG Chunks have the same scrolling style as the FG Chunks, preferably in file "_inc/DeformLayers.asm" ? In other words, have the BG chunks directly behind the FG chunks?

    2, How can I auto-scroll chunks and objects for a level? An example would be the earthquake section in MGZ and SSZ1 in S3/K, though I cannot seem to neither understand or locate the game code sections that handles this in the S3K disasm.
     
  20. Clownacy

    Clownacy Retired Staff lolololo Member

    Joined:
    Aug 15, 2014
    Messages:
    1,016
    S3K achieves that 'scrolling chunks' thing by splitting the level between the FG plane and the BG plane. S2 does a similar thing with the HTZ rising lava. I'm not sure if the two are related code-wise, though.