1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <signal.h>
5 #include <sys/time.h>
6 #include "platform.h"
7 #include "term.h"
8
gameLoop()9 static void gameLoop() {
10 signal(SIGINT, SIG_DFL); // keep SDL from overriding the default ^C handler when it's linked
11
12 if (!Term.start()) {
13 return;
14 }
15 Term.title("Brogue");
16 Term.resize(COLS, ROWS);
17
18 rogueMain();
19
20 Term.end();
21 }
22
glyphToAscii(enum displayGlyph glyph)23 static char glyphToAscii(enum displayGlyph glyph) {
24 unsigned int ch;
25
26 switch (glyph) {
27 case G_UP_ARROW: return '^';
28 case G_DOWN_ARROW: return 'v';
29 case G_FLOOR: return '.';
30 case G_CHASM: return ':';
31 case G_TRAP: return '%';
32 case G_FIRE: return '^';
33 case G_FOLIAGE: return '&';
34 case G_AMULET: return ',';
35 case G_SCROLL: return '?';
36 case G_RING: return '=';
37 case G_WEAPON: return '(';
38 case G_GEM: return '+';
39 case G_TOTEM: return '0'; // zero
40 case G_GOOD_MAGIC: return '$';
41 case G_BAD_MAGIC: return '+';
42 case G_DOORWAY: return '<';
43 case G_CHARM: return '7';
44 case G_GUARDIAN: return '5';
45 case G_WINGED_GUARDIAN: return '5';
46 case G_EGG: return 'o';
47 case G_BLOODWORT_STALK: return '&';
48 case G_FLOOR_ALT: return '.';
49 case G_UNICORN: return 'U';
50 case G_TURRET: return '*';
51 case G_CARPET: return '.';
52 case G_STATUE: return '5';
53 case G_CRACKED_STATUE: return '5';
54 case G_MAGIC_GLYPH: return ':';
55 case G_ELECTRIC_CRYSTAL: return '$';
56
57 default:
58 ch = glyphToUnicode(glyph);
59 brogueAssert(ch < 0x80); // assert ascii
60 return ch;
61 }
62 }
63
curses_plotChar(enum displayGlyph ch,short xLoc,short yLoc,short foreRed,short foreGreen,short foreBlue,short backRed,short backGreen,short backBlue)64 static void curses_plotChar(enum displayGlyph ch,
65 short xLoc, short yLoc,
66 short foreRed, short foreGreen, short foreBlue,
67 short backRed, short backGreen, short backBlue) {
68
69 fcolor fore;
70 fcolor back;
71
72 fore.r = (float) foreRed / 100;
73 fore.g = (float) foreGreen / 100;
74 fore.b = (float) foreBlue / 100;
75 back.r = (float) backRed / 100;
76 back.g = (float) backGreen / 100;
77 back.b = (float) backBlue / 100;
78
79 ch = glyphToAscii(ch);
80
81 if (ch < ' ' || ch > 127) ch = ' ';
82 Term.put(xLoc, yLoc, ch, &fore, &back);
83 }
84
85
86 struct mapsymbol {
87 int in_c, out_c;
88 struct mapsymbol *next;
89 };
90
91 static struct mapsymbol *keymap = NULL;
92
rewriteKey(int key,boolean text)93 static int rewriteKey(int key, boolean text) {
94 if (text) return key;
95
96 struct mapsymbol *s = keymap;
97 while (s != NULL) {
98 if (s->in_c == key) {
99 return s->out_c;
100 }
101
102 s = s->next;
103 }
104 return key;
105 }
106
107
108 #define PAUSE_BETWEEN_EVENT_POLLING 34//17
109
getTime()110 static uint64_t getTime() {
111 struct timeval tv;
112 gettimeofday(&tv, NULL);
113 return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
114 }
115
curses_pauseForMilliseconds(short milliseconds)116 static boolean curses_pauseForMilliseconds(short milliseconds) {
117 Term.refresh();
118 Term.wait(milliseconds);
119
120 // hasKey returns true if we have a mouse event, too.
121 return Term.hasKey();
122 }
123
curses_nextKeyOrMouseEvent(rogueEvent * returnEvent,boolean textInput,boolean colorsDance)124 static void curses_nextKeyOrMouseEvent(rogueEvent *returnEvent, boolean textInput, boolean colorsDance) {
125 int key;
126 // TCOD_mouse_t mouse;
127 uint64_t theTime, waitTime;
128 // short x, y;
129
130 Term.refresh();
131
132 for (;;) {
133 theTime = getTime(); //TCOD_sys_elapsed_milli();
134
135 /*if (TCOD_console_is_window_closed()) {
136 rogue.gameHasEnded = true; // causes the game loop to terminate quickly
137 returnEvent->eventType = KEYSTROKE;
138 returnEvent->param1 = ACKNOWLEDGE_KEY;
139 return;
140 }*/
141
142 if (colorsDance) {
143 shuffleTerrainColors(3, true);
144 commitDraws();
145 }
146
147
148 key = Term.getkey();
149 if (key == TERM_MOUSE) {
150 if (Term.mouse.x > 0 && Term.mouse.y > 0 && Term.mouse.x < COLS && Term.mouse.y < ROWS) {
151 returnEvent->param1 = Term.mouse.x;
152 returnEvent->param2 = Term.mouse.y;
153 returnEvent->eventType = KEYSTROKE;
154 if (Term.mouse.justReleased) returnEvent->eventType = MOUSE_UP;
155 if (Term.mouse.justPressed) returnEvent->eventType = MOUSE_DOWN;
156 if (Term.mouse.justMoved) returnEvent->eventType = MOUSE_ENTERED_CELL;
157 returnEvent->controlKey = Term.mouse.control;
158 returnEvent->shiftKey = Term.mouse.shift;
159 if (returnEvent->eventType != KEYSTROKE) return;
160 }
161 } else if (key != TERM_NONE) {
162 key = rewriteKey(key, textInput);
163
164 returnEvent->eventType = KEYSTROKE;
165 returnEvent->controlKey = 0; //(key.rctrl || key.lctrl);
166 returnEvent->shiftKey = 0; //key.shift;
167 returnEvent->param1 = key;
168
169 if (key == Term.keys.backspace || key == Term.keys.del) returnEvent->param1 = DELETE_KEY;
170 else if (key == Term.keys.up) returnEvent->param1 = UP_ARROW;
171 else if (key == Term.keys.down) returnEvent->param1 = DOWN_ARROW;
172 else if (key == Term.keys.left) returnEvent->param1 = LEFT_ARROW;
173 else if (key == Term.keys.right) returnEvent->param1 = RIGHT_ARROW;
174 else if (key == Term.keys.quit) {
175 rogue.gameHasEnded = true;
176 rogue.nextGame = NG_QUIT; // causes the menu to drop out immediately
177 }
178 else if ((key >= 'A' && key <= 'Z')) {
179 returnEvent->shiftKey = 1;
180 // returnEvent->param1 += 'a' - 'A';
181 }
182 // we could try to catch control keys, where possible, but we'll catch keys we mustn't
183 /* else if ((key >= 'A'-'@' && key <= 'Z'-'@')) {
184 returnEvent->controlKey = 1;
185 returnEvent->param1 += 'a' - ('A'-'@');
186 } */
187
188 return;
189 }
190
191 waitTime = PAUSE_BETWEEN_EVENT_POLLING + theTime - getTime();
192
193 if (waitTime > 0 && waitTime <= PAUSE_BETWEEN_EVENT_POLLING) {
194 curses_pauseForMilliseconds(waitTime);
195 }
196 }
197 }
198
curses_remap(const char * input_name,const char * output_name)199 static void curses_remap(const char *input_name, const char *output_name) {
200 struct mapsymbol *sym = malloc(sizeof(*sym));
201
202 if (sym == NULL) return; // out of memory? seriously?
203
204 sym->in_c = Term.keycodeByName(input_name);
205 sym->out_c = Term.keycodeByName(output_name);
206
207 sym->next = keymap;
208 keymap = sym;
209 }
210
modifier_held(int modifier)211 static boolean modifier_held(int modifier) {
212 return 0;
213 }
214
215 struct brogueConsole cursesConsole = {
216 gameLoop,
217 curses_pauseForMilliseconds,
218 curses_nextKeyOrMouseEvent,
219 curses_plotChar,
220 curses_remap,
221 modifier_held,
222 NULL,
223 NULL,
224 NULL
225 };
226