Objectives (in decreasing priority)
- Does not early start or blow up (disqualifications)
- Aims for the fastest in-game time
- Secondary goal: Aims for maximum distance
- Aims for track completion with fewest input frames
- Secondary goal: Aims for fastest in-game time
- Tertiary goal: Aims for maximum distance
I was very impressed by Omnigamer's excellent investigation into the mechanics of Dragster, suggesting that the fastest achievable time in the game is 5.57, in contradiction to Todd Rogers' claim of achieving a 5.51. It was well researched and even included a spreadsheet simulating the game making it easy to try it for yourself. However, the missing piece in the chain of evidence for me was that it was not clear that spreadsheet modeled the game correctly. Maybe you could perform actions outside what the spreadsheet allowed for a faster time? It started nagging at me, I had no choice: I needed investigate the game for myself. If nothing else, it is good science to replicate the findings to add more confidence to the results.
In some ways, I feel bad submitting this and potentially obsoleting Omnigamer's submission, with all the original research they did on this. On the other hand, this maybe more than any other category shows that no run is unbeatable, even when you think it's at its limit already.
This run ends up saving 1 frame compared to Omnigamer's run for both primary objectives, and completes the fewest input frames objective with a faster finishing time and greater distance.
Note on emulation differences
This submission uses BizHawk 2.2.2, which emulates slightly differently than BizHawk 1.12.1 used in Omnigamer's run. Specifically, this run is 5 frames shorter due to emulation differences. All 5 frames are in the initial startup phase, and you can add/remove them at the start of the input file and the rest of the input will sync fine.
So I disassembled the game for myself. It only consists of about 800 instructions total, so it was fairly easy to do. Next step, figuring out what the memory addresses are used for. Omnigamer provided a very helpful list in their submission to get started.
The first thing that became obvious is that it's not at all about emulation accuracy. The game has a main loop which is executed once per frame, and within that loop it increases the in-game time and advances the dragsters. Since we use the game's in-game timer for timing, any emulation timing inaccuracies are irrelevant. As long as the emulator executes the loop instructions in order (and it does, there are no hardware interrupts), it doesn't matter when it does it, the result will be the same. We're trying to minimize the number of iterations of that main loop here, not the number of frames.
The overall control flow starts the game up into a disabled state (the same state is also entered when switching game modes), and from there starting a new game clears most of the RAM to reset the dragsters and starts the countdown. During the game, each player is processed on alternating frames, running through exactly the same code paths. Each player has their own set of variables, including their own in-game timer, the game basically runs two isolated instances in parallel, which can't affect each other.
The game mechanics themselves work exactly as described by Omnigamer. As far as I can tell, the spreadsheet they created is an accurate representation of what happens during a game of Dragster when only looking at one of the players.
So that's all good and well, we now have a disassembly of the game, and some more confidence. But there were actually discrepancies and improvements compared to Omnigamer's original investigation and movie.
The first is an oversight in Omnigamer's model. It's not in the calculations, but in the initial conditions. As it turns out, when you start a new game, only most of the RAM is wiped, but not all of it. Most interestingly, the Tachometer is not set to zero when starting a new game, you can actually carry over your tachometer value from one game to the next. That means, instead of only being able to start off with a tachometer value that is divisible by 3, you can start out with any tachometer number you want, providing more possibilities to find an even faster starting configuration. Sadly though, as it turns out, starting at other tachometer values doesn't seem to end up allowing for any faster times or more distance than starting from values divisible by 3, at least as far as I could find. Feel free to try it out in Omnigamer's spreadsheet though, just ignore the "Must be multiple of 3" part, the maximum valid value is 31. Maybe this has interesting applications for non-TAS speedruns as well, allowing for an easier-to-perform setup (I did not investigate this; I think it's unlikely though, considering you'd need to do the tachometer setup before every attempt).
The other findings are improvements to Omnigamer's published run. The fastest in-game time of 5.57 and the largest distance with 0x62 subdistance spare are optimal from my calculations. However, the second primary goal of using the fewest input frames is not. To achieve the primary goal of the fastest in-game time and largest distance, the frame counter offset needs to be exactly 12 or 13. Due to an unintuitive quirk in how the frame counter is updated though (the active player is determined before the counter is incremented, but the frame rule is only evaluated after the counter is incremented), the bottom player actually is the first player in terms of where in its cycle the frame counter is, so it gets to the necessary offset of 12 first. In other words, it's player 2's turn at frame offset 12 and player 1's turn at 13, not the other way around as previously thought.
Thus, by having the fastest in-game time goal achieved by the bottom player, both players can start a frame earlier (with the top player starting first and using the earlier frame rule). This saves a frame compared to the current movie, with the last input on frame 337, and also makes the input file overall a frame shorter, without sacrificing any distance for the other player.
Additionally, the player using the least inputs finishes the race 20 frames (0.33 seconds) earlier than in the current movie, shortening the overall run time. Note that this was not an objective officially listed in Omnigamer's run, but it's likely they optimized for it considering they ended up with the optimal values for the chosen frame offset. Also, it feels like it fits this category well, so I added it as secondary and tertiary goals to this submission.
All data was generated using a program searching for optimal solutions based on a model of the game I extracted from the disassembly (which matches Omnigamer's model as far as I can tell).
Here's a table of the best achievable times and (sub)distances for each tachometer and frame counter offset value.
And a table for the earliest (in-game time) you can end the input, and their corresponding best finishing times and (sub)distances.
It is quite a nice coincidence that the best possible configurations for these two sets of objectives align in a way that allows showing them off in the same run. Note that the absolute fastest frame you could end the input and still finish (ignoring any other objective) is a single frame faster than shown in this run, and can be achieved by using the bottom player instead of the top player, with the exact same inputs.
Noxxa: It's interesting to see how even one of the most thoroughly researched, dissected, and optimized games still has a small optimization (be it not in-game time) left in it. For the Vault, this technically counts as an improvement - as such, accepting as an improvement to the published movie.