• 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
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.

Cheers! From what little I've seen from messing around with script-related stuff in pokeruby it seems like a lot of it is fairly similar to XSE command wise. I didn't have too much trouble following it seeing as I already know this part, so I figured if people can pick this up in the meantime it might still be beneficial to them in some way later down the line! When the disassembly is done I'd be happy to take on the task of making the tutorial for scripting via that too if that's something that would be needed =)
 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
sethealingplace

You'll notice that all Pok?mon Centers host a level script containing something along these lines:

mqwwTV1.png

What does this do? On entering the building, this script runs to make sure the player respawns at the last-visited Pok?mon Center on white-out.

sethealingplace IDs: [FR]
Spoiler:


sethealingplace IDs: [EM]
Spoiler:


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

Manipulating weather in the overworld is easy; all you need are these two lines in your script:
Code:
setweather 0x[Weather]
doweather
We use setweather to define the weather type we'd like and doweather to activate it. For example, here's the kind of script we'd need to make it start raining:
Avara said:
#org @start
lock
faceplayer
msgbox @msg1 0x6
setweather 0x3
doweather
msgbox @msg2 0x6
release
end

#org @msg1
= What a lovely day!

#org @msg2
= Oh[.] I spoke too soon.
The following spoiler contains a list of weather types, accompanied by gifs that show how they look in-game:
Spoiler:

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Changing Map Tiles

The "setmaptile" command, as you could probably guess, allows you to change a map's tiles. This is commonly used in the canon games for puzzles - such as Cinnabar's mansion where you interact with statues to open doors - but it can be used for anything, really.
Avara said:
setmaptile 0x[X-Coordinate] 0x[Y-Coordinate] 0x[Block Number] 0x[Passable? - 0x0 = Passable, 0x1 = Not Passable]
Your map editor should show the X and Y co-ordinates of the tile you want to change when you hover over it, same with the block number when selecting from the block palette. If you're using AdvanceMap, this data is shown at the bottom of the screen.
In this example, I'm just going to make some flowers appear when you talk to someone in an unedited Emerald ROM. Nothing too fancy!
Avara said:
#org @main
lock
faceplayer
checkflag 0x250
if 0x1 goto @done
msgbox @msg1 0x6
setmaptile 0x08 0x08 0x04 0x0
setmaptile 0x09 0x08 0x04 0x0
setmaptile 0x0A 0x08 0x04 0x0
setmaptile 0x0B 0x08 0x04 0x0
special 0x91
setflag 0x250
release
end

#org @done
msgbox @msg2 0x6
release
end

#org @msg1
= Bellsprout, use Growth!

#org @msg2
= Aren't Grass-type Pokémon great?

These X and Y co-ordinates are for the tiles between Brendan & May's homes in Littleroot Town. In vanilla Emerald, block number 0x04 is the one containing default flowers. I used 0x0 for the last bit, so that the flowers don't block the player's path. What's the special 0x91 for? This refreshes the map so that we can see the changes we've made. If you're hacking FR, you'll need special 0x8E to refresh the map instead of 0x91. I've also setflag 0x250 so that the script doesn't repeat itself - although you could use a var instead if you wanted.

DgRGkge.gif

Yay, it works! But what about when we exit the map? The flowers are gone! We used a flag, so the player can't talk to the NPC to make the flowers grow again. How do we make this a permanent change? We need a second script for the map header.
Avara said:
#org @start
checkflag 0x250
if 0x1 call @pointer
end

#org @pointer
setmaptile 0x08 0x08 0x04 0x0
setmaptile 0x09 0x08 0x04 0x0
setmaptile 0x0A 0x08 0x04 0x0
setmaptile 0x0B 0x08 0x04 0x0
return
All this does is call @pointer which shows our flower tiles if flag 0x250 is set. We want to add this to the map's header so that the script runs immediately upon entering the map.
To do this, first compile a similar script to the one above and take a note of its offset. Add a "setmaptile" script as shown then paste your offset in the "Script Offset" box if you're using AdvanceMap:

LYWlzZt.png

Test again, and this time when you talk to the NPC to make the flowers grow, the map will be changed permanently.

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Hide/Show Map Objects
Do you need to make a NPC or other OW sprite disappear?
Code:
hidesprite 0x[Map Object ID]
One line is all you need! The "Map Object ID" refers to what AdvanceMap calls the "Person Event Number", as seen here:
A6SpSMS.png

