PHO - Pokémon Hackers Online
Go Back   PHO - Pokémon Hackers Online > Hacking Suite > Resources and Tutorials > Generation 3 (Traditional)

Notices

Generation 3 (Traditional) Traditionally, Generation 3 is hacked using tools, hex editors and patches. This is for you if you do that.

User Tag List

Reply
 
Thread Tools Display Modes
Old 1st March 2018, 09:58 PM   #1
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Post XSE Scripting Tutorial

this is eventually gonna be a contents page promise x

Last edited by Alice; 2nd March 2018 at 10:34 PM.
Avara is offline   Reply With Quote
Likes The_Learner, Lunos liked this post
Sponsored Links
Old 1st March 2018, 09:58 PM   #2
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

Part #1: The Basics
-----------------------------------------------------------------------------------------------------------------------------------------------------

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.


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.

Quote:
Originally Posted by Avara View Post
#dynamic 0x800000

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:

Quote:
Originally Posted by Avara View Post
#dynamic 0x800000

#org @main

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:

Quote:
Originally Posted by Avara View Post
#dynamic 0x800000

#org @main
{your script contents}
end

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

Avara is offline   Reply With Quote
Likes Lunos liked this post
Old 1st March 2018, 10:00 PM   #3
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

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:



You should end up with a screen like this:



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:



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:




Last edited by Avara; 1st March 2018 at 10:07 PM.
Avara is offline   Reply With Quote
Likes Lunos liked this post
Old 1st March 2018, 10:02 PM   #4
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

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:
Quote:
Originally Posted by Avara View Post
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:



Spoiler:
#dynamic 0x800000

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

#org @greeting
= Hi!


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.



Spoiler:
#dynamic 0x800000

#org @main
msgbox @greeting 0x2
end

#org @greeting
= Hi!


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.
Quote:
Originally Posted by Avara View Post
#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.
Quote:
Originally Posted by Avara View Post
#dynamic 0x800000

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

#org @greeting
= Hi!

Last edited by Avara; 1st March 2018 at 10:07 PM.
Avara is offline   Reply With Quote
Likes Lunos liked this post
Old 1st March 2018, 10:05 PM   #5
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

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.


