123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- /*
- * maps.c
- * Duality
- *
- * Copyright (C) 2025 Thomas Buck <thomas@xythobuz.de>
- *
- * 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.
- *
- * See <http://www.gnu.org/licenses/>.
- */
-
- #include <gbdk/platform.h>
- #include <string.h>
- #include "gb/gb.h"
- #include "score.h"
- #include "title_map.h"
- #include "bg_map.h"
- #include "numbers_fnt.h"
- #include "text_fnt.h"
- #include "git.h"
- #include "main.h"
- #include "maps.h"
-
- #define MAX_DIGITS 7
- #define LINE_WIDTH 10
-
- // TODO inverted score color not visible on DMG
-
- BANKREF(maps)
-
- const unsigned char num_attr_1[104] = {
- 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
- 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
- 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
- 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
- 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,
- 0x81,0x81,0x81,0x81,
- };
-
- const unsigned char num_attr_2[104] = {
- 0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,
- 0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,
- 0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,
- 0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,
- 0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,
- 0x82,0x82,0x82,0x82,
- };
-
- const palette_color_t num_pal_inv[4] = {
- //RGB8( 0, 0, 0), RGB8(248,252,248), RGB8( 0, 0, 0), RGB8( 0, 0, 0)
- RGB8( 0, 0, 0), RGB8( 0, 0, 0), RGB8(248,252,248), RGB8( 0, 0, 0)
- };
-
- static uint8_t fnt_off = 0;
-
- void map_title(void) NONBANKED {
- SWITCH_ROM(BANK(title_map));
- set_bkg_palette(OAMF_CGB_PAL0, title_map_PALETTE_COUNT, title_map_palettes);
- set_bkg_data(0, title_map_TILE_COUNT, title_map_tiles);
- set_bkg_attributes(0, 0, title_map_MAP_ATTRIBUTES_WIDTH, title_map_MAP_ATTRIBUTES_HEIGHT, title_map_MAP_ATTRIBUTES);
- set_bkg_tiles(0, 0, title_map_WIDTH / title_map_TILE_W, title_map_HEIGHT / title_map_TILE_H, title_map_map);
- }
-
- void map_game(void) NONBANKED {
- SWITCH_ROM(BANK(bg_map));
- set_bkg_palette(OAMF_CGB_PAL0, bg_map_PALETTE_COUNT, bg_map_palettes);
- set_bkg_data(0, bg_map_TILE_COUNT, bg_map_tiles);
- set_bkg_attributes(0, 0, bg_map_MAP_ATTRIBUTES_WIDTH, bg_map_MAP_ATTRIBUTES_HEIGHT, bg_map_MAP_ATTRIBUTES);
- set_bkg_tiles(0, 0, bg_map_WIDTH / bg_map_TILE_W, bg_map_HEIGHT / bg_map_TILE_H, bg_map_map);
- }
-
- void win_init(uint8_t is_splash) NONBANKED {
- fnt_off = is_splash ? title_map_TILE_COUNT : bg_map_TILE_COUNT;
-
- SWITCH_ROM(BANK(numbers_fnt));
- set_bkg_palette(OAMF_CGB_PAL0 + bg_map_PALETTE_COUNT, numbers_fnt_PALETTE_COUNT, numbers_fnt_palettes);
- set_win_data(fnt_off, numbers_fnt_TILE_COUNT, numbers_fnt_tiles);
-
- SWITCH_ROM(BANK(maps));
- set_bkg_palette(OAMF_CGB_PAL0 + bg_map_PALETTE_COUNT + numbers_fnt_PALETTE_COUNT, numbers_fnt_PALETTE_COUNT, num_pal_inv);
-
- if (is_splash) {
- SWITCH_ROM(BANK(text_fnt));
- set_win_data(fnt_off + numbers_fnt_TILE_COUNT, text_fnt_TILE_COUNT, text_fnt_tiles);
- }
- }
-
- static void set_win_based(uint8_t x, uint8_t y, uint8_t w, uint8_t h,
- const uint8_t *tiles, uint8_t base_tile, uint8_t tile_bank,
- const uint8_t *attributes, uint8_t attr_bank) NONBANKED {
- SWITCH_ROM(attr_bank);
- VBK_REG = VBK_ATTRIBUTES;
- set_win_tiles(x, y, w, h, attributes);
-
- SWITCH_ROM(tile_bank);
- VBK_REG = VBK_TILES;
- set_win_based_tiles(x, y, w, h, tiles, base_tile);
- }
-
- static void character(uint8_t c, uint8_t pos, uint8_t x_off, uint8_t y_off, uint8_t is_black) NONBANKED {
- uint8_t off = c * text_fnt_WIDTH / text_fnt_TILE_W;
-
- set_win_based(x_off + (pos * text_fnt_WIDTH / text_fnt_TILE_W), y_off,
- text_fnt_WIDTH / text_fnt_TILE_W, 1,
- text_fnt_map + off, fnt_off + numbers_fnt_TILE_COUNT, BANK(text_fnt),
- (is_black ? num_attr_2 : num_attr_1) + off, BANK(maps));
-
- set_win_based(x_off + (pos * text_fnt_WIDTH / text_fnt_TILE_W), y_off + 1,
- text_fnt_WIDTH / text_fnt_TILE_W, 1,
- text_fnt_map + off + (sizeof(text_fnt_map) / 2), fnt_off + numbers_fnt_TILE_COUNT, BANK(text_fnt),
- (is_black ? num_attr_2 : num_attr_1) + off, BANK(maps));
- }
-
- static void str3(uint16_t name, uint8_t x_off, uint8_t y_off,
- uint8_t is_black_a, uint8_t is_black_b, uint8_t is_black_c) NONBANKED {
- character((name >> 10) & 0x1F, 0, x_off, y_off, is_black_a);
- character((name >> 5) & 0x1F, 1, x_off, y_off, is_black_b);
- character((name >> 0) & 0x1F, 2, x_off, y_off, is_black_c);
- }
-
- static void digit(uint8_t val, uint8_t pos, uint8_t x_off, uint8_t y_off, uint8_t is_black) NONBANKED {
- uint8_t off = val * numbers_fnt_WIDTH / numbers_fnt_TILE_W;
-
- set_win_based(x_off + (pos * numbers_fnt_WIDTH / numbers_fnt_TILE_W), y_off,
- numbers_fnt_WIDTH / numbers_fnt_TILE_W, 1,
- numbers_fnt_map + off, fnt_off, BANK(numbers_fnt),
- (is_black ? num_attr_2 : num_attr_1) + off, BANK(maps));
-
- set_win_based(x_off + (pos * numbers_fnt_WIDTH / numbers_fnt_TILE_W), y_off + 1,
- numbers_fnt_WIDTH / numbers_fnt_TILE_W, 1,
- numbers_fnt_map + off + (sizeof(numbers_fnt_map) / 2), fnt_off, BANK(numbers_fnt),
- (is_black ? num_attr_2 : num_attr_1) + off, BANK(maps));
- }
-
- static void str_l(const char *s, uint8_t len, uint8_t x_off, uint8_t y_off, uint8_t is_black) NONBANKED {
- for (uint8_t n = 0; (*s) && (n < LINE_WIDTH) && (n < len); n++) {
- char c = *(s++);
- if ((c >= 'A') && (c <= 'Z')) {
- c = c - 'A' + 'a';
- }
- if ((c >= '0') && (c <= '9')) {
- digit(c - '0', n, x_off, y_off, is_black);
- } else if ((c >= 'a') && (c <= 'z')) {
- character(c - 'a', n, x_off, y_off, is_black);
- }
- }
- }
-
- static void str(const char *s, uint8_t x_off, uint8_t y_off, uint8_t is_black) NONBANKED {
- str_l(s, 0xFF, x_off, y_off, is_black);
- }
-
- static void str_center(const char *s, uint8_t y_off, uint8_t is_black) NONBANKED {
- uint8_t n = strlen(s);
- if (n > LINE_WIDTH) n = LINE_WIDTH;
- str(s, LINE_WIDTH - n, y_off, is_black);
- }
-
- static void str_lines(const char *s, uint8_t y_off, uint8_t is_black) NONBANKED {
- if (strlen(s) > 10) {
- str(s, 0, y_off, is_black);
- str_center(s + 10, y_off + 2, is_black);
- } else {
- str_center(s, y_off, is_black);
- }
- }
-
- static uint8_t number(int32_t score, uint8_t x_off, uint8_t y_off, uint8_t is_black) NONBANKED {
- // TODO can not set numbers larger than int16 max?!
- //score = 32767 + 1; // wtf?!
-
- uint8_t len = 0;
- uint8_t digits[MAX_DIGITS];
- do {
- digits[len++] = score % 10L;
- score = score / 10L;
- if (len >= MAX_DIGITS) {
- break;
- }
- } while (score > 0);
-
- // if the number was too large for our buffer don't draw anything
- if (score > 0) {
- return 0;
- }
-
- uint8_t off = (x_off == 0xFF) ? (LINE_WIDTH - len) : ((x_off == 0xFE) ? ((LINE_WIDTH * 2) - (len * 2)) : x_off);
- for (uint8_t i = 0; i < len; i++) {
- digit(digits[len - i - 1], i, off, y_off, is_black);
- }
-
- return 8 * len * 2;
- }
-
- static void fill_win(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t tile, uint8_t attr) NONBANKED {
- VBK_REG = VBK_ATTRIBUTES;
- fill_win_rect(x, y, w, h, attr);
- VBK_REG = VBK_TILES;
- fill_win_rect(x, y, w, h, tile);
- }
-
- void win_splash_draw(int32_t lowest, int32_t highest) NONBANKED {
- // reuse full black and white tiles at 0 and 1 from splash bg
- fill_win(0, 0, 10, 2, 0, 0x00);
- fill_win(10, 0, 10, 2, 1, 0x00);
-
- number(lowest, 0, 0, 1);
- number(highest, 0xFE, 0, 0);
- }
-
- void win_score_clear(uint8_t is_black) NONBANKED {
- set_win_based(0, 0,
- title_map_WIDTH / title_map_TILE_W, title_map_HEIGHT / title_map_TILE_H,
- title_map_map, 0, BANK(title_map), title_map_MAP_ATTRIBUTES, BANK(title_map));
-
- str_center(is_black ? "black" : "white", 1, is_black);
- }
-
- void win_score_draw(struct scores score, uint8_t off, uint8_t is_black) NONBANKED {
- str3(score.name, 0, 4 + off * 3, is_black, is_black, is_black);
- number(is_black ? -score.score : score.score, 7, 4 + off * 3, is_black);
- }
-
- void win_about(void) NONBANKED {
- set_win_based(0, 0,
- title_map_WIDTH / title_map_TILE_W, title_map_HEIGHT / title_map_TILE_H,
- title_map_map, 0, BANK(title_map), title_map_MAP_ATTRIBUTES, BANK(title_map));
-
- str_center("Duality", 0, 1);
- str_center("xythobuz", 2, 1);
-
- SWITCH_ROM(BANK(git));
- char line_buff[2 * LINE_WIDTH + 1] = {0};
- strncpy(line_buff, git_version, 2 * LINE_WIDTH);
-
- str_lines(line_buff, 7, 0);
-
- str_l(&__DATE__[7], 4, 0, 14, 1); // year (4)
- str_l(&__DATE__[0], 3, (4 * 2) + 1, 14, 1); // month (3)
- str_l(&__DATE__[4], 2, (7 * 2) + 2, 14, 1); // day (2)
-
- str(__TIME__, 4, 16, 0);
- }
-
- void win_debug(void) NONBANKED {
- set_win_based(0, 0,
- title_map_WIDTH / title_map_TILE_W, title_map_HEIGHT / title_map_TILE_H,
- title_map_map, 0, BANK(title_map), title_map_MAP_ATTRIBUTES, BANK(title_map));
-
- // TODO paging when more options added
-
- str_center("Debug Menu", 0, 0);
-
- char name_buff[DEBUG_ENTRY_NAME_LEN + 2 + 1] = {0};
- for (uint8_t i = 0; (i < DEBUG_ENTRY_COUNT) && (i < 7); i++) {
- SWITCH_ROM(BANK(main));
- strncpy(name_buff, debug_entries[i].name, DEBUG_ENTRY_NAME_LEN + 1);
-
- uint8_t n_len = strlen(name_buff);
- name_buff[n_len] = ' ';
- name_buff[n_len + 1] = (debug_flags & debug_entries[i].flag) ? '1' : '0';
- name_buff[n_len + 2] = '\0';
- n_len += 2;
-
- str(name_buff, (LINE_WIDTH - n_len) * 2, (i * 2) + 3, (debug_menu_index == i) ? 1 : 0);
- }
- }
-
- void win_name(int32_t score) NONBANKED {
- set_win_based(0, 0,
- title_map_WIDTH / title_map_TILE_W, title_map_HEIGHT / title_map_TILE_H,
- title_map_map, 0, BANK(title_map), title_map_MAP_ATTRIBUTES, BANK(title_map));
-
- str_center("score", 1, score < 0);
- number(score < 0 ? -score : score, 0xFF, 3, score < 0);
-
- str_center("enter", 6, score < 0);
- str_center("name", 8, score < 0);
-
- str_center("start ok", 16, score < 0);
- }
-
- void win_name_draw(uint16_t name, uint8_t is_black, uint8_t pos) NONBANKED {
- str3(name, LINE_WIDTH - 3, 12,
- (pos == 0) ? !is_black : is_black,
- (pos == 1) ? !is_black : is_black,
- (pos == 2) ? !is_black : is_black);
- }
-
- uint8_t win_game_draw(int32_t score) NONBANKED {
- fill_win(0, 0, 10, 2, fnt_off + numbers_fnt_TILE_COUNT, 0x81);
-
- uint8_t is_black = 0;
- if (score < 0) {
- score = -score;
- is_black = 1;
- }
-
- return number(score, 0, 0, is_black);
- }
|