Playing through Pokemon as a kid, walking through the different towns really made you feel like you were exploring another world. As you go between cities, the houses change colours and you see different characters hanging out. Every time I played, I wondered if there was some way to make a huge world map that had the exact same detail as when you were playing. Then with a bit of time over a holiday, I hacked up a script to do exactly that.
The Pokémon mod community
Extracting map data, rendering each one and then putting it all together from any game can seem like a pretty big task but luckily, the Pokémon modding community had a ton of resources to help. Because Pokémon is so widely played by kids who love tinkering around, there are a ton of programs and tutorials to help you modify the game in a ton of different ways. There are simple mods, like changing dialog text or which Pokémon you encounter in fields, and then there are more advanced mods, like changing maps completely to resemble a different world or creating new NPCs with entirely new behaviour. In that respect then, our challenge looks both simple and very different from what others in the community are doing.
Some of the resources I used:
- Advance Map A Windows program that lets you examine and modify maps of the game. I used this as a reference map renderer because it was much faster than opening up the game in an emulator and going to a specific map. It is also useful to create test maps to run through my own renderer.
- 0x3526A8 This magic number is a pointer to the list of maps and is key to rendering a map. I believe I originally found this post mentioning it and later pored over this reference when looking for other interesting data. (Finding this pointer statically or dynamically would definitely be an interesting exercise.)
Understanding palettes, tiles, and blocks
The Pokémon Fire Red game takes up only 16 MB. While its graphics are not as amazing as modern games like Monument Valley, storing all the maps, Pokémon images, animations, and gameplay routines in 16 MB is a tall order. As a result of minifying the game, building up the drawing of a map has various components and each can be reused to save space.
To help understand the difference between a palette, tile and block, let’s examine this tiny map rendering at different levels.
The smallest unit in rendering is a pixel and simply put, palettes define the colour of each pixel. Tiles are stored as greyscale images but palettes make them actually colourful. Changing the palette will usually result in a similar but visually different tile that can be reused for a different purpose. For example, in our image the red Pokémon Center and the blue Pokémart have the exact same pattern for their roof. This is done by using the same tiles but with a different palette.
An interesting example of palette switching that you might be familiar with is original Game Boy games running on a Game Boy Color. Because the Game Boy only had 4 colours but the Game Boy Color allowed so many, the Game Boy Color applied a palette that you could change by pressing a certain combination of buttons at startup.
Tiles and blocks
In Fire Red, a block is 16x16 pixels (the size of your character) and tiles are each 8x8 pixels. A block actually has two parts: a ground part and a 3D part. Each part is drawn with a 2x2 grid of tiles thus requiring 8 tiles for a block total. (To help understand the difference between a ground and 3D part, imagine a signpost which has a grass texture for its ground part but the sign part for its 3D.)
Amazements, surprises and quirks along the way
Some tidbits of trivia that I picked up along the way:
- the small levels all fit together without overlapping or leaving huge spaces! There’s no actual need for the towns and routes to all connect together like on a real map but somehow the creators made sure it did!
- tiles within blocks can be flipped, which is mainly used for drawing road borders or the sides of buildings.
- nlzss compression on the tileset: to save even more space, the tileset is compressed inline. Luckily there are libraries online with the relevant decompression methods.
- there are a bunch of extra maps that are never used in the game but still in the executable. The Pokédex in the binary also contains 250 Pokémon even though only 151 are used.
The final result
After running pokemap.py with the ROM, this huge image is produced: (click through for full resolution)
All the code required to generate the map is on GitHub.