The first step towards achieving a seamless transition is to replicate the end of act 1 at the start of the act 2 layout. This is where splitting level data into "primary" and "secondary" sets comes into play: by ensuring only tiles from the primary set are visible during the act 1 results screen, act 1's secondary tile set can be swapped out for act 2's without affecting anything present on screen.
Covering up the background plane with foreground tiles makes for an easier transition, because then the position of the background scroll doesn't have to be maintained between acts. It also lets act 2 use a completely different background, without ever having to reconcile the two. Finally, it frees up act 1's background tiles to be overwritten, either by the act 2 tiles or by the boss' own graphics.
Below is the Hydrocity Zone 1 boss area, as it appears in the act 1 and act 2 level layouts. Interestingly, the act 2 entry corridor is present in the act 1 layout, even though the player can never get there legitimately.
Let's do a quick breakdown of the intervening code:
HCZ1_BackgroundEvent: move.w ($FFFFEEC2).w,d0 jmp loc_50BC6(pc,d0.w) ; --------------------------------------------------------------------------- loc_50BC6: bra.w HCZ1BGE_Normal ; --------------------------------------------------------------------------- bra.w HCZ1BGE_DoTransition ; --------------------------------------------------------------------------- HCZ1BGE_Normal: tst.w ($FFFFEEC6).w beq.s loc_50C2AFirst, the background event function waits for the signal from the level results object at RAM address $EEC6. While the transition has yet to start, loc_50C2A simply draws the HCZ1 background as usual.
clr.w ($FFFFEEC6).w ; Do transition movem.l d7-a0/a2-a3,-(sp) lea (HCZ2_128x128_Secondary_Kos).l,a1 lea ($FFFF0A00).l,a2 jsr (Queue_Kos).l lea (HCZ2_16x16_Secondary_Kos).l,a1 lea ($FFFF9558).w,a2 jsr (Queue_Kos).l lea (HCZ2_8x8_Secondary_KosM).l,a1 ; Load secondary HCZ2 art, blocks, and chunks move.w #$2360,d2 jsr (Queue_Kos_Module).lAs soon at the signal goes off, the background event function goes to work loading the secondary level data. This does not use the level load block at all, and is surprisingly hardcoded for every level. As best as I can tell, this is because the level load block doesn't contain any information about the size of the primary data once it's decompressed, so it doesn't know where to decompress the secondary data to without first decompressing the primary data.
moveq #$10,d0 jsr (Load_PLC).l moveq #$11,d0 jsr (Load_PLC).l ; load HCZ2 PLCs movem.l (sp)+,d7-a0/a2-a3 st ($FFFFEEE8).w addq.w #4,($FFFFEEC2).w loc_50C2A: jsr HCZ1_Deform(pc) lea (Camera_Y_pos_BG_copy).w,a6 lea (Camera_Y_pos_BG_rounded).w,a5 moveq #0,d1 moveq #$20,d6 jsr Draw_TileRow(pc) lea (HCZ1_BGDeformArray).l,a4 lea ($FFFFA800).w,a5 jmp ApplyDeformation(pc) ; ---------------------------------------------------------------------------After queueing a couple of PLCs, the background event routine counter at RAM address $EEC2 gets incremented, and so beginning next frame, HCZ1BGE_DoTransition will run instead.
HCZ1BGE_DoTransition: tst.b (Kos_modules_left).w bne.w loc_50CDC ; Don't do anything else until kos queue has been clearedThis one's kind of important. Nothing happens until all the level data is done decompressing.
move.w #$101,(Current_zone_and_act).w ; Change the act clr.b (Dynamic_resize_routine).w ; Reload resize routine counter clr.b (Object_load_routine).w ; Reload sprite manager clr.b (Rings_manager_routine).w ; Reload ring manager clr.b (Boss_flag).w ; Unlock the screen clr.b ($FFFFFF97).w ; Refresh sprite/ring memory jsr Clear_Switches(pc) move.l #Obj_HCZWaterSplash,($FFFFB172).w ; Load the splash object move.b #1,($FFFFB19E).wBecause of this. Right off the bat, the current level value in RAM is changed to zone $1, act $1, more commonly known as Hydrocity Zone 2. Once this happens, the next time the function runs, it will run the background events for act 2, so this is the last frame in which to do everything that's still left over.
movem.l d7-a0/a2-a3,-(sp) jsr (Load_Level).l ; Load HCZ2 layout jsr (LoadSolids).l jsr (CheckLevelForWater).l move.w #$6A0,d0 move.w d0,(Water_level).w move.w d0,(Mean_water_level).w move.w d0,(Target_water_level).w ; Set the water up moveq #$D,d0 jsr (LoadPalette_Immediate).l ; Load HCZ2 palette movem.l (sp)+,d7-a0/a2-a3The Load_Level and LoadSolids functions load the act 2 level layout and collision data. Since both of them are stored uncompressed in the ROM, they can be quickly loaded within a single frame, ensuring there is no gap where the level's solidity is compromised.
move.w #$3600,d0 moveq #0,d1 sub.w d0,($FFFFB010).w sub.w d0,($FFFFB05A).w jsr Offset_ObjectsDuringTransition(pc) sub.w d0,(Camera_X_pos).w sub.w d0,(Camera_X_pos_copy).w sub.w d0,(Camera_min_X_pos).w sub.w d0,(Camera_max_X_pos).w ; Offset objects/camera position by specified amount jsr Reset_TileOffsetPositionActual(pc)The Offset_ObjectsDuringTransition function goes through every active SST in object RAM, and adjusts their X and Y positions based on the values stored in the d0 and d1 registers. The act 1 boss area is $3600 pixels further to the left in the act 2 layout, so this makes it seem like everything stays in place.
clr.w ($FFFFEEC2).w loc_50CDC: jsr HCZ1_Deform(pc) lea (Camera_Y_pos_BG_copy).w,a6 lea (Camera_Y_pos_BG_rounded).w,a5 moveq #0,d1 moveq #$20,d6 jsr Draw_TileRow(pc) lea (HCZ1_BGDeformArray).l,a4 lea ($FFFFA800).w,a5 jmp ApplyDeformation(pc)Finally, the routine counter at $EEC2 is cleared, ready to start running background events for HCZ2. Strangely enough, after this the code falls directly into loc_50CDC, a duplicate of loc_50C2A that renders HCZ1's background, which isn't really there anymore. Oh well, it's just for this one frame.
Next, we'll take a look at those corner cases I mentioned at the start.
Corner cases as in the AIZ1/ICZ1 transitions?
ReplyDeleteAlso, what if you're in an unintented position during the transition which underflows your X position at the start of Act 2?
And if you glitch through the rising lava section in LRZ1 and head to the boss, why doesn't the act transition happen completely (loads the Act 2 palette and object art but not the level or object layout)?
so many questions~
You guessed all but one of them. Good job!
Delete