This article assumes you know the basics of TASing, including RNGs, memory searching, frame advance, savestates, and basic Lua scripting. Additionally, while some of this knowledge is applicable to action games, the focus is on Role-playing type games.
I am often approached by TASers to help them manipulate luck in their current TAS project. The most common requests I hear is'can you write me a lua script to do this manipulation?' or worse, 'can you help me disassemble the code?' These are actually the last options that a player should consider. I'm going to list the steps as I've learned through various RNG projects I've helped with.
Step 1: Is it worth it?
This is one step I find that most people ignore. Ask yourself these questions:
- How many times during this run will I use this knowledge?
- Can I effectively manipulate random events without the use of Lua or a deep understanding of the RNG functionality?
- Is it worth my time to delve deeply into the game to figure out RNG manipulation?
If you are simply trying to dissect a game's RNG to maximize a single boss's pattern, or a one-time bonus stage, you are probably wasting your time. In that situation, simple hard-work, ie. brute-forcing by hand, is more likely to produce the desired outcome. If you still believe the run will benefit from a deeper understanding of the RNG, then proceed to step 2.
Step 2: Identify the type of RNG movement
While there are numerous types of RNGs, an RNG will typically fall under one of 4 categories:
1. Frame-based RNG (Example: Shining Force 2)
This is the best RNG for beginner luck manipulation. However, you are limited in your ability to perfect the outcome, as you have a trade-off in number of frames to wait before triggering an outcome, and the quality of that outcome. To test for this RNG, wait a certain number of frames, and then trigger the event requiring manipulation. If the result changes, it may be a frame-based RNG, however, this does not preclude it being a ...
2. Input-based RNG: (Examples: Shining Force 1, Shining in the Darkness)
If you find this type of RNG, you've hit the jackpot. Almost any result possible can be achieved. However, this is a double-edged sword, as this RNG will require the most understanding. To test for this RNG, make a savestate before an event requiring manipulation. Hit keys before an event, then trigger the event on the same frame. If the result changes, then it may be an input-based RNG. However, this does not preclude it being a ...
3. CPU-cycle based RNG: (Examples: Dragon Warrior 1, Dragon Warrior 4)
This RNG changes its value based on the number of left-over CPU cycles before the next frame. Thus, the only way to manipulate it is to wait frames, or 'nudge' it with input. This is nearly indistinguishable from an input-based RNG without looking at the code. If you find that you are not able to massively change results with input-based manipulation, you may have a CPU-based RNG.
4. RNG-based RNG (Examples: Dragon Warrior 3, Chrono Trigger)
This is the hardest of hard RNGs to manipulate, as it stays almost completely inaccessible to the player. This type RNG only changes when a new random number is required. Thus, any event a player wishes to manipulate requires that the player first do an action that invokes the RNG, often consuming time. If this is the type of RNG in your game, it will require a large amount of advanced planning. There are some steps that can help minimize your pain, however.
Step 3: Finding the RNG memory address(es)
Now that you know how the RNG moves, it is time to find the RNG itself. Using your knowledge of how the RNG changes, search for memory addresses that change in a similar fashion. Many NES era RPGs had two RNGs, so you may be searching for multiple addresses. Unfortunately, you will find many memory addresses that change per frame. Once you have parsed it down to only 20 or so addresses, a good way to check it is to either use the cheat function of the emulator to set values, or a simple Lua script, filling in the address for RNG:
RNG = 0x?????? while true do memory.writebyte(RNG, Value); emu.frameadvance(); end;
Check the behavior. Are you no longer able to change outcomes? Does changing Value to different numbers affect the outcome? If you said yes to both of these, there is a good chance you have found the RNG.
(This is my method, if anyone has any other methods, please fill in.)
Now, we can finally manipulate the RNG. I am going to do a breakdown of each method, its pros and cons, and best pairing with RNG-type. Will fill more in later
What most people refer to as Botting. Good for CPU-based and Input-based when you can't figure out formulas.
Get results, Check results, best for frame-based RNGs. Menu-based selection
Requires disassembling the code. Best for Input-based RNGs.
Take what you know about the RNG, and look at what happens given a certain RNG. Best for RNG-based RNGs.