Remember to convert this to hex! So, if our OW sprite had a "Person Event Number" of 10, you'd want to use 0xA in your script, not 0x10. To make a previously hidden sprite visible, we'd use showsprite the same way:
Code:
showsprite 0x[Map Object ID]
If you want to make it disappear permanently, there's an extra little thing to do. Take a look at this section outlined in red below in AdvanceMap:
bhThIsl.png

What you want to do here is assign a flag number to your NPC/OW and put it in the "Person ID" box. Let's say our map object had Person Event number 1 and flag 2F0:
Avara said:
...
hidesprite 0x1
setflag 0x2F0
...
Alternatively, to show a previously hidden sprite, in reverse order:
Avara said:
...
clearflag 0x2F0
showsprite 0x1
...

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
NPC Movements

The applymovement command is what you'll need if you want to make an overworld sprite move in your script:
Code:
applymovement 0x[Map Object ID] @PointerToMovements
waitmovement 0x0
If you want to move the player and not a NPC, you'll have to use 0xFF as the Map Object ID. waitmovement, as you probably guessed, means the script will wait for the movements to be finished before continuing. Let's look at a more fleshed-out example:
Avara said:
#org @start
lock
faceplayer
msgbox @msg 0x6
applymovement 0x1 @movements
applymovement 0xFF @movements
waitmovement 0x0
release
end

#org @msg
= Let's walk three steps left!

#org @movements
#raw 0x0A
#raw 0x0A
#raw 0x0A
#raw 0xfe
Assuming our OW's "Person Event Number" in AdvanceMap is "1", we've used 0x1 as the first ID and 0xFF to make the player move along with them. Our pointer @movements contans the movement data. Where does #raw 0x0A come from? Basically, these are just identifiers for movement types. raw 0x0A is used to make the object step left in Emerald - these IDs differ between EM and FR, so make sure you don't get them mixed up! Another thing you shouldn't forget to do is add raw 0xFE at the end of your list of movements.

Movement IDs for Emerald
Spoiler:


Movement IDs for FireRed
Spoiler:


Another thing you might like to know about while we're on the subject of movements is how to move the camera. This is an example for Emerald:
Avara said:
#org @start
lock
faceplayer
special 0x116
applymovement 0x7F @move1up
waitmovement 0x0
msgbox @msg 0x6
applymovement 0x7F @move1down
waitmovement 0x0
special 0x117
release
end

#org @msg
= I'll move the camera!

#org @move1up
#raw 0x09
#raw 0xfe

#org @move1down
#raw 0x08
#raw 0xfe
Using 0x7F defines that we want the camera to move.
[EM] special 0x116 "unlocks" the camera (for lack of a better word) allowing it to move and special 0x117 "locks" it back in place.
[FR] In FireRed, the equivalent of these are special 0x113 and special 0x114 respectively.

That's about it for applymovement!

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Opening & Closing Doors

Kind of a short section, but if you need a script that involves having the player/NPCs enter/exit a building or something, you'll need to know how to do this.
Code:
setdooropened 0x[X Co-ordinate of Door Tile] 0x[Y Co-ordinate of Door Tile]
doorchange
The first line is where we specify that we want the door to open, and which door on the map it is. This is followed by doorchange, which activates the door's animation. The X/Y co-ordinates refer to the position of your door in your map. You'll need to make sure this is a proper door tile (has the appropriate animation when interacted with). To close doors again, it's pretty similar:
Code:
setdoorclosed 0x[X Co-ordinate of Door Tile] 0x[Y Co-ordinate of Door Tile]
doorchange
Let's have an example script, and go over some points from earlier! For starters, I've just put the Professor's OW outside his lab, so that he's blocking the doorway.
VZ6Oya8.png
All we want to do here is make him go inside, so we'd have this:
Avara said:
#org @main
lock
faceplayer
msgbox @msg 0x6
applymovement 0x1 @faceup
waitmovement 0x0
setdooropened 0x07 0x10
doorchange
sound 0x8
applymovement 0x1 @stepup
waitmovement 0x0
hidesprite 0x1
setflag 0x250
setdoorclosed 0x07 0x10
doorchange
release
end

#org @msg
= Please, come in!

#org @faceup
#raw 0x01
#raw 0xfe

#org @stepup
#raw 0x09
#raw 0xfe
We've made him face the door before it opens (because if he didn't that would look very weird) and then he walks through the open door. Next, we've used hidesprite to hide the OW, and set a flag to make sure that it doesn't reappear as soon as the script ends.

