Tile artwork
Source: src/dungeon_tiles.c · 128 lines · 8 functions.
Module responsibility
Converts generated cell shapes and variants into artwork paths and validates the required tile files.
Module entry points
These functions are exposed to the rest of the Dungeon system. Open one to follow its decisions and helper calls.
How to read these diagrams
Each function has an expandable structural diagram derived from the current C source. Decisions split into True and False, loop bodies are indented, and arrows show statement order.
These are source diagrams before preprocessing, not runtime traces. Callback execution, task scheduling and macro expansion are not inferred.
Functions in this file
singleExitSuffix() · source line 8
static const char *singleExitSuffix(uint8_t exits)
- Select a case
exitsEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case DUNGEON_EXIT_NORTH: - Exit this function
return "n"; - Case / label
case DUNGEON_EXIT_EAST: - Exit this function
return "e"; - Case / label
case DUNGEON_EXIT_SOUTH: - Exit this function
return "s"; - Case / label
case DUNGEON_EXIT_WEST: - Exit this function
return "w"; - Case / label
default: - Exit this function
return NULL;
Read original function source
static const char *singleExitSuffix(uint8_t exits)
{
switch (exits) {
case DUNGEON_EXIT_NORTH: return "n";
case DUNGEON_EXIT_EAST: return "e";
case DUNGEON_EXIT_SOUTH: return "s";
case DUNGEON_EXIT_WEST: return "w";
default: return NULL;
}
}roundRoomExitSuffix() · source line 19
static const char *roundRoomExitSuffix(uint8_t exits)
Calls into this documentation:
- Decision
exits == DUNGEON_EXIT_EASTTrue- Exit this function
return "w";
FalseContinue after this decision.
- Decision
exits == DUNGEON_EXIT_WESTTrue- Exit this function
return "e";
FalseContinue after this decision.
- Exit this function
return singleExitSuffix(exits);
Read original function source
static const char *roundRoomExitSuffix(uint8_t exits)
{
if (exits == DUNGEON_EXIT_EAST) return "w";
if (exits == DUNGEON_EXIT_WEST) return "e";
return singleExitSuffix(exits);
}passageSuffix() · source line 26
static const char *passageSuffix(uint8_t exits)
- Select a case
exitsEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST: - Exit this function
return "ne"; - Case / label
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH: - Exit this function
return "ns"; - Case / label
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_WEST: - Exit this function
return "nw"; - Case / label
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH: - Exit this function
return "es"; - Case / label
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST: - Exit this function
return "ew"; - Case / label
case DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: - Exit this function
return "sw"; - Case / label
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH: - Exit this function
return "nes"; - Case / label
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST: - Exit this function
return "new"; - Case / label
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: - Exit this function
return "nsw"; - Case / label
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: - Exit this function
return "esw"; - Case / label
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: - Exit this function
return "nsew"; - Case / label
default: - Exit this function
return NULL;
Read original function source
static const char *passageSuffix(uint8_t exits)
{
switch (exits) {
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST: return "ne";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH: return "ns";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_WEST: return "nw";
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH: return "es";
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST: return "ew";
case DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: return "sw";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH: return "nes";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST: return "new";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: return "nsw";
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: return "esw";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: return "nsew";
default: return NULL;
}
}straightSuffix() · source line 44
static const char *straightSuffix(uint8_t exits)
- Decision
exits == (DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH)True- Exit this function
return "ns";
FalseContinue after this decision.
- Decision
exits == (DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST)True- Exit this function
return "ew";
FalseContinue after this decision.
- Exit this function
return NULL;
Read original function source
static const char *straightSuffix(uint8_t exits)
{
if (exits == (DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH)) return "ns";
if (exits == (DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST)) return "ew";
return NULL;
}makePath() · source line 51
static bool makePath(char *path, size_t path_size, const char *format, const char *suffix)
- Decision
path == NULL || path_size == 0 || suffix == NULLTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
const int written = snprintf(path, path_size, format, suffix); - Exit this function
return written > 0 && (size_t)written < path_size;
Read original function source
static bool makePath(char *path, size_t path_size, const char *format, const char *suffix)
{
if (path == NULL || path_size == 0 || suffix == NULL) return false;
const int written = snprintf(path, path_size, format, suffix);
return written > 0 && (size_t)written < path_size;
}resolveDungeonTilePath() · source line 58
bool resolveDungeonTilePath(const DungeonCell *cell, char *path, size_t path_size)
Calls into this documentation:
- Decision
cell == NULLTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
const char *suffix = NULL; - Select a case
cell->tileTypeEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case DUNGEON_TILE_PASSAGE: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Passage_way/Pass_%s_result.jpg", passageSuffix(cell->exits)); - Case / label
case DUNGEON_TILE_ROOM_OPEN: - Execute
suffix = cell->exits == (DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST) ? "nsew" : straightSuffix(cell->exits); - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Room_open/Room_%s_result.jpg", suffix); - Case / label
case DUNGEON_TILE_DEAD_END_PASSAGE: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_passage_way/Dend_%s_result.jpg", singleExitSuffix(cell->exits)); - Case / label
case DUNGEON_TILE_DEAD_END_ROOM_ROUND: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room_rnd/DE_room-rnd_%s_result.jpg", roundRoomExitSuffix(cell->exits)); - Case / label
case DUNGEON_TILE_DEAD_END_ROOM_SQUARE: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room_sqr/R1_DE_%s_result.jpg", singleExitSuffix(cell->exits)); - Case / label
case DUNGEON_TILE_DEAD_END_ROOM_ROUND_ALT: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room1_rnd/DE_room1_rnd_%s_result.jpg", singleExitSuffix(cell->exits)); - Case / label
case DUNGEON_TILE_ENTRANCE: - Case / label
case DUNGEON_TILE_EXIT: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Ent_Exit/EE_%s_result.jpg", singleExitSuffix(cell->exits)); - Case / label
case DUNGEON_TILE_STAIRS_UP: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_U_%s_result.jpg", straightSuffix(cell->exits)); - Case / label
case DUNGEON_TILE_STAIRS_DOWN: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_D_%s_result.jpg", straightSuffix(cell->exits)); - Case / label
case DUNGEON_TILE_STAIRS_BOTH: - Exit this function
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_UD_%s_result.jpg", straightSuffix(cell->exits)); - Case / label
default: - Exit this function
return false;
Read original function source
bool resolveDungeonTilePath(const DungeonCell *cell, char *path, size_t path_size)
{
if (cell == NULL) return false;
const char *suffix = NULL;
switch (cell->tileType) {
case DUNGEON_TILE_PASSAGE:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Passage_way/Pass_%s_result.jpg", passageSuffix(cell->exits));
case DUNGEON_TILE_ROOM_OPEN:
suffix = cell->exits == (DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST) ? "nsew" : straightSuffix(cell->exits);
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Room_open/Room_%s_result.jpg", suffix);
case DUNGEON_TILE_DEAD_END_PASSAGE:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_passage_way/Dend_%s_result.jpg", singleExitSuffix(cell->exits));
case DUNGEON_TILE_DEAD_END_ROOM_ROUND:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room_rnd/DE_room-rnd_%s_result.jpg", roundRoomExitSuffix(cell->exits));
case DUNGEON_TILE_DEAD_END_ROOM_SQUARE:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room_sqr/R1_DE_%s_result.jpg", singleExitSuffix(cell->exits));
case DUNGEON_TILE_DEAD_END_ROOM_ROUND_ALT:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room1_rnd/DE_room1_rnd_%s_result.jpg", singleExitSuffix(cell->exits));
case DUNGEON_TILE_ENTRANCE:
case DUNGEON_TILE_EXIT:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Ent_Exit/EE_%s_result.jpg", singleExitSuffix(cell->exits));
case DUNGEON_TILE_STAIRS_UP:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_U_%s_result.jpg", straightSuffix(cell->exits));
case DUNGEON_TILE_STAIRS_DOWN:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_D_%s_result.jpg", straightSuffix(cell->exits));
case DUNGEON_TILE_STAIRS_BOTH:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_UD_%s_result.jpg", straightSuffix(cell->exits));
default: return false;
}
}validateDungeonTiles() · source line 89
bool validateDungeonTiles(DungeonTileValidationStats *stats)
Calls into this documentation:
- Decision
stats == NULLTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
memset(stats, 0, sizeof(*stats)); - Execute
bool checked[DUNGEON_TILE_STAIRS_BOTH + 1U][16] = {{false}}; - Execute
DungeonWorld *world = getDungeonWorld(); - Execute
char path[sizeof(stats->problemPath)]; - FOR loop
unsigned floor = 0; floor < DUNGEON_FLOOR_COUNT; ++floorRepeat body while the loop condition permits; then continue below.
- FOR loop
unsigned y = 0; y < DUNGEON_HEIGHT; ++yRepeat body while the loop condition permits; then continue below.
- FOR loop
unsigned x = 0; x < DUNGEON_WIDTH; ++xRepeat body while the loop condition permits; then continue below.
- Execute
const DungeonCell *cell = &world->floors[floor].cells[y][x]; - Decision
cell->tileType > DUNGEON_TILE_STAIRS_BOTH || cell->exits > 0x0FU || !resolveDungeonTilePath(cell, path, sizeof(path))True- Execute
++stats->unsupportedCells; - Next loop iteration
continue;
FalseContinue after this decision.
- Execute
++stats->resolvedCells; - Decision
checked[cell->tileType][cell->exits]True- Next loop iteration
continue;
FalseContinue after this decision.
- Execute
checked[cell->tileType][cell->exits] = true; - Execute
++stats->uniqueImages; - Execute
struct stat information; - Decision
stat(path, &information) == 0True- Next loop iteration
continue;
FalseContinue after this decision.
- Execute
++stats->missingImages; - Decision
stats->problemPath[0] == '\0'True- Execute
strncpy(stats->problemPath, path, sizeof(stats->problemPath) - 1U); - Execute
stats->problemPath[sizeof(stats->problemPath) - 1U] = '\0';
FalseContinue after this decision.
- Execute
stats->error = stats->unsupportedCells ? DUNGEON_TILE_UNSUPPORTED : stats->missingImages ? DUNGEON_TILE_IMAGE_MISSING : DUNGEON_TILE_OK; - Execute
stats->valid = stats->error == DUNGEON_TILE_OK; - Exit this function
return stats->valid;
Read original function source
bool validateDungeonTiles(DungeonTileValidationStats *stats)
{
if (stats == NULL) return false;
memset(stats, 0, sizeof(*stats));
bool checked[DUNGEON_TILE_STAIRS_BOTH + 1U][16] = {{false}};
DungeonWorld *world = getDungeonWorld();
char path[sizeof(stats->problemPath)];
for (unsigned floor = 0; floor < DUNGEON_FLOOR_COUNT; ++floor) for (unsigned y = 0; y < DUNGEON_HEIGHT; ++y) for (unsigned x = 0; x < DUNGEON_WIDTH; ++x) {
const DungeonCell *cell = &world->floors[floor].cells[y][x];
if (cell->tileType > DUNGEON_TILE_STAIRS_BOTH || cell->exits > 0x0FU || !resolveDungeonTilePath(cell, path, sizeof(path))) {
++stats->unsupportedCells;
continue;
}
++stats->resolvedCells;
if (checked[cell->tileType][cell->exits]) continue;
checked[cell->tileType][cell->exits] = true;
++stats->uniqueImages;
struct stat information;
if (stat(path, &information) == 0) continue;
++stats->missingImages;
if (stats->problemPath[0] == '\0') {
strncpy(stats->problemPath, path, sizeof(stats->problemPath) - 1U);
stats->problemPath[sizeof(stats->problemPath) - 1U] = '\0';
}
}
stats->error = stats->unsupportedCells ? DUNGEON_TILE_UNSUPPORTED :
stats->missingImages ? DUNGEON_TILE_IMAGE_MISSING : DUNGEON_TILE_OK;
stats->valid = stats->error == DUNGEON_TILE_OK;
return stats->valid;
}dungeonTileErrorText() · source line 120
const char *dungeonTileErrorText(DungeonTileError error)
- Select a case
errorEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case DUNGEON_TILE_OK: - Exit this function
return "OK"; - Case / label
case DUNGEON_TILE_UNSUPPORTED: - Exit this function
return "Unsupported tile"; - Case / label
case DUNGEON_TILE_IMAGE_MISSING: - Exit this function
return "Missing image"; - Case / label
default: - Exit this function
return "Unknown error";
Read original function source
const char *dungeonTileErrorText(DungeonTileError error)
{
switch (error) {
case DUNGEON_TILE_OK: return "OK";
case DUNGEON_TILE_UNSUPPORTED: return "Unsupported tile";
case DUNGEON_TILE_IMAGE_MISSING: return "Missing image";
default: return "Unknown error";
}
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "dungeon_tiles.h"
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#define DUNGEON_TILE_ROOT "/spiffs/dungeon/dungeon_tiles"
static const char *singleExitSuffix(uint8_t exits)
{
switch (exits) {
case DUNGEON_EXIT_NORTH: return "n";
case DUNGEON_EXIT_EAST: return "e";
case DUNGEON_EXIT_SOUTH: return "s";
case DUNGEON_EXIT_WEST: return "w";
default: return NULL;
}
}
static const char *roundRoomExitSuffix(uint8_t exits)
{
if (exits == DUNGEON_EXIT_EAST) return "w";
if (exits == DUNGEON_EXIT_WEST) return "e";
return singleExitSuffix(exits);
}
static const char *passageSuffix(uint8_t exits)
{
switch (exits) {
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST: return "ne";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH: return "ns";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_WEST: return "nw";
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH: return "es";
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST: return "ew";
case DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: return "sw";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH: return "nes";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST: return "new";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: return "nsw";
case DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: return "esw";
case DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST: return "nsew";
default: return NULL;
}
}
static const char *straightSuffix(uint8_t exits)
{
if (exits == (DUNGEON_EXIT_NORTH | DUNGEON_EXIT_SOUTH)) return "ns";
if (exits == (DUNGEON_EXIT_EAST | DUNGEON_EXIT_WEST)) return "ew";
return NULL;
}
static bool makePath(char *path, size_t path_size, const char *format, const char *suffix)
{
if (path == NULL || path_size == 0 || suffix == NULL) return false;
const int written = snprintf(path, path_size, format, suffix);
return written > 0 && (size_t)written < path_size;
}
bool resolveDungeonTilePath(const DungeonCell *cell, char *path, size_t path_size)
{
if (cell == NULL) return false;
const char *suffix = NULL;
switch (cell->tileType) {
case DUNGEON_TILE_PASSAGE:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Passage_way/Pass_%s_result.jpg", passageSuffix(cell->exits));
case DUNGEON_TILE_ROOM_OPEN:
suffix = cell->exits == (DUNGEON_EXIT_NORTH | DUNGEON_EXIT_EAST | DUNGEON_EXIT_SOUTH | DUNGEON_EXIT_WEST) ? "nsew" : straightSuffix(cell->exits);
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Room_open/Room_%s_result.jpg", suffix);
case DUNGEON_TILE_DEAD_END_PASSAGE:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_passage_way/Dend_%s_result.jpg", singleExitSuffix(cell->exits));
case DUNGEON_TILE_DEAD_END_ROOM_ROUND:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room_rnd/DE_room-rnd_%s_result.jpg", roundRoomExitSuffix(cell->exits));
case DUNGEON_TILE_DEAD_END_ROOM_SQUARE:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room_sqr/R1_DE_%s_result.jpg", singleExitSuffix(cell->exits));
case DUNGEON_TILE_DEAD_END_ROOM_ROUND_ALT:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/DE_room1_rnd/DE_room1_rnd_%s_result.jpg", singleExitSuffix(cell->exits));
case DUNGEON_TILE_ENTRANCE:
case DUNGEON_TILE_EXIT:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Ent_Exit/EE_%s_result.jpg", singleExitSuffix(cell->exits));
case DUNGEON_TILE_STAIRS_UP:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_U_%s_result.jpg", straightSuffix(cell->exits));
case DUNGEON_TILE_STAIRS_DOWN:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_D_%s_result.jpg", straightSuffix(cell->exits));
case DUNGEON_TILE_STAIRS_BOTH:
return makePath(path, path_size, DUNGEON_TILE_ROOT "/Stairs/Stairs_UD_%s_result.jpg", straightSuffix(cell->exits));
default: return false;
}
}
bool validateDungeonTiles(DungeonTileValidationStats *stats)
{
if (stats == NULL) return false;
memset(stats, 0, sizeof(*stats));
bool checked[DUNGEON_TILE_STAIRS_BOTH + 1U][16] = {{false}};
DungeonWorld *world = getDungeonWorld();
char path[sizeof(stats->problemPath)];
for (unsigned floor = 0; floor < DUNGEON_FLOOR_COUNT; ++floor) for (unsigned y = 0; y < DUNGEON_HEIGHT; ++y) for (unsigned x = 0; x < DUNGEON_WIDTH; ++x) {
const DungeonCell *cell = &world->floors[floor].cells[y][x];
if (cell->tileType > DUNGEON_TILE_STAIRS_BOTH || cell->exits > 0x0FU || !resolveDungeonTilePath(cell, path, sizeof(path))) {
++stats->unsupportedCells;
continue;
}
++stats->resolvedCells;
if (checked[cell->tileType][cell->exits]) continue;
checked[cell->tileType][cell->exits] = true;
++stats->uniqueImages;
struct stat information;
if (stat(path, &information) == 0) continue;
++stats->missingImages;
if (stats->problemPath[0] == '\0') {
strncpy(stats->problemPath, path, sizeof(stats->problemPath) - 1U);
stats->problemPath[sizeof(stats->problemPath) - 1U] = '\0';
}
}
stats->error = stats->unsupportedCells ? DUNGEON_TILE_UNSUPPORTED :
stats->missingImages ? DUNGEON_TILE_IMAGE_MISSING : DUNGEON_TILE_OK;
stats->valid = stats->error == DUNGEON_TILE_OK;
return stats->valid;
}
const char *dungeonTileErrorText(DungeonTileError error)
{
switch (error) {
case DUNGEON_TILE_OK: return "OK";
case DUNGEON_TILE_UNSUPPORTED: return "Unsupported tile";
case DUNGEON_TILE_IMAGE_MISSING: return "Missing image";
default: return "Unknown error";
}
}