GameBoy exporter for Aseprite documentation

This document is a documentation for GameBoy exporter for Aseprite. It's supposed to be used with GBDK and is to be used for games for original (monochrome) GameBoy. While I can be used with GameBoy Color the palettes would have to be assigned manually.

Both the tool and this document need some improvements but it was useful for me already so maybe it'll be for you as well.

Installation

You can download the tool from itch.io and install it the standard Aseprite way. You can confirm that it was installed bu checking if Export2GbSpritesC is present under File menu in the window's topbar.

Files

Preparing image

example prepared file screenshot

An image is prepared with RGB Color Mode and it doesn't matter what size it is. I use color to indicate different logical parts of my sprites/tiles. Each tile is indicated with a slice. You can use shift+C shortcut to add/edit sliced (doubleclick to change its properties). Size of each slice MUST be of size 8x8 or integer multiplication of that. Each such slice will be exported as 16 integers (uint8_t, hexadecimal) in the final export file. Each pixel inside a slice will be mapped to GB palette: pure white to white; gray lighter than 128 to light gray; gray darker then 128 to dark gray; pure black to black. Technically the script only use red component of the pixel to determine the shade but it's highly recommended you just use colors where all 3 components are equal (white/gray/black).

The indexed color mode is not used so I can use color outside of slices (this part is never exported) to convey other information. Not every part of the image needs to be exported. For example: The purple section titled WIP is only some ideas and won't be epxorted; in the green HP section some tiles are only used to present how the tiles are supposed to be used. This workflow worked for me.

Naming the slices is important. You might want to split your sprites into multiple sections depending on your game. The most basic would be to split your slices into sprites and tiles. This can be accomplished with prefixing and putting a dot (.) between the prefix and the actual name. For example hero's icon tile name is m_hero and prefix is t (for tile, but you can have any prefixes you want as long as they are legal C language identifier) so the final slice name is t.m_hero.

hero tile slice name: t.m_hero

Likewise sprites are prefixed with s so the Necromancer (well, half of it as the other 12 tiles are mirrored) is named s.e_necromancer (e stands for enemy here)

You might want more sections if you want to change the tiles/sprites that are loaded to VRAM during the game (i.e. after the initial setup); but for a simple setup two sections will be enough.

Exporting

When you have all your sprites and tiles marked with slices you can just click FileExport2GbSpritesC and a export window will pop up:

export window

Path option let you choose where to save the file.

If the Include #defines is unchecked you'll loose all the information about particular slices, and will be left with just sections. This should be left checked for majority of cases.

The next 4 buttons map gb colors to different palette (from 0,1,2,3 to whatever is chosen). The thing is it's applied to all the slices and it's not that useful because usually you want different setup for different sprites (there is no reason to do this to tiles). This is not that useful. It's best to just keep it 0,1,2,3 (default value). This is what I did in the example file where I drew the enemies as I'd like to have them in the game and next to them there are slices with the same enemy but colors mapped manually (color 0 is always transparent). I'l try to rethink that fe/ature in the future but for now it is what it is.

Then you have 0123 and 3210 buttons. Those just set the palette buttons to those two default values

Finally the Export button does exactly what it says it does.

Exported file

