Clean ups
[SmugglerRL.git] / src / game.d
blobd361ea8e5c69e3fc457b0a667cf0b0a84a31f36f
1 import std.container.rbtree: set = redBlackTree;
3 import BearLibTerminal;
5 import colour;
6 import constants;
7 import fov;
8 import glyph;
9 import graphix;
10 import graphix0;
11 import logging;
12 import mapgen;
13 import map;
14 import rng;
15 import util;
19 abstract class Being {
20 int i;
21 private bool gender;
22 ubyte xlvl;
23 int xp, hp = 30, maxhp, mp, maxmp;
24 Vector2n loc;
25 RGBColour fgcolour, bgcolour;
26 Glyph glyph;
28 private struct _attr { bool reverse, italic, bold, underline; }
29 _attr attrs;
31 pragma(inline, true) {
32 pure void inchp(int amount=1) {
33 if ((amount + hp) > maxhp) {
34 hp = maxhp;
35 } else {
36 hp += amount;
39 pure bool ismale() {
40 return gender;
42 pure bool isfemale() {
43 return !gender;
47 Action getaction();
50 class Mon: Being {
51 override Action getaction() {
52 import std.random: uniform;
53 return uniform(Action.MoveNorth, Action.MoveSouthRight);
55 this() {
56 fgcolour = RGBColour(0x00ff00);
57 bgcolour = RGBColour(0xff00ff);
58 attrs.reverse = true;
59 this.glyph = Glyph.r;
63 class You: Being {
64 Graphics1 graphics;
65 this(Graphics1 g) {
66 fgcolour = RGBColour(0xffffff);
67 bgcolour = RGBColour(0x000000);
68 attrs.reverse = true;
70 this.graphics = g;
71 this.glyph = Glyph.at;
73 override Action getaction() {
75 // TODO gdc doesn't like RedBlackTrees. But someday it will
76 version (GNU) {
77 //static immutable bool[int] vikeys = ['h': 1, 'j': 1, 'k': 1, 'l': 1, 'y': 1, 'u': 1, 'b': 1, 'n': 1, 'q': 1, '.', 'w': 1];
78 bool[dchar] vikeys = ['h': 1, 'j': 1, 'k': 1, 'l': 1, 'y': 1, 'u': 1, 'b': 1, 'n': 1, 'q': 1, '.': 1, 'w': 1];
79 } else {
80 static immutable auto vikeys = set!dchar('h', 'j', 'k', 'l', 'y', 'u', 'b', 'n', 'q', '.', 'w');
83 Action tmp;
84 dchar c;
86 while ((c = graphics.getch()) !in vikeys) {}
88 switch (c) {
89 case 'h':
90 tmp = Action.MoveLeft;
91 break;
92 case 'l':
93 tmp = Action.MoveRight;
94 break;
95 case 'j':
96 tmp = Action.MoveSouth;
97 break;
98 case 'k':
99 tmp = Action.MoveNorth;
100 break;
101 case 'y':
102 tmp = Action.MoveNorthLeft;
103 break;
104 case 'u':
105 tmp = Action.MoveNorthRight;
106 break;
107 case 'b':
108 tmp = Action.MoveSouthLeft;
109 break;
110 case 'n':
111 tmp = Action.MoveSouthRight;
112 break;
113 case 'q':
114 tmp = Action.Quit;
115 break;
116 case '.':
117 tmp = Action.Wait;
118 break;
119 case 'w': // (w)here am I?
120 tmp = Action.Printloc;
121 break;
122 default: assert(0);
124 return tmp;
133 class Game {
134 Being u;
135 Being[] mons;
136 Graphics1 graphics;
137 Map map;
139 this(string[] args) {
140 graphics = new Default_chargfx!BLT0(this);
142 this.map = genmap(MapType.caves);
144 mons = [u = new You(graphics)];
145 foreach (_; 1..10) {
146 mons ~= new Mon();
149 // Fill with " "
150 map.for_all((ref Tile x) => x.setdefglyph());
152 parseargs(args);
154 // If we didn't have this, then if (0, 0) was walkable, then you would automatically get placed there
155 foreach (ref m; mons) {
156 do {
157 m.loc.x = rn1(map_x+1);
158 m.loc.y = rn1(map_y+1);
159 } while ((!map[m.loc].walkable) || !mon_at(m.loc));
162 u.glyph = Glyph.at;
165 // TODO
166 void parseargs(string[] args) {
167 if (args.length == 2) {
168 if (args[1] == "dumpmap") {
169 dumpmap();
170 exit(0);
171 } else if (args[1] == "dumphtmlmap") {
172 dumphtmlmap();
173 exit(0);
178 // Name credit to lrogue
179 ref Being mon_at(uint y, uint x) {
180 foreach (ref tmpmon; mons) {
181 if ((tmpmon.loc.y == y) && (tmpmon.loc.x == x)) {
182 return tmpmon;
185 // Evil hackery so we can return null
186 static Being tmp = null;
187 return tmp;
189 ref Being mon_at(Vector2n loc) {
190 return mon_at(loc.y, loc.x);
194 void dumpmap() {
195 import std.stdio;
196 foreach (row; map.get_tiles) {
197 foreach (tile; row) {
198 write(cast(dchar)tile.glyph);
200 writeln();
203 void dumphtmlmap() {
204 import std.stdio;
205 writeln(`
206 <!doctype html>
207 <html lang="rl"> <!-- RogueLike! -->
208 <head>
209 <meta charset="utf-8">
210 <title>SmuglerRL HTML dump!</title>
211 </head>
212 <body fgcolor="#ffffff" bgcolor="#000000">
213 <div style="font-family: monospace">`);
215 bool clr_changed, bgclr_changed;
216 RGBColour fg, last_fg, bg, last_bg;
217 foreach (row; map.get_tiles) {
218 foreach (tile; row) {
219 fg = tile.fgcolour;
220 bg = tile.bgcolour;
222 if (fg != last_fg) {
223 clr_changed = true;
224 } else {
225 clr_changed = false;
227 if (bg != last_bg) {
228 bgclr_changed = true;
229 } else {
230 bgclr_changed = false;
233 if (clr_changed) write(`</font>`);
234 if (bgclr_changed) write(`</font>`);
235 if (clr_changed) {
236 with (fg) writef(`<font color="#%02x%02x%02x">`, r, g, b);
237 last_fg = fg;
239 if (bgclr_changed) {
240 with (bg) writef(`<font bgcolor="#%02x%02x%02x">`, r, g, b);
241 last_bg = bg;
243 write(cast(dchar)tile.glyph);
245 writeln("<br>");
247 writeln(`</div>
248 </body>
249 </html>`);
252 ~this() {
253 terminal.close();
255 pragma(inline, true) void refresh() {
256 graphics.refresh();
258 pragma(inline, true) void pline(T...)(T args) {
259 graphics.pline(args);
262 void mainloop() {
263 bool moving;
264 int deltax, deltay;
265 Action act;
267 refresh();
268 void handlemove(int yshift, int xshift, ref Being b) {
269 if (/*map[b.loc.y+yshift, b.loc.x+xshift].walkable && */!mon_at(b.loc.y+yshift, b.loc.x+xshift)) {
270 map[b.loc.y, b.loc.x].setdefglyph();
271 b.loc.y = b.loc.y + yshift;
272 b.loc.x = b.loc.x + xshift;
273 // pline("another message, of exceeding length. You should eat it, if you feel like, but make sure it's still long enough. Ugh, it has to be *LONGER*?? FINE>>>");
274 } else {
275 // only when *you* walk into a wall
276 if (cast(You)b) pline("there is a thingy there!");
279 outerloop: while (true) { refresh(); foreach (ref Being mon; mons) {
280 act = mon.getaction();
281 // If we're moving, then move!
282 if ((Action.MoveNorth <= act) && (act <= Action.MoveSouthRight)) {
283 moving = true;
284 } else {
285 moving = false;
287 switch(act) {
288 case Action.MoveNorth:
289 deltay = -1;
290 break;
291 case Action.MoveSouth:
292 // ayyy
293 deltay = 1;
294 break;
295 case Action.MoveLeft:
296 deltax = -1;
297 break;
298 case Action.MoveRight:
299 deltax = 1;
300 break;
301 case Action.MoveNorthLeft:
302 deltay = deltax = -1;
303 break;
304 case Action.MoveNorthRight:
305 deltay = -1;
306 deltax = 1;
307 break;
308 case Action.MoveSouthLeft:
309 deltay = 1;
310 deltax = -1;
311 break;
312 case Action.MoveSouthRight:
313 deltay = deltax = 1;
314 break;
315 case Action.Wait:
316 break;
317 case Action.Quit:
318 break outerloop;
319 case Action.Printloc:
320 pline("(%s, %s)", mon.loc.x, mon.loc.y);
321 break;
322 default: assert(0);
326 if (moving) {
327 handlemove(deltay, deltax, mon);
329 if (cast(You)mon) { refresh(); }
331 deltay = deltax = 0;
333 refresh();
334 do_fov(map, u.loc.x, u.loc.y, 100, true);
336 graphics.close();