'Looping' routines

Discussion in 'Discussion and Q&A Archive' started by Psi, Mar 20, 2015.

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

    Psi Well-Known Member Member

    Joined:
    Dec 20, 2014
    Messages:
    98
    Does anyone know how to make certain routines continue on a loop until a certain action is made? Here's the move I have so far:


    ; ---------------------------------------------------------------------------
    ; Subroutine for Sonic's hammer spin animation
    ; ---------------------------------------------------------------------------
     
    ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
     
    Sonic_HammerSpin:
    move.b ($FFFFF603).w,d0 ; move the current button press to d0
    btst #1,($FFFFF602).w ; is Down button pressed?
    beq.s HS_End1 ; if not, return
    and.b #$40,d0 ; get only button A
    beq.s HS_End1 ; if A was pressed, branch
    tst.b ($FFFFFFCC).w ; was jumpdash flag set?
    beq.s HammerSpin_Cont ; if yes, branch
    HS_End1:
    rts
     
    HammerSpin_Cont:
    move.b  #1,($FFFFFFCC).w                ; set jumpdash flag
    move.b  #$20,$1C(a0)                    ; show hammer animation
    move.w  #$BC,d0                         ; set jumpdash sound
    jsr    (PlaySound).l                   ; play jumpdash sound
     
    HammerSpin_Hearts:
    cmpi.b #$20,$1C(a0) ; is Sonic in the jumping animation?
    bne.w HS_End2 ; if not, return
    bsr     SingleObjLoad
    bne     HS_End2
    move.b  #$10,(a1)
    move.l  8(a0),d0
    move.l  $C(a0),$C(a1)
    move.b  #0,$1C(a1) 
    btst    #0,$22(a0)
    beq     @Set1stXPos
    neg     $10(a1)
    move.b  #2,$1C(a1)

    @Set1stXPos:
    move.b  #0*2,$2A(a1)
    bsr     SingleObjLoad
    bne     HS_End2
    move.b  #$10,(a1)
    move.l  8(a0),8(a1)
    move.l  $C(a0),$C(a1)
    move.b  #1,$1C(a1)

    @Set2ndFrameDuration:
    move.b  #2*2,$2A(a1)
    bsr     SingleObjLoad
    bne     HS_End2
    move.b  #$10,(a1)
    move.l  8(a0),d0
    move.l  $C(a0),$C(a1)
    move.b  #2,$1C(a1)
    btst    #0,$22(a0)
    beq     @Set3rdXPos
    neg     $10(a1)
    move.b  #0,$1C(a1)

    @Set3rdXPos:
    move.b  #4*2,$2A(a1)
    bsr     SingleObjLoad
    bne     HS_End2
    move.b  #$10,(a1)
    move.l  8(a0),8(a1)
    move.l  $C(a0),$C(a1)
    move.b  #3,$1C(a1)
     
    @Set4thFrameDuration:
    move.b  #6*2,$2A(a1)

    HS_End2:
    clr.w   $10(a0) ; clear X-velocity to move sonic directly down
    tst.w   $12(a0)                                 ; is Sonic moving upwards?
    bpl.s   HS_End3                                 ; if not, branch
    clr.w   $12(a0)                                 ; clear X-velocity to move sonic directly down
     
    HS_End3:
    rts
    What I want is the four objects to keep loading in this formation until the characters animation changes.
     
    Last edited by a moderator: Mar 20, 2015
  2. Pacca

    Pacca Having an online identity crisis since 2019 Member

    Joined:
    Jul 5, 2014
    Messages:
    1,170
    Location:
    Limbo
    You could set up a mini routine system for this particular block of code; just find an unused ram address to hold the routine counter, and set up a check to add to the routine counter when you want to move on.
     
  3. Psi

    Psi Well-Known Member Member

    Joined:
    Dec 20, 2014
    Messages:
    98
    How would I go about making this mini routine? (sorry I haven't tried much like this before.)
     
    Last edited by a moderator: Mar 20, 2015
  4. N30member

    N30member non-pro user btw Member

    Joined:
    Feb 15, 2014
    Messages:
    216
    Location:
    Kazakhstan
    OR make a direct check for animation (like you did after label HammerSpin_Hearts and do a branch if equal to Sonic_HammerSpin. I'm sorry if this wouldn't work, as you you all know, I still suck at all this...

    EDIT: ninja'd by Psi.
     
    Last edited by a moderator: Mar 20, 2015
  5. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    While I don't exactly understand what you're trying to do, like it was suggested, you could use a secondary routine counter. Whereas a normal routine counter uses $24(a0), you can use $25(a0) as a secondary counter for your objects, and modify your code so it only loads during it's specific routine. When the character's animation has finished, add to the routine counter to stop the 'loop'.

    EDIT: $24 and $25 may have different names in disassemblies that use equates, i.e. routine/routine_secondary or something similar, so for reference, that's what I mean when I talk about them.
     
    Last edited by a moderator: Mar 20, 2015
  6. Psi

    Psi Well-Known Member Member

    Joined:
    Dec 20, 2014
    Messages:
    98
    I haven't worked as much with implementing routines before, could you explain how this would be implemented to make or stop a 'loop'?
     
    Last edited by a moderator: Mar 21, 2015
  7. DanielHall

    DanielHall Well-Known Member Member

    Joined:
    Jan 18, 2010
    Messages:
    860
    Location:
    North Wales
    Sure. It's quite similar to how the object routine counter works at the start of every object. Here's an example:


    ObjXX:

            moveq      #0,d0                      ; Clear d0
    move.b     $24(a0),d0                 ; Move the object's routine counter value into d0.
            move.w     ObjXX_Index(pc,d0.w),d1     ; Add ObjXX_Index+routine counter value, store in d1.
            jmp        ObjXX_Index(pc,d1.w)    ; Jump to appropriate routine.

    ; ===========================================================================

    ObjXX_Index:
            dc.w        ObjXX_InitStuff-ObjXX_Index       ; Will jump here if routine counter is #$0.
            dc.w        ObjXX_AI-ObjXX_Index               ; Will jump here if routine counter is #$2
     
    ; =============================
    ObjXX_InitStuff:
                            addq.b   #2,$24(a0)     ; Add 2 to the routine counter (Now next time the
                                                    ; object code is ran, it'll skip InitStuff and
    ; go straight to AI. This is the loop stop, BTW).
                            *Object init code*
                             rts
    ; ==============================
    ObjXX_AI:
             moveq     #0,d0                       ; Clear d0.
             move.b    $25(a0),d0                  ; Move the 'mini' object counter ($25) value into d0.
             move.w    ObjXX_AITable(pc,d0.w),d1   ; Add ObjXX_AITable+mini routine value, store in d1.
             jmp           ObjXX_AITable(pc,d1.w)  ; Jump to appropriate routine. 
    ; ================================================================================
    ObjXX_AITable:
            dc.w        ObjXX_Function1-ObjXX_AITable   ; Will jump here if mini routine counter is #$0.
            dc.w        ObjXX_Function2-ObjXX_AITable   ; Will jump here if mini routine counter is #$2.
    ; ==============================================
    ObjXX_Function1:
             *conditional code*                        ; Is whatever you want doing what you want?
             beq/bne      Skipadd                      ; If so/not, branch over the routine add.
             addq.b       #2,$25(a0)                   ; Add to mini counter to run Function2.
    Skipadd:
             *etc*
             rts
    ; ===============================================
    ObjXX_Function2:
             *etc*
             rts 

    Now, I'm probably over-complicating your issue, but that's just a basic explanation on how they work. Since you seem to be working with Sonic's object, it might have to go in that HammerSpin routine you made, as this is just an example with a regular object. I don't think Sonic uses $25, so you should be free to use it. Do note that there are probably simpler methods, because I'm not sure with what you're trying to do exactly.     
     
    Last edited by a moderator: Mar 21, 2015
  8. Psi

    Psi Well-Known Member Member

    Joined:
    Dec 20, 2014
    Messages:
    98
    To elaborate on the effect I'm intending, has anyone played Sonic Advance 1? You know the hearts that come out of Amy's hammer when using her attacks? I'm basically implementing that.

    This code in particular is for the Hammer Whirl attack (by holding down + attack), where this rotating trail of hearts follows Amy as long as she is swinging her hammer around. 

    To see the effect I want, look at around 0:56



    What I have now does it, but for only one loop of the four objects, then stops. I need it to keep going on and on like in Advance until the attack stops.
     
    Last edited by a moderator: Mar 21, 2015
  9. Psi

    Psi Well-Known Member Member

    Joined:
    Dec 20, 2014
    Messages:
    98

    OR make a direct check for animation (like you did after label HammerSpin_Hearts and do a branch if equal to Sonic_HammerSpin. I'm sorry if this wouldn't work, as you you all know, I still suck at all this...

    EDIT: ninja'd by Psi.





    Could we compare? I'm certain I've tried this and it just caused the game to freeze. I added this at the end of the objects' code:



    Code:
      cmpi.b #$20,$1C(a0) ; is Sonic in the jumping animation? 
    bne.w HS_End2 ; if not, return
    bra.w HammerSpin_Hearts
     
  10. Selbi

    Selbi The Euphonic Mess Member

    Joined:
    Jul 20, 2008
    Messages:
    2,416
    Location:
    Northern Germany
    A completely different approach would be simply to use one RAM byte as a counter that you set to 4. Every so-and-so frames you check if the counter is zero, and if it isn't decrease the byte by one and spawn a new heart object at Amy's position (plus some repositioning for the hammer). Each heart object would be stationary and simply get deleted after the animation has finished.


    The trickiest part is the repositioning. I wouldn't use a routine counter for that though; a lookup table is more flexible and easier to manage.


    Since I'm not on my pc right now I can't give any examples, but I'll write back later.
     
  11. Selbi

    Selbi The Euphonic Mess Member

    Joined:
    Jul 20, 2008
    Messages:
    2,416
    Location:
    Northern Germany
    ; ---------------------------------------------------------------------------
    ; Subroutine for Amy's hammer spin animation
    ; ---------------------------------------------------------------------------

    ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||

    Sonic_HammerSpin:
    cmpi.b #$20,$1C(a0) ; are we still in the hammer spin animation?
    beq.s HammerSpin_Cont ; if yes, branch
    btst #1,($FFFFF602).w ; is Down button held?
    beq.s HS_End ; if not, return
    btst #6,($FFFFF603).w ; is A pressed?
    beq.s HS_End ; if not, branch

    move.b #1,($FFFFFFCC).w ; set hammer spin flag
    move.b #$20,$1C(a0) ; show hammer spin animation
    move.w #$BC,d0 ; set jumpdash sound
    jsr (PlaySound).l ; play jumpdash sound

    clr.w $10(a0) ; clear X-velocity
    tst.w $12(a0) ; is Amy moving upwards?
    bpl.s HammerSpin_Cont ; if not, branch
    clr.w $12(a0) ; clear y-velocity to move Amy directly down

    HammerSpin_Cont:
    tst.b $1E(a0) ; is frame duration at 0? (is a new frame about to be shown?)
    bne.s HS_End ; if not, branch

    bsr.w SingleObjLoad ; find free object location
    bne.w HS_End ; skip if none was found
    move.b #$10,(a1) ; set it to hearts object

    move.w 8(a0),8(a1) ; copy Amy's x-pos
    move.w $C(a0),$C(a1) ; copy Amy's y-pos

    lea (HS_Deviation).l,a2 ; load position deviation data into a2
    moveq #0,d0 ; clear d0
    move.b $1A(a0),d0 ; load current frame into d0
    subi.b #$50,d0 ; substract $50 (???) from it so the first frame of the animation is at 0 now
    lsl.b #2,d0 ; bit-shift by two to the left (four bytes per entry in HS_Deviation)
    adda.w d0,a2 ; get correct offset for current frame

    move.w (a2)+,d1 ; get x-deviation (and increase pointer to y-deviation)
    btst #0,$22(a0) ; is Amy facing leftwards?
    beq.s @SetXPos ; if not, branch
    neg.w d1 ; if yes, negate x-deviation
    @SetXPos:
    add.w d1,8(a1) ; add deviation to x-pos

    move.w (a2),d1 ; get y-deviation
    add.w d1,$C(a1) ; add deviation to y-pos

    HS_End:
    rts

    ; ---------------------------------------------------------------------------
    HS_Deviation: ; x y
    dc.w $0010, -$0010 ; frame 1
    dc.w -$0010, $0010 ; frame 2
    dc.w -$0010, -$0010 ; frame 3
    dc.w $0010, $0010 ; frame 4
    dc.w -$0010, $0010 ; frame 5
    dc.w -$0010, $0010 ; frame 6
    even
    ; ---------------------------------------------------------------------------Alright, this was more ambitious than I thought, and therefore I can't actually guarrantee that this will work (I had no way to test it, so I wrote it from my head). Anyway, what this code does is to continuously check if the flag is set ($FFCC) and if it isn't, do the regular set-flag-and-play-sound stuff. If it is, however, it simply branches to the execution code at every frame.
    From there the first thing to notice is the check if the animation frame duration is at 0. This is to make sure the hearts are spawned in a synchronized fashion with Amy's hammer spin frames (otherwise there would be a new heart object in every frame). Then comes the normal object loading stuff.

    But here it gets interesting. As I said in my previous post, simply copying over Amy's position is done in two lines. Setting the correct deviation for each frame is a whole different deal, though. Here I did it by assuming the sprites are in a correct order already. All you need to do is to change that $50 to the real offset (see in SonMapEd or something) and then of course set the correct offsets in the table. Finally, actually adding these values to the position.

    I see that in your previous code you do a lot with setting animations, which I assume correspond to the different deviations already. You can remove that and rework Obj10 to simply display one version at all times, no matter where it was spawned, and then delete the object when it reached its last frame.

    To be honest, I'd wish I could directly test it. Remember that my offer in the IRC still stands.

    Edit: Applied some fixes to the code.
     
    Last edited by a moderator: Mar 24, 2015
  12. Psi

    Psi Well-Known Member Member

    Joined:
    Dec 20, 2014
    Messages:
    98
    It seems to be having problems loading at the right position.

    By the subtract code, do you subtract the number where the hammer animation ($20) begins? It starts off at $68, would that be what I put?

    Also the hearts only seem to load when the player is going downward (there doesn't seem to be anything branching past the data if going upward though) and also reappear when going downward with the flag still set, even when not in the hammer animation (eg. if you hammer onto a spring).
     
  13. Selbi

    Selbi The Euphonic Mess Member

    Joined:
    Jul 20, 2008
    Messages:
    2,416
    Location:
    Northern Germany
    $68 should be correct then. As for the other problem, as I said, I have no chance to test this without having access to your disassembly. That's why I'd like to directly discuss this in a chat room, as I've stated before.
     
Thread Status:
Not open for further replies.