don't click here

Dynamic level construction (art, palettes and collisions per act)

Discussion in 'Engineering & Reverse Engineering' started by silent.creature, Jan 29, 2009.

Thread Status:
Not open for further replies.
  1. silent.creature

    silent.creature

    Silent Creature Member
    18
    0
    0
    Brazil
    Studying both to work and to get back to some stopped hobbies...
    EDIT 4: Since I don't know if I need to make another topic to update this, I'll use this one for that. If this topic is bumped against newer (or older) forum rules, please inform me, but that's not the intention.

    Well, I've been a while improving the routines and merging tables, and I had this as a result.

    I want to credit HPZMan for his idea and New Sonic (I think this one isn't registered here, so don't bother if so) for remembering me of some macro details (especifically levartptrs).

    I could merge and load "sequentially" both collision and art tables for each act, getting rid of the comparisons. So, let's see.

    First, look for "LoadCollisionIndexes" routine.
    Code (ASM):
    1. LoadCollisionIndexes:
    2.     moveq   #0,d0
    3.     move.b  (Current_Zone).w,d0
    4.     lsl.w   #2,d0
    5.     move.l  #Primary_Collision,(Collision_addr).w
    6.     move.w  d0,-(sp)
    7.     movea.l Off_ColP(pc,d0.w),a0
    8.     lea (Primary_Collision).w,a1
    9.     bsr.w   KosDec
    10.     move.w  (sp)+,d0
    11.     movea.l Off_ColS(pc,d0.w),a0
    12.     lea (Secondary_Collision).w,a1
    13.     bra.w   KosDec
    14.  
    Change this routine to:
    Code (ASM):
    1.     moveq   #0,d0
    2.     move.w  (Current_ZoneAndAct).w,d0
    3.     ror.b   #1,d0
    4.     lsr.w   #4,d0
    5.     move.l  #Primary_Collision,(Collision_addr).w
    6.     move.w  d0,-(sp)
    7.     movea.l Off_Collision(pc,d0.w),a0
    8.     lea (Primary_Collision).w,a1
    9.     bsr.w   PuleA_KosDec
    10.     move.w  (sp)+,d0
    11.     movea.l Off_Collision+4(pc,d0.w),a0
    12.     lea (Secondary_Collision).w,a1
    13.     bra.w   PuleA_KosDec
    14.  
    EDIT: This makes collision routine load data like "LevelSizeLoad" loads is own data. Now, since you have two disjoint tables, and this new routine loads only one (Off_Collision), you need to merge the tables. The format used on it is described within the following code:
    Code (ASM):
    1. Off_Collision:
    2. ; format used: dc.l Act_Prim_Col, Act_Sec_Col
    3. dc.l ColP_EHZHTZ, ColS_EHZHTZ ;00-00
    4. dc.l ColP_EHZHTZ, ColS_EHZHTZ ;00-01
    5. dc.l Off_Level, Off_Level ;01-00
    6. dc.l Off_Level, Off_Level ;01-01
    7. dc.l Off_Level, Off_Level ;02-00
    8. dc.l Off_Level, Off_Level ;02-01
    9. dc.l Off_Level, Off_Level ;03-00
    10. dc.l Off_Level, Off_Level ;03-01
    11. dc.l ColP_MTZ, ColP_MTZ ;04-00
    12. dc.l ColP_MTZ, ColP_MTZ ;04-01
    13. dc.l ColP_MTZ, ColP_MTZ ;05-00
    14. dc.l ColP_MTZ, ColP_MTZ ;05-01
    15. dc.l ColP_WFZSCZ, ColS_WFZSCZ ;06-00
    16. dc.l ColP_WFZSCZ, ColS_WFZSCZ ;06-01
    17. dc.l ColP_EHZHTZ, ColS_EHZHTZ ;07-00
    18. dc.l ColP_EHZHTZ, ColS_EHZHTZ ;07-01
    19. dc.l Off_Level, Off_Level ;08-00
    20. dc.l Off_Level, Off_Level ;08-01
    21. dc.l Off_Level, Off_Level ;09-00
    22. dc.l Off_Level, Off_Level ;09-01
    23. dc.l ColP_OOZ, ColP_OOZ ;0A-00
    24. dc.l ColP_OOZ, ColP_OOZ ;0A-01
    25. dc.l ColP_MCZ, ColP_MCZ ;0B-00
    26. dc.l ColP_MCZ, ColP_MCZ ;0B-01
    27. dc.l ColP_CNZ, ColS_CNZ ;0C-00
    28. dc.l ColP_CNZ, ColS_CNZ ;0C-01
    29. dc.l ColP_CPZDEZ, ColS_CPZDEZ ;0D-00
    30. dc.l ColP_CPZDEZ, ColS_CPZDEZ ;0D-01
    31. dc.l ColP_CPZDEZ, ColS_CPZDEZ ;0E-00
    32. dc.l ColP_CPZDEZ, ColS_CPZDEZ ;0E-01
    33. dc.l ColP_ARZ, ColS_ARZ ;0F-00
    34. dc.l ColP_ARZ, ColS_ARZ ;0F-01
    35. dc.l ColP_WFZSCZ, ColS_WFZSCZ ;10-00
    36. dc.l ColP_WFZSCZ, ColS_WFZSCZ ;10-01
    It's a simple table format, isn't it?

    Now, let's take care of level art table. First of all, we need to change the routines to load level art and mappings data. So, look for "Level" and, inside the routine, look for this code:
    Code (ASM):
    1. move.b (Current_Zone).w,d0
    2.  
    3. ; multiply d0 by 12, the size of a level art load block
    4. add.w d0,d0
    5. add.w d0,d0
    6. move.w d0,d1
    7. add.w d0,d0
    8. add.w d1,d0
    9. lea (LevelArtPointers).l,a2
    10. ...
    Change it to:
    Code (ASM):
    1. moveq #0,d0
    2. move.w (Current_ZoneAndAct).w,d0
    3. ror.b #1,d0
    4. lsr.w #6,d0 ; with this, it load two by two levels.
    5.  
    6. add.w d0,d0
    7. add.w d0,d0
    8. move.w d0,d1
    9. add.w d0,d0
    10. add.w d1,d0
    11. lea (LevelSeqTable).l,a2
    12. ...
    Where "LevelSeqTable" is the new table I describe after fixing the routines. Also, I'll explain later for what reason I wrote "with this, it load two by two levels". Moving on:
    Look for "sub_4E98":
    Code (ASM):
    1. sub_4E98:
    2. add.w d0,d0
    3. add.w d0,d0
    4. move.w d0,d1
    5. add.w d0,d0
    6. add.w d1,d0
    7. lea (LevelArtPointers).l,a2
    8. ...
    And change this to:
    Code (ASM):
    1. sub_4E98:
    2. moveq #0,d0
    3. move.w (Current_ZoneAndAct).w,d0
    4. ror.b #1,d0
    5. lsr.w #6,d0 ; with this, it load two by two levels.
    6.  
    7. add.w d0,d0
    8. add.w d0,d0
    9. move.w d0,d1
    10. add.w d0,d0
    11. add.w d1,d0
    12. lea (LevelSeqTable).l,a2
    13. ...
    Look for "loadZoneBlockMaps":
    Code (ASM):
    1. loadZoneBlockMaps:
    2. moveq #0,d0
    3. move.b (Current_Zone).w,d0
    4. add.w d0,d0
    5. add.w d0,d0
    6. move.w d0,d1
    7. add.w d0,d0
    8. add.w d1,d0
    9. lea (LevelArtPointers).l,a2
    10. ...
    And change this to:
    Code (ASM):
    1. loadZoneBlockMaps:
    2. moveq #0,d0
    3. move.w (Current_ZoneAndAct).w,d0
    4. ror.b #1,d0
    5. lsr.w #6,d0 ; with this, it load two by two levels.
    6.  
    7. add.w d0,d0
    8. add.w d0,d0
    9. move.w d0,d1
    10. add.w d0,d0
    11. add.w d1,d0
    12. lea (LevelSeqTable).l,a2
    13. ...
    Before building the new table, let's review the macro "levartptrs". Its arguments are loaded like this:
    levartptrs (Prim_PLC_Index), (Sec_PLC_Index), (Palette_Index), (8x8), (16x16), (128x128)

    So, that's another way to make dynamic palettes without making those comparisons (the ones I've put before). Ah, you'll need to expand your palette pointers table to perform this. I'll put the table I've assembled within my own code, so, with this explanation, change my weird pointers to your right ones.

    The art and mappings table I've assembled within these routines is loaded sequentially by level/act, but I still want to get rid of some (some?) zeroes here and I appreciate help on this. This table, by itself, explains why I wrote "with this it will load two by two levels".
    Code (ASM):
    1. LevelSeqTable:
    2. levartptrs 4, 5, 4, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 0 ; EHZ ; EMERALD HILL ZONE Act 1
    3. dc.l 0, 0, 0 ;filler
    4. levartptrs 4, 5,$39, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 0 ; EHZ ; EMERALD HILL ZONE Act 2
    5. dc.l 0, 0, 0 ;filler
    6. levartptrs 6, 7, 5, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 1 ; LEV1 ; LEVEL 1 (UNUSED)
    7. dc.l 0, 0, 0 ;filler
    8. levartptrs 6, 7,$3A, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 1 ; LEV1 ; LEVEL 1 (UNUSED)
    9. dc.l 0, 0, 0 ;filler
    10. levartptrs 8, 9, 6, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 2 ; LEV2 ; LEVEL 2 (UNUSED)
    11. dc.l 0, 0, 0 ;filler
    12. levartptrs 8, 9,$3B, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 2 ; LEV2 ; LEVEL 2 (UNUSED)
    13. dc.l 0, 0, 0 ;filler
    14. levartptrs $A, $B, 7, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 3 ; LEV3 ; LEVEL 3 (UNUSED)
    15. dc.l 0, 0, 0 ;filler
    16. levartptrs $A, $B,$3C, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 3 ; LEV3 ; LEVEL 3 (UNUSED)
    17. dc.l 0, 0, 0 ;filler
    18. levartptrs $C, $D, 8, ArtKos_MTZ, BM16_MTZ, BM128_MTZ ; 4 ; MTZ ; METROPOLIS ZONE ACTS 1 & 2
    19. dc.l 0, 0, 0 ;filler
    20. levartptrs $C, $D,$3D, ArtKos_MTZ, BM16_MTZ, BM128_MTZ ; 4 ; MTZ ; METROPOLIS ZONE ACTS 1 & 2
    21. dc.l 0, 0, 0 ;filler
    22. levartptrs $C, $D, 9, ArtKos_MTZ, BM16_MTZ, BM128_MTZ ; 5 ; MTZ3 ; METROPOLIS ZONE ACT 3
    23. dc.l 0, 0, 0 ;filler
    24. levartptrs $C, $D,$3E, ArtKos_MTZ, BM16_MTZ, BM128_MTZ ; 5 ; MTZ3 ; METROPOLIS ZONE ACT 3
    25. dc.l 0, 0, 0 ;filler
    26. levartptrs $10,$11, $A, ArtKos_SCZ, BM16_WFZ, BM128_WFZ ; 6 ; WFZ ; WING FORTRESS ZONE
    27. dc.l 0, 0, 0 ;filler
    28. levartptrs $10,$11,$3F, ArtKos_SCZ, BM16_WFZ, BM128_WFZ ; 6 ; WFZ ; WING FORTRESS ZONE
    29. dc.l 0, 0, 0 ;filler
    30. levartptrs $12,$13, $B, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 7 ; HTZ ; HILL TOP ZONE
    31. dc.l 0, 0, 0 ;filler
    32. levartptrs $12,$13,$40, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 7 ; HTZ ; HILL TOP ZONE
    33. dc.l 0, 0, 0 ;filler
    34. levartptrs $14,$15, $C, BM16_OOZ, BM16_OOZ, BM16_OOZ ; 8 ; HPZ ; HIDDEN PALACE ZONE (UNUSED)
    35. dc.l 0, 0, 0 ;filler
    36. levartptrs $14,$15,$41, BM16_OOZ, BM16_OOZ, BM16_OOZ ; 8 ; HPZ ; HIDDEN PALACE ZONE (UNUSED)
    37. dc.l 0, 0, 0 ;filler
    38. levartptrs $16,$17, $D, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 9 ; LEV9 ; LEVEL 9 (UNUSED)
    39. dc.l 0, 0, 0 ;filler
    40. levartptrs $16,$17,$42, ArtKos_EHZ, BM16_EHZ, BM128_EHZ ; 9 ; LEV9 ; LEVEL 9 (UNUSED)
    41. dc.l 0, 0, 0 ;filler
    42. levartptrs $18,$19, $E, ArtKos_OOZ, BM16_OOZ, BM128_OOZ ; $A ; OOZ ; OIL OCEAN ZONE
    43. dc.l 0, 0, 0 ;filler
    44. levartptrs $18,$19,$43, ArtKos_OOZ, BM16_OOZ, BM128_OOZ ; $A ; OOZ ; OIL OCEAN ZONE
    45. dc.l 0, 0, 0 ;filler
    46. levartptrs $1A,$1B, $F, ArtKos_MCZ, BM16_MCZ, BM128_MCZ ; $B ; MCZ ; MYSTIC CAVE ZONE
    47. dc.l 0, 0, 0 ;filler
    48. levartptrs $1A,$1B,$44, ArtKos_MCZ, BM16_MCZ, BM128_MCZ ; $B ; MCZ ; MYSTIC CAVE ZONE
    49. dc.l 0, 0, 0 ;filler
    50. levartptrs $1C,$1D,$10, ArtKos_CNZ, BM16_CNZ, BM128_CNZ ; $C ; CNZ ; CASINO NIGHT ZONE
    51. dc.l 0, 0, 0 ;filler
    52. levartptrs $1C,$1D,$45, ArtKos_CNZ, BM16_CNZ, BM128_CNZ ; $C ; CNZ ; CASINO NIGHT ZONE
    53. dc.l 0, 0, 0 ;filler
    54. levartptrs $1E,$1F,$11, ArtKos_CPZ, BM16_CPZ, BM128_CPZ ; $D ; CPZ ; CHEMICAL PLANT ZONE
    55. dc.l 0, 0, 0 ;filler
    56. levartptrs $1E,$1F,$46, ArtKos_CPZ, BM16_CPZ, BM128_CPZ ; $D ; CPZ ; CHEMICAL PLANT ZONE
    57. dc.l 0, 0, 0 ;filler
    58. levartptrs $20,$21,$12, ArtKos_CPZ, BM16_CPZ, BM128_CPZ ; $E ; DEZ ; DEATH EGG ZONE
    59. dc.l 0, 0, 0 ;filler
    60. levartptrs $20,$21,$47, ArtKos_CPZ, BM16_CPZ, BM128_CPZ ; $E ; DEZ ; DEATH EGG ZONE
    61. dc.l 0, 0, 0 ;filler
    62. levartptrs $22,$23,$13, ArtKos_ARZ, BM16_ARZ, BM128_ARZ ; $F ; ARZ ; AQUATIC RUIN ZONE
    63. dc.l 0, 0, 0 ;filler
    64. levartptrs $22,$23,$48, ArtKos_ARZ, BM16_ARZ, BM128_ARZ ; $F ; ARZ ; AQUATIC RUIN ZONE
    65. dc.l 0, 0, 0 ;filler
    66. levartptrs $24,$25,$14, ArtKos_SCZ, BM16_WFZ, BM128_WFZ ; $10 ; SCZ ; SKY CHASE ZONE
    67. dc.l 0, 0, 0 ;filler
    68. levartptrs $24,$25,$49, ArtKos_SCZ, BM16_WFZ, BM128_WFZ ; $10 ; SCZ ; SKY CHASE ZONE
    69. dc.l 0, 0, 0 ;filler
    Please inform me if I've made mistakes here.
     
  2. Eduardo Knuckles

    Eduardo Knuckles

    Not a loved one, but the most hated person. Banned
    414
    10
    18
    Someplace somewhere
    Project S.A.M.G.
    Dynamic layouts???
    But the layouts already aren't dynamic in the original game?
    :colbert:
     
  3. amphobius

    amphobius

    doing more important things with my life Member
    2,120
    0
    16
    life
    I'm thinking he means Dynamic Palletes or Art, if not, I'm stumped.
     
  4. Eduardo Knuckles

    Eduardo Knuckles

    Not a loved one, but the most hated person. Banned
    414
    10
    18
    Someplace somewhere
    Project S.A.M.G.
  5. PsychoSk8r

    PsychoSk8r

    PsychedelAnt | Tone Turner Oldbie
    2,642
    57
    28
    Birmingham, UK
    30 Day Project: Revisited.A New Release!
    I'm pretty sure this is for S2, not S1. =P
     
  6. Tweaker

    Tweaker

    Banned
    12,387
    2
    0
    Not too shabby! The methods behind achieving this are similar—if not exactly the same—in both Sonic 1 and Sonic 2, so it doesn't surprise me that you were able to work this out so quickly. It's a nifty little guide, for sure; hopefully some talented artists and whatnot can make good use of this.

    Nice job, though! Thanks for writing up the step-by-step details—it should definitely help out those who aren't too technically inclined. :colbert:
     
  7. silent.creature

    silent.creature

    Silent Creature Member
    18
    0
    0
    Brazil
    Studying both to work and to get back to some stopped hobbies...
    Alright, but I haven't read that guide completely, just its beginning. Collision was a trial and error test and I still can't make that procedure call the data like that is shown in the rom (all that procedure first, and then the data; and not a space between the procedures with some sort of data), to keep the code organized (specially because I make a real disorder in any code).
     
  8. Alriightyman

    Alriightyman

    I am back... from the dead! Tech Member
    357
    11
    18
    Somewhere in hot, death Florida
    0101001101101111011011100110100101100011 00000010: 0101001100000011 01000101011001000110100101110100011010010110111101101110
    I would recommend using S&K's Collision. You won't have to make a sub-routine for each act, and it saves a ton of space! Look for this label:

    Code (Text):
    1. LoadSolids:
    You'll have to edit it a tiny bit to make it work in sonic 2 though. It's not too hard. Good luck!

    EDIT: Not the collision data, but the code.
     
  9. c1owd

    c1owd

    Previously 'CarrascoZX0' Member
    183
    0
    16
    Hm, I think I remember reading a tutorial about this... I'll try to find it again...
     
  10. Eduardo Knuckles

    Eduardo Knuckles

    Not a loved one, but the most hated person. Banned
    414
    10
    18
    Someplace somewhere
    Project S.A.M.G.
    I had noticed it. =P
    But the procedure I used in Sonic 2 Harder Levels is the same I used in the Sonic 1's hack. As well, it's a good initiative in done it. Certainly it will be welcome to me. Great work so far, silent.creature!
     
  11. silent.creature

    silent.creature

    Silent Creature Member
    18
    0
    0
    Brazil
    Studying both to work and to get back to some stopped hobbies...
    I've been trying to study that collision loading procedure, but, since I couldn't understand the RAM addresses used, I prefer to make the base in part of Sonic 2 code, more specifically in the procedure which loads the level size array. I've also used it in loading art tables. So, thank you for the suggestion.
     
Thread Status:
Not open for further replies.