Introduction
Introduction Statistics Contact Development Disclaimer Help
ui_rogue.c - sacc - sacc - sacc(omys), simple console gopher client (config)
git clone git://git.codemadness.org/sacc
Log
Files
Refs
LICENSE
---
ui_rogue.c (29707B)
---
1 #include <errno.h>
2 #include <signal.h>
3 #include <stdarg.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <term.h>
9 #include <termios.h>
10 #include <unistd.h>
11 #include <sys/select.h>
12 #include <sys/types.h>
13
14 #include "common.h"
15 #include "config.h"
16
17 #define C(c) #c
18 #define S(c) C(c)
19
20 /* ncurses doesn't define those in term.h, where they're used */
21 #ifndef OK
22 #define OK (0)
23 #endif
24 #ifndef ERR
25 #define ERR (-1)
26 #endif
27
28 #define maplines (lines - 2)
29
30 enum {
31 Blocks = 1,
32 Standout = 2,
33 Important = 4
34 };
35
36 struct cell;
37 struct tile {
38 char c;
39 char flags;
40 char *name;
41 char *description;
42 char *afterinteract;
43 Item *(*interact)(struct cell *);
44 };
45
46 struct cell {
47 struct tile *tile;
48 size_t nitems;
49 Item **items;
50 };
51
52 struct room {
53 size_t x, y;
54 size_t w, h;
55 };
56
57 struct rect {
58 struct rect *next, *next2;
59 struct rect *p;
60 size_t x1, y1;
61 size_t x2, y2;
62 size_t d;
63 union {
64 void *p;
65 int i;
66 } data;
67 };
68
69 static struct termios tsave;
70 static struct termios tsacc;
71 static Item *curentry;
72 static int termset = ERR;
73 static char bufout[256];
74 static char bufout2[256];
75
76 size_t ox, oy;
77 size_t px, py;
78
79 #define MAPHEIGHT (50)
80 #define MAPWIDTH (160)
81 struct cell map[MAPHEIGHT][MAPWIDTH];
82
83 enum {
84 DungeonScreen,
85 MenuScreen
86 } screen;
87
88 Item *interactitem(struct cell *);
89 Item *interactmenu(struct cell *);
90
91 struct tile tile_void = { ' ', Blocks, "Void", "The void. The thing whic…
92 struct tile tile_floor = { '.', 0, "Floor", "An ordinary stone floor.", …
93 struct tile tile_corridor = { '#', 0, "Different Floor", "This floor loo…
94 struct tile tile_verticalwall = { '|', Blocks, "Wall", "Wall.", NULL, NU…
95 struct tile tile_horizontalwall = { '-', Blocks, "Wall", "Wall.", NULL, …
96 struct tile tile_door = { '/', 0, "Door", "A door.", NULL, NULL };
97 struct tile tile_bookshelf = { 'E', Important, "Bookshelf", "A bookshelf…
98 struct tile tile_book = { '?', Important, "%s", "A book: '%s'.", "A load…
99 struct tile tile_portal = { '0', Important, "%s", "A portal: '%s'.", "Yo…
100 struct tile tile_portalmachine = { 'O', Important, "Portal Machine", "A …
101 struct tile tile_heapofstuff = { '%', Important, "Heap", "A heap of stuf…
102 struct tile tile_elevator = { 'L', Important, "Elevator", "An elevator."…
103 struct tile tile_stairsdown = { '>', Important, "'%s'", "A staircase lea…
104
105 struct tile tile_stairsup = { '<', Standout | Important, "'%s'", "A stai…
106 struct tile tile_backportal = { '0', Standout | Important, "'%s'", "A po…
107
108 void drawscreen(void);
109
110 int
111 mygetchar_(void)
112 {
113 int r;
114 fd_set fdset;
115
116 FD_ZERO(&fdset);
117 FD_SET(0, &fdset);
118
119 if ((r = select(1, &fdset, NULL, NULL, NULL)) == -1) {
120 if (errno == EINTR)
121 return -1;
122 return -2;
123 }
124
125 return getchar();
126 }
127
128 volatile sig_atomic_t sigwinch;
129
130 int
131 mygetchar(void)
132 {
133 int r;
134
135 while ((r = mygetchar_()) == -1) {
136 if (sigwinch) {
137 sigwinch = 0;
138
139 if (termset == OK)
140 del_curterm(cur_term);
141 termset = setupterm(NULL, 1, NULL);
142
143 drawscreen();
144 }
145 }
146
147 if (r == -2)
148 die("mygetchar: %s", strerror(errno));
149
150 return r;
151 }
152
153 /*
154 FNV-1a ( http://www.isthe.com/chongo/tech/comp/fnv/ )
155 FNV was published into the public domain ( https://creativecommo…
156 by Landon Curt Noll: http://www.isthe.com/chongo/tech/comp/fnv/#…
157 */
158 uint32_t
159 fnv1a(int n,...)
160 {
161 int i;
162 char *s;
163 va_list l;
164 uint32_t h;
165
166 h = 0x811c9dc5;
167
168 va_start(l, n);
169 for (i = 0; i < n; i++) {
170 for (s = va_arg(l, char*); *s; s++) {
171 h ^= *s;
172 h *= 0x01000193;
173 }
174 }
175 va_end(l);
176
177 return h;
178 }
179
180 /*
181 An LCG using the constants from "Numerical Recipes".
182 */
183 uint16_t
184 ranqd1(uint32_t *s)
185 {
186 return (*s = 1664525 * (*s) + 1013904223) >> 16;
187 }
188
189 struct rect *
190 randomneighbor(struct rect *x, struct rect *rs, uint32_t *prng, int (*fi…
191 {
192 struct rect *r, *result;
193 size_t n;
194
195 n = 0;
196 result = NULL;
197 for (r = rs; r; r = r->next) {
198 if (r == x)
199 continue;
200 if (r->y2 < x->y1 || r->y1 > x->y2 || r->x2 < x->x1 || r…
201 continue;
202 if ((r->y2 == x->y1 || r->y1 == x->y2) && (r->x2 == x->x…
203 continue;
204 if (!filter(x, r))
205 continue;
206 n++;
207 if (ranqd1(prng) / (1. + UINT16_MAX) < 1. / n)
208 result = r;
209 }
210
211 return result;
212 }
213
214 size_t
215 min(size_t a, size_t b)
216 {
217 if (a < b)
218 return a;
219 return b;
220 }
221
222 size_t
223 max(size_t a, size_t b)
224 {
225 if (a > b)
226 return a;
227 return b;
228 }
229
230 /*
231 Creates an uneven grid by splitting the map recursively.
232 Returns an array containing the cells (rects) of the grid.
233 */
234 struct rect *
235 generaterects(size_t heightmin, size_t widthmin, uint32_t prng)
236 {
237 struct rect *queuehead, *queuetail;
238 struct rect *r, *t;
239 struct rect *rects;
240 size_t w, h;
241 int vertical, spaceforvertical, spaceforhorizontal;
242
243 r = malloc(sizeof(*r));
244 memset(r, 0, sizeof(*r));
245 r->x1 = r->y1 = 0;
246 r->x2 = MAPWIDTH;
247 r->y2 = MAPHEIGHT;
248 r->d = 0;
249
250 queuetail = r;
251 queuetail->next = NULL;
252 queuehead = r;
253
254 rects = NULL;
255
256 while (queuehead) {
257 r = queuehead;
258 if (queuetail == queuehead)
259 queuetail = NULL;
260 queuehead = queuehead->next;
261
262 spaceforvertical = r->y2 - r->y1 >= heightmin * 2;
263 spaceforhorizontal = r->x2 - r->x1 >= widthmin * 2;
264
265 if (spaceforhorizontal && spaceforvertical) {
266 vertical = ranqd1(&prng) & 1;
267 } else if (spaceforhorizontal) {
268 vertical = 0;
269 } else if (spaceforvertical) {
270 vertical = 1;
271 } else {
272 r->next = rects;
273 rects = r;
274 continue;
275 }
276
277 if (vertical) {
278 w = r->x2 - r->x1;
279 h = heightmin + ranqd1(&prng) % (1 + r->y2 - r->…
280 } else {
281 w = widthmin + ranqd1(&prng) % (1 + r->x2 - r->x…
282 h = r->y2 - r->y1;
283 }
284
285 t = malloc(sizeof(*t));
286 memset(t, 0, sizeof(*t));
287 t->x1 = r->x1;
288 t->y1 = r->y1;
289 t->x2 = r->x1 + w;
290 t->y2 = r->y1 + h;
291 t->d = r->d + 1;
292
293 if (!queuetail) {
294 queuehead = t;
295 queuetail = t;
296 } else {
297 queuetail->next = t;
298 queuetail = t;
299 }
300
301 t = malloc(sizeof(*t));
302 memset(t, 0, sizeof(*t));
303 if (vertical) {
304 t->x1 = r->x1;
305 t->y1 = r->y1 + h;
306 } else {
307 t->x1 = r->x1 + w;
308 t->y1 = r->y1;
309 }
310 t->x2 = r->x2;
311 t->y2 = r->y2;
312 t->d = r->d + 1;
313
314 queuetail->next = t;
315 queuetail = t;
316
317 free(r);
318 }
319
320 return rects;
321 }
322
323 void
324 connectpoints_horizontal(size_t y,
325 size_t ax, int ea, struct tile *at,
326 size_t bx, int eb, struct tile *bt,
327 struct tile *t)
328 {
329 size_t i, s, e;
330 ssize_t ii;
331
332 if (ax < bx)
333 ii = 1;
334 else if (ax > bx)
335 ii = -1;
336 else
337 ii = 0;
338
339 s = ax;
340 if (ea)
341 s += ii;
342 e = bx + ii;
343 if (eb)
344 e -= ii;
345
346 for (i = s; i != e; i += ii)
347 map[y][i].tile = t;
348
349 if (e - ii == s) {
350 if (at != t)
351 map[y][s].tile = at;
352 if (bt != t)
353 map[y][s].tile = bt;
354 } else {
355 map[y][s].tile = at;
356 map[y][e - ii].tile = bt;
357 }
358 }
359
360 void
361 connectpoints_vertical(size_t x,
362 size_t ay, int ea, struct tile *at,
363 size_t by, int eb, struct tile *bt,
364 struct tile *t)
365 {
366 size_t i, s, e;
367 ssize_t ii;
368
369 if (ay < by)
370 ii = 1;
371 else if (ay > by)
372 ii = -1;
373 else
374 ii = 0;
375
376 s = ay;
377 if (ea)
378 s += ii;
379 e = by + ii;
380 if (eb)
381 e -= ii;
382
383 for (i = s; i != e; i += ii)
384 map[i][x].tile = t;
385
386 if (e - ii == s) {
387 if (at != t)
388 map[s][x].tile = at;
389 if (bt != t)
390 map[s][x].tile = bt;
391 } else {
392 map[s][x].tile = at;
393 map[e - ii][x].tile = bt;
394 }
395 }
396
397 void
398 connectpoints(size_t ax, size_t ay, int ea, struct tile *at,
399 size_t bx, size_t by, int eb, struct tile *bt,
400 int vertical, struct tile *ct)
401 {
402 if (!vertical) {
403 connectpoints_horizontal(ay,
404 ax, ea, at,
405 bx, 0, ct,
406 ct);
407 connectpoints_vertical(bx,
408 ay, 0, ct,
409 by, eb, bt,
410 ct);
411 } else {
412 connectpoints_vertical(ax,
413 ay, ea, at,
414 by, 0, ct,
415 ct);
416 connectpoints_horizontal(by,
417 ax, 0, ct,
418 bx, eb, bt,
419 ct);
420 }
421 }
422
423 void
424 nearestpoints(struct room *a, struct room *b, size_t *ax, size_t *ay, si…
425 {
426 if (a->y >= b->y && a->y < b->y + b->h) {
427 *ay = *by = a->y;
428 } else if (b->y >= a->y && b->y < a->y + a->h) {
429 *ay = *by = b->y;
430 } else if (a->y >= b->y) {
431 *ay = a->y;
432 *by = b->y + b->h - 1;
433 } else if (b->y >= a->y) {
434 *ay = a->y + a->h - 1;
435 *by = b->y;
436 }
437
438 if (a->x >= b->x && a->x < b->x + b->w) {
439 *ax = *bx = a->x;
440 } else if (b->x >= a->x && b->x < a->x + a->w) {
441 *ax = *bx = b->x;
442 } else if (a->x >= b->x) {
443 *ax = a->x;
444 *bx = b->x + b->w - 1;
445 } else if (b->x >= a->x) {
446 *ax = a->x + a->w - 1;
447 *bx = b->x;
448 }
449 }
450
451 void
452 connectadjacentrooms(struct rect *a, struct room *ar, struct rect *b, st…
453 {
454 size_t irx1, iry1, irx2, iry2;
455 size_t rx1, ry1, rx2, ry2;
456 size_t cx, cy;
457 struct rect *r1, *r2;
458 struct room *room1, *room2;
459 int vertical;
460
461 if (a->x2 == b->x1) {
462 r1 = a;
463 room1 = ar;
464 r2 = b;
465 room2 = br;
466 } else if (b->x2 == a->x1) {
467 r1 = b;
468 room1 = br;
469 r2 = a;
470 room2 = ar;
471 } else if (a->y2 == b->y1) {
472 r1 = a;
473 room1 = ar;
474 r2 = b;
475 room2 = br;
476 } else if (b->y2 == a->y1) {
477 r1 = b;
478 room1 = br;
479 room2 = ar;
480 r2 = a;
481 } else {
482 return;
483 }
484
485 if (r1->y2 == r2->y1) {
486 irx1 = max(r1->x1, r2->x1);
487 irx2 = min(r1->x2, r2->x2);
488 iry1 = r1->y2;
489 iry2 = r1->y2 + 1;
490 } else {
491 iry1 = max(r1->y1, r2->y1);
492 iry2 = min(r1->y2, r2->y2);
493 irx1 = r1->x2;
494 irx2 = r1->x2 + 1;
495 }
496
497 nearestpoints(room1, room2, &rx1, &ry1, &rx2, &ry2);
498
499 if (r1->y2 == r2->y1) {
500 /* both points are in the intersection */
501 if (rx1 >= irx1 && rx1 < irx2 &&
502 rx2 >= irx1 && rx2 < irx2) {
503 vertical = 1;
504 cx = (rx2 + rx1) / 2;
505 cy = (ry2 + ry1) / 2;
506 } else
507 /* none is in the intersection */
508 if (!(rx1 >= irx1 && rx1 < irx2) &&
509 !(rx2 >= irx1 && rx2 < irx2)) {
510 vertical = 0;
511 cx = irx1;
512 cy = r1->y2;
513 } else if (rx1 >= irx1 && rx1 < irx2) {
514 vertical = 1;
515 cx = (rx2 + rx1) / 2;
516 cy = r1->y2;
517 } else if (rx2 >= irx1 && rx2 < irx2) {
518 vertical = 1;
519 cx = rx2;
520 cy = r1->y2 - 1;
521 }
522 } else {
523 /* both points are in the intersection */
524 if (ry1 >= iry1 && ry1 < iry2 &&
525 ry2 >= iry1 && ry2 < iry2) {
526 vertical = 0;
527 cx = (rx2 + rx1) / 2;
528 cy = (ry2 + ry1) / 2;
529 } else
530 /* none is in the intersection */
531 if (!(ry1 >= iry1 && ry1 < iry2) &&
532 !(ry2 >= iry1 && ry2 < iry2)) {
533 vertical = 1;
534 cx = r1->x2;
535 cy = iry1;
536 } else if (ry1 >= iry1 && ry1 < iry2) {
537 vertical = 0;
538 cx = r1->x2;
539 cy = (ry2 + ry1) / 2;
540 } else if (ry2 >= iry1 && ry2 < iry2) {
541 vertical = 0;
542 cx = r1->x2 - 1;
543 cy = ry2;
544 }
545 }
546
547 if (rx1 == rx2) {
548 connectpoints_vertical(rx1,
549 ry1, 1, &tile_door,
550 ry2, 1, &tile_door,
551 &tile_corridor);
552 } else if (ry1 == ry2) {
553 connectpoints_horizontal(ry1,
554 rx1, 1, &tile_door,
555 rx2, 1, &tile_door,
556 &tile_corridor);
557 } else {
558 connectpoints(rx1, ry1, 1, &tile_door,
559 cx, cy, 0, &tile_corridor,
560 vertical, &tile_corridor);
561 connectpoints(cx, cy, 1, &tile_corridor,
562 rx2, ry2, 1, &tile_door,
563 !vertical, &tile_corridor);
564 }
565 }
566
567 int
568 rectisfull(struct rect *x, struct rect *r)
569 {
570 return !!r->data.i;
571 }
572
573 int
574 rectisempty(struct rect *x, struct rect *r)
575 {
576 return !r->data.i;
577 }
578
579 int
580 rectisnotp(struct rect *x, struct rect *r)
581 {
582 return r->data.p && x->p != r && r->p != x;
583 }
584
585 int
586 rectisrandom(struct rect *x, struct rect *r)
587 {
588 return 1;
589 }
590
591 /*
592 Basically https://www.roguebasin.com/index.php/Diffusion-limited…
593 Returns the list of carved rooms.
594 */
595 struct rect *
596 dla(struct rect *rects, size_t l, uint32_t prng) {
597 size_t rl, i, n;
598 struct rect *r, *t, *walk, *p;
599
600 for (r = rects, rl = 0; r; r = r->next)
601 rl++;
602
603 if (l > rl)
604 l = rl;
605
606 /* get the rect which contains the map center */
607 for (r = rects; r; r = r->next) {
608 if (MAPHEIGHT / 2 >= r->y1 && MAPHEIGHT / 2 < r->y2 &&
609 MAPWIDTH / 2 >= r->x1 && MAPWIDTH / 2 < r->x2)
610 break;
611 }
612
613 p = NULL;
614 walk = NULL;
615 i = 0;
616 for (;;) {
617 r->p = p;
618 r->data.i = 1;
619 r->next2 = walk;
620 walk = r;
621
622 if (i >= l - 1)
623 break;
624
625 t = NULL;
626 for (r = rects, n = 0; r; r = r->next) {
627 if (r->data.i)
628 continue;
629 n++;
630 if (ranqd1(&prng) / (1. + UINT16_MAX) < 1. / n)
631 t = r;
632 }
633
634 /* there is no free rect left */
635 if (!t)
636 break;
637
638 /* do a random walk starting from t until the walk colli…
639 while ((r = randomneighbor(t, rects, &prng, rectisrandom…
640 t = r;
641
642 p = r;
643 r = t;
644
645 i++;
646 }
647
648 return walk;
649 }
650
651 void
652 rendermapchar(size_t i, size_t j) {
653 if (map[i][j].tile->flags & Standout)
654 putp(tiparm(enter_standout_mode));
655 putchar(map[i][j].tile->c);
656 if (map[i][j].tile->flags & Standout)
657 putp(tiparm(exit_standout_mode));
658 }
659
660 void
661 rendermapline(size_t i)
662 {
663 size_t j;
664
665 for (j = ox; j < min(MAPWIDTH, ox + columns); j++)
666 rendermapchar(i, j);
667 }
668
669 void
670 rendermap(void)
671 {
672 size_t i;
673
674 if (px < columns / 2 || MAPWIDTH <= columns)
675 ox = 0;
676 else if (px >= MAPWIDTH - columns / 2 - 1)
677 ox = MAPWIDTH - columns;
678 else
679 ox = px - columns / 2;
680
681 if (py < maplines / 2 || MAPHEIGHT <= maplines)
682 oy = 0;
683 else if (py >= MAPHEIGHT - maplines / 2 - 1)
684 oy = MAPHEIGHT - maplines;
685 else
686 oy = py - maplines / 2;
687
688 for (i = oy; i < min(MAPHEIGHT, oy + (lines - 2)); i++) {
689 if (i != oy)
690 putp(tiparm(cursor_down));
691 rendermapline(i);
692 }
693 }
694
695 size_t
696 placeitems_hash(Item *item, size_t *assocs, size_t k)
697 {
698 Dir *dir;
699 Item *citem;
700 size_t i;
701
702 dir = item->dat;
703 for (i = 0; i < dir->nitems; i++) {
704 citem = &dir->items[i];
705 /* TODO Somewhere else */
706 if (!citem->host || !citem->port || !citem->selector)
707 continue;
708 assocs[i] = fnv1a(6, item->host, item->port, item->selec…
709 }
710
711 return k;
712 }
713
714 #define POSITIONS_LENGTH 5
715 enum {
716 Portal,
717 StaircaseDown,
718 Bookshelf,
719 OtherStuff,
720 Back
721 };
722
723 enum {
724 FillEntireCell = 1
725 };
726
727 #define length(a) (sizeof(a) / sizeof(a[0]))
728 static struct dungeontype {
729 char *name;
730 char flags;
731 size_t heightmin;
732 size_t heightmax;
733 size_t widthmin;
734 size_t widthmax;
735 size_t margin;
736 size_t wiggle;
737 } dungeontypes[] = {
738 { "rogueish", 0, 2, 5, 3, 7, 2, 0 },
739 { "rogueish-wide", 0, 2, 5, 3, 7, 3, 1 },
740 { "compact", FillEntireCell, 2, 2, 3, 3, 1, 0 },
741 };
742
743 void
744 generatemap(Item *item, Item *pitem)
745 {
746 Dir *dir;
747 Item *citem;
748 size_t l, i, j, k, ir, n, m, x, y;
749 struct rect *rects, *walk, *tr, *cr;
750 struct room *rooms, *room;
751 size_t *cassocs;
752 int changedlevel, gonedown;
753 char buffer[10];
754 uint32_t prng;
755 struct {
756 size_t x, y;
757 } positions[POSITIONS_LENGTH];
758 size_t cellwidth, cellheight;
759 struct dungeontype *type;
760
761 type = &dungeontypes[fnv1a(3, item->host, item->port, "dungeonty…
762
763 cellheight = type->heightmin + 2 * type->margin + type->wiggle;
764 cellwidth = type->widthmin + 2 * type->margin + type->wiggle;
765
766 rects = generaterects(cellheight, cellwidth, fnv1a(4, item->host…
767
768 dir = item->dat;
769 for (j = l = 0; j < dir->nitems; j++) {
770 if (dir->items[j].type != 0 &&
771 dir->items[j].type != 'i' &&
772 dir->items[j].type != '3')
773 l++;
774 }
775
776 k = 1 + l / 10;
777 walk = dla(rects, k, fnv1a(4, item->host, item->port, item->sele…
778 for (cr = walk, k = 0; cr; cr = cr->next2, k++);
779
780 for (cr = rects; cr; cr = cr->next)
781 cr->data.p = NULL;
782
783 rooms = calloc(k, sizeof(*rooms));
784 for (cr = walk, i = 0; cr; cr = cr->next2, i++)
785 cr->data.p = &rooms[i];
786
787 prng = fnv1a(4, item->host, item->port, item->selector, "roomsse…
788 for (cr = walk; cr; cr = cr->next2) {
789 room = cr->data.p;
790
791 if (type->flags & FillEntireCell) {
792 room->w = cr->x2 - cr->x1 - 2 * type->margin;
793 room->x = cr->x1 + type->margin;
794 room->h = cr->y2 - cr->y1 - 2 * type->margin;
795 room->y = cr->y1 + type->margin;
796 } else {
797 room->w = type->widthmin + ranqd1(&prng) % (1 + …
798 room->x = cr->x1 + type->margin + ranqd1(&prng) …
799 room->h = type->heightmin + ranqd1(&prng) % (1 +…
800 room->y = cr->y1 + type->margin + ranqd1(&prng) …
801 }
802 }
803
804 for (i = 0; i < MAPHEIGHT; i++) {
805 for (j = 0; j < MAPWIDTH; j++) {
806 map[i][j].tile = &tile_void;
807 free(map[i][j].items);
808 map[i][j].items = NULL;
809 map[i][j].nitems = 0;
810 }
811 }
812
813 for (cr = walk; cr; cr = cr->next2) {
814 room = cr->data.p;
815
816 for (x = room->x - 1; x < room->x + room->w + 1; x++)
817 map[room->y-1][x].tile = &tile_horizontalwall;
818 for (y = room->y; y < room->y + room->h; y++) {
819 map[y][room->x - 1].tile = &tile_verticalwall;
820 for (x = room->x; x < room->x + room->w; x++)
821 map[y][x].tile = &tile_floor;
822 map[y][room->x + room->w].tile = &tile_verticalw…
823 }
824 for (x = room->x - 1; x < room->x + room->w + 1; x++)
825 map[room->y + room->h][x].tile = &tile_horizonta…
826 }
827
828 for (cr = walk; cr; cr = cr->next2) {
829 if (cr->p)
830 connectadjacentrooms(cr, cr->data.p,
831 cr->p, cr->p->data.p);
832
833 /* Add some loop possibility */
834 if (tr = randomneighbor(cr, rects, &prng, rectisnotp))
835 connectadjacentrooms(cr, cr->data.p,
836 tr, tr->data.p);
837 }
838
839 cassocs = calloc(dir->nitems, sizeof(*cassocs));
840
841 k = placeitems_hash(item, cassocs, k);
842
843 changedlevel = item != pitem;
844 gonedown = pitem == item->entry;
845
846 /*
847 Insert items
848 The placement of items affects the initial placement of …
849 player, because they could have gone back to this map, s…
850 should appear at the elevator/portal/stair they used.
851 */
852
853 /*
854 The initial room is everytime the first one. Reason: The…
855 of rooms is based on how many entries are in the gopherm…
856 how many rooms can fit on the map. There will be at mini…
857 So when more entries get added there will be more rooms …
858 first one stays at the same position. I think about the
859 retrying and clownflare things on bitreich.org, the sele…
860 doesn't change...
861 */
862 ir = 0;
863
864 for (i = 0; i < k; i++) {
865 /* select random positions for different item types insi…
866 snprintf(buffer, sizeof(buffer), "%lu", i);
867 prng = fnv1a(4, item->host, item->port, item->selector, …
868 for (j = 0, m = rooms[i].h * rooms[i].w; j < m; j++) {
869 n = j;
870 if (j >= POSITIONS_LENGTH)
871 n *= ranqd1(&prng) / (double)UINT16_MAX;
872
873 if (n < POSITIONS_LENGTH) {
874 positions[n].x = rooms[i].x + j % rooms[…
875 positions[n].y = rooms[i].y + j / rooms[…
876 }
877 }
878
879 for (j = 0; j < dir->nitems; j++) {
880 if (cassocs[j] != i)
881 continue;
882
883 citem = &dir->items[j];
884 switch (citem->type) {
885 case '0':
886 x = positions[Bookshelf].x;
887 y = positions[Bookshelf].y;
888 if (map[y][x].nitems)
889 map[y][x].tile = &tile_bookshelf;
890 else
891 map[y][x].tile = &tile_book;
892 break;
893 case '1':
894 if (strcmp(citem->host, item->host) || s…
895 x = positions[Portal].x;
896 y = positions[Portal].y;
897 if (map[y][x].nitems)
898 map[y][x].tile = &tile_p…
899 else
900 map[y][x].tile = &tile_p…
901 } else {
902 x = positions[StaircaseDown].x;
903 y = positions[StaircaseDown].y;
904 if (map[y][x].nitems)
905 map[y][x].tile = &tile_e…
906 else
907 map[y][x].tile = &tile_s…
908 }
909 break;
910 case 0:
911 case 'i':
912 case '3':
913 continue;
914 break;
915 default:
916 x = positions[OtherStuff].x;
917 y = positions[OtherStuff].y;
918 map[y][x].tile = &tile_heapofstuff;
919 break;
920 }
921
922 map[y][x].nitems++;
923 map[y][x].items = realloc(map[y][x].items, map[y…
924 map[y][x].items[map[y][x].nitems-1] = citem;
925
926 if (changedlevel && citem == pitem) {
927 px = x;
928 py = y;
929 }
930 }
931
932 if (i == ir && item->entry != item) {
933 y = positions[Back].y;
934 x = positions[Back].x;
935 if (strcmp(item->entry->host, item->host) || str…
936 map[y][x].tile = &tile_backportal;
937 else
938 map[y][x].tile = &tile_stairsup;
939 map[y][x].nitems++;
940 map[y][x].items = realloc(map[y][x].items, map[y…
941 map[y][x].items[map[y][x].nitems-1] = item->entr…
942 }
943
944 if (changedlevel && i == ir && (gonedown || !pitem)) {
945 px = positions[Back].x;
946 py = positions[Back].y;
947 }
948 }
949
950 free(cassocs);
951 free(rooms);
952
953 for (cr = rects; cr;) {
954 tr = cr;
955 cr = cr->next;
956 free(tr);
957 }
958 }
959
960 void
961 uisetup(void)
962 {
963 tcgetattr(0, &tsave);
964 tsacc = tsave;
965 tsacc.c_lflag &= ~(ECHO|ICANON);
966 tsacc.c_cc[VMIN] = 1;
967 tsacc.c_cc[VTIME] = 0;
968 tcsetattr(0, TCSANOW, &tsacc);
969
970 if (termset != OK)
971 /* setupterm call exits on error */
972 termset = setupterm(NULL, 1, NULL);
973 putp(tiparm(clear_screen));
974 fflush(stdout);
975 }
976
977 void
978 uicleanup(void)
979 {
980 tcsetattr(0, TCSANOW, &tsave);
981
982 if (termset != OK)
983 return;
984
985 putp(tiparm(change_scroll_region, 0, lines-1));
986 putp(tiparm(clear_screen));
987 fflush(stdout);
988 }
989
990 char *
991 uiprompt(char *fmt, ...)
992 {
993 va_list ap;
994 char *input = NULL;
995 size_t n;
996 ssize_t r;
997
998 putp(tiparm(save_cursor));
999
1000 putp(tiparm(cursor_address, lines-1, 0));
1001 putp(tiparm(clr_eol));
1002
1003 va_start(ap, fmt);
1004 vsnprintf(bufout, sizeof(bufout), fmt, ap);
1005 va_end(ap);
1006
1007 n = mbsprint(bufout, columns);
1008
1009 putp(tiparm(clr_eol));
1010
1011 putp(tiparm(cursor_address, lines-1, n));
1012
1013 tsacc.c_lflag |= (ECHO|ICANON);
1014 tcsetattr(0, TCSANOW, &tsacc);
1015 fflush(stdout);
1016
1017 n = 0;
1018 r = getline(&input, &n, stdin);
1019
1020 tsacc.c_lflag &= ~(ECHO|ICANON);
1021 tcsetattr(0, TCSANOW, &tsacc);
1022 putp(tiparm(restore_cursor));
1023 fflush(stdout);
1024
1025 if (r == -1 || feof(stdin)) {
1026 clearerr(stdin);
1027 clear(&input);
1028 } else if (input[r - 1] == '\n') {
1029 input[--r] = '\0';
1030 }
1031
1032 return input;
1033 }
1034
1035 void
1036 displaybar(char *s) {
1037 size_t n;
1038
1039 putp(tiparm(save_cursor));
1040
1041 putp(tiparm(cursor_address, lines-2, 0));
1042 putp(tiparm(enter_standout_mode));
1043
1044 n = mbsprint(s, columns);
1045 for (n = columns - n; n; n--)
1046 putchar(' ');
1047
1048 putp(tiparm(exit_standout_mode));
1049
1050 putp(tiparm(restore_cursor));
1051 fflush(stdout);
1052 }
1053
1054 void
1055 vdisplayinfoline(char *fmt, va_list ap)
1056 {
1057 putp(tiparm(save_cursor));
1058
1059 putp(tiparm(cursor_address, lines-1, 0));
1060
1061 vsnprintf(bufout, sizeof(bufout), fmt, ap);
1062
1063 mbsprint(bufout, columns);
1064
1065 putp(tiparm(clr_eol));
1066
1067 putp(tiparm(restore_cursor));
1068 fflush(stdout);
1069 }
1070
1071 void
1072 uistatus(char *fmt, ...)
1073 {
1074 va_list ap;
1075 size_t n;
1076
1077 putp(tiparm(save_cursor));
1078
1079 putp(tiparm(cursor_address, lines-1, 0));
1080
1081 va_start(ap, fmt);
1082 n = vsnprintf(bufout, sizeof(bufout), fmt, ap);
1083 va_end(ap);
1084
1085 if (n < sizeof(bufout)-1) {
1086 snprintf(bufout+n, sizeof(bufout)-n,
1087 " [Press a key to continue \xe2\x98\x83]");
1088 }
1089
1090 mbsprint(bufout, columns);
1091
1092 putp(tiparm(clr_eol));
1093
1094 putp(tiparm(restore_cursor));
1095 fflush(stdout);
1096
1097 mygetchar();
1098 }
1099
1100 void
1101 displayinfoline(char *fmt, ...)
1102 {
1103 va_list ap;
1104
1105 va_start(ap, fmt);
1106 vdisplayinfoline(fmt, ap);
1107 va_end(ap);
1108 }
1109
1110 char *menutitle;
1111 Item **menuitems;
1112 size_t menunitems;
1113 volatile size_t menuoffset;
1114 size_t menuselected;
1115
1116 void
1117 menudraw(void)
1118 {
1119 size_t i, n;
1120
1121 putp(tiparm(change_scroll_region, 1, lines-1));
1122 putp(tiparm(clear_screen));
1123
1124 putp(tiparm(enter_standout_mode));
1125 puts(menutitle);
1126 putp(tiparm(exit_standout_mode));
1127
1128 if (menuselected - menuoffset >= lines - 1)
1129 menuoffset = menuselected - (lines - 1) + 1;
1130
1131 for (i = menuoffset, n = 0; i < menunitems && n < lines - 1; i++…
1132 if (i != menuoffset)
1133 putp(tiparm(cursor_down));
1134 if (i == menuselected)
1135 putp(tiparm(enter_standout_mode));
1136 mbsprint(menuitems[i]->username, columns);
1137 if (i == menuselected)
1138 putp(tiparm(exit_standout_mode));
1139 putp(tiparm(column_address, 0));
1140 }
1141 fflush(stdout);
1142 }
1143
1144 Item *
1145 showmenu(char *title, Item **item, size_t l)
1146 {
1147 Item *selection;
1148
1149 menutitle = title;
1150 menuitems = item;
1151 menunitems = l;
1152 menuselected = 0;
1153 menuoffset = 0;
1154 screen = MenuScreen;
1155 drawscreen();
1156
1157 selection = NULL;
1158 for (;;) {
1159 switch (mygetchar()) {
1160 case 'j':
1161 if (menuselected + 1 < menunitems) {
1162 putp(tiparm(cursor_address, 1 + menusele…
1163 mbsprint(menuitems[menuselected]->userna…
1164 menuselected++;
1165 putp(tiparm(column_address, 0));
1166 if (menuselected - menuoffset >= lines -…
1167 menuoffset++;
1168 putp(tiparm(scroll_forward));
1169 } else {
1170 putp(tiparm(cursor_down));
1171 }
1172 putp(tiparm(enter_standout_mode));
1173 mbsprint(menuitems[menuselected]->userna…
1174 putp(tiparm(exit_standout_mode));
1175 }
1176 break;
1177 case 'k':
1178 if (menuselected > 0) {
1179 putp(tiparm(cursor_address, 1 + menusele…
1180 mbsprint(menuitems[menuselected]->userna…
1181 menuselected--;
1182 putp(tiparm(column_address, 0));
1183 if (menuselected < menuoffset) {
1184 menuoffset = menuselected;
1185 putp(tiparm(scroll_reverse));
1186 } else {
1187 putp(tiparm(cursor_up));
1188 }
1189 putp(tiparm(enter_standout_mode));
1190 mbsprint(menuitems[menuselected]->userna…
1191 putp(tiparm(exit_standout_mode));
1192 }
1193 break;
1194 case ' ':
1195 selection = menuitems[menuselected];
1196 case 0x1b:
1197 goto endloop;
1198 break;
1199 }
1200 fflush(stdout);
1201 }
1202
1203 endloop:
1204 screen = DungeonScreen;
1205 drawscreen();
1206
1207 return selection;
1208 }
1209
1210 Item *
1211 interactitem(struct cell *c)
1212 {
1213 displayinfoline(map[py][px].tile->afterinteract);
1214
1215 return map[py][px].items[0];
1216 }
1217
1218 Item *
1219 interactmenu(struct cell *c)
1220 {
1221 Item *selection;
1222
1223 if (selection = showmenu(map[py][px].tile->name, map[py][px].ite…
1224 displayinfoline(map[py][px].tile->afterinteract);
1225
1226 return selection;
1227 }
1228
1229 Item *
1230 interact(Item *item)
1231 {
1232 if (map[py][px].tile->interact)
1233 return map[py][px].tile->interact(&map[py][px]);
1234
1235 return NULL;
1236 }
1237
1238 void
1239 describe(size_t x, size_t y, int verbose)
1240 {
1241 char *name;
1242
1243 if (map[y][x].nitems) {
1244 if (*map[y][x].items[0]->username) {
1245 name = map[y][x].items[0]->username;
1246 } else {
1247 itemuri(map[y][x].items[0], bufout2, sizeof(bufo…
1248 name = bufout2;
1249 }
1250 } else {
1251 name = NULL;
1252 }
1253 if (map[y][x].tile->flags & Important || verbose)
1254 displayinfoline(map[y][x].tile->description, name);
1255 else
1256 displayinfoline("");
1257 }
1258
1259 void
1260 dungeondraw(void)
1261 {
1262 putp(tiparm(change_scroll_region, 0, lines-3));
1263 putp(tiparm(clear_screen));
1264
1265 rendermap();
1266
1267 putp(tiparm(cursor_address, py - oy, px - ox));
1268 putchar('@');
1269 putp(tiparm(cursor_address, py - oy, px - ox));
1270
1271 if (curentry->entry != curentry) {
1272 displaybar(curentry->username);
1273 } else {
1274 itemuri(curentry, bufout, sizeof(bufout));
1275 displaybar(bufout);
1276 }
1277
1278 describe(px, py, 0);
1279 }
1280
1281 void
1282 move(ssize_t dx, ssize_t dy)
1283 {
1284 ssize_t i;
1285 size_t x, y;
1286 size_t noy, nox;
1287
1288 if ((ssize_t)py + dy >= MAPHEIGHT || (ssize_t)py + dy < 0)
1289 return;
1290 if ((ssize_t)px + dx >= MAPWIDTH || (ssize_t)px + dx < 0)
1291 return;
1292
1293 x = px + dx;
1294 y = py + dy;
1295
1296 if (map[y][x].tile->flags & Blocks)
1297 return;
1298
1299 if (dx) {
1300 if (x < columns / 2 || MAPWIDTH <= columns)
1301 nox = 0;
1302 else if (x >= MAPWIDTH - columns / 2 - 1)
1303 nox = MAPWIDTH - columns;
1304 else
1305 nox = x - columns / 2;
1306
1307 if (ox != nox) {
1308 putp(tiparm(cursor_address, 0, 0));
1309 rendermap();
1310 } else {
1311 putp(tiparm(cursor_address, py - oy, px - ox));
1312 rendermapchar(py, px);
1313 }
1314 } else if (dy) {
1315 putp(tiparm(cursor_address, py - oy, px - ox));
1316 rendermapchar(py, px);
1317
1318 if (y < maplines / 2 || MAPHEIGHT <= maplines) {
1319 noy = 0;
1320 } else if (y >= MAPHEIGHT - maplines / 2 - 1) {
1321 noy = MAPHEIGHT - maplines;
1322 } else {
1323 noy = y - maplines / 2;
1324 }
1325
1326 if (noy < oy) {
1327 putp(tiparm(cursor_address, 0, 0));
1328 for (i = (ssize_t)oy - 1; i >= (ssize_t)noy; i--…
1329 putp(tiparm(scroll_reverse));
1330 rendermapline(i);
1331 putp(tiparm(column_address, 0));
1332 }
1333 } else if (noy > oy) {
1334 putp(tiparm(cursor_address, lines-3, 0));
1335 for (i = oy + 1; i <= noy; i++) {
1336 putp(tiparm(scroll_forward));
1337 rendermapline(i + maplines - 1);
1338 putp(tiparm(column_address, 0));
1339 }
1340 }
1341 oy = noy;
1342 }
1343
1344 py = y;
1345 px = x;
1346 putp(tiparm(cursor_address, py - oy, px - ox));
1347 putchar('@');
1348 putp(tiparm(cursor_address, py - oy, px - ox));
1349
1350 describe(px, py, 0);
1351 }
1352
1353 void
1354 drawscreen(void)
1355 {
1356 switch (screen) {
1357 case DungeonScreen:
1358 dungeondraw();
1359 break;
1360 case MenuScreen:
1361 menudraw();
1362 break;
1363 }
1364 fflush(stdout);
1365 }
1366
1367 void
1368 uidisplay(Item *entry)
1369 {
1370 if (!entry || !(entry->type == '1' || entry->type == '+' || entr…
1371 return;
1372
1373 if (entry != curentry) {
1374 generatemap(entry, curentry);
1375 curentry = entry;
1376 }
1377
1378 drawscreen();
1379 }
1380
1381 Item *
1382 uiselectitem(Item *entry)
1383 {
1384 Item *e;
1385
1386 if (!entry || !entry->dat)
1387 return NULL;
1388
1389 for (;;) {
1390 switch (mygetchar()) {
1391 case 'h':
1392 move(-1, 0);
1393 break;
1394 case 'j':
1395 move(0, 1);
1396 break;
1397 case 'k':
1398 move(0, -1);
1399 break;
1400 case 'l':
1401 move(1, 0);
1402 break;
1403 case ' ':
1404 if (e = interact(entry))
1405 return e;
1406 break;
1407 case 'q':
1408 case 0x1b:
1409 return NULL;
1410 }
1411 fflush(stdout);
1412 }
1413 }
1414
1415 void
1416 uisigwinch(int signal)
1417 {
1418 sigwinch = 1;
1419 }
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.