I want to explain in detail how the RNG really works. Not necessarily for your benefit, but for anyone who wants to someday replicate what I did and spawn fairies and predict things.
... Except that I seem to be at a loss at words. I can't really figure out a good terse explanation, so I will go verbose on any details that come to mind to compensate. I'll probably miss a few details anyway.
RNG begins at 051A. I will call this R[1]. The following bytes are R[2] through R[9].
I have a script that detects when a screen transition occurs, by basically setting a breakpoint on a specific instruction and printing a message. When R[1] resets, which is what that instruction does, that leaves R[2] to R[9]. However, none of R[3] through R[9] is used for new RNGs, and R[1] has already reset, so only R[2] has any impact. And one bit out of R[2] (0x01) is not used at all for new RNGs, leaving the other 7 bits (0xFE) as the only effect left. In my script, I divide R[2] by 2 and report a number from 0 to 127.
Obviously, I also have a piece of code to calculate future RNGs. One thing I've been doing is simply counting frames from when R[1] is last reset to when the RNG becomes important. The frame count is less about FCEUX's (or another emulator's) frame count, but more whether the game updated its own timers. Once I have a minimum frame count to important event, then I can pick out an initial R[2] and do fancy calculations to see if the right things happen. Presumably, we can delay an arbitrary and precise number of frames as desired, so if the minimum is 705 frames, and none of the 128 R[2] works, we can check at 706 frames, or 707, and so on.
Where the gTimer (Global Timer, 0500) comes in is the fact it is persistent between screen transitions, and the fact some events use this and the RNG together. There are two types of overworld spawns: Ones that run down its clock regardless of what you do (gTimer spawn, 0516), and the other ticks down based on you moving about (Step Timer spawn, 0026). Notably, the gTimer spawns use the gTimer, so the only way to adjust when they happen when we're already deep in monster territory is to either wait in 21-frame blocks at the last side-scrolling screen or delay when we enter the last side-scrolling screen. This delay prior to the side-scrolling screen will also affect the RNG, as it runs through a calculation step each frame, and you also get a different R[2]. So, for the gTimer spawns, there are 2688 initial starting conditions, gTimer and R[2] together, where you can adjust what you get. Again, you can always delay in 21-frame chunks to get to the next gTimer thing.
There is also the aTimer (Area Timer, 0012). I name it such as it resets the same time R[1] resets, on a side-scrolling screen transition. Actually, not quite the same time (37 or 38 frames apart, by my count)), but as we have no control over this, it is not considered important for a lot of things. Still, by delaying a frame before we transition in, we have a different gTimer, and therefore a different relation between gTimer and aTimer. The aTimer is critical for spawn movements, as they will only decide a new direction when aTimer modulo 16 is zero. The groups will pick a direction based on what internal slot they fill, selecting out R[2] to R[9] based on the slot. Indeed, on your last screen transition, if you have the same R[2] but different gTimer, it is possible that enemies will pick the same directions.
So anyway, in my scripting, I try to count out how many RNG calls (a script watches gTimer for this), then once I know how many from last transition to important event (or multiple events in sequence), figure out whether the minimum calls can work or if I need to add delays. In my sample for the last fairy we spawn, the earliest I can get a west fairy spawn that immediately travels east is at 829 and 830 frames, both requiring R[2]=31 at time of screen transition. At 831 to 858 RNG calls, not a single one of the R[2] possibilities exist that fit my criteria, so I keep re-rolling that RNG until the next shot comes up. 859, we have R[2]=72. There are other things than just that fairy that uses the RNG, as evidenced by the Skettlar, and those things need to work out if that possibility is going to work at all.
Side note: If you need a "from start" movie that has R[2]=31 at that spot, I can make one easily enough.
Anyway, once I know the number of RNG calls, I can figure out my initial gTimer. When gTimer underflows from 0 to 20, it decrements a counter for the gTimer spawn. So, a gTimer spawn will always trigger at the same moment gTimer is 20, not counting terrain that denies spawns. gTimer decrements every frame, but we need to go backwards, so add our call count (829 from my sample), modulo 21, and we have a gTimer of 9. So, with R[2]=31, I would also want gTimer=9. 830 is also a possibility, which is gTimer=10. The reason why there are consecutive gTimers that work with the same R[2] is probably an artifact of the RNG the game uses, and it happens to have a sequence of 9+ bits all 1s being shifted through the "spawn fairy" part, and the directions traveled depend on aTimer and will only pick every 16th RNG call.
Pathing is critical for the fairy encounters at the Reflect Trek, and we're also highly constrained in screen transitions since our last restart. Since the aTimer has 37 or 38 frames to run before R[1] resets, my RNG calls counter is actually 37 or 38 frames behind the aTimer. So when triggering an important encounter, I add 37 or 38 to the RNG calls to figure out where the aTimer is sitting, and figure out when the decision is made. If I know in advance what slots things will spawn in, I will know their exact path. Things just get plain messy if there are multiple spawns and the important one is the last one of them, where the other spawns may or may not disappear off the screen edge by then, and it's really hard to tell which slot our important fairy will show up in.
Still, with constraints known, a program can trim out useless possibilities, and there are a lot of them where fairies don't spawn, so we have a better shot at manually checking what's left. I guess thanks for reading this verbose explanation, but if I can figure out something smaller and simpler, I'll try it again with that thought.