How speed works
Firstly, here's a load of useful RAM addresses. There are bunch Vhyrro gave me, and then I tested while referencing the "VARS.PDS" file in the source code to find everything useful.
User movie #68108177071818206
Robin's X speed (0x311) increases by 1 each frame you're running, to a max of 47. If you crouch it instead decreases by 1 each frame, for the crouch duration of 21 frames. Stopping will set it to 0, and turning will set it 0 turning left, or 2 turning right.
The subpixel value (0x307) starts at 0, and each frame it either decreases (while moving left) or increases (while moving right) by the value of your X speed on the next frame multiplied by 5. So if you run left from the start, it will go 0, 251 (-5), 241 (-10), 226 (-15), 206 (-20), etc, changing by 5 more each time. This is up to a max change of 230 on the frame you reach 46 speed, and then the subpixel value stays constant once you have 47 speed (the max).
But how are these values used? Well:
- to begin, you move one pixel each frame
- if the subpixel value wraps around, you move an extra pixel
- jumping always moves you an extra pixel on the exact frame you jump, and doubles the amount the subpixel value changes for one frame only. This means it can wrap around twice on one frame, for a total of four pixels that frame
- for the rest of the jump, the amount the subpixel value changes by is constant, since your X speed is constant (unless you hit a wall)
So after you run for 46 frames, you'll run at a constant 2 pixels a frame.
If you jump while at max speed then you'll always move two pixels each frame in the air.
On the frame you jump, you'll move at least two pixels, up to a max of four.
Note that there is one frame that you don't move when landing from a jump, so four pixels at the start and zero at the end cancel out: it isn't faster to do extra jumps along the ground for no reason.
There's also a small discrepancy between running left and running right: when you run right the X speed of 1 is skipped, and it goes from 0 to 2. This means your X subpixel will start by going from 0 to 10.
Here's an example: starting with a subpixel of 0, you run right for 12 frames and then jump on the 13th frame.
The values while running are:
0, 10 (+10), 25 (+15), 45 (+20), 70 (+25), 100 (+30), 135 (+35), 175 (+40), 220 (+45),
14 (+50), 69 (+65), 129 (+70), 194 (+75).
On the 10th frame (in bold) the speed wraps around, so Robin moves two pixels instead of one.
Then the jump. The next increase is 70, which gets doubled to 140, and 194 + 140 = 334 which comes out to 78 with a wrap around. This means he moves two extra pixels this frame: one that always comes on the first jump frame, and one from the wrap around.
So the total pixels moved comes out to:
1 for each of the 13 frames
+1 for the one frame the subpixel value wrapped around while running
+2 for the jump, from the constant and then the wrap around
Totalling 16 pixels! And if you check in game, you'll see that's what happens.
The X speed address also happens to be the address set to 255 for hyperjumps. Having a value above 47 messes with the calculation in ways I don't understand, and it means you no longer have that two pixel per frame guarantee from reaching max speed. There is an upside, however: some speed values will give you really nice jumps that are *almost* constantly two pixels per frame. One such value is 146, which (while moving left, since hyperjumps only work going left) decreases the subpixel value by 249 each frame, larger than normally possible. So you only lose a pixel roughly every 37 frames compared to a regular full speed jump!
Instead of figuring out the formula, I just looked at each value to get a list of the best, with the most important in bold:
X Speed: Subpixel Increase
047: +00 (no glitch)
052: +23
059: +23
068: +23
079: +07
082: +16
095: +23
102: +07
139: +23
146: +07
165: +24
168: +07
201: +05
205: +16
228: +07
244: +24
247: +07
255: +04
I figured representing it as an increase was clearer here: +4 means -252 and the value wrapped around. So jumping with a speed of 255 only loses a pixel every 256 / 4 = 64 frames!
These values are the most important ones because the initial speed you have from the hyperjump is either 235 or 255 depending on if you get the crouch animation or not.
From 235, 244 is the first good value, and then 247 and 255 are very close. In situations where you need to chain hyperjumps you can't reuse the same value constantly (it always increases by at least 1), making this combination a great choice.
From 255, it takes one frame to halve your speed to 128, or two frames to get it to 64. That means it takes 19 frames to reach 146 speed, but only 17 frames to reach 79. If you don't need much more than regular height then that makes 79 the best value! But if you need considerable height then 146 will get you up anywhere.
I hope this explanation was vaguely comprehensible. The subpixel value is never, ever cleared, even on death, which makes optimising and syncing pretty tricky, given how it works.
One final neat thing is you can actually manipulate your subpixel while clipping through a ceiling, without losing frames. I managed to get it to 64 different values going from the first to the second room, 1/4 of the total, which should be a lot to work with! I'm not sure what value will be best. It might simply be the highest, 253, to start gaining pixels as soon as possible when moving right in the second room? It will certainly all need tested carefully.