Basic Questions and Answers Thread

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

  1. Superandroidtron

    Superandroidtron Newcomer Trialist

    Joined:
    Aug 15, 2013
    Messages:
    3
    How can I adjust the amount of time that the Sega screen is displayed for in Sonic 1? I've tried isolating the code that controls the delay before fade out but I can't seem to make it display for a different time. Strangely, it seems linked to the DAC driver, as playing anything other than the Sega sound causes the screen to fade much quicker than usual.
     
  2. MarkeyJester

    MarkeyJester ! % # @ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,771
    In the original Sonic 1, the SEGA PCM sample is played by the Z80, however, the main processor idles in its own sound driver code while it waits for the Z80 to finish playing the sample, you can find this delay at "Sound_E1:".

    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Play "Say-gaa" PCM sound
    ; ---------------------------------------------------------------------------

    Sound_E1: ; XREF: Sound_ExIndex
    move.b #$88,($A01FFF).l
    move.w #0,($A11100).l ; start the Z80
    move.w #$11,d1

    loc_71FC0:
    move.w #-1,d0

    loc_71FC4:
    nop
    dbf d0,loc_71FC4
    dbf d1,loc_71FC0
    addq.w #4,sp
    rts

    ; ===========================================================================Registers d0 and d1 are responsible for the loop, d1 is set to 0011, d0 is set to FFFF, what happens is that d0 is decreased (FFFE, FFFD, FFFC, etc) until it reaches back round to FFFF again, d1 is then decreased from 0011 to 0010, and d0 is reset back to FFFF and the process is repeated until d1 reaches below 0000 (i.e. FFFF).
    Essentially this is your delay time, think of the 11 and FFFF as one long timer; 11FFFF loops. Obviously, the best way to increase is to change the 11 to something higher.

    ---------------------------------------

    If however, you have applied this fix, then the situation is different, it's no longer the Z80 playing the sample, it's the main processor, and it is designed specifically so that, the delay time will "always" be as long as the sample (i.e. it will never return until the sample has finished playing). If for whatever reason you want to increase the delay time here, then I strongly recommend going to "Sega_WaitPallet:" and altering this line:

    Code:
    		move.w	#$1E,($FFFFF614).w
    That will be the delay time for; after the sample has played, so the sample plays, finishes, and then waits 1E frames before fading out, you may change that to increase the delay time further (this also applies to the non-fixed version I formally mentioned above).
     
  3. Superandroidtron

    Superandroidtron Newcomer Trialist

    Joined:
    Aug 15, 2013
    Messages:
    3
    Thanks for the help! I was actually going to apply the fix you linked to but figured I would wait until I had the screen delay figured out. Now I can do the fix and continue my mod.
     
  4. TimpZ

    TimpZ Well-Known Member Member

    Joined:
    Apr 30, 2013
    Messages:
    63
    Location:
    Lund
    I've been working on importing the instashield from S3K to Sonic 2 (later I want to expand this to the elemental shields as well), both disassemblies are the Hg version.
     
    So I searched around a bit this forum and found that copying the spindash dust code probably would be the best thing rather than trying to for example directly port the S3K code or similar. So I took that and fleshed it out a bit in order to try and understand the basic requirements etc.
     
    Anyway there's a couple places where I've gotten stuck that I figured would be a lot easier to just ask about without me just leeching off someone elses code.
     
    I'm going to try and explain and flesh out what I've done and my understanding of things so you can follow my thoughts etc. So to begin with, Initplayers (sub_446E) in S2 seems to correspond to SpawnLevelMainSprites_SpawnPlayers in S3K. S3K has this piece of code:
     


    move.l #Obj_Sonic,(Player_1).w
    move.l #Obj_DashDust,(Dust).w
    move.l #Obj_Insta_Shield,(Shield).w
    move.w #$B000,($FFFFCD2A).w 
    and S2 has this part:
     


    move.b #ObjID_Sonic,(MainCharacter+id).w ; load Obj01 Sonic object at $FFFFB000
    move.b #ObjID_SpindashDust,(Sonic_Dust+id).w ; load Obj08 Sonic's spindash dust/splash object at $FFFFD100

    So what I did was go to S2.constants.asm and added this to the object list:
    ObjID_Instashield = id(ObjPtr_Instashield) ; DD
     
    and this to the object pointer array:
    ObjID_Instashield: dc.l ObjDD
     
    Then I went to Obj38 (shield) and added this right after it:
     


    ObjDD:
    rts

     
    Questions:

    Any places I've missed for creating a new object above?

    this is what I want to do


    move.b #ObjID_Sonic,(MainCharacter+id).w
    move.b #ObjID_SpindashDust,(Sonic_Dust+id).w
    move.b #ObjID_Instashield,(???).w

    I'm guessing I can safely use .b instead of .l here since I'm basically copying the dust code? Also, where can I put a new "Sonic_Instashield" RAM variable in the RAM variable list in the constants document? I'm guessing putting it in the middle somewhere would make everything after become offset but I'm not sure. Also I'm not quite sure what "+id" is referencing in this context.
     
    I'm guessing I could put it in for example the places where it says "; $FFFFEE32-$FFFFEE33 ; seems unused" but are all of those fine or do I want it to be within a certain range of adresses? Finally I'm guessing a single byte would be sufficient?
     


     
    Then it comes the problem of actually loading the object. From what I can tell,
    move.b #ObjID_SpindashDust,(Sonic_Dust+id).w
    loads the pointer to the object into that RAM adress. Then (not counting turning or splashes) it's only referenced in Sonic_CheckSpindash, Sonic_UpdateSpindash and Obj08_Init where it says:
     


    Sonic_CheckSpindash:
    ...
    move.b #2,(Sonic_Dust+anim).w ; when starting a spindash


    Sonic_UpdateSpindash:
    bset #2,status(a0) ; says it's unused in SCHG?
    move.b #0,(Sonic_Dust+anim).w ; when releasing a spindash
    move.w #SndID_SpindashRelease,d0 ; spindash zoom sound
    jsr (PlaySound).l

    Obj08_Init:
    move.w #make_art_tile(ArtTile_ArtNem_SonicDust,0,0),art_tile(a0)
    move.w #MainCharacter,parent(a0)
    move.w #tiles_to_bytes(ArtTile_ArtNem_SonicDust),objoff_3C(a0)
    cmpa.w #Sonic_Dust,a0
    beq.s +
    ... ; stuff about Tails_Dust

    +
    bsr.w Adjust2PArtPointer

    Obj08 also has a index offset table that I find confusing:


    Obj08:
    moveq #0,d0
    move.b routine(a0),d0
    move.w Obj08_Index(pc,d0.w),d1
    jmp Obj08_Index(pc,d1.w)
    ; ===========================================================================
    ; off_1DD2E:
    Obj08_Index: offsetTable
    offsetTableEntry.w Obj08_Init ; 0
    offsetTableEntry.w Obj08_Main ; 2
    offsetTableEntry.w BranchTo16_DeleteObject ; 4
    offsetTableEntry.w Obj08_CheckSkid ; 6
    ; ===========================================================================

    Questions:

    What exactly does "move.b    #2,(Sonic_Dust+anim).w" or #0 do? I realise #2 spawns the object and #0 removes it but there's no obviously apparent branches to anything that spawns the object in the spindash code, what part controls this? I initially thought it was for the offset table but then to my knowledge at least #4 would be the pointer to remove the object.

    Why is there a jmp command to the Obj08_Index? Is it necessary for some reason or is it simply because there's no code in between?

    I can't find what "routine(a0)" does, SCHG gives the very helpful description of "routine counter" but as far as I understand there's no obvious equivalent in S3K.

    There are more questions I have but that's for stuff I haven't thought as much about yet and I want to try myself first. Also this is getting lengthy as it is.
     
  5. MarkeyJester

    MarkeyJester ! % # @ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,771
    Regarding the +id:

    In RAM, the Sonic 2 engine preserves a memory space from B000 to D5FF (according to the notes of the disassembly), now, every 40 bytes of that RAM space is an object "slot", a space for one single object, so B000 - B03F is one slot, B040 - B07F is another.

    "Sonic_Dust" would be the object slot D100 - D13F, if you were to perform "move.b #$20,(Sonic_Dust).w", the number 20 would be moved to RAM address D100, if you were to perform "move.b #$20,(Sonic_Dust+$18).w", the number 20 would be moved to RAM address D118. That "id" lable there is added to the address "Sonic_Dust", since "id" is 00, naturally, you'd be moving to D100 + 00, which is D100.

    I think the reason why they put in the +id, is to allow you to quickly and effectively change where in the 40 bytes of the object slot, the Object ID number is stored. As it currently stands, the ID is the first byte (byte 00).

    Regarding where you can put the object:

    You must only put objects into the object RAM space, otherwise they will not be processed by the software, the object RAM space is from (as I mentioned before) B000 to D5FF.

    Regarding the #2 / #0 thing:

    The "+anim" is the clue, in the object slot of 40 bytes, byte 1C is the animation ID, it sets which script to use in the animation list:



    Ani_obj08:dc.w Obj08Ani_Null-Ani_obj08 ; 0

    dc.w Obj08Ani_Splash-Ani_obj08 ; 1

    dc.w Obj08Ani_Dash-Ani_obj08 ; 2

    dc.w Obj08Ani_Skid-Ani_obj08 ; 3

    Obj08Ani_Null: dc.b $1F, 0,$FF

    Obj08Ani_Splash:dc.b 3, 1, 2, 3, 4, 5, 6, 7, 8, 9,$FD, 0

    Obj08Ani_Dash: dc.b 1, $A, $B, $C, $D, $E, $F,$10,$FF

    Obj08Ani_Skid: dc.b 3,$11,$12,$13,$14,$FC

    even



    As you can see, 0 is null, and displays the map frame 00 at the speed of 20 (1F+01) frames. While the dash, which displays the map frames 0A, 0B 0C, 0D, 0E, 0F, and 10 at the speed of 02 (01+01) frames. The FF represents a loop back to the beginning.

    To summarise, the objects is always running, even when you're not performing the spindash, or skidding or anything, it's just displaying nothing, what causes it to appear is a simple change of animation.
     
  6. TimpZ

    TimpZ Well-Known Member Member

    Joined:
    Apr 30, 2013
    Messages:
    63
    Location:
    Lund
    Oh hey that makes a lot of sense, I think I'm starting to understand it now. Looking back at the code now I figured that

    ---

    SpawnLevelMainSprites_SpawnPowerup Spawns = shield_monitor in S2 (or very similar at least)

     


    S3K uses the Shield object RAM for insta, fire, water and electric

     

    S2 only uses Shield object RAM for the basic shield


    ---

    So I figured that I'd scratch the whole spindash thing and just copied the shield object into my custom ObjDD for now since I want to use the Sonic_shield RAM for the (insta)shields. Now I can finally manipulate the objects (somewhat) knowingly. Or well, I can delete the shield or screw with the animations when doing my instashield after messing with it for 10 minutes etc so that's definitely something. Anyway I just wanted to say thank you this helped me a lot!

    Though one question did arise when looking over the object RAM:

    I have this part:


    TitleCard_Bottom: ; level title card: yellow part at the bottom
    ds.b object_size
    TitleCard_Left: ; level title card: red part on the left
    ds.b object_size

    ; Reserved object RAM, free slots
    ds.b object_size
    ds.b object_size
    ds.b object_size
    ds.b object_size
    ds.b object_size

    CPZPylon: ; Pylon in the foreground in CPZ
    ds.b object_size

    And that is all great. However there's also this part here:


    Tails_Shield:
    ds.b object_size
    Sonic_InvincibilityStars:
    ds.b object_size
    ds.b object_size
    ds.b object_size
    ds.b object_size
    Tails_InvincibilityStars:
    ds.b object_size
    ds.b object_size
    ds.b object_size
    ds.b object_size

    Are those "extra" ds.b's more free RAM or is it like multiple instances of the stars loaded at once?
     
    Last edited by a moderator: Sep 5, 2013
  7. MarkeyJester

    MarkeyJester ! % # @ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,771
    I'd like to help you on this one, I really would. but this is an extemely odd use of preserving memory spaces for a Mega Drive game.

    Actually no, this is just outright pathetically silly now, this method has only confused the situation, not made it easier, who's idea was this?
     
  8. TimpZ

    TimpZ Well-Known Member Member

    Joined:
    Apr 30, 2013
    Messages:
    63
    Location:
    Lund
    I'm sorry but I'm not sure if I follow you. From my understanding S3K uses basically the same routines for shields, only when you have no shield, you get the insta-shield art. When you have a fire shield you get fire shield art etc. The instashield is loaded into the shield RAM every frame (?) and then is replaced depending on if you have a shield or not and if yes, which shield.

    Are you suggesting me to use the free RAM space to create separate instances of every shield type? I'm not planning on keeping the original shield around, I'm just messing with it to learn how to manipulate the object and hopefully write code for the shield objects rather than blatantly copy it since the methods used are very different.
     
    Last edited by a moderator: Sep 5, 2013
  9. MarkeyJester

    MarkeyJester ! % # @ Member

    Joined:
    Jun 27, 2009
    Messages:
    2,771
    No, I was referring to the use of ds/dc for initialising memory spaces for RAM, not your fault, it's whoever's been "improving" the disassemblies. And because of that, it's thrown me off.
     
  10. JoenickROS

    JoenickROS ROS is on hiatus. (...again) Member

    Joined:
    Feb 5, 2012
    Messages:
    920
    Alright, So recently I have been messing around with getting the big ring revived to work like Sonic 3. Well so far I have the ring to load Sonic into the special stage after the ring flash object is deleted and too give him 50 rings if all chaos emeralds have been collected. Problems I have are; after the collecting the ring and then going back to where it was deleted, it shows up again. I have added a routine in the ring code to markobject gone but it still shows up. Pointed it like so


    off_1220E:
    dc.w loc_12216-off_1220E
    dc.w loc_12264-off_1220E; 2
    dc.w loc_12282-off_1220E; 4
    dc.w BranchTo6_DeleteObject-off_1220E; 6
    dc.w JmpToDD_MarkObjGone-off_1220E



    That being all the labels and then this the markobject routine,


    JmpToDD_MarkObjGone:
    jmp Markobjgone

    and yet it doesn't change a thing. Next problem I have is too get the uncompressed ring art to load in all levels, I looked in Sonic 1 and found this for the control of loading it.


    AniArt_GiantRing: ; XREF: AniArt_Load
    tst.w ($FFFFF7BE).w
    bne.s loc_1C518
    rts
    ; ===========================================================================

    loc_1C518:
    subi.w #$1C0,($FFFFF7BE).w
    lea (Art_BigRing).l,a1 ; load giant ring patterns
    moveq #0,d0
    move.w ($FFFFF7BE).w,d0
    lea (a1,d0.w),a1
    addi.w #$8000,d0
    lsl.l #2,d0
    lsr.w #2,d0
    ori.w #$4000,d0
    swap d0
    move.l d0,4(a6)
    move.w #$D,d1
    jmp loadZoneBlockMaps
    ; End of function AniArt_GiantRing


    but I had to change jmp LoadTiles, to jmp loadZoneBlockMaps, which I believe is the equivalent to loadtiles in Sonic 1. One problem though is I need to point this somewhere in the big ring code, I though it would go next to the art tiles line but that caused the game to freeze when going to the location of another big ring. One other thing I'm going to do is have the ring not load again when returning from a special stage and to remember Sonics location, just like the star post object.

    Any tips or things I should be looked at to achieve the results I'm looking for?
     
    Last edited by a moderator: Sep 5, 2013
  11. TimpZ

    TimpZ Well-Known Member Member

    Joined:
    Apr 30, 2013
    Messages:
    63
    Location:
    Lund
    Well the starposts have essentially the same effect. You hit them with 50 rings and the stars show up. After the special stage is done you are returned with 0 rings (or all if you're Knuckles) to the same spot without ever being able to enter the same checkpoint (except for with gameovers?). I'm certainly no expert nor have tried to achieve something like this (though I might in the future). But personally I'd probably try and copy the code of those stars that're spawned although they probably save your position just as if you had hit the starpost and died. So perhaps creating a separate instance of the same code, essentially copying the starposts but having the stars "on" all the time is the way I'd try for first.

    Hopefully this helps.
     
    Last edited by a moderator: Sep 5, 2013
  12. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    864
    All four slots are used, the invincibility stars object loads copies of itself in its own slot and the next three slots.
     
  13. JoenickROS

    JoenickROS ROS is on hiatus. (...again) Member

    Joined:
    Feb 5, 2012
    Messages:
    920
    Ok I have successfully made the ring object not appear after hitting it and made it so multiple rings can show up, now I just need to know where to place the uncompressed art routine branch, thought in Level: but it had no effect. This is to save level data but I have no idea where to place it in the big ring object.

    Code:
    jsr	Obj79_SaveData
    
     
  14. TimpZ

    TimpZ Well-Known Member Member

    Joined:
    Apr 30, 2013
    Messages:
    63
    Location:
    Lund
    Ok so I've been working a bit on importing the instashield object into S2 and I need help. This is my 20th post so I figured I should be as thorough as possible with my questions if I for whatever reason don't get approved :p.
     
    This is the code from S3K:


    Obj_Insta_Shield:
    ; SpawnLevelMainSprites_SpawnPlayers+BCo ...
    move.l #Map_InstaShield,$C(a0) ; load mappings
    move.l #DPLC_InstaShield,$3C(a0) ; load dynamic pattern load cues
    move.l #ArtUnc_InstaShield,$38(a0) ; load uncompressed art
    move.b #4,4(a0) ; use playfield coordinates
    move.w #$80,8(a0) ; Sprite priority, in units of $80 (00 = front).
    move.b #$18,7(a0) ; Width of the object, in pixels.
    move.b #$18,6(a0) ; Height of the object, in pixels.
    move.w #$79C,$A(a0) ; decides what tiles the object is going to use
    move.w #$F380,$40(a0) ; Address of art in VRAM (the same as starting art block * $20)
    btst #7,($FFFFB00A).w ; Significance of 7? PCCVH AAAAAAAAAAA ; P = priority, CC = palette line, V = y-flip; H = x-flip, A = starting cell index of art
    beq.s loc_19518
    bset #7,$A(a0) ; set the 7th bit in the art adress?

    loc_19518:
    move.w #1,$20(a0) ; Animation number.
    move.b #-1,$34(a0) ; "Stores a code pointer branched to from various routines upon meeting certain conditions." -SCHG
    move.l #loc_1952A,(a0)

    loc_1952A:
    movea.w $42(a0),a2 ; Put Sonic in a0?
    btst #1,$2B(a2) ; are you invincible?
    bne.s locret_195A4 ; rts if you are
    move.w $10(a2),$10(a0) ; get X coordinate for sonic
    move.w $14(a2),$14(a0) ; Y
    move.b $2A(a2),$2A(a0) ; orientation
    andi.b #1,$2A(a0) ; make the orientation same as sonic?
    tst.b (Reverse_gravity_flag).w ;are you upside down?
    beq.s loc_1955A ; if not then don't inverse
    ori.b #2,$2A(a0) ; make upside down

    loc_1955A:
    andi.w #$7FFF,$A(a0) ; Drawing mask? Something about the starting position of the art used
    tst.w $A(a2) ; is sonic's art_tile 0?
    bpl.s loc_1956C
    ori.w #$8000,$A(a0) ; set high priority?

    loc_1956C:
    lea (Ani_InstaShield).l,a1 ; load animations to a1
    jsr (Animate_Sprite).l
    cmpi.b #7,$22(a0) ; are you on the 7th animation?
    bne.s loc_1958C ; don't mess with the double jump flag
    tst.b $2F(a2) ; is the double jump flag clear?
    beq.s loc_1958C ; branch if yes
    move.b #2,$2F(a2) ; set flag to "done with performing instashield"

    loc_1958C:

    tst.b $22(a0) ; is the frame diplay thing 0?
    beq.s loc_1959A ; skip frame 4(?) check
    cmpi.b #3,$22(a0) ; skip PLCLoad_Shields if on the 4th frame?
    bne.s loc_1959E

    loc_1959A:
    bsr.w PLCLoad_Shields

    loc_1959E:
    jmp (Draw_Sprite).l
    ; ---------------------------------------------------------------------------

    locret_195A4:
    rts
    ; ---------------------------------------------------------------------------
     
    First off I have a couple basic questions. Feel free to answer any of them if you like:
     


    btst #7,($FFFFB00A).w
    beq.s loc_19518
    bset #7,$A(a0)
    Could anyone tell me why this is done? It seems somewhat arbitrary to set a single bit in the VRAM location depending on Sonic's art location when it already set the values for where the art is. This should shift where in the VRAM the art is, so could it be done to conserve space possibly?
     
     


    move.b #-1,$34(a0)

    I don't understand exactly what the function of this location is or why it's significant to include, nor how I'd go about translating it to S2. At first I thought it might be similar to the routine or routine counter but there's nothing in the object code that use it.
     
     
     


    movea.w $42(a0),a2

    Each object has $4A bytes allocated for them in S3(K) (as opposed to $40 in S2). But as far as I'm understanding this it would put whatever object is after the instashield one in the object RAM in a2. Whatever that object is (shield_P2 as far as I can see), it shouldn't be Sonic since he's the first object, but every reference to a2 afterwards I can only interpret as it being Sonic (such as it rts'ing if the first bit in $2A(a2) is set, which is invincibility for sonic).
     
     
     


    move.b #$18,6(a0) ; Height of the object, in pixels.

    width_pixels is defined both by the Hg disassembly and SCHG, but there's no height_pixels. Is there something I'm missing and what is the difference between width_pixels and x_radius?
     
     


    andi.w #$7FFF,$A(a0)
    tst.w $A(a2) ; is sonic's art_tile 0?
    bpl.s loc_1956C
    ori.w #$8000,$A(a0) ; set high priority?
    ; Equivalent commands in S2: andi.w #drawing_mask,art_tile(a0)
    ori.w #high_priority,art_tile(a0)
    What exactly is the significance of $7FFF and $8000 here? According to SCHG it's the last byte of Chunk_Table and first byte of Level_Layout respectively but the disassemblies say otherwise.
     
     
     
    Now to my main problem, the DPLC's. Both the insta- and elemental shields use it. I know that Sonic and Tails use PLC's but I have no idea where to even begin with DPLC's, what I would need to port or alter or how/if I'd need to edit the S3K ones. Perhaps I can even just use PLC's, honestly I'm not sure what makes the DPLC's "dynamic". Either way it uses data situated beyond $3F in the object RAM so something significant has to be done . Any help at all would be much appreciated.
     
  15. JoenickROS

    JoenickROS ROS is on hiatus. (...again) Member

    Joined:
    Feb 5, 2012
    Messages:
    920
    My turn, ok so as you know I'm reviving the big ring. I only have one more issue with saving the data.

    (copy and pasted from Skype), I fixed the ring thing so I thought, but without hitting a starpost it doesn't save my rings or time when returning from the special stage, but if I hit a starpost before hand it does. Also if I have a ring and starpost already hit if I die before hitting another starpost, it loads me to where the ring was, very confusing.

    Here is a snipit of code that should check for this.


    moveq #0,d0
    move.b d0,(Dynamic_Resize_Routine).w ; load level boundaries
    move.w (Current_ZoneAndAct).w,d0
    ror.b #1,d0
    lsr.w #4,d0
    lea WrdArr_LvlSize(pc,d0.w),a0
    move.l (a0)+,d0
    move.l d0,(Camera_Min_X_pos).w
    move.l d0,($FFFFEEC0).w ; unused besides this one write...
    move.l d0,(Tails_Min_X_pos).w
    move.l (a0)+,d0
    move.l d0,(Camera_Min_Y_pos).w
    move.l d0,($FFFFEEC4).w ; unused besides this one write...
    move.l d0,($FFFFEEFC).w
    move.w #$1010,($FFFFEE40).w
    move.w #$60,(Camera_Y_pos_bias).w
    move.w #$60,(Camera_Y_pos_bias_2P).w
    tst.b (bonus_stage_flag).w
    bne.w loc_C164_bonus
    bra.w loc_C164

    The bottom part checks to load if I'm returning from the special stage, and to load the ring load data, here


    loc_C164_bonus:
    tst.b (ring_collected).w
    beq.s loc_C17A
    jsr (ObjE1_LoadData).l
    move.w (MainCharacter+x_pos).w,d1
    move.w (MainCharacter+y_pos).w,d0
    bra.s loc_C196
    loc_C164:
    tst.b (Last_star_pole_hit).w
    beq.s loc_C17A
    jsr (Obj79_LoadData).l
    move.w (MainCharacter+x_pos).w,d1
    move.w (MainCharacter+y_pos).w,d0
    bra.s loc_C196

    Loading the data.


    ObjE1_LoadData:
    move.w (Saved_x_pos).w,(MainCharacter+x_pos).w
    move.w (Saved_y_pos).w,(MainCharacter+y_pos).w
    move.w (Saved_Ring_count).w,(Ring_count).w
    move.b (Saved_Extra_life_flags).w,(Extra_life_flags).w
    tst.b (Bonus_Stage_Flag).w
    bne.s Exit_Bonus_Stage_ring
    clr.w (Ring_count).w
    clr.b (Extra_life_flags).w

    Exit_Bonus_Stage_ring: ; <----- Insert this line
    clr.b (Bonus_Stage_Flag).w ; <----- Insert this line. This is how we clear the variable. Remember this.
    move.l (Saved_Timer).w,(Timer).w
    move.b #59,(Timer_centisecond).w
    subq.b #1,(Timer_second).w
    move.w (Saved_art_tile).w,(MainCharacter+art_tile).w
    move.w (Saved_layer).w,(MainCharacter+layer).w
    move.b (Saved_Dynamic_Resize_Routine).w,(Dynamic_Resize_Routine).w
    move.b (Saved_Water_routine).w,(Water_routine).w
    move.w (Saved_Camera_Max_Y_pos).w,(Camera_Max_Y_pos_now).w
    move.w (Saved_Camera_Max_Y_pos).w,(Camera_Max_Y_pos).w
    move.w (Saved_Camera_X_pos).w,(Camera_X_pos).w
    move.w (Saved_Camera_Y_pos).w,(Camera_Y_pos).w
    move.w ($FFFFFE44).w,($FFFFEE08).w
    move.w ($FFFFFE46).w,($FFFFEE0C).w
    move.w ($FFFFFE48).w,($FFFFEE10).w
    move.w ($FFFFFE4A).w,($FFFFEE14).w
    move.w ($FFFFFE4C).w,($FFFFEE18).w
    move.w ($FFFFFE4E).w,($FFFFEE1C).w
    tst.b (Water_flag).w ; does the level have water?
    beq.s + ; if not, branch to skip loading water stuff
    move.w (Saved_Water_Level).w,(Water_Level_2).w
    move.b (Saved_Water_routine).w,(Water_routine).w
    move.b (Saved_Water_move).w,(Water_move).w
    +
    tst.b (ring_collected).w
    bpl.s return_1F412
    move.w (Saved_x_pos).w,d0
    subi.w #$A0,d0
    move.w d0,(Camera_Min_X_pos).w

    return_1F412_ring:
    rts

    This should make it so this data only loads for the ring if returning from the bonus, but it also loads if I die before hitting a starpost. Have I forgot to clear some of the flags?
     
    Last edited by a moderator: Sep 8, 2013
  16. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    864
    #$7FFF is a bitmask which has all but the most significant bit of a word set. The andi.w (bitwise AND Immediate Word) will unset the MSB of the word at $A(a0), keeping all other bits the same. #$8000 conversely, has only the MSB of the word set, so the ori.w (bitwise OR Immediate Word) will set the MSB of the word at $A(a0), keeping all other bits the same. You may want to read up on the bitwise operations if you're unfamiliar.
     
  17. KingofHarts

    KingofHarts Active Member Member

    Joined:
    Sep 30, 2012
    Messages:
    47
    Location:
    Chi-Town
    To at least answer the question about DPLCs, since I've become quite familiar with them as of late... what with needing to program DPLC Loading into Triad and all.


    What are they, exactly? They are cues that tell the game to load a specific amount of art tiles into a location in VRAM. They are used with Uncompressed Art, as those can be, and need to be loaded and replaced right away, immediately... unlike compressed art, which needs to be, well, decompressed.

    I hope I explain this clear enough, which is never my strong suit. Please use ReGen's VDP viewer to have a visual aid in what I'm trying, and probably failing to put into words here...

    As to answer why they are "dynamic", well this can be best answered by comparing them to the standard Pattern Loading Cues. I'll use Sonic 1 as an example here. If you have the S1 Disassembly, go to _incPattern Load Cues.asm. What these cues do is tell the program to load an entire file's (Nemesis, in this case) compressed art into a slot in VRAM. ALL OF IT... even if it is not used THIS instant... as it will be used when called upon by the sprite's mappings. You can call it a "static" PLC if you want to, as it will not change (Unless a different static PLC overwrites its VRAM location.)

    Dynamic PLC's load certain tiles out of a set of tiles, instead of just loading the ENTIRE tileset at once. This save a LOT of VRAM space, only loading what is needed. Looking at the near-end of the VRAM, you will see Sonic's tiles, and they change constantly depending on Sonic's current sprite. They must, otherwise they won't look right. Load Sonic's art in SonMapEd, minus the DPLC's and you'll see why. The mappings themselves don't, and cannot call upon certain sprites in the entire set, because they call upon a tile index based on what is loaded already in VRAM. So the tiles need to constantly change. THAT is what DPLC's do. They change the art loaded in VRAM dynamically to suit what is needed at that time.

    Now if you open _mapsSonic - Dynamic gfx script.asm, you will see something like this:


    SonPLC_Stand: dc.b 4, $20, 0, $70, 3, $20, $B, $20, $E
    SonPLC_Wait1: dc.b 3, $50, $11, $50, $17, $20, $1D

    The first digit in each entry is the number of requests to make. This is usually equal to the number of sprite pieces in that frame, though not always... as in cases where some pieces are merely mirrored pieces of others.


    For every request, there is a word. Let's look at the last word in SonPLC_Stand: $20, $E. As a word, this makes $200E. The first nybble, 2, determines the # of tiles to load into VRAM, minus one. So this is telling us to load 3 tiles. Now, which 3 tiles are loaded? the other 3 nybbles tell us this. $00E. So tiles $E, $F, and $10 are loaded.

    Hope this helps clear things up a bit about DPLC's. Unfortunately SonMapEd doesn't edit these directly... I hope to provide a remedy to this at some point. ;)
     
  18. MainMemory

    MainMemory Well-Known Member Member

    Joined:
    Mar 29, 2011
    Messages:
    864
    First off, you're describing Sonic 1 DPLCs, while we're editing Sonic 2 (not a huge difference), and secondly that doesn't explain how to use them in the game.

    I do know that the DPLCs from S3K will probably have to be converted to Sonic 2's format, which MappingsConverter can do.
     
  19. KingofHarts

    KingofHarts Active Member Member

    Joined:
    Sep 30, 2012
    Messages:
    47
    Location:
    Chi-Town
    Yea, I understand that I used a different game as a reference. I pointed out as such, and did it only because I'm a little more familiar with Sonic 1's... and because I don't feel like putting a bunch of hex numbers into a quote tag.  :eek:nthequiet:  ... on the count of Sonic 2's disassembly uses .bin DPLC files instead of ASM.

    As for how to use them... I thought I put in enough to build an understanding, but as I said, I'm not the best at relaying these kinds of things in word form.
     
  20. TimpZ

    TimpZ Well-Known Member Member

    Joined:
    Apr 30, 2013
    Messages:
    63
    Location:
    Lund
    I'm not gonna be able to explore this further for a couple days but I figured I could at least give a response for now.

    It's fine KingofHarts, I appreciate your description. I learned a couple things from it and finding documentation on these sorts of things is really hard. It gave me some good pointers on where to look for examples in the existing code and more of its usage. Also I now know for certain that DPLC's do exist and how to convert them between games. I have imported animated objects into levels before (water waves) so hopefully I can make sense of it.

    You are absolutely correct MainMemory. I feel dumb for missing those i's in the code now, I mostly got confused from the fact that the values have names in the S2 Hg as opposed to anything I've seen before and I just immediately assumed it referred to adresses. Combine it with the fact that I never really heard much about masking before (I haven't had the time to look into it much like I said but I'm guessing it's doing something similar to this: http://en.wikipedia.org/wiki/Mask_(computing)#Image_masks ?) but I'm gonna read up on it.