Speed Up Ring Loss Process (With Underwater)
From Sonic Retro
Revision as of 22:55, 6 May 2012 by KingofHarts (talk | contribs) (→Part 2: Edited a change in ASM)
Part 2
Ok, so I ported the S3&K priority manager into my hack [Sonic 2 Recreation], and you can make the scattered rings object do something extremely similar. So this is only making one object do it, but because of the amount of rings you can lose, this actually makes a BIG difference (as usual, especially underwater).
Go to "loc_120BA:" (part of the scattered rings object) and delete this line: <asm>
move.b #3,priority(a1)
</asm>
When the rings are being created, it won't have to move 3 to it's priority anymore, saving a command per ring created and slightly speeding it up (you'll probably won't notice any difference, but this isn't what I am trying to accomplish here).
Now you're probably thinking "WTF! The rings aren't going to be displayed now!" Well, in a way, you're wrong. It will still be displayed, but with a priority of 0. Now, we do not want that, we still want it to be 3, and we're about to fix it, and this will be what speeds it up dramatically.
Go to "loc_121B8" and you should see a command: <asm>
bra.w DisplaySprite
</asm>
We are going to replace this with a new code, similar to how S3K does it. In S2, before it can display the sprite, it converts the object's priority into a word, and then displays it. It does calculations that are about 3 lines long to convert it into a word. When lots of objects use this code every single frame (Sonic and Tails constantly for example), it can be a slow process.
Now, imagine you just got hurt and lost 32 rings, each one of them 32 rings branches to DisplaySprite, does the calculations, then displays the sprite; every single frame! All 32 of them! This slows it down quite a bit! Now, you can't just turn the scattered ring's priority into a word, otherwise it will over-write the scattered rings's "width_pixel". So, what do we do? Well, we can just copy part of the DisplaySprite's coding and insert it into the scattered rings' object coding.
Now, normally, after the rings have jumped to DisplaySprite to convert it's priority into a word, it becomes $180. Look at this:
Priority = 3 (byte) <asm> DisplaySprite:
lea (Sprite_Table_Input).w,a1 move.w priority(a0),d0 ; To be deleted lsr.w #1,d0 ; To be deleted andi.w #$380,d0 ; To be deleted adda.w d0,a1 ; To be changed cmpi.w #$7E,(a1) bcc.s return_16510 addq.w #2,(a1) adda.w (a1),a1 move.w a0,(a1)
return_16510:
rts
</asm>
Now, Priority = $180 (word)
So, we're going to copy this code, then edit it a bit, then move it to the scattered rings object. So copy it, then move it to where the branch was in the scattered rings object. So you have something looking like this:
WAS: <asm> loc_121B8:
tst.b (Ring_spill_anim_counter).w beq.s BranchTo5_DeleteObject move.w (Camera_Max_Y_pos_now).w,d0 addi.w #$E0,d0 cmp.w y_pos(a0),d0 bcs.s BranchTo5_DeleteObject bra.w DisplaySprite
</asm>
And change that to this: <asm> loc_121B8:
tst.b (Ring_spill_anim_counter).w beq.s BranchTo5_DeleteObject move.w (Camera_Max_Y_pos_now).w,d0 addi.w #$E0,d0 cmp.w y_pos(a0),d0 bcs.s BranchTo5_DeleteObject lea (Sprite_Table_Input).w,a1 ; To be changed move.w priority(a0),d0 ; To be deleted lsr.w #1,d0 ; To be deleted andi.w #$380,d0 ; To be deleted adda.w d0,a1 ; To be deleted cmpi.w #$7E,(a1) bcc.s + addq.w #2,(a1) adda.w (a1),a1 move.w a0,(a1)
+
rts
</asm>
"To be changed" means that line is going to be edited and the "To be deleted", well, guess what we will do with that? =P
Change <asm>
lea (Sprite_Table_Input).w,a1 ; To be changed
</asm>
To this: <asm>
lea Sprite_Table_Input+$180,a1
</asm>
As we now know 3 would equal $180, we can just add straight to a1. No more calculations every single frame, we've already done it! You should have something like this now: <asm> loc_121B8:
tst.b (Ring_spill_anim_counter).w beq.s BranchTo5_DeleteObject move.w (Camera_Max_Y_pos_now).w,d0 addi.w #$E0,d0 cmp.w y_pos(a0),d0 bcs.s BranchTo5_DeleteObject lea Sprite_Table_Input+$180,a1 cmpi.w #$7E,(a1) bcc.s + addq.w #2,(a1) adda.w (a1),a1 move.w a0,(a1)
+
rts
</asm>
So, what have we done? Well, we saved a line of it branching somewhere for a start, it's already there, so that's a plus! Also, we're moving $180 straight to a1, rather than doing them 3 lines of calculations! What a time saver! ALL done. That was easy, eh? Now your scattered rings will be even quicker, hopefully not slowing anything else down!
Part 2.5 (optional)
This is optional; you do not have to do it if you do not want to.
If you look at the code you just edited: <asm> Obj_37_sub_4:
addq.b #2,routine(a0) move.b #0,collision_flags(a0) move.b #1,priority(a0) bsr.w sub_11FC2
Obj_37_sub_6:
lea (byte_1237A).l,a1 bsr.w AnimateSprite bra.w DisplaySprite
- ===========================================================================
BranchTo5_DeleteObject
bra.w DeleteObject
</asm>
You can see a command move 1 to priority, and displaying it again. This is for when you collect the rings (when the rings turn into them sparkly effects). You can do something extremely similar here if you like. It will make quite a bit of a difference if you collect a lot of scattered rings at the same time, otherwise, it won't do too much. If you want it to do the same, then you can. But it won't be $180 again! When 1 has been through DisplaySprite's calculations, it will equal $80 instead!
So, at "Obj_37_sub_4:", delete this line/command: <asm>
move.b #1,priority(a0)
</asm>
Then, at "Obj_37_sub_6:", replace: <asm>
bra.w DisplaySprite
</asm>
with this: <asm>
lea (Sprite_Table_Input).w,a1 adda.w #$80,a1 cmpi.w #$7E,(a1) bcc.s + addq.w #2,(a1) adda.w (a1),a1 move.w a0,(a1)
+
rts
</asm>
So you have something like this: <asm> Obj_37_sub_4:
addq.b #2,routine(a0) move.b #0,collision_flags(a0) bsr.w sub_11FC2
Obj_37_sub_6:
lea (byte_1237A).l,a1 bsr.w AnimateSprite lea (Sprite_Table_Input).w,a1 adda.w #$80,a1 cmpi.w #$7E,(a1) bcc.s + addq.w #2,(a1) adda.w (a1),a1 move.w a0,(a1)
+
rts
</asm>
Done: you've made it slightly faster again!