Posts for FatRatKnight

Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
My gut reaction was that I did not like the idea of running through the start area as quickly as possible because of this checkpoint doing the killings for you. I can go through the emotional response that it looks all cool and stuff that you're going out of your way to slay them yourself, but I soon thought of a more rational approach. My main thought boils down to one thing: Differing content. Well, we have any%. It's goal is to clear through the game as quickly as possible, with rather few restrictions. We have the 100% that has the additional restriction to save everyone, and the "maximum casualties" which is to slay whoever you can. A choice was made in the previous run to give more differing content. An effort in that, even though the game kills everyone up until this checkpoint, the run still goes out of their way to kill them personally. If we use this checkpoint as an excuse for not doing so ourselves, then for this segment of the run, we are using, effectively, any% rules. We lose out on differing content for the sake of a faster run and our deaths counter remaining the same. I can always throw a hypothetical: What if someone was hacking the game a bit and found some unused piece of code, another of these checkpoints, that bring the casualties up to 65 if you haven't rescued any of them. And through glitches, we can trigger this unused code. Such a run triggering this hypothetical checkpoint would squeeze us much more closely to the any% run. The most extreme hypothetical is, naturally enough, we use Arbitrary Code Execution to tweak the counter directly. This is almost certainly unacceptable, so I want to ask, where's the best spot for our line? I'm of the opinion that we keep the line rigid with past choices, so long as these choices improve or maintain the differing content I adore. The moment any segments suddenly snap to what an existing run already does, despite being an entirely different branch, I get a little upset by this. We lose an interesting detail, only to show another detail covered elsewhere anyway. I will still respect any decision made here, however. I just wanted to advise that the point of different branches is to show viewers interesting things that wouldn't normally be covered by our standard any% rules.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
If we're using FCEUX lua, best use things like memory.registerexec and memory.setregister for more lua-side control. Merely adjusting memory on frame boundaries surely wouldn't be enough. Move the Program Counter to skip over the rupee collection routine and have perfect detection of when it would otherwise be collected. If necessary, memory.writebyte a short piece of code in some unused spot of RAM and force the PC there. I haven't looked too deeply into other emulators for instruction level control offered by lua functions. But I did have a touch of fun messing about with the debugger and coming up with a useful script that uses memory.registerexec for handy information.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
An unexpected (but also minor) one came up near the end, when the game skipped the HP increase text on level up. I have no clue how it happened, but it did save a few more seconds (and looks funny) ...
At around frame 279000, the TAS crashes the game under FCEUX 2.2.3 now. Curious if this glitch has something to do with a well-timed interrupt and some timing changes between FCEUX 2.1.3 and 2.2.3
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
In summary: * Search using byte (usually), unsigned (always) * If you're not moving, sub-pixels are probably not changing. Search either equal or zero changes * If you are moving, sub-pixels are changing. Search either not equal or more than zero changes * Repeat these searches until you have few enough addresses to study * Sub-pixels usually are 1/256 of one pixel Sub-pixel is probably one byte. They could use two bytes for it, for those cases the developers didn't want to change to byte mode, but sub-pixels probably are in one byte. And yes, it's perfectly valid to have two-byte pixel position and one-byte sub-pixel position. Read sub-pixels as an unsigned value, it makes a lot less sense to see possible negative values with signed values. The calculation of a one-byte sub-pixel is usually just 1/256 of a pixel. In my instructions, I never said anything about greater than or less than. Just whatever isn't equal. Such instructions get more complicated, as blindly searching for "greater than" will remove the sub-pixel address you're looking for. It can be done, in that if you are moving 1 or 2 pixels, the sub-pixel got greater if you moved only 1 pixel, and smaller if you moved 2 pixels. Do not trust the graphics, trust more in the pixel address you found. When you're not moving at all, there's a good chance the sub-pixels aren't doing anything either, though I am aware of one case where that isn't true (Super Mario World's Y position comes to mind). So when I say search for equal when not moving and not equal when moving a short distance, you might find it. If you have access to change count, search based on it being 0 (did not move) or not being 0 (you did move) and reset it every time after a search. There are other possible sub-pixel patterns, but I'm talking about the one I'm more familiar with. The less familiar sorts would be the game simply counting up how many frames of movement and pick out how many full pixels to move you that frame without any fractional calculations. I'm not familiar with that, and for all I know, the game uses a global timer for that type. If it doesn't use a timer, then it would change or not change based on whether you're moving. ... Now I'm turning the topic into a tutorial. Sorry about that, everyone! We probably should go to the Newbie Corner for further explanations.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
To start with, you'll need some speed shoes. With none, you only ever move 1 pixel, and with the full amount, you only ever move 2 pixels. Neither of these will involve the sub-pixel, so you're stuck there. Pick some number in between these two extremes, so you have some pattern of 1s and 2s rather than only 1s or only 2s. Begin your search once you have some speed speed shoes, but not too many. Hold still. Search for things that did not change. Do this a few times to remove addresses changing without you moving. Move a frame east. Search for things not equal. Move another frame and repeat. Once you track that, restart your search for going south just in case they use sub-pixels for each axis. There's a good chance the sub-pixel is changing in some step of 32 (0, 32, 64, 96, 128, 160, 192, 224). If you see the address changing like that when moving, it's almost certainly what you're looking for. I'm not saying that's the only way it'll go, but my experience with sub-pixels in other games lead me to believe that's the pattern you'll likely find. Side note: Memory addresses are best referred in hexadecimal. The value at the address can be viewed in whatever form is best (decimal, hexadecimal, or some bizarre base value), but the address itself should be given in hexadecimal only, as that's standard practice.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Language: lua

