157 lines
3.6 KiB
C
157 lines
3.6 KiB
C
#include "world.h"
|
|
#include "game.h"
|
|
#include <ncurses.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
int TIMEOUT = 100;
|
|
|
|
void abort_game(const char* msg) {
|
|
endwin();
|
|
puts(msg);
|
|
exit(1);
|
|
}
|
|
|
|
void check_bounds(const char* tag, int x, int y) {
|
|
char err[256];
|
|
if (x < 0 || x >= COLS) {
|
|
snprintf(err, sizeof(err), "%s: x=%d out of screen (0,%d)", tag, x, COLS);
|
|
abort_game(err);
|
|
}
|
|
if (y < 0 || y >= LINES) {
|
|
snprintf(err, sizeof(err), "%s: y=%d out of screen (0,%d)", tag, y, LINES);
|
|
abort_game(err);
|
|
}
|
|
}
|
|
|
|
void clear_screen() {
|
|
mvaddch(0, 0, ' ');
|
|
for (int p = 1; p < COLS * LINES; p++) {
|
|
addch(' ');
|
|
}
|
|
}
|
|
|
|
void game_speed(int v) {
|
|
if (v < 0) abort_game("negative speed?");
|
|
TIMEOUT = v;
|
|
}
|
|
|
|
void set_message(const char* msg, int x, int y) {
|
|
int n = strlen(msg);
|
|
for (int i = 0; i < n; i++) {
|
|
check_bounds("set_message", x + i, y);
|
|
set_cell(msg[i], x + i, y);
|
|
}
|
|
}
|
|
|
|
void assert_message(int ok, const char* msg) {
|
|
if (!ok) abort_game(msg);
|
|
}
|
|
|
|
void set_cell(int c, int x, int y) {
|
|
check_bounds("set_cell", x, y);
|
|
set_color_cell(c, x, y, COLOR_WHITE, COLOR_BLACK);
|
|
}
|
|
|
|
void set_color_cell(int c, int x, int y, short fg, short bg) {
|
|
check_bounds("set_color_cell", x, y);
|
|
if (has_colors()) {
|
|
int pair = COLOR_COUNT * fg + bg;
|
|
attron(COLOR_PAIR(pair));
|
|
mvaddch(y, x, c);
|
|
attroff(COLOR_PAIR(pair));
|
|
} else {
|
|
mvaddch(y, x, c);
|
|
}
|
|
}
|
|
|
|
int world_run(void* (*init_game)(), int (*world_event)(struct event* e, void* g)) {
|
|
void* game = init_game();
|
|
if (!game) return -1;
|
|
|
|
timeout(TIMEOUT);
|
|
|
|
struct event ev;
|
|
memset(&ev, 0, sizeof(ev));
|
|
ev.height = LINES;
|
|
ev.width = COLS;
|
|
ev.type = EVENT_START;
|
|
ev.time_ms = clock();
|
|
|
|
world_event(&ev, game);
|
|
|
|
while (1) {
|
|
memset(&ev, 0, sizeof(ev));
|
|
ev.height = LINES;
|
|
ev.width = COLS;
|
|
ev.key = getch();
|
|
|
|
if (ev.key == ERR) {
|
|
ev.type = EVENT_TIMEOUT;
|
|
} else if (ev.key == KEY_MOUSE) {
|
|
ev.type = EVENT_MOUSE;
|
|
MEVENT m;
|
|
if (getmouse(&m) == OK) {
|
|
ev.mouse_x = m.x;
|
|
ev.mouse_y = m.y;
|
|
if (m.bstate & BUTTON1_PRESSED) ev.mouse_left = 1;
|
|
if (m.bstate & BUTTON2_PRESSED) ev.mouse_middle = 1;
|
|
if (m.bstate & BUTTON3_PRESSED) ev.mouse_right = 1;
|
|
}
|
|
} else if (ev.key == KEY_RESIZE) {
|
|
ev.type = EVENT_RESIZE;
|
|
} else {
|
|
ev.type = EVENT_KEY;
|
|
if (ev.key == 27) {
|
|
ev.type = EVENT_ESC;
|
|
}
|
|
}
|
|
|
|
ev.time_ms = clock();
|
|
world_event(&ev, game);
|
|
timeout(TIMEOUT);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int start_world(void* (*init_game)(),
|
|
int (*world_event)(struct event*, void*),
|
|
void (*destroy_game)(void*)) {
|
|
initscr();
|
|
if (initscr() == NULL) {
|
|
puts("initscr failed");
|
|
return -1;
|
|
}
|
|
|
|
noecho();
|
|
cbreak();
|
|
keypad(stdscr, TRUE);
|
|
nodelay(stdscr, TRUE);
|
|
curs_set(0);
|
|
mousemask(ALL_MOUSE_EVENTS, NULL);
|
|
|
|
if (has_colors()) {
|
|
start_color();
|
|
for (int i = 0; i < COLOR_COUNT; i++) {
|
|
for (int j = 0; j < COLOR_COUNT; j++) {
|
|
init_pair(i * COLOR_COUNT + j, i, j);
|
|
}
|
|
}
|
|
} else {
|
|
puts("No color support.");
|
|
}
|
|
|
|
int res = world_run(init_game, world_event);
|
|
|
|
if (destroy_game) {
|
|
void* g = init_game();
|
|
destroy_game(g);
|
|
}
|
|
|
|
endwin();
|
|
return res;
|
|
}
|
|
|