- 29
- Posts
- 10
- Years
- Seen Feb 3, 2020
I'm aware that there are two other Tutorials, but I don't think either of them really make things easy to understand for the reader. There is also information missing from both of them, so it's probably time for a new one.
TUTORIAL
The goal of this tutorial is that the reader learn a few things before diving head-first into scripting:
For this tutorial you will need:
Make a single directory where we'll have all of our files contained. Lets call this directory /My Pokemon Hack/.
Inside this folder, lets make a folder for our ROM Hack, PKSV and G2Map.
It should look something like:
/My Pokemon Hack/G2Map
/My Pokemon Hack/PKSV
/My Pokemon Hack/ROM Hack
Next, you should make your GBC Emulator the default program for .gbc files.
Right click on the rom and use the "Open With..." Dialog to point it to the Emulator's executable with "Always use this program to open files of this type" selected.
Finally, open G2Map, load a ROM, switch to Event Edit mode, and click on an event.
Click on "Launch Script Editor" and it will ask you for PKSV's location. Point it in the right direction and everything will be setup at this point in time.
- How Addresses(or offsets) and Pointers work, and what the difference is between the two.
- How to script without causing bugs.
- How to use the Scripting Compendium to script effectively.
- What resources are available to aid in scripting.
- How to find free space manually
For this tutorial you will need:
- A Pokemon Gold Rom as well as an Emulator to use it with.
- THIS version of G2Map(Skeetendo Demo).
- The Latest Version of PKSV.
- The Scripting Compendium
1. Set up your Workspace
First off, lets setup our enviornment.
Make a single directory where we'll have all of our files contained. Lets call this directory /My Pokemon Hack/.
Inside this folder, lets make a folder for our ROM Hack, PKSV and G2Map.
It should look something like:
/My Pokemon Hack/G2Map
/My Pokemon Hack/PKSV
/My Pokemon Hack/ROM Hack
Next, you should make your GBC Emulator the default program for .gbc files.
Right click on the rom and use the "Open With..." Dialog to point it to the Emulator's executable with "Always use this program to open files of this type" selected.
Finally, open G2Map, load a ROM, switch to Event Edit mode, and click on an event.
Click on "Launch Script Editor" and it will ask you for PKSV's location. Point it in the right direction and everything will be setup at this point in time.
2. Understanding Addresses and Pointers
You won't make it very far in scripting if you don't understand how the Addresses(offsets) and Pointers work together.
First, lets talk about Addresses.
Addresses are one-to-one with the ROM file.
Our ROM is 2MB in size, or 2,097,152 Bytes. The number 0x200000 in hexadecimal is equivalent to 2,097,152 in Decimal.
When computers count, they start at 0 and go up until they don't have space. So, rather than counting from 0x000001 to 0x200000 they'll count from 0x000000 to 0x1FFFFF.
All Addresses are always in Hexadecimal and range from 0x000000 to 0x1FFFFF.
I want to point out a few things:
While scripting in Pokemon Gold and Silver, you'll first load a bank between 0x00 and 0x7F into the Memory Bank Controller(MBC), then reference all memory in that bank as a pointer between 0x4000 and 0x7FFF(Remember what I said about counting? The first address is 0x4000 and the 0x4000th address is 0x7FFF).
Why? The first 0x4000 bytes of the Gameboy are allocated to the first 0x4000 bytes of the ROM's data, and may not be changed. The game runs from this area primarily.
Let me clarify something that would confuse you if you go into it knowing only that, typically scripts run within one memory bank. They use two byte pointers which reference memory within the current bank.
Commands of this type include '2call','2jump', '2writetext', and several others.
First, lets talk about Addresses.
Addresses are one-to-one with the ROM file.
Our ROM is 2MB in size, or 2,097,152 Bytes. The number 0x200000 in hexadecimal is equivalent to 2,097,152 in Decimal.
When computers count, they start at 0 and go up until they don't have space. So, rather than counting from 0x000001 to 0x200000 they'll count from 0x000000 to 0x1FFFFF.
All Addresses are always in Hexadecimal and range from 0x000000 to 0x1FFFFF.
I want to point out a few things:
Because of the limited memory of a Gameboy Color Catridge, only so much data can be accessed at one time from the ROM; 0x4000 Bytes to be exact.
- Each digit of a hexadecimal number is called a Nibble. It ranges from 0 to F(15), and two Nibbles make a Byte. I won't talk about Nibbles much during this tutorial, I just wanted to be sure that everyone knows what they're called in case they appear in other tutorials or guides.
- One Byte ranges from 0x00 to 0xFF.
- Addresses are 3 Bytes total. They appear commented in PKSV as ' $12ABC3 at the end of certain lines.
While scripting in Pokemon Gold and Silver, you'll first load a bank between 0x00 and 0x7F into the Memory Bank Controller(MBC), then reference all memory in that bank as a pointer between 0x4000 and 0x7FFF(Remember what I said about counting? The first address is 0x4000 and the 0x4000th address is 0x7FFF).
Why? The first 0x4000 bytes of the Gameboy are allocated to the first 0x4000 bytes of the ROM's data, and may not be changed. The game runs from this area primarily.
Let me clarify something that would confuse you if you go into it knowing only that, typically scripts run within one memory bank. They use two byte pointers which reference memory within the current bank.
Commands of this type include '2call','2jump', '2writetext', and several others.
3. The Scripting Compendium
Use this as a reference to learn what the exact bytes and parameters of the commands you use
or see are.
Here is the compendium's Quick Reference section:
The actual compendium will tell you about each function in detail.
or see are.
Here is the compendium's Quick Reference section:
Spoiler:
Short overview:
---------------
00 = Pointer code [2b+ret]
01 = Pointer code [3b+ret]
02 = Pointer code [2b+3b+ret]
03 = Pointer code [2b]
04 = Pointer code [3b]
05 = Pointer code [2b+3b]
06 = RAM check [=byte]
07 = RAM check [<>byte]
08 = RAM check [=0]
09 = RAM check [<>0]
0A = RAM check [<byte]
0B = RAM check [>byte]
0C = 0C codes [xxyy]
0D = 0D codes [xxyy]
0E = ASM code1 [3b]
0F = 0F codes [xxyy]
10 = ASM code2 [2b]
11 = Trigger event check1 [xxyy]
12 = Activate trigger event from afar [xxyyzz]
13 = Trigger event check
14 = De-/activate trigger event [xx]
15 = Load variable into RAM [xx]
16 = Add variables [xx]
17 = Random number [xx]
18 = Version check
19 = Copy variable code1 [xxyy]
1A = Copy variable code2 [xxyy]
1B = Load variable [xxyyzz]
1C = Check codes [xx]
1D = Input code1 [xx]
1E = Input code2 [xxyy]
1F = Give item code [xxyy]
20 = Take item code [xxyy]
21 = Check for item code [xx]
22 = Give money code [xxyyzzaa]
23 = Take money code [xxyyzzaa]
24 = Check for money code [xxyyzzaa]
25 = Give coins code [xxyy]
26 = Take coins code [xxyy]
27 = Check for coins code [xxyy]
28 = Give cell phone number [xx]
29 = Take cell phone number [xx]
2A = Check for cell phone number [xx]
2B = Check time of day [xx]
2C = Check for PKMN [xx]
2D = Give PKMN [xxyyzzaa(+2b +2b)]
2E = Give EGG [xxyy]
2F = Attach item code [2B]
30 = Check letter code [2b]
31 = BitTable1 check [xxyy]
32 = BitTable1 reset [xxyy]
33 = BitTable1 set [xxyy]
34 = BitTable2 check [xxyy]
35 = BitTable2 reset [xxyy]
36 = BitTable2 set [xxyy]
37 = Deactivate PKMN battles
38 = Activate PKMN battles
39 = X/Y comparison [xxyy]
3A = Warp modifier [xxyyzz]
3B = Blackout modifier [xxyy]
3C = Warp code [xxyyzzaa]
3D = Account code [xxyy]
3E = Coin case code [xx]
3F = Display RAM [xx]
40 = Display PokéMon name [xxyy]
41 = Display item name [xxyy]
42 = Display location name [xx]
43 = Display trainer name [xxyyzz]
44 = Display strings [2b + xx]
45 = Stow away item code
46 = Full item pocket code
47 = Text box&font code
48 = Refresh code [xx]
49 = Load moving sprites
4A = Load byte to C1CE [xx]
4B = Display text [3b]
4C = Display text [2b]
4D = Repeat text [xxyy]
4E = YES/No box
4F = Menu data code [2b]
50 = Write backup code
51 = Text1 code [2b]
52 = Text2 code [2b]
53 = Close text box code
54 = Keep text box open code
55 = Pokémon picture code [xx]
56 = Pokémon picture YES/NO code
57 = Menu interpreter 1
58 = Menu interpreter 2
59 = Load Pikachu data
5A = Delete FightRAM/reset person check
5B = Load trainer data1
5C = Load Pokémon data [xxyy]
5D = Load trainer data2 [xxyy]
5E = Start battle
5F = Return to In game engine after battle
60 = Learn how to catch PKMN [xx]
61 = Trainer text code
62 = Trainer status code [xx]
63 = Pointer Win/Loss [2b + 2b]
64 = Script talk-after
65 = Script talk-after-cancel
66 = Script talk-after-check
67 = Set talked-to person [xx]
68 = Moving code [xx + 2b]
69 = Moving code for talked-to person [2b]
6A = Talk-to facing code
6B = Facing of people code [xxyy]
6C = Variable sprites [xxyy]
6D = Hide person [xx]
6E = Show person [xx]
6F = Following code1 [xxyy]
70 = Stop following code
71 = Move person [xxyyzz]
72 = Write person location [xx]
73 = Load emoticons [xx]
74 = Display emoticon [xxyyzz]
75 = Change facing [xxyy]
76 = Following code2 [xxyy]
77 = Earth quake [xx]
78 = Exchange map [3b]
79 = Change block code [xxyyzz]
7A = Reload map code
7B = Reload map part code
7C = Write command queue
7D = Delete command queue
7E = Song code1 [xxyy]
7F = Song code2
80 = Music fade-out code [xxyy][zz]
81 = Play map music code
82 = Map reload music code
83 = Cry code [xx00]
84 = Sound code [xxyy]
85 = Key-down code
86 = Warp sound
87 = Special sound
88 = Engine remote control [2b]
89 = Load map anew [xx]
8A = Waiting code [xx]
8B = Deactivate static facing [xx]
8C = Priority jump1 [2b]
8D = Warp check
8E = Priority jump2 [2b]
8F = Return code1
90 = Return code2
91 = Return code3
92 = Reset sophisticated functions
93 = Mart menu [xxyyzz]
94 = Elevator menu [2b]
95 = Trade menu [xx]
96 = Give cell phone number with YES/NO [xx]
97 = Call code [2b]
98 = Hang-up code
99 = Decoration code [xx]
9A = Fruit tree code [xx]
9B = Cell phone call code [xx00]
9C = Check cell phone call code
9D = Commented give item code [xxyy]
9E = Load special wild PKMN data [xxyy]
9F = Hall of Fame code
A0 = Credits code
A1 = Facing warp
A2 = MEMORY code [2b + Bank + xx]
A3 = Display any location name [xx]
---------------
00 = Pointer code [2b+ret]
01 = Pointer code [3b+ret]
02 = Pointer code [2b+3b+ret]
03 = Pointer code [2b]
04 = Pointer code [3b]
05 = Pointer code [2b+3b]
06 = RAM check [=byte]
07 = RAM check [<>byte]
08 = RAM check [=0]
09 = RAM check [<>0]
0A = RAM check [<byte]
0B = RAM check [>byte]
0C = 0C codes [xxyy]
0D = 0D codes [xxyy]
0E = ASM code1 [3b]
0F = 0F codes [xxyy]
10 = ASM code2 [2b]
11 = Trigger event check1 [xxyy]
12 = Activate trigger event from afar [xxyyzz]
13 = Trigger event check
14 = De-/activate trigger event [xx]
15 = Load variable into RAM [xx]
16 = Add variables [xx]
17 = Random number [xx]
18 = Version check
19 = Copy variable code1 [xxyy]
1A = Copy variable code2 [xxyy]
1B = Load variable [xxyyzz]
1C = Check codes [xx]
1D = Input code1 [xx]
1E = Input code2 [xxyy]
1F = Give item code [xxyy]
20 = Take item code [xxyy]
21 = Check for item code [xx]
22 = Give money code [xxyyzzaa]
23 = Take money code [xxyyzzaa]
24 = Check for money code [xxyyzzaa]
25 = Give coins code [xxyy]
26 = Take coins code [xxyy]
27 = Check for coins code [xxyy]
28 = Give cell phone number [xx]
29 = Take cell phone number [xx]
2A = Check for cell phone number [xx]
2B = Check time of day [xx]
2C = Check for PKMN [xx]
2D = Give PKMN [xxyyzzaa(+2b +2b)]
2E = Give EGG [xxyy]
2F = Attach item code [2B]
30 = Check letter code [2b]
31 = BitTable1 check [xxyy]
32 = BitTable1 reset [xxyy]
33 = BitTable1 set [xxyy]
34 = BitTable2 check [xxyy]
35 = BitTable2 reset [xxyy]
36 = BitTable2 set [xxyy]
37 = Deactivate PKMN battles
38 = Activate PKMN battles
39 = X/Y comparison [xxyy]
3A = Warp modifier [xxyyzz]
3B = Blackout modifier [xxyy]
3C = Warp code [xxyyzzaa]
3D = Account code [xxyy]
3E = Coin case code [xx]
3F = Display RAM [xx]
40 = Display PokéMon name [xxyy]
41 = Display item name [xxyy]
42 = Display location name [xx]
43 = Display trainer name [xxyyzz]
44 = Display strings [2b + xx]
45 = Stow away item code
46 = Full item pocket code
47 = Text box&font code
48 = Refresh code [xx]
49 = Load moving sprites
4A = Load byte to C1CE [xx]
4B = Display text [3b]
4C = Display text [2b]
4D = Repeat text [xxyy]
4E = YES/No box
4F = Menu data code [2b]
50 = Write backup code
51 = Text1 code [2b]
52 = Text2 code [2b]
53 = Close text box code
54 = Keep text box open code
55 = Pokémon picture code [xx]
56 = Pokémon picture YES/NO code
57 = Menu interpreter 1
58 = Menu interpreter 2
59 = Load Pikachu data
5A = Delete FightRAM/reset person check
5B = Load trainer data1
5C = Load Pokémon data [xxyy]
5D = Load trainer data2 [xxyy]
5E = Start battle
5F = Return to In game engine after battle
60 = Learn how to catch PKMN [xx]
61 = Trainer text code
62 = Trainer status code [xx]
63 = Pointer Win/Loss [2b + 2b]
64 = Script talk-after
65 = Script talk-after-cancel
66 = Script talk-after-check
67 = Set talked-to person [xx]
68 = Moving code [xx + 2b]
69 = Moving code for talked-to person [2b]
6A = Talk-to facing code
6B = Facing of people code [xxyy]
6C = Variable sprites [xxyy]
6D = Hide person [xx]
6E = Show person [xx]
6F = Following code1 [xxyy]
70 = Stop following code
71 = Move person [xxyyzz]
72 = Write person location [xx]
73 = Load emoticons [xx]
74 = Display emoticon [xxyyzz]
75 = Change facing [xxyy]
76 = Following code2 [xxyy]
77 = Earth quake [xx]
78 = Exchange map [3b]
79 = Change block code [xxyyzz]
7A = Reload map code
7B = Reload map part code
7C = Write command queue
7D = Delete command queue
7E = Song code1 [xxyy]
7F = Song code2
80 = Music fade-out code [xxyy][zz]
81 = Play map music code
82 = Map reload music code
83 = Cry code [xx00]
84 = Sound code [xxyy]
85 = Key-down code
86 = Warp sound
87 = Special sound
88 = Engine remote control [2b]
89 = Load map anew [xx]
8A = Waiting code [xx]
8B = Deactivate static facing [xx]
8C = Priority jump1 [2b]
8D = Warp check
8E = Priority jump2 [2b]
8F = Return code1
90 = Return code2
91 = Return code3
92 = Reset sophisticated functions
93 = Mart menu [xxyyzz]
94 = Elevator menu [2b]
95 = Trade menu [xx]
96 = Give cell phone number with YES/NO [xx]
97 = Call code [2b]
98 = Hang-up code
99 = Decoration code [xx]
9A = Fruit tree code [xx]
9B = Cell phone call code [xx00]
9C = Check cell phone call code
9D = Commented give item code [xxyy]
9E = Load special wild PKMN data [xxyy]
9F = Hall of Fame code
A0 = Credits code
A1 = Facing warp
A2 = MEMORY code [2b + Bank + xx]
A3 = Display any location name [xx]
The actual compendium will tell you about each function in detail.
4. When does the actual scripting start?
(I'm getting to that!)
Once you understand what I meant about the compendium.
Here is a random script from Whitney's Gym:
When editing scripts you MUST be aware of how much space they consume to begin with, and how much space you need to achieve your goal.
Here is a practice I like to use to keep track of my space consumption and available space while scripting:
By keeping track of how many bytes each command uses, you'll be able to make scripts without causing any bugs. How does this prevent you from causing bugs?
If you write more bytes in script than the original code occupied it will write over the existing code of other scripts. That is not what we want. This will cause bugs, and will /probably/ make your hack unplayable.
The above example looks like this in the actual ROM when viewed through a hex editor.
It can be split as:
A quick check of the compendium will show you that each of the first bytes matches each of the bytes here in function.
(I'm getting to that!)
Once you understand what I meant about the compendium.
Here is a random script from Whitney's Gym:
Code:
[FONT=Monospace]#org 0x15C037
'-----------------------------------
loadfont
checkbit1 0x28
if false 0x4044 ' 0x15C044
2writetext 0x41F5 ' 0x15C1F5
closetext
loadmovesprites
end[/FONT]
Here is a practice I like to use to keep track of my space consumption and available space while scripting:
Code:
[FONT=Monospace]#org 0x15C037
'-----------------------------------
loadfont' 1B
checkbit1 0x28' 3B
if false 0x4044 ' 0x15C044 3B
2writetext 0x41F5 ' 0x15C1F5 3B
closetext' 1B
loadmovesprites' 1B
end' 1B
' 13 Byte Total[/FONT]
If you write more bytes in script than the original code occupied it will write over the existing code of other scripts. That is not what we want. This will cause bugs, and will /probably/ make your hack unplayable.
The above example looks like this in the actual ROM when viewed through a hex editor.
Code:
47 31 28 00 08 44 40 4C F5 41 53 49 90
Code:
[FONT=Monospace]47 loadtext
31 28 00 checkbit1
08 44 40 if false
4C F5 41 2writetext
53 closetext
49 loadmovesprites
90 end[/FONT]
5. The Example
In the above code, a string is referenced by the 2writetext command:
If I'm not mistaken, this block of script is for when you talk to Whitney immediately after beating her. Now, I've played through this generation a LOT, and if there's one thing I /HATE/, it's Whitney being a spoiled crybaby.
Leeeets, fix this.
That'll teach her! This gives you your badge and displays the string at pointer 0x15C278
However, this is not a good idea. Each time the player talks to Whitney immediately after defeating her this will give them the Plain Badge and play the sound. This also doesn't stop the second event from occuring when the player leaves and re-enters the gym, nor does it give them her TM.
Lets change this in a better way:
This is a much better method of skipping that fugly exit-and-return process.
It clears the bit 0x28 which is checked to see whether or not the player can receive the badge, and also the 0x0B bit. The second clear is essentially padding since the bit has not yet been set, however; this is a safe method of ensuring that it absolutely isn't set since a check is made on it before giving the player the badge.
Press F9 to compile, and CTRL-T to test this. If my code is correct(I haven't actually tested it, but I see no reason why it wouldn't work), then Whitney will surrender her badge and TM without the player having to take a long walk out and a long walk back.
Another thing I want to make a little mention about is the code below the 2jump line. This is what is called 'unreachable code'. At this point, the game will never use that small portion of script for any reason unless you call it somewhere else in your scripts.
Don't abuse this by making a whole bunch of things unreachable for no reason. That unreachable script is actually really useful in situations like the guy in Cherrygrove City who gives you the Map Card for the PokeGear. If you use a portion of his MASSIVE sight seeing tour, you'll have some unreachable code hopefully. Now you have free space to put any code you'd like.
How do you reference it? Another great thing about keeping track of how many bytes you're using is that you can add to the offset to know exactly what address a line is at.
So our unreachable code begins at Address 0x15C041 or Local Pointer 0x4041. It's only three bytes, so all it would hold is a pointer, a 2byte operation and an end, or two 1-byte operations and an end.
Make sure your code doesn't fall through to other code by the way!
When scripting, especially with large scripts, it's best to look for some free space in the current memory bank and start there.
In my All Pokemon hack for Pokemon Gold I want to create an event for Mewtwo in Mt. Mortar.
I'll start by finding an event in Mt. Mortar that I don't particularly care about:
This event is an Item Ball containing a Guard Spec.
The player would have a Guard Spec. if they really wanted one, especially at the point where they could freely pass around Mt. Mortar, so I really don't care about it. It's perfect for what I want it for!
Next, I'll edit the event properties window so that the event looks the way I want it to look:
I'll also move it to the place I want it to be, and have a look at it in-game:
Now, I'll click on the "Launch Script Editor" button in the Event Properties window to bring up the script of the event:
It uses exactly three bytes. This could not be more perfect. The reason why is that a 2jump command will perfectly fit in the space already occupied by the script.
My next goal is finding the free space within this bank.
By using a hex editor it's pretty easy to locate any available free space. This script is located at 0x119DB4 within the ROM. This means that the actual block loaded into the memory bank starts at 0x118000 and ends at 0x11BFFF.
For any script, check the third nibble of the address to see what the upper and lower bounds of the block are inside the actual ROM:
Using this information, I use my hex editor to scroll for a location between 0x118000 and 0x11BFFF which has nothing but 0's:
I'll start my code at 0x11A360 because I like to start at 0. It isn't necessary to do so, but the extra space on the 0x11A35X line makes it easier to see that custom code was added on the following line.
Now, I'll change the existing code to jump to the line of free space where I'll start my code, and let PKSV know that I'm going to start adding script on that line as well:
It's worth noting that the full pointer to my new code is 46:6360. You can use the PKSV Calculator(In PKSV, Tools -> Calculator and Notes) to figure out what the pointer to your region will look like. Enter in the ROM Address(11A360 in my case) of your free space and click on Offset2Pointer.
Now that I have a plethora of free space, I'll just go ahead and script as I want to:
And here's a look at the end result:
I may gradually add other things to this tutorial in the future.
Other resources:
Bulbapedia:
In the above code, a string is referenced by the 2writetext command:
Code:
#org 0x15C1F5
= Waaaaah!\pWaaaaah!\p[.]Snivel, hic[.]\n[.]You meanie!\e
Leeeets, fix this.
Code:
[FONT=Monospace]#org 0x15C037
'-----------------------------------
loadfont' 1B
setbit2 0x1C' 3B[/FONT][FONT=Monospace]
2writetext 0x4278 ' 0x15C278 3B
[/FONT][FONT=Monospace]playsound 0x9C 3B
closetext' 1B
loadmovesprites' 1B
end' 1B
' 13 Byte Total[/FONT]
Code:
#org 0x15C278
= [PLAYER] received\nPLAINBADGE.\e
Lets change this in a better way:
Code:
[FONT=Monospace]#org 0x15C037
'-----------------------------------
loadfont' 1B
clearbit1 0x28' 3B
clearbit1 0x0B' 3B
2jump 0x4044 ' 0x15C044 3B
closetext' 1B
loadmovesprites' 1B
end' 1B
' 13 Byte Total[/FONT]
It clears the bit 0x28 which is checked to see whether or not the player can receive the badge, and also the 0x0B bit. The second clear is essentially padding since the bit has not yet been set, however; this is a safe method of ensuring that it absolutely isn't set since a check is made on it before giving the player the badge.
Press F9 to compile, and CTRL-T to test this. If my code is correct(I haven't actually tested it, but I see no reason why it wouldn't work), then Whitney will surrender her badge and TM without the player having to take a long walk out and a long walk back.
Another thing I want to make a little mention about is the code below the 2jump line. This is what is called 'unreachable code'. At this point, the game will never use that small portion of script for any reason unless you call it somewhere else in your scripts.
Don't abuse this by making a whole bunch of things unreachable for no reason. That unreachable script is actually really useful in situations like the guy in Cherrygrove City who gives you the Map Card for the PokeGear. If you use a portion of his MASSIVE sight seeing tour, you'll have some unreachable code hopefully. Now you have free space to put any code you'd like.
How do you reference it? Another great thing about keeping track of how many bytes you're using is that you can add to the offset to know exactly what address a line is at.
Code:
[FONT=Monospace]#org 0x15C037
'-----------------------------------
loadfont' 1B 0x15C037 + 1 =
clearbit1 0x28' 3B 0x15C038 + 3 =
clearbit1 0x0B' 3B 0x15C03B + 3 =
2jump 0x4044 ' 0x15C044 3B 0x15C03E + 3 =
closetext' 1B 0x15C041 + 1 = <-- Unreachable code begins here
loadmovesprites' 1B 0x15C042 + 1 =
end' 1B 0x15C043
' 13 Byte Total[/FONT]
Make sure your code doesn't fall through to other code by the way!
6. Finding Free Space
When scripting, especially with large scripts, it's best to look for some free space in the current memory bank and start there.
In my All Pokemon hack for Pokemon Gold I want to create an event for Mewtwo in Mt. Mortar.
I'll start by finding an event in Mt. Mortar that I don't particularly care about:
Spoiler:
"image removed"
This event is an Item Ball containing a Guard Spec.
The player would have a Guard Spec. if they really wanted one, especially at the point where they could freely pass around Mt. Mortar, so I really don't care about it. It's perfect for what I want it for!
Next, I'll edit the event properties window so that the event looks the way I want it to look:
Spoiler:
"image removed"
I'll also move it to the place I want it to be, and have a look at it in-game:
Spoiler:
"image removed"
Now, I'll click on the "Launch Script Editor" button in the Event Properties window to bring up the script of the event:
Code:
#org 0x119DB4
'-----------------------------------
takephonenumber 0x1
end
My next goal is finding the free space within this bank.
By using a hex editor it's pretty easy to locate any available free space. This script is located at 0x119DB4 within the ROM. This means that the actual block loaded into the memory bank starts at 0x118000 and ends at 0x11BFFF.
For any script, check the third nibble of the address to see what the upper and lower bounds of the block are inside the actual ROM:
Code:
[LIST]
[*]0xYY0ZZZ - 0xYY3ZZZ: Located between 0xYY0000 and 0xYY3FFF in ROM
[*]0xYY4ZZZ - 0xYY7ZZZ: Located between 0xYY4000 and 0xYY7FFF in ROM
[*]0xYY8ZZZ - 0xYYBZZZ: Located between 0xYY8000 and 0xYYBFFF in ROM
[*]0xYYCZZZ - 0xYYFZZZ: Located between 0xYYC000 and 0xYYFFFF in ROM
[/LIST]
Spoiler:
"image removed"
I'll start my code at 0x11A360 because I like to start at 0. It isn't necessary to do so, but the extra space on the 0x11A35X line makes it easier to see that custom code was added on the following line.
Now, I'll change the existing code to jump to the line of free space where I'll start my code, and let PKSV know that I'm going to start adding script on that line as well:
Code:
#org 0x119DB4
'-----------------------------------
2jump 0x6360
#org 0x11A360
'-----------------------------------
Now that I have a plethora of free space, I'll just go ahead and script as I want to:
Code:
#org 0x119DB4
'-----------------------------------
2jump 0x6360 ' 0x11A360
#org 0x11A360
'-----------------------------------
checkbit1 0x65B
if false 0x637C ' 0x11A37A
loadfont
2writetext 0x63A6 ' 0x11A3A5
closetext
cry 0x96
pause 0xF
loadmovesprites
loadpokedata 0x96 0x50
startbattle
returnafterbattle
setbit1 0x067C
disappear 0x3
end
#org 0x11A37C
'-----------------------------------
refreshscreen 0x0
loadfont
2writetext 0x638E ' 0x11A387
closetext
loadmovesprites
pokepic 0x96
pause 0xF
closetext
refreshscreen 0x0
loadmovesprites
end
#org 0x11A3A6
= The strange\nstatue attacked!\e
#org 0x11A38E
= It's a strange\nstatue.\e
Spoiler:
"image removed"
I may gradually add other things to this tutorial in the future.
Other resources:
Bulbapedia:
- List of Pokemon by Index Number (Generation II)
- List of Items by Index Number (Generation II)
- Pokémon data structure in Generation II (This is excellent for use with a script which loads custom assembly routines. Necessary if you wanted to make an event that makes pokemon shiny or does something really special).
<NearEDGE>
Silly things:
Spoiler:
After having actually looked at Whitney's script, I realize how terribly redundant my code in the example was. To properly get rid of Whitney's nonsense, you only have to change ONE LINE OF SCRIPT:
Code:
#org 0x15C00C
'-----------------------------------
faceplayer
checkbit1 0x4BF
if true 0x4037 ' 0x15C037
loadfont
2writetext 0x4122 ' 0x15C122
closetext
loadmovesprites
winlosstext 0x41A5 0x0 ' 0x15C1A5,0xFFFFFFFF
loadtrainer 0x2 0x1
startbattle
returnafterbattle
setbit1 0x4BF
setbit1 0x28
dotrigger 0x1
setbit1 0x4AD
setbit1 0x4AE
setbit1 0x515
setbit1 0x516
loadfont
checkbit1 0x28
if true 0x4044 ' 0x15C044 <- Changed from false to true.
'One change, and she gives you your badge after the battle, and never cries at you again.
2writetext 0x41F5 ' 0x15C1F5
closetext
loadmovesprites
end
Last edited: