• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

[Pokecrystal] Guide to Scripting for Overworld Events [Status: I Fixed the Issues! / In Search of More Flexible Solutions]

2
Posts
4
Years
    • Seen Mar 30, 2020
    EDIT: I meant to post this in the Decomp & Disassembly section of the forum but I don't want to spam the website. If a mod could move it or if I am free to move it or if it doesn't belong there, can anyone let me know? Thanks!

    Update: I fixed the issues and have explanations for their fixes! This is now (according to myself) a pretty good, semi-comprehensive guide to the subject!

    Hi!

    The goal of this thread is to gather info on the scripting portion of the Pokemon Crystal disassembly project, pokecrystal. That includes NPCs, items on the ground, and more. I will attempt to explain everything I know that is relevant to the topic but I am by no means an expert and ask for any and all knowledgable folk to please chime in and fill in the gaps. I will do my best to edit the post and include your feedback. Thank you in advance!


    Short background:

    I was able to create new scripts, new script commands, new variables, and new flags, and successfully implement them in an assembly hack. If you follow my lead, I believe you can do it too.



    Contents:

    I. Relevant files
    1. Code Files
    2. INCLUDE Files
    II. How to's
    1. Add an NPC
    2. Add a New Command
    3. Add a New Variable
    4. Add New Flags
    III. Issues
    1. Bank Overflow
    2. White Screen / Black Screen / GBC Error / Corrupted Graphics / Other Weird Behavior
    VI. Conclusion
    1. Lessons Learned



    I. Relevant files


    Github Repo:

    /pret/pokecrystal



    1. Code Files:

    Scripting:

    engine/overworld/scripting.asm - The script commands and what they do are found here
    maps/map_name.asm - The scripts are written here
    macros/scripts/events.asm - These macros are called when "scripting"


    New Variables:

    wram.asm - The memory here can be referenced and used as "variables" when scripting
    possibly any other file - If you repurpose some wram, you need to be sure its old label is no longer being called by other code


    New Flags:

    wram.asm - The memory here can be referenced and used as flags when scripting
    possibly any other file - If you repurpose some wram, you need to be sure its old label is no longer being called by other code
    constants/wram_constants.asm - Relevant constants defined here
    constants/engine_flags.asm - Relevant constants defined here
    data/engine_flags.asm - Associates bits of the wram byte with the flag constants



    2. INCLUDE Files:

    Scripting:

    engine/overworld/events.asm - Contains the "Events" SECTION and INCLUDEs engine/overworld/scripting.asm
    data/maps/scripts.asm - INCLUDEs all the map_name.asm files
    data/maps/map_data.asm - Contains the "Maps" SECTION and INCLUDEs data/maps/scripts.asm
    macros.asm - INCLUDEs macros/scripts/events.asm


    New Variables:

    [Haven't looked into it yet]


    New Flags:

    [Haven't looked into it yet]



    II. How to's:


    1. Add an NPC

    i. Open the map where you want the event (maps/map_name.asm)
    ii. At the top of the file, define a constant for your event
    iii. a. At the bottom of the file, add your event's info to the bottom in the style of the others
    iii. b. The first two numbers are x, y coordinates - you can get these by opening the map_name.blk file in PolishedMap
    iii. c. The next four numbers have to do with movement radius
    iii. d. The argument immediately following the four numbers is for color - 0 is some sort of default - otherwise its the appropriate constant for the color you want
    iii. e. Create a label name for the script (I recommend following the existing naming style)
    iii. f. At the end of the line, you will usually place a "-1" but you can use this argument to control when and if the NPC will appear - "-1" means "always appear"
    iii. g. At the bottom of the file, make sure the number in the line: "db number ; object events" matches the number of items below it
    iv. Find preexisting script labels somewhere in the middle of the file - create a label using the label name you chose in (iii. e.) and start scripting! - use only script commands and "sublabels" - no gameboy instructions allowed
    v. Some script commands reference other mini scripts so be wary of those
    vi. Some scripts write text - you can find the labels for text past all of the script labels (second-halfish of the file)
    vii. a. Try to copy the style of pre-existing scripts
    vii. b. If you are attempting something new (e.g. a shop that sells pokemon), search for a similar event that already exists in the game (e.g. the goldenrod gamecorner exchanges pokemon for coins)


    2. Add a New Command

    i. Open engine/overworld/scripting.asm
    ii. Navigate to ScriptCommandTable:
    iii. At the end of the table, define a word (dw), following the naming convention there
    iv. a. At the bottom of the file (before .byte), write the instructions for the script command, following the naming conventions of the labels and ending the script command with a return (ret)
    iv. b. Think about a place in the game where a similar thing is done, understand each line of the code, copy it, and tweak it for your purpose (I strongly urge you to do this - see section III.)
    iv. c. If you want your commands to have inputs/arguments then all you need to do is add the line "call GetScriptByte" to your command's instructions - this will load the first argument into register a - if you use "call GetScriptByte" again, it will load the next argument into register a
    v. Add a new macro for your new command in macros/scripts/events.asm
    vi. Use the macro as a script command within a script in one of the map_name.asm files


    3. Add a New Variable

    i. Consider whether you should use flags instead (used with script commands checkflag, setflag, and clearflag; see (4.) below)
    ii. Open wram.asm
    iii. a. Find an unused byte or a byte that you will convert to unused status
    iii. b. If the memory is being used elsewhere and you want to use it, change its label and make sure the old label does not get referenced elsewhere in your code
    iv. Relabel the unused byte for easy reference in your script command's instructions
    v. Use as a "variable" within the instructions for a script command


    4. Add New Flags (on/off, zero/one, TRUE/FALSE, yes/no, etc.)

    i. Open wram.asm
    ii. a. Find an unused byte (one byte = 8 bits = 8 flags) or a byte that you will convert to unused status
    ii. b. If the memory is being used elsewhere and you want to use it, change its label and make sure the old label does not get referenced elsewhere in your code
    iii. Relabel the unused byte for easy reference in the flag constants files
    iv. Look at the relevant files I listed above and edit the flags in (just do what has been written before in the files)
    v. Use the flags with the checkflag, setflag, and clearflag script commands in a script



    III. Issues:

    1. Bank Overflow

    Issue: When I attempted to add a second script command (which was rather large), I could not 'make' the .gbc file with Cygwin. I got an error that said it was unable to place 'Events' at $some_address in bank $25. By looking at the linker script, you will find that the "Maps" and "Events" sections are placed in bank $25 (or at least in my assembly they are).

    Solution 1 (try this first!): If you write short, efficient code, you may be able to fit everything into the little remaining space there is in the memory bank. I was able to do that (see Issue 2.). Solving my second issue fixed the first!

    Solution 2 (it works but may give certain hacks issues): It's a little ugly, but the short of it is to delete unused script commands in engine/overworld/scripting.asm. My game will not feature fruit trees or the hall of fame so i can get rid of the commands for those. Cygwin will make the ROM just fine. Just be sure that the commands do not get called in a script somewhere. Also, I left them in the ScriptCommandTable and just added my commands at the end. (Not sure if you really need to do this so some further experimentation is needed.) And by the way, I am not using this solution as of writing this post (I am using solution 1) but I may need to resort to it later on.

    Solution 3 (not available yet): Adding onto engine/overworld/scripting.asm seems to be the cause of this overflow. By appropriately putting code into new sections, I imagine this issue can be resolved. I am not sure how to go about this so if anyone can help here, please do!



    2. Get white screen, black screen, "This game was designed for GBC" error screen, corrupted graphics, or other weird stuff

    Issue: My code would fit and Cygwin would make the .gbc file but I would run into the "This game was designed for GBC" error, corrupted graphics, or, somewhat humorously, a wild pokemon battle everytime I interacted with the NPC. I cannot fully explain why this was happening but I think it has to do with the inefficiency of my code and the limitations of the scripting engine. I tried to create a new command that, used alongside other commands, would get the job done. I ended up writing a script about 30 commands long just for my one task. I believe that, in theory, the code should have run, but it didn't.

    Solution (DO THIS AS MUCH AS POSSIBLE): Find code that already exists in the game that serves a similar purpose to your new code and copy as much of it as you can. For example, I needed to produce 6 unique, random bytes and store them in WRAM. I found a short, roughly 20 lines long function that simultaneously produces random bytes, checks for repeats, and saves them in memory for later use - really efficient, perfect for my task, and proven to work! I made a new command modeled after this and it made everything run perfectly using just one script command.



    VI. Conclusion:

    Lessons Learned: This solution to the second issue ended up being really easy and since my code ended up being short, I entirely avoided the first issue! I've been stuck on these issues for about a week but I now know to look for already existing code instead of challenging the pre-existing architecture. Truly, this is the best way to avoid creating unnecessary problems for yourself and to get things done! Be sure to fully understand each line of the code so you can tweak it. It was not too hard - it took time, but it was doable. Plus, its the only way to learn this stuff and move on to more complex things.

    Good luck! And don't give up! Take breaks, but don't give up, hehe ;)
     
    Last edited:
    1,403
    Posts
    10
    Years
    • Seen Apr 29, 2024
    EDIT: I meant to post this in the Decomp & Disassembly section of the forum but I don't want to spam the website. If a mod could move it or if I am free to move it or if it doesn't belong there, can anyone let me know? Thanks!

    Moved! Good luck with your questions :)
     
    3
    Posts
    245
    Days
    • Seen Sep 8, 2023
    Quick question about adding in an NPC on the overworld. I got the nitty gritty of the coding all situated (the game built with no errors) but the NPC sprite isn't visible. In short, I wanted to add the surfing_pikachu sprite into the water at Cherrygrove City. But it isn't visible. Not sure where to go from here sadly, lol.
     
    Back
    Top