MAKE THE TORUS FUCKING WORK!! I swear to god I am NEVER messing with signedness...
[SmugglerRL.git] / src / graphix.d
blob4180f74c8241ca48c9411a937c0560b76cdf5e49
1 import constants;
2 import util;
3 import game;
4 import graphix0;
5 import map;
7 interface Graphics1 {
8 void refresh();
9 // Originally, this was pragma(inline, true) pure final void pline(T...)(string s, T args)
10 // But the opportunity was too good to pass up
11 // then it was
12 //pragma(inline, true) pure const static inout shared ref nothrow override @property @nogc @safe public final void
13 // in all its glory. But after about a year, I found out that this didn't actually work, which brings you to the state you see today :<<
14 pragma(inline, true) public final void pline(T...)(T args) {
15 import std.conv: to;
16 import std.string: format;
17 if (args.length == 1) {
18 this.pline(to!string(args[0]));
19 } else {
20 this.pline(format(args));
23 void pline(string s);
24 int maxx();
25 int maxy();
26 dchar getch();
27 void close();
30 private struct startendspec { int startx, endx, cursx, starty, endy, cursy; }
32 // Find the x-y coordinates to start drawing from in the map so the camera is centred on the player
33 // FUN FACT while coding this, I had no idea what it did or how
34 // it worked. I still have no idea how it works. But it does!
35 private @nogc @safe final startendspec focuscamera(int width, int height, int x, int y) {
36 import std.math: round;
37 startendspec tmp;
38 int startx, starty, endx, endy;
39 int offsetx, offsety; // offsets are distance from top edge, left edge to centre
40 int cursx, cursy;
41 height -= 1;
43 offsetx = cast(int)round(width / 2.0);
44 offsety = cast(int)round(height / 2.0);
46 // Don't keep the map centred when we're near an edge,
47 // actually move the @ closer to the edge
49 if (x <= offsetx) {
50 startx = 1;
51 cursx = x - 1;
52 } else {*/
53 startx = x - offsetx;
54 cursx = offsetx;
57 if (y <= offsety) {
58 starty = 1;
59 cursy = y - 1;
60 } else {
62 starty = y - offsety;
63 cursy = offsety;
64 //}
66 endx = startx + width;
67 endy = starty + height;
69 // Ditto
71 if (endx >= map_x) {
72 endx = map_x+1;
73 startx = endx-width;
74 cursx = width - (map_x - x) - 1;
76 if (endy >= map_y) {
77 endy = map_y+1;
78 starty = endy-height;
79 cursy = height - (map_y - y) - 1;
83 tmp.startx = startx;
84 tmp.starty = starty;
85 tmp.endx = endx;
86 tmp.endy = endy;
87 tmp.cursx = cursx;
88 tmp.cursy = cursy;
90 return tmp;
93 class Default_chargfx(G0type: CharGfx0): Graphics1 {
94 CharGfx0 graphics0;
95 Game game;
97 this(Game g, string title="") {
98 this.game = g;
99 this.graphics0 = new G0type();
101 graphics0.settitle(title);
103 void close() { graphics0.close(); }
105 void drawmons() {
106 auto lens = focuscamera(maxx(), maxy(), game.u.loc.x, game.u.loc.y);
107 uint tmpy, tmpx; // position of character on the screen
108 Being mon;
109 uint fg, bg;
111 foreach (int i; lens.starty..lens.endy) {
112 tmpy++;
113 foreach (int j; lens.startx..lens.endx) {
114 tmpx++;
115 Vector2n maploc = Vector2n(i, j);
117 if ((mon = game.mon_at(maploc)) is null) {
118 continue;
120 if (!game.map[maploc].visible) {
121 continue;
124 /* x and y both start at 1, so we want to get them to 0
125 * in order to align them with the edges of the terminal.
126 * But it's okay to "add" 1 to y, because we want to leave
127 * an extra line up to for messages.
129 with (mon.attrs)
130 graphics0.mvaddch(mon.glyph, tmpy, tmpx-1, mon.fgcolour, mon.bgcolour, bold, italic, underline, reverse);
132 tmpx = 0;
135 void drawmap() {
136 uint tmpy, tmpx;
138 auto lens = focuscamera(maxx(), maxy(), game.u.loc.x, game.u.loc.y);
140 foreach (int i; lens.starty..lens.endy) {
141 tmpy++;
142 foreach (int j; lens.startx..lens.endx) {
143 tmpx++;
145 Vector2n maploc = Vector2n(i, j);
147 /* x and y both start at 1, so we want to get them to 0
148 * in order to align them with the edges of the terminal.
149 * But it's okay to "add" 1 to y, because we want to leave
150 * an extra line up to for messages.
152 with (game.map[maploc].attrs)
153 graphics0.mvaddch(game.map[maploc].glyph, tmpy, tmpx-1, game.map[maploc].visible ? game.map[maploc].fgcolour.lighten(20) : game.map[maploc].fgcolour.darken(20), game.map[maploc].bgcolour, bold, italic, underline, reverse);
155 tmpx = 0;
159 void pline(string msg) {
160 if (msg.length == 0) {
161 return;
164 // TODO chop stuff up based on words, not character counts
165 pure string[] chopupmsg(string msgtext, int x) {
166 int tmp = 0;
167 string[] buf;
168 immutable uint maxlen = x - cast(int)" --More--".length;
169 while (msgtext.length > x) {
170 buf ~= (msgtext[tmp..tmp+maxlen] ~ " --More--");
171 tmp += maxlen;
172 msgtext = msgtext[tmp..$];
174 buf ~= msgtext;
175 return buf;
177 void clearmsgbar() {
178 graphics0.printext(fillstr(maxx()), 0, 0);
181 if (msg.length <= maxx()) {
182 clearmsgbar();
183 graphics0.printext(msg, 0, 0);
184 graphics0.refresh();
185 } else {
186 string[] buffer = chopupmsg(msg, /*cast(int)*/maxx());
188 loop: foreach (lineindex; 0..buffer.length) {
189 graphics0.printext(buffer[lineindex], 0, 0);
190 graphics0.refresh();
191 int c;
192 c = graphics0.getch();
193 if (c == '\033') {
194 clearmsgbar();
195 graphics0.printext(buffer[$-1], 0, 0);
196 break;
198 if (lineindex < buffer.length-1) {
199 while ((c != '\n') && (c != ' ')) {
200 if (c == '\033') {
201 clearmsgbar();
202 graphics0.printext(buffer[$-1], 0, 0);
203 break loop;
205 c = graphics0.getch;
208 clearmsgbar();
213 int maxx() { return graphics0.maxx(); }
214 int maxy() { return graphics0.maxy(); }
215 void refresh() {
216 drawmap();
217 drawmons();
218 graphics0.refresh();
221 dchar getch() { return graphics0.getch; }