Today I had a lot of client work so rather than dive into more complex parts of my game, I instead tinkered with setting up a custom character set for the C64 version.
Like many retro computers, the C64 allows you to reconfigure the default characterset (kind of like a font) to display special tile graphics in your game.

This is done by adding a character data array chars[] filled with hex or binary that contains the actual bits for the character definitions that are being loaded into memory.
Defining a New Characterset
There are two great options that I regularly turn to for creating custom characters, and those are petscii.krissz.hu, the browser app PETSCII, Sprite and Character editor and CBM PRG Studio. As the latter is not out of the box mac friendly and the former works anywhere, that is more convenient.
I used to spend many fun hours drawing on graph paper and doing the math manually but the days where I had time are long gone!

Either way, what we want as our export is just the bytes as an array, like so:


You can now follow the tutorials and edit the code right in your web browser with the Online Retro IDE
– No downloads, configuration, etc necessary, and it is free!
How the C Code Works:
- First, the character data is loaded into memory at 49152 (0xC000) using
memcpy - Then the RAM bank is configured to allow access to the character ROM area
- The VIC-II is told to use our custom character set at $2000
- Finally, the cursor character is set to use one of our custom characters
If you are following along at home compile with:
cl65 -t c64 -v -o chars.prg charset-c64.c && x64sc chars.prg
charset-c64.c
#include
#include
#include
#include
// Custom character set data - 8x8 pixel patterns for each character
unsigned char chars[]={
0x5C,0x57,0xE9,0x59,0x39,0x1E,0x14,0x36,
0x10,0x28,0x28,0x44,0x7C,0x44,0xEE,0x00,
0xFC,0x42,0x42,0x7C,0x42,0x42,0xFC,0x00,
0x38,0x44,0x82,0x80,0x82,0x44,0x38,0x00,
0xFC,0x42,0x42,0x42,0x42,0x42,0xFC,0x00,
0xFE,0x42,0x48,0x78,0x48,0x42,0xFE,0x00,
0xFE,0x42,0x48,0x78,0x48,0x40,0xE0,0x00,
0x3C,0x42,0x80,0x8E,0x82,0x42,0x3C,0x00,
0xEE,0x44,0x7C,0x44,0x44,0x44,0xEE,0x00,
0xFE,0x10,0x10,0x10,0x10,0x10,0xFE,0x00,
0x7C,0x10,0x10,0x10,0x90,0x90,0x60,0x00,
0xEE,0x44,0x48,0x70,0x48,0x44,0xEE,0x00,
0xE0,0x40,0x40,0x40,0x42,0x42,0xFE,0x00,
0xEE,0x54,0x54,0x54,0x44,0x44,0xEE,0x00,
0xEE,0x64,0x54,0x54,0x4C,0x4C,0xE4,0x00,
0x38,0x44,0x82,0x82,0x82,0x44,0x38,0x00,
0xFC,0x42,0x42,0x42,0x7C,0x40,0xE0,0x00,
0x38,0x44,0x82,0x82,0x92,0x4C,0x3A,0x00,
0xFC,0x42,0x42,0x42,0x7C,0x48,0xEE,0x00,
0x7C,0x82,0x80,0x7C,0x02,0x82,0x7C,0x00,
0xFE,0x92,0x10,0x10,0x10,0x10,0x38,0x00,
0xEE,0x44,0x44,0x44,0x44,0x44,0x38,0x00,
0xEE,0x44,0x44,0x28,0x28,0x28,0x10,0x00,
0xEE,0x44,0x44,0x54,0x54,0x6C,0x44,0x00,
0xEE,0x44,0x28,0x10,0x28,0x44,0xEE,0x00,
0xEE,0x44,0x28,0x28,0x10,0x10,0x38,0x00,
0xFE,0x84,0x08,0x10,0x20,0x42,0xFE,0x00,
0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,
0x0C,0x12,0x30,0x7C,0x30,0x62,0xFC,0x00,
0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,
0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,
0x00,0x10,0x30,0x7F,0x7F,0x30,0x10,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x00,
0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,
0xFE,0xD4,0xAA,0xD4,0xAA,0xD4,0xAA,0x00,
0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00,
0x00,0x00,0x70,0x5E,0x72,0x00,0x00,0x00,
0x08,0x94,0x48,0x2E,0x1A,0x24,0x6C,0x00,
0x06,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,
0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00,
0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00,
0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,
0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30,
0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,
0x00,0x03,0x06,0x0C,0x18,0x30,0x60,0x00,
0x38,0x44,0x82,0x82,0x82,0x44,0x38,0x00,
0x30,0x50,0x90,0x10,0x10,0x10,0xFE,0x00,
0x7C,0x82,0x02,0x7C,0x80,0x82,0xFE,0x00,
0xFE,0x84,0x08,0x1C,0x82,0x82,0x7C,0x00,
0x0C,0x18,0x28,0x4A,0xFE,0x0A,0x1C,0x00,
0xFE,0x82,0xFC,0x02,0x82,0x82,0x7C,0x00,
0x7C,0x82,0x80,0xFC,0x82,0x82,0x7C,0x00,
0xFE,0x84,0x08,0x08,0x10,0x10,0x38,0x00,
0x7C,0x82,0x82,0x7C,0x82,0x82,0x7C,0x00,
0x7C,0x82,0x82,0x82,0x7C,0x04,0x78,0x00,
0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,
0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30,
0x00,0x7E,0x00,0x3C,0x00,0x18,0x00,0x00,
0xEF,0x8A,0x0C,0x00,0xFE,0xAA,0x80,0x00,
0x00,0x00,0x18,0x00,0x3C,0x00,0x7E,0x00,
0x00,0x3C,0x7E,0xFE,0x7A,0x7E,0xFE,0x7E,
0x00,0x3C,0x7E,0xFE,0x7A,0x7E,0xFE,0x7E,
0x08,0x1C,0x3E,0x7F,0x7F,0x1C,0x3E,0x00,
0x00,0x7E,0xDE,0xFE,0xFE,0xFE,0x7E,0x14,
0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,
0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,
0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,
0x00,0x00,0x00,0xE0,0xF0,0x38,0x18,0x18,
0x18,0x18,0x1C,0x0F,0x07,0x00,0x00,0x00,
0x18,0x18,0x38,0xF0,0xE0,0x00,0x00,0x00,
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,
0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,
0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0xFF,0xFF,0x03,0x03,0x03,0x03,0x03,0x03,
0x08,0x18,0x99,0x7E,0x3C,0x3C,0x66,0x81,
0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,
0x36,0x7F,0x6B,0x63,0x2A,0x1C,0x08,0x00,
0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
0x00,0x00,0x00,0x07,0x0F,0x1C,0x18,0x18,
0xC3,0xE7,0x7E,0x3C,0x3C,0x7E,0xE7,0xC3,
0x00,0x3C,0x7E,0x66,0x66,0x7E,0x3C,0x00,
0x18,0x3C,0x72,0x62,0x24,0x18,0x3C,0x00,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x08,0x1C,0x3E,0x7F,0x3E,0x1C,0x08,0x00,
0x18,0x18,0x18,0xFF,0xFF,0x18,0x18,0x18,
0xC0,0xC0,0x30,0x30,0xC0,0xC0,0x30,0x30,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x00,0x0C,0x02,0x02,0x2C,0x7C,0xEC,0x00,
0xFF,0x7F,0x3F,0x1F,0x0F,0x07,0x03,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0xCC,0x87,0x30,0x66,0x08,0x93,0xC7,0x46,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x00,0x00,0x00,0x00,0xCC,0xCC,0x33,0x33,
0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x18,0x18,0x18,0x1F,0x1F,0x18,0x18,0x18,
0x00,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x0F,
0x18,0x18,0x18,0x1F,0x1F,0x00,0x00,0x00,
0x00,0x00,0x00,0xF8,0xF8,0x18,0x18,0x18,
0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,
0x00,0x00,0x00,0x1F,0x1F,0x18,0x18,0x18,
0x18,0x18,0x18,0xFF,0xFF,0x00,0x00,0x00,
0x00,0x00,0x00,0xFF,0xFF,0x18,0x18,0x18,
0x18,0x18,0x18,0xF8,0xF8,0x18,0x18,0x18,
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,
0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,
0x03,0x03,0x03,0x03,0x03,0x03,0xFF,0xFF,
0x00,0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0,
0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00,
0x18,0x18,0x18,0xF8,0xF8,0x00,0x00,0x00,
0xF0,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,
0xF0,0xF0,0xF0,0xF0,0x0F,0x0F,0x0F,0x0F,
0xC3,0x99,0x91,0x91,0x9F,0x99,0xC3,0xFF,
0xE7,0xC3,0x99,0x81,0x99,0x99,0x99,0xFF,
0x83,0x99,0x99,0x83,0x99,0x99,0x83,0xFF,
0xC3,0x99,0x9F,0x9F,0x9F,0x99,0xC3,0xFF,
0x87,0x93,0x99,0x99,0x99,0x93,0x87,0xFF,
0x81,0x9F,0x9F,0x87,0x9F,0x9F,0x81,0xFF,
0x81,0x9F,0x9F,0x87,0x9F,0x9F,0x9F,0xFF,
0xC3,0x99,0x9F,0x91,0x99,0x99,0xC3,0xFF,
0x99,0x99,0x99,0x81,0x99,0x99,0x99,0xFF,
0xC3,0xE7,0xE7,0xE7,0xE7,0xE7,0xC3,0xFF,
0xE1,0xF3,0xF3,0xF3,0xF3,0x93,0xC7,0xFF,
0x99,0x93,0x87,0x8F,0x87,0x93,0x99,0xFF,
0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x81,0xFF,
0x9C,0x88,0x80,0x94,0x9C,0x9C,0x9C,0xFF,
0x99,0x89,0x81,0x81,0x91,0x99,0x99,0xFF,
0xC3,0x99,0x99,0x99,0x99,0x99,0xC3,0xFF,
0x83,0x99,0x99,0x83,0x9F,0x9F,0x9F,0xFF,
0xC3,0x99,0x99,0x99,0x99,0xC3,0xF1,0xFF,
0x83,0x99,0x99,0x83,0x87,0x93,0x99,0xFF,
0xC3,0x99,0x9F,0xC3,0xF9,0x99,0xC3,0xFF,
0x81,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xFF,
0x99,0x99,0x99,0x99,0x99,0x99,0xC3,0xFF,
0x99,0x99,0x99,0x99,0x99,0xC3,0xE7,0xFF,
0x9C,0x9C,0x9C,0x94,0x80,0x88,0x9C,0xFF,
0x99,0x99,0xC3,0xE7,0xC3,0x99,0x99,0xFF,
0x99,0x99,0x99,0xC3,0xE7,0xE7,0xE7,0xFF,
0x81,0xF9,0xF3,0xE7,0xCF,0x9F,0x81,0xFF,
0xC3,0xCF,0xCF,0xCF,0xCF,0xCF,0xC3,0xFF,
0xF3,0xED,0xCF,0x83,0xCF,0x9D,0x03,0xFF,
0xC3,0xF3,0xF3,0xF3,0xF3,0xF3,0xC3,0xFF,
0xFF,0xE7,0xC3,0x81,0xE7,0xE7,0xE7,0xE7,
0xFF,0xEF,0xCF,0x80,0x80,0xCF,0xEF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xE7,0xE7,0xE7,0xE7,0xFF,0xFF,0xE7,0xFF,
0x99,0x99,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,
0x99,0x99,0x00,0x99,0x00,0x99,0x99,0xFF,
0xE7,0xC1,0x9F,0xC3,0xF9,0x83,0xE7,0xFF,
0x9D,0x99,0xF3,0xE7,0xCF,0x99,0xB9,0xFF,
0xC3,0x99,0xC3,0xC7,0x98,0x99,0xC0,0xFF,
0xF9,0xF3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,
0xF3,0xE7,0xCF,0xCF,0xCF,0xE7,0xF3,0xFF,
0xCF,0xE7,0xF3,0xF3,0xF3,0xE7,0xCF,0xFF,
0xFF,0x99,0xC3,0x00,0xC3,0x99,0xFF,0xFF,
0xFF,0xE7,0xE7,0x81,0xE7,0xE7,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xE7,0xCF,
0xFF,0xFF,0xFF,0x81,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xE7,0xFF,
0xFF,0xFC,0xF9,0xF3,0xE7,0xCF,0x9F,0xFF,
0xC3,0x99,0x91,0x89,0x99,0x99,0xC3,0xFF,
0xE7,0xE7,0xC7,0xE7,0xE7,0xE7,0x81,0xFF,
0xC3,0x99,0xF9,0xF3,0xCF,0x9F,0x81,0xFF,
0xC3,0x99,0xF9,0xE3,0xF9,0x99,0xC3,0xFF,
0xF9,0xF1,0xE1,0x99,0x80,0xF9,0xF9,0xFF,
0x81,0x9F,0x83,0xF9,0xF9,0x99,0xC3,0xFF,
0xC3,0x99,0x9F,0x83,0x99,0x99,0xC3,0xFF,
0x81,0x99,0xF3,0xE7,0xE7,0xE7,0xE7,0xFF,
0xC3,0x99,0x99,0xC3,0x99,0x99,0xC3,0xFF,
0xC3,0x99,0x99,0xC1,0xF9,0x99,0xC3,0xFF,
0xFF,0xFF,0xE7,0xFF,0xFF,0xE7,0xFF,0xFF,
0xFF,0xFF,0xE7,0xFF,0xFF,0xE7,0xE7,0xCF,
0xF1,0xE7,0xCF,0x9F,0xCF,0xE7,0xF1,0xFF,
0xFF,0xFF,0x81,0xFF,0x81,0xFF,0xFF,0xFF,
0x8F,0xE7,0xF3,0xF9,0xF3,0xE7,0x8F,0xFF,
0xC3,0x99,0xF9,0xF3,0xE7,0xFF,0xE7,0xFF,
0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,
0xF7,0xE3,0xC1,0x80,0x80,0xE3,0xC1,0xFF,
0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,
0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,
0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,
0xCF,0xCF,0xCF,0xCF,0xCF,0xCF,0xCF,0xCF,
0xF3,0xF3,0xF3,0xF3,0xF3,0xF3,0xF3,0xF3,
0xFF,0xFF,0xFF,0x1F,0x0F,0xC7,0xE7,0xE7,
0xE7,0xE7,0xE3,0xF0,0xF8,0xFF,0xFF,0xFF,
0xE7,0xE7,0xC7,0x0F,0x1F,0xFF,0xFF,0xFF,
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x00,0x00,
0x3F,0x1F,0x8F,0xC7,0xE3,0xF1,0xF8,0xFC,
0xFC,0xF8,0xF1,0xE3,0xC7,0x8F,0x1F,0x3F,
0x00,0x00,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
0x00,0x00,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
0xFF,0xC3,0x81,0x81,0x81,0x81,0xC3,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,
0xC9,0x80,0x80,0x80,0xC1,0xE3,0xF7,0xFF,
0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,0x9F,
0xFF,0xFF,0xFF,0xF8,0xF0,0xE3,0xE7,0xE7,
0x3C,0x18,0x81,0xC3,0xC3,0x81,0x18,0x3C,
0xFF,0xC3,0x81,0x99,0x99,0x81,0xC3,0xFF,
0xE7,0xE7,0x99,0x99,0xE7,0xE7,0xC3,0xFF,
0xF9,0xF9,0xF9,0xF9,0xF9,0xF9,0xF9,0xF9,
0xF7,0xE3,0xC1,0x80,0xC1,0xE3,0xF7,0xFF,
0xE7,0xE7,0xE7,0x00,0x00,0xE7,0xE7,0xE7,
0x3F,0x3F,0xCF,0xCF,0x3F,0x3F,0xCF,0xCF,
0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,
0xFF,0xFF,0xFC,0xC1,0x89,0xC9,0xC9,0xFF,
0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
0x33,0x33,0xCC,0xCC,0x33,0x33,0xCC,0xCC,
0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
0xFF,0xFF,0xFF,0xFF,0x33,0x33,0xCC,0xCC,
0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F,
0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
0xE7,0xE7,0xE7,0xE0,0xE0,0xE7,0xE7,0xE7,
0xFF,0xFF,0xFF,0xFF,0xF0,0xF0,0xF0,0xF0,
0xE7,0xE7,0xE7,0xE0,0xE0,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0x07,0x07,0xE7,0xE7,0xE7,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0xFF,0xFF,0xFF,0xE0,0xE0,0xE7,0xE7,0xE7,
0xE7,0xE7,0xE7,0x00,0x00,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0x00,0x00,0xE7,0xE7,0xE7,
0xE7,0xE7,0xE7,0x07,0x07,0xE7,0xE7,0xE7,
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,
0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,
0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,
0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0x00,0x00,
0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,
0xF0,0xF0,0xF0,0xF0,0xFF,0xFF,0xFF,0xFF,
0xE7,0xE7,0xE7,0x07,0x07,0xFF,0xFF,0xFF,
0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,
0x0F,0x0F,0x0F,0x0F,0xF0,0xF0,0xF0,0xF0
};
unsigned int key,i,x,y;
// Initialize the PETSCII character set (0-255) in screen memory
void petscii() {
// Set the screen colours (green on black)
bgcolor(0);
bordercolor(0);
textcolor(5);
// Clear the screen
clrscr();
// Output each character to screen memory
for(i=51200;i<51200+256;i++) {
POKE(i,i-51200);
}
}
void main() {
// Load our custom character set into memory at $C000 (49152)
// This is where the VIC-II will look for character definitions
memcpy(49152,&chars,sizeof(chars));
// Configure the C64's memory layout for custom character set:
// 1. Set up RAM bank for character ROM access
// CIA2 port A (56576) controls RAM bank selection
// Mask with 252 (11111100) to select the correct bank for $C000
POKE(56576,PEEK(57576)&252);
// 2. Configure VIC-II to use our custom character set
// 53272 is the VIC-II control register for character ROM location
// Setting to 32 tells VIC-II to use character ROM at $2000 (8192)
// This points to our custom character set loaded at $C000
POKE(53272,32);
// 3. Set the cursor character to use our custom character set
// 648 is the cursor character location in memory
// Setting to 200 makes cursor use character code 200 from our set
POKE(648,200);
// Output the redefined PETSCII characters to screen memory
petscii();
// Wait for a key press before exiting
key=cgetc();
}
POKE(56576,PEEK(57576)&252):- This sets up the RAM bank for the C64
- 56576 is the CIA2 port A register (DDR)
- It’s masking the current value with 252 (11111100) to set up the RAM bank for character ROM
POKE(53272,32):- This sets the character ROM location
- 53272 is the VIC-II control register
- Setting it to 32 tells the VIC-II to use the character ROM at $2000 (8192 decimal)
- This is where we’re loading our custom character set
POKE(648,200):- This sets the cursor character
- 648 is the cursor character location in memory
- Setting it to 200 makes the cursor use character code 200 from our custom character set
Implemented in My Rogue-Like Dungeon Game


