Shaychu Forums
Click the "Register" button or go here: http://www.shaychu.com/register to become a member! There will be a Chatbox for all registered users at the bottom of the forum home page and the portal. The ads go away when you log in!
Cirrus' Ridiculously-Long XSE Scripting Tutorial (Not Finished ATM o.o) Offshaychusmall
Shaychu Forums
Click the "Register" button or go here: http://www.shaychu.com/register to become a member! There will be a Chatbox for all registered users at the bottom of the forum home page and the portal. The ads go away when you log in!
Cirrus' Ridiculously-Long XSE Scripting Tutorial (Not Finished ATM o.o) Offshaychusmall

Cirrus' Ridiculously-Long XSE Scripting Tutorial (Not Finished ATM o.o)

View previous topic View next topic Go down

Cirrus' Ridiculously-Long XSE Scripting Tutorial (Not Finished ATM o.o) Empty Cirrus' Ridiculously-Long XSE Scripting Tutorial (Not Finished ATM o.o)

Post by Cirrus Thu Dec 03, 2009 3:18 pm

Hello, Shaychuians. Have you ever wanted to completely customize a Pokemon game? Make people say whatever you want, walk around, give you any Pokemon/item you want, or even create your own trainers with your own choice of Pokemon? Your computer g33k friend Cirrus will be teaching you how to do this, and moar if he feels like it.

This article will cover how to write a script to your Pokemon ROM. ROM links are illegal, so you'll have to find one yourself. But I will give you links to the tools that you'll need to start your Pokemon-hacking hobby:

Advance Trainer - This tool will allow you to customize any trainer in your Pokemon game, including which trainer they are, the music that plays, their Pokemon, the Pokemon's held item, as well as the trainers' name.

XSE - The best scripting tool out there IMO. This will be one of your most-used tools if you plan to script. There are older scripting programs such as scriptEd and Pokescript that can be used as well, but the computer language that is used for it is somewhat different than XSE, and they are outdated, so I wouldn't normally recommend them. Writing the scripts to your ROM using these programs takes longer, and also requires that you make multiple files.

Free Space Finder - I believe this comes with XSE when you download it, but if it doesn't here it is. This is mainly used for finding free space to write scripts to in XSE, and as such, it'd be a great idea to integrate it with XSE through the drop-down menu that can automatically open up FSF. How to do this will be covered later in the article.

unLZ - A bit buggy and somewhat complex, but this tool is the most popular of its kind. This tool allows you to change the graphics of any picture in your Pokemon game. Sounds simple, doesn't it? Well, this program deserves its own tutorial, so using this will be covered later on.

AdvanceMap v1.92 - A must-have for any kind of ROM hacker. This tool is very easy to use, and allows you to completely customize any map in the game, as well as change the position and sprite type of any person in the game. It is also needed in scripting to appoint scripts to the game, and to people. Many other easy-to-use tools come with this, including PET (another trainer editor) and PokeCryGUI.

APE (Advanced Palette Editor) - A tool that allows you to change or swap color palettes in your ROM. More details on it will be included in future articles.

Lunar IPS (LIPS) - A very useful tool that makes patches from your ROMs so that you can apply said patch to a clean Pokemon ROM, and convert it into your customized game. Think of it as a 'change saver' that you can patch onto an unmodified ROM to give it the changes.

Elite Map - A more advanced program that does what AdvanceMap does, and more. I'm not very familiar with this program, as I mainly use AdvanceMap. But if you want to get more complex with your ROM-hacking, EliteMap is an option.

Advance Mart - A very user-friendly tool that allows you to edit Pokemart items.

Advance Starter - Allows you to change the starter Pokemon in the game.

Before we do any scripting, we'll make our lives easier, and integrate FSF with XSE. It is much easier than it sounds. All you need to do is put FSF in the same folder as XSE. That's all there is to it, but it will help you out a lot in the future.


Alright, on to scripting. You will need XSE above, AdvanceMap, Free Space Finder, and a Firered, Leafgreen, Ruby, Sapphire or Emerald ROM. First, open up XSE. On the File tab, select 'Open', and choose your ROM.

MESSAGE scriptS


I'll start off with the most basic of scripts - we're gonna make someone in the game say something. It can be whatever we want.

