From 72f5ec3ce777fc05150856f1841e60b0f5c9f8f7 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sat, 18 Jul 2026 13:34:49 -0400 Subject: restore old frontends as they were Minimal changes, just enough to get them building and running. Signed-off-by: Andrew Opalach --- frontends/curses/curses_ui.c | 258 +++++++++++++++++++++++++++++++++++++++++++ frontends/curses/meson.build | 17 +++ 2 files changed, 275 insertions(+) create mode 100644 frontends/curses/curses_ui.c create mode 100644 frontends/curses/meson.build (limited to 'frontends/curses') diff --git a/frontends/curses/curses_ui.c b/frontends/curses/curses_ui.c new file mode 100644 index 0000000..91792f5 --- /dev/null +++ b/frontends/curses/curses_ui.c @@ -0,0 +1,258 @@ +/* very simple curses interface, DAS is not functional because you cant detect + * key up presses on the terminal, there are 2 character sets, ASCII_COMPATIBLE + * for no UTF-8 chars and the normal which will look better on a platform that can + * support UTF-8. Color support is limited because I havent figured out colors yet */ + +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif +#include + +#define CETRIS_HI_RES 1 +#define CETRIS_ENABLE_DAS 0 +#include +#include + +#include "../timer.c" + +#define WIN_COL 55 +#define WIN_LINE 25 + +//#define ASCII_COMPATIBLE +#ifdef ASCII_COMPATIBLE +#define BLOCK "[]" +#define PLAY_FIELD_STR " /--------------------\\ /----------------\\ \n"\ + " | | | | \n"\ + " | | \\----------------/ \n"\ + " | | \n"\ + " | | \n"\ + " | | /---------\\ \n"\ + " | | | | \n"\ + " | | | | \n"\ + " | | | | \n"\ + " | | | | \n"\ + " | | \\---------/ \n"\ + " | | \n"\ + " | | \n"\ + " | | \n"\ + " | | \n"\ + " | | \n"\ + " | | \n"\ + " | | \n"\ + " | | \n"\ + " | | \n"\ + " | | \n"\ + " \\--------------------/" +#else +#define BLOCK "[]" +#define PLAY_FIELD_STR " ┏━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━score━━━━━┓ \n"\ + " ┃ ┃ ┃ ┃ \n"\ + " ┃ ┃ ┗━━━━━━━━━━━━━━━┛ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ ┏━━━queue━━━┓ \n"\ + " ┃ ┃ ┃ ┃ \n"\ + " ┃ ┃ ┃ ┃ \n"\ + " ┃ ┃ ┃ ┃ \n"\ + " ┃ ┃ ┃ ┃ \n"\ + " ┃ ┃ ┗━━━━━━━━━━━┛ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┃ ┃ \n"\ + " ┗━━━━━━━━━━━━━━━━━━━━┛ " +#endif + +#define X_OFFSET 8 +#define Y_OFFSET -2 + +ctrs_game game = { 0 }; +bool is_paused = false; + +void curses_init() { + setlocale(LC_CTYPE, ""); + initscr(); + curs_set(0); + noecho(); + keypad(stdscr, TRUE); + timeout(2); + +#ifdef _WIN32 // only resize manually on windows + resize_term(WIN_LINE, WIN_COL); +#endif + + start_color(); + init_pair(MINO_O, COLOR_YELLOW, COLOR_BLACK); + init_pair(MINO_Z, COLOR_RED, COLOR_BLACK); + init_pair(MINO_S, COLOR_GREEN, COLOR_BLACK); + init_pair(MINO_T, COLOR_MAGENTA, COLOR_BLACK); + init_pair(MINO_L, COLOR_WHITE, COLOR_BLACK); // should be orange + init_pair(MINO_I, COLOR_CYAN, COLOR_BLACK); + init_pair(MINO_J, COLOR_BLUE, COLOR_BLACK); + clear(); +} + +#ifdef _WIN32 +DWORD WINAPI game_loop(void* data) { + while(1) { + Sleep((1.0/60.0) * 1000.0); + if (!is_paused) ctrs_update_game_tick(&game); + } + return 0; +} +#else +void *game_loop(void) { + struct timespec start_time, end_time; + clock_gettime(CLOCK_MONOTONIC_RAW, &start_time); + while (1) { + clock_gettime(CLOCK_MONOTONIC_RAW, &end_time); + long nsec_elapsed = (end_time.tv_sec - start_time.tv_sec) * (long)1e9 + (end_time.tv_nsec - start_time.tv_nsec); + game.timer = nsec_elapsed / 1000; + game.tick = nsec_elapsed / 1000000; + if (!ctrs_update_game_tick(&game)) { + break; + } + usleep(1000); + } + return 0; +} +#endif + + +void draw_board() { + mvaddstr(0, 0, PLAY_FIELD_STR); + + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + if ((game.current.m[y]>>(3 - x))&1) { + int draw_x = X_OFFSET + ((x + game.current.pos.x) * 2); + int draw_y = Y_OFFSET + (y + game.current.pos.y) - game.config.board_visible; + int ghost_y = Y_OFFSET + (y + game.current.ghost_y) - game.config.board_visible; + attron(A_DIM); + mvaddstr(ghost_y, draw_x, BLOCK); + attroff(A_DIM); + attron(COLOR_PAIR(game.current.t) | A_BOLD); + mvaddstr(draw_y, draw_x, BLOCK); + attroff(COLOR_PAIR(game.current.t) | A_BOLD); + } + if ((ctrs_default_matrices[game.piece_queue[game.current_index]][y]>>(3 - x))&1) { + mvaddstr(6 + y, (x * 2) + 36, BLOCK); + } + } + } + + for (int x = 0; x < game.config.board_x; x++) { + for (int y = game.highest_line; y < game.config.board_y; y++) { + int draw_y = y - game.config.board_visible + Y_OFFSET; + int draw_x = x * 2 + X_OFFSET; + if (game.board[x][y] & CTRS_SLOT_OCCUPIED) { + attron(COLOR_PAIR(game.board[x][y] >> 5) | A_BOLD); + if (game.line_remove_tick[y]) { + if (game.tick % 2 == 0) { + mvaddstr(draw_y, draw_x, BLOCK); + } + } else { + mvaddstr(draw_y, draw_x, BLOCK); + } + attroff(COLOR_PAIR(game.board[x][y] >> 5) | A_BOLD); + } + } + } + + attron(A_BOLD); + + char score[50]; + sprintf(score, "%i", game.score); + mvaddstr(1, (39 + X_OFFSET) - strlen(score), score); + + char level[20]; + sprintf(level, "%i", game.level); + mvaddstr(3, 37, "Level"); + mvaddstr(4, 40 - strlen(level), level); + + if (game.game_over) { + mvaddstr(10, 5 + X_OFFSET, "GAME OVER"); + mvaddstr(11, 4 + X_OFFSET, "r to restart"); + } + + if (is_paused) { + mvaddstr(10, 7 + X_OFFSET, "paused"); + } + + attroff(A_BOLD); +} + +int main(void) { + curses_init(); + + game.config = tetris_ds_config; + game.config.levels = &tetris_worlds_levels[0]; + game.config.win_condition = twenty_line_sprint; + game.config.wait_on_clear = 0; + ctrs_init_game(&game); + + ctrs_start_game(&game); + /* +#ifdef _WIN32 + HANDLE thread = CreateThread(NULL, 0, game_loop, NULL, 0, NULL); +#else + pthread_t thread; + pthread_create(&thread, NULL, (void*)game_loop, (void*)0); +#endif +*/ + + int c; + while(1) { + c = getch(); + switch (c) { + case 'q': endwin(); exit(1); + case 27: // esc or alt + is_paused = !is_paused; break; + case 'r': + if (game.game_over) { + ctrs_init_game(&game); + } + break; + } + if (is_paused) continue; // dont allow input if paused + switch (c) { + case KEY_LEFT: + ctrs_move_piece(&game, LEFT); break; + case KEY_RIGHT: + ctrs_move_piece(&game, RIGHT); break; + case KEY_DOWN: + ctrs_move_piece(&game, DOWN); break; + case KEY_UP: + case 'x': + ctrs_move_piece(&game, ROTATE_CW); break; + case '^': + case 'z': + ctrs_move_piece(&game, ROTATE_CCW); break; + case ' ': + ctrs_move_piece(&game, HARD_DROP); break; + case KEY_SLEFT: + case 'c': + ctrs_hold_piece(&game); break; + } + erase(); + draw_board(); + refresh(); + } + return 0; +} + diff --git a/frontends/curses/meson.build b/frontends/curses/meson.build new file mode 100644 index 0000000..46763fd --- /dev/null +++ b/frontends/curses/meson.build @@ -0,0 +1,17 @@ +src = ['curses_ui.c'] + +inc = [cetris_inc] +deps = [] + +if host_machine.system() == 'windows' + deps += compiler.find_library('pdcurses') +else + deps += dependency('ncursesw') + deps += dependency('tinfow') + deps += dependency('threads') +endif + +executable('cetris', src, + dependencies: deps, + include_directories: inc, + install: false) -- cgit v1.2.3-101-g0448