Before we proceed any further in our analysis, a brief digression. On the subject of
the Animate_Tiles function, reader
Silver Sonic 1992 commented:
Lava Reef zone has some type of dynamically reloading tiles. Is it just garbage data?
I completely missed this the first time around. Amidst all the pointers to null routines, the
Offs_AniFunc table actually contains a pointer to a properly-defined animation routine for Lava Reef Zone 1:
dc.w AnimateTiles_NULL-Offs_AniFunc
dc.w AniPLC_ALZ-Offs_AniFunc
dc.w AnimateTiles_LRZ1-Offs_AniFunc
dc.w AniPLC_ALZ-Offs_AniFunc
dc.w AnimateTiles_NULL-Offs_AniFunc
dc.w AniPLC_ALZ-Offs_AniFunc
Notably, apart from some tweaks to the target VRAM offsets to make the routine work also for act 2, as well as the fact that
ArtUnc_AniLRZ__BG2 seemingly grew to 1.5x its size sometime after Sonic 3's release, the bulk of the routine is quite similar to the code found in Sonic & Knuckles:
AnimateTiles_LRZ1: AnimateTiles_LRZ1:
move.w #$6400,d4
move.w #$6880,d6
bra.s loc_282D0
; ---------------------------------------------
AnimateTiles_LRZ2:
move.w #$6400,d4
move.w #$6880,d6
loc_282D0:
lea (Anim_Counters).w,a3 lea (Anim_Counters).w,a3
moveq #0,d0 moveq #0,d0
move.w ($FFFFEEE4).w,d0 move.w ($FFFFEEE4).w,d0
sub.w (Camera_X_pos_BG_copy).w,d0 sub.w (Camera_X_pos_BG_copy).w,d0
subq.w #1,d0
divu.w #$30,d0 divu.w #$30,d0
swap d0 swap d0
cmp.b 1(a3),d0 cmp.b 1(a3),d0
beq.s loc_27440 beq.s loc_2833C
move.b d0,1(a3) move.b d0,1(a3)
moveq #0,d1 moveq #0,d1
move.w d0,d2 move.w d0,d2
andi.w #7,d0 andi.w #7,d0
lsl.w #7,d0 lsl.w #7,d0
move.w d0,d1 move.w d0,d1
lsl.w #3,d0 lsl.w #3,d0
add.w d0,d1 add.w d0,d1
move.l d1,d5 move.l d1,d5
andi.w #$38,d2 andi.w #$38,d2
move.w d2,d0 move.w d2,d0
lsl.w #3,d2 lsl.w #3,d2
add.w d2,d1 add.w d2,d1
add.w d2,d2 add.w d2,d2
add.w d2,d1 add.w d2,d1
lsr.w #1,d0 lsr.w #1,d0
lea word_27446(pc,d0.w),a4 lea word_2834C(pc,d0.w),a4
lea (ArtUnc_AniALZ).l,a0 lea (ArtUnc_AniLRZ__BG).l,a0
move.w #$6020,d4
add.l a0,d1 add.l a0,d1
move.w d4,d2 move.w d4,d2
move.w (a4)+,d3 move.w (a4)+,d3
add.w d3,d4 add.w d3,d4
add.w d3,d4 add.w d3,d4
jsr (Add_To_DMA_Queue).l jsr (Add_To_DMA_Queue).l
move.l d5,d1 move.l d5,d1
add.l a0,d1 add.l a0,d1
move.w d4,d2 move.w d4,d2
move.w (a4)+,d3 move.w (a4)+,d3
beq.s loc_27440 beq.s loc_2833C
jsr (Add_To_DMA_Queue).l jsr (Add_To_DMA_Queue).l
loc_27440: loc_2833C:
cmpi.b #$16,(Current_zone).w
beq.s locret_2834A
addq.w #2,a3 addq.w #2,a3
bra.w loc_2745E bra.w loc_28364
; --------------------------------------------- ; ---------------------------------------------
locret_2834A:
rts
; ---------------------------------------------
word_27446: word_2834C:
dc.w $240, 0 dc.w $240, 0
dc.w $1E0, $60 dc.w $1E0, $60
dc.w $180, $C0 dc.w $180, $C0
dc.w $120, $120 dc.w $120, $120
dc.w $C0, $180 dc.w $C0, $180
dc.w $60, $1E0 dc.w $60, $1E0
; --------------------------------------------- ; ---------------------------------------------
loc_2745E: loc_28364:
moveq #0,d0 moveq #0,d0
move.w ($FFFFEEE2).w,d0 move.w ($FFFFEEE2).w,d0
sub.w (Camera_X_pos_BG_copy).w,d0 sub.w (Camera_X_pos_BG_copy).w,d0
andi.w #$1F,d0 andi.w #$1F,d0
cmp.b 1(a3),d0 cmp.b 1(a3),d0
beq.s locret_274BE beq.s loc_283CC
move.b d0,1(a3) move.b d0,1(a3)
moveq #0,d1 moveq #0,d1
move.w d0,d2 move.w d0,d2
andi.w #7,d0 andi.w #7,d0
lsl.w #8,d0 lsl.w #7,d0
move.w d0,d1
add.w d0,d0
add.w d1,d0
move.w d0,d1 move.w d0,d1
move.l d1,d5 move.l d1,d5
andi.w #$18,d2 andi.w #$18,d2
move.w d2,d0 move.w d2,d0
lsl.w #3,d2 lsl.w #2,d2
add.w d2,d1
add.w d2,d2
add.w d2,d1 add.w d2,d1
lsr.w #1,d0 lsr.w #1,d0
lea word_274C0(pc,d0.w),a4 lea word_283D2(pc,d0.w),a4
lea (ArtUnc_AniALZ).l,a0 lea (ArtUnc_AniLRZ__BG2).l,a0
move.w #$64A0,d4 move.w d6,d4
add.l a0,d1 add.l a0,d1
move.w d4,d2 move.w d4,d2
move.w (a4)+,d3 move.w (a4)+,d3
add.w d3,d4 add.w d3,d4
add.w d3,d4 add.w d3,d4
jsr (Add_To_DMA_Queue).l jsr (Add_To_DMA_Queue).l
move.l d5,d1 move.l d5,d1
add.l a0,d1 add.l a0,d1
move.w d4,d2 move.w d4,d2
move.w (a4)+,d3 move.w (a4)+,d3
beq.s locret_274BE beq.s loc_283CC
jsr (Add_To_DMA_Queue).l jsr (Add_To_DMA_Queue).l
locret_274BE: loc_283CC:
addq.w #2,a3
rts bra.w loc_286E8
; --------------------------------------------- ; ---------------------------------------------
word_274C0: word_283D2:
dc.w $80, 0 dc.w $C0, 0
dc.w $60, $20 dc.w $90, $30
dc.w $40, $40 dc.w $60, $60
dc.w $20, $60 dc.w $30, $90
; --------------------------------------------- ; ---------------------------------------------
Much like what happened with the level load block though, the uncompressed art used by this routine was completely wiped from the Sonic 3 ROM, leaving the code
pointing at whatever data came next. In this case it's
ArtUnc_AniALZ, which is uncompressed art normally used by
Azure Lake's animation routine.
8 comments:
At this point, I'm convinced Sonic 3 alone is just a published Sonic 3&K prototype.
Uh, that's exactly what it is. The magic is in Sonic & Knuckles, where they had to design a way to somehow patch the prototype into a complete game.
When you said all the Sonic & Knuckles zones contain an unaltered copy of Angel Island Zone's level load block; ID 0D instead seems to point at a few other offsets for some reason.
Good catch. While all the other slots are pointing at the AIZ1 intro graphics like the actual AIZ slot, zone $0D act 1 -- the ending level where Sonic and Tails fly by Angel Island in the Tornado -- is already pointing at the main level graphics as it does in Sonic & Knuckles.
So they must have planned to use Act 1 originally, instead of Act 2 like in Sonic & Knuckles.
Makes you wonder how the game would have worked if it was never split.
Ah shoot, you're right. Act 2 is the one used for the ending scene in Sonic & Knuckles. What's happening is the LoadLevelLoadBlock function (which loads the level load block) loads stuff from zone $D instead if the current level is AIZ1 and any star post has been set (including the fake one at the start of the act).
I should really get around to blogging all of that.
Got question for you, whats the deal in ice cap with snowpile that transports you to launch base?
Post a Comment