Overworld Scripting ‐ Scripting Basics - haven1433/HexManiacAdvance GitHub Wiki

Click to return to the main scripting page

So you know what event scripts are and you know how to use the templates. But reading scripts and using templates can only get you so far - it's time to start writing your own scripts! Lets spend a moment to learn about the most important concepts and commands to keep in mind when writing your own script.

Introduction

This scripting tutorial will hone in on individual commands that are commonly used when configuring NPCs and map scripts in the overworld, as well as how scripts are divided up in Hex Maniac Advance (HMA) and what the <auto> argument does. Having the information on what these commands do will allow ROM hack developers to get the most out of this API; in other words, they can create characters and overworld events that work exactly how they want them to work.

Sections

Many preexisting and user-created scripts have branching code so that different things can happen when running a single script. These variations could be attributed to the player's progression in the game, random chance, or whether or not the player has room for more Pokémon/items. Regardless of the reasoning, HMA divides code segments into sections to make the whole script easier to follow, and they're labeled by numbers (section0, section1, and so on) instead of locations in the ROM.

For example, this vanilla, Pacifidlog Town NPC script has two different sections — each section corresponds to a different message that the player sees, depending on whether or not the player can Surf to Mirage Island. The top section, section0, would run all the way to its end command if the Island was not present, resulting in the player seeing the top message (indicated by the content inside the curly braces). If it was present, then the if.yes.goto <section1> command would run, followed by all of the commands underneath section1. As a result, the player sees the bottom message instead.

section0: # 204111
  lock
  faceplayer
  special2 0x800D IsMirageIslandPresent
  if.yes.goto <section1>
  msgbox.default <204140>
{
I can't see MIRAGE ISLAND today\.
}
  release
  end

section1: # 20412D
  msgbox.default <204161>
{
Oh! Oh my!
I can see MIRAGE ISLAND today!
}
  release
  end

Sections are also useful when script commands need to be looped for a period of time; HMA would make it easier to clarify which block of commands were effectively being run multiple times as opposed to once. This could be useful if a character doesn't want to take "no" for an answer or if a number needed to be multiplied by another number.

When creating a script from scratch, you can use names like <section1>, <section2>, <fullBag>, or practically anything each time you need to use a command that can disjoint code (such as goto or call). This way, there's no need to scroll through the ROM and manually search for free space offsets — HMA will handle all of that for you. Here is a sample script that makes use of sections:

section0: # FFFE10
  lock                         # Locks the NPC.
  faceplayer                   # The NPC faces the player.
  msgbox.yesno <auto>          # Offers the player 1 Smeargle. The word "auto" can substitute a ROM address (see the "Auto" section below).
{
Would you like a Smeargle?
}
  if.yes.goto <section1>       # If selected "YES," then go to the section where the Pokémon is given.
  closeonkeypress              # Closes the message box.
  release                      # Terminates the script if "NO" is selected by releasing the NPC.
  end

section1: # FFFE30
  givePokemon SMEARGLE 5 ???????? 0 0 0     # Grants the Smeargle at Level 5.
  msgbox.autoclose <auto>
{
You received a Smeargle!
}
  release                      # Allows the NPC to move again.
  end

The top section, section0, prevents the NPC from moving away from the player and causes the NPC to look at them. The NPC asks if the player wants a Smeargle. Upon clicking "NO," the script continues because there's no branching code. The NPC is unlocked, and the script ends. Upon clicking "YES," the script jumps to the bottom section, section1, which involves giving the player a Smeargle. The same release and end commands are used to terminate the script.

The following script is a variation of the Smeargle-giving script in which the player cannot answer "NO" without jumping back to the top section (section0):

section0: # FFFE10
  lock                         # Makes the NPC stop moving and face the player.
  faceplayer
  msgbox.yesno <auto>          # Offers the player 6 Smeargles.
{
Would you like 6 Smeargles?
}
  if.yes.goto <section1>       # If selected "YES," then go to the section where the Pokémon are given.
  msgbox.autoclose <auto>      # Refuses to cancel the offer if the player said "NO."
{
Don't pass up on this offer!
I will ask you again.
}
  goto <section0>              # Goes back to the first message until the player says "YES."

section1: # FFFE30
  setvar 0x8000 0              # Initializes a counter variable to 0, then continues to section2.

section2: # FFFE35             # This section loops 6 times, giving the player 6 Pokémon.
  if.compare.goto 0x8000 >= 6 <section3>
  givePokemon SMEARGLE 5 ???????? 0 0 0
  addvar 0x8000 1
  goto <section2>

