aeropaws.dog/blog

Kirby's Dream Land 2 Level Data - First Look

June 5, 2025

I have started working on a KDL2 level editor that provides an easy to use UI for editing tiles and objects in the game. My motivation for starting this project actually stemmed from wanting to develop a Kirby Super Star level editor. The current level editor that I know about, PopStarCore, is a very useful editor. However, it is pretty buggy, only in Japanese, and is closed sourced. I wanted to make a level editor that has more features and has the code open to anyone so that it can be preserved in the future if someone else wants to take on the project.

As much as I wanted to make this level editor for KSS, I felt like it would be more practical if my resources were first put toward making a level editor for a game that doesn’t even have an editor yet. The two options that I saw for this were KDL2 and KDL3, both games that I really enjoy and don’t have level editors. I chose KDL2 because I wanted to choose a game that was simpler to work with, given that it is a GameBoy game. This is my first time ever developing a program as large of a scale as this, so choosing the GameBoy game felt like an easier choice for me (in addition, KDL3 uses SA-1, and from my time working with KSS, it can be a hassle to deal with).

In addition to developing an editor for a game that does not have one yet, I thought it would be just as useful to document how the game works and map out any RAM addresses or code so that future work on this game could be done more easily. As far as I am aware, KDL2 does not have much documented about it online, whereas KSS has a lot done already. I wanted to challenge myself to see how hard it would be to figure out how level data is structured and loaded into the game from ROM, and so far it has been really cool to figure out without the help of any previous documentation (I am not sure if any exists out there, but I didn’t use any).

As for why I wanted to create this level editor, it is because I believe that many casual players enjoy this game fondly, and I would like for there to be a tool for those who aren’t familiar with ROM hacking to create their own levels and hacks easily. I like how simple the game is, and I think that this simplicity could lead to a lot of cool and unique levels. It is unfortunate that Kirby games do not have as big of a hacking scene as other games like Super Mario World or Super Metroid, and I believe that part of it is due to the lack of tools and documentation available to many older Kirby games that makes it very hard to realistically do anything. I definitely cannot do it by myself, but I would like to push for developing tools and documenting the code of these older games, because I believe they deserve better. Kirby is a beloved franchise to many people, just like any other, so I would like to see a ROM hacking scene as big as any other franchise.

Anyways, enough about my blabbering regarding why I am doing all of this. I think now is a good time to go over my detailed analysis on what I have figured out so far regarding level data, how it is loaded, how objects are handled, and much more. If you don’t care about the hacky technical side of what I am doing, you can stop reading here.

Warning - Technical Garbage

I did all of my research on the Japanese version of the game for no particular reason. I have no idea if anything I have found so far will differ in the English release, but I will eventually figure this out at a later time.

First of all, one important thing to note is that a lot of data in this game is compressed. This makes sense given that space was pretty expensive at this time, so if compression is an option it makes sense to use it. And it’s honestly really interesting that things are even compressed, because just from playing the game it is hard to tell. This sounds really silly, because how could you possibly tell things are compressed just from playing the game? Well, I am used to KSS making it extremely obvious that things are being decompressed due to the long loading times (If you summon a helper, you will notice the game pausing briefly when doing the summon. This is because the helper graphics are decompressing first, which takes time to do). KDL2, for the most part, has very fast loads. Nothing really seems slow to load and everything is pretty spontaneous, so it surprised me that pretty much everything is compressed given how fast everything loads (it could be because data and graphics are generally smaller in size compared to KSS).

Thankfully, the decompression algorithm is documented, as many games developed by HAL use the exact same algorithm. This algorithm is known as inhal (compression) and exhal (decompression), which are the names of the extremely useful tools developed by Devin Acker to compress and decompress the graphics in several games developed by HAL. I was really happy to see that KDL2 uses the exact same compression, as if it were anything else it would’ve made my life much harder. And it seems like Devin was already aware that KDL2 uses this compression.

