Hey, did you know that checkpoints don't exist or even function at all in the past or future time zones? In fact, the game even has code that forces Sonic to spawn at the beginning of the stage if you're not in the present when he dies.
I genuinely never noticed this and it didn't seem right to me, but I went and checked and it's absolutely true - the present time zones have checkpoints pretty liberally placed all over, but they're completely absent in every other time zone. Incredible that I never noticed it before.
Since checkpoints have an internal order (most noticeable in Emerald Hill Zone), I guess they just didn't know how to handle multiple checkpoints at potentially different locations in different timezones, and they didn't feel like using two more bytes of RAM. But it's only a guess.
Here's a bonus fun fact. In Palmtree Panic act 1, in the present, the checkpoint object is set to ID 0x13, but in the other time zones, they are set to ID 0x2B. The checkpoints in the present for that stage wouldn't have even shown up for the other time zones because of this!
I always noticed you'd restart at the beginning if you died or restarted in the past, but it'd never occurred to me that was why. Interesting!
I think I found the relevant code for the C port in PLAYER.C, function play00erase. A "checkpoint" is apparently known as a "marker" there: Code (Text): if (markerno == 0 && time_flag == 1) play_start &= 253; if (pl_suu != 0) { if (time_flag == 1) { if (markerno != 0) plflag = 1; } else { plflag = 0; } } sub_sync(14);
I knew about the restarting thing for a while now... maybe I've just played the 2011 version quite a bit. If I had to guess, I suspect that it would be a problem if, after time-traveling, respawning at a checkpoint's coordinates would lead to you being stuck inside a wall or something.
There's an inconsistency in the code for the first boss in the C version. I wonder if it's also in the Mega CD original. In file BOSS_1.C, function egg1leg1_11, lines 2961 and 2962, it retrieves the ID of a sub-object: Code (Text): subact = pActwk->actfree[6]; subact = actwk[subact].actfree[6]; What's wrong with it? Usually these IDs are retrieved as a short, not as a char, like this: Code (Text): subact = ((short*)pActwk)[26]; The maximum ID is 128, which fits in one byte, so at first glance this isn't an issue. However, on a big-endian system (like the GameCube), this would retrieve the high byte, which would be zero.
That looks like a bug they made while translating the code. The original game treats it like the latter. Code (Text): ROM:0020D0EE egg1leg1_11: ROM:0020D0EE btst #0,actfree+2(a0) ROM:0020D0F4 bne.s loc_20D12E ROM:0020D0F6 movea.w actfree+6(a0),a1 ROM:0020D0FA movea.w actfree+6(a1),a1 (Here, the values are direct 16-bit addresses in work RAM rather than offsets in the "actwk" pool, since they get sign extended, but it's basically the same logic)