sprites.c:
uint8_t TS_tiles[] =
{
  // 0x0000 :: s.beholder
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x18, 0x18, 0x3c, 0x14, 0x3e, 0x0c, 0x1e, 0x04, 0x0a, 0x06, 0x0d, 0x06, 0x09, 0x07, 0x0c,
  0x00, 0x01, 0x01, 0x02, 0x02, 0x07, 0x02, 0x05, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf0,
  0x00, 0x00, 0x00, 0x0f, 0x0f, 0x16, 0x09, 0x1f, 0x0b, 0x1f, 0x0f, 0x16, 0x00, 0x0f, 0x00, 0x00,
  0x01, 0x06, 0x01, 0x12, 0x13, 0xbf, 0x1b, 0xbe, 0x0f, 0x9e, 0x83, 0x4d, 0xcf, 0x2f, 0x61, 0x9e,
  0xf8, 0xb7, 0x7f, 0xfd, 0xbf, 0xfd, 0xff, 0xf2, 0xff, 0x7f, 0xf0, 0xbf, 0xe3, 0xff, 0xe7, 0x3f,
  0x00, 0x3d, 0x3d, 0x7a, 0x47, 0xfc, 0x56, 0xfd, 0x44, 0xfe, 0x38, 0x7c, 0x00, 0x38, 0x00, 0x00,
  0x4f, 0xf0, 0xbf, 0xfe, 0xff, 0x7f, 0x4f, 0xff, 0x2f, 0x71, 0x1f, 0x2f, 0x1f, 0x34, 0x1f, 0x2e,
  0xe7, 0xbf, 0xf3, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x9c, 0xf9, 0xc6, 0xc9, 0x3f, 0xc9, 0xbf,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x0f, 0x1b, 0x07, 0x1f, 0x13, 0x7f, 0x43, 0xf6, 0x61, 0xf2, 0x01, 0x62, 0x01, 0x07, 0x06, 0x0f,
  0x59, 0xff, 0x4d, 0xff, 0x6f, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x7f, 0x9f, 0x7f,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x06, 0x0d, 0x0c, 0x12, 0x10, 0x2c, 0x00, 0x30, 0x00, 0x03, 0x03, 0x07, 0x00, 0x07, 0x00, 0x00,
  0x9f, 0x7f, 0x17, 0xff, 0x55, 0xbf, 0x75, 0x8f, 0xfd, 0x92, 0x7f, 0xc6, 0x3f, 0xdf, 0x00, 0x3f,
  // 0x000f :: s.necromancer
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x08, 0x14, 0x10, 0x28, 0x10, 0x28, 0x00, 0x30, 0x10, 0x28,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x02, 0x05,
  0x08, 0x14, 0x1c, 0x22, 0x14, 0x2a, 0x34, 0x4a, 0x2c, 0x52, 0x28, 0x54, 0x18, 0x27, 0x06, 0x11,
  0x03, 0x05, 0x02, 0x05, 0x03, 0x0d, 0x0f, 0x1e, 0x1f, 0x23, 0x0d, 0x7b, 0x0f, 0x77, 0x5f, 0xa7,
  0x1f, 0x3b, 0x1f, 0x3e, 0x1f, 0x3f, 0x3d, 0x7f, 0x38, 0x7d, 0x38, 0x7d, 0x38, 0x7d, 0x38, 0x7d,
  0xf7, 0xcf, 0xff, 0x4f, 0xff, 0x4e, 0xff, 0xa7, 0xff, 0x32, 0xff, 0x9b, 0xff, 0xcb, 0xff, 0x3b,
  0x38, 0xf4, 0x70, 0xf8, 0x70, 0xb8, 0x30, 0x58, 0x30, 0x78, 0x30, 0x58, 0x30, 0x58, 0x20, 0x70,
  0x7f, 0x9b, 0x3f, 0x4b, 0x3f, 0x7f, 0x3f, 0x5b, 0x3f, 0x4f, 0x3f, 0x67, 0x3f, 0x7f, 0x7f, 0xbf,
  0x20, 0x70, 0x20, 0x50, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
  0x7f, 0xbf, 0x7f, 0xbf, 0x7f, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xbf,
  0x01, 0x03, 0x03, 0x05, 0x03, 0x07, 0x03, 0x07, 0x07, 0x1e, 0x1f, 0x2f, 0x03, 0x3e, 0x00, 0x03,
  0xff, 0xe7, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff,
};

#define TS_BEHOLDER 0x0000
#define TS_NECROMANCER 0x000f