For those who aren’t experienced with ROM hacking, I will explain what pointers are, because they are used very frequently when loading levels. Pointers are numbers in the ROM that refer to a specific location in the ROM itself, which could either be an address or an offset (but most of the time in our situation it will be an exact address location). Pointers are important in the case of loading level data because when loading data, the game needs to know where each level’s data starts, so pointers are used to tell the game where to load information from.

Since there are a ton of rooms in the game, we will have a pointer associated with each room, and having all of these pointers lined up together in the ROM is called a pointer table (this table starts at 0x210BB in the ROM). This is very useful because when loading a specific level, the game would say for example “load the 3rd room in the ROM data”, which would grab the 3rd pointer in the pointer table, and this pointer would lead to the data of the 3rd room in the ROM (note that this isn’t the “3rd room” that the player would see, the data in the ROM technically does not need to follow the exact order in which they appear in gameplay). Most of the time, the room that is loaded is based on what room is set in the data for the door that was entered, which I will explain later.

Main Level Data

After utilizing the pointer, the game is now at the level data, which is usually structured like this:

Object data

Level data

Tile data

This is a lot of stuff, so I will explain it!

Now, what will make zero sense is the fact that this sequence actually works backwards based on how it looks visually here. The room loading process goes in this order:

It actually makes perfect sense to load the data in this order, but what doesn’t make sense is why they decided to save the data completely backwards in the ROM. This would’ve made things easier probably, but it’s whatever. It would make more sense if I explained it in the order of execution, rather than in the order it appears in the ROM.

Tile data: The tile data is what tile layout is loaded into the room, simple enough. The layouts are compressed in the ROM, so these are decompressed and loaded starting from RAM address 0xB300. Data from 0xB300 to 0xB7FF are reserved for level data, so rooms can have a maximum tile count of about 1280, though it is technically less than this because there will at least be a 1 tile invisible wall around the borders of the room, making the tiles around the perimeter inaccessible. Additionally, the first tile of the room data is unused completely, and I am still not sure what its purpose is, if it even has one (it might be a remnant of the decompression, I am not sure though). The compression algorithm also has a way to determine the end of the data set, so that is how it knows where the end of the room data is.

Level data: The first six bytes of the level data section have to do with the room size. The first two bytes are the number of “screens” in the room, which are 16x16 areas. These values are essentially saying “how many 16x16 areas are there in this room horizontally and vertically”. The other four bytes have to do with the room size as well, but what is interesting is that these are the bytes that actually affect the length and width of the room. The first two screen count bytes deal with tile collision and loading in objects. This means that you still have to manually make the room length the size that you want, and you can actually make the room smaller than the amount of screens you have, which makes no sense. I’m not sure why the developers decided to make the number of screens and the room size two independent values, when they could have programmed a way to instead calculate the room length based on the screen number. So overall, dealing with these values can be a bit confusing, since you have to adjust both of these parameters instead of just one.

The three pointers at the end of the level data each go to the room’s tileset, object data, and door locations. Tileset loading is pretty straightforward but a bit complex, I will explain it later. The object location pointer is very silly, because it more often than not points to the object data that is right before the level data, so this just feels like a waste of space when they could’ve made this much more efficient. The door location pointer goes to all of the door coordinates in the room and where those doors bring you to, which is also a bit complicated so I will touch on this later.

Object data: The first block of level data in the ROM has to do with object spawns (enemies, collectables, etc). The first two parameters, graphics and object count, are not a fixed number of bytes, so FF is used to denote the end of the list. So first, the game would list off whatever object graphics need to be loaded in, and then put the FF there to say “the graphics list is done, so now the next set of bytes are going to be the number of objects”. The objects list is the same, with FF used to tell the game the list ended.

KDL2 is very convenient with object graphics, because you can load in whatever graphics you want in any area. If you wanted to load in the graphics for Waddle Dee, Kracko, and Broom Hatter, you would just use the three byte values associated with each object’s graphics in this section.

