• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

[XSE] Scripting Tutorial

1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
XSE Scripting Tutorial for 2017

NOTE: If you are using pokéruby, pokéfirered or pokéemerald, this tutorial is not relevant to you. This is for those who are still using binary hacking tools and methods.
If you're using pokéemerald, this tutorial is where you want to go!


-----------------------------------------------------------------------------------------------------------------------------------------------------

I would like to first and foremost like to thank tajaros and diegoisawesome plus those who inspired them way back when for their tutorials which taught me the foundations of scripting. My guide aims to go over some points of theirs, make it as easy as possible for new members to learn, collect everything script-related on one page, and share some tips and tricks I picked up on my own that I wish someone had put in a tutorial when I was starting out! To find something in particular that you might be curious about that isn't immediately obvious in the contents list, you can Ctrl+F and search for a key word, such as "attack" if you're looking for something to do with attacks.

Scripting is, in my humble opinion, THE most important thing to learn in manipulating Pokémon games. It's what you use to create your dialog, your events, your quests, to make stuff happen, to literally create your gameplay. You can create a perfectly good hack using default sprites and tiles in your ROM if you script it well. If you're new to ROM hacking, learn scripting first. Fancy tiles, custom sprites and all that stuff can come later.

The first thing you should do, if you haven't already, is download a copy of HackMew's XSE 1.1.1, Lu-ho's AdvanceMap 1.92 and a ROM of your choice. At this point in time this tutorial is for FireRed[FR] and Emerald[EM] only as these two seem to be the most popular ROMs of choice for binary. If you find any terminology confusing or want very in-depth explanations of commands, I recommend DavidJCobb & Spherical Ice's extensive documentation on XSE commands here.

-----------------------------------------------------------------------------------------------------------------------------------------------------

Table Of Contents

Part #1: The Basics

Part #2: The Core

Part #3: Manipulating the Overworld

Miscellaneous

*to be expanded upon*
 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Pointers & Script Layout
XSE uses dynamic offsets - meaning it automatically searches for free space from a given beginning offset. For the sake of this tutorial, we'll use #dynamic 0x800000, although it can technically be any free offset. 0x800000 and upwards is generally the safest, as from that point onwards there is a lot of free space to use.

0JsCJPh.png

Thus, below should be the first line of your script. This means that every script you compile from now on will automatically compile to the first free offset it finds after 0x800000.

#dynamic 0x800000
Upn2geu.png

Now, onto the second line of your script. A pointer is just a label for a section of your script, prefixed with @. It can be any mixture of letters or numbers as long as it doesn't contain any spaces or special characters. For example, we can have @MyScript1 but not @My Script 1. We'll call our first pointer @main for the sake of the tutorial, so now we've got this:

#dynamic 0x800000

#org @main
sS9qe9c.png

The #org part notes that this is the start of a new script section labelled pointer @main. There are lots of different ways of "closing" the script which I will cover later in the tutorial, but for now I'll just show you the most basic way of finishing it: end. That's it. You can put whatever you want between your pointer and your "finishing statement", like this:

#dynamic 0x800000

#org @main
{your script contents}
end
PhKtPtl.png

Above is your basic layout. This tells XSE to compile the script labelled @main to free space anywhere above 0x800000.

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Simple Text Scripts

Let's start with a basic NPC - we want to make someone face us and say hi, or in scripting terms, display a string of text. We do this with a msgbox.

The msgbox command is set up like this:
msgbox @pointer 0x[number of msgbox type]

There are various msgbox types which we'll go through one at a time. Here's the most common, 0x6:

CjtuuIG.png


Spoiler:


So, we have quite a few new additions here. lock prevents the player from moving. Alternatively, lockall stops all NPCs on the map from moving. Should come directly after your #org @main but before your msgbox.
faceplayer is fairly self explanitory too; it just makes the NPC face the PC before talking.
release lets the player move again. If you used lockall instead, you'll have to use releaseall. After release or releaseall, finish with end.
#org @greeting is a pointer to our text string, "= Hi!". I'll go into more detail on text info later, but the "=" basically tells XSE it's the start of a string, or line of text.

That script will make someone face you and say "Hi!". Alternatively, there is a shorter way of scripting NPCs: msgbox 0x2.

zutWgPY.png


Spoiler:


