Fix fov being recalculated when you move into a wall. Because I'm stupid
[SmugglerRL.git] / src / game.d
blob58af66baa9a4b1a1d25f9ad5eab574151c98d202
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 util;
20 abstract class Being {
21 int i;
22 private bool gender;
23 ubyte xlvl;
24 int xp, hp = 30, maxhp, mp, maxmp;
25 Vector2n loc;
26 RGBColour fgcolour, bgcolour;
27 Glyph glyph;
28 Item[] inventory;
30 private struct _attr { bool reverse, italic, bold, underline; }
31 _attr attrs;
33 pragma(inline, true) {
34 pure void inchp(int amount=1) {
35 if ((amount + hp) > maxhp) {
36 hp = maxhp;
37 } else {
38 hp += amount;
41 pure bool ismale() {
42 return gender;
44 pure bool isfemale() {
45 return !gender;
49 Action getaction();
52 class Mon: Being {
53 override Action getaction() {
54 return rnd(Action.MoveNorth, Action.MoveSouthRight);
56 this() {
57 fgcolour = RGBColour(0x00ff00);
58 bgcolour = RGBColour(0xff00ff);
59 attrs.reverse = true;
60 this.glyph = Glyph.r;
64 class You: Being {
65 Graphics1 graphics;
66 this(Graphics1 g) {
67 fgcolour = RGBColour(0xffffff);
68 bgcolour = RGBColour(0x000000);
69 attrs.reverse = true;
71 this.graphics = g;
72 this.glyph = Glyph.at;
74 override Action getaction() {
75 static immutable auto vikeys = set!dchar('h', 'j', 'k', 'l', 'y', 'u', 'b', 'n', 'q', '.', 'w');
77 Action tmp;
78 dchar c;
80 while ((c = graphics.getch()) !in vikeys) {}
82 switch (c) {
83 case 'h':
84 tmp = Action.MoveLeft;
85 break;
86 case 'l':
87 tmp = Action.MoveRight;
88 break;
89 case 'j':
90 tmp = Action.MoveSouth;
91 break;
92 case 'k':
93 tmp = Action.MoveNorth;
94 break;
95 case 'y':
96 tmp = Action.MoveNorthLeft;
97 break;
98 case 'u':
99 tmp = Action.MoveNorthRight;
100 break;
101 case 'b':
102 tmp = Action.MoveSouthLeft;
103 break;
104 case 'n':
105 tmp = Action.MoveSouthRight;
106 break;
108 /+ TODO
109 case 'H':
110 tmp = Action.AttackLeft;
111 break;
112 case 'L':
113 tmp = Action.AttackRight;
114 break;
115 case 'J':
116 tmp = Action.AttackSouth;
117 break;
118 case 'K':
119 tmp = Action.AttackNorth;
120 break;
121 case 'Y':
122 tmp = Action.AttackNorthLeft;
123 break;
124 case 'U':
125 tmp = Action.AttackNorthRight;
126 break;
127 case 'B':
128 tmp = Action.AttackSouthLeft;
129 break;
130 case 'N':
131 tmp = Action.AttackSouthRight;
132 break;
135 case 'q':
136 tmp = Action.Quit;
137 break;
138 case '.':
139 tmp = Action.Wait;
140 break;
141 case 'w': // (w)here am I?
142 tmp = Action.Printloc;
143 break;
144 case ',':
145 tmp = Action.Pickup;
146 break;
147 case 'i':
148 tmp = Action.Showinv;
149 break;
150 default: assert(0);
152 return tmp;
160 class Game {
161 Being u;
162 list!Being mons;
163 list!Item items;
164 Graphics1 graphics;
165 Map map;
167 this(string[] args) {
168 graphics = new Default_chargfx!BLT0("SmugglerRL!");
170 this.map = genmap(MapType.caves);
172 mons = [u = new You(graphics)];
173 foreach (_; 1 .. 1000) {
174 mons ~= new Mon();
177 // Fill with " "
178 map.for_all((ref Tile x) => x.setdefglyph());
180 parseargs(args);
182 // If we didn't have this, then if (0, 0) was walkable, then you would automatically get placed there
183 foreach (ref m; mons) {
184 do {
185 m.loc.x = rn1(map_x+1);
186 m.loc.y = rn1(map_y+1);
187 } while ((!map[m.loc].walkable) || !mon_at(m.loc));
191 foreach (_; 1 .. 100) {
192 items ~= Item(choice(all_items));
194 foreach (ref i; items) {
195 do {
196 i.loc.x = rn1(map_x+1);
197 i.loc.y = rn1(map_y+1);
198 } while (!map[i.loc].walkable);
201 u.glyph = Glyph.at;
204 // TODO
205 void parseargs(string[] args) {
206 if (args.length == 2) {
207 if (args[1] == "dumpmap") {
208 dumpmap();
209 exit(0);
210 } else if (args[1] == "dumphtmlmap") {
211 dumphtmlmap();
212 exit(0);
217 // Name credit to lrogue
218 ref Being mon_at(uint y, uint x) {
219 foreach (ref tmpmon; mons) {
220 if ((tmpmon.loc.y == y) && (tmpmon.loc.x == x)) {
221 return tmpmon;
224 // Evil hackery so we can return null
225 static Being tmp = null;
226 return tmp;
228 ref Being mon_at(Vector2n loc) {
229 return mon_at(loc.y, loc.x);
233 void dumpmap() {
234 import std.stdio;
235 foreach (row; map.get_tiles) {
236 foreach (tile; row) {
237 write(cast(dchar)tile.glyph);
239 writeln();
242 void dumphtmlmap() {
243 import std.stdio;
244 writeln(`
245 <!doctype html>
246 <html lang="rl"> <!-- RogueLike! -->
247 <head>
248 <meta charset="utf-8">
249 <title>SmuglerRL HTML dump!</title>
250 </head>
251 <body fgcolor="#ffffff" bgcolor="#000000">
252 <div style="font-family: monospace">`);
254 bool clr_changed, bgclr_changed;
255 RGBColour fg, last_fg, bg, last_bg;
256 foreach (row; map.get_tiles) {
257 foreach (tile; row) {
258 fg = tile.fgcolour;
259 bg = tile.bgcolour;
261 if (fg != last_fg) {
262 clr_changed = true;
263 } else {
264 clr_changed = false;
266 if (bg != last_bg) {
267 bgclr_changed = true;
268 } else {
269 bgclr_changed = false;
272 if (clr_changed) write(`</font>`);
273 if (bgclr_changed) write(`</font>`);
274 if (clr_changed) {
275 with (fg) writef(`<font color="#%02x%02x%02x">`, r, g, b);
276 last_fg = fg;
278 if (bgclr_changed) {
279 with (bg) writef(`<font bgcolor="#%02x%02x%02x">`, r, g, b);
280 last_bg = bg;
282 write(cast(dchar)tile.glyph);
284 writeln("<br>");
286 writeln(`</div>
287 </body>
288 </html>`);
291 ~this() {
292 terminal.close();
294 pragma(inline, true) void refresh() {
295 graphics.refresh(u.loc.y, u.loc.x, mons, map);
297 pragma(inline, true) void pline(T...)(T args) {
298 graphics.pline(args);
301 void mainloop() {
302 bool moving;
303 int deltax, deltay;
304 Action act;
306 refresh();
307 void handlemove(int yshift, int xshift, ref Being b) {
308 if (map[b.loc.y+yshift, b.loc.x+xshift].walkable && !mon_at(b.loc.y+yshift, b.loc.x+xshift)) {
309 map[b.loc.y, b.loc.x].setdefglyph();
310 b.loc.y = b.loc.y + yshift;
311 b.loc.x = b.loc.x + xshift;
312 } else {
313 // only when *you* walk into a wall
314 if (cast(You)b) pline("there is a thingy there!");
317 outerloop: while (true) { foreach (ref Being mon; mons) {
318 act = mon.getaction();
319 // If we're moving, then move!
320 if ((Action.MoveNorth <= act) && (act <= Action.MoveSouthRight)) {
321 moving = true;
322 } else {
323 moving = false;
325 switch(act) {
326 case Action.MoveNorth:
327 deltay = -1;
328 break;
329 case Action.MoveSouth:
330 // ayyy
331 deltay = 1;
332 break;
333 case Action.MoveLeft:
334 deltax = -1;
335 break;
336 case Action.MoveRight:
337 deltax = 1;
338 break;
339 case Action.MoveNorthLeft:
340 deltay = deltax = -1;
341 break;
342 case Action.MoveNorthRight:
343 deltay = -1;
344 deltax = 1;
345 break;
346 case Action.MoveSouthLeft:
347 deltay = 1;
348 deltax = -1;
349 break;
350 case Action.MoveSouthRight:
351 deltay = deltax = 1;
352 break;
353 case Action.Wait:
354 break;
355 case Action.Quit:
356 break outerloop;
357 case Action.Printloc:
358 pline("(%s, %s)", mon.loc.x, mon.loc.y);
359 break;
360 default: assert(0);
364 if (moving) {
365 handlemove(deltay, deltax, mon);
367 //if (cast(You)mon) { refresh(); }
369 deltay = deltax = 0;
371 do_fov(map, u.loc.x, u.loc.y, 100);
372 refresh();
374 graphics.close();