The \n allows the text to go to a new line when it gets too long. After the initial use of \n, \l is used for each new line after that. As an example:
Quote:
Originally Posted by Avara View Post
#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.
That text string, first with \n and then \l to break up the lines, will look like this:
Quote:
Originally Posted by Avara View Post
Hi!
My name is Adam.
What's your name? ...
... [player's name]?
-----------------------------------------------------------------------------------------------------------------------------------------------------
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:
Quote:
Originally Posted by Avara View Post
bufferfirstpokemon 0x[buffer number]
The [buffer number] part is where you choose the buffer number to assign the first Pokémon in your party's 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:
Quote:
Originally Posted by Avara View Post
#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:
Quote:
Originally Posted by Avara View Post
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.
Quote:
Originally Posted by Avara View Post
#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!" in FR, or EM "Your [first party member] is so cool, but my Sceptile is tougher!" (I assume).

The bufferitem and bufferattack commands are almost identical to bufferpokemon, set up like this:
Quote:
Originally Posted by Avara View Post
bufferitem 0x[buffer number] 0x[Item ID]
Quote:
Originally Posted by Avara View Post
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.
Quote:
Originally Posted by Avara View Post
#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.
Quote:
Originally Posted by Avara View Post
#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".
Quote:
Originally Posted by Avara View Post
#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.
Quote:
Originally Posted by Avara View Post
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.
Quote:
Originally Posted by Avara View Post
#dynamic 0x800000

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

#org @npctext
= My Charizard grew to level [buffer1]!
-----------------------------------------------------------------------------------------------------------------------------------------------------

Adding color to your text is a nice way of differentiating characters and making item or place names stand out.
Quote:
Originally Posted by Avara View Post
#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 Colors:
Spoiler:
White - [white_fr]
Black - [black_fr]
Gray - [grey_fr]
Red - [red_fr]
Orange - [orange_fr]
Green - [green_fr]
Light Green - [lightgreen_fr]
Blue - [blue_fr]
Light Blue - [lightblue_fr]
Light Blue 2 - [lightblue2_fr]
Cyan - [cyan_fr]
Light Blue 3 - [lightblue3_fr]
Navy Blue - [navyblue_fr]
Dark Navy Blue - [darknavyblue_fr]


Emerald Colors:
Spoiler:
White - [white_em]
Dark Gray - [darkgrey_em]
Gray - [grey_em]
Red - [red_em]
Orange - [orange_em]
Green - [green_em]
Light Green - [lightgreen_em]
Blue - [blue_em]
Light Blue - [lightblue_em]
White 4 - [white4_em]
Lime Green- [limegreen_em]
Aqua - [aqua_em]
Navy - [navy_em]



Last edited by Avara; 1st March 2018 at 10:08 PM.
Avara is offline   Reply With Quote
Likes Lunos liked this post
Old 1st March 2018, 10:15 PM   #6
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

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


Spoiler:
#dynamic 0x800000

#org @main
lock
faceplayer
msgbox @yesno 0x5
compare 0x800D 0x1
if 0x1 goto @YesOrg
msgbox @no 0x6
release
end

#org @YesOrg
msgbox @yes 0x6
release
end

#org @yesno
= Yes or no?

#org @yes
= You said yes.

#org @no
= You said no.

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.


Spoiler:
#dynamic 0x800000

#org @main
lock
faceplayer
msgbox @yesno 0x5
compare 0x800D 0x1
if 0x1 goto @YesOrg
goto @NoOrg

#org @NoOrg
msgbox @no 0x6
release
end

#org @YesOrg
msgbox @yes 0x6
release
end

#org @yesno
= Yes or no?

#org @yes
= You said yes.

#org @no
= You said no.

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

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:

Quote:
Originally Posted by Avara View Post
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:


Spoiler:
#dynamic 0x800000

#org @main
lock
faceplayer
random 0x03
compare 0x800D 0x0
if 0x1 goto @option1
compare 0x800D 0x1
if 0x1 goto @option2
compare 0x800D 0x2
if 0x1 goto @option3
end

#org @option1
msgbox @option1msg 0x6
release
end

#org @option2
msgbox @option2msg 0x6
release
end

#org @option3
msgbox @option3msg 0x6
release
end

#org @option1msg
= Message one text.

#org @option2msg
= Message two text.

#org @option3msg
= Message three text.

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

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.


The layout for the multichoice command is as follows:

Quote:
Originally Posted by Avara View Post
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:
preparemsg @pointer
waitmsg
multichoice 0xE 0x0 0x10 0x1
copyvar 0x8000 LASTRESULT
compare 0x8000 0x0
if 0x1 goto @yes
compare 0x8000 0x1
if 0x1 goto @no
compare 0x8000 0x2
if 0x1 goto @info
end

#org @yes
msgbox @yesmsg 0x6
release
end

#org @no
msgbox @nomsg 0x6
release
end

#org @info
msgbox @infomsg 0x6
release
end

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:

Quote:
Originally Posted by Avara View Post
#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:

Quote:
Originally Posted by Avara View Post
#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 =)

Avara is offline   Reply With Quote
Likes Lunos liked this post
Old 1st March 2018, 10:17 PM   #7
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

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:
Quote:
Originally Posted by Avara
setflag 0x[Flag Number]
Quote:
Originally Posted by Avara
clearflag 0x[Flag Number]


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

FireRed:
Spoiler:
0x820 – Activates First Badge
0x821 - Activates Second Badge
0x822 - Activates Third Badge
0x823 - Activates Fourth Badge
0x824 - Activates Fifth Badge
0x825 - Activates Sixth Badge
0x826 - Activates Seventh Badge
0x827 - Activates Eighth Badge
0x828 - Activates Pokémon Menu
0x829 - Activates Pokédex Menu
0x82F - Activates Running Shoes

Emerald:
Spoiler:
0x860 - Activates Pokémon Menu
0x861 - Activates Pokédex Menu
0x862 - Activates Pokénav Menu
0x867 - Activates First Badge
0x868 - Activates Second Badge
0x869 - Activates Third Badge
0x86A - Activates Fourth Badge
0x86B - Activates Fifth Badge
0x86C - Activates Sixth Badge
0x86D - Activates Seventh Badge
0x86E - Activates Eighth Badge
0x8C0 - Activates Running Shoes

-----------------------------------------------------------------------------------------------------------------------------------------------------
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.
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
subvar 0x[Variable Number] 0x[Value To Subtract From Var]
What if we want to copy the value of one variable into another?
Quote:
Originally Posted by Avara
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?
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
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.
Quote:
Originally Posted by Avara View Post
0x0 = Lower Than
0x1 = Equal To
0x2 = Greater Than
0x3 = Lower Than or Equal To
0x4 = Greater Than or Equal To
Avara is offline   Reply With Quote
Likes Lunos liked this post
Old 1st March 2018, 10:19 PM   #8
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

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!
Quote:
Originally Posted by Avara View Post
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:
Quote:
Originally Posted by Avara View Post
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.
Quote:
Originally Posted by Avara View Post
additem 0x[Item ID] 0x[Quantity]
This version is useful for if you want to add your own custom string, for example:
Quote:
Originally Posted by Avara View Post
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:
Quote:
Originally Posted by Avara View Post
checkitem 0x[Item ID] 0x[Quantity]
Let's see an example and check if the player has one Master Ball.
Quote:
Originally Posted by Avara View Post
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.
Quote:
Originally Posted by Avara View Post
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:
Quote:
Originally Posted by Avara View Post
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:
Quote:
Originally Posted by Avara View Post
removeitem ITEM_MASTERBALL 0x1
-----------------------------------------------------------------------------------------------------------------------------------------------------

Adding an item to the player's PC is just as easy with a single line:
Quote:
Originally Posted by Avara View Post
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.

Avara is offline   Reply With Quote
Old 1st March 2018, 10:21 PM   #9
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

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:
'---------------
#dynamic 0x800000

#org @start
lock
faceplayer
checkflag 0x240
if 0x1 goto @Done
msgbox @question 0x5
compare LASTRESULT 0x1
if 0x1 goto @Yes
msgbox @saidnomsg 0x6
release
end

#org @Yes
countpokemon
compare 0x800D 0x6
if 0x1 goto @Full
msgbox @take 0x6
givepokemon 0x1 0x5 0x0 0x0 0x0 0x0
fanfare 0x101
msgbox @receive 0x4
waitfanfare
closeonkeypress
msgbox @nick 0x5
compare LASTRESULT 0x1
if 0x1 call @YesToNick
msgbox @Donemsg 0x6
setflag 0x240
release
end

#org @YesToNick
setvar 0x8004 0x0
call 0x81A74EB
return

#org @Full
msgbox @Fullmsg 0x6
release
end

#org @Done
msgbox @Donemsg 0x6
release
end

#org @question
= Do you like grass-types?

#org @saidnomsg
= Too bad[.]

#org @Fullmsg
= Your party is full.

#org @Donemsg
= Bye!

#org @take
= You can have one of mine!

#org @receive
= [black_fr][player] received a Pokémon!

#org @nick
= [black_fr]Give it a nickname?


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:
Quote:
Originally Posted by Avara
'---------------
#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.
Quote:
Originally Posted by Avara
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!
Quote:
Originally Posted by Avara
#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.
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
givepokemon PKMN_BULBASAUR 0x5 0x0 0x0 0x0 0x0
The next part is music related which we'll cover in more detail later.
Quote:
Originally Posted by Avara
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.
Quote:
Originally Posted by Avara
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.
Quote:
Originally Posted by Avara
#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!
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
giveegg 0x[ID of Pokémon]
So, to give a Bulbasaur egg, we'd have giveegg 0x1.

Avara is offline   Reply With Quote
Old 1st March 2018, 10:24 PM   #10
Avara
Mirage Of Tales Creator
 
Join Date: Nov 2013
Posts: 33
Avara
Default

Sounds, Fanfares & Music

Since we're hacking a Pokémon game, let's start with the cry command:
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
...
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.
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
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:
Quote:
Originally Posted by Avara
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.

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

If you'd like to play music through your script, this is also nice and simple:
Quote:
Originally Posted by Avara
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.
Quote:
Originally Posted by Avara
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.
Quote:
Originally Posted by Avara View Post
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.

Avara is offline   Reply With Quote
Reply

Tags
scripting, tutorial, xse, [Document], [Tutorial]

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 08:44 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2018, vBulletin Solutions, Inc. User Alert System provided by Advanced User Tagging (Lite) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Feedback Buttons provided by Advanced Post Thanks / Like (Lite) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Pokémon characters and images belong to Pokémon USA, Inc. and Nintendo.
Pokémon Hackers Online (PHO) is in no way affiliated with or endorsed by Nintendo LLC, Creatures, GAMEFREAK inc,
The Pokémon Company, Pokémon USA, Inc., The Pokémon Company International, or Wizards of the Coast.
All forum/site content (unless noted otherwise) and site designs are © 2006-2013 Pokémon Hackers Online (PHO).
Green Charizard Christos TreeckoLv100

"Black 2" by ARTPOP. Kyurem artwork by XOUS.

no new posts