As you can see above, I have most of the characterset implemented in-game. There are a few I need to draw, redraw, or otherwise decide on.
Of course, all things are up to change later as I test and share for playtesting. Software plans are always fluid when faced with the reality of users!
I started by just adding the characters to RAM if the compiler was for C64, but then I pondered how to translate the map characters to the changed tiles.
This is because the map is defined using ASCII characters, for example 'g' for goblin and 'r' for rat. I wanted to keep the actual alphanumeric characters (though I did draw new bitmaps for them to make it a nice fancy font) so rather than redefine 'g' I wanted to swap it out, but only when displayed.
// Translate the character C to a selected character from the
// new character set using a lookup table but only for c64 currently
void translate_cputcxy(int col, int row, char c) {
// if c64 then translate the character
#ifdef __C64__
c = translate_char(c);
#else
// pass to cputcxy without changes
#endif
cputcxy(col, row, c);
}
This was the first part of my solution. When the game needs to put a character at an X, Y coordinate it calls cputxy which is a conio.h function (or my function that works in its place). CC65 uses this library but I didn’t want to switch it out like I do on other platforms so instead I have an intermediary function that places the character and translates if C64.
For the translation, I intended to use a lookup table, which is a high-performance option. That was right up to actually doing the table and I slacked off and used a switch statement instead. Much more human-writable and readable. I can always create a lookup table later. I’ll also need to do the same thing for Atari as that also had its own PETSCII equivalent.
char translate_char(char c) {
// Translate characters to the new character set using a switch statement
#ifdef __C64__
switch(c) {
case 'h': return 'S';
case 'i': return 'X';
case '+': return '?';
case '*': return 'Q';
case 'k': return '%';
case 'g': return '&';
case 'r': return 126;
default: return c;
}
#else
return c;
#endif
}
When I get to the other platforms I can refactor, but for now this works.
I did discover I made a mistake. The question mark symbol is being used for the door graphic. Oops.
Just a little more tweaking and then I will set about creating more bad guys.
Having a variety of enemies will make a big difference to the fun and longevity of the game. Currently I have one that is random and another one which attacks you.
An idea I have in mind is a “Cultist” who would try to protect the idols that are our mission to collect. It could move to try and get between the closest idol and you. Not sure if the logic might be too much for 8 bit systems, but I am going to think about it.

Retro Rogue-Like: Modular Programming in C