Code:

#dynamic 0x800000

#org @message
lock
faceplayer
msgbox @message 0x6
release
end

#org @message
=OMG. I love Cirrus SOOO\nmuch for making this guide!!

I'll explain this from the top down.
#dynamic 0x800000 at the top is the offset that the game will use to write the script to the ROM. To use any kind of information, the ROM needs to know where the info is, and this offset tells it this. To find free space in your ROM, go to the Tools dropdown menu in XSE, and select 'Free Space Finder' (you DID integrate it with XSE, didn't you? o.O). When FSF comes up, it'll look like this:

Cirrus' Ridiculously-Long XSE Scripting Tutorial (Not Finished ATM o.o) M79mjs

Click on 'Search'. Assuming you opened that ROM, it will give you an offset number that you can use for the script. Select 'Copy', and X out of FSF. Then paste this offset number after the '0x' in #dynamic. KEEP NOTE OF THIS NUMBER. You will need it after you write the script to the ROM!

Back to the script, #org @message is the pointer that will be used for the script, and declares the start of the script. 'Message' can be anything you want, as long as it doesn't start with a number! @main, @script, @start, @iliekmudkipzlulz, anything you like.

lock prevents your character from moving when the script is being executed, as you may have noticed if you played a Pokemon game.

faceplayer turns the sprite you're talking to to you while the script is being executed.

msgbox is the XSE command to show a message box at the bottom of the screen. It is preceded with the pointer that contains the text to be shown in this box.

0x6 is the 'normal' box number. There are 5 different types.

0x2
Spoiler:

0x3
Spoiler:

0x4
Spoiler:

0x5
Spoiler:

0x6
Spoiler:

release at the end of the script instructs the game to cancel out the lock effect that was defined earlier, and end, of course, ends the script.

As with most programming languages, variables are declared after the initial program processes. In this script, @message was declared during the msgbox command that we used earlier. "#org @message" is where the defined text is stored for the @message variable. It is preceded on the next line by an = sign, followed by the message you wish to display.

In messaging, there are 6 commands for line positioning.

\c is used for coloring text.

\h is used to define hex values, particularly used for special characters in the game.

Me wrote:I have \hB7200! Razz

Shows as "I have $200! Razz" in the game, as hex B7 in the game is the currency symbol.

A complete list of all the hexes for each special symbol:

Spoiler:

\n is used to indent onto a new line.

[quote=Me]Hello.\nI'm Cirrus.[/quote]

Shows up as:

[quote=Me]Hello.
I'm Cirrus.[/quote]

\l indents the text to a new line, but it can only be used after \n is used.