Now, object count is a different story, and is a bit confusing. This section is basically saying “how many objects are in each screen of the room”. So if you were to put the bytes “06 01 FF” here, this would be saying there are 6 objects in the first screen of the room and 1 object in the second screen, with FF ending the list. There are many different room sizes in KDL2. Some are strictly horizontal, some are strictly vertical, some are just giant areas with horizontal and vertical scrolling. The game counts each screen of the room from the top left to the bottom right to account for all types of scrolling. It counts each screen horizontally first, then once it gets to the end of the room, it shifts down a row vertically and continues from there. Note that this is dependent on what values are set for the number of screens in the previous section.

The X and Y coordinates of the objects and the object type are all listed without a byte to indicate the end of the list, and this is because it instead references the previous object count to figure out all of the values. Based on our previous example, if we have “06 01 FF”, that means there are 7 objects total in the room, so it will go through this list expecting 7 of each byte. First the 7 X coordinates are read, then the Y, and then the object type. All three of these values are then written to RAM: 0xCA00 for X, 0xCB00 for Y, and 0xCC00 for the type of object. Note that the game goes through these lists sequentially, so the 7th byte in all of these lists will be correlated to the object in the second screen of the room.

Tilesets

So that covers all of the main important level data. Now to cover tilesets:

Because tilesets are typically reused across several levels, it makes sense to not have them grouped closely to the main level data (though we could say the same for the door data but… whatever). The tileset data is structured like so:

I can’t believe they did it again… the developers literally have the pointer to the tileset data just go to another pointer to go to the tileset graphics that are right before that. I feel like at that point why don’t you just… point to the graphics in the first place.

The graphics of the tileset are compressed in the same format as the level data. These graphics are decompressed and written to VRAM. Once this is done, the tile data then gets decompressed. This data consists of the graphics used for each tile and the properties for the tile (is the tile sloped, is it water, does it hurt you, etc). In addition to the collision data, each tile in the game is comprised of four graphics, and in order for the game to know what each tile is consisted of, it reads it from this data. The four corners of each tile’s data is written to RAM: 0xC500, 0xC600, 0xC700, and 0xC800. The collision data is written to 0xC900.

Within the tile data of a given room, you will notice that each tile is designated a number, and this number corresponds to the data in each of these sections. So for example, if we wanted to find the data for tile 5 of a given tileset, we would view this data in RAM with the offset of 5, so it would view 0xC505, 0xC605, etc. It will read from these five “banks” of data to construct the tile. This is useful for looking into what each tile’s graphics are. I plan to program a way to pull the graphics data from the ROM itself in the level editor, rather than hardcoding these graphics in myself, so this information will be utilized at some point eventually.

Doors

And here’s how door data is structured:

Most of these values are self explanatory, but I’ll cover some of it as it could be confusing.

The first two bytes indicate the X and Y position of the door currently being entered. Whenever you enter a door, the game will search the current room’s door list until it finds a door that matches Kirby’s current X and Y, which is how the game determines what door you are going through.

The stage number is the current stage being entered when entering from a world hub, so this byte is completely omitted if it is a door inside a stage.

Door type has a lot of options, so I will list them all here too!

These are a lot of values, and some that are very interesting, as there is an entire door type just used for the final boss shooting segment. What’s also interesting is that 06 and 07 are normally never hardcoded in the ROM, but are instead calculated. Level exits are usually labeled as 0x03 or 0x04, but on a first clear, the game will add 0x03 to this number, so that it will equal the door type of 0x06 or 0x07. Very interesting.

The room to appear in, as well as the X and Y coordinates, are pretty easy to understand. It is simply the location you will appear in when you enter the door.

So now what…

Welp, I just rambled a ton about stuff that not many people care about, probably. But this has been a lot of fun so far! I think the most challenging part for me will actually be building the level editor interface itself, rather than doing the edits manually in the ROM.

I think my next steps are going to be trying to load the KDL2 tilesets so that you can visualize them. This seems really basic, but I think this would be a great first step in getting familiar with how I can make the interface for the level editor. I am not very well experienced with developing UI programs, so this should be interesting. I hope that whatever tool I could build will be satisfactory enough, haha. Don’t be surprised if it’s extremely jank or something.

I am hoping that my documentation of this information will be found by someone, and maybe they can utilize it for something. I would love to see more people ROM hacking Kirby games in general :3

© AeroPaws 2025