[Sonic 1 Github] Basics of Dynamic Level Events, and how to use them in your levels.

Discussion in 'Tutorials' started by Giovanni, Feb 4, 2020.

  1. Giovanni

    Giovanni Well-Known Member Member

    Apr 16, 2015
    Vercelli, Italy
    I've noticed no guide has been made before on this really useful topic, and I've also noticed some hacks that don't make use of these, so I thought that I might make one myself.

    What are Dynamic Level Events?

    Dynamic Level Events (which I'll now refer to as DLEs) are major events that happen when certain conditions are met.

    Let's look at an example.

            cmpi.w    #$D00,(v_screenposx).w
            bcs.s    locret_6F8C
            cmpi.w    #$18,(v_player+obY).w ; has Sonic reached the top of the level?
            bcc.s    locret_6F8C    ; if not, branch
            clr.b    (v_lastlamp).w
            move.w    #1,(f_restart).w ; restart level
            move.w    #(id_SBZ<<8)+2,(v_zone).w ; set level number to 0502 (FZ)
            move.b    #1,(f_lockmulti).w ; freeze Sonic
    This snippet of code has been taken from \_inc\DynamicLevelEvents.asm, and it represents the way SBZ3 takes you to FZ. In case the comments on the code were not good enough for your understanding, what you need to understand is that when Sonic reaches the top boundary of SBZ3 past the X position of $D00, the level will "restart", but will have you taken to the Final Zone. Sonic is also frozen in place while this happens.

    Now that we've looked at this example, it's time I explain to you...

    How to work with DLEs.

    I will present to you two basic examples.

    How to use DLEs to change the level boundaries.

    Imagine this. You are at GHZ2, and you really hate the platforming section in the middle of the level, so you decide that you want to place an S-tube and make a small section that connects perfectly with the rest of the level. You look at what you made proudly, and try out your level, but...

    Sonic dies upon entering the S-tube, because of the lower boundary that was there originally.

    You feel frustrated, because you know that there are several routes that go even lower than that, and you really don't want to put to waste your work.

    But then you realize you can use DLEs.

    So you open up your DynamicLevelEvents.asm file and are presented with this.

            move.w    #$300,(v_limitbtm1).w
            cmpi.w    #$ED0,(v_screenposx).w
            bcs.s    locret_6E3A
            move.w    #$200,(v_limitbtm1).w
            cmpi.w    #$1600,(v_screenposx).w
            bcs.s    locret_6E3A
            move.w    #$400,(v_limitbtm1).w
            cmpi.w    #$1D60,(v_screenposx).w
            bcs.s    locret_6E3A
            move.w    #$300,(v_limitbtm1).w
    What interests you is these lines.
            cmpi.w    #$ED0,(v_screenposx).w
            bcs.s    locret_6E3A
            move.w    #$200,(v_limitbtm1).w
    These lines set the bottom limit to the Y position of #$200 when you reach the X position of #$ED0. Seems like it's what you've been looking for!
    So what will you do?
    A) remove these lines
    B) replace #$ED0 with something else
    C) replace #$200 with something else

    Answer: It depends on the level you're making.

    If you remove these lines, the level will keep the lower boundary limit where it was at the start, or at the last position it was moved to (In this case, at Y position #$300.). If you replace #$ED0, you'll make the limit raise later (or sooner, it depends on what you use.), and if you replace #$200, you will change the bottom limit itself.

    In the case that you've seen earlier, option C seems like the best option, but since I would have to set the limit to #$300, option A is better.

    This is what I obtain if I do it:

    How to use DLEs to relocate Eggman.

    DISCLAIMER: This part of the guide assumes that you already know how to resize levels through the Level Size Array. You will also need boss editing skills if you are going to use this part of the guide.

    You're trying to resize GHZ3, but Eggman gets in the way. So you open up your level editor of choice and try to move Eggman's object. Except he isn't there. But where is he then?

    You see, his spawn position does not depend on the position of an object, but it depends on DLEs as well.

            cmpi.w    #$2960,(v_screenposx).w
            bcs.s    locret_6EE8
            bsr.w    FindFreeObj
            bne.s    loc_6ED0
            move.b    #id_BossGreenHill,0(a1) ; load GHZ boss    object
            move.w    #$2A60,obX(a1)
            move.w    #$280,obY(a1)
    This is the code that spawns Eggman.
    Basically, when the screen reaches the X position of #$2960, the game spawns Eggman at the following coordinates:

    X: #$2A60
    Y: #$280

    Let's just try moving him #$1000 pixels further on the X axis. You should replace #$2960 with #$3960 and #$2A60 with #$3A60 to do so. This way, when the screen reaches the X position of #$3960, the game will spawn Eggman.

    This is the final result:

    It works! Except you'll have to change a few values from the Eggman object to make him act properly...

    Thank you for reading this guide! This is just a fraction of what DLEs can do. Trust me, if used well, they can turn a basic level into something impressive! Your only limitations are your programming knowledge, your imagination and the technical limitations of the hardware.

    If you were already aware of how DLEs worked, then please consider giving me feedback! Did I do a good job at explaining? Are there things that I could improve/fix? I am ready to take your suggestions.
    Last edited: Feb 5, 2020