local MemoryMap= { Speed= { --Version name. Boss = 0x00000000, --Your list of addresses. State = 0x00000001, Map = 0x00000002, Player_X= 0x00000003, Player_Y= 0x00000004, Money = 0x00000005 }, Power= { --The other version's name. Boss = 0x00000010, State = 0x00000011, Map = 0x00000012, Player_X= 0x00000013, Player_Y= 0x00000014, Money = 0x00000015 } } while true do local v= version() if v and MemoryMap[v] then v= MemoryMap[v] gui.text(0,45,"BOSS: "..memory.readbyte(v.Boss).." State: "..memory.readbyte(v.State)) gui.text(0,250,"MAP: "..memory.readbyte(v.Map).."("..string.format('%.6f',memory.read_u32_le(v.Player_X)/65536.0)..","..string.format('%.6f',memory.read_u32_le(v.Player_Y)/65536.0)..")") gui.text(0,265,"$: "..memory.read_u32_le(v.Money)) end emu.frameadvance() end
This would be my attempt. Basically, create a table with more tables inside, keyed to "Power" and "Speed". Once you know which version you're using, fetch the appropriate table using the key string, then use that fetched table like you did in your copied code. Naturally, you'll need to know the addresses of each version, but in case there's a few variables that aren't simply 0x10 apart between versions, you can specify that in your tables.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I believe it's because gui.drawbox was redefined during an update, and broke some older scripts. The parameter that currently defines the fill color of the box used to instead define the border color, and the old box drawing had no fill. After the change, any scripts that would use gui.drawbox now defines the fill color and gives the mess you see. Since it isn't just one script, though, you'll need to look through x_functions.lua as well, and ctrl+F for any gui.drawbox in both the script you want to use and the one I pointed out. It will use the old way of dealing with boxes, which end up doing fill color. Old: gui.drawbox(x_topleft, y_topleft, x_bottomright, y_bottomright, bordercolor) New: gui.drawbox(x_topleft, y_topleft, x_bottomright, y_bottomright, fillcolor, bordercolor) So the solution would be to insert the string "clear" just before the last parameter, so that we have six parameters instead of five, and have it define the border color like it did long, long ago.
Language: lua

-- Line 31 of SMB-Mouse.lua gui.drawbox( 6, 28 + i, 250, 92 - i, "#000000"); gui.drawbox( 6, 28 + i, 250, 92 - i, "clear", "#000000"); --Line 40 of SMB-Mouse.lua gui.drawbox(7, 29, 249, 91, "#ff" .. warningboxcolor .. warningboxcolor); gui.drawbox(7, 29, 249, 91, "clear", "#ff" .. warningboxcolor .. warningboxcolor); --Line 59 of x_functions.lua ]] gui.drawbox(x1,y1,x2,y2,color); ]] gui.drawbox(x1,y1,x2,y2,"clear",color);
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Rejected Overlord TAS. I do claim it was a serious attempt, and unless someone finds a major glitch, or perhaps a sub-frame reset for save-glitching, we're not likely getting a faster run. Rejected due to the fact the run as a whole is probably RTA viable, given some practice. Well, it's one run we can probably write off as done and rejected. One less game to think about, unless someone comes by and figure out how to beat it faster than me.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
48 tracks, all items, all gold Just in case no one bothers to look a few posts back, speed works in 8 MPH increments, so dropping to 96 from 103 has zero impact on my position. Since a slower speed slightly affects steering, I sometimes drop the accelerator just so the maximum difference in my momentum and facing is reduced, slightly. And since I don't drop below the speed threshold, I'm not any slower, actually. I'm on the fence about submitting this. If a 100% definition can be applied to this game, I probably picked the most complete definition. I'd like to know how much more 100% it can get than fetching all pick-ups, including the skull ones that reduce your ammo count, as well as getting all golds. Any% would instead pick items that would benefit the races and allow for taking 2nd or 3rd on each track the leading CPU can complete faster. ... Well, I probably will submit, thinking about it. There are potential improvements, but whether or not it is perceived that the 100% definition I picked is enough to differentiate from a theoretical any%, I probably should allow a judge to make that decision. Open permission given, in case I somehow lose track and never submitted with nice write-ups.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Language: lua

