/* Kitsune's Curse Copyright (C) 2020-2023 Juan J. Martinez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "aplib.h" #include "main.h" #include "splib.h" #include "tiles.h" #define LOCAL #include "maps.h" #include "stage.h" #include "entities.h" // working map (using 4-bit per tile), 8x8 static uint8_t ml; static const unsigned char *map_ents; static uint8_t blocked; void _expand_map() { uint8_t *b = (uint8_t *)BUFF_ADDR; uint16_t i; // uncompress at the end of the working area aplib_uncompress(b, (uint8_t *)(map[cmap] + 2)); // expand from 4-bpt to 8-bpt for (i = 0; i < TMW * TMH; i += 2) { wmap[i] = (*b >> 4) + ts; wmap[i + 1] = (*b & 0x0f) + ts; b++; } } void draw_map() { uint8_t i, j, k, c, m; validate_screen(); // draw the bottom to top; invalidate is LIFO for (j = TMH; j; --j) { k = j - 1; for (i = 0; i < TMW; ++i) { c = wmap[i + k * TMW]; // only if is part of a tileset if (c < LAST_TILE_TILESET) { m = c & 15; // special tiles: bricks if (!m || m == 12) { if (k & 1) ++c; } } else if (c == BLOCKED_OPEN_DOOR) c = BLOCKED_OPEN_DOOR_TILE; put_tile(bgtiles[c], get_tile_xy(i, k)); } } } void init_map(uint8_t m) { #ifdef DEBUG pad_numbers(wmap, 2, m); set_text_ink(15, 15, 15); put_text(wmap, 0, 192); #endif cmap = m; // map length (not including tileset or flags) ml = map[cmap][0]; // tileset ts = (map[cmap][1] & 0x0f) << 4; blocked = map[cmap][1] & 0xf0; // map_ents map_ents = map[cmap] + 2 + ml; _expand_map(); exit_up = cmap - WMAPS; offset_up = 0; exit_down = cmap + WMAPS; offset_down = 0; init_entities(); spawn_entities(map_ents); draw_map(); } void set_map(uint8_t m) { init_map(m); if (!player_h) { // IMPORTANT: set new player coords before // calling to set_map! // checkpoint smap = cmap; spx = px; spy = py; sdir = dir; } draw_entities(); update_screen(); } void set_map_tile(uint8_t x, uint8_t y, uint8_t tile) { wmap[x + (y * TMW)] = tile; } static struct st_entity *sp_mit; static uint8_t group, last_blocked; uint8_t is_map_blocked(uint8_t x, uint8_t y) { last_blocked = wmap[(x >> 3) + ((y >> 3) * TMW)]; if (last_blocked == BLOCKED_OPEN_DOOR) return BLOCKED_OPEN_DOOR; if (last_blocked < LAST_TILE_TILESET) { if((last_blocked & 15) > LAST_NON_SOLID) return 1; } else // from this on, all solids if (last_blocked > SWITCH_DOOR_TILE - 1) return 1; group = 0; for (sp_mit = sp_used; sp_mit; sp_mit = sp_mit->n) { // this requires ET_DOOR and ET_PLATFORM to go grouped switch (sp_mit->type) { case ET_PLATFORM: group = 1; if (check_for_point(sp_mit, x, y, 16, 8)) return BLOCKED_PLATFORM; break; case ET_DOOR: group = 1; if (check_for_point(sp_mit, x, y, 8, 32) && (sp_it || !keys || magic)) return 1; break; default: if (group) return 0; break; } } return 0; } uint8_t is_map_deadly(uint8_t x, uint8_t y) { last_deadly = wmap[(x >> 3) + ((y >> 3) * TMW)]; // deadly tiles are at the end of the tile table return (last_deadly < 64 && last_deadly > DEADLY_TILE_BASE - 1); } uint8_t exit_map_left() { if (blocked & BLOCKED_LEFT) return 0; opx = px = (uint8_t)(TW * TMW - 8); set_map(cmap - 1); return 1; } uint8_t exit_map_right() { if (blocked & BLOCKED_RIGHT) return 0; opx = px = 0; set_map(cmap + 1); return 1; } uint8_t exit_map_up() { if (blocked & BLOCKED_UP) return 0; px += offset_up; opx = px; opy = py = (uint8_t)(TH * TMH - 24); set_map(exit_up); return 1; } uint8_t exit_map_down() { if (blocked & BLOCKED_DOWN) return 0; px += offset_down; opx = px; opy = py = 0; set_map(exit_down); return 1; }