#include #include #include #include #include "vga.h" #include "data.h" #include "entities.h" #include "effect.h" #include "player.h" #include "snake.h" #include "bat.h" #include "old.h" #include "bones.h" #include "pickup.h" #include "map.h" /* current map; set via map_init */ static uint8_t cmap[MAP_W * MAP_H]; static uint8_t gold[MAP_W * MAP_H]; static uint8_t total_gold; static uint8_t erase; static uint16_t ex, ey; static void (* const init[])(Entity *) = { snake_init, bat_init, old_init, bones_init, pickup_time_init, pickup_bonus_init, pickup_pickaxe_init, pickup_goldkey_init, pickup_silverkey_init, }; void map_init(const uint8_t map[]) { /* make a copy of the map data in RAM */ memcpy(cmap, map, MAP_W * MAP_H); /* make a copy of the gold data in RAM */ memcpy(gold, map + MAP_W * MAP_H, MAP_W * MAP_H); /* count how many pieces of gold on this map */ total_gold = 0; for (uint16_t i = 0; i < MAP_W * MAP_H; i++) /* gold is not 0xff */ if (gold[i] != 0xff) total_gold++; entities_init(); Entity *e; /* spawn entities, 0xff is the list terminator */ for ( const uint8_t *ent = map + MAP_W * MAP_H * 2; *ent != 0xff; ent += 4 ) { /* the player (entity 0) is not part of the entity system */ if (*ent == 0) { player_init(ent[1] * MAP_TILE_W, ent[2] * MAP_TILE_H, ent[3] & 1); continue; } e = entities_new(); #ifdef DEBUG if (!e) { set_mode(3); fprintf(stderr, "ERROR: run out of entities\n"); exit(1); } #endif e->ox = e->x = ent[1] * MAP_TILE_W; e->oy = e->y = ent[2] * MAP_TILE_H; e->dir = ent[3] & 1; init[*ent - 1](e); } erase = 0; } void map_render() { Rect src = { 0, 0, 160, 48 }; Rect dst = { 0, 0, 8, 8 }; for (uint8_t y = 0; y < MAP_H; y++) for (uint8_t x = 0; x < MAP_W; x++) { dst.x = x * MAP_TILE_W; dst.y = y * MAP_TILE_H + MAP_OFFS_Y; uint8_t t = cmap[x + y * MAP_W]; src.x = (t % MAP_TILESET_COLS) * MAP_TILE_W; src.y = (t / MAP_TILESET_COLS) * MAP_TILE_H; blitrc(binary_tiles_start, &src, &dst); t = gold[x + y * MAP_W]; /* not gold, skip! */ if (t == 0xff) continue; src.x = (t % MAP_TILESET_COLS) * MAP_TILE_W; src.y = (t / MAP_TILESET_COLS) * MAP_TILE_H; blitrc(binary_tiles_start, &src, &dst); } } uint8_t map_is_blocked(uint16_t x, uint16_t y) { return cmap[(x / MAP_TILE_W) + (y / MAP_TILE_H) * MAP_W] >= MAP_FIRST_BLOCKED; } uint8_t map_is_deadly(uint16_t x, uint16_t y) { return cmap[(x / MAP_TILE_W) + (y / MAP_TILE_H) * MAP_W] >= MAP_FIRST_DEADLY; } void map_erase() { if (!erase) return; Rect dst = { ex, ey, 8, 8 }; blit_copy(&dst); erase = 0; } uint8_t map_update_gold(uint16_t x, uint16_t y) { Rect src = { 0, 0, 160, 48 }; Rect dst = { 0, 0, 8, 8 }; uint16_t mx = x / MAP_TILE_W; uint16_t my = y / MAP_TILE_H; if (gold[mx + my * MAP_W] != 0xff) { /* this gold is collected */ gold[mx + my * MAP_W] = 0xff; /* erase the background */ dst.x = mx * MAP_TILE_W; dst.y = my * MAP_TILE_H + MAP_OFFS_Y; uint8_t t = cmap[mx + my * MAP_W]; src.x = (t % MAP_TILESET_COLS) * MAP_TILE_W; src.y = (t / MAP_TILESET_COLS) * MAP_TILE_H; blit_target(TARGET_BUFFER); blitrc(binary_tiles_start, &src, &dst); blit_target(TARGET_SCREEN); /* will be used by map_erase */ ex = dst.x; ey = dst.y; erase = 1; total_gold--; return 1; } return 0; } static void map_open_key(uint8_t top, uint8_t bottom) { Rect src = { 0, 0, 160, 48 }; Rect dst = { 0, 0, 16, 8 }; blit_target(TARGET_BUFFER); for (uint8_t y = 0; y < MAP_H; y++) for (uint8_t x = 0; x < MAP_W; x++) { uint8_t t = cmap[x + y * MAP_W]; if (t == top || t == bottom) { /* not solid */ cmap[x + y * MAP_W] = 0; cmap[x + 1 + y * MAP_W] = 0; dst.x = x * MAP_TILE_W; dst.y = y * MAP_TILE_H + MAP_OFFS_Y; /* top */ if (t == top) { src.x = 64; src.y = 0; effect_out_new(x * MAP_TILE_W, y * MAP_TILE_H); } else { /* bottom */ src.x = 32; src.y = 8; } blitrc(binary_tiles_start, &src, &dst); continue; } } blit_target(TARGET_SCREEN); } void map_open_goldkey() { map_open_key(45, 65); } void map_open_silverkey() { map_open_key(47, 67); } uint8_t map_is_complete() { return total_gold == 0; }