[quote="Me]Hello.\nI am Cirrus.\nYour creator.\nYour teacher.[/quote]

Would show up as:

Me wrote:Hello.
I am Cirrus.
Your creator. <----You would be pressing A at this point.
Your teacher.

\p can be used to continue the message in a new box.

\v is used to display stored text. For example:

Code:
\v\h01! Come here!

Would display as:

Me wrote:(player's name)! Come here!



FLAGS


Flags are very useful tools. They are in-game "on and off switches" that can control whether an event should happen only once. They can also be used to make a sprite disappear after an event.
They are declared in hexadecimal, and have a value of either 0x0 or 0x1.

There are two commands for the flag statement.

setflag, as you may predict, sets a flag, or "turns on the switch". Once set, there is no way to uncheck it in a save file of the game.

checkflag checks to see what the value of the flag is, whether it be on or off.

Here's an example script:

Code:
#dynamic 0x800000

#org @main
lock
faceplayer
checkflag 0x200
if 0x1 goto @done
msgbox @message1 0x6
setflag 0x200
release
end

#org @done
msgbox @message2 0x6
release
end

#org @message1
= Hello, my name is\nPeter Griffin!

#org @message2
= Haven't we talked before?

In this script, the game will check the flag at 0x200, and if the flag has been set (it will have a value of 0x1), it will go to the pointer '@done', and continue the script from there. If the flag is not set (therefore, would have a value of 0x0), it will continue as normal with the script, moving on to 'msgbox @message1 0x6'.

Because we want the event to only happen once, we put 'setflag 0x200' after the initial script is done executing. Of course, since the script is using the same flag to determine what to do, we are using one flag for the entire script, 0x200.

Here is a list of flags that are already used in the game, and that may interfere with other game aliments if you use them in a custom script:

Spoiler:

Additionally, here are a few useful flags that are already in the game:

Firered
Spoiler:

Ruby & Sapphire
Spoiler:

GIVE POKEMON


Code:

#dynamic 0x800000

1   #org @main
2   checkflag 0x200
3   if 0x1 goto @done
4   msgbox @1 0x5
5   compare LASTRESULT 0x1
6   if 0x1 goto @get
7   msgbox @2 0x6
8   release
9   end

10   #org @get
11   givepokemon 1 0x5 0 0x0 0x0 0x0
12   fanfare 0x13E
13   msgbox @receivedmsg 0x4
14   waitfanfare
15   closeonkeypress
16   setflag 0x200
17   msgbox @nickname 0x5
18   compare LASTRESULT 0x1
19   if 0x1 gosub @name
20   msgbox @5 0x6
21   release
22   end

23   #org @name
24   call 0x1A74EB
25   return

26   #org @done
27   msgbox @6 0x6
28   release
29   end

30   #org @1
31   = Hey, kid. You want\pthis POKEMON?

32   #org @2
33   = Fine.\pSee ya around.

34   #org @receivedmsg
35   = [black_fr]You received a BULBASAUR!

36   #org @nickname
37   = [black_fr]Would you like to give a\nnickname to BULBASAUR?

38   #org @5
39   = Take care of that\nBULBASAUR, kid.

40   #org @6
41   = How's that BULBASAUR doing?

Alright, starting from the top again.

We already covered checkflag and setflag, but I'd like to stress again that the same 2 flags should be used in the script. Notice how checkflag on line 2 and setflag on line 16 are both set to 0x200?

Anyhoo, look at line 3 and 4. In XSE, as well as almost any programming language, we have the if statement. On line 2, the game checks the flag number 0x200, and if it not set to 0x1, it will continue
on with the script, and execute msgbox @1 on line 4.

On line 5, we have compare LASTRESULT 0x1. This command is almost always preceded after an 0x5 boxset, which is what we defined in line 4. Remember how I said that 0x5 is used for Yes and No statements? Well, if you select Yes from that box, it will write 0x1 to the variable LASTRESULT, which is a stored variable in the game. If you answer No, it will do nothing, and continue with the script from there.

On line 11, we have the meat of this entire command, the givepokemon command.

Code:
givepokemon 1 (The Pokemon you want, in this case Bulbasaur) 0x5 (level) 0 (hold item) 0x0 0x0 0x0 (buffers)

List of Pokemon numbers:

Spoiler:

List of items:

Spoiler:

You could also convert these values to hex, and prefix it with 0x to acheive the same effect, but I find it simpler to just use the decimal representation. It is automatically converted to hex after you compile it, anyway.

On line 12, we have fanfare 0x13E. This is the little jingle that plays when someone gives you a Pokemon. Bear in mind that the script is read quite fast by the game, so the jingle will play at approximately the same time as msgbox @receivedmsg 0x4.

waitfanfare on line 14 is very important. It waits until the jingle is finished before the script proceeds. If we didn't include this, the nicknaming dialogue would come up if the player were to hit A during the fanfare, which is not too pro.

closeonkeypress makes it so that the only way to continue with the script is if the player presses A or B after the fanfare is done.

On line 16, we have the setflag command, as I described earlier. Theoretically, you can put the setflag command in several places in this script, but for orderly purposes, I like to put it after the main event would be completed. It could be put on, say, lines 17-20, or line 25.

Line 24 reads call 0x1A74EB. The call command makes the game go to a certain offset number in the game. In this case, it is going to the script with the name 1A74EB. Just like how this script would be written to 0x800000, the script at 1A74EB also has a function. As you may be able to find out, it's the nicknaming dialogue screen.

gosub at line 19 basically tells the game "go there, but come back". A VERY important point is that when you declare gosub, you must always declare return in the pointer that you're telling it to go to. Because the game is going to the pointer @name, we must declare return after the function.

It is good programming practice in any programming languages to order your functions, and in the case of XSE, your pointers. I put all my pointers after the main programming function at the top, and in the order in which they appear. It's a good thing to get into this habit, as it will make your script more orderly, and easier to debug. The script will compile just fine if you were to, say, put the function @nickname on line 36 before the function @1 on line 30, but it's usually best to order them.


WILD BATTLE


Code:
1   #dynamic 0x800000

2   #org @start
3   lock
4   faceplayer
5   msgbox @1 0x6
6   cry 0x9 0x0
7   wildbattle 0x9 0x1E 0x8B
8   fadescreen 0x1
9   fadescreen 0x0
10   hidesprite 0x800F
11   setflag 0x200
12   release
13   end

14   #org @1
15   = BLASTOISE: BLAAAAAAA!!!!

Once again, I'll start from the top, and descend.

As usual, we have the #dynamic command on the first line that declares which offset we will use for the script, as well as #org @start, lock and faceplayer.

As a refresher, msgbox @1 0x6 on line 5 displays a dialogue box with a type-6 box (0x6, it's just converted to hex), which is a 'normal' message box. What is contained inside that dialogue box is determined in the pointer @1. As said before, you can substitute anything you like for the 1 in that pointer, as long as the pointer on line 14 has the same name as it. Otherwise, it will not work.

Line 6 contains the cry command. As you may be able to guess, it plays the Pokemon's cry almost simultaneously when the dialogue box is opened.

Code:
cry 0x9 (Pokemon hex number you want the cry to be) 0x0 (effect number of the cry, but I'm not completely sure on how this works. 0x0 works just fine in this case.)

On line 7, we have the wildbattle command.

Code:
wildbattle 0x9 (hex number of Blastoise) 0x1E (hex of the encounter level, in this case, 30) 0x8B (hex value of hold item, in this case, Oran Berry)

On line 8 and 9, we have fadescreen, which fades the screen from white to black, or from black to white. There are 4 specific commands for it.

Spoiler:

The hidesprite command is very useful, as it will make the overworld sprite of the Pokemon disappear after the battle, thus having the script run only once. It should be noted that hidesprite should always precede the setflag command. Otherwise, the sprite will only disappear when you talk to the sprite, and will reappear if you move!

But why 0x800F? Well, in the game, when we interact with a sprite, the person number (found in AdvanceMap) is assigned to the game variable named 0x800F. In this command, we are basically saying "hide the sprite that I am currently talking with.". hidesprite can also be used for specific person numbers on the map, but I will cover this later on.

But why no checkflag command in this script? Well, since we have the hidesprite command, it isn't really needed. What we DO need to do, however, is set the flag number to the Person ID number in AdvanceMap.

Cirrus' Ridiculously-Long XSE Scripting Tutorial (Not Finished ATM o.o) Blasto11

Because we have setflag 0x200 in our script, that Person ID MUST be 0200 for the Pokemon to disappear when it is supposed to disappear. Of course, you can choose another flag number, as long as it is the same flag number that is in the Person ID value. Now because we use hidesprite 0x800F BEFORE we set the flag 0x200, the sprite will not reappear because its status has already been recorded into the setflag command. Therefore, checkflag is not needed for this script.

GIVEITEM

Code:


1   #dynamic 0x800000
2   
3   #org @main
4   lock
5   faceplayer
6   checkflag 0x200
7   if 0x1 goto @done
8   msgbox @1 0x5
9   compare 0x800D 0x1
10   if 0x1 goto @take
11   msgbox @2 0x6
12   release
13   end
14   
15   #org @done
16   msgbox @3 0x6
17   release
18   end
19   
20   #org @take
21   giveitem 0xD 0x1 MSG_OBTAIN
22   msgbox @3 0x6
23   setflag 0x200
24   release
25   end
26
27   #org @1
28   = Hey, kid! You want this?
29
30   #org @2
31   = Fine. I'll give it to\nsome other person.
32
33   #org @3
34   = I don't have anymore.\nGo buy them if you want more.

I think I covered pretty much everything here except for the actual giveitem command. The syntax for it is:

Code:
giveitem 0xD (item hex) 0x1 (amount to give) MSG_OBTAIN (message type)

For the message type, you can use either MSG_OBTAIN or MSG_FIND.

APPLYMOVEMENT


Code:

1   #dynamic 0x800000
2   
3   #org @start
4   checkflag 0x200
5   if 0x1 goto @done
6   msgbox @message 0x6
7   applymovement 2 @movements
8   waitmovement 0x0
9   pause 0x30
10   applymovement 0xFF @follow
11   waitmovement 0x0
12   msgbox @message2 0x6
13   setflag 0x200
14   release
15   end
16   
17   #org @done
18   release
19   end
20   
21   #org @message
22   = /v/h01, follow me!
23   
24   #org @movements
25   #raw 0x12 0x12 0x12 0x12 0x03 0xFE
26   
27   #org @follow
28   #raw 0x12 0x12 0x12 0xFE
29   
30   #org @message
31   = Great! You can walk!

We have a few new commands here, including waitmovement 0x0, #raw and of course, applymovement.

The syntax for applymovement is:

Code:
applymovement 2 (the number of the person's sprite in AdvanceMap) @movements (pointer leading to the movement commands)

This is where many beginners make mistakes. When you want somebody to move, you MUST ensure that the parameter for the person's sprite is the same as it is found in AdvanceMap. It can be found here:

Spoiler:

DO NOT confuse the top Person Event No. field with the one that is under 'Delete Event'. In the example I used above, the value for the circled Person Event No. field would have to be 2 for this script to work.

On lines 8 and 11, I used the command waitmovement 0x0. This tells the game to stop the script until the movements have finished executing. If we did not include it on line 11, the message that we declared on line 12 would be executed while the player was moving.

On line 9, we have pause 0x30. This will pause the script from executing for the amount of time that you define for the parameter where 0x30 is. To give you an idea of how long the pauses are, 0x30 is nearly equivalent to one second in real time. As I have said before, 0x30 is the hexadecimal representation. If you convert 0x30 from hexadecimal to regular decimal, you will get 48. This means that I could have used pause 48, and it would have given me the same effect as if I used 0x30.

Notice on line 7, I declared the pointer @movements for the applymovement command. This brings it to line 24 to execute the movements there. On line 25, we have the actual movements that are to be done. When you do this, you always have to start with #raw. This tells the game that you are using raw hexadecimal data for the data that you are to declare. After that, you include all of the movements that you want the person to make. Here's a complete list of them:

Ruby/Sapphire
Spoiler:

Firered/Leafgreen:

Spoiler:

You can declare as many of them as you like.

After you declare the movements, you MUST, MUST follow it with 0xFE. This terminates the movements declaration, and continues the script. Otherwise, your game will freeze.

On line 22, I used the \v\h01 command. As mentioned at the beginning of the tutorial, this will display your in-game name.

SPECIAL


Code:

1   #dynamic 0x800000
2   
3   #org @start
4   lock
5   faceplayer
6   msgbox @talk 0x4
7   closeonkeypress
8   fadescreen 0x1
9   fanfare 0x100
10   special 0x0
11   waitfanfare
12   fadescreen 0x0
13   msgbox @after 0x6
14   release
15   end
16
17   #org @talk
18   = Would you like me to/nheal your POKEMON?
19
20   #org @after
21   = Now they look better!\nGood luck on your journey!

We have a new command here, fadescreen 0x1 and fadescreen 0x0. As you might guess. it fades the screen from normal to black. It will remain black until we declare fadescreen 0x0.

Notice how I used 0x4 on line 6. We covered this before, and this is where such a command comes in handy. You never thought we'd have to use it, huh?

Anyhoo, because I declared 0x4, the message box will not close until we hit A or B. Why did I use 0x4 and closeonkeypress, rather than just 0x6?

If I were to do that, the dialogue box would remain open while the screen is black, which we don't want. The script would run, but showing the dialogue box during the black screen part would look quite unprofessional. When we use 0x4 and closeonkeypress, the dialogue box closes before fadescreen 0x1 is executed.

Here's a list of all the special commands:

Spoiler:



More coming later on.
Cirrus
Cirrus

Post Count : 1152
Age : 33
Shaycoins : 7056
Registration date : 2008-12-06

http://pokerealm.com

Back to top Go down

View previous topic View next topic Back to top

- Similar topics

Permissions in this forum:
You cannot reply to topics in this forum