As I was watching the
new publication, I noticed a small mistake. It's possible to enter the crooked house at 15:02 3 cycles faster. I did some testing, and the gain ends up getting wiped out by framerules later on, so the mistake does not actually lose time. But it's close—saving even 1 additional cycle in this segment of the run could catch an earlier framerule and save up to 1 second overall.
The mistake I made was entering the door near the bottom of the screen, instead of near the top. The door is activated when the player touches a signal line, represented by the color green in the
priority screen. As you can see in the graphic below, the signal line is 3 pixels closer to the right edge of the screen at the top, compared to the bottom. It doesn't lose any time to get to the top of the signal line, so I should have done that in room 15, as I did when entering similar doors at the clock house (room 24) at 11:00 and Jack Horner's house (room 26) at 12:57.
A zoomed-in crop of the priority screen in room 15, with semitransparent player characters overlaid, showing where they touch the signal line at its top and bottom.
The earlier entry into the clock house saves 3 cycles, but then causes a desync after delivering the Pail to Jack and Jill, which has to be fixed by adding 2 cycles of waiting before ending the cutscene. Let's look at the nature of the framerule. There are several places—including during delivery cutscenes—where the game delays for a fixed amount of time. It does this by setting the
special variable clock_seconds to 0, then waiting for it to exceed a certain value. Here's an example in 51.agilogic, which is the logic file for the Pail delivery cutscene:
if (!FLAG_CUTSCENE_PLAYING_f104 && FLAG_IN_POSITION_FOR_CUTSCENE_f104) {
set(FLAG_CUTSCENE_PLAYING_f104);
set(advance_sequence_f43);
reset(FLAG_IN_POSITION_FOR_CUTSCENE_f104);
sound(4, FLAG_SOUND_FINISHED_f103);
clock_seconds = 0;
set(f15);
if (video_mode != 2) {
print.at(" \n\n\n", 17, 2, 37);
display(18, 2, "Jack and Jill went up the hill,");
} else {
print.at(" \n\n\n", 19, 2, 37);
display(20, 2, "Jack and Jill went up the hill,");
}
}
if ((clock_seconds > 4) && FLAG_CUTSCENE_PLAYING_f104 && !f109) {
set(f109);
if (video_mode != 2) {
display(19, 2, " To fetch a pail of water;");
} else {
display(21, 2, " To fetch a pail of water;");
}
}
Notice
clock_seconds = 0 and
if (clock_seconds > 4).
The game engine measures time using the variables
clock_seconds, which is read/write accessible to logic code, and
clock_subseconds, which is not accessible to logic.
clock_subseconds increments 20 times a second (regardless of game speed), repeatedly counting from 0 to 19 and incrementing
clock_seconds when it wraps from 19 to 0. When the logic zeroes
clock_seconds to start a delay timer, it does not also zero
clock_subseconds, which means the first "second" may be less than a full second. A nominal delay of 5 seconds, for example, may take anywhere between 4.05 and 5.00 seconds of real time.
Why then, does the game desync only after the Pail delivery, and not with the delivery of the Horse or the Sheep, which happen after entering the crooked house and before delivering the Pail? Both of those deliveries have similar delay logic using
clock_seconds. Delivery cutscenes have many things happening at once: animation of sprites, music, and timed text in a text box. The cutscene does not end until all those mostly independent sequences are finished. The animation and music sequences have their own, separate methods of timing; animation usually works by counting game cycles rather than counting seconds. The Pail delivery, unusually, has a conditional that couples the animation timing and the delay timing:
if ((animation_counter_v48 == 5) && (clock_seconds > 9)) {
set(advance_sequence_f43);
}
There are only three other deliveries that have such a coupling: Watering Can, Mouse, and Pie.
It is actually more complicated than I have explained so far. You can fix the desync after the Pail delivery by adding not 3, but
2 cycles of delay. After that, the movie will desync again the collection of Miss Muffet (which uses a similar
clock_seconds delay). You can fix that by adding 1 more cycle of delay, but at which point the 3 cycles gained are used up, and the movie syncs to the end with no gain or loss in time. Why are only 2 cycles lost because of the
clock_seconds framerule, not 3? I think it is because of a
different framerule, one that comes into play when the game logic slows the game speed from Fast to Normal (i.e., changes the value of
cycle_delay from 1 to 2) and back again, before and after the cutscene. I observed this 2-cycle framerule a couple of times while working on the TAS; I found a way to improve an earlier section by 1 cycle, but the gain was nullified by a later delivery.
If the 3-cycle improvement on entering the crooked house doesn't help because it doesn't catch an earlier framerule, how close is that earlier framerule? Very close, it turns out: saving even 1 more cycle anywhere between delivering the Pie and delivering the Pail would do it, and save up to 1 second. In the published TAS, the zeroing of
clock_seconds happens when
clock_subseconds is 3. With the earlier crooked house entry, the zeroing of
clock_seconds happens when
clock_subseconds is 0; that is, it happens 3 cycles earlier, but then you have to wait 20 cycles to the top of the next second instead of 17 cycles. If you could get there early enough so that
clock_seconds were zeroed when
clock_subseconds was 19, the first "second" of delay would take only 1 cycle to elapse.
I say "up to" 1 second because of the other sequences that happen during the cutscene; it could be that the actual gain is less.
User movie #638120343391821721 demonstrates the faster crooked house entry.