Warning: This is a mirror of http://sphericalice.com/romhacking/documents/script/ . It will probably get out of date and stuff (last updated 2014-12-31 20:47)
This document is meant to serve as a comprehensive reference to each scripting command. The information is FireRed-centric and includes detailed descriptions of what the commands do, the locations of their ASM code, and more.
Commands above 0xD5
are not listed because they do
not exist in FireRed.
Some revisions have been added in. They are styled like so. Want to make a contribution? PM Spherical Ice on PokéCommunity, or e-mail him.
A single-byte value.
A two-byte value.
A four-byte value.
A dword. The value should be the offset (in ROM or RAM) of some piece of data that the command needs.
The two-byte numeric identifier of any valid script variable; that is, a word value greater than 0x3FFF
.
In most cases, commands that accept variables will extract the variables' values and use those values as input. Sometimes, a command will actually act on the variable itself rather than on its value (i.e. setvar).
It should be noted that variables 0x5084
to 0x7FFF
are not actually valid scripting variables, and modifying them may overwrite game data (including Pokémon stored in the PC).[source] Variables 0x4100
to 0x4180
may also be unsafe; a list of all safe variables hasn't been created yet.
Check out this document by karatekid552 on safe variables and flags.
The two-byte numeric identifier of any valid script flag; that is, a word value lower than 0x0900
.
It should be noted that many flags have been reserved by the game engine. Flags 0x500
to 0x700
are trainer flags, flags 0x890
to 0x8FD
are world map flags, and many others are used as well.
The single-byte numeric identifier of one of the four zero-indexed script banks.
The single-byte numeric identifier of one of the three zero-indexed string buffers.
The single-byte numeric identifier of one of the game's 64 hidden variables.
If the supplied argument is between 0x00000000
and 0x00000003
(inclusive), then it will be treated as a reference to a script bank. Otherwise, it is treated as a four-byte pointer to data.
A pointer or script bank 0 may be used, but the other script banks may not be used.
If the supplied argument is a variable, then the game will use its value to locate the proper flag. Otherwise, the argument itself is treated as a flag identifier.
If the supplied argument is a variable, then the game will extract that variable's value and use that as the input. Otherwise, the argument itself becomes the input.
If the supplied argument is a variable, then the game will extract that variable's value and use that as the input. Otherwise, the argument itself becomes the input. Either way, the input must be a word but is converted to a single-byte value (all bytes except the least-significant byte are discarded; 0xYYZZ
-> 0x00ZZ
).
Does nothing.
Does nothing.
Terminates script execution.
Jumps back to after the last-executed call statement, and continues script execution from there.
Jumps to destination
and continues script execution from there. The location of the calling script is remembered and can be returned to later.
The maximum script depth (that is, the maximum nested calls you can make) is 20. When this limit is reached, the game starts treating call
as goto.[source]
Jumps to destination
and continues script execution from there.
If the result of the last comparison matches condition
(see Comparison operators), jumps to destination
and continues script execution from there.
XSE automatically converts the slightly-more-readable form if condition goto pointer
to an if1
.
If the result of the last comparison matches condition
(see Comparison operators), calls destination
.
XSE automatically converts the slightly-more-readable form if condition call pointer
to an if2
.
Jumps to the standard function at index function
.
Calls the standard function at index function
.
If the result of the last comparison matches condition
(see Comparison operators), jumps to the standard function at index function
.
If the result of the last comparison matches condition
(see Comparison operators), calls the standard function at index function
.
Executes a script stored in a default RAM location.
Terminates script execution and "resets the script RAM".
Pads the specified value to a dword, and then writes that dword to a predefined address (0x0203AAA8
).
(What does that RAM offset do?)
Sets the specified script bank to value
.
(The function is named "loadpointer" because it was originally used to store pointers to strings in script banks, in preparation for certain dialog box-related standard functions. "Setbank" would have been a better name.)
Sets the specified script bank to value
.
Sets the byte at offset
to value
.
Copies the byte value at source
into the specified script bank.
Not sure. Judging from XSE's description I think it takes the least-significant byte in bank source
and writes it to destination
.
Copies the contents of bank source
into bank destination
.
Copies the byte at source
to destination
, replacing whatever byte was previously there.
Changes the value of destination
to value
.
Changes the value of destination
by adding value
to it. Overflow is not prevented (0xFFFF
+ 1
= 0x0000
).
Changes the value of destination
by subtracting value
to it. Overflow is not prevented (0x0000
- 1
= 0xFFFF
).
Copies the value of source
into destination
.
If source
is not a variable, then this function acts like setvar. Otherwise, it acts like copyvar.
("Copyvarifnotzero" is a misnomer. This function was previously thought to act like copyvar if source
was a variable with a non-zero value, and to do nothing otherwise.)
Compares the values of script banks a
and b
, after forcing the values to bytes.
Warning: XSE has it wrong. The arguments are bytes, not words. This means that you will need to use #raw
to compile a script that uses this command, and that such scripts will not decompile properly.
Compares the least-significant byte of the value of script bank a
to a fixed byte value (b
).
Compares the least-significant byte of the value of script bank a
to the byte located at offset b
.
Compares the byte located at offset a
to the least-significant byte of the value of script bank b
.
Compares the byte located at offset a
to a fixed byte value (b
).
Compares the byte located at offset a
to the byte located at offset b
.
Compares the value of a
to a fixed word value (b
).
Compares the value of a
to the value of b
.
Calls the ASM routine stored at code
. Script execution is blocked until the ASM returns (bx lr
, mov pc, lr
, etc.). Remember to add 1 to the offset when calling THUMB code.
Replaces a pointer in the script engine RAM with asm_pointer
.
(The pointer points to a THUMB routine... What effect does replacing it have?)
Calls a special function; that is, a piece of ASM code designed for use by scripts and listed in a table of pointers.
The special table is located at 0x0815FD60
.
Calls a special function. That function's output (if any) will be written to the variable you specify.
Blocks script execution until a command or ASM code manually unblocks it. Generally used with specific commands and specials. If this command runs, and a subsequent command or piece of ASM does not unblock state, the script will remain blocked indefinitely (essentially a hang).
Blocks script execution for time
(frames? milliseconds?).
(According to some movement tutorials on the web, a value of 0x0010
represents the amount of time it takes for a walking NPC to move one tile.)
Sets a
to 1.
Sets a
to 0.
Compares a
to 1.
In FireRed, this command is a nop.
Warning: XSE has it wrong. The function has no arguments. This means that you may need to use #raw
to compile a script that uses this command, and that such scripts will not decompile properly.
In FireRed, this command is a nop.
In R/S/E, it had something to do with flags and the real-time clock.
Resets the values of variables 0x8000, 0x8001, and 0x8002.
Plays the specified (sound_number
) sound. Only one sound may play at a time, with newer ones interrupting older ones.
If you specify sound 0x0000
, then all music will be muted. If you specify the number of a non-existent sound, no new sound will be played, and currently-playing sounds will not be interrupted. A comprehensive list of sound numbers may be found on PokeCommunity.
Note that when using older versions of VisualBoyAdvance, the sound channel used for this command (and, sometimes, in music) will be completely muted after loading from a savestate.
Blocks script execution until the currently-playing sound (triggered by sound) finishes playing.
(Does this also block until cries finish playing? The manner in which it's used by default scripts suggests that it might.)
Plays the specified (fanfare_number
) fanfare.
(Is it limited to one fanfare at a time, like sound?)
Blocks script execution until all currently-playing fanfares finish.
Plays the specified (song_number
) song. The byte is apparently supposed to be 0x00
.
(I need to test this command to see it has any quirks... And does it accept a variable?)
Plays the specified (song_number
) song.
(I need to test this command to see it has any quirks... Among other things, it's failed to work for me in situations where playsong has worked. And does it accept a variable?)
Crossfades the currently-playing song into the map's default song.
(I need to test this command to see it has any quirks...)
Crossfades the currently-playng song into the specified (song_number
) song.
(I need to test this command to see it has any quirks... And does it accept a variable?)
Fades out the currently-playing song.
(I need to test this command to see it has any quirks... And what unit of measurement is used for speed
? And does it accept a variable?)
Fades the currently-playing song back in.
(I need to test this command to see it has any quirks... And what unit of measurement is used for speed
? And does it accept a variable?)
Sends the player to Warp warp
on Map bank
.map
. If the specified warp
is 0xFF
, then the player will instead be sent to (X
, Y
) on the map.
This command will also play Sappy song 0x0009, but only if the bytes at 0x02031DD8 and 0x0203ADFA are not equal to 0x00 and 0x02, respectively.
(Function terminates script execution?)
Clone of warp that does not play a sound effect.
Clone of warp that uses "a walking effect".
(Any other differences?)
Warps the player to another map using a hole animation. It doesn't accept warp numbers or X/Y coordinates, so where does it send the player? Same (X, Y) as when the command is triggered?
Clone of warp that uses a teleport effect. It is apparently only used in R/S/E.[source]
(Any other differences?)
Clone of warp. Used by an (unused?) Safari Zone script to return the player to the gatehouse and end the Safari Game.
The only difference between this and warp
/warpmuted are that those two commands write 01 01 00
to 0x02031DD4
when they finish, but this command does not. I don't yet know what this difference means.
Sets a default warp place. If a warp tries to send the player to Warp 127 on Map 127.127, they will instead be sent here. Useful when a map has warps that need to go to script-controlled locations (i.e. elevators).
(Does this accept variables for X and Y?)
Clone of warp3, except that this writes data to different offsets...
With normal warp commands, the stats for the map being entered replace data starting at 0x02031DBC
(RAM: current map)... But this warp command instead writes to 0x02031DC4
.
(With that in mind, could this have been used internally for DIVE?)
Clone of warp3, except that this writes data to different offsets...
With normal warp commands, the stats for the map being entered replace data starting at 0x02031DBC
(RAM: current map)... But this warp command instead writes to 0x02031DCC
.
(With that in mind, could this have been used internally for DIVE?)
Retrieves the player's zero-indexed X- and Y-coordinates in the map, and stores them in the specified variables.
Retrieves the number of Pokémon in the player's party, and stores that number in variable 0x800D (LASTRESULT).
Attempts to add quantity
of item index
to the player's Bag. If the player has enough room, the item will be added and variable 0x800D (LASTRESULT) will be set to 0x0001; otherwise, LASTRESULT is set to 0x0000.
Removes quantity
of item index
from the player's Bag.
If you attempt to remove more of the item than the player actually has, then this command will do absolutely nothing, and they will keep the item. (For example, attempting to remove 6 Master Balls when the player only has 5 will result in them keeping all 5.)
Checks if the player has enough space in their Bag to hold quantity
more of item index
. Sets variable 0x800D (LASTRESULT) to 0x0001 if there is room, or 0x0000 is there is no room.
Checks if the player has quantity
or more of item index
in their Bag. Sets variable 0x800D (LASTRESULT) to 0x0001 if the player has enough of the item, or 0x0000 if they have fewer than quantity
of the item.
Checks which Bag pocket the specified (index
) item belongs in, and writes the value to variable 0x800D (LASTRESULT). This script is used to show the name of the proper Bag pocket when the player receives an item via callstd (simplified to giveitem
in XSE).
Return values:
0x0001
Items Pocket0x0002
Key Items Pocket0x0003
Poke Balls Pocket0x0004
TM Case0x0005
Berry PouchAdds a quantity
amount of item index
to the player's PC. Both arguments can be variables.
Checks for quantity
amount of item index
in the player's PC. Both arguments can be variables.
Return values:
In FireRed, this command is a nop. (The argument is read, but not used for anything.)
In R/S/E, it added one of the specified (a
) decoration to the player's PC, and stored something in variable 0x800D (LASTRESULT) -- apparently, a value determining whether the decoration was successfully added (0x0001
) or not (0x0000
).
In FireRed, this command is a nop. (The argument is read, but not used for anything.)
In R/S/E, it removed one of the specified (a
) decoration from the player's PC.
In FireRed, this command is a nop. (The argument is read, but not used for anything.)
In R/S/E, it checked to see if the player's PC could store one more of the specified (a
) decoration.
In FireRed, this command is a nop. (The argument is read, but not used for anything.)
In R/S/E, it checked to see if the player's PC contained at least one of the specified (a
) decoration.
Applies the movement data at movements
to the specified (index
) Person event. Also closes any standard message boxes that are still open.
Indices 0xFF
and 0x7F
refer to the player and the camera, respectively. Running this command from a Script event will crash the game unless that Script event's "Unknown" field (in AdvanceMap) is "$0003" and its "Var number" field refers to a valid script variable.
Apparent clone of applymovement. Oddly, it doesn't seem to work at all if applied to any Person other than the player (0xFF
), and the X
and Y
arguments don't seem to do anything.
This command in fact uses variables to access the Person event ID. So, for example, if you setvar 0x8000 to 0x3, and then use applymovementpos 0x8000 @move1, Person event 3 will have the movements at @move1 applied to them. Thank you Shiny Quagsire for bringing this to my attention.
Blocks script execution until the movements being applied to the specified (index
) Person event finish. If the specified Person event is 0x0000
, then the command will block script execution until all Person events affected by applymovement finish their movements. If the specified Person event is not currently being manipulated with applymovement
, then this command does nothing.
Apparent clone of waitmovement. Oddly, it doesn't seem to work at all if applied to any Person other than the player (0xFF
), and the X
and Y
arguments don't seem to do anything.
Attempts to hide the specified (local_ID
, a local ID) Person event on the current map, by setting its visibility flag if it has a valid one. If the Person does not have a valid visibility flag, this command does nothing.
(For example, if Person event no. 7 has a "Person number" of 8 and a "Person ID" of $0015, then hidesprite 0x8
will hide that Person event by setting flag 0x015
.)
Supplying a local ID of 0xFF
(the player) will result in the player taking control of a random Person event on the map, and map drawing will break (drawing chunks of terrain from the player's original position, along with chunks from their new position). This effect lasts until the player exits the map via a warp (I don't know what map connections would do).
Clone of hidesprite
that also moves the Person? Test it!
If the script was called by a Person event, then that Person will turn to face toward the tile that the player is stepping off of.
If the Trainer flag for Trainer index
is not set, this command does absolutely nothing.
Otherwise, this command will prepare and then indirectly initiate a trainer battle, blocking script execution until the battle ends. The effects of the battle (and even the number of arguments that the command accepts) differ depending on the first argument (the battle type).
For most types, if the player defeats the Trainer, then they say the text at loss
on the battle screen, their Trainer flag is cleared automatically, and script execution is terminated immediately; if the player loses, they whiteout and script execution terminates.
I'm not too sure what the local_id
is used for; most battle types "prefer" it set to 0x0000
, while setting it to 0x0003
with battle type 9 enables Oak's narration. (Actually, any local ID that, when bitwise-and 3, doesn't equal zero will trigger the narration in a type-9 battle.)
trainerbattle 0x2 is not identical to trainerbattle 0x1; the former (0x2) plays encounter music, while the latter (0x1) does not.
Type (hover for info) | intro | loss | extra | extra2 |
---|---|---|---|---|
0 Normal | Pre-battle text | Player win text | UNUSED | UNUSED |
1 Run Script After Win | Pre-battle text | Player win text | Post-battle script offset (run on player win only) |
UNUSED |
2 Run Script After Win | ||||
3 Continue Caller | Pre-battle text | UNUSED | UNUSED | UNUSED |
4 Double | Pre-battle text | Player win text | Not enough PKMN text | UNUSED |
5 Rematch | Clone of 00 with rematch functionality. | |||
6 Double-Special | Pre-battle text | Player win text | Not enough PKMN text | Unknown, but it is used. |
7 Double-Rematch | Clone of 04 with rematch functionality. | |||
8 Double-Special | Clone of 06. | |||
9 Tutorial (Can't Lose) | Pre-battle text | Player win text | UNUSED | UNUSED |
All Other Values | Treated as Type 0. |
The "Rematch" types check the specified trainer flag. If that trainer has already been battled, the game will use a table (at 0x0845318C
) to find trainer flags associated with rematches against the trainer. The game will search for the earliest cleared rematch flag; it will then check if that rematch is usable based on...
0x292
(flag function not known) is set, rematch 1 is enabled for all trainers.0x896
(Celadon City world map flag) is set, rematch 2 is enabled for all trainers.0x897
(Fuchsia City world map flag) is set, rematch 3 is enabled for all trainers.0x82C
(Elite Four defeated) is set, rematch 4 is enabled for all trainers.0x844
(R/S/E trading enabled) is set, rematch 5 is enabled for all trainers.If the found rematch flag is usable, then the command uses that flag instead of the specified one, and starts a battle. If the found rematch flag is unusable, or if all rematch flags are set, then no battle begins. Essentially, the game will automatically handle rematches for you based on the player's progress through the game world and on how many times the trainer has been defeated.
If you wish to change which flags enable rematches, you need only edit the dwords at 0x0810CCD8
, 0x0810CCE0
, 0x0810CCE8
, 0x0810CCF0
, and 0x0810CD10
. If you wish to modify the rematch table, a section in the Appendix describes its structure and function.
(Can the trainer index be a variable? (Check that empirically using an actual script, not ASM examination.) Verify that the unknown word can be used to enable Oak's tutorial narration.)
Starts a trainer battle using the battle information stored in RAM (usually by trainerbattle, which actually calls this command behind-the-scenes), and blocks script execution until the battle finishes.
If no battle information has been prepared, the player will fight a nameless "PKMN TRAINER" (Aqua Leader Archie's sprite) equipped with a team of ?????????? (null Pokémon). The battle type used appears to be 0x00
, with empty strings used by the trainer.
Compares Flag (trainer + 0x500)
to 1. (If the flag is set, then the trainer has been defeated by the player.)
Sets Flag (trainer + 0x500)
. (I didn't make a mistake. The command names actually are backwards.)
Clears Flag (trainer + 0x500)
. (I didn't make a mistake. The command names actually are backwards.)
If a standard message box (or its text) is being drawn on-screen, this command blocks script execution until the box and its text have been fully drawn.
Starts displaying a standard message box containing the specified text. If text
is a pointer, then the string at that offset will be loaded and used. If text
is script bank 0, then the value of script bank 0 will be treated as a pointer to the text. (You can use loadpointer to place a string pointer in a script bank.)
This function is not blocking; script execution will continue while the message box is still being displayed. Use waitmsg to block.
Holds the current message box open until the player presses a key. The message box is then closed.
Ceases movement for all OWs on-screen.
(Does this also affect OWs not on-screen? Viewing OAM data at run-time or possibly using a move-camera script could allow us to check.)
If the script was called by a Person event, then that Person's movement will cease.
Resumes normal movement for all OWs on-screen, and closes any standard message boxes that are still open.
If the script was called by a Person event, then that Person's movement will resume. This command also closes any standard message boxes that are still open.
Blocks script execution until the player presses any key.
Displays a YES/NO multichoice box at the specified coordinates, and blocks script execution until the user makes a selection. Their selection is stored in variable 0x800D (LASTRESULT); 0x0000
for "NO" or if the user pressed B, and 0x0001
for "YES".
Displays a multichoice box from which the user can choose a selection, and blocks script execution until a selection is made. Lists of options are predefined and the one to be used is specified with list
. If B
is set to a non-zero value, then the user will not be allowed to back out of the multichoice with the B button.
The user's selection is stored as a zero-indexed integer in variable 0x800D (LASTRESULT). If they backed out with B, LASTRESULT will be 0x7F
.
Displays a multichoice box from which the user can choose a selection, and blocks script execution until a selection is made. Lists of options are predefined and the one to be used is specified with list
. The default
argument determines the initial position of the cursor when the box is first opened; it is zero-indexed, and if it is too large, it is treated as 0x00
. If B
is set to a non-zero value, then the user will not be allowed to back out of the multichoice with the B button.
The user's selection is stored as a zero-indexed integer in variable 0x800D (LASTRESULT). If they backed out with B, LASTRESULT will be 0x7F
.
0x01
was the default.
0x05
was the default.
0x06
was the default.
Displays a multichoice box from which the user can choose a selection, and blocks script execution until a selection is made. Lists of options are predefined and the one to be used is specified with list
. The per_row
argument determines how many list items will be shown on a single row of the box.
The total number of options must be divisible by the number of options per row. "Orphaned" options will not be displayed or selectable. If the number of options per row is greater than the total number of options, then no choices will be visible or selectable.
The user's selection is stored as a zero-indexed integer in variable 0x800D (LASTRESULT). If they backed out with B, LASTRESULT will be 0x7F
.
Displays a box containing the front sprite for the specified (species
) Pokémon species.
Hides all boxes displayed with showpokepic.
If this command is called too quickly after showpokepic
, then it will fail to hide the Pokémon picture box and it will hang the script engine. My guess is that problems specifically happen if this command runs while the game is still trying to draw the showpokepic
box.
In FireRed, this command is a nop. (The argument is discarded.)
In R/S/E, it displayed the paintaing of the winner of the specified (a
) Pokémon Contest.
Displays the string at pointer
as braille text in a standard message box. The string must be formatted to use braille characters.
Note that the \l
and \p
string control codes are not supported, and braille text is too large to use \n
. To show multi-line or multi-part braille messages, you must use a clever scripting technique involving the braille2 command. You can see the script technique if you decompile Signpost scripts used in the Ruby and Sapphire chambers in Mt. Ember.
Gives the player one of the specified (species
) Pokémon at level level
holding item
. The unknown arguments should all be zeroes.
This function will also modify certain script variables to indicate the result of the command. Variable 0x800D (LASTRESULT) will be set to 0x0000
if the Pokémon was stored in the party; 0x0001
if the Pokémon was transferred to the PC; and 0x0002
if there was no room in the party or the PC. Variable 0x4037 appears to be set to the number of the PC Box that the Pokémon was sent to (if it was boxed). Flag 0x843 may be cleared (and then set) if the Pokémon was boxed.
(Confirm that this command specifically modifies var 0x4037.)
Checks if at least one Pokémon in the player's party knows the specified (index
) attack. If so, variable 0x800D (LASTRESULT) is set to the (zero-indexed) slot number of the Pokémon that knows the move. If not, LASTRESULT is set to 0x0006
.
(Does this accept a variable? If multiple Pokémon in the party know the attack, what is written to LASTRESULT?)
Writes the name of the Pokémon at index species
to the specified buffer.
...Specifically, the game tries to read a string starting at 0x08245EE0 + (0xB * species)
, the offset in that formula being a table of Pokémon names padded to ten bytes and separated by 0xFF
s. The game does not validate the species number; if it is larger than the number of Pokémon in the game, the game ends up trying to read from the data after the table, resulting in garbled strings or even a crash.
Writes the name of the first Pokémon in the player's party to the specified buffer.
(Does this buffer nicknames, if present? What happens if the player has no Pokémon?)
Writes the name of the Pokémon in slot slot
(zero-indexed) of the player's party to the specified buffer. If an empty or invalid slot is specified, ten spaces (" ") are written to the buffer.
(Does this buffer nicknames, if present?)
Writes the name of the item at index item
to the specified buffer. If the specified index is larger than the number of items in the game (0x176
), the name of item 0 ("????????") is buffered instead.
A tip: if the item is a Poke Ball (0x0004) or any Berry except the Enigma Berry (0x0085 - 0x00AE), you can pluralize the name with bufferitems.
In FireRed, this command is a nop. (The first argument is discarded immediately. The second argument is read, but not used for anything.)
In R/S/E, this command wrote the name of the decoration at index b
to the specified (a
) buffer.
Writes the name of the attack at index attack
to the specified buffer.
...Specifically, the game tries to read a string starting at 0x08247094 + (0xD * attack)
, the offset in that formula being a table of attack names padded unevenly but such that each first letter is 0xD
bytes apart. The game does not validate the attack number; if it is larger than the number of attacks in the game (0x162
), the game ends up trying to read from the data after the table, resulting in garbled strings or even a reset.
Converts the value of input
to a decimal string, and writes that string to the specified buffer.
Writes the standard string identified by index
to the specified buffer. Specifying an invalid standard string (e.x. 0x2B
) can and usually will cause data corruption (I've observed destruction of the stored player name and crashes when entering/exiting certain menu screens).
These are the standard strings in Pokémon FireRed (BPRE):
0x00
COOL0x01
BEAUTY0x02
CUTE0x03
SMART0x04
TOUGH0x05
COOL0x06
BEAUTY0x07
CUTE0x08
SMART0x09
TOUGH0x0A
ITEMS0x0B
KEY ITEMS0x0C
POKe BALLS0x0D
TMs & HMs0x0E
BERRIES0x0F
BOULDERBADGE0x10
CASCADEBADGE0x11
THUNDERBADGE0x12
RAINBOWBADGE0x13
SOULBADGE0x14
MARSHBADGE0x15
VOLCANOBADGE0x16
EARTHBADGE0x17
COINS0x18
ITEMS POCKET0x19
KEY ITEMS POCKET0x1A
POKe BALLS POCKET0x1B
TM CASE0x1C
BERRY POUCH0x1D
Trade Pokémon with another playe (longer than the buffer supports)0x1E
You may battle another TRAINER0x1F
Cancels the selected MENU item.0x20
You may trade your Pokémon here0x21
You may battle with your friends (longer than the buffer supports)0x22
Two to five TRAINERS can make0x23
Cancels the selected MENU item.0x24
You may trade your Pokémon here0x25
You may battle with your friends (longer than the buffer supports)0x26
Cancels the selected MENU item.Copies the string at offset
to the specified buffer.
Opens the Pokemart system, offering the specified products for sale.
The products
argument should point to a list of words. Each word is the identifier of an item to be sold. 0x0000
terminates the list.
Apparent clone of pokemart.
Apparent clone of pokemart.
In FireRed, this command is a nop.
Warning: XSE has it wrong. The function has no arguments. This means that you may need to use #raw
to compile a script that uses this command, and that such scripts will not decompile properly.
In FireRed, this command sets the byte at 0x03000EA8
to 0x01
. I do not know what that means.
In R/S/E, it prompted the player to choose a Pokémon to enter into a Pokémon Contest.
In FireRed, this command is a nop.
In R/S/E, it started a Pokémon Contest.
In FireRed, this command is a nop.
In R/S/E, it showed the results of a Pokémon Contest.
In FireRed, this command is a nop.
In Emerald, it apparently started a Pokémon Contest over a wireless connection.
Stores a random integer between 0 and limit
in variable 0x800D (LASTRESULT).
The number will always be less than limit
.
If check
is 0x00
, this command adds value
to the player's money.
(Can this overflow?)
If check
is 0x00
, this command subtracts value
from the player's money.
(Can this overflow?)
If check
is 0x00
, this command will check if the player has value
or more money; script variable 0x800D (LASTRESULT) is set to 0x0001
if the player has enough money, or 0x0000
if the do not.
Spawns a secondary box showing how much money the player has.
The box does not update automatically. If you change how much money the player has after using showmoney
, you must use updatemoney to display the new amount. The box can be hidden using hidemoney.
(Need to test this to find its quirks...)
Hides the secondary box spawned by showmoney.
(Does this discard its arguments like hidecoins does?)
Updates the secondary box spawned by showmoney. (What does it do with its arguments?)
You'd want to use this if you change how much money the player has after using showmoney
.
In FireRed, this command is a nop.
Warning: XSE has it wrong. The function has no arguments. This means that you may need to use #raw
to compile a script that uses this command, and that such scripts will not decompile properly.
Fades the screen to black or back, using the specified effect
. Effect 0x00
fades in, and effect 0x01
fades out. I don't know if other effects exist.
If effect 0x00
is used when the screen isn't actually faded to black, then the screen will be immediately blackened and then faded back in, producing a "blinking" effect.
(Does this block?)
Executes the specified field move animation.
The animations are defined in a table stored in the ROM, and they use their own scripting engine. More information can be found in a post on PokeCommunity.
These are the animations that have been found in Pokémon FireRed (BPRE):
0x01
CUT (grass)? (black Pokémon bar + leaf spiral) I can confirm.0x02
CUT0x03
Part of the FLY animation sequence.0x06
Part of the FLY animation sequence.0x08
Buggy SURF-Pokémon sprite appears on map0x09
SURF0x19
PokeCenter healing machine0x1E
Part of the FLY animation sequence. (takeoff)0x1F
Part of the FLY animation sequence. Calls animation 0x3B.0x20
Part of the FLY animation sequence.0x22
Landing (after FLY)0x23
FLY (crashes, probably because destination isn't set)0x25
ROCK SMASH0x26
TELEPORT? (black Pokémon bar)0x28
STRENGTH0x2B
WATERFALL0x2C
DIVE (crashes, probably because destination/directionality isn't set)0x2D
Shows a buggy message box in the top-left corner0x33
SWEET SCENT? I can confirm.0x3B
Part of the FLY animation sequence.0x3E
Hall of Fame registration machine0x3F
Teleports to player's home? Teleports to the flying spot for the sethealingplace map.0x41
VS SEEKER (crashes)0x45
White flash(Does it accept a variable? Test and confirm 01, 1E, 26, 3F, 41.)
Tells the game which party Pokémon to use for the next field move animation.
(What does the byte do?)
Blocks script execution until all playing field move animations complete.
(What does the word do?)
Sets which healing place the player will return to if all of the Pokémon in their party faint. A list of available healing places can be found on PokeCommunity.
(Does it accept a variable? And what happens if we supply a value of 0x00
?)
Checks the player's gender. If male, then 0x0000 is stored in variable 0x800D (LASTRESULT). If female, then 0x0001 is stored in LASTRESULT.
Plays the specified (species
) Pokémon's cry. You can use waitcry to block script execution until the sound finishes.
(What is the effect? Can it be a variable?)
Changes the tile at (X
, Y
) on the current map.
(Can some or all arguments be variables? What is tile_attrib
? It's usually 0x0 or 0x1, but I don't think it's a movement permission.)
Queues a weather change to the default weather for the map.
(Only one weather change can be queued at once?)
Queues a weather change to type
weather.
(Only one weather change can be queued at once?)
(Does this accept variables?)
Executes the weather change queued with resetweather or setweather. The current weather will smoothly fade into the queued weather.
(Does this block?)
This command manages cases in which maps have tiles that change state when stepped on (specifically, cracked/breakable floors).
Think of cmda6
as a script-friendly way to access Game Freak's official walking script implementation (but with ASM instead of scripts). This command allows you to select which one of eight predefined ASM subroutines should be enabled.
Number | Used In | Function |
---|---|---|
0 | Unused/Nop. Returns immediately without doing anything. | |
1 | Route 113 | R/S/E leftover. Crippled in FireRed -- it does nothing. When the player steps on Tile 20A (ash-covered tall grass), it changes into Tile 212 (normal grass). |
2 | Unused/Nop. Returns immediately without doing anything. | |
3 | ||
4 | Icefall Cave |
When the player steps on a tile with behavior byte 0x26 (uncracked ice), it changes into Tile 35A (cracked ice). When they step on a tile with behavior byte 0x27 (cracked ice), it changes into Tile 35B (hole) after a four-frame delay and script variable 0x4001 is set to 0x0001. This subroutine also compares the player's coordinates to a set of nine X/Y coordinate pairs stored at |
5 | Unused/Nop. Returns immediately without doing anything. | |
6 | ||
7 | Granite Cave Sky Pillar |
R/S/E leftover. Crippled in FireRed -- it does nothing. When the player steps on Tile 22F (cracked floor), it changes into Tile 206 (hole). At some point, script variable 0x4030 is set to 0x0000. |
Others | Treated as Subroutine 0 |
At 0x03005090
, there is an execution queue -- a list of ASM functions to be executed on every frame. (Each list item also has a small amount of space to use to maintain its state.) Cmda6
checks the queue to see if a specific ASM routine, the walking routine manager at 0x0806E811
, is there. If so, cmda6
clears the state data for that queue item, and then inserts the argument you specify into the state data.
When the walking routine manager runs (once every frame), it reads the injected state data and uses that to determine which walking subroutine it should call. (Eight are allowed, three of which are defined and one of which actually works.) It then calls the selected walking subroutine, which will generally perform some action if the player has taken a step (usually, changing the tile under their feet).
Bundled in this resource's ZIP should be a file, CmdA6, disassembled and rewritten.txt. (If I've forgotten to include it, remind me.) That file contains the assembly code for CmdA6, the tile manager routine, and the three subroutines (rewritten in a pseudosyntax which you may or may not find more readable). Studying that should provide you with most of the information you would need to, say, add a subroutine of your own to create a cmda6
-managed walking function that is accurate to the frame.
Queues the opening of the door tile at (X
, Y
) with an animation.
(Does this accept variables? What happens if it's used on a tile that isn't a door?)
Queues the closing of the door tile at (X
, Y
) with an animation.
(Does this accept variables? What happens if it's used on a tile that isn't a door?)
Executes the state changes queued with setdooropened, setdoorclosed, setdooropened2, and setdoorclosed2.
(Does this block for animated door changes? For both?)
Queues the opening of the door tile at (X
, Y
) without an animation.
(Does this accept variables? What happens if it's used on a tile that isn't a door?)
Queues the closing of the door tile at (X
, Y
) without an animation.
(Does this accept variables? What happens if it's used on a tile that isn't a door?)
In FireRed, this command is a nop.
Warning: XSE has it wrong. The function has no arguments. This means that you may need to use #raw
to compile a script that uses this command, and that such scripts will not decompile properly.
In FireRed, this command is a nop.
Prepares to start a wild battle against a species
at Level level
holding item
. Running this command will not affect normal wild battles. You start the prepared battle with dowildbattle.
To be specific, this command will automatically generate a 100-byte Pokémon matching the provided arguments, and store it at 0x0202402C
(the RAM location of the first enemy in a battle). The RAM for enemies 2-6 is also cleared. This allows a script to generate a wild Pokémon before initiating a battle.
The uses for generating a Pokémon in this manner are many and varied. Hypothetically speaking, one could call this command, use writebytetooffset to pre-damage the generated Pokémon, and then run dowildbattle
.
(Can the item be a variable?) Tests would suggest that, no, items cannot be set through variables.
Starts a wild battle against the Pokémon generated by setwildbattle. Blocks script execution until the battle finishes.
If the Pokémon created by setwildbattle
was invalid, then this command will hang and a battle will not start.
(Nonexistent species such as 0x4000
are known to cause invalid Pokémon... But would other Pokémon (i.e. broken checksums, or stats in the last 20 bytes being modified) cause problems as well?)
Spawns a secondary box showing how many Coins the player has.
The box does not update automatically. If you change how many Coins the player has after using showcoins
, you must use updatecoins to display the new amount. The box can be hidden using hidecoins.
Hides the secondary box spawned by showcoins. It doesn't appear to use its arguments, but they are still required.
Updates the secondary box spawned by showcoins. (What does it do with its arguments?)
You'd want to use this if you change how many Coins the player has after using showcoins
.
Increases the value of the specified hidden variable by 1. The hidden variable's value will not be allowed to exceed 0x00FFFFFF
.
The PokeCenter nurses use this to increment hidden variable 15 (0xF) just after you pick "YES" to heal your party. I don't know why.
Clone of warp... Except that it doesn't appear to have any effect when used in some of FireRed's default level scripts. (If it did, Berry Forest would be impossible to enter...)
Blocks script execution until cry finishes.
Writes the name of the specified (box
) PC box to the specified buffer.
Sets the color
of the text in standard message boxes. 0x00
produces blue (male) text, 0x01
produces red (female) text, 0xFF
resets the color to the default for the current OW's gender, and all other values produce black text.
This command does not affect braille text. Colors specified with this command will be overriden by colors specified by control codes in the string.
(The command writes a byte to 0x020370DA
, and that byte is reset to 0xFF
every frame.)
The exact purpose of this command is unknown, but it is related to the blue help-text box that appears on the bottom of the screen when the Main Menu is opened.
This command will load the appropriate palette and tiles for a help-text box containing the specified string. It also writes data for a new dialog box into RAM. However, the dialog box is not displayed.
Note that when this command loads the palette and tiles, it overwrites the frame tiles in use by any standard message boxes that may already be on-screen. Their frames change into (improperly-displayed) help-text frames, though the text remains completely unchanged.
Warning: XSE has it wrong. The function has one four-byte argument. This means that you will need to use #raw
to compile a script that uses this command, and that such scripts will not decompile properly.
The exact purpose of this command is unknown, but it is related to the blue help-text box that appears on the bottom of the screen when the Main Menu is opened.
This command appears to unload most of the text and frame tiles that cmdc8 loads into memory, though it will not restore overwritten frame tiles used by other dialog boxes.
After using this command, all standard message boxes will use the signpost frame.
Ends the effects of signmsg, returning message box frames to normal.
Compares the value of a hidden variable to a dword.
Warning: XSE has it wrong. The second argument is a dword, not a word. This means that you will need to use #raw
to compile a script that uses this command, and that such scripts will not decompile properly.
Makes the Pokémon in the specified slot
of the player's party obedient. It will not randomly disobey orders in battle.
(Can the slot be a variable?)
Checks if the Pokémon in the specified slot
of the player's party is obedient. If the Pokémon is disobedient, 0x0001
is written to script variable 0x800D (LASTRESULT). If the Pokémon is obedient (or if the specified slot is empty or invalid), 0x0000
is written.
Depending on factors I haven't managed to understand yet, this command may cause script execution to jump to the offset specified by the pointer at 0x020370A4
.
This command uses what appear to be checksums at [0x03005008] + 0x32E0
and [0x03005008] + 0x361C
to validate data pointed to by pointers at [0x03005008] + 0x32E4
(target is 332 bytes) and [0x03005008] + 0x3620
(target is either 1000 or 1004 bytes), respectively. If this validation fails, the command does nothing. Unfortunately, I've looked at the ASM every way I can; unless someone figures out what's at those DMA-protected RAM offsets, this command's function will remain a mystery.
Sets worldmapflag
to 1. This allows the player to Fly to the corresponding map, if that map has a flightspot.
Specifically, the command will set the specified flag if all of the following requirements are met, and will apparently do nothing if one or more of the requirements are not met:
0x0203ADFA
is greater than 0x03
.0x08456C50
, with 0x10
two-byte entries) of world map flags that can actually be flown to.Clone of warpteleport? It is apparently only used in FR/LG, and only with specials.[source]
Changes the location where the player caught the Pokémon in the specified slot
of their party. A list of valid catch locations can be found on PokeCommunity.
Sets variable 0x8004 to a value based on the width of the braille string at text
.
Because braille strings do not support the \p
or \l
control codes, Game Freak had to create a "fake" message cursor every time they wanted to show multi-part or multi-line braille strings. To facilitate this, they created special 0x1B2, which draws a cursor on the screen at a position specified by variables 0x8004 (X) and 0x8005 (Y).
This command, braille2
, will calculate the length of a specified braille string, and then set 0x8004 to a value based on that length. If you then show that string in a message box and call special
0x1B2, a cursor will appear exactly at the end of the braille string.
Writes the name of the specified (item
) item to the specified buffer. If the specified item is a Berry (0x85 - 0xAE) or Poke Ball (0x4) and if the quantity is 2 or more, the buffered string will be pluralized ("IES" or "S" appended). If the specified item is the Enigma Berry, I have no idea what this command does (but testing showed no pluralization). If the specified index is larger than the number of items in the game (0x176
), the name of item 0 ("????????") is buffered instead.
(The Enigma Berry is treated as a special case and handled with ASM that, among many other things, appears to conditionally read from a table at 0x083DF7CC
. What the hell is this command doing for Enigma Berries?)
In FireRed, this command is a nop.
Warning: XSE has it wrong. The function has no arguments. This means that you may need to use #raw
to compile a script that uses this command, and that such scripts will not decompile properly.
The condition byte supplied to the if1 and if2 commands determines what is done with the result of the previous comparison.
0x00
= A is less than B0x01
= A is equal to B0x02
= A is greater than B0x03
= A is less than or equal to B0x04
= A is greater than or equal to B0x05
= A is not equal to BThe dialog box types that I have identified in FireRed are as follows:
To find the offset of a given script command's ASM, the game looks it up from a table. In BPRE, this table is located at 0x0815F9B4
, and to find the pointer for a given command, you left-shift that command by 2 and then add the result to the table's offset. There, you'll find a pointer to the command's ASM.
For example, the command byte for showcoins is 0xC0
. Left-shifting that by two gives us 0x300
; adding that to the table offset gives us 0x0815FCB4
, and the pointer at that offset is 0x0806C259
-- a pointer to showcoins
' ASM with the THUMB bit set.
FireRed maintains 64 "hidden variables" in one of its DMA-protected RAM sections (specifically, they overlap the RAM used for script variables 0x4100 - 0x417F, at [0x03005008] + 0x1200
). Each of these variables is a dword whose value has been encrypted with a dword key stored at [0x0300500C] + 0xF20
. Of these sixty-four variables, scripts have access to all but the last six (vars 0x00 to 0x33).
The purpose of these hidden variables is not yet clear. Hidden variable 5 appears to be a pedometer, and PokeCenters use hidden variable 15 (0xF) for something.
For the sake of consistency and to save on explanations in the command descriptions, I shall use the following terminology when discussing commands that deal with Person events on maps:
This is what AdvanceMap calls the "Person event no". It is a single-byte identifier that serves to differentiate one Person event from another within the current map. Most of the commands that deal with Person events require you to specify a Person using its local ID.
Local IDs must be unique within the map. That is, two Person events on the same map cannot have the same local IDs, but two Person events on different maps can. The player uses local ID 0x00
internally but is identified by local ID 0xFF
in scripts; the camera is identified by local ID 0x7F
in scripts. Person IDs are zero-indexed, but (as I just said) 0 is reserved for the player's OW.
This is what AdvanceMap calls the "Person ID". It is a scriptable flag that, if set, hides the Person event from the map. Commands like hidesprite modify the states of these flags.
Visibility flags do not have to be unique; multiple Person events can share the same visibility flag, even if on the same map. (They will all be affected by the flag's state.) However, the flag 0x0000
cannot be used; a Person event that has been set to use it ("Person ID" is "$0000" in AdvanceMap) effetively has no visibility flag.
A script bank is a four-byte storage area. Four such banks are available. They are usually used to load pointers that certain commands (or ASM code) can make use of.
The Advance games contain "standard functions". These are reusable scripts that have been given a single-byte identifier. They can be invoked using gotostd, callstd, gotostdif, and callstdif.
Most standard functions display different types of message boxes, or handle the process of obtaining a visible item from the overworld. A thread on PokeCommunity describes the standard functions in detail, lists each of Emerald's standard functions, and describes how to add your own standard function to any of the Pokémon Advance-generation games.
FireRed has a data table at 0x0845318C
, which associates a "base" trainer flag with up to five other trainer flags. These other flags are used for rematches; their trainers are rematch versions of the trainer associated with the "base" flag.
The table is limited to 0xDC
(zero-indexed) rows. A single row in the table is structured in the following manner:
0xFFFF
in a row means that there is no rematch for that slot. 0x0000
in a row means that no rematches are defined for that slot or any of the ones after it (and the slots after it should be 0x0000
as well).
When initiating a rematch battle via trainerbattle, the game will attempt to select the appropriate rematch flag, which will be used to start the battle.
First, the command locates the rematch table row for the input trainer flag (by searching for a row whose first flag is equal to the input trainer flag). The ASM will then loop through each rematch flag in the row, checking their states and retrieving the earliest cleared (non-defeated) rematch flag. If the ASM encounters an 0xFFFF
entry, that entry will be skipped. If the ASM encounters 0x0000
at any point in the row, it will stop looping and select the last valid flag it looped over.
The game saves the number of the selected rematch flag (0 - 5), and uses that to check one of five different flags that enable rematches based on the player's progress through the game; we'll cause these five flags "state flags". If the state flag that would enable this rematch flag is cleared, then the game will select the previous rematch flag. (If the previous rematch flag is 0xFFFF
, then the game loops backwards through the row until it finds a valid flag; that flag is then selected.)
Finally, the game will take the selected flag and check its state. If it is cleared, trainerbattle
will call a script (different one for each battle type), and that script will start the battle by calling repeattrainerbattle (or an equivalent special). If the selected flag is set, on the other hand, then trainerbattle
will return without doing anything and the calling script will continue.
The limit to 0xDC
rows is the result of a comparison at 0x0810D1BC
. As far as I know you can change that to any single-byte value without problems, though you'll probably have to repoint the table so you can extend it. (Multi-byte values would require rearranging some RAM and some ASM.)
The trainerbattle
command's pointer to the table is at 0x0810CEA4
. There may be other pointers to the table elsewhere in the ROM, but so far as I can discern, that's the only pointer used by trainerbattle
.
The limit to five rematch flags per row is the result of:
0x0810D1AC
and 0x0810CCA8
compare registers to the maximum number of rematch flags.0x0810D1B8
increments a register by the length of one table row (0x10
bytes).0x0810CE88
is used to recalculate the offset of a table row given a row number. (The result of the shift is the number of bytes that, when added to the table offset, produces the row offset.)0x0810CCBC
point to ASM routines (which load the appropriate "state flag" for a given rematch number and then goto the ASM routine at 0x0806E6D0
); there's one routine per rematch slot, and to add more, you'll need to repoint that set of pointers (the pointer to that set of pointers is at 0x0810CCB8
).0x0000
entries for new rematch flags to each row.