Skip to main content

Adding New Overworlds in HeartGold Engine

Author: Senate

This guide will help you to add new overworlds in HeartGold Engine (HGE).

WARNING: HGE will continue to add more overworlds and more overworld graphics -- if you merge these into your project, make sure to update the GFX number that your overworlds start with (more on that later in the guide).


Table of Contents


Acknowledgements

BluRose: All the help in teaching me this and making this possible in HGE.


Prerequisites


Part 1 - .BTX0 Files And How to Extract Them

.BTX0 files contain the various frames of overworlds. An example of one, as displayed in Tinke 0.9.2, is shown below:

We will need to extract a .BTX0 file of an existing overworld (for the purposes of this guide, we will use the .BTX0 for Eusine) because the program pngtobtx0 will read the contents of a vanilla .BTX0 file, then add your PNG over top of it without replacing the original sprite in the game.

To extract a .BTX0 file, use Tinke 0.9.2 and navigate to a/0/8/1. Tinke will show you a preview of the sprite in the .BTX0 if you click the file, then press View or hit spacebar on your keyboard. Once you have found one that matches your intentions, press Extract and save it where you would like.


Part 2 - Editing The Sprite In A .BTX0 File

Once you have your .BTX0, open it in BTXEditor2 (Prerequisites).

Click Export and save the .png where you would like.

You are now free to edit it in your sprite editing software of choice.


Part 3 - Editing pngtobtx0.cs To Work With Your New Sprite

The next step is to move your .BTX0 to the ../rawdata folder. Rename it to something like a081_npcs for clarity as so:

It's important to remove the .BTX0 file extension -- don't worry, no data will be lost.

After you have done so, create a folder called new npcs in ../data/graphics/overworlds. Place your .png in there and rename it to 0000.png. If you add more sprites, name them 0001.png, 0002.png, and so on.

Now, we must edit pngtobtx0.cs, which is in ../tools/source to tell it to properly convert your .png to a .BTX0. Copy the following code into pngtobtx0.cs after the section of code that begins with if (bitmap.Width > 32) // if a big mon:

else if (bitmap.Height == 384) // npcs -- their dimensions are 32x384
{
if (pngFile.Contains("new_npcs/"))
{
pngFile = pngFile.Substring("new_npcs/".Length, pngFile.Length - "new_npcs/".Length);
}

try
{
this.BTXFile = File.ReadAllBytes("rawdata/a081_npcs");
}
catch (Exception e)
{
Console.WriteLine(e.Message);

return;
}

this.bm = BTX0.Read(this.BTXFile);
}

Next, we need to update this line in pngtobtx0.cs:

if (Program.PaletteSize == 64U && Program.PaletteCount == 2U) // handle shiny palette if one exists first

to also include your new npcs folder. Simply add && !args[0].Contains("new_npcs") to that line within the parentheses.

All this code will look for .png files in your new folder new_npcs and begin applying the .png over the .BTX0 called a081_npcs (functionally a .BTX0 file even without the file extension) in ../rawdata once you build your ROM with HGE.

Now, we need to expand the table for overworlds to have a new entry for yours.


Part 4 - Expanding The Overworld Table

At the top of ../src/field/overworld_table.c with the definitions for shadows, include the following code:

#define NEW_NPC_START 7000
#define NEW_NPC_GFX_START 1458
#define NEW_NPC_ENTRY(num) {.tag = NEW_NPC_START + num, .gfx = NEW_NPC_GFX_START + num, .callback_params = 0}

You can choose what NEW_NPC_START is defined as, but choose an arbitrarily large number that HGE will likely not reach. This ensures that your overworld entry will not be shifted later in your project, which would make for an extremely tedious process of updating your overworlds in DSPRE.

As mentioned at the beginning of this guide, you will have to change NEW_NPC_GFX_START as HGE adds more overworld sprites. At the time of writing this guide, 1457 is the last used GFX, which belongs to the three segment form of Dudunsparce. Make sure you pay attention to what the last number used by HGE is as you merge!

After the Pokémon overworlds, include the following:

NEW_NPC_ENTRY(0), // the name of your sprite for easy reference

So that it will look like:

(...)
{ .tag = 1789, .gfx = 297, .callback_params = OVERWORLD_SIZE_SMALL}, // SPECIES_IRON_BOULDER
{ .tag = 1790, .gfx = 297, .callback_params = OVERWORLD_SIZE_SMALL}, // SPECIES_IRON_CROWN
{ .tag = 1791, .gfx = 297, .callback_params = OVERWORLD_SIZE_SMALL}, // SPECIES_TERAPAGOS
{ .tag = 1792, .gfx = 297, .callback_params = OVERWORLD_SIZE_SMALL}, // SPECIES_PECHARUNT

NEW_NPC_ENTRY(0), // the name of your sprite for easy reference

You have now expanded the overworld table to fit yours!


Part 5 - Compiling

If you were to compile now, you would successfully have a new entry in the overworld table in DSPRE, but your sprite would not show up. This is due to HGE not rebuilding a/0/8/1 without being told to do so.

To fix this, we can add a Make option in narcs.mk to update a/0/8/1 during the build process. Add this in narcs.mk:

# add make option for rebuilding overworlds
reset_overworlds:
rm -rf build/a081
rm build/narc/pokemonow.narc

Additionally, you will need to add the following in narcs.mk near OVERWORLDS_DIR := $(BUILD)/pokemonow:

OVERWORLDS_NEW_NPCS_SRCS := $(wildcard $(OVERWORLDS_DEPENDENCIES_DIR)/new_npcs/*.png)
OVERWORLDS_NEW_NPCS_OBJS := $(patsubst $(OVERWORLDS_DEPENDENCIES_DIR)/new_npcs/%.png,$(OVERWORLDS_DIR)/4_%,$(OVERWORLDS_NEW_NPCS_SRCS))
$(OVERWORLDS_DIR)/4_%:$(OVERWORLDS_DEPENDENCIES_DIR)/new_npcs/%.png
$(BTX) $< $@

It should end up looking like this:

Finally, add $(OVERWORLDS_NEW_NPCS_OBJS) to the $(OVERWORLDS_NARC): | overworld_extract $(OVERWORLDS_OBJS) $(OVERWORLDS_NEW_BERRIES_OBJS) line near ``remove binaries:`; i.e.:

remove_binaries:
for n in $$(seq 297 $$(expr $$(ls $(OVERWORLDS_DIR) | wc -l) - 1)); do rm -f $(OVERWORLDS_DIR)/1_$$(printf "%04d" $$n); done

$(OVERWORLDS_NARC): | overworld_extract $(OVERWORLDS_OBJS) $(OVERWORLDS_BERRIES_OBJS) $(OVERWORLDS_NEW_NPCS_OBJS) remove_binaries

Now, all that's left to do is run make reset_overworlds before you compile your ROM with make.

You're done!


You can also apply this to porting overworlds from DPPt if you'd like.