section3: # FFFE59             # A final message before the script ends.
  msgbox.autoclose <auto>
{
You received 6 Smeargles!
}
  release                      # Unlocks the NPC.

More sections were created to simulate a loop that executes 6 times so that the player receives 6 Smeargles instead of 1. section1 sets a temporary variable to 0 to ensure that section2 runs 6 times. section2 is responsible for giving the player a Smeargle and updating the variable initialized in section1. Once 6 Smeargles are given (variable 0x8000 equals 6 or higher), section2 jumps to section3, where one final message is printed, the NPC is unlocked, and the script ends.

If you forgot to put an end command at the bottom of a script or section, HMA will automatically fill it in at the very end unless the bottom-most command is something like a goto or return command, where the script would jump to another area in the ROM instead.

Auto

When supplying pointers for commands like msgbox or applymovement, instead of specifying a free space address in the ROM, an alternative is using the <auto> argument. HMA will automatically find a free space offset that's directly after the script's last end command to place things like text strings and sets of movement commands. This address is flexible, meaning that while the argument <auto> doesn't change, the actual pointer to the content changes as more commands are being added/taken away from the whole script.

In the above sample script, there are 3 uses of the <auto> pointer, all of which are after msgbox commands. The exact addresses of these text strings are not totally relevant, unless the ROM hacker wanted to reuse the text string for another script.

Common Commands

When scripting NPCs or map scripts, there are a handful of commands that will appear inevitably and frequently. Understanding them all will provide a solid foundation to build upon as a ROM hacker continues making more and more sophisticated scripts.

lock and release

Most scripts have these commands to make sure that the NPC in question cannot move while the script is running. lock stops all of the NPC's movements while release resumes them. To prevent the game from softlocking, place a release command before each end command if a lock command is present at the start of the script. Some macros like msgbox.npc have lock and release bulit in, so having multiple lock commands to stop NPC movements may be necessary, depending on the scenario. Neither command has parameters.

faceplayer

This command makes the NPC turn around so that they look at the player. It is used after lock in most scripts. This command does not have any parameters. The msgbox.npc macro has this command built-in.

end

This command marks the finale of an overworld script. When typing a script without an end command, HMA will automatically place an 02 byte, signaling an end command at the end of the script, with a few exceptions. If a script has multiple ways to finish due to branching off into sections, then each ending will have an end command unless the final command is something like goto or killscript.

move.npc

This command will cause a specified NPC to move, face a different direction, and/or emote. It takes two parameters: one for the ID of the NPC (which can be found in the map editor) and a pointer to movement data. (<auto> can be used instead of a numerical address.) Movement data is encapsulated in curly braces ({}). Typing in movement commands within them will show possible options to autocomplete. Some movement commands are walk_up, face_down, and emote_exclamation_mark. NPCs cannot walk through walls nor leave maps with this command alone.

move.player

This command is similar to move.npc, but the movement commands would apply to the player instead. It takes one parameter: a pointer to movement data. (<auto> can be used instead of a numerical address.) The player cannot walk through walls, either.

msgbox

There are several variations of this command macro — all of them show a message on the screen, but there are slight variations in commands that are ran behind the scenes. All of them have msgbox to start, followed by a . character, then the name of each variation (ex. autoclose). All of them take in one parameter: a pointer to text data. It is usually convenient to use <auto> instead of manually inserting a ROM address.

msgbox.npc

This command will show a message box after making the NPC (if any) face the player. This type of message must be closed with a button press before further code can be executed.

msgbox.sign

This command will show a message box and stop the movement of all NPCs on the screen. The script and the NPCs' movements are resumed after the message is closed with a button press. Usually, ROM hackers would use this msgbox variant with Signpost tiles.

msgbox.default

This command will show a message box and allow the script to continue. Whenever a message box of this type needs to be closed, use a closeonkeypress command. If you end a script with something like msgbox.default <auto>, release, and end, the player can move while the message box is still there. Temporary graphical glitches can occur when opening the Start Menu in this state.

msgbox.yesno

This command will show a message box and a Yes/No selection box. In order for there to be different outcomes based on the player's selection, follow this commmand up with something like if.yes.goto <section1> and/or if.no.goto <section1>. Pressing the (B) button will act as if the player selected "NO." To make the message box itself disappear, you can insert the closeonkeypress command inside the code that corresponds to each outcome.

msgbox.autoclose

This command will show a message box without anything else happening. This type of message must be closed with a button press before further code can be executed.

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