Using the above version, msgbox 0x2, means you don't need the lock, faceplayer or release commands, whereas msgbox 0x6 does. Both scripts do exactly the same thing.

msgbox 0x3 is used in the original games for signposts; it displays the sign textbox when used on an actual signpost tile. Like 0x2, you don't need the lock, faceplayer or release commands.
Avara said:
#dynamic 0x800000

#org @main
msgbox @sign 0x3
end

#org @sign
= Signpost

msgbox 0x4 is a normal textbox just like 0x6, in that you need the lock, faceplayer and release commands surrounding it. The difference here is that the textbox will stay open, meaning we require a new command to make it go away, closeonkeypress.
#dynamic 0x800000

#org @main
lock
faceplayer
msgbox @greeting 0x4
closeonkeypress
release
end

#org @greeting
= Hi!

From here on in for a bunch of things, you are going to need to refer to the following:

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
FireRed & Emerald Item ID Numbers
Spoiler:

FireRed & Emerald Pokémon ID Numbers
Spoiler:

FireRed & Emerald Attack ID Numbers
Spoiler:

FireRed Multichoice ID Numbers
Spoiler:


 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Additional Text Info

As I mentioned before, the "=" before your desired script's text lets the program know you want the text that follows it to be displayed. Of course, there's a limit to how long the text can be - to ensure you're never wrong, use the Text Adjuster.

rSIm1uG.png

The \n allows the text to go to a new line when it gets too long.
After the initial use of \n, \l can be used for a new line, but only after \n. As an example:
Avara said:
#dynamic 0x800000

#org @main
lock
faceplayer
msgbox @greeting 0x6
release
end

#org @greeting
= Hi! My name is Adam.\nWhat's your name? [.]\l[.][player]?

