Name the tiles to make everything better because I'm a bloody idiot
[SmugglerRL.git] / src / game.d
blob61c01fe2bc8e1fd145ed5a5d81196285013b488f
1 import BearLibTerminal;
3 import stdlib;
5 import colour;
6 import constants;
7 import myfov;
8 import glyph;
9 import graphix;
10 import graphix0;
11 import item;
12 import logging;
13 import mapgen;
14 import map;
15 import rng;
16 import tile;
17 import util;
21 abstract class Being {
22 int i;
23 private bool gender;
24 ubyte xlvl;
25 int xp, hp = 30, maxhp, mp, maxmp;
26 Vector2n loc;
27 RGBColour fgcolour, bgcolour;
28 Glyph glyph;
29 Item[] inventory;
31 private struct _attr { bool reverse, italic, bold, underline; }
32 _attr attrs;
34 pragma(inline, true) {
35 pure void inchp(int amount=1) {
36 if ((amount + hp) > maxhp) {
37 hp = maxhp;
38 } else {
39 hp += amount;
42 pure bool ismale() {
43 return gender;
45 pure bool isfemale() {
46 return !gender;
50 Action getaction();
53 class Mon: Being {
54 override Action getaction() {
55 return rnd(Action.MoveNorth, Action.MoveSouthRight);
57 this() {
58 fgcolour = RGBColour(0x00ff00);
59 bgcolour = RGBColour(0xff00ff);
60 attrs.reverse = true;
61 this.glyph = Glyph.r;
65 class You: Being {
66 Graphics1 graphics;
67 this(Graphics1 g) {
68 fgcolour = RGBColour(0xffffff);
69 bgcolour = RGBColour(0x000000);
70 attrs.reverse = true;
72 this.graphics = g;
73 this.glyph = Glyph.at;
75 override Action getaction() {
76 static immutable auto vikeys = set!dchar('h', 'j', 'k', 'l', 'y', 'u', 'b', 'n', 'q', '.', 'w');
78 Action tmp;
79 dchar c;
81 while ((c = graphics.getch()) !in vikeys) {}
83 switch (c) {
84 case 'h':
85 tmp = Action.MoveLeft;
86 break;
87 case 'l':
88 tmp = Action.MoveRight;
89 break;
90 case 'j':
91 tmp = Action.MoveSouth;
92 break;
93 case 'k':
94 tmp = Action.MoveNorth;
95 break;
96 case 'y':
97 tmp = Action.MoveNorthLeft;
98 break;
99 case 'u':
100 tmp = Action.MoveNorthRight;
101 break;
102 case 'b':
103 tmp = Action.MoveSouthLeft;
104 break;
105 case 'n':
106 tmp = Action.MoveSouthRight;
107 break;
109 /+ TODO
110 case 'H':
111 tmp = Action.AttackLeft;
112 break;
113 case 'L':
114 tmp = Action.AttackRight;
115 break;
116 case 'J':
117 tmp = Action.AttackSouth;
118 break;
119 case 'K':
120 tmp = Action.AttackNorth;
121 break;
122 case 'Y':
123 tmp = Action.AttackNorthLeft;
124 break;
125 case 'U':
126 tmp = Action.AttackNorthRight;
127 break;
128 case 'B':
129 tmp = Action.AttackSouthLeft;
130 break;
131 case 'N':
132 tmp = Action.AttackSouthRight;
133 break;
136 case 'q':
137 tmp = Action.Quit;
138 break;
139 case '.':
140 tmp = Action.Wait;
141 break;
142 case 'w': // (w)here am I?
143 tmp = Action.Printloc;
144 break;
145 case ',':
146 tmp = Action.Pickup;
147 break;
148 case 'i':
149 tmp = Action.Showinv;
150 break;
151 default: assert(0);
153 return tmp;
161 class Game {
162 Being u;
163 list!Being mons;
164 list!Item items;
165 Graphics1 graphics;
166 Map map;
168 this(string[] args) {
169 graphics = new Default_chargfx!BLT0("SmugglerRL!");
171 this.map = genmap(MapType.caves);
173 mons = [u = new You(graphics)];
174 foreach (_; 1 .. 1000) {
175 mons ~= new Mon();
178 parseargs(args);
180 // If we didn't have this, then if (0, 0) was walkable, then you would automatically get placed there
181 foreach (ref m; mons) {
182 do {
183 m.loc.x = rn1(map_x+1);
184 m.loc.y = rn1(map_y+1);
185 } while ((!map[m.loc].walkable) || !mon_at(m.loc));
189 foreach (_; 1 .. 100) {
190 items ~= Item(choice(all_items));
192 foreach (ref i; items) {
193 do {
194 i.loc.x = rn1(map_x+1);
195 i.loc.y = rn1(map_y+1);
196 } while (!map[i.loc].walkable);
199 u.glyph = Glyph.at;
202 // TODO
203 void parseargs(string[] args) {
204 if (args.length == 2) {
205 if (args[1] == "dumpmap") {
206 dumpmap();
207 exit(0);
208 } else if (args[1] == "dumphtmlmap") {
209 dumphtmlmap();
210 exit(0);
215 // Name credit to lrogue
216 ref Being mon_at(uint y, uint x) {
217 foreach (ref tmpmon; mons) {
218 if ((tmpmon.loc.y == y) && (tmpmon.loc.x == x)) {
219 return tmpmon;
222 // Evil hackery so we can return null
223 static Being tmp = null;
224 return tmp;
226 ref Being mon_at(Vector2n loc) {
227 return mon_at(loc.y, loc.x);
231 void dumpmap() {
232 import std.stdio;
233 foreach (row; map.get_tiles) {
234 foreach (tile; row) {
235 write(cast(dchar)tile.glyph);
237 writeln();
240 void dumphtmlmap() {
241 import std.stdio;
242 writeln(`
243 <!doctype html>
244 <html lang="rl"> <!-- RogueLike! -->
245 <head>
246 <meta charset="utf-8">
247 <title>SmuglerRL HTML dump!</title>
248 </head>
249 <body fgcolor="#ffffff" bgcolor="#000000">
250 <div style="font-family: monospace">`);
252 bool clr_changed, bgclr_changed;
253 RGBColour fg, last_fg, bg, last_bg;
254 foreach (row; map.get_tiles) {
255 foreach (tile; row) {
256 fg = tile.fgcolour;
257 bg = tile.bgcolour;
259 if (fg != last_fg) {
260 clr_changed = true;
261 } else {
262 clr_changed = false;
264 if (bg != last_bg) {
265 bgclr_changed = true;
266 } else {
267 bgclr_changed = false;
270 if (clr_changed) write(`</font>`);
271 if (bgclr_changed) write(`</font>`);
272 if (clr_changed) {
273 with (fg) writef(`<font color="#%02x%02x%02x">`, r, g, b);
274 last_fg = fg;
276 if (bgclr_changed) {
277 with (bg) writef(`<font bgcolor="#%02x%02x%02x">`, r, g, b);
278 last_bg = bg;
280 write(cast(dchar)tile.glyph);
282 writeln("<br>");
284 writeln(`</div>
285 </body>
286 </html>`);
289 ~this() {
290 terminal.close();
292 pragma(inline, true) void refresh() {
293 graphics.refresh(u.loc.y, u.loc.x, mons, map);
295 pragma(inline, true) void pline(T...)(T args) {
296 graphics.pline(args);
299 void mainloop() {
300 bool moving;
301 int deltax, deltay;
302 Action act;
304 refresh();
305 void handlemove(int yshift, int xshift, ref Being b) {
306 if (map[b.loc.y+yshift, b.loc.x+xshift].walkable && !mon_at(b.loc.y+yshift, b.loc.x+xshift)) {
307 b.loc.y = b.loc.y + yshift;
308 b.loc.x = b.loc.x + xshift;
309 } else {
310 // only when *you* walk into a wall
311 if (cast(You)b) pline("there is a thingy there!");
314 outerloop: while (true) { foreach (ref Being mon; mons) {
315 act = mon.getaction();
316 // If we're moving, then move!
317 if ((Action.MoveNorth <= act) && (act <= Action.MoveSouthRight)) {
318 moving = true;
319 } else {
320 moving = false;
322 switch(act) {
323 case Action.MoveNorth:
324 deltay = -1;
325 break;
326 case Action.MoveSouth:
327 // ayyy
328 deltay = 1;
329 break;
330 case Action.MoveLeft:
331 deltax = -1;
332 break;
333 case Action.MoveRight:
334 deltax = 1;
335 break;
336 case Action.MoveNorthLeft:
337 deltay = deltax = -1;
338 break;
339 case Action.MoveNorthRight:
340 deltay = -1;
341 deltax = 1;
342 break;
343 case Action.MoveSouthLeft:
344 deltay = 1;
345 deltax = -1;
346 break;
347 case Action.MoveSouthRight:
348 deltay = deltax = 1;
349 break;
350 case Action.Wait:
351 break;
352 case Action.Quit:
353 break outerloop;
354 case Action.Printloc:
355 pline("(%s, %s)", mon.loc.x, mon.loc.y);
356 break;
357 default: assert(0);
361 if (moving) {
362 handlemove(deltay, deltax, mon);
365 deltay = deltax = 0;
367 do_fov(map, u.loc.x, u.loc.y, 1000);
369 refresh();
371 graphics.close();