Fix demo playback
From Sonic Retro
(Original guide by FraGag)
In Sonic 1 and Sonic 2, the demo playback routine doesn't behave correctly: it emulates press-press-press-press... instead of press-hold-hold-hold... In other words, it simulates button presses every frame the button is supposed to be held down instead of simulating a press only once. This happens because the game, to determine whether a button should be set to pressed and/or held, compares the button flags of the current frame with the button flags of the previous frame, but the demo playback routine reads the wrong value ($FFF604 instead of $FFF602). This doesn't have any negative effect in the original game demos, because pressing , or while the character is in the air doesn't do anything. However, if you record a demo using the Spin Dash, or new air moves such as the Jump Dash or the Homing Attack, and you hold down , or for more than one frame long, they will trigger too often or too early. The same buggy instruction is also what makes it possible to disrupt a demo by pressing , or while it plays in Sonic 1 REV00.
Recording new demos can be tricky if not done right, and it doesn't help when the demo doesn't play back correctly because of a bug in the original game. Fortunately, this problem is very easy to fix, and this guide will show you how to fix it in Sonic 1 REV00, Sonic 1 REV01 and Sonic 2 (any edition). Sonic 3 and Sonic & Knuckles don't exhibit this behaviour.
Sonic 1 (SVN disassembly)
In _inc\MoveSonicInDemo.asm, under @notcredits, replace these lines:
if Revision=0 move.b (a0),d2 else moveq #0,d2 endc
with this line:
In REV00, it would read from $FFF604, which contains the actual controller input instead of the fake controller input simulated by the demo playback, so this is why the player can disrupt a demo by pressing , or ; if this value is zero (i.e. if you don't press anything on the controller), the game will think that no buttons were pressed on the previous frame in the demo, which causes the game to emulate presses on every frame. In REV01, the instruction was changed to clear the register so that the controller input is ignored, making the clever press/hold detection that was supposed to happen completely useless. The solution proposed here makes it read the value from $FFF602, which tell what buttons were pressed in the previous frame in the demo.
Sonic 1 (Hivebrain's 2005 disassembly)
In Hivebrain's 2005 disassembly, this code is under loc_4056. Replace this:
Sonic 2 (SVN disassembly and Xenowhirl's 2007 disassembly)
In Sonic 2, the fix implemented in Sonic 1 REV01 was kept and applied to both characters, so we need to change 2 lines. Under MoveDemo_On_P1, replace:
moveq #0,d2 ; this was modified from (a0) to #0 in Rev01 of Sonic 1 to nullify the following line
and under MoveDemo_On_P2, replace: