Tools, Tutorials & Resources Various tools to help you develop your hacks can be found here.


Reply
 
Thread Tools
  #1    
Old August 7th, 2014 (5:55 PM). Edited August 10th, 2014 by NearEDGE.
NearEDGE NearEDGE is offline
     
    Join Date: Aug 2014
    Gender: Male
    Posts: 29
    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:
    Quote:
    • 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:
    1. A Pokemon Gold Rom as well as an Emulator to use it with.
    2. THIS version of G2Map(Skeetendo Demo).
    3. The Latest Version of PKSV.
    4. 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:
    Quote:
    • 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.
    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.
    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:
    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]


    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:
    Code:
    #org 0x15C037
    '-----------------------------------
    loadfont
    checkbit1 0x28
    if false 0x4044 ' 0x15C044
    2writetext 0x41F5 ' 0x15C1F5
    closetext
    loadmovesprites
    end
    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:

    Code:
    #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
    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.
    Code:
    47 31 28 00 08 44 40 4C F5 41 53 49 90
    It can be split as:

    Code:
    47        loadtext
    31 28 00  checkbit1
    08 44 40  if false
    4C F5 41  2writetext
    53        closetext
    49        loadmovesprites
    90        end
    A quick check of the compendium will show you that each of the first bytes matches each of the bytes here in function.


    5. The Example

    In the above code, a string is referenced by the 2writetext command:

    Code:
    #org 0x15C1F5
    = Waaaaah!\pWaaaaah!\p[.]Snivel, hic[.]\n[.]You meanie!\e
    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.

    Code:
    #org 0x15C037
    '-----------------------------------
    loadfont'                    1B
    setbit2 0x1C'                3B
    2writetext 0x4278 ' 0x15C278 3B
    playsound 0x9C               3B
    closetext'                   1B
    loadmovesprites'             1B
    end'                         1B
    '                           13 Byte Total
    That'll teach her! This gives you your badge and displays the string at pointer 0x15C278
    Code:
    #org 0x15C278
    = [PLAYER] received\nPLAINBADGE.\e
    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:
    Code:
    #org 0x15C037
    '-----------------------------------
    loadfont'                    1B
    clearbit1 0x28'              3B
    clearbit1 0x0B'              3B
    2jump 0x4044 ' 0x15C044      3B
    closetext'                   1B
    loadmovesprites'             1B
    end'                         1B
    '                           13 Byte Total
    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.


    Code:
    #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
    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!

    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:

    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:

    I'll also move it to the place I want it to be, and have a look at it in-game:
    Spoiler:


    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
    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:
    Code:
    • 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
    Using this information, I use my hex editor to scroll for a location between 0x118000 and 0x11BFFF which has nothing but 0's:
    Spoiler:


    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
    '-----------------------------------
    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:
    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
    And here's a look at the end result:
    Spoiler:



    I may gradually add other things to this tutorial in the future.

    Other resources:
    Bulbapedia:



    <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

    Reply With Quote

    Relevant Advertising!

      #2    
    Old August 8th, 2014 (12:31 PM).
    NearEDGE NearEDGE is offline
       
      Join Date: Aug 2014
      Gender: Male
      Posts: 29
      KNOCK: Added links to resources at the beginning.
      Also, attaching resources to this post just in case any of them become unavailable for some unforseeable reason.
      G2Map_v02_Skeetendo-demo.rar
      pksvui_pkg2-1-1.zip
      Scripting Compendium Gold_Silver.rar
      Reply With Quote
        #3    
      Old August 9th, 2014 (1:39 PM).
      ~Ruki!'s Avatar
      ~Ruki! ~Ruki! is offline
      Made in Guatemala
         
        Join Date: Feb 2014
        Location: Guatemala City
        Gender: Female
        Nature: Brave
        Posts: 266
        Good tutorial, in my times I never see a tutorial aboit scripting with PKSV.

        My hints to your scripting method

        1. Is better use Johtomap, because Johtomap can add more people easy, and can decompile and edit the map scripts.

        2. The script banks are very small, I recomend make the scripts in empty banks using the commands 3writetext, 3call and 3jump (the 3-byte poiners rulez xD)

        3. Using the PKSV calculator you can make more easy the free space finding

        4. And for easy scripts I recommend use the dynamic labels (but no use if you use advances commands like 2callasm, loadmenudata, interpretmenu, etc)

        Good work!
        __________________
        I'm just a normal romhacker c:
        Reply With Quote
          #4    
        Old August 9th, 2014 (9:53 PM).
        NearEDGE NearEDGE is offline
           
          Join Date: Aug 2014
          Gender: Male
          Posts: 29
          Quote:
          Originally Posted by ~G0LD! View Post
          Good tutorial, in my times I never see a tutorial aboit scripting with PKSV.

          My hints to your scripting method

          1. Is better use Johtomap, because Johtomap can add more people easy, and can decompile and edit the map scripts.

          2. The script banks are very small, I recomend make the scripts in empty banks using the commands 3writetext, 3call and 3jump (the 3-byte poiners rulez xD)

          3. Using the PKSV calculator you can make more easy the free space finding

          4. And for easy scripts I recommend use the dynamic labels (but no use if you use advances commands like 2callasm, loadmenudata, interpretmenu, etc)

          Good work!
          Thanks!
          I don't like using dynamically allocated resources in a setting like this. Not having precise control will always bug me.
          Also, I had noticed after browsing through the script banks that none of them are ever filled to start off with. In part 6 of my tutorial I find free space at 0x11A358. The free space starts there and continues to 0x11BFFF for a total of 7328 free bytes in bank 46 alone. The PKSV can find free space of whatever size you need, but It's better to just find the free space in the bank the base script is in yourself and use that since I think there always is at least 1000 bytes free in every bank.

          I try to avoid using the 3 byte pointers for his reason. It can easily cause unexpected results especially if you jump somewhere you should instead call.
          Reply With Quote
          Reply

          Quick Reply

          Join the conversation!

          Create an account to post a reply in this thread, participate in other discussions, and more!

          Create a PokéCommunity Account

          Sponsored Links
          Thread Tools

          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 -8. The time now is 6:18 PM.