2AkqmZM.gif

 
Last edited:
162
Posts
6
Years
  • Age 32
  • Seen Mar 1, 2023
I'm driving my head against the wall due to an issue with XSE, and I just can't figure out what the problem is. Can you help me?

Basically, what's going on is that I'm trying to change Professor Oak's movement route in Pokémon FireRed when he approaches the player after you try to enter Route 01 before obtaining a Pokémon. I've found that this happens in two places: 0x1656F2 for the left event, and 0x1656FB for the right event.

In the right event, the movement route functions properly:
A3S8asu.jpg


The left event is naturally right next to it, so the only change would be that the professor has to move left one more time. So it looks like this:
EyPx9JT.jpg


However, for some reason, every single time after I compile and reload the file it ends up looking like this!
Q5NkFY9.jpg


For some reason a part of 0x1656FB gets pasted into 0x1656F2, and I can't for the live of me figure out why. At least I thought it might be because I was copy-pasting code, but even after re-typing it all by hand I still get the same issue.
 
38
Posts
7
Years
I'm driving my head against the wall due to an issue with XSE, and I just can't figure out what the problem is. Can you help me?

Basically, what's going on is that I'm trying to change Professor Oak's movement route in Pokémon FireRed when he approaches the player after you try to enter Route 01 before obtaining a Pokémon. I've found that this happens in two places: 0x1656F2 for the left event, and 0x1656FB for the right event.

In the right event, the movement route functions properly:
A3S8asu.jpg


The left event is naturally right next to it, so the only change would be that the professor has to move left one more time. So it looks like this:
EyPx9JT.jpg


However, for some reason, every single time after I compile and reload the file it ends up looking like this!
Q5NkFY9.jpg


For some reason a part of 0x1656FB gets pasted into 0x1656F2, and I can't for the live of me figure out why. At least I thought it might be because I was copy-pasting code, but even after re-typing it all by hand I still get the same issue.

Editing existing scripts isn't very safe, because you change the code length. When the length exceeds the original, other data might get overwritten, that's why XSE prevents you from doing that. The best thing to do is find some free space (FF bytes) and repoint the script (e.g. in advance map)
 
162
Posts
6
Years
  • Age 32
  • Seen Mar 1, 2023
Okay, this program is really not cooperating and it's starting to get really frustrating.

So, I followed Skyro005's advice, and I tried making a short test script to see if it worked. And it did! Upon entering your living room for the first time, you get a short bit of text as a test. All was well.

However... Here comes the big problem. The #dynamic 0x800000 command simply does not work. No matter how much I try, the single and only offset it will give to any of my new scripts is 0x800000. One that is already taken by my test script, which as far as I can tell cannot be changed or removed anymore. This means that at the moment, I cannot add anything to the game simply because this command is broken.

What do I do now? I cannot find even a single mention of this problem, let alone a solution!

