Overworld Scripting ‐ Variables - haven1433/HexManiacAdvance GitHub Wiki

Click to return to the main scripting page

Introduction

This tutorial is centered around using variables in overworld (event) scripts via Hex Maniac Advance (HMA). In the context of a Gameboy Advance (GBA) game, variables are containers of numbers that always range from 0 (0x0) to 65,535 (0xFFFF). Some of them reside in the save file while others reside in RAM. Certain commands require the usage of variables to keep track of data, and the Pokémon games for the GBA frequently use variables to keep track of the player's progress in their save file.

Flags are also used for similar purposes, but they work differently and are not covered in this tutorial. In places that require a variable number, a flag number is not sufficient. Click here for the Flags tutorial.

Variable Macros

As of version 0.5.4, HMA officially supports aliases for certain variable numbers. Instead of typing 0x800D, for instance, a user can type varResult within the script editor, and HMA will compile the correct bytes as if 0x800D was typed. Auto-completion in the script editor will make inserting special variables into script commands as convenient as possible.

The variable aliases list can be found in the default.toml file by clicking [Utilities] and [Scripts] and going up one directory in File Explorer. Notably,

  • temp0 through tempF are macros for 0x4000 through 0x400F.
  • gfx0 through gfx are macros for 0x4010 through 0x401F.
  • var0 through varB are macros for 0x8000 through 0x800B.
Macro Name Number
varFacing 0x800C
varResult 0x800D
varItemID 0x800E
varLastTalked 0x800F
varContestRank 0x8010 (TBA)
varContestCat 0x8011
varMonBoxID 0x8012
varMonBoxPos 0x8013
var14 0x8014
varOpponentA 0x8015

Resources

The domain of valid variable numbers is rigid for the Generation 3 Pokémon games, so a ROM hacker cannot supply any number willy-nilly. Fortunately, the decompilations of Pokémon Ruby, FireRed, and Emerald have information on which variables are valid and unused.

To access them in HMA, click [Help], then hover over [Online Reference Content] and the name of the ROM that's being edited, and select [List of Script Variables]. A GitHub page will show up that lists each variable in the game: the name & the number. The variables in Pokémon Ruby are the same as in Pokémon Sapphire; likewise, the variables in Pokémon FireRed are the same as in LeafGreen.

Animated GIF of finding the variables page from HMA

Temporary Variables

Variables 0x4000 through 0x400F (temp0 through tempF) all reset to zero when changing maps (falling into a hole, leaving a building, etc.). These variables can be used to store temporary information that doesn't need to carry through the entire storyline of a ROM hack. Some script tiles can make use of these temporary variables so that they can be activated more than once.

Commands that use Variables

Quite a few commands use variables as parameters and/or modify the values of some variables after being executed. Some common ones will be listed below:

if.compare.goto/if.compare.call

These commands will inspect the value of a specified variable. If it meets a certain criterion, then the current script will jump to a new address, either permanently or temporarily. It takes in several parameters: a variable number, a comparison operator, a value to compare to, and a pointer to continue the script in that order.

The difference between the goto portion and the call portion is that the former continues the script (if the comparison was true) at the new address with no chance of returning to the previous segment of script code while the latter does the same, albeit expecting a return command to go back to the script that had the if.compare.call command.

Example: In this line of code, if.compare.call 0x40FA <= 2 <E3CF64>, the script will temporarily go to address E3CF64 if and only if the value stored in variable 0x40FA is less than or equal to 2.

setvar

This command will change a specified variable to a new value. It takes in two parameters: a variable number, and a value. For example, setvar var4 5 will modify variable 0x8004 (var4) so that its new value is 5.

This is helpful to prevent infinite loops on script tiles where variable numbers are required to configure them. It's also useful for marking milestones in the story part of a ROM hack. Some special commands require one or more setvar commands to be ran beforehand as they depend on certain variables being equal to certain numbers.

addvar/subvar

These commands will perform arithmetic on a specified variable. The addvar command will add a specified number to the variable's current value while subvar does the opposite. It takes in two parameters: a variable number, and a value. For example, running subvar 0x40FA 4 will take away 4 from the current value of variable 0x40FA.

copyvar

This command will set the value of one variable to the value of a second variable. It takes in two parameters: a destination variable number and a different variable number that's used as a "template." Like addvar, setvar, and subvar, the first parameter is the variable that's getting changed, and it's getting changed to the current value of the second parameter's variable.

