Post by v)Luminesce(v on Oct 14, 2016 22:23:11 GMT
Many members here are probably already familiar with the basics of scripting. Nonetheless, it might be useful to explain it to people who are less so.
'Scripting' is predominantly used for events. It allows you to include events of many kinds, by writing down what is to happen. That this is done using certain terms, like 'checkflag,' should not confuse you - these are used to manipulate the basic coding of the game. Hence, 'scripting' is not that different from 'hex editing,' it is merely a particular application of this.
Free Space
To add a new code, all you generally need is free space in the game. This free space usually looks like this in hex:
FFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFF
And so on. A notable case of this is at around 0x800000 in FireRed. The longer your code, the more free space you will need. A script would be added in the form:
FFFFFFFFFFFFFFFF1337FFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFF
If '1337' were a code, it would now be a part of the game. You could then implement it by having a character use it. Mapping programs like Advance Map make this simpler, by allowing you to add any code to people or events so long as you know their 'offset,' or their place in the ROM.
Some games will instead use '00' for free space, as in:
00000000000000000000.
Scripting and Hex editing
So what are we looking at when we look at a line of script, ie. a command, like 'lock' or 'givePokémon'? This command is actually a part of the game which, in a hex editor, would be represented as a hex number or, if you prefer, as two characters - like 'CF,' 'D2' or 'F6.' Hence, by adding that, you are adding two letters or numbers, like 'D2,' to the game. This then has an effect on the game. To summarise, a script command looks in hex terms like this:
D2.
As such, although it might appear complex, it is in a sense a simple alteration. All that is added is two characters, which already have a meaning in the script.
In addition to this, some scripts will need more quantities to be added. For instance, if you are giving them a Pokémon, then which one? If you are giving them an item, then how many?
Hence, let's say that D2 was the number representing giving someone a Pokémon. Then we would have to add a number saying what type of Pokémon. Let's say we gave them Bulbasaur. This is Pokémon number '1,' or in hex '01.' Hence, we insert the hex number after the command:
D2 01.
It hence becomes a 'give Bulbasaur' command.
It is likely that something very similar to this command once led to the phenomenon of 'VineShipping.'
What is needed for an action like this to be added is merely the hex number for it, followed by the necessary specifications for the code.
Pointers
A pointer is a number which refers to an off-set. It essentially tells the game to load data from an off-set. In events, it mostly comes up when data from elsewhere has to be called as part of an action's specification. For instance, instead of adding a command for a Pokémon and then its number, we might want to add a dialogue and load the text from elsewhere. Dialogue is the most standard instance of having to use pointers in events.
A pointer is essentially telling the game: 'look for this data in this location.'
Hence, what we want to tell the game is, 'Look for this text in this location.' As such, while in some commands we specify the data in the script, in others we say where to find the data elsewhere.
Dialogue is not a part of the script - it is of indeterminate length, and if in the script could involve commands which modify the game in unwanted manners. It has to be added elsewhere, and then the script has to tell the game where it is. Thus, we have to add the text in free space as well.
A pointer is four characters of text or number, which tells the game where to look for information. The 'pointer' to an off-set is a simple alteration of the off-set number.
This guide isn't about calculating pointers, so we won't elaborate on that.
However, we now know most of the basic elements of a script: commands, data, and pointers. Most of what scripting programs do is altering these elements, or in brief changing a few numbers in the code.
Representing this in textual format is more easy for users, but also gives a slight illusion of being able to do more than is there available - that is, of something more elaborate than scripting is in-game.
Dynamic offsets
You might recall that we insert a code into a ROM by looking for free space. However, instead of looking manually for free space to insert a code, scripting programs also include something called 'dynamic off-sets.' This means that the program automatically looks for free space to insert the code.
This can be useful for several reasons. Firstly, you don't have to worry about your script being too long for the space you're writing it in. The program will look for a space to place it. This could be circumvented by writing out the script in advance, and then looking for an appropriate location, but in any case it is quite straightforward.
Secondly, you can freely add things like dialogue without having to look for available space elsewhere for this. The usual way of doing this would be to look for free space or or a series of 'FF' in the ROM. However, this makes such things quite straightforward.
A dynamic off-set looks something like this, and is placed at the opening of a code:
#dynamic 0x800000
The 0x800000 merely tells the program which section of the ROM to look in. It will find free space near this region. 0x800000 is a site of free space in Fire Red, and hence is often seen in dynamic scripts.
This has to be followed by an 'org' command. These usually open a script, and tell it which off-set to use. However, when using dynamic off-sets, you do not have to specify an off-set, but instead merely label it, and the program will find a place for it. Hence, '#org @flying' would add the following script into an available off-set.
In general, the most common distinction between dynamic scripts and others is that instead of referring to off-sets by numbers, they are referred to by a label, which is preceded by '@'.
This can be followed by a usual script, but without the need to specify numerical off-sets (unless you want to.) These off-sets will be conjured by the program.
To have it do this, you merely have to add an '@' before a label for this off-set, and it will find free space for this. Hence, instead of 'goto 0x838836,' telling the script to change into another script, you can just add 'goto @offset,' where @offset is specified elsewhere in the dynamic code. Thus, as long as there is a '#org @offset' somewhere in the code, the code will be told to go to this off-set.
Hence, how this will finally look is:
'#org @offset' will be converted into an off-set, like 0x800300.
'goto @offset' will be converted into a command to go to an offset: 'goto 0x800300.' This off-set will be represented, in the game's code, via a pointer.
Dynamic scripts are useful for creating scripts which others can use as well, or 'resource scripts,' because they can be added to a ROM even if a certain area is limited. Generally, however, scripting tends to be an activity which you should try to do yourself.
Messages and Callstd
To display a message, or dialogue, follow these steps:
a) Add the text somewhere in the ROM. To do this, you will usually want a '.tbl' file, which essentially tells you how to convert the text into the hex code used in the ROM.
b) Add an event where the character says this dialogue. For this, use the 'msgbox' command in programs, or an appropriate hex code, followed by a pointer to the location.
c) Add a 'callstd,' which essentially specifies how this message is to be presented. Callstd 0x2 or 0x6 are usual dialogue, while 0x5 will present it as a yes/no question.
Hence:
msgbox 0x800400
callstd 0x5msgbox 0x800400
callstd 0x5
Is a message followed by a 'Yes/No' question.
In hex, the 'callstd' would look like this: 0905. ('09' is 'callstd,' '05' is the type.)
Conditions
If you have used a 'Yes/No' question, the game is usually expected to respond differently to each response.
Hence, if they answer 'yes,' you might want to redirect them to a different script, using the 'goto' command.
As this script is also of variable length, you cannot include it within the original script where the question was asked, as the game will not know where this section ends and the main script begins.
Therefore, you will want to add an 'if' command. This will be quite simple: If they answer one way, then go to an off-set.
An 'if' command takes the data from a process, and if it is of a certain kind leads to a different result.
However, you will first need to collect the data from the player's response. This script is in interaction with the player, and hence first has to respond to them. Therefore:
msgbox 0x800400
callstd 0x5 (Asks YES/NO. Stores the result.)
compare LASTRESULT 0x1 (Checks if 'LASTRESULT,' here the player's response, is 0x1, or positive - that is, if they said 'Yes.')
if 0x1 goto 0x800300 (If the previous check was positive - if they answered 'Yes' - then it goes elsewhere. This would often be specified by a pointer in hex.)
Finally, as people who answered 'Yes' have been sent to another script, the rest of the script is just about what should happen if the player says 'No.'
All that you need to do from there is specify the script at '0x800300,' or the script if the player says 'Yes.'
This is hence a quite simple mode of having the game interact with the player. Depending on the players' response, it goes to a different script.
The script, however, remains the same regardless. Hence, this is quite limited.
Trainer battles
To battle trainers, you need to uses both pointers and data entered. The exact process can differ between games, in terms of for instance whether double battles are available.
Firstly, in games like FR, you are to specify the battle type. This is usually 0x0. This designates an ordinary trainer. However, things like 0x1 can lead to Gym leaders and others who add an extra message in after a battle. When you battle a Gym leader, they usually use an extra dialogue to give you the badge, TMs, and so on. This is part of their own battle type. They do not repeat this dialogue if asked again. (So if players weren't paying attention, that's a nuisance.)
Secondly, you'll want a trainer ID number. This is in hex. You can generally find it in a trainer editor. Alternatively, you could just edit a trainer in order to have them and their Pokémon be as you prefer. This number specifies which trainer the player battles, in terms of their team, name, and trainer type, and you will want to be careful with it. You would usually want to avoid a trainer coming up against a bug-catcher in battle after taking on a lass, or similar. This rarely seems to occur, suggesting that people try not to alter trainer types too much.
Hence, say we wanted a normal trainer battle against trainer number 10 (or '0A'.) We would use:
trainerbattle 0x0 0xA ...
(Or: 5C 00 0A.)
You then would add a further point of data which is generally 00. You would rarely use this, except perhaps for battles where you wanted the option of the player losing. Outside of this, people will mostly assume that this is 00. Hence, ordinarily: trainerbattle 0x0 0xA 0x0 (or 5C 00 0A 00.)
Finally, you need two pointers. The first is their conversation before a battle. Usually, when you walk up to a trainer, they say something, and then initiate a battle. Or they could go, '...' Whichever. The second pointer is to their dialogue when the battle finishes, while the battle screen is active.
This post-battle statement could be anything from 'I hate losing,' to, 'Aw,' but in any case occurs before the screen returns to the map. Each of these pointers is about four characters long. Hence, trainerbattle ends up being quite an expansive script.
After this, you might want to add further dialogue for after the player returns to the map. This dialogue is for if the player attempts to talk to them further.
Hence, after the trainerbattle, you would add a further message command, along with a pointer, in a fairly conventional manner. Alternatively, you could skip this, and make something like a Team Rocket member whose statement on defeat is 'Blasting off again!' Then just add a 'hidesprite' or something similarly affable post-battle.
Keep an eye out for if a ROM has dialogue after the battle which is highly different from that preceding it. This usually implies that the ROM was made with a fairly clear condition for getting past opponents. This stage is treated as something independent. Hence, you might want to pay attention to cues for an easy way through the hack.
Lock
'Lock,' or 6A, is a command which prevents the player from moving the player character. While useful, be cautious not to use it for over-elaborate sequences, where the player can no longer control the player-character. This can lead to railroading or a sense of intruding cutscenes.
Alternatively, make a Final Fantasy-themed game which is just a sequence of lock functions going on for increasingly unnecessary periods of time.
Who's to say? It could open up new paths for ROM Hacking.
In any case, a lock function should usually be followed by a 'release' function, at the end of the code. This allows the player to move freely again. Otherwise they would just be stuck in the same pose continually, like an unconvincing ending to a date sim game.
Modifiers
There are 'buffer' commands available in many programs. These are used for dialogue. By saving something to a 'buffer,' you can then add [buffer1], etc., to the text, and then this will be part of the text. This is useful for saving thing like the nickname or type of the first Pokémon in the party.
A 'special' command calls a pre-configured script. For instance, the 'Old Man' catching display, or choosing a Pokémon from the bag in R/S/E. Special commands are hence special, in a way: they play a notable role in things similar to the Missingno. glitch. These are helpful to be aware of, but you usually don't have to use them.
You could generally make a decent game without 'special' scripts, they aren't usually the main gameplay.
Things like 'warp' alter locations. You then have to specify where you want the character to go.
Things like 'setmaptile' can be useful. They alter a tile on the map - for instance, converting a blocked path to an open door. For example, if you were on a journey and talked to a character, and they remove an obstacle from your path forwards. This could be made a common thing along the journey. Nonetheless, this usually isn't strictly necessary.
That said, if you wanted to do something similar to the Team Aqua or Magma thing, having tiles of the map change into water, etc., could be a convenient way of doing this. It would give a sense of danger or encroachment on the Pokémon cities.
We will deal with variables and flags, which are similar, elsewhere. They have more to do with the overall layout of the ROM.
Other commands can alter things like the weather, an important part of R/S/E (I mean, yes, you could stop the legendary Pokémon from unleashing its power or whatever, but if you have a Castform you're probably too busy enjoying the weather to care.), as well as places where players heal after whiting out, whether sounds are played during a conversation, and whether the player's gender alters the script they go through.
'Scripting' is predominantly used for events. It allows you to include events of many kinds, by writing down what is to happen. That this is done using certain terms, like 'checkflag,' should not confuse you - these are used to manipulate the basic coding of the game. Hence, 'scripting' is not that different from 'hex editing,' it is merely a particular application of this.
Free Space
To add a new code, all you generally need is free space in the game. This free space usually looks like this in hex:
FFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFF
And so on. A notable case of this is at around 0x800000 in FireRed. The longer your code, the more free space you will need. A script would be added in the form:
FFFFFFFFFFFFFFFF1337FFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFF
If '1337' were a code, it would now be a part of the game. You could then implement it by having a character use it. Mapping programs like Advance Map make this simpler, by allowing you to add any code to people or events so long as you know their 'offset,' or their place in the ROM.
Some games will instead use '00' for free space, as in:
00000000000000000000.
Scripting and Hex editing
So what are we looking at when we look at a line of script, ie. a command, like 'lock' or 'givePokémon'? This command is actually a part of the game which, in a hex editor, would be represented as a hex number or, if you prefer, as two characters - like 'CF,' 'D2' or 'F6.' Hence, by adding that, you are adding two letters or numbers, like 'D2,' to the game. This then has an effect on the game. To summarise, a script command looks in hex terms like this:
D2.
As such, although it might appear complex, it is in a sense a simple alteration. All that is added is two characters, which already have a meaning in the script.
In addition to this, some scripts will need more quantities to be added. For instance, if you are giving them a Pokémon, then which one? If you are giving them an item, then how many?
Hence, let's say that D2 was the number representing giving someone a Pokémon. Then we would have to add a number saying what type of Pokémon. Let's say we gave them Bulbasaur. This is Pokémon number '1,' or in hex '01.' Hence, we insert the hex number after the command:
D2 01.
It hence becomes a 'give Bulbasaur' command.
It is likely that something very similar to this command once led to the phenomenon of 'VineShipping.'
What is needed for an action like this to be added is merely the hex number for it, followed by the necessary specifications for the code.
Pointers
A pointer is a number which refers to an off-set. It essentially tells the game to load data from an off-set. In events, it mostly comes up when data from elsewhere has to be called as part of an action's specification. For instance, instead of adding a command for a Pokémon and then its number, we might want to add a dialogue and load the text from elsewhere. Dialogue is the most standard instance of having to use pointers in events.
A pointer is essentially telling the game: 'look for this data in this location.'
Hence, what we want to tell the game is, 'Look for this text in this location.' As such, while in some commands we specify the data in the script, in others we say where to find the data elsewhere.
Dialogue is not a part of the script - it is of indeterminate length, and if in the script could involve commands which modify the game in unwanted manners. It has to be added elsewhere, and then the script has to tell the game where it is. Thus, we have to add the text in free space as well.
A pointer is four characters of text or number, which tells the game where to look for information. The 'pointer' to an off-set is a simple alteration of the off-set number.
This guide isn't about calculating pointers, so we won't elaborate on that.
However, we now know most of the basic elements of a script: commands, data, and pointers. Most of what scripting programs do is altering these elements, or in brief changing a few numbers in the code.
Representing this in textual format is more easy for users, but also gives a slight illusion of being able to do more than is there available - that is, of something more elaborate than scripting is in-game.
Dynamic offsets
You might recall that we insert a code into a ROM by looking for free space. However, instead of looking manually for free space to insert a code, scripting programs also include something called 'dynamic off-sets.' This means that the program automatically looks for free space to insert the code.
This can be useful for several reasons. Firstly, you don't have to worry about your script being too long for the space you're writing it in. The program will look for a space to place it. This could be circumvented by writing out the script in advance, and then looking for an appropriate location, but in any case it is quite straightforward.
Secondly, you can freely add things like dialogue without having to look for available space elsewhere for this. The usual way of doing this would be to look for free space or or a series of 'FF' in the ROM. However, this makes such things quite straightforward.
A dynamic off-set looks something like this, and is placed at the opening of a code:
#dynamic 0x800000
The 0x800000 merely tells the program which section of the ROM to look in. It will find free space near this region. 0x800000 is a site of free space in Fire Red, and hence is often seen in dynamic scripts.
This has to be followed by an 'org' command. These usually open a script, and tell it which off-set to use. However, when using dynamic off-sets, you do not have to specify an off-set, but instead merely label it, and the program will find a place for it. Hence, '#org @flying' would add the following script into an available off-set.
In general, the most common distinction between dynamic scripts and others is that instead of referring to off-sets by numbers, they are referred to by a label, which is preceded by '@'.
This can be followed by a usual script, but without the need to specify numerical off-sets (unless you want to.) These off-sets will be conjured by the program.
To have it do this, you merely have to add an '@' before a label for this off-set, and it will find free space for this. Hence, instead of 'goto 0x838836,' telling the script to change into another script, you can just add 'goto @offset,' where @offset is specified elsewhere in the dynamic code. Thus, as long as there is a '#org @offset' somewhere in the code, the code will be told to go to this off-set.
Hence, how this will finally look is:
'#org @offset' will be converted into an off-set, like 0x800300.
'goto @offset' will be converted into a command to go to an offset: 'goto 0x800300.' This off-set will be represented, in the game's code, via a pointer.
Dynamic scripts are useful for creating scripts which others can use as well, or 'resource scripts,' because they can be added to a ROM even if a certain area is limited. Generally, however, scripting tends to be an activity which you should try to do yourself.
Messages and Callstd
To display a message, or dialogue, follow these steps:
a) Add the text somewhere in the ROM. To do this, you will usually want a '.tbl' file, which essentially tells you how to convert the text into the hex code used in the ROM.
b) Add an event where the character says this dialogue. For this, use the 'msgbox' command in programs, or an appropriate hex code, followed by a pointer to the location.
c) Add a 'callstd,' which essentially specifies how this message is to be presented. Callstd 0x2 or 0x6 are usual dialogue, while 0x5 will present it as a yes/no question.
Hence:
msgbox 0x800400
callstd 0x5msgbox 0x800400
callstd 0x5
Is a message followed by a 'Yes/No' question.
In hex, the 'callstd' would look like this: 0905. ('09' is 'callstd,' '05' is the type.)
Conditions
If you have used a 'Yes/No' question, the game is usually expected to respond differently to each response.
Hence, if they answer 'yes,' you might want to redirect them to a different script, using the 'goto' command.
As this script is also of variable length, you cannot include it within the original script where the question was asked, as the game will not know where this section ends and the main script begins.
Therefore, you will want to add an 'if' command. This will be quite simple: If they answer one way, then go to an off-set.
An 'if' command takes the data from a process, and if it is of a certain kind leads to a different result.
However, you will first need to collect the data from the player's response. This script is in interaction with the player, and hence first has to respond to them. Therefore:
msgbox 0x800400
callstd 0x5 (Asks YES/NO. Stores the result.)
compare LASTRESULT 0x1 (Checks if 'LASTRESULT,' here the player's response, is 0x1, or positive - that is, if they said 'Yes.')
if 0x1 goto 0x800300 (If the previous check was positive - if they answered 'Yes' - then it goes elsewhere. This would often be specified by a pointer in hex.)
Finally, as people who answered 'Yes' have been sent to another script, the rest of the script is just about what should happen if the player says 'No.'
All that you need to do from there is specify the script at '0x800300,' or the script if the player says 'Yes.'
This is hence a quite simple mode of having the game interact with the player. Depending on the players' response, it goes to a different script.
The script, however, remains the same regardless. Hence, this is quite limited.
Trainer battles
To battle trainers, you need to uses both pointers and data entered. The exact process can differ between games, in terms of for instance whether double battles are available.
Firstly, in games like FR, you are to specify the battle type. This is usually 0x0. This designates an ordinary trainer. However, things like 0x1 can lead to Gym leaders and others who add an extra message in after a battle. When you battle a Gym leader, they usually use an extra dialogue to give you the badge, TMs, and so on. This is part of their own battle type. They do not repeat this dialogue if asked again. (So if players weren't paying attention, that's a nuisance.)
Secondly, you'll want a trainer ID number. This is in hex. You can generally find it in a trainer editor. Alternatively, you could just edit a trainer in order to have them and their Pokémon be as you prefer. This number specifies which trainer the player battles, in terms of their team, name, and trainer type, and you will want to be careful with it. You would usually want to avoid a trainer coming up against a bug-catcher in battle after taking on a lass, or similar. This rarely seems to occur, suggesting that people try not to alter trainer types too much.
Hence, say we wanted a normal trainer battle against trainer number 10 (or '0A'.) We would use:
trainerbattle 0x0 0xA ...
(Or: 5C 00 0A.)
You then would add a further point of data which is generally 00. You would rarely use this, except perhaps for battles where you wanted the option of the player losing. Outside of this, people will mostly assume that this is 00. Hence, ordinarily: trainerbattle 0x0 0xA 0x0 (or 5C 00 0A 00.)
Finally, you need two pointers. The first is their conversation before a battle. Usually, when you walk up to a trainer, they say something, and then initiate a battle. Or they could go, '...' Whichever. The second pointer is to their dialogue when the battle finishes, while the battle screen is active.
This post-battle statement could be anything from 'I hate losing,' to, 'Aw,' but in any case occurs before the screen returns to the map. Each of these pointers is about four characters long. Hence, trainerbattle ends up being quite an expansive script.
After this, you might want to add further dialogue for after the player returns to the map. This dialogue is for if the player attempts to talk to them further.
Hence, after the trainerbattle, you would add a further message command, along with a pointer, in a fairly conventional manner. Alternatively, you could skip this, and make something like a Team Rocket member whose statement on defeat is 'Blasting off again!' Then just add a 'hidesprite' or something similarly affable post-battle.
Keep an eye out for if a ROM has dialogue after the battle which is highly different from that preceding it. This usually implies that the ROM was made with a fairly clear condition for getting past opponents. This stage is treated as something independent. Hence, you might want to pay attention to cues for an easy way through the hack.
Lock
'Lock,' or 6A, is a command which prevents the player from moving the player character. While useful, be cautious not to use it for over-elaborate sequences, where the player can no longer control the player-character. This can lead to railroading or a sense of intruding cutscenes.
Alternatively, make a Final Fantasy-themed game which is just a sequence of lock functions going on for increasingly unnecessary periods of time.
Who's to say? It could open up new paths for ROM Hacking.
In any case, a lock function should usually be followed by a 'release' function, at the end of the code. This allows the player to move freely again. Otherwise they would just be stuck in the same pose continually, like an unconvincing ending to a date sim game.
Modifiers
There are 'buffer' commands available in many programs. These are used for dialogue. By saving something to a 'buffer,' you can then add [buffer1], etc., to the text, and then this will be part of the text. This is useful for saving thing like the nickname or type of the first Pokémon in the party.
A 'special' command calls a pre-configured script. For instance, the 'Old Man' catching display, or choosing a Pokémon from the bag in R/S/E. Special commands are hence special, in a way: they play a notable role in things similar to the Missingno. glitch. These are helpful to be aware of, but you usually don't have to use them.
You could generally make a decent game without 'special' scripts, they aren't usually the main gameplay.
Things like 'warp' alter locations. You then have to specify where you want the character to go.
Things like 'setmaptile' can be useful. They alter a tile on the map - for instance, converting a blocked path to an open door. For example, if you were on a journey and talked to a character, and they remove an obstacle from your path forwards. This could be made a common thing along the journey. Nonetheless, this usually isn't strictly necessary.
That said, if you wanted to do something similar to the Team Aqua or Magma thing, having tiles of the map change into water, etc., could be a convenient way of doing this. It would give a sense of danger or encroachment on the Pokémon cities.
We will deal with variables and flags, which are similar, elsewhere. They have more to do with the overall layout of the ROM.
Other commands can alter things like the weather, an important part of R/S/E (I mean, yes, you could stop the legendary Pokémon from unleashing its power or whatever, but if you have a Castform you're probably too busy enjoying the weather to care.), as well as places where players heal after whiting out, whether sounds are played during a conversation, and whether the player's gender alters the script they go through.