BtnA, BtnB= {A=true}, {B=true} while true do local tbl= input.get() if tabl["E"] then if emu.framecount()%2 == 0 then joypad.set(BtnA) else joypad.set(BtnB) end end emu.frameadvance() end
This would be my recommendation. In MUGG's revised code, tabl holds all the pressed keys. Now, joypad.set takes a table and looks for specific table keys to figure out which buttons to press. At the start of the loop, tabl gets a new table, then it is modified based on emu.framecount(). There is no explicit code to set nil or false to remove the true from A or B. The main reason why it's able to alternate A and B is that A and B are no longer true when the table is reset from the first line in the loop, as it keeps getting a new table from input.get(), and it's using a new table every loop that gets the default not-true value for both A and B. If it matters, the glitch in MUGG's code means that if you hold A or B on the keyboard while holding E as well, then A or B will be always set regardless of the frame count. If you have something set for those keys, and have something important to press while holding E that happens to be assigned to A or B, then you'll hit this glitch even if the controller A or B aren't assigned to keyboard A or B.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
hidaigai wrote:
(Tastudio is the best tool for me. So, I want to use bizhawk.)
Makes me want to improve on my MtEdit script for lsnes and get things to fancy levels. It's a fairly old script, but it might work for beta23 as is. I haven't watched this run yet, so I can't really say much about it. Just lurking through the messages and saw this.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Well, that is an idea. Any condition where luck is required is best handled by picking as many possible screens to delay at as possible. Note that the last time a restart is done resets both the RNG and Global Timer. No amount of manipulation will affect the initial conditions after a reset, so you'd only have to count the transitions since the last restart, and find the earliest one of that set that can be used to manipulate the thing you need, without breaking other stuff that went right, of course. As for lag management, it's hard to be certain. Delay a frame here and you remove a lag later. Net gain is zero frames in that simplified case, but it will also affect later RNG, and the gTimer is also different. Thankfully, the points where we need to change our delays has been identified, so if there's luck involved, we'll know where to scatter our delays without tearing our hair or closest equivalent out.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
On the Overworld manipulation half, I can't say the RNG manipulation will give much help for the major skips run. Might as well answer my half. Arc has more familiarity with the other techniques, of course. But on the RNG front, I don't see anything obviously useful to the 5-minute run.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
This submission was basically my fault. I manipulated that luck really hard, and look what happened. No fewer than four fairies appeared! I'll be around to answer any questions involving the fairy manipulation, I'm probably the best person for that. On a side note, seeing FF for the fairy threshold at the Valley of Death and looking at the disassembly made me wonder if fairies could spawn at all there. Since the game is looking for "greater than or equal to," I figured manipulating 255 would at least meet the 'equal to' part. The results of poking about this detail should be obvious now.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
My search for the third fairy has stopped. My search space has given no helpful results, and there's still a few potential spots to look through. There's no certainty that it'll even give the fairy we're looking for, the RNG is relatively limited (128 R[2] possibilities on transition, and we need gTiners to line up precisely). I'll still be around, in case someone else wants to take up the search. No guarantee we'll get anything.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
More bad news. I examined the second iteration. No viable prospects there, either. I also learned I need to make a tweak to my script, since if a spawn happens on (aTimer AND 0x0F) == 0, they will react immediately, not 16 frames later. One item in my list is erroneous in that it fails to display the first step (r[2]=114 gTimer=16 calls= 731 ( 747)^<>><v>vv>). Here's the bad news listed out. This time, the numbers indicate number of RNG calls to make r[2]= 91 or 30 happen. I've only manually checked two of them, but alas, the fewest RNG calls I could make were not low enough for the target calls. I've also shown cases with very high RNG calls, which means I wait long enough to go well beyond the displayed directions I have in my list. I have not examined those in detail, due to... Well, high delay.
r[2]=  0 gTimer=14 calls= 750 ( 763)v>v<v^vv>>  ====912, too south for my taste
r[2]= 20 gTimer= 7 calls= 743 ( 747)^^>vvv^v<v  ====913, lowest is 919. Fail.
r[2]= 39 gTimer= 2 calls= 738 ( 747)>><vvv>v>v  ====984
r[2]= 43 gTimer=10 calls= 746 ( 747)>vv<>^<^>^  ----890, path looks bad...
r[2]= 44 gTimer= 7 calls= 743 ( 747)>vv^^vv>v>  ====947
r[2]= 55 gTimer= 7 calls= 743 ( 747)^<v<vv^<>v  ----955
r[2]= 90 gTimer=16 calls= 731 ( 731)v^<<v>vv^<  ====901, lowest is 914. Fail.
r[2]=114 gTimer=16 calls= 731 ( 747)^<>><v>vv>  ----901, path looks bad...
r[2]=114 gTimer= 0 calls= 736 ( 747)^<>><v>vv>  ----901
r[2]=114 gTimer= 2 calls= 738 ( 747)^<>><v>vv>  ----950
This fairy just does not want to help us.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Well, not a lot of luck in my search. I haven't found any R[2]/gTimer pair that allows me to precisely time an encounter and enter the first fairy encounter (exiting town) with the right R[2]/gTimer pair for the consecutive fairy to appear. Most RNG's just don't let it happen at all, and for the some that show promise, the fairy pathing gets in the way. In one case, I'm two frames away to an ideal encounter when the fairy flies out of reach. I can keep looking, but this means delays get worse with each iteration. All the fastest spots aren't helping. My text file. I started marking "no" when I realized I could check if the RNG can produce something reasonable assuming the fairy path was perfect. And if it came up empty, I wouldn't need to TAS getting the fairy manually.
r[2]=  1 gTimer= 1 calls= 716 ( 731)v>v^v<<^<^  --~857, Path works, gTimer bad
r[2]=  4 gTimer=12 calls= 706 ( 715)v^>v^<vv><  -- 899, Path works, gTimer bad
r[2]= 34 gTimer=10 calls= 704 ( 715)vv>><<<<^v  --????, Used in movie, RNG bad
r[2]= 46 gTimer=17 calls= 711 ( 715)<<>vvv^>v^  -- 864, Path works, gTimer bad
r[2]= 47 gTimer= 8 calls= 723 ( 731)v^v<v^^v>^  -- 851, Path works, RNG bad
r[2]= 47 gTimer= 9 calls= 724 ( 731)v^v<v^^v>^  -- 851, Path works, RNG bad
r[2]= 51 gTimer= 8 calls= 723 ( 731)v><<v<v>v^  -- 851, Path works, gTimer bad
r[2]= 53 gTimer=14 calls= 708 ( 715)<v^<v>v>^v  -- 884, Path works, RNG bad
r[2]= 55 gTimer=10 calls= 704 ( 715)>>^<v<vv^<  --~883, Path works, RNG bad
r[2]= 55 gTimer=12 calls= 706 ( 715)>>^<v<vv^<  --~883, Path works, RNG bad
r[2]= 55 gTimer=13 calls= 707 ( 715)>>^<v<vv^<  --~883, Path works, RNG bad
r[2]= 55 gTimer=14 calls= 708 ( 715)>>^<v<vv^<  --~883, Path works, RNG bad
r[2]= 65 gTimer=11 calls= 726 ( 731)<>v<><v^v^  --~885, Path works, gTimer bad
r[2]= 68 gTimer=20 calls= 714 ( 715)v>>v<^v<>v  -- 867, max at 898, need 900
r[2]= 70 gTimer= 2 calls= 717 ( 731)v>v<vv^><<  -- 880, Path works, RNG bad
r[2]= 70 gTimer= 3 calls= 718 ( 731)v>v<vv^><<  --No
r[2]= 70 gTimer= 4 calls= 719 ( 731)v>v<vv^><<  --No
r[2]= 79 gTimer=18 calls= 712 ( 715)<>>>vv^<v>  --No
r[2]=105 gTimer=13 calls= 728 ( 731)<>v>v>v<^>  --No
r[2]=105 gTimer=14 calls= 729 ( 731)<>v>v>v<^>  --No
r[2]=114 gTimer=13 calls= 707 ( 715)<v^<>><v>v  --Test this (long pathing. fail)
r[2]=114 gTimer=14 calls= 708 ( 715)<v^<>><v>v  --No
r[2]=114 gTimer= 0 calls= 715 ( 731)v^<>><v>vv  --No
r[2]=116 gTimer= 9 calls= 724 ( 731)v><^vv>^v<  --No
r[2]=116 gTimer=15 calls= 730 ( 731)v><^vv>^v<  --No
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Now that I have a bigger knowledge base on how RNGs work, and a better script and all that, I got annoyed how quickly I gave up on the extra fairies at the Reflect Trek. Those things need an extra look. Well, after fixing up my formulas again and again, I've looked at making the west desert fairy travel east for its first three steps. I'm scanning by straight up RNG calls. Results:
West desert fairy
Spawn RNG >= 0xF0, west must exist, fairy travel east, east, east.
r[2]= 27 gTimer= 8 calls= 303 ( 314)
r[2]= 88 gTimer=16 calls= 479 ( 490)
... Not pretty. When I say "Short enough delays", it seems the second fastest west fairy is almost 3 seconds slower than the fastest west fairy. We need something exactly 303 RNG calls out, so that dictates our gTimer, and only one specific R[2] can do it. It will indeed be the stuff of miracles if we can not only get R[2]=27 and gTimer=8 (1 out of 2688 possibilities), but do so with an RNG that had already spawned a prior fairy. The trip to the town is fairly unpredictable, so if anyone works out that maze of RNGs, I'd love to know if it is possible. My later search only confirmed the absurdity. Okay, so that's a bust, most likely. What about coming back from town? We want an east fairy traveling west for its first three steps. What have I got?
East desert fairy
Spawn RNG >= 0xF0, east must exist, fairy travel west, west, west
r[2]= 91 gTimer=18 calls= 250 ( 266)
r[2]= 91 gTimer= 2 calls= 255 ( 266)
r[2]= 30 gTimer=18 calls= 271 ( 282)
r[2]= 30 gTimer= 5 calls= 279 ( 282)
r[2]= 30 gTimer=20 calls= 294 ( 298)
r[2]= 84 gTimer= 9 calls= 325 ( 330)
r[2]= 84 gTimer=10 calls= 326 ( 330)
r[2]=124 gTimer=10 calls= 326 ( 330)
r[2]=100 gTimer= 9 calls= 367 ( 378)
Sweet. We have more possibilities. The best one with R[2]=91. My prior searches must have been flaky. I'm still not liking my unreliability from before. The numbers in parentheses are the calls until the random direction is decided, which I needed to see while working out the formula. I've actually cranked my script out to a ludicrous 2000 frames, but none of the R[2]/gTimer pairs I got from delaying our current fairy matched any of those possibilities. This does tell me we have to try out different sorts of fairy spawns, and I'm not sure how to simulate the difference in RNG calls for any given fairy path. Obviously, an east fairy immediately going west will be quicker than one that wanders about, so we don't have consistent timing. In any case, this second look is making that third fairy in the Reflect Trek actually look viable. It'll give me something more to do, and we've proven the run syncs just fine after P4 with any changes we make. You'll be short one small kill for P4, though. Not sure how that affects the route.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
My conclusion is that what we have now, the R[2]=72 fairy spawn, is the best we've got. We're currently worrying over something we don't need to right now. The main problem here is that we can't manipulate luck at all when it comes to the Skettlar flame. If we want the 829 RNG calls fairy (hacked fm2), we get the forward flame. The 859 RNG calls fairy (main fm2) picks an RNG where we have the rear flame instead, which isn't bad because we need to wait anyway thanks to the fact we need 859 RNG calls. Of course, the published run gets no flame, but this was with an R[2] that didn't cause any convenient fairies to spawn. You want our current fairy to appear, you get the rear flame. You also must wait in the side-scrolling screen for a bit, too. So the problem is in RNG limitations. Fairy spell solution for R[2]=31 is only good if it saves two "frame rules" over R[2]=72. From my end, this does not appear to be the case with our route. If an improvement down the road somehow shows up, and is having trouble manipulating R[2]=72 in a timely fashion, they can still use R[2]=31 as a reasonably fast backup and eat the menu time later. Again, we've already got the best input file we can with the route we have. No amount of RNG trickery is going to make it faster, only what we do with the RNGs we are dealt with. I say just focus on finishing up what you have now and think about the last fairy in detail later. I do not expect to save any more frames with the setup we have. In case you need it, here's a full movie from start to R[2]=31. It definitely can get the fairy faster than our current movie, but we lose out due to menu time. Again, unless you know a way to get around that specific fireball, or can theorize a way without manipulating luck (killing the 829 RNG calls fairy if we use a different R[2]) there's no reason to worry about trying to improve on this.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
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.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Alas. That was done on R[2]=72 (getting the fairy no sooner than 859 frames). Skettlar acts on the RNG, and I need it on R[2]=31 (getting the fairy no sooner than 829 frames), and hacking in that value has the movie fail. The fireball just comes out too early. The biggest attraction to R[2]=31 is the fact the fairy can potentially show up earlier. Try starting from the RAM-hacked movie. The problem should be real clear, although TASEditor doesn't like save state anchored movies. An old lua script of mine might work if you still need something like TASEditor, though I've ignored it since, well... TASEditor happened. Can't say if it's still good after any internal changes in FCEUX.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
This is the problem I spot with R[2]=31. If there's a way to bypass that fireball as regular Link, I'd love to know the TASing technique to do so without waiting too long (we'd miss the fairy chance) or changing the RNG (we'd manipulate away the fairy chance, too). Aside from that, I have nothing new to report. Hope to see the submissions come by on time!
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Hey, even the manipulation likes your savings! I think we're now at 287 frames saved with the Valley of Death fairies, though lately my arithmetic has proven distressingly unreliable. I blame sickness. Ran my script (and whoops, marked the wrong gTimers. Should be 18-2, not 0-4. Distressingly unreliable mental arithmetic, I say) and we have better savings now. No longer I pass a 21-frame block, although we are technically one frame away for a rather flimsy chance to beat the next 21-frame block. The chance exists -- We just need R[2]=0 R[2]=12 (EDIT: Distressingly unreliable. I'm hating this fail) when we trigger the encounter, if we somehow save that one frame. I think all that's left to do at this point is finish up the Great Palace with this and call it a good day. Might be a good idea to mention that fairies have 1/256 chance to spawn in the Valley of Death, 3/4 chance the west group spawns, and 1/4 chance of any particular direction in their random pathing. The last fairy has approximately 1-in-1365 chance of appearing in the west spot and subsequently moving east as its first step. The first fairy in the Valley of Death has proven suitably less likely as we also need to manipulate unwanted groups out of our path and additionally out of the screen before the fairy can spawn, and we have further to travel for its drunken path to be where we need it.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I now have a fourth fairy. Any doubts should evaporate around now. Once again, I generated up a list.
R2 Fra d
31 829 4  gTimer= 9
31 830 4  gTimer=10
72 859 4  gTimer= 0
72 860 4  gTimer= 1
72 861 4  gTimer= 2
72 862 4  gTimer= 3
72 863 4  gTimer= 4
37 870 4
37 871 4
71 872 4
 0 877 4
 0 878 4