EDIT: Oh, and also, if I try changing the command so I can forcefully get a different offset (like using #dynamic 0x800003), it once again spews random crap into my script when I try to compile it. How on earth anybody can work with this tool is beyond me, because this is without a doubt one of the most frustrating and nonsensible scripting tools I have ever worked with.
 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Trainer Battle Scripts

Next we're going to move on to trainer battles, the command for these isn't as straightforward as it seems at first glance.
Code:
trainerbattle 0x[Type Of Battle] 0x[Trainer's ID in Hex] 0x0
You can find a trainer's hex ID in any trainer editing tool, but what do I mean by "type of battle"? I'm going to list these one at a time. As I'm covering both FireRed[FR] and Emerald[EM], keep in mind that FR has the VS Seeker whereas EM has the Match Call function instead, so some types of trainer battle may not work correctly in a certain ROM.

trainerbattle 0x0 [FR] [EM]

This battle type is exactly the same in FR as it is in EM, used for standard trainer battles. Here's an example script:
Avara said:
#org @start
trainerbattle 0x0 0x001 0x0 @EncounterText @DefeatText
msgbox @AfterBattle 0x6
end

#org @EncounterText
= I challenge you!

#org @DefeatText
= You beat me[.]

#org @AfterBattle
= I'll say this after you've\nbattled me.
We're just using Trainer ID 0x001 for the sake of consistency.

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

trainerbattle 0x1 [FR] [EM]

0x1 is used for Gym Leaders in both FR and EM. If you open up a Gym Leader's script in your ROM of choice you'll be able to see that there's quite a bit going on, such as setting or clearing trainerflags (this is mainly done to ensure any unbattled Gym trainers don't try to fight you when you're on your way out after beating the Leader). For this example script, we don't have any of that, just a basic Gym Battle that ends in the player receiving a Badge and TM as a reward for winning:
Avara said:
#org @start
lock
faceplayer
checkflag 0x231
if 0x1 goto @Defeated
trainerbattle 0x1 0x001 0x0 @EncounterText @DefeatText @WonPointer
release
end

#org @Defeated
msgbox @AfterBattle 0x6
release
end

#org @WonPointer
msgbox @BadgeInfomsg 0x6
fanfare 0x171
preparemsg @ReceivedBadgemsg
waitmsg
waitfanfare
checkitemroom 0x121 0x1
compare LASTRESULT 0x0
if 0x1 goto @BagFull
additem 0x121 0x1
msgbox @ReceivedTMmsg 0x4
closeonkeypress
setflag 0x231
msgbox @TMInfomsg 0x6
release
end

#org @BagFull
msgbox @BagFullmsg 0x6
release
end

#org @EncounterText
= I challenge you!

#org @DefeatText
= You beat me[.]

#org @AfterBattle
= I'll say this after you've\nbattled me.

#org @BadgeInfomsg
= Please, take the X Badge and this\nTM!

#org @ReceivedBadgemsg
= [player] received the X Badge\nfrom the Gym Leader.

#org @ReceivedTMmsg
= [player] received TMX!

#org @TMInfomsg
= TM01 contains X move!

#org @BagFullmsg
= You don't have enough space in\nyour bag.
Just like before, we've got pointers for the initial encounter text, the message that displays when you win the battle and for after the battle. Although the Gen III games have special flags set aside for Badge functionality, I used 0x231 here for the sake of easiness, as well as Trainer ID 0x001 again. Notice that beside @DefeatText we have @WonPointer which contains the section of the script that rewards the player. fanfare 0x171 is the jingle played in Emerald when a Gym battle is won. If you've been paying close attention or have scripting experience already, you should know what everything else is for by now!

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

trainerbattle 0x2 [EM]

This battle type isn't used in FireRed. It's used with the PokéNav's Match Call rematches - see the Emerald section of trainerbattle 0x5.

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

trainerbattle 0x3 [FR] [EM]

0x3 is unique in that it allows the script to continue once the player wins the battle, as opposed to displaying a few messages and ending.
Avara said:
...
trainerbattle 0x3 0x001 0x0 @DefeatText
...

#org @DefeatText
= You beat me[.]
Substitute the "..."'s for whatever you like and that's pretty much it! All you need is a trainer ID and a pointer to the defeat text.

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

trainerbattle 0x4 [FR] [EM]

This one is used for standard double battles and is set up the same way in both FireRed and Emerald.
Avara said:
#org @start
trainerbattle 0x4 0x001 0x0 @EncounterText @DefeatText @OnlyOnePoke
msgbox @AfterBattle 0x6
end

#org @EncounterText
= We challenge you!

#org @DefeatText
= You beat us[.]

#org @AfterBattle
= We'll say this after you've\nbattled us.

#org @OnlyOnePoke
= You can't double battle with only\none Pokémon!
The trainerbattle commands concerning double battles have a nice built-in check - if the player only has one party member, the battle won't happen.

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

trainerbattle 0x5 [FR] [EM]

0x5 has different uses depending on your ROM.
[FR] In FireRed, it's used for VS Seeker rematches.
Avara said:
#org @start
trainerbattle 0x0 0x001 0x0 @EncounterText1 @DefeatText
special2 LASTRESULT 0x39
compare LASTRESULT 0x1
if 0x1 goto @RematchPointer
msgbox @AfterBattle 0x6
end

#org @RematchPointer
trainerbattle 0x5 0x001 0x0 @EncounterText2 @DefeatText
msgbox @AfterBattle 0x6
end

#org @EncounterText1
= I challenge you!

#org @EncounterText2
= I challenge you again!

#org @DefeatText
= You beat me[.]

#org @AfterBattle
= I'll say this after you've\nbattled me.
The first part closely resembles a standard trainer battle, using trainerbattle 0x0 and its usual parameters. The special2 LASTRESULT 0x39 and the following couple of lines correspond to the VS Seeker - don't worry too much about that for now! @RematchPointer contains, as labelled, our rematch - which is set up exactly the same as a standard battle, except we've used trainerbattle 0x5 as our prefix instead.

[EM] In Emerald, we don't have the VS Seeker - we've got Match Call instead. For single rematches, we'd need a script like this:
Avara said:
#org @start
trainerbattle 0x2 0x001 0x0 @EncounterText1 @DefeatText1 @NavPointer
special2 LASTRESULT 0x3C
compare LASTRESULT 0x1
if 0x1 goto @RematchPointer
msgbox @AfterBattle 0x6
release
end

#org @NavPointer
special 0x207
waitmovement 0x0
msgbox @PokenavMsg 0x6
setvar 0x8004 0x001
special 0x1E9
registernav 0x001
release
end

#org @RematchPointer
trainerbattle 0x5 0x001 0x0 @EncounterText2 @DefeatText2
msgbox @AfterBattle 0x6
end

#org @EncounterText1
= I challenge you!

#org @DefeatText1
= You beat me[.]

#org @PokenavMsg
= Do you have a PokéNav?

#org @EncounterText2
= I challenge you again!

#org @DefeatText2
= You beat me again[.]

#org @AfterBattle
= I'll say this after you've\nbattled me.
Again, we're focusing mainly on the battle stuff, so don't worry too much about what the specials are there for. Notice that we've used trainerbattle 0x2 for the first part, which otherwise looks like a standard battle script; only we've got @NavPointer at the end to allow this trainer to be registered in the player's PokéNav. Our @RematchPointer looks the same as a standard trainer battle, only with 0x5 as the battle type instead of 0x0.

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

trainerbattle 0x6 [EM]

Do you remember how trainerbattle 0x1, commonly used for Gym Leaders, allowed you to go to an extra pointer after the defeat text("You beat me..."), but before the default final message("I'll say this after you've battled me")? Trainerbattle 0x6 also allows for this in double battles. In EM it's used often with Gabby&Ty. It has no known use in FireRed.
Avara said:
#org @start
trainerbattle 0x6 0x001 0x0 @EncounterText @DefeatText @OnlyOnePoke @ExtraPointer
msgbox @AfterBattle 0x6
release
end

#org @EncounterText
= We challenge you!

#org @DefeatText
= You beat us[.]

#org @AfterBattle
= We'll say this after you've\nbattled us.

#org @OnlyOnePoke
= You can't double battle with only\none Pokémon!

#org @ExtraPointer
...
Seems familiar by now, right? At least, I hope it does =P

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

trainerbattle 0x7 [FR] [EM]

This type of trainerbattle has different uses in either ROM.
[FR] In FR 0x7 tied to the VS Seeker, this time for double battle rematches! It's used in conjunction with trainerbattle 0x4, like this:
Avara said:
#org @start
trainerbattle 0x4 0x001 0x0 @EncounterText1 @DefeatText @OnlyOnePoke
special2 LASTRESULT 0x39
compare LASTRESULT 0x1
if 0x1 goto @RematchPointer
msgbox @AfterBattle 0x6
end

#org @RematchPointer
trainerbattle 0x7 0x001 0x0 @EncounterText2 @DefeatText @OnlyOnePoke
msgbox @AfterBattle 0x6
end

#org @EncounterText1
= We challenge you!

#org @EncounterText2
= We challenge you again!

#org @DefeatText
= You beat us[.]

#org @AfterBattle
= We'll say this after you've\nbattled us.

#org @OnlyOnePoke
= You can't double battle with only\none Pokémon!
It's similar to the single VS Seeker battle script, only it has the built-in check to ensure the player can't take part in the double battle with a single Pokémon.

[EM] In Emerald, trainerbattle 0x7 is used with 0x4 and 0x8 for double battle rematches through Match Call.

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

trainerbattle 0x8 [EM]

The only instance I can think of for trainerbattle 0x8 is Tate & Liza's Gym - seeing as all the Gym Leaders have double battle rematches in EM, it's used with 0x7. So, it's like a double Gym battle followed by a double battle rematch.
Avara said:
#org @start
trainerbattle 0x8 0x001 0x0 @EncounterText1 @DefeatText @OnlyOnePoke @ExtraPointer
special2 LASTRESULT 0x3C
compare LASTRESULT 0x1
if 0x1 goto @RematchPointer
msgbox @AfterBattle 0x6
release
end

#org @ExtraPointer
fanfare 0x171
preparemsg @ReceivedBadgemsg
waitmsg
waitfanfare
...
release
end

#org @RematchPointer
trainerbattle 0x7 0x001 0x0 @EncounterText2 @DefeatText @OnlyOnePoke
msgbox @AfterBattle 0x6
end

#org @EncounterText1
= We challenge you!

#org @EncounterText2
= We challenge you again!

#org @DefeatText
= You beat us[.]

#org @AfterBattle
= We'll say this after you've\nbattled us.

#org @OnlyOnePoke
= You can't double battle with only\none Pokémon!

#org @ReceivedBadgemsg
= [player] received the X Badge\nfrom the Gym Leaders.

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

trainerbattle 0x9 [FR]

Not used in Emerald, trainerbattle 0x9 is a FR-exclusive that's used for your first rival battle in Oak's Lab. Let's have a look:
Avara said:
...
trainerbattle 0x9 0x001 0x0 @DefeatText @WinText
...

#org @DefeatText
= You beat me[.]

#org @WinText
= I'm the best!
It's quite similar to trainerbattle 0x3 in that you can safely have whatever you want before and after it. @DefeatText will display if the opponent loses as usual, but @WinText will display if the opponent wins against the player. Why have I got a special 0x0 after the battle? That special silently heals the player's Pokémon, so that it's safe for them to go on if they lose.
Not only does it let you display different end-of-battle text depending on whether or not the player loses, it also displays Professor Oak's tutorial-text during the battle.
What if you want to remove Oak's commentary? It's extremely easy - open your FireRed ROM in a hex editor, such as HxD, and navigate to 080484. Fill the next 8 bytes with 0s like so:
rCUd3a5.png

Hit save and test. Bye, Oak!

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

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

What is the difference between special and special2? The latter can return a value to be stored in a variable.
We're going to focus on the former for now! So, what is the special command used for? It's used to perform a particular function in-game. For demonstration purposes, I'm going to activate Emerald's National Pokédex.
Avara said:
#org @main
lock
faceplayer
special 0x1F3
msgbox @msg 0x6
release
end

#org @msg
= Your Pokédex was updated!
A short list of specials can be found in the spoiler below:

Spoiler:
Further information on special and special2 commands for FireRed can be found here and Emerald hackers will want to check out this post.

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

 
Last edited:
45
Posts
6
Years
  • Age 114
  • Seen today
any advice for making things appear after a specific badge is obtained? ex: i want a legendary encounter/new area to appear in viridian forest only after the 5th badge is obtained, but i have no idea how to script that
 

DJTiki

top 3 most uninteresting microcelebrities
1,257
Posts
10
Years
This is actually quite nice. I think it was about time that we had another comprehensive tutorial on XSE. The old threads are fine, but a little bit of cleaner organization can work wonders for a project. I definitely see myself and many ROM Hackers frequenting this thread like diego's because of how convienent it is. Good work as always, Avara.
 
242
Posts
6
Years
  • Age 30
  • Seen Apr 3, 2023
any advice for making things appear after a specific badge is obtained? ex: i want a legendary encounter/new area to appear in viridian forest only after the 5th badge is obtained, but i have no idea how to script that

Easy. Set a flag in the script that gives you the 5th badge. Then have an NPC block access to the area, and in the NPC script have it check if the flag that was set when you got the 5th badge is active or not.
 
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
Manipulating NPC Behaviour

Using movesprite2 allows you to have NPCs or other map objects placed at different co-ordinates on a map depending on a condition, like a flag or variable.
Avara said:
movesprite2 0x[Map Object ID] 0x[X Co-ordinate] 0x[Y Co-ordinate]
For example, we're going to make Prof. Birch stand outside Oldale Town's Mart when a variable is at 0, then have him stand outside the house next to the Mart when the variable has a value of 1.
Avara said:
#org @start
compare 0x405A 0x0
if 0x1 call @Position0
compare 0x405A 0x1
if 0x1 call @Position1
end

#org @Position0
movesprite2 0x1 0xF 0x7
return

#org @Position1
movesprite2 0x1 0x8 0x7
return
0xF and 0x7 are the co-ordinates on the map - in Oldale Town, it's the red square below. 0x8 and 0x7 is approximately where the orange square is.
LlJDbRi.png

0x405A is the variable we're using. 0x1 is our Birch OW's map object ID/"Person Event Number". The script needs to be added to the map header under "type 3":

7jH2bhU.png


To test it properly, you're going to need to set your var to 1 elsewhere, and then exit and re-enter the map to check that it's working. I just used the short example script in the spoiler below on another NPC for testing purposes.

Spoiler:

Now, let's try it out...

dqrPqLw.gif


There we go! Now we know how to change the positions of NPCs, how about changing what they are actually doing? Walking around or facing a certain direction? You can do this with the spritebehave command:
Avara said:
spritebehave 0x[Map Object ID] 0x[Behaviour Type]
The spoiler below contains a list of the "behaviour types". AdvanceMap has labelled a lot of these incorrectly, but Spherical Ice has given them more fitting names! For a more in-depth explanation on behaviour types in FR, check out his guide
here, where this list is from.

Spoiler:


Let's revisit our script from before, Prof. Birch in Oldale Town. When our variable was 0 he stood outside the Mart and when it was 1 he stood outside the neighbouring house. We're going to have him face up towards the Mart while he's there, and when he's outside the house we want him to walk up and down.
Avara said:
#org @start
compare 0x405A 0x0
if 0x1 call @Behaviour0
compare 0x405A 0x1
if 0x1 call @Behaviour1
end

#org @Behaviour0
movesprite2 0x1 0xF 0x7
spritebehave 0x1 0x7
return

#org @Behaviour1
movesprite2 0x1 0x8 0x7
spritebehave 0x1 0x3
return

lICtVRH.gif


The combination of movesprite2 and spritebehave can be used for way more interesting possibilities than what Game Freak used it for - get creative! : )

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
~reposting since the old one got lost in the server change
Money, Marts & Coins
To check if your player has a certain amount of money, we use the checkmoney command like so:
Code:
checkmoney 0x[Amount In Hex] 0x0
compare LASTRESULT 0x1
if [More/Less/EqualTo] goto @pointer
For the [More/Less/EqualTo] part, remember this from the item section?
Avara said:
0x0 = Lower Than
0x1 = Equal To
0x2 = Greater Than
0x3 = Lower Than or Equal To
0x4 = Greater Than or Equal To
These apply here too - meaning if the player has what we want them to have, we goto @pointer. What if we wanted to check if a player has less than the amount specified? Here's a fuller example:
Avara said:
#org @start
lock
faceplayer
checkmoney 0x2710 0x0
compare LASTRESULT 0x1
if 0x0 goto @HasCorrectAmount
msgbox @IncorrectAmountMsg 0x6
release
end

#org @HasCorrectAmount
msgbox @HasCorrectAmountMsg 0x6
release
end

#org @HasCorrectAmountMsg
= Oh, you don't have very much\nmoney.

#org @IncorrectAmountMsg
= Wow, you have lots of money!
Let's pretend this is a script for an obnoxious rich kid NPC. If the player has more than or exactly $10,000 (0x2710), our rich kid will mention that the player has lots of money. If the player has less than that (if 0x0, our rich kid will make a snarky comment about their perceived lack of money =P

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

To give your player a certain amount of money, the givemoney command is extremely straightforward.
Code:
givemoney 0x[Amount In Hex] 0x0
Let's give our player $10,000 so he can be as well off as Obnoxious Rich Kid from earlier:
Code:
givemoney 0x2710 0x0
Okay, now your player is now pretty comfortable financially. Let's take it all away from them again using paymoney, which is set up just the same.
Code:
paymoney 0x[Amount In Hex] 0x0
As you can probably guess, this makes the player pay up the specified amount. Before you use this command in a script, I recommend you actually check if the player has the desired amount that you want to be taken from them in the first place.
Avara said:
#org @main
lock
faceplayer
checkmoney 0x2710 0x0
compare LASTRESULT 0x1
if 0x4 goto @MoneyCanBeTaken
[...]

#org @MoneyCanBeTaken
paymoney 0x2710 0x0
[...]
-----------------------------------------------------------------------------------------------------------------------------------------------------
Pokémarts, as we know, show the player's amount of money then update it when an item is purchased and money is taken, complete with a sound effect. What if we wanted to replicate that, minus the list of buyable items? I'll start by explaining how to show the player's money:
Code:
showmoney 0x[X-Co-ord] 0x[Y-Co-ord] 0x0
The X and Y co-ordinates pertain to the position of the box on the screen. Hiding the money box is also just a single line:
Code:
hidemoney 0x[X-Co-ord] 0x[Y-Co-ord]
The following is a script for a NPC who sells... eh, Heart Scales or something. Just so you can see how to use all the commands combined together:
Code:
#org @main
lock
faceplayer
showmoney 0x0 0x0 0x0
msgbox @OfferMsg 0x5
compare 0x800D 0x1
if 0x1 goto @AcceptedOffer
msgbox @DeclinedMsg 0x6
hidemoney 0x0 0x0
release
end

#org @AcceptedOffer
checkmoney 0x1F4 0x0
compare LASTRESULT 0x1
if 0x4 goto @Transaction
msgbox @IncorrectAmountMsg 0x6
hidemoney 0x0 0x0
release
end

#org @NoRoom
msgbox @NoRoomMsg 0x6
hidemoney 0x0 0x0
release
end

#org @Transaction
checkitemroom 0x6F 0x1
compare LASTRESULT 0x0
if 0x1 goto @NoRoom
paymoney 0x1F4 0x0
sound 0x58
updatemoney 0x0 0x0 0x0
msgbox @TransactionMsg 0x6
additem 0x6F 0x1
hidemoney 0x0 0x0
release
end

#org @OfferMsg
= Hi! Would you like to buy a Heart\nScale for [$]500?

#org @IncorrectAmountMsg
= Oh, you can't afford one.

#org @DeclinedMsg
= Not interested?

#org @NoRoomMsg
= You don't have room for it.

#org @TransactionMsg
= Thank you!\nPlease come again!
EGw7e32.gif
First, we display their money in the top left-hand corner of the screen and ask the player whether or not they'd like to buy an incredibly useful Heart Scale. If the player decines this incredible offer the money display box closes, our script ends and they are free to go. If the player says "Yes", the script will goto @AcceptedOffer then check if they have $500 (0x1F4). If they can't afford it, the script will also close everything and end. Having the required amount of $$$ takes us to @Transaction, where as long as the player has enough space for the item in their bag, we can go ahead with the exchange - if their bag is full the script will close. sound 0x58 plays a mart transaction noise as the player's money updates. We use additem as opposed to giveitem here, as it adds the item to the player's bag silently.

-----------------------------------------------------------------------------------------------------------------------------------------------------
Coins

Coins are used mainly in the Game Corner of the canon games, but since we're ROM hacking, you could use them for anything. Coin commands are very similar to the ones for money, so they don't require too much explanation, hopefully! To show, update and hide the box which shows the player's coins:
Code:
showcoins 0x[X-Co-ord] 0x[Y-Co-ord]
Code:
updatecoins 0x[X-Co-ord] 0x[Y-Co-ord]
Code:
hidecoins 0x[X-Co-ord] 0x[Y-Co-ord]
If you want to add coins to the player's Coin Case, you only need one short line.
Code:
givecoins 0x[Amount In Hex]
Practically the same for taking coins away, just a different command name:
Code:
removecoins 0x[Amount In Hex]

-----------------------------------------------------------------------------------------------------------------------------------------------------
Pokémarts

So, we now know how to check, give and take amounts of money, plus coins. Since we referred to Marts earlier, why don't we cover those to tie up the money stuff?
Code:
#dynamic 0x800000

#org @main
lock
faceplayer
preparemsg @MartGreetingMsg
waitmsg
pokemart @MartItemsList
msgbox @MartLeavingMsg 0x6
release
end

#org @MartGreetingMsg
= Welcome!\pHow may I help you?

#org @MartLeavingMsg
= Please come again!

#org @MartItemsList
#raw word 0x4
#raw word 0xD
#raw word 0xE
#raw word 0x12
#raw word 0x11
#raw word 0x0
If you've made it this far and read the previous material I shouldn't have too much to explain here. The "raw word" corresponds to numerical item IDs you can look up here. For example, "raw word 0xD" means the Mart will sell Potions.

 
Last edited:
1,309
Posts
12
Years
  • Age 31
  • Seen Nov 24, 2023
sethealingplace
You'll notice that all Pokémon Centers host a level script containing something along these lines:

mqwwTV1.png

What does this do? On entering the building, this script runs to make sure the player respawns at the last-visited Pokémon Center on white-out.

sethealingplace IDs: [FR]
Spoiler:

sethealingplace IDs: [EM]
Spoiler:

 
Back
Top