(Original guide by Mercury)
This guide allows you to have dynamically loaded wall art in the Special Stages. Visually, this makes little to no difference when playing the Special Stage, but it will free VRAM, leaving A LOT of room for other things, like the HUD, or new blocks/objects! This guide follows the current HG disassembly version of Sonic 1.
So the very first thing we will do, aside from backing up our disassembly, is decompress the Special Stage wall art. Now, you could simply decompress the art, and that's that, right? Wrong! Because we are using uncompressed animated art, we will be changing how the art is mapped together. The absolute easiest way to do this is to have all of the wall sprites under ONE single mapping frame. So, that means that for every possible wall frame, we will want 16 tiles. This requires some slight editing of the wall art to make every possible wall frame centered within a 32x32 pixel image. This shouldn't be too hard to do, as it really only requires fixing up the tiles for the first frame. A visual reference will be provided in the near future, to aid you. After this is done, you will want to save this art uncompressed, and relocate it to the artunc folder. With that finished, we want the asm pointing to the new art location. In sonic.asm, search for the following pointer:
Nem_SSWalls: incbin "artnem\Special Walls.bin" ; special stage walls even
and replace it with this:
Art_SSWalls: incbin "artunc\Special Walls.bin" ; special stage walls even
You don't need to change the pointer to "Art_SSWalls", but if you do, just know that you will need to perform a "Find & Replace" to correct any possible errors.
Now, we are going to change the mappings for the wall art. They currently look something like this:
; --------------------------------------------------------------------------- ; Sprite mappings - walls of the special stage ; --------------------------------------------------------------------------- Map_SSWalls: dc.w byte_2C584-Map_SSWalls, byte_2C58A-Map_SSWalls dc.w byte_2C590-Map_SSWalls, byte_2C596-Map_SSWalls dc.w byte_2C59C-Map_SSWalls, byte_2C5A2-Map_SSWalls dc.w byte_2C5A8-Map_SSWalls, byte_2C5AE-Map_SSWalls dc.w byte_2C5B4-Map_SSWalls, byte_2C5BA-Map_SSWalls dc.w byte_2C5C0-Map_SSWalls, byte_2C5C6-Map_SSWalls dc.w byte_2C5CC-Map_SSWalls, byte_2C5D2-Map_SSWalls dc.w byte_2C5D8-Map_SSWalls, byte_2C5DE-Map_SSWalls byte_2C584: dc.b 1 dc.b $F4, $A, 0, 0, $F4 byte_2C58A: dc.b 1 dc.b $F0, $F, 0, 9, $F0 byte_2C590: dc.b 1 dc.b $F0, $F, 0, $19, $F0 byte_2C596: dc.b 1 dc.b $F0, $F, 0, $29, $F0 byte_2C59C: dc.b 1 dc.b $F0, $F, 0, $39, $F0 byte_2C5A2: dc.b 1 dc.b $F0, $F, 0, $49, $F0 byte_2C5A8: dc.b 1 dc.b $F0, $F, 0, $59, $F0 byte_2C5AE: dc.b 1 dc.b $F0, $F, 0, $69, $F0 byte_2C5B4: dc.b 1 dc.b $F0, $F, 0, $79, $F0 byte_2C5BA: dc.b 1 dc.b $F0, $F, 0, $89, $F0 byte_2C5C0: dc.b 1 dc.b $F0, $F, 0, $99, $F0 byte_2C5C6: dc.b 1 dc.b $F0, $F, 0, $A9, $F0 byte_2C5CC: dc.b 1 dc.b $F0, $F, 0, $B9, $F0 byte_2C5D2: dc.b 1 dc.b $F0, $F, 0, $C9, $F0 byte_2C5D8: dc.b 1 dc.b $F0, $F, 0, $D9, $F0 byte_2C5DE: dc.b 1 dc.b $F0, $F, 0, $E9, $F0 even
These are mappings for 16 frames. All of them but the first one are 4 tiles x 4 tiles, with the first frame being a 3x3 frame. This requires 249 ($F9) tiles loaded into VRAM to work. What we are going to do is consolidate this down to one single mapping. It will look like this:
; --------------------------------------------------------------------------- ; Sprite mappings - walls of the special stage ; --------------------------------------------------------------------------- Map_SSWalls: dc.w byte_2C584-Map_SSWalls byte_2C584: dc.b 1 dc.b $F0, $F, 0, 0, $F0 even
Now every frame can be created with one single mapping. Each one will be a 4x4 sprite, and will only require 16 tiles to be loaded into VRAM to make it happen. As the frame change is needed, the game simply needs to change the 16 tiles that are loaded into VRAM, and because EVERY wall tile will always be on the same frame at the same time, that's that! Now let's get the game to do just that!
Next, we need to make some tweaks to the code. Go to VBla_0A: and find @nochg:. Just below it, insert this code:
cmpi.b #96,(v_hbla_line).w bcc.s @update bra.w @end @update: jsr SS_LoadWalls
Now let's go to VBla_16:, and, again, find @nochg:. Just below it, insert the same code block as above.
Now we need to go to GM_Special: and find SS_ClrNemRam:. You will see this chunk of code.
SS_ClrNemRam: move.l d0,(a1)+ dbf d1,SS_ClrNemRam ; clear Nemesis buffer clr.b (f_wtr_state).w clr.w (f_restart).w moveq #palid_Special,d0 bsr.w PalLoad1 ; load special stage palette jsr SS_Load ; load SS layout data move.l #0,(v_screenposx).w move.l #0,(v_screenposy).w move.b #9,(v_objspace).w ; load special stage Sonic object bsr.w PalCycle_SS clr.w (v_ssangle).w ; set stage angle to "upright"
Just below the line that loads Special Stage Sonic, add this line:
move.b #$FF,(v_ssangleprev).w ; fill previous angle with obviously false value to force an update
This v_ssangleprev is a new RAM variable, so we are going to need to add an equate for it. In Variables.asm, add it wherever you have a free byte of RAM.
Next we are going to SS_AniWallsRings: to change how the walls are animated. Remove the following chunk right at the start of the section:
lea ($FF400C).l,a1 moveq #0,d0 move.b (v_ssangle).w,d0 lsr.b #2,d0 andi.w #$F,d0 moveq #$23,d1 loc_1B2A4: move.w d0,(a1) addq.w #8,a1 dbf d1,loc_1B2A4
Next, go to the end of the section where you will find a data table that looks like this:
; =========================================================================== SS_WaRiVramSet: dc.w $142, $6142, $142, $142, $142, $142, $142, $6142 dc.w $142, $6142, $142, $142, $142, $142, $142, $6142 ...
Just above that, we are going to create a new subroutine to load the wall art dynamically. Insert this code above the table:
SS_LoadWalls: moveq #0,d0 move.b (v_ssangle).w,d0 ; get the Special Stage angle lsr.b #2,d0 ; modify so it can be used as a frame ID andi.w #$F,d0 cmp.b (v_ssangleprev).w,d0 ; does the modified angle match the recorded value? beq.s @return ; if so, branch lea ($C00000).l,a6 lea (Nem_SSWalls).l,a1 ; load wall art move.w d0,d1 lsl.w #8,d1 add.w d1,d1 add.w d1,a1 locVRAM $2840 ; VRAM address move.w #$F,d1 ; number of 8x8 tiles jsr LoadTiles move.b d0,(v_ssangleprev).w ; record the modified angle for comparison @return: rts
SS_LoadWalls uses the new RAM variable to determine when new tiles are loaded into VRAM. Every time tiles are loaded, $10 tiles will be loaded to VRAM at address $2840. You can find this in a Regen VRAM dump at location 142, the same location that the tileset was previously loaded to. The big difference now, is that you have room for an additional 233 ($E9) tiles for use. You can use that for plenty of things, most notably a HUD! Now there is one final thing we need to do. We still have a Pattern Loading Cue for Special Stage walls to be loaded in this same spot... Having this means that all 256 tiles will be loaded to VRAM, meaning that not only will we not have the desired free VRAM, but even worse, the Bumper art will be overwritten! To fix this, simply go to inc\Pattern Load Cues.asm and at PLC_SpecialStage:, remove the following line:
plcm Nem_SSWalls, $2840 ; walls
That should be it! Enjoy the freed VRAM! Also note that another advantage to this method is that you can freely add more art to make more in-between frames to make the rotation even smoother!
(Additional fix by Cinossu)
Speaking of smoother rotation, you may also want to implement this change as well. Go to SS_ShowLayout: and take out this line:
|SCHG How-To Guide: Sonic the Hedgehog (16-bit)|
|Fix Demo Playback | Fix a Race Condition with Pattern Load Cues | Fix the SEGA Sound | Display the Press Start Button Text | Fix the Level Select Menu | Fix the Hidden Points Bug | Fix Accidental Deletion of Scattered Rings | Fix Ring Timers | Fix the Walk-Jump Bug | Correct Drowning Bugs | Fix the Death Boundary Bug | Fix the Camera Follow Bug | Fix Song Restoration Bugs | Fix the HUD Blinking | Fix the Level Select Graphics Bug | Fix a remember sprite related bug|
|Changing Design Choices|
|Change Spike Behavior | Fix Special Stage Jumping Physics | Improve the Fade In\Fade Out Progression Routines | Fix Scattered Rings' Underwater Physics | Remove the Speed Cap | Port the REV01 Background Effects | Port Sonic 2's Level Art Loader | Retain Rings Between Acts | Add Sonic 2 (Simon Wai Prototype) Level Select | Improve ObjectMove Subroutines | Port Sonic 2 Level Select|
|Add Spin Dash ( Part 1 / Part 2 / Part 3 / Part 4 ) | Add Eggman Monitor|
|Expand Music Index From $94 to $9F | Extend Music Slots | Play Different Songs Per Act | Expand Music Index to Start at $00 | Port Sonic 2 Final Sound Driver | Port Sonic 3's Sound Driver|
|Extending the Game|
|Load Chunks From ROM | Add Extra Characters | Make an Alternative Title Screen | Use Dynamic Tilesets | Make GHZ Load Alternate Art | Add a New Zone | Set Up the Goggle Monitor | Add New Moves | Add a Dynamic Collision System | Dynamic Special Stage Walls System | Extend Sprite Mappings and Art Limit | Enigma Credits|
|Convert the Hivebrain 2005 Disassembly to ASM68K|
|Split Disassembly Guides|
|Set Up a Split Disassembly | Basic Level Editing | Basic Art Editing | Basic ASM Editing (Spin Dash)|