File: [contributed] / brogue-ce / src / platform / curses-platform.c (download)
Revision 1.1.1.1 (vendor branch), Thu May 27 20:31:42 2021 UTC (3 years, 3 months ago) by rubenllorente
Branch: tmewett, MAIN
CVS Tags: start, HEAD Changes since 1.1: +0 -0 lines
Initial Import from release 1.9.3
|
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <signal.h>
#include <sys/time.h>
#include "platform.h"
#include "term.h"
static void gameLoop() {
signal(SIGINT, SIG_DFL); // keep SDL from overriding the default ^C handler when it's linked
if (!Term.start()) {
return;
}
Term.title("Brogue");
Term.resize(COLS, ROWS);
rogueMain();
Term.end();
}
static char glyphToAscii(enum displayGlyph glyph) {
unsigned int ch;
switch (glyph) {
case G_UP_ARROW: return '^';
case G_DOWN_ARROW: return 'v';
case G_FLOOR: return '.';
case G_CHASM: return ':';
case G_TRAP: return '%';
case G_FIRE: return '^';
case G_FOLIAGE: return '&';
case G_AMULET: return ',';
case G_SCROLL: return '?';
case G_RING: return '=';
case G_WEAPON: return '(';
case G_GEM: return '+';
case G_TOTEM: return '0'; // zero
case G_GOOD_MAGIC: return '$';
case G_BAD_MAGIC: return '+';
case G_DOORWAY: return '<';
case G_CHARM: return '7';
case G_GUARDIAN: return '5';
case G_WINGED_GUARDIAN: return '5';
case G_EGG: return 'o';
case G_BLOODWORT_STALK: return '&';
case G_FLOOR_ALT: return '.';
case G_UNICORN: return 'U';
case G_TURRET: return '*';
case G_CARPET: return '.';
case G_STATUE: return '5';
case G_CRACKED_STATUE: return '5';
case G_MAGIC_GLYPH: return ':';
case G_ELECTRIC_CRYSTAL: return '$';
default:
ch = glyphToUnicode(glyph);
brogueAssert(ch < 0x80); // assert ascii
return ch;
}
}
static void curses_plotChar(enum displayGlyph ch,
short xLoc, short yLoc,
short foreRed, short foreGreen, short foreBlue,
short backRed, short backGreen, short backBlue) {
fcolor fore;
fcolor back;
fore.r = (float) foreRed / 100;
fore.g = (float) foreGreen / 100;
fore.b = (float) foreBlue / 100;
back.r = (float) backRed / 100;
back.g = (float) backGreen / 100;
back.b = (float) backBlue / 100;
ch = glyphToAscii(ch);
if (ch < ' ' || ch > 127) ch = ' ';
Term.put(xLoc, yLoc, ch, &fore, &back);
}
struct mapsymbol {
int in_c, out_c;
struct mapsymbol *next;
};
static struct mapsymbol *keymap = NULL;
static int rewriteKey(int key, boolean text) {
if (text) return key;
struct mapsymbol *s = keymap;
while (s != NULL) {
if (s->in_c == key) {
return s->out_c;
}
s = s->next;
}
return key;
}
#define PAUSE_BETWEEN_EVENT_POLLING 34//17
static uint64_t getTime() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static boolean curses_pauseForMilliseconds(short milliseconds) {
Term.refresh();
Term.wait(milliseconds);
// hasKey returns true if we have a mouse event, too.
return Term.hasKey();
}
static void curses_nextKeyOrMouseEvent(rogueEvent *returnEvent, boolean textInput, boolean colorsDance) {
int key;
// TCOD_mouse_t mouse;
uint64_t theTime, waitTime;
// short x, y;
Term.refresh();
for (;;) {
theTime = getTime(); //TCOD_sys_elapsed_milli();
/*if (TCOD_console_is_window_closed()) {
rogue.gameHasEnded = true; // causes the game loop to terminate quickly
returnEvent->eventType = KEYSTROKE;
returnEvent->param1 = ACKNOWLEDGE_KEY;
return;
}*/
if (colorsDance) {
shuffleTerrainColors(3, true);
commitDraws();
}
key = Term.getkey();
if (key == TERM_MOUSE) {
if (Term.mouse.x > 0 && Term.mouse.y > 0 && Term.mouse.x < COLS && Term.mouse.y < ROWS) {
returnEvent->param1 = Term.mouse.x;
returnEvent->param2 = Term.mouse.y;
returnEvent->eventType = KEYSTROKE;
if (Term.mouse.justReleased) returnEvent->eventType = MOUSE_UP;
if (Term.mouse.justPressed) returnEvent->eventType = MOUSE_DOWN;
if (Term.mouse.justMoved) returnEvent->eventType = MOUSE_ENTERED_CELL;
returnEvent->controlKey = Term.mouse.control;
returnEvent->shiftKey = Term.mouse.shift;
if (returnEvent->eventType != KEYSTROKE) return;
}
} else if (key != TERM_NONE) {
key = rewriteKey(key, textInput);
returnEvent->eventType = KEYSTROKE;
returnEvent->controlKey = 0; //(key.rctrl || key.lctrl);
returnEvent->shiftKey = 0; //key.shift;
returnEvent->param1 = key;
if (key == Term.keys.backspace || key == Term.keys.del) returnEvent->param1 = DELETE_KEY;
else if (key == Term.keys.up) returnEvent->param1 = UP_ARROW;
else if (key == Term.keys.down) returnEvent->param1 = DOWN_ARROW;
else if (key == Term.keys.left) returnEvent->param1 = LEFT_ARROW;
else if (key == Term.keys.right) returnEvent->param1 = RIGHT_ARROW;
else if (key == Term.keys.quit) {
rogue.gameHasEnded = true;
rogue.nextGame = NG_QUIT; // causes the menu to drop out immediately
}
else if ((key >= 'A' && key <= 'Z')) {
returnEvent->shiftKey = 1;
// returnEvent->param1 += 'a' - 'A';
}
// we could try to catch control keys, where possible, but we'll catch keys we mustn't
/* else if ((key >= 'A'-'@' && key <= 'Z'-'@')) {
returnEvent->controlKey = 1;
returnEvent->param1 += 'a' - ('A'-'@');
} */
return;
}
waitTime = PAUSE_BETWEEN_EVENT_POLLING + theTime - getTime();
if (waitTime > 0 && waitTime <= PAUSE_BETWEEN_EVENT_POLLING) {
curses_pauseForMilliseconds(waitTime);
}
}
}
static void curses_remap(const char *input_name, const char *output_name) {
struct mapsymbol *sym = malloc(sizeof(*sym));
if (sym == NULL) return; // out of memory? seriously?
sym->in_c = Term.keycodeByName(input_name);
sym->out_c = Term.keycodeByName(output_name);
sym->next = keymap;
keymap = sym;
}
static boolean modifier_held(int modifier) {
return 0;
}
struct brogueConsole cursesConsole = {
gameLoop,
curses_pauseForMilliseconds,
curses_nextKeyOrMouseEvent,
curses_plotChar,
curses_remap,
modifier_held,
NULL,
NULL,
NULL
};