51 886 4
51 887 4
19 890 4
23 900 4
R[2], frames until spawn (delaying at side-scrolling screen if necessary for 21-frame steps), and direction the fairy will travel on its first step (must be east). Actually, it would show 0, 4, 128, or 132 for direction, but I wanted to look at the number myself to make sure I don't mess up. I've only filled out gTimer manually to know what timing to go for. Once I got something working, there wasn't need to fill out the rest of the table. I picked R[2]=72, even though it takes longer than R[2]=31, as picking 31 meant Link takes a fireball to the face. If that didn't happen, then 31 would be the best choice. Since I'm stuck delaying anyway, being slowed by the fireball after Link passes that enemy isn't a big problem. Getting this last fairy took approximately 1 second. I don't want to say we're done with this place. I just wanted to go forward and see if that last fairy is possible, and it definitely is. The encounter between fairies looks real iffy how I did it, so I imagine we should figure out the best path. I have no idea how to script something up to deal with this, so manually checking the 12 possible gTimer starts by delaying at the first fairy may be desired.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I spawn a third fairy. This files starts from a fresh state rather than a save state with hacked RAM. We have the fairy. What I did this time was to generate a list of possible starting RNGs that would get me R[2]=15 after no fewer than 905 RNG rolls, the theoretical fastest time. Now, with a target gTimer of either 18 or 20, this gives two possible gTimers for any given RNG count, meaning two possible spawns where I hope the west group is omitted. I found a target I like at 933 RNG calls, which works out to an initial R[2] of 46 and gTimer of either 6 or 8. I got a decent group spawn at gTimer=8. From there, I just ran my recursive function to find R[2]=46 and gTimer=8 from the numerous transitions after P6. It took me a while to realize you delayed a while for the last bridge, so I ended up TASing the same bits over and over until I spotted the extra delays you used for manipulation. There were enough leftover frames from removing this delay to do the manipulation. ... I hate getting sick, by the way. Wasn't really able to think well for a few days. Still, here's a fairy. I've got one more fairy to theorize a spawn for.