The [.] adds a little suspension point "..." in the actual text.
[player] will show up as the player's name in-game. Similarly, [rival] displays the rival's name in FireRed.
That text string, first with \n and then \l to break up the lines, will look like this:
Avara said:
Hi!
My name is Adam.
What's your name? ...
... [player's name]?
Alternatively, you could have:
Avara said:
#dynamic 0x800000

#org @main
lock
faceplayer
msgbox @greeting 0x6
release
end

#org @greeting
= Hi! My name is Adam.\nWhat's your name? [.]\p[.][player]?
What does \p do? This actually opens a new textbox without scrolling like \l does, so it can look better in some cases, such as for a new sentence as opposed to a continuing one. So it'd look like:
Avara said:
Hi!
My name is Adam.
What's your name? ...

... [player's name]?
-----------------------------------------------------------------------------------------------------------------------------------------------------
Buffers
We can display more than just the player or rival's name similarly, using buffer commands. These let you show the name of a Pokémon, item, attack or number.

Now that we've got that handy list of hex IDs, we can move onto our first set of commands that use them. Let's start with the easiest; bufferfirstpokemon, set up like this:
bufferfirstpokemon 0x[buffer number]

This one gets the species name of the first Pokémon in your player's party. The [buffer number] part is where you choose the buffer number to assign the name to - for [buffer1] set this to 0x0, for [buffer2] set this to 0x1, etc. The [buffer1] part is what you'll be using in your text to display the PC's first Pokémon's name like so:
#dynamic 0x800000

#org @main
lock
faceplayer
bufferfirstpokemon 0x0
msgbox @npctext 0x6
release
end

#org @npctext
= Wow, your [buffer1] is so cool!

The bufferfirstpokemon part has to come before your msgbox that uses it, otherwise the game won't know which name to display in your text and you'll get a nasty glitch. It's the same for all buffer commands, including the next one, bufferpokemon:
bufferpokemon 0x[buffer number] 0x[Pokemon ID]

Like before, you need to assign the Pokémon's name to a buffer number. Using that list of hex IDs from earlier, you can then choose a Pokémon's name to display. Let's pick Venusaur for example, or the Pokémon ID number 3. Here's an example combining bufferfirstpokemon and bufferpokemon, assigning them to buffer numbers 1 and 2 respectively.
Avara said:
#dynamic 0x800000

#org @main
lock
faceplayer
bufferfirstpokemon 0x0
bufferpokemon 0x1 0x3
msgbox @npctext 0x6
release
end

#org @npctext
= Your [buffer1] is so cool, but\nmy [buffer2] is tougher!

In-game, this will show up as "Your [first party member] is so cool, but my Venusaur is tougher!".

The bufferitem and bufferattack commands are almost identical to bufferpokemon, set up like this:
bufferitem 0x[buffer number] 0x[Item ID]
bufferattack 0x[buffer number] 0x[Attack ID]

All you have to do is choose your buffer number as before, and an item ID. For the sake of the tutorial, let's use item ID #1 - a Master Ball in both FR and EM.
#dynamic 0x800000

#org @main
bufferitem 0x0 0x1
msgbox @npctext 0x2
end

#org @npctext
= I wish I had a [buffer1].

... Or an attack ID. For the sake of the tutorial, let's use item ID #1 - Pound.
Avara said:
#dynamic 0x800000

#org @main
bufferattack 0x0 0x1
msgbox @npctext 0x2
end

#org @npctext
= The only attack my Pokémon\nknows is [buffer1].
If you're using the "stdattacks.rbh" file as demonstrated below, you can substitute the attack ID for how it's defined there, so for the same attack, Pound (0x1) can simply be "ATK_POUND".
Avara said:
#dynamic 0x800000
#include stdattacks.rbh

#org @main
bufferattack 0x0 ATK_POUND
-----------------------------------------------------------------------------------------------------------------------------------------------------

The buffernumber command isn't as straightforward. It actually shows the numerical value of a variable. We'll go into more detail on variables later, but let's use 0x8000 and its value is 100 for example purposes.
buffernumber 0x[buffer number] 0x[Variable containing desired number]

With buffernumber we choose the number of the buffer to display, and then the variable we want the value of to get our desired number. In this case, we've assumed var 8000 contains our desired number, 100.
Avara said:
#dynamic 0x800000

#org @main
buffernumber 0x00 0x8000
msgbox @npctext 0x2
end

#org @npctext
= My Charizard grew to level [buffer1]!
-----------------------------------------------------------------------------------------------------------------------------------------------------
Text Colours
9UqlgRF.png

Adding colour to your text is a nice way of differentiating characters and making item or place names stand out.
Avara said:
#dynamic 0x800000
#org @main
lock
faceplayer
msgbox @npctext 0x6
release
end

//FireRed;

#org @npctext
= [blue_fr]What I wouldn't give for a cup\nof [green_fr]Coffee[blue_fr] from Clifftop Café[.]

//Emerald;
#org @npctext
= [blue_em]What I wouldn't give for a cup\nof [green_em]Coffee[blue_em] from Clifftop Café[.]

Fire Red Colours:
Spoiler:


Emerald Colours:
Spoiler:


 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Conditional Text Scripts

Let's start the next section with something nice and simple, shall we? Throwback to our msgbox command. This time we'll be looking at msgbox 0x5, or in other words, making a script where the player can answer "Yes" or "No".

2JTOAQl.png

Spoiler:

The goto command is exactly as it sounds; it literally tells the script to go to another pointer.
compare 0x800D, or compare LASTRESULT gets the result of the player's choice - in msgbox 0x5's case, 0x0 for 0 "No" or 0x1 for 1 "Yes".
Notice that when the player chooses "Yes", it doesn't go straight to the msgbox command which displays the text. This needs to be contained in its own script section, hence why I named the pointer "@YesOrg" for convenience. If you accidentally send your "Yes" pointer to the pointer for the text string(@yes) instead of the script section it's contained in (@YesOrg), bugs will follow.
If the LASTRESULT, or 0x800D is not 0x1 for "Yes" it will not goto @YesOrg, it just continues the script, meaning it displays the text string for @no and closes.

goto works just as well - the example below will give you the exact same results as the script above.

RSQCFHR.png

Spoiler:

-----------------------------------------------------------------------------------------------------------------------------------------------------

Let's go back to our basic NPC scripts for a moment. Every city needs filler NPCs, and they can get boring if they just say the same thing over and over again. In comes our next handy command, random. All it does is generate a random number within the range you set and then goes to the appropriate pointer, like this:

random 0x[number of options you want]
compare 0x800D 0x0
if 0x1 goto @option1
[etc...]

Let's say you wanted a NPC to say three different things depending on the random number generated. You'd need a script like this:

epZ14wp.png

Spoiler:

-----------------------------------------------------------------------------------------------------------------------------------------------------

Now we've covered random, we can move onto multichoice. For those of you who don't know what a multichoice box is, here's an example.

04yP3hg.png

The layout for the multichoice command is as follows:

preparemsg @pointer
waitmsg
multichoice 0x[X Co-ordinate of Box] 0x[Y Co-ordinate of Box] 0x[Multichoice ID]* 0x1

*Refer to multichoice IDs provided.

preparemsg prepares a text string to display and waitmsg is self explanitory, it just makes sure the full text is displayed before opening the multichoice box.
The 0x1 at the end means the player can't press B to exit the multichoice box. If it's 0x0 it can be cancelled with B - 0x1 is just my personal preference as it forces the player to pick a choice. Here's an example script from the above screenshot of a FireRed ROM, with "Yes", "No" and "Info" as options:

Spoiler:

The copyvar command here copies the result stored in LASTRESULT to var number 8000 so it can be compared to the result of the player's choice. More on vars later. Depending on the player's choice, you can make the script goto a different @pointer.

-----------------------------------------------------------------------------------------------------------------------------------------------------

Another minor conditional script example is one based on whether the player chose the male or female character - for this we could use the checkgender command:

#org @start
lock
faceplayer
checkgender
compare LASTRESULT 0x0
if 0x1 goto @boy
goto @girl

If the value for the player's gender is 0, this means they are playing the male character and the script jumps to @boy, if not it goes to @girl. The value for the female character is 1, so vice-versa you can have this:

#org @start
lock
faceplayer
checkgender
compare LASTRESULT 0x1
if 0x1 goto @girl
goto @boy

Ultimately, both of those examples do the same thing, so you can use either =)

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Flags & Variables
Think of a flag as an on or off switch - it can be either 1 "ON" or 0 "OFF". Think of a variable as a better version of a flag - it can't just be 0x0 or 0x1 "on or off"- but holds any value between 0x0 and 0xFF, hence the name "variable". Both are crucial for creating your gameplay events, but we'll focus on flags for now:
Code:
setflag 0x[Flag Number]

Code:
clearflag 0x[Flag Number]

RSaz6ss.png


Here is a list of "special" flags for each game - these have different in-game functions when set, or "ON":

FireRed:
Spoiler:

Emerald:
Spoiler:

-----------------------------------------------------------------------------------------------------------------------------------------------------
karatekid552 and DavidJCobb did an excellent job of referencing every flag and variable in the FireRed ROM and what they do. If you hack FR, this documentation will be invaluable to you. Emerald hackers will find this information on flags/vars useful.
-----------------------------------------------------------------------------------------------------------------------------------------------------

Let's move on to variables.
Code:
setvar 0x[Variable Number] 0x[Value To Set To]
As you could probably guess, the setvar command sets your chosen variable to your chosen value. If you want to add to a variable's existing value, we use addvar:
Code:
addvar 0x[Variable Number] 0x[Value To Add To Var]
Let's say I wanted to increase the value of 0x40D1 by 10 - I'd have addvar 0x40D1 0xA. Similarly, if I wanted to subtract from a variable's existing value, I'd use subvar, which is set up exactly the same:
Code:
subvar 0x[Variable Number] 0x[Value To Subtract From Var]
What if we want to copy the value of one variable into another?
Code:
copyvar 0x[Variable 1] 0x[Variable 2]
The above line just takes the value of Var #1 and stores it in Var #2.
Now that we know how to add to, subtract from and set a variable, how do we check it?
Code:
compare 0x[Variable Number] 0x[Value To Check For]
if 0x[More/Less/EqualTo] goto @pointer
Let's say we want to check if the var 4011's value is 3, for example:
Avara said:
compare 0x4011 0x3
if 0x1 goto @pointer
What we're telling the script to do here is check that 4011 is equal to 3, and if it is to go to @pointer.
0x0 = Lower Than
0x1 = Equal To
0x2 = Greater Than
0x3 = Lower Than or Equal To
0x4 = Greater Than or Equal To

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Part #2: The Core
-----------------------------------------------------------------------------------------------------------------------------------------------------
Give, Take & Check For Items

Before you think about the multitude of free items you can give your players, you should always make sure they can actually take the item first!
Code:
checkitemroom 0x[Item ID] 0x[Quantity]
compare LASTRESULT 0x0
if 0x1 goto @pointer
This neat little command checks if you have enough room in your bag for the amount of the desired item. If your bag is full, the last line sends you to @pointer.
Not using this command prior to giving items can cause the player to "lose" them if they've got no space in their bag to take it. Now, onto actually giving the items! There are two ways of doing it:
Code:
giveitem 0x[Item ID] 0x[Quantity] 0x0
Nice and simple, and this way you even get a little message box automatically generated to notify the player that they've received the item. There is another way of giving the player an item "silently", meaning no pop-up notification.
Code:
additem 0x[Item ID] 0x[Quantity]
This version is useful for if you want to add your own custom string, for example:
Avara said:
additem 0x1 0x1
fanfare 0x101
msgbox @item 0x4
waitfanfare
closeonkeypress

#org @item
= [black_fr][player] received a [green_fr]Master\nBall[black_fr] from Atenza!

-----------------------------------------------------------------------------------------------------------------------------------------------------

Checking for items is easy with the checkitem command, set up like this:
checkitem 0x[Item ID] 0x[Quantity]
Let's see an example and check if the player has one Master Ball.
checkitem 0x1 0x1
compare LASTRESULT 0x1
if 0x4 goto @got
I used if 0x4 instead of 0x1 because this time, we're checking not that we have exactly one Master Ball - we're checking that we have more than one before we go to our pointer @Has.
0x0 = Lower Than
0x1 = Equal To
0x2 = Greater Than
0x3 = Lower Than or Equal To
0x4 = Greater Than or Equal To

To remove an item from the player's bag, all we need is this:
Code:
removeitem 0x[Item ID] 0x[Quantity]
Remember that if you're using the header file "#include stditems.rbh" you can substitute the item ID for its name beside the #define in any of these cases, e.g. if you want to take the player's Master Ball you could have:
Code:
removeitem ITEM_MASTERBALL 0x1
-----------------------------------------------------------------------------------------------------------------------------------------------------

Adding an item to the player's PC is just as easy with a single line:
Code:
addpcitem 0x[Item ID] 0x[Quantity]
Useful in cases where a player's bag might be full, but you want them to receive an item anyway.

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Sounds, Fanfares & Music

Since we're hacking a Pokémon game, let's start with the cry command:
Code:
cry 0x[Pokémon's Hex ID] 0x[Cry Effect]
It plays the cry of any chosen Pokémon. Let's say we wanted to play Charizard's cry:
Avara said:
...
cry 0x6 0x0
msgbox @Roar 0x4
waitcry
closeonkeypress
release
end

#org @Roar
= Charizard: Roar!
We use waitcry to ensure that the cry has finished playing before continuing the script - in this case, the textbox won't go away until then. You don't have to use it, just keep in mind that if you choose not to, the script will continue as the cry sound plays. It's really up to you. One thing quite a few people seem not to be aware of is that there's actually a variety of different effects that you can use to change the sound of your desired cry - you don't have to use 0x0 after specifying the Pokémon, contrary to popular belief! I tested each cry effect in both FireRed and Emerald and have done my best to identify them, but seeing as I had no exact documentation to refer to I could definitely be inaccurate.
Avara said:
Cry Effects
0x0 - Normal cry
0x1 - Reversed cry
0x2 - Unsure (slightly louder normal cry?)
0x3 - Unsure (like 0x2, maybe used for Growl or similar attacks)
0x4 - Unsure (low cry in reverse?)
0x5 - Low cry (before fainting?)

-----------------------------------------------------------------------------------------------------------------------------------------------------

It's kind of hard to describe what a fanfare is - in not so many words it's a short tune, for example, the healing jingle in Pokémon Centers. To use one in your script, use these lines:
Code:
fanfare 0x[Fanfare's Hex ID]
waitfanfare
All you have to do is choose the ID number of the fanfare you want from this list and put it after the 0x. waitfanfare means the script will wait for the sound to finish playing before continuing.

-----------------------------------------------------------------------------------------------------------------------------------------------------

For sounds, the layout is almost identical to fanfares:
Code:
sound 0x[Sound's Hex ID]
That's literally it. If you want to make the script wait for the sound to finish before continuing, you can add waitsound if you want to. The sounds list is here too.

-----------------------------------------------------------------------------------------------------------------------------------------------------

If you'd like to play music through your script, this is also nice and simple:
Code:
playsong 0x[Song's Hex ID] 0x0
Similarly to the others, use the ID of your desired music after playsong 0x, only you need that 0x0 at the end! There are a variety of ways to revert or change the music. Entering a battle after using the playsong command will also change the music back to default, so if you want to continue your music for the remainder of your script, you'll need another playsong straight after the battle.
Code:
playsong 0x[Song's Hex ID] 0x0
fadesong 0x[Song's Hex ID]
fadesong, as the name suggests, fades your song into another nicely so it doesn't just abruptly cut to the next music.
playsong 0x[Song's Hex ID] 0x0
fadeout 0x[Fade Speed]
pause 0x1
fadein 0x[Fade Speed]
fadeout fades the song that was playing to silence. pause 0x1 does what it says on the tin, it's just a small pause which lasts for approximately half a second. fadein fades the song that was playing back in from silence.

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
FireRed Songs & Fanfares
Spoiler:


FireRed Sound List ~ found by tajaros
Spoiler:
 
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
How To Compile Your Script

To insert your script into your hack, or compile it, is nice and simple. First you want to open your ROM in AdvanceMap 1.92, and decide where you want your script to be run from:

  • A Person Event/NPC Green "P"
  • A Signpost/Red "S" tile
  • A Trigger/Green "S" tile
  • A Level Script/The Map Header

In this example, we're going to assign a script to a NPC. Assemble your script, then hit this button:

LhAyeRP.png


You should end up with a screen like this:

Z3TCuUX.png


All you have to do is copy that offset beside @start, or your beginning pointer, and paste it in the person event's "Script Offset" Box, shown here:

REBXppW.png


For level scripts that are not triggered in the overworld, but from entering the map, you want to put your script here, outlined in red:

ir86UkT.png


 
239
Posts
8
Years
  • Age 31
  • Seen Apr 15, 2024
This is certainly ambitious but definitely much needed! Let me know if you'd like any help with things :)

I would suggest you cover preprocessing directives like #define and #include. Header files are really useful, especially when sharing scripts with other people in a project, or just your own sanity's sake so you don't have to try and remember the ID of an arbitrary pokemon or item every time you make a script.

It might also be useful to go more in depth on some commands that aren't well documented such as spriteface, spritebehave, or if there are any differences between warp and warp1, for example.

A level script tutorial would also be very helpful since most are somewhat older as well.

I know this is a lot to dump on you at once, but it would make this tutorial the most complete I've seen yet! :)
 
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
This is certainly ambitious but definitely much needed! Let me know if you'd like any help with things :)

I would suggest you cover preprocessing directives like #define and #include. Header files are really useful, especially when sharing scripts with other people in a project, or just your own sanity's sake so you don't have to try and remember the ID of an arbitrary pokemon or item every time you make a script.

It might also be useful to go more in depth on some commands that aren't well documented such as spriteface, spritebehave, or if there are any differences between warp and warp1, for example.

A level script tutorial would also be very helpful since most are somewhat older as well.

I know this is a lot to dump on you at once, but it would make this tutorial the most complete I've seen yet! :)

Thanks a lot! Yeah someone had suggested header files to me before, i'll definitely include some of those once I get around to making ones we don't already have! Less-documented commands and level scripting are going to be included too - my first aim is covering what we already have in other scripting tutorials like diego's and tajaros's, then when all that's done I'll move onto the extra stuff, just to make sure nothing is missed =)
 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Giving Pokémon & Eggs
Wondering how to give your player a Pokémon? In order to do this, we'll need to make use of two commands called givepokemon and countpokemon. Here's an example of how to use both, incorporating some things we've learned already:

Spoiler:


This script is for a NPC who gives the player a Bulbasaur - if they answer "Yes" to the question and have room for it in their party. It only happens once, afterwards the NPC says something generic. Let's break it all down:
Avara said:
'---------------
#dynamic 0x800000

#org @start
lock
faceplayer
checkflag 0x240
if 0x1 goto @Done
First section checks if flag 0x240 is set, and if it is, go to the pointer @done.
Avara said:
msgbox @question 0x5
compare LASTRESULT 0x1
if 0x1 goto @Yes
msgbox @saidnomsg 0x6
release
end
Next section asks the player a question. If they answer "Yes", or the result is 1, the script goes to pointer @Yes. If they said "No", they just say a line of text and the script ends there. By the way, LASTRESULT can be substituted for 0x800D, which is a bit harder to remember!
Avara said:
#org @Yes
countpokemon
compare 0x800D 0x6
if 0x1 goto @Full
This is the beginning of the @Yes pointer. countpokemon is fairly self explanitory, it counts how many party members you have.
compare 0x800D 0x6 compares the result of countpokemon to 6, and if it is 6, the script goes to the pointer @Full.
Avara said:
givepokemon 0x[Pokemon Hex ID] 0x[Level in Hex] 0x[Held Item ID] 0x0 0x0 0x0
That is how the givepokemon command is set up - in our script, it's a level 5 Bulbasaur not holding any items, so we've got this:
Avara said:
msgbox @take 0x6
givepokemon 0x1 0x5 0x0 0x0 0x0 0x0
Alternatively, if you're using "#include stdpoke.rbh" you could have this to make it easier on yourself:
Avara said:
givepokemon PKMN_BULBASAUR 0x5 0x0 0x0 0x0 0x0
The next part is music related which we'll cover in more detail later.
Avara said:
fanfare 0x101
msgbox @receive 0x4
waitfanfare
closeonkeypress
All this section does is play the little level-up jingle and display a message notifying that the player's received a Pokémon.
We've used msgbox 0x4 here, followed by waitfanfare then closeonkeypress, which prevents the message from being closed until the jingle has finished playing, similarly to how the pop-up message for finding items on the ground is.
Avara said:
msgbox @nick 0x5
compare LASTRESULT 0x1
if 0x1 call @YesToNick
msgbox @Donemsg 0x6
release
end
Fairly straightforward repeat - this part asks the player if they want to give their new party member a nickname. The difference here is that instead of goto we've used call instead. call will jump to a pointer, and then back to the original script with return.
Avara said:
#org @YesToNick
setvar 0x8004 0x0
call 0x81A74EB
return
In our nickname pointer that we've momentarily jumped to, we call 0x81A74EB - this will jump to the nicknaming screen in FireRed*.
return takes us back to our original script when the nicknaming screen is exited.
*If you're hacking Emerald, 0x2723DD for nicknaming instead of 0x81A74EB. Those are just pointers to already existing in-game scripts containing specials, which we'll cover much later!
Avara said:
msgbox @Donemsg 0x6
setflag 0x240
release
end
setflag 0x240 goes at the end, to set the flag number 240 and stop you from receiving infinite Bulbasaurs =P To give an Egg instead of a Pokémon, all you have to do is remove the givepokemon line and replace it with the giveegg command:
Avara said:
giveegg 0x[ID of Pokémon]
So, to give a Bulbasaur egg, we'd have giveegg 0x1.
 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Header Files

Open "stdpoke.rbh" (if you have it, it should come with XSE) and you'll see something like this:
gkcnELF.png


What does #define do? Let's look at Bulbasaur's entry - #define PKMN_BULBASAUR 0x1. This stops you needing to remember that Bulbasaur's ID is 0x1, you just have PKMN_BULBASAUR instead. To use a header file, all you have to do is add this line to the beginning of your script:
Avara said:
#include [filename].rbh
I'll refer back to an earlier example:
Avara said:
#dynamic 0x800000

#org @main
...
wildbattle 0x149 0x32 0xD1
...
This was to create a wild Pokémon battle with a level 50 Milotic holding Mystic Water. If you make use of "stdpoke.rbh" and "stditems.rbh", you could have this instead:
Avara said:
#include stdpoke.rbh
#include stditems.rbh

#dynamic 0x800000

#org @main
...
wildbattle PKMN_MILOTIC 0x32 ITEM_MYSTICWATER
...

For the majority of the tutorial I use the hex IDs so that you know where everything's supposed to be placed, but if you use header files like these, it will keep you from having to constantly refer to the hex ID lists. It really is a matter of personal preference!

Mainly hosting these here for safekeeping instead of attaching as files ~

Pokémon Header File
Spoiler:

Items Header File
Spoiler:

Attacks Header File
Spoiler:

Mart Items Header File
Spoiler:


 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Warps
There are a variety of different warp commands, which are used to teleport the player from one map to another. The simplest of these is warp, set up like this:
Code:
warp 0x[Map Bank] 0x[Map Number] 0x[Warp Number] 0x0 0x0
The map bank/number can be found next to the map's name in AdvanceMap. For example, if you open an Emerald ROM you'll notice that next to Littleroot Town it says (0.9). Littleroot Town's map bank would be 0 and the map number is 9. To get the warp number, you want to click A-Map's "Events" tab and look for the purple "W" tile. If you highlight the "W" tile for Birch's Lab you'll see that it's 2. So, to teleport the player to come out of the door to Birch's Lab, we'd do:
Code:
warp 0x0 0x9 0x2 0x0 0x0
There's also warpmuted shown below, which is exactly the same as above apart from the fact that it's silent:
Code:
warpmuted 0x[Map Bank] 0x[Map Number] 0x[Warp Number] 0x0 0x0
Next is warpwalk. It tends to be used in conjunction with doors, because it makes the player take one step upwards before warping:
Code:
warpwalk 0x[Map Bank] 0x[Map Number] 0x[Warp Number] 0x0 0x0
 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Pokémon Battle Scripts
First, we're going to learn how to make a wild Pokémon battle, useful for legendary encounters and such. We'll cover trainer battles a little later! The wildbattle command is set up like this:
Code:
wildbattle 0x[Pokémon] 0x[Level In Hex] 0x[Held Item]
Imagine we wanted to battle a level 50 Milotic holding Mystic Water:
Avara said:
#dynamic 0x800000

#org @main
...
wildbattle 0x149 0x32 0xD1
...
0x149 is Milotic's ID, 0x32 is 50 in hex, and 0xD1 is the item Mystic Water's ID. Click here for Pokémon/Item hex IDs if needed. Reminder that if you make use of the header files "stdpoke.rbh" and "stditems.rbh", you could have this instead:
Avara said:
#include stdpoke.rbh
#include stditems.rbh

#dynamic 0x800000

#org @main
...
wildbattle PKMN_MILOTIC 0x32 ITEM_MYSTICWATER
...

Checking The Result Of A Wild Battle
Wild Battle Result Check: [FR]
Code:
wildbattle 0x[Pokémon] 0x[Level In Hex] 0x[Held Item]
special2 LASTRESULT 0xB4
compare LASTRESULT 0x1
if 0x1 goto @DefeatedPointer
compare LASTRESULT 0x4
if 0x1 goto @RanPointer
hidesprite LASTTALKED
setflag 0x[OW's Person ID in A-Map]
release
end
special2 LASTRESULT 0xB4 returns a value. In this case if the returned value is 1, the script will goto @DefeatedPointer if the player accidentally fainted the Pokémon during the battle; good for letting them have another chance at capturing it. @RanPointer will be jumped to if, you guessed it, the player ran from the encounter. Aaand here's the equivalent for Emerald:

Wild Battle Result Check: [EM]
Code:
wildbattle 0x[Pokémon] 0x[Level In Hex] 0x[Held Item]
special2 LASTRESULT 0xB7
compare LASTRESULT 0x1
if 0x1 goto @DefeatedPointer
compare LASTRESULT 0x4
if 0x1 goto @RanPointer
hidesprite LASTTALKED
setflag 0x[OW's Person ID in A-Map]
release
end

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Display Pokémon Sprite
The showpokepic command is set up like this:
Avara said:
showpokepic 0x[Pokémon ID] 0x[X-Co-ord On Screen] 0x[Y-Co-ord On Screen]
Let's use it in a script.
Avara said:
#org @start
lock
faceplayer
showpokepic 0x4 0xA 0x3
msgbox @msg 0x4
closeonkeypress
hidepokepic
release
end

#org @msg
= I'm looking for this Pokémon.
0x4 is the ID for Charmander, 0xA 0x3 places the box containing the sprite in the middle of the screen so that it ends up looking like this:

DOTAhLW.png
 
Last edited:
794
Posts
10
Years
It's such a nice tutorial, you must have put lot of work into that. Why tho, I'm sure XSE will get replaced soon.
 
Last edited:
Back
Top