uint8_t TT_tiles[] =
{
  // 0x0000 :: t.black
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  // 0x0001 :: t.chars_letters
  0xff, 0xff, 0xc3, 0xc3, 0x9d, 0x9d, 0x9d, 0x9d, 0x81, 0x81, 0x9d, 0x9d, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x83, 0x83, 0x99, 0x99, 0x83, 0x83, 0x99, 0x99, 0x83, 0x83, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xc1, 0xc1, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xc1, 0xc1, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x83, 0x83, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x83, 0x83, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x81, 0x81, 0x9f, 0x9f, 0x87, 0x87, 0x9f, 0x9f, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x81, 0x81, 0x9f, 0x9f, 0x87, 0x87, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xc1, 0xc1, 0x9f, 0x9f, 0x91, 0x91, 0x9d, 0x9d, 0xc1, 0xc1, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0x81, 0x81, 0x99, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xc3, 0xc3, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xc3, 0xc3, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xe1, 0xe1, 0xf3, 0xf3, 0xf3, 0xf3, 0xb3, 0xb3, 0xc7, 0xc7, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x99, 0x99, 0x9b, 0x9b, 0x87, 0x87, 0x9b, 0x9b, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x9d, 0x9d, 0x89, 0x89, 0x95, 0x95, 0x9d, 0x9d, 0x9d, 0x9d, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x99, 0x99, 0x89, 0x89, 0x91, 0x91, 0x99, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xc3, 0xc3, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0xc3, 0xc3, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x83, 0x83, 0x9d, 0x9d, 0x9d, 0x9d, 0x83, 0x83, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xc3, 0xc3, 0x9d, 0x9d, 0x95, 0x95, 0x9b, 0x9b, 0xc5, 0xc5, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x83, 0x83, 0x9d, 0x9d, 0x9d, 0x9d, 0x83, 0x83, 0x9d, 0x9d, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xc1, 0xc1, 0x9f, 0x9f, 0xc3, 0xc3, 0xf9, 0xf9, 0x83, 0x83, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x81, 0x81, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0xc3, 0xc3, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x9d, 0x9d, 0x9d, 0x9d, 0xc9, 0xc9, 0xe3, 0xe3, 0xf7, 0xf7, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x9d, 0x9d, 0x95, 0x95, 0x95, 0x95, 0x81, 0x81, 0xcb, 0xcb, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x99, 0x99, 0xdb, 0xdb, 0xe7, 0xe7, 0xdb, 0xdb, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0xc3, 0xc3, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x81, 0x81, 0xf3, 0xf3, 0xe7, 0xe7, 0xcf, 0xcf, 0x81, 0x81, 0xff, 0xff, 0xff, 0xff,
  // 0x001b :: t.chars_nums
  0xff, 0xff, 0xc3, 0xc3, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xc3, 0xc3, 0xff, 0xff,
  0xff, 0xff, 0xe7, 0xe7, 0xc7, 0xc7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xc3, 0xc3, 0xff, 0xff,
  0xff, 0xff, 0xc3, 0xc3, 0x99, 0x99, 0xf3, 0xf3, 0xe7, 0xe7, 0xcf, 0xcf, 0x81, 0x81, 0xff, 0xff,
  0xff, 0xff, 0xc3, 0xc3, 0x99, 0x99, 0xf3, 0xf3, 0xf9, 0xf9, 0x99, 0x99, 0xc3, 0xc3, 0xff, 0xff,
  0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x81, 0x81, 0xf9, 0xf9, 0xf9, 0xf9, 0xff, 0xff,
  0xff, 0xff, 0x81, 0x81, 0x9f, 0x9f, 0x83, 0x83, 0xf9, 0xf9, 0x99, 0x99, 0xc3, 0xc3, 0xff, 0xff,
  0xff, 0xff, 0xc3, 0xc3, 0x9f, 0x9f, 0x83, 0x83, 0x99, 0x99, 0x99, 0x99, 0xc3, 0xc3, 0xff, 0xff,
  0xff, 0xff, 0x81, 0x81, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xff, 0xff,
  0xff, 0xff, 0xc3, 0xc3, 0x99, 0x99, 0xc3, 0xc3, 0x99, 0x99, 0x99, 0x99, 0xc3, 0xc3, 0xff, 0xff,
  0xff, 0xff, 0xc3, 0xc3, 0x99, 0x99, 0x99, 0x99, 0xc1, 0xc1, 0xf9, 0xf9, 0xc3, 0xc3, 0xff, 0xff,
  // 0x0025 :: t.chars_symbols
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x9f, 0x9f, 0x9f, 0xbf, 0xbf, 0xff, 0xff,
  0xe7, 0xe7, 0xe7, 0xe7, 0xf7, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff,
  0x83, 0x83, 0xb3, 0xb3, 0xf3, 0xf3, 0xc3, 0xc3, 0xff, 0xff, 0xcf, 0xcf, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xf9, 0xf9, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf9, 0xf9, 0xff, 0xff,
  0xff, 0xff, 0x9f, 0x9f, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x9f, 0x9f, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xbf, 0xbf, 0xff, 0xff, 0xbf, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xef, 0xc7, 0xc7, 0xef, 0xef, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xf8, 0xfa, 0xfa, 0xf8, 0xf8, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xdf, 0xdf, 0xbf, 0xbf, 0x9f, 0x9f, 0xbf, 0xbf, 0xbf, 0xbf, 0xff, 0xff,
  // 0x0031 :: t.gray
  0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
  // 0x0032 :: t.hp_bar
  0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
  0xff, 0x00, 0xff, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xff, 0xff, 0xff, 0x00,
  0xff, 0x00, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0x00,
  0xff, 0x00, 0xff, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xff, 0xff, 0xff, 0x00,
  0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
  // 0x0037 :: t.hp_end
  0xff, 0xff, 0xff, 0x7f, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0x3f,
  // 0x0038 :: t.hp_enemy
  0xff, 0xfe, 0xc3, 0xc3, 0x81, 0x81, 0x8d, 0x8d, 0xad, 0xad, 0x81, 0x81, 0xdb, 0xdb, 0xff, 0xfe,
  // 0x0039 :: t.hp_heart
  0xff, 0x00, 0xff, 0x7f, 0xc9, 0x49, 0xc1, 0x41, 0xe3, 0x63, 0xf7, 0xb7, 0xff, 0xdf, 0xff, 0xe0,
  // 0x003a :: t.m_block
  0xff, 0x20, 0xff, 0x20, 0xff, 0x20, 0xff, 0xff, 0xff, 0x14, 0xff, 0x04, 0xff, 0x04, 0xff, 0xff,
  // 0x003b :: t.m_enemy
  0xff, 0xff, 0xc3, 0xc3, 0x81, 0x81, 0x8d, 0x8d, 0xad, 0xad, 0x81, 0x81, 0xdb, 0xdb, 0xff, 0xff,
  // 0x003c :: t.m_hero
  0xff, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0x81, 0x81, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0xff,
  // 0x003d :: t.m_question
  0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xfb, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff,
  // 0x003e :: t.m_stairs
  0xff, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xff, 0xff, 0xc3, 0xc3, 0xff, 0xff, 0x81, 0x81, 0xff, 0xff,
  // 0x003f :: t.nesw
  0xff, 0xff, 0xe7, 0xe7, 0xc3, 0xc3, 0x81, 0x81, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xf7, 0xf7, 0xf3, 0xf3, 0xc1, 0xc1, 0xc1, 0xc1, 0xf3, 0xf3, 0xf7, 0xf7, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0x81, 0x81, 0xc3, 0xc3, 0xe7, 0xe7, 0xff, 0xff,
  0xff, 0xff, 0xef, 0xef, 0xcf, 0xcf, 0x83, 0x83, 0x83, 0x83, 0xcf, 0xcf, 0xef, 0xef, 0xff, 0xff,
};