Example: Running copyvar 0x40F7 varResult will copy the value from variable 0x800D (varResult) and paste it to variable 0x40F7.

countPokemon

This command will set variable 0x800D (varResult) to the number of Pokémon that are present in the player's party. No parameters are needed. Use an if.compare.goto command afterwards for the script to make use of that information.

random

This command will set variable 0x800D (varResult) to a random number within a specified domain. It takes in one parameter: a value that indicates the number of possible outcomes. More specifically, the random number that can be generated will always be between 0 and one less than the specified number, inclusively.

Example: Executing random 6 will make it so that variable 0x800D can be set to 0, 1, 2, 3, 4, or 5.

To store this value for later use — as this particular variable can change without warning — a copyvar command will come in handy.

Script Tiles

The reason why most script tiles cause the game to freeze upon being stepped on is that there are a few fields that the user left blank.

Notice that the Trigger field defaults to 0000. This is not a valid variable number. It will need to be changed to one of the valid variable numbers. Choose an unused variable number to have the most control over when a script tile can or cannot activate. The next heading will cover that. Script tiles check for the specified variable in the Trigger field.

For this tutorial, the variable number 0x4050 will be used for the Trigger field. Notice that, in the image below, the preceding 0x was omitted. This field will always be in hexadecimal, so the 0x is implied. (This particular variable is already used, but there are cases where ROM hackers can strategically use them.)

The Index field defaults to 0. This field is the value that the variable must be set to upon stepping on the script tile in order for the script to activate. Since unused variables remain at 0 for their value, there may not be a need to (by default) change this checked value. According to the image, since the Index field of this script tile is now configured to 3, the script contained in the script tile will activate if and only if it's stepped on while variable 0x4050 is equal to 3.

The Elevation field is more of a map-editor attribute. This field determines which elevation level (usually 3, could be 0 for any elevation) the player must be on in order for the script tile to activate. It's set to 3, in this case, but that is not relevant.

Caution

One important thing about script tiles is that the script will always be executing when the player is on one of them (if all conditions were met). If the script ends, it starts back up again. There is a way to prevent this infinite loop and force the script to run once.

In the script, there must be a command present to alter the value of the variable that is being checked. The setvar command is the most recommended command to use, but addvar and subvar can also be used, depending on the scenario/use cases of the particular variable. For instance, the above script tile checks to see if varable 0x4050 is set to 3. If the tile's script has a setvar 0x4050 1 command that will always be executed, then the conditions for the script tile will no longer be met, and the player will no longer be stuck until the game is reset.

Choosing an Unused Variable

When making new script tiles and/or scripts, there will be times when ROM hackers will need to use variables that are untouched in the ROM. Each ROM has a handful of unused variable numbers to pick from.

The easiest way to get an unused variable is by using the "unused variable" button in HMA:

Depiction of unused variable button

The button appears whenever you're adding or editing a command that uses a variable. Clicking this button (or pressing Ctrl+U) will automatically find an unused variable for you to use.

However, some hackers will prefer to manually manage and track all their variables. A hacker can use the decomp reference to get a full list of all variables, both used an unused. When looking at the vars.h pages for the FireRed & Emerald decomps (see the Resources section), the reader will see some variable numbers that just say VAR_(number) (in FireRed/LeafGreen) or VAR_UNUSED_(number) (in Emerald). See below:

Depiction of unused vars in pokefirered and pokeemerald

Such variables are unused and can be used in ROM hacks without affecting the vanilla game's scripts, story lines, etc.

Finding Where a Variable is Used

Ruby and Sapphire's decomps make looking for unused variables trickier as their vars.h file doesn't explicitly point them out. Also, if a ROM hacker already used some unused variables and forgot which ones were used, there is a way to check an individual variable number.

The ROM hacker can write a test script that has something like setvar [var number] [value]. [var number] would be the variable number to check while [value] can be any integer. Afterwards, right-click the variable number, and click [Find Uses]. A new tab will open up that contains bytes and scripts that already use said variable. If no results were found, then the variable is unused by the ROM.

Celadon City's Route 16 Gate script

This above image used an existing script to demonstrate the [Find Uses] feature, but the process is still the same.

Search results for var. 405E

This is a sample search results tab that can show up if a variable number is already used.

⚠️ **GitHub.com Fallback** ⚠️