mgba-emu / mgba

mGBA Game Boy Advance Emulator
https://mgba.io/
Mozilla Public License 2.0
5.67k stars 781 forks source link

Inaccurate scanline-specific RNG in Final Fantasy I #1802

Open RetroEdit opened 4 years ago

RetroEdit commented 4 years ago

Basically, the way I know this is because I have reverse-engineered the RNG for the 15-puzzle, and have taken many samples from real-console of 15-puzzle seeds on real-console. The RNG for the 15-puzzle is partially seeded by VCOUNT, and the VCOUNT values I've observed on real-console differ significantly from those I've seen on emulator.

I'll provide more specific details showing the exact discrepancy soon. Perhaps I may eventually create a testrom that narrows in on the specific timing elements that cause the difference (though this is not something I've ever done, so it would be a new challenge).

RetroEdit commented 4 years ago

FF1 uses an LCG for its randomness, with a multiplier of 0x6C078965, increment of 7. Most of the time, this operates in a fairly standard way, advancing once per frame on the overworld and whenever random numbers are needed, but the 15-puzzle is a bit different. The 15-puzzle is revealed by entering a boat and then pressing 'B' 23 times while holding down 'A'. When the sequence is entered, the screen fades out and then VCOUNT is added to the RNG state. This adds an additional level of unpredictability, but it is still possible to predict puzzles in advance and manipulate puzzle prizes to the speedrunner's favor.

I first became aware of the discrepancy between mGBA and real-console because a FF1 GBA speedrunner was researching how to RNG-manipulate the 15-puzzle. They successfully found some setups for emulator, but found the same setups did not work on real-console. By looking into it more deeply, I began to suspect the main factor in this difference was VCOUNT. Basically, VCOUNT's value when seeding the 15-puzzle is quite variable on the exact frame the last 'B' input is pressed.

Running some experiments, I collected many samples of VCOUNT from real-console by trying to press the buttons as fast as possible after turning on the console. This requires starting from a save file, but the variance in possible save files is not a significant factor; in theory, exact player stats/party composition could have some affect on how the RNG plays out, but I did not find anything to suggest this is the case from my investigations of the RNG in this particular case, as the RNG state is set to 0 on power-on, and stats have probably no affect on the timing because the player will start in the boat anyway to enter the 15-puzzle as fast as possible after powering on the console. The values for VCOUNT I got from real-console seemed quite different from those I had gotten from some cursory testing on emulator, leading me to believe that the timing was indeed significantly different as a result of varying VCOUNT values.

I have subsequently ran far more extensive experiments on emulator. This revealed a few things: for one, the value of VCOUNT is heavily periodic, depending largely on the 2400 frame music loop for the ship music. Secondly, real-console likely has higher averages for its VCOUNT values. The highest values found on console were not found on emulator at all, even though significantly more trials were conducted on emulator. However, a direct comparison is hindered by the bias in the results collected from real-console, but I will nonetheless present a graph showing the difference:

mGBA_puzzle_VCOUNT

The emulator results were just a collections of 24000 different frames for the final B-press, while the real-console results were collected from 239 distinct results I gathered from real-console. The graph is merely a rough illustration of the difference; it seems clear to me that this method of comparison can only show if emulator deviates from real-console and cannot validate when emulation becomes accurate to real-console. More incisive and specific tests are probably the way forward to solving this problem.