#define TT_BLACK 0x0000
#define TT_CHARS_LETTERS 0x0001
#define TT_CHARS_NUMS 0x001b
#define TT_CHARS_SYMBOLS 0x0025
#define TT_GRAY 0x0031
#define TT_HP_BAR 0x0032
#define TT_HP_END 0x0037
#define TT_HP_ENEMY 0x0038
#define TT_HP_HEART 0x0039
#define TT_M_BLOCK 0x003a
#define TT_M_ENEMY 0x003b
#define TT_M_HERO 0x003c
#define TT_M_QUESTION 0x003d
#define TT_M_STAIRS 0x003e
#define TT_NESW 0x003f

Please note that tile offsets defines are prefixed with TT_ and sprites are prefixed with TS_. This matches the prefix of the slices (t.m_hero → TT_M_HERO). Additionally each slice is marked as a comments. Each sprite/tile (8x8 pixels) is one line (16 chars).

Example

screenshot of example

Note how in the txt_xy macro TT_CHARS_LETTERS are used as offset but then modified by offset and starting 'a' char.

Please also note how SIZEs of both TT_tiles and TS_tiles are divided by 16 because each sprite consists of 16 8-bit numbers).

#include <gb/gb.h>

#define true 1
#define false 0
#define SIZE(x) (sizeof(x)/sizeof(*(x)))
#include "sprites.c"

