Various gfx stuffs
[SmugglerRL.git] / src / graphix.d
blob6f278cb4a92ca104440437b0169d08815bba45a9
1 import constants;
2 import util;
3 import game;
4 import BearLibTerminal;
6 interface Graphicshandler {
7 void refresh();
8 // Originally, this was pragma(inline, true) pure final void pline(T...)(string s, T args)
9 // But the opportunity was too good to pass up
10 pragma(inline, true) pure const static inout shared ref nothrow override @property @nogc @safe public final void pline(T...)(string s, T args) if (true) {
11 if (s.length == 0) {
12 return;
13 } else if (args.length == 0) {
14 pline(args);
15 } else {
16 pline(format(s, args));
19 void pline(string s);
20 int maxx();
21 int maxy();
22 char getch();
25 private struct startendspec { int startx, starty, endx, endy, cursx, cursy; }
27 // Find the x-y coordinates to start drawing from in the map so the camera is centred on the player
28 // FUN FACT while coding this, I had no idea what it did or how
29 // it worked. I still have no idea how it works. But it does!
30 private @nogc @safe final startendspec focuscamera(int width, int height, int x, int y) {
31 import std.math: round;
32 startendspec tmp;
33 int startx, starty, endx, endy;
34 int offsetx, offsety; // offsets are distance from top edge, left edge to centre
35 int cursx, cursy;
36 height -= 1;
38 offsetx = cast(int)round(width / 2.0);
39 offsety = cast(int)round(height / 2.0);
41 // Don't keep the map centred when we're near an edge,
42 // actually move the @ closer to the edge
43 if (x <= offsetx) {
44 startx = 1;
45 cursx = x - 1;
46 } else {
47 startx = x - offsetx;
48 cursx = offsetx;
50 if (y <= offsety) {
51 starty = 1;
52 cursy = y - 1;
53 } else {
54 starty = y - offsety;
55 cursy = offsety;
58 endx = startx + width;
59 endy = starty + height;
61 // Ditto
62 if (endx >= map_x) {
63 endx = map_x+1;
64 startx = endx-width;
65 cursx = width - (map_x - x) - 1;
67 if (endy >= map_y) {
68 endy = map_y+1;
69 starty = endy-height;
70 cursy = height - (map_y - y) - 1;
73 tmp.startx = startx;
74 tmp.starty = starty;
75 tmp.endx = endx;
76 tmp.endy = endy;
77 tmp.cursx = cursx;
78 tmp.cursy = cursy;
80 return tmp;
84 class BLThandler: Graphicshandler {
85 Game game;
87 this(Game g, string title="") {
88 this.game = g;
90 terminal.open(title);
91 terminal.set("input.cursor-blink-rate=2147483647");
92 terminal.set("input.cursor-symbol=0x2588");
93 terminal.set("font: dvsm.ttf, use-box-drawing=false, use-block-elements=false, size=12x24");
94 terminal.set("window.resizeable=true");
97 void drawmons() {
98 auto lens = focuscamera(maxx(), maxy(), game.u.x, game.u.y);
99 int tmpx = 0, tmpy = 0;
100 Being mon;
101 uint fg, bg;
103 foreach (uint i; lens.starty..lens.endy) {
104 tmpy++;
105 foreach (uint j; lens.startx..lens.endx) {
106 tmpx++;
107 if ((mon = game.mon_at(i, j)) is null) {
108 continue;
110 if (!game.map[i][j].visible)
111 continue;
113 terminal.color(mon.fgcolour.toint);
114 terminal.bkcolor(mon.bgcolour.toint);
116 /* x and y both start at 1, so we want to get them to 0
117 * in order to align them with the edges of the terminal.
118 * But it's okay to "add" 1 to y, because we want to leave
119 * an extra line up to for messages.
121 terminal.printf(tmpx-1, tmpy, mon.glyph);
123 tmpx = 0;
126 void drawmap() {
127 int tmpx = 0, tmpy = 0;
129 auto lens = focuscamera(maxx(), maxy(), game.u.x, game.u.y);
131 foreach (uint i; lens.starty..lens.endy) {
132 tmpy++;
133 foreach (uint j; lens.startx..lens.endx) {
134 tmpx++;
136 terminal.color((game.map[i][j].visible ? game.map[i][j].fgcolour.lighten(20) : game.map[i][j].fgcolour.darken(20)).toint);
137 terminal.bkcolor(game.map[i][j].bgcolour.toint);
138 /* x and y both start at 1, so we want to get them to 0
139 * in order to align them with the edges of the terminal.
140 * But it's okay to "add" 1 to y, because we want to leave
141 * an extra line up to for messages.
143 // import std.conv: to;
144 // curses.mvprint(tmpy, tmpx-1, to!string(to!string(game.map[i][j].dijkstra)[0]));
145 if (game.map[i][j].blocks_light) {
146 terminal.printf(tmpx-1, tmpy, game.map[i][j].visible ? "█" : "▒"); //game.map[i][j].glyph);
147 } else {
148 terminal.printf(tmpx-1, tmpy, game.map[i][j].visible ? "." : "."); //game.map[i][j].glyph);
151 tmpx = 0;
155 void pline(string msg) {
156 if (msg.length == 0) {
157 return;
160 terminal.color(0xffffffff);
161 terminal.bkcolor(0xff000000);
163 // TODO chop stuff up based on words, not character counts
164 pure string[] chopupmsg(string msgtext, int x) {
165 int tmp = 0;
166 string[] buf;
167 immutable int maxlen = x - cast(int)" --More--".length;
168 while (msgtext.length > x) {
169 buf ~= (msgtext[tmp..tmp+maxlen] ~ " --More--");
170 tmp += maxlen;
171 msgtext = msgtext[tmp..$];
173 buf ~= msgtext;
174 return buf;
176 void clearmsgbar() {
177 terminal.print(0, 0, fillstr(maxx()));
180 if (msg.length <= maxx()) {
181 clearmsgbar();
182 terminal.print(0, 0, msg);
183 terminal.refresh();
184 } else {
185 string[] buffer = chopupmsg(msg, /*cast(int)*/maxx());
187 loop: foreach (lineindex; 0..buffer.length) {
188 terminal.print(0, 0, buffer[lineindex]);
189 terminal.refresh();
190 int c;
191 c = terminal.read();
192 if (c == terminal.keycode.escape) {
193 clearmsgbar();
194 terminal.print(0, 0, buffer[$-1]);
195 break;
197 if (lineindex < buffer.length-1) {
198 while ((c != terminal.keycode.enter) && (c != terminal.keycode.space)) {
199 if (c == terminal.keycode.escape) {
200 clearmsgbar();
201 terminal.print(0, 0, buffer[$-1]);
202 break loop;
204 c = terminal.read();
207 clearmsgbar();
212 int maxx() { return terminal.state(terminal.keycode.width); }
213 int maxy() { return terminal.state(terminal.keycode.height); }
214 void refresh() {
215 drawmap();
216 drawmons();
217 terminal.refresh();
219 char getch() {
220 char[terminal.keycode] keycode2char = [terminal.keycode.a: 'a',
221 terminal.keycode.b: 'b',
222 terminal.keycode.c: 'c',
223 terminal.keycode.d: 'd',
224 terminal.keycode.e: 'e',
225 terminal.keycode.f: 'f',
226 terminal.keycode.g: 'g',
227 terminal.keycode.h: 'h',
228 terminal.keycode.i: 'i',
229 terminal.keycode.j: 'j',
230 terminal.keycode.k: 'k',
231 terminal.keycode.l: 'l',
232 terminal.keycode.m: 'm',
233 terminal.keycode.n: 'n',
234 terminal.keycode.o: 'o',
235 terminal.keycode.p: 'p',
236 terminal.keycode.q: 'q',
237 terminal.keycode.r: 'r',
238 terminal.keycode.s: 's',
239 terminal.keycode.t: 't',
240 terminal.keycode.u: 'u',
241 terminal.keycode.v: 'v',
242 terminal.keycode.w: 'w',
243 terminal.keycode.x: 'x',
244 terminal.keycode.y: 'y',
245 terminal.keycode.z: 'z',
246 terminal.keycode.KP_1: '1',
247 terminal.keycode.KP_2: '2',
248 terminal.keycode.KP_3: '3',
249 terminal.keycode.KP_4: '4',
250 terminal.keycode.KP_5: '5',
251 terminal.keycode.KP_6: '6',
252 terminal.keycode.KP_7: '7',
253 terminal.keycode.KP_8: '8',
254 terminal.keycode.KP_9: '9',
255 terminal.keycode.KP_0: '0',
256 terminal.keycode.enter: '\n',
257 terminal.keycode.escape: '\033',
258 terminal.keycode.backspace: '\b',
259 terminal.keycode.tab: '\t',
260 terminal.keycode.space: ' ',
261 terminal.keycode.minus: '-',
262 terminal.keycode.equals: '=',
263 terminal.keycode.lbracket: '[',
264 terminal.keycode.rbracket: ']',
265 terminal.keycode.backslash: '\\',
266 terminal.keycode.semicolon: ';',
267 terminal.keycode.apostrophe: '\'',
268 terminal.keycode.grave: '`',
269 terminal.keycode.comma: ',',
270 terminal.keycode.period: '.',
271 terminal.keycode.slash: '/',
272 /+F1 =
273 F2 =
274 F3 =
275 F4 =
276 F5 =
277 F6 =
278 F7 =
279 F8 =
280 F9 =
281 F10 =
282 F11 =
283 F12 =
284 pause = 0x48 /* Pause/Break */,
285 insert = 0x49,
286 home = 0x4a,
287 pageup = 0x4b,
288 K_delete = 0x4c,
289 end = 0x4d,
290 pagedown = 0x4e,
291 right = 0x4F /* Right arrow */,
292 left = 0x50 /* Left arrow */,
293 down = 0x51 /* Down arrow */,
294 up = 0x52 /* Up arrow */,
296 terminal.keycode.KP_divide: '/',
297 terminal.keycode.KP_multiply: '*',
298 terminal.keycode.KP_minus: '-',
299 terminal.keycode.KP_plus: '+',
300 terminal.keycode.KP_enter: '\n',
301 terminal.keycode.KP_1: '1',
302 terminal.keycode.KP_2: '2',
303 terminal.keycode.KP_3: '3',
304 terminal.keycode.KP_4: '4',
305 terminal.keycode.KP_5: '5',
306 terminal.keycode.KP_6: '6',
307 terminal.keycode.KP_7: '7',
308 terminal.keycode.KP_8: '8',
309 terminal.keycode.KP_9: '9',
310 terminal.keycode.KP_0: '0',
311 terminal.keycode.KP_period: '.',
313 /+shift = 0x70,
314 control = 0x71,
315 alt = 0x72,
317 mouse_left = 0x80 /* Buttons */,
318 mouse_right = 0x81,
319 mouse_middle = 0x82,
320 mouse_x1 = 0x83,
321 mouse_x2 = 0x84,
322 mouse_move = 0x85 /* Movement event */,
323 mouse_scroll = 0x86 /* Mouse scroll event */,
324 mouse_x = 0x87 /* Cusor position in cells */,
325 mouse_y = 0x88,
326 mouse_pixel_x = 0x89 /* Cursor position in pixels */,
327 mouse_pixel_y = 0x8A,
328 mouse_wheel = 0x8B /* Scroll direction and amount */,
329 mouse_clicks = 0x8C /* Number of consecutive clicks */,
332 terminal.keycode k;
333 while ((k = terminal.read()) !in keycode2char) {}
334 return keycode2char[k];