#define txt_xy(x, y, offset) \
  set_bkg_tile_xy((x), (y), (uint8_t)TT_CHARS_LETTERS + offset - 'a');

void draw_hp(uint8_t x, uint8_t y, uint8_t is_enemy, uint8_t hp)
{
  if (hp > 128) hp = 128;
  set_bkg_tile_xy(x+0, y, is_enemy ? TT_HP_ENEMY : TT_HP_HEART);
  set_bkg_tile_xy(x+1, y, TT_HP_BAR + (hp / 32));
  set_bkg_tile_xy(x+2, y, TT_HP_END);
}

void spr_put(uint8_t nb, uint8_t base_t, uint8_t prop, uint8_t x, uint8_t y)
{
  move_sprite(nb, x, y);
  set_sprite_tile(nb, base_t);
  set_sprite_prop(nb, prop);
}

void _enemy_put_line(uint8_t nb, uint8_t base, uint8_t x, uint8_t y)
{
  spr_put(nb+0, base+0, 0,       x + 8*0, y);
  spr_put(nb+1, base+1, 0,       x + 8*1, y);
  spr_put(nb+2, base+1, S_FLIPX, x + 8*2, y);
  spr_put(nb+3, base+0, S_FLIPX, x + 8*3, y);
}

void draw_necromancer(uint8_t x, uint8_t y)
{
  _enemy_put_line(0, TS_NECROMANCER+0, x, y+0);
  _enemy_put_line(4, TS_NECROMANCER+2, x, y+8);
  _enemy_put_line(8, TS_NECROMANCER+4, x, y+16);
  _enemy_put_line(12, TS_NECROMANCER+6, x, y+24);
  _enemy_put_line(16, TS_NECROMANCER+8, x, y+32);
  _enemy_put_line(20, TS_NECROMANCER+10, x, y+40);
}


void main(void)
{
  DISPLAY_ON;
  OBP0_REG = 0b11000100;

  init_bkg(TT_BLACK);

  set_bkg_data(0, SIZE(TT_tiles)/16, TT_tiles);
  set_sprite_data(0, SIZE(TS_tiles)/16, TS_tiles);

  {
    txt_xy(4, 1, 'n');
    txt_xy(5, 1, 'e');
    txt_xy(6, 1, 'c');
    txt_xy(7, 1, 'r');
    txt_xy(8, 1, 'o');
    txt_xy(9, 1, 'm');
    txt_xy(10, 1, 'a');
    txt_xy(11, 1, 'n');
    txt_xy(12, 1, 'c');
    txt_xy(13, 1, 'e');
    txt_xy(14, 1, 'r');
  }

  SHOW_BKG;
  SHOW_SPRITES;

  uint8_t hp = 255;

  while(1) {
    hp--;
    draw_hp(16, 3, true, hp);
    draw_hp(1, 3, false, hp + 128);

    draw_necromancer(70, 60+ ((hp / 16) % 2 ? 3 : 0));

    wait_vbl_done();
  }
}