Introduction
Introduction Statistics Contact Development Disclaimer Help
Update ui_rogue - sacc - sacc(omys), simple console gopher client
git clone git://bitreich.org/sacc/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65…
Log
Files
Refs
Tags
LICENSE
---
commit 90a9d3c81f27588c62faa43f22d946740042a3ce
parent cc6a6881e06ab4b851c7778842374b953e51539c
Author: Julian Schweinsberg <[email protected]>
Date: Mon, 28 Oct 2024 15:17:33 +0100
Update ui_rogue
ui_rogue: Overengineered Edition
This adds a readme and notes (mostly ideas) file for ui_rogue, too.
These changes were made half a year ago and I don't do real
documentation of my changes...
(There is some git branch, but the commit messages aren't helpful:
"HuH?!", "Well, better than nothing...", "Typical
pazz0-overengineering.", ...)
Changes:
- Better menus
- Bigger maps (160x50)
- Moving scrolls the displayed map if needed
- Rooms and corridors use ASCII characters to look like hack
- Removes look mode for now
- Replaces xorshift PRNG algorithm with ranqd1 (this means that the
layout of gopherholes change with this update)
- Moved setupterm call out of signal handler (IIRC [you remember:
months] there were some crashes I had in combination with heap
allocations, my thought was that setupterm is using heap allocations)
- Parameters for room generation are randomly selected (based on the
hostname and port) from a list of "dungeontypes"
Diffstat:
M ui_rogue.c | 1225 +++++++++++++++++++++--------…
A ui_rogue_notes | 31 +++++++++++++++++++++++++++++…
A ui_rogue_readme | 28 ++++++++++++++++++++++++++++
3 files changed, 912 insertions(+), 372 deletions(-)
---
diff --git a/ui_rogue.c b/ui_rogue.c
@@ -1,3 +1,5 @@
+#include <errno.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -6,6 +8,7 @@
#include <term.h>
#include <termios.h>
#include <unistd.h>
+#include <sys/select.h>
#include <sys/types.h>
#include "common.h"
@@ -22,6 +25,47 @@
#define ERR (-1)
#endif
+#define maplines (lines - 2)
+
+enum {
+ Blocks = 1,
+ Standout = 2,
+ Important = 4
+};
+
+struct cell;
+struct tile {
+ char c;
+ char flags;
+ char *name;
+ char *description;
+ char *afterinteract;
+ Item *(*interact)(struct cell *);
+};
+
+struct cell {
+ struct tile *tile;
+ size_t nitems;
+ Item **items;
+};
+
+struct room {
+ size_t x, y;
+ size_t w, h;
+};
+
+struct rect {
+ struct rect *next, *next2;
+ struct rect *p;
+ size_t x1, y1;
+ size_t x2, y2;
+ size_t d;
+ union {
+ void *p;
+ int i;
+ } data;
+};
+
static struct termios tsave;
static struct termios tsacc;
static Item *curentry;
@@ -29,8 +73,88 @@ static int termset = ERR;
static char bufout[256];
static char bufout2[256];
+size_t ox, oy;
+size_t px, py;
+
+#define MAPHEIGHT (50)
+#define MAPWIDTH (160)
+struct cell map[MAPHEIGHT][MAPWIDTH];
+
+enum {
+ DungeonScreen,
+ MenuScreen
+} screen;
+
+Item *interactitem(struct cell *);
+Item *interactmenu(struct cell *);
+
+struct tile tile_void = { ' ', Blocks, "Void", "The void. The thing which is e…
+struct tile tile_floor = { '.', 0, "Floor", "An ordinary stone floor.", NULL, …
+struct tile tile_corridor = { '#', 0, "Different Floor", "This floor looks dif…
+struct tile tile_verticalwall = { '|', Blocks, "Wall", "Wall.", NULL, NULL };
+struct tile tile_horizontalwall = { '-', Blocks, "Wall", "Wall.", NULL, NULL };
+struct tile tile_door = { '/', 0, "Door", "A door.", NULL, NULL };
+struct tile tile_bookshelf = { 'E', Important, "Bookshelf", "A bookshelf.", "A…
+struct tile tile_book = { '?', Important, "%s", "A book: '%s'.", "A loading ba…
+struct tile tile_portal = { '0', Important, "%s", "A portal: '%s'.", "You are …
+struct tile tile_portalmachine = { 'O', Important, "Portal Machine", "A portal…
+struct tile tile_heapofstuff = { '%', Important, "Heap", "A heap of stuff.", "…
+struct tile tile_elevator = { 'L', Important, "Elevator", "An elevator.", "You…
+struct tile tile_stairsdown = { '>', Important, "'%s'", "A staircase leading d…
+
+struct tile tile_stairsup = { '<', Standout | Important, "'%s'", "A staircase …
+struct tile tile_backportal = { '0', Standout | Important, "'%s'", "A portal l…
+
void drawscreen(void);
+int
+mygetchar_(void)
+{
+ int r;
+ fd_set fdset;
+
+ FD_ZERO(&fdset);
+ FD_SET(0, &fdset);
+
+ if ((r = select(1, &fdset, NULL, NULL, NULL)) == -1) {
+ if (errno == EINTR)
+ return -1;
+ return -2;
+ }
+
+ return getchar();
+}
+
+volatile sig_atomic_t sigwinch;
+
+int
+mygetchar(void)
+{
+ int r;
+
+ while ((r = mygetchar_()) == -1) {
+ if (sigwinch) {
+ sigwinch = 0;
+
+ if (termset == OK)
+ del_curterm(cur_term);
+ termset = setupterm(NULL, 1, NULL);
+
+ drawscreen();
+ }
+ }
+
+ if (r == -2)
+ die("mygetchar: %s", strerror(errno));
+
+ return r;
+}
+
+/*
+ FNV-1a ( http://www.isthe.com/chongo/tech/comp/fnv/ )
+ FNV was published into the public domain ( https://creativecommons.org…
+ by Landon Curt Noll: http://www.isthe.com/chongo/tech/comp/fnv/#public…
+*/
uint32_t
fnv1a(int n,...)
{
@@ -41,7 +165,7 @@ fnv1a(int n,...)
h = 0x811c9dc5;
- va_start(l, n);
+ va_start(l, n);
for (i = 0; i < n; i++) {
for (s = va_arg(l, char*); *s; s++) {
h ^= *s;
@@ -53,42 +177,17 @@ fnv1a(int n,...)
return h;
}
-uint32_t
-xorshift(uint32_t *s)
+/*
+ An LCG using the constants from "Numerical Recipes".
+*/
+uint16_t
+ranqd1(uint32_t *s)
{
- *s ^= *s << 13;
- *s ^= *s >> 17;
- *s ^= *s << 5;
- return *s;
+ return (*s = 1664525 * (*s) + 1013904223) >> 16;
}
-struct cell {
- char c;
- size_t nitems;
- Item **items;
-};
-
-#define MAPHEIGHT (25)
-#define MAPWIDTH (80)
-struct cell map[MAPHEIGHT][MAPWIDTH];
-
-struct room {
- struct room *p;
- void *d;
- size_t x, y;
- size_t w, h;
-};
-
-struct rect {
- struct rect *next, *next2;
- struct room *room;
- size_t x1, y1;
- size_t x2, y2;
- size_t d;
-};
-
struct rect *
-randomneighbor(struct rect *x, struct rect *rs, uint32_t *prng)
+randomneighbor(struct rect *x, struct rect *rs, uint32_t *prng, int (*filter)(…
{
struct rect *r, *result;
size_t n;
@@ -96,35 +195,54 @@ randomneighbor(struct rect *x, struct rect *rs, uint32_t *…
n = 0;
result = NULL;
for (r = rs; r; r = r->next) {
+ if (r == x)
+ continue;
if (r->y2 < x->y1 || r->y1 > x->y2 || r->x2 < x->x1 || r->x1 >…
continue;
if ((r->y2 == x->y1 || r->y1 == x->y2) && (r->x2 == x->x1 || r…
continue;
+ if (!filter(x, r))
+ continue;
n++;
- if (xorshift(prng) / (1. + UINT32_MAX) < 1. / n)
+ if (ranqd1(prng) / (1. + UINT16_MAX) < 1. / n)
result = r;
}
return result;
}
-#define ROOM_HEIGHT_MIN 3
-#define ROOM_WIDTH_MIN 5
-#define ROOM_MARGIN_MIN 1
-#define CELL_HEIGHT_MIN (ROOM_HEIGHT_MIN + ROOM_MARGIN_MIN + 3)
-#define CELL_WIDTH_MIN (ROOM_WIDTH_MIN + ROOM_MARGIN_MIN + 3)
size_t
-generaterooms_gnarf(uint32_t prng, struct room *rs, size_t l)
+min(size_t a, size_t b)
+{
+ if (a < b)
+ return a;
+ return b;
+}
+
+size_t
+max(size_t a, size_t b)
+{
+ if (a > b)
+ return a;
+ return b;
+}
+
+/*
+ Creates an uneven grid by splitting the map recursively.
+ Returns an array containing the cells (rects) of the grid.
+*/
+struct rect *
+generaterects(size_t heightmin, size_t widthmin, uint32_t prng)
{
struct rect *queuehead, *queuetail;
struct rect *r, *t;
- struct rect *rects, *walk;
- size_t w, h, i, j, rl, n;
- int vertical;
- struct room *room;
+ struct rect *rects;
+ size_t w, h;
+ int vertical, spaceforvertical, spaceforhorizontal;
r = malloc(sizeof(*r));
- r->x1 = r->y1 = ROOM_MARGIN_MIN;
+ memset(r, 0, sizeof(*r));
+ r->x1 = r->y1 = 0;
r->x2 = MAPWIDTH;
r->y2 = MAPHEIGHT;
r->d = 0;
@@ -134,7 +252,6 @@ generaterooms_gnarf(uint32_t prng, struct room *rs, size_t …
queuehead = r;
rects = NULL;
- rl = 0;
while (queuehead) {
r = queuehead;
@@ -142,35 +259,36 @@ generaterooms_gnarf(uint32_t prng, struct room *rs, size_…
queuetail = NULL;
queuehead = queuehead->next;
- if (r->x2 - r->x1 >= CELL_WIDTH_MIN * 2 && r->y2 - r->y1 >= CE…
- vertical = xorshift(&prng) & 1;
- } else if (r->x2 - r->x1 >= CELL_WIDTH_MIN * 2) {
+ spaceforvertical = r->y2 - r->y1 >= heightmin * 2;
+ spaceforhorizontal = r->x2 - r->x1 >= widthmin * 2;
+
+ if (spaceforhorizontal && spaceforvertical) {
+ vertical = ranqd1(&prng) & 1;
+ } else if (spaceforhorizontal) {
vertical = 0;
- } else if (r->y2 - r->y1 >= CELL_HEIGHT_MIN * 2) {
+ } else if (spaceforvertical) {
vertical = 1;
} else {
r->next = rects;
rects = r;
- rl++;
continue;
}
if (vertical) {
w = r->x2 - r->x1;
- h = CELL_HEIGHT_MIN + xorshift(&prng) % (1 + r->y2 - r…
+ h = heightmin + ranqd1(&prng) % (1 + r->y2 - r->y1 - h…
} else {
- w = CELL_WIDTH_MIN + xorshift(&prng) % (1 + r->x2 - r-…
+ w = widthmin + ranqd1(&prng) % (1 + r->x2 - r->x1 - wi…
h = r->y2 - r->y1;
}
t = malloc(sizeof(*t));
+ memset(t, 0, sizeof(*t));
t->x1 = r->x1;
t->y1 = r->y1;
t->x2 = r->x1 + w;
t->y2 = r->y1 + h;
t->d = r->d + 1;
- t->next = NULL;
- t->room = NULL;
if (!queuetail) {
queuehead = t;
@@ -181,6 +299,7 @@ generaterooms_gnarf(uint32_t prng, struct room *rs, size_t …
}
t = malloc(sizeof(*t));
+ memset(t, 0, sizeof(*t));
if (vertical) {
t->x1 = r->x1;
t->y1 = r->y1 + h;
@@ -191,8 +310,6 @@ generaterooms_gnarf(uint32_t prng, struct room *rs, size_t …
t->x2 = r->x2;
t->y2 = r->y2;
t->d = r->d + 1;
- t->next = NULL;
- t->room = NULL;
queuetail->next = t;
queuetail = t;
@@ -200,75 +317,107 @@ generaterooms_gnarf(uint32_t prng, struct room *rs, size…
free(r);
}
- if (l > rl)
- l = rl;
+ return rects;
+}
- for (r = rects; r; r = r->next) {
- if (MAPHEIGHT / 2 >= r->y1 && MAPHEIGHT / 2 < r->y2 &&
- MAPWIDTH / 2 >= r->x1 && MAPWIDTH / 2 < r->x2)
- break;
- }
-
- i = 0;
- rs[i].w = ROOM_WIDTH_MIN + xorshift(&prng) % (1 + r->x2 - r->x1 - ROOM…
- rs[i].h = ROOM_HEIGHT_MIN + xorshift(&prng) % (1 + r->y2 - r->y1 - ROO…
- rs[i].x = r->x1 + xorshift(&prng) % (1 + r->x2 - r->x1 - ROOM_MARGIN_M…
- rs[i].y = r->y1 + xorshift(&prng) % (1 + r->y2 - r->y1 - ROOM_MARGIN_M…
- rs[i].p = NULL;
- r->room = &rs[i];
-
- walk = r;
- walk->next2 = NULL;
-
- i++;
- for (; i < l;) {
- t = randomneighbor(r, rects, &prng);
- if (!t || t->room) {
- n = 0;
- for (t = walk; t; t = t->next2) {
- n++;
- if (xorshift(&prng) / (1. + UINT32_MAX) < 1. /…
- r = t;
-
- }
- continue;
- }
- rs[i].w = ROOM_WIDTH_MIN + xorshift(&prng) % (1 + t->x2 - t->x…
- rs[i].h = ROOM_HEIGHT_MIN + xorshift(&prng) % (1 + t->y2 - t->…
- rs[i].x = t->x1 + xorshift(&prng) % (1 + t->x2 - t->x1 - ROOM_…
- rs[i].y = t->y1 + xorshift(&prng) % (1 + t->y2 - t->y1 - ROOM_…
- rs[i].p = r->room;
- t->room = &rs[i];
- i++;
- r = t;
- r->next2 = walk;
- walk = r;
- }
+void
+connectpoints_horizontal(size_t y,
+ size_t ax, int ea, struct tile *at,
+ size_t bx, int eb, struct tile *bt,
+ struct tile *t)
+{
+ size_t i, s, e;
+ ssize_t ii;
- for (r = rects; r;) {
- t = r->next;
- free(r);
- r = t;
- }
+ if (ax < bx)
+ ii = 1;
+ else if (ax > bx)
+ ii = -1;
+ else
+ ii = 0;
- return l;
+ s = ax;
+ if (ea)
+ s += ii;
+ e = bx + ii;
+ if (eb)
+ e -= ii;
+
+ for (i = s; i != e; i += ii)
+ map[y][i].tile = t;
+
+ if (e - ii == s) {
+ if (at != t)
+ map[y][s].tile = at;
+ if (bt != t)
+ map[y][s].tile = bt;
+ } else {
+ map[y][s].tile = at;
+ map[y][e - ii].tile = bt;
+ }
}
-size_t
-distance(size_t x1, size_t y1, size_t x2, size_t y2)
+void
+connectpoints_vertical(size_t x,
+ size_t ay, int ea, struct tile *at,
+ size_t by, int eb, struct tile *bt,
+ struct tile *t)
{
- size_t d;
+ size_t i, s, e;
+ ssize_t ii;
- if (y1 < y2)
- d = y2 - y1;
- else
- d = y1 - y2;
- if (x1 < x2)
- d += x2 - x1;
+ if (ay < by)
+ ii = 1;
+ else if (ay > by)
+ ii = -1;
else
- d += x1 - x2;
+ ii = 0;
- return d;
+ s = ay;
+ if (ea)
+ s += ii;
+ e = by + ii;
+ if (eb)
+ e -= ii;
+
+ for (i = s; i != e; i += ii)
+ map[i][x].tile = t;
+
+ if (e - ii == s) {
+ if (at != t)
+ map[s][x].tile = at;
+ if (bt != t)
+ map[s][x].tile = bt;
+ } else {
+ map[s][x].tile = at;
+ map[e - ii][x].tile = bt;
+ }
+}
+
+void
+connectpoints(size_t ax, size_t ay, int ea, struct tile *at,
+ size_t bx, size_t by, int eb, struct tile *bt,
+ int vertical, struct tile *ct)
+{
+ if (!vertical) {
+ connectpoints_horizontal(ay,
+ ax, ea, at,
+ bx, 0, ct,
+ ct);
+ connectpoints_vertical(bx,
+ ay, 0, ct,
+ by, eb, bt,
+ ct);
+ } else {
+ connectpoints_vertical(ax,
+ ay, ea, at,
+ by, 0, ct,
+ ct);
+ connectpoints_horizontal(by,
+ ax, 0, ct,
+ bx, eb, bt,
+ ct);
+ }
}
void
@@ -300,50 +449,246 @@ nearestpoints(struct room *a, struct room *b, size_t *ax…
}
void
-connectrooms(struct room *a, struct room *b)
+connectadjacentrooms(struct rect *a, struct room *ar, struct rect *b, struct r…
{
- size_t i, j;
- ssize_t ii;
- size_t x1, y1;
- size_t x2, y2;
+ size_t irx1, iry1, irx2, iry2;
+ size_t rx1, ry1, rx2, ry2;
+ size_t cx, cy;
+ struct rect *r1, *r2;
+ struct room *room1, *room2;
+ int vertical;
- nearestpoints(a, b, &x1, &y1, &x2, &y2);
+ if (a->x2 == b->x1) {
+ r1 = a;
+ room1 = ar;
+ r2 = b;
+ room2 = br;
+ } else if (b->x2 == a->x1) {
+ r1 = b;
+ room1 = br;
+ r2 = a;
+ room2 = ar;
+ } else if (a->y2 == b->y1) {
+ r1 = a;
+ room1 = ar;
+ r2 = b;
+ room2 = br;
+ } else if (b->y2 == a->y1) {
+ r1 = b;
+ room1 = br;
+ room2 = ar;
+ r2 = a;
+ } else {
+ return;
+ }
- if (y1 > y2) {
- ii = -1;
- } else if (y2 > y1) {
- ii = 1;
+ if (r1->y2 == r2->y1) {
+ irx1 = max(r1->x1, r2->x1);
+ irx2 = min(r1->x2, r2->x2);
+ iry1 = r1->y2;
+ iry2 = r1->y2 + 1;
} else {
- ii = 0;
+ iry1 = max(r1->y1, r2->y1);
+ iry2 = min(r1->y2, r2->y2);
+ irx1 = r1->x2;
+ irx2 = r1->x2 + 1;
+ }
+
+ nearestpoints(room1, room2, &rx1, &ry1, &rx2, &ry2);
+
+ if (r1->y2 == r2->y1) {
+ /* both points are in the intersection */
+ if (rx1 >= irx1 && rx1 < irx2 &&
+ rx2 >= irx1 && rx2 < irx2) {
+ vertical = 1;
+ cx = (rx2 + rx1) / 2;
+ cy = (ry2 + ry1) / 2;
+ } else
+ /* none is in the intersection */
+ if (!(rx1 >= irx1 && rx1 < irx2) &&
+ !(rx2 >= irx1 && rx2 < irx2)) {
+ vertical = 0;
+ cx = irx1;
+ cy = r1->y2;
+ } else if (rx1 >= irx1 && rx1 < irx2) {
+ vertical = 1;
+ cx = (rx2 + rx1) / 2;
+ cy = r1->y2;
+ } else if (rx2 >= irx1 && rx2 < irx2) {
+ vertical = 1;
+ cx = rx2;
+ cy = r1->y2 - 1;
+ }
+ } else {
+ /* both points are in the intersection */
+ if (ry1 >= iry1 && ry1 < iry2 &&
+ ry2 >= iry1 && ry2 < iry2) {
+ vertical = 0;
+ cx = (rx2 + rx1) / 2;
+ cy = (ry2 + ry1) / 2;
+ } else
+ /* none is in the intersection */
+ if (!(ry1 >= iry1 && ry1 < iry2) &&
+ !(ry2 >= iry1 && ry2 < iry2)) {
+ vertical = 1;
+ cx = r1->x2;
+ cy = iry1;
+ } else if (ry1 >= iry1 && ry1 < iry2) {
+ vertical = 0;
+ cx = r1->x2;
+ cy = (ry2 + ry1) / 2;
+ } else if (ry2 >= iry1 && ry2 < iry2) {
+ vertical = 0;
+ cx = r1->x2 - 1;
+ cy = ry2;
+ }
}
+ if (rx1 == rx2) {
+ connectpoints_vertical(rx1,
+ ry1, 1, &tile_door,
+ ry2, 1, &tile_door,
+ &tile_corridor);
+ } else if (ry1 == ry2) {
+ connectpoints_horizontal(ry1,
+ rx1, 1, &tile_door,
+ rx2, 1, &tile_door,
+ &tile_corridor);
+ } else {
+ connectpoints(rx1, ry1, 1, &tile_door,
+ cx, cy, 0, &tile_corridor,
+ vertical, &tile_corridor);
+ connectpoints(cx, cy, 1, &tile_corridor,
+ rx2, ry2, 1, &tile_door,
+ !vertical, &tile_corridor);
+ }
+}
+
+int
+rectisfull(struct rect *x, struct rect *r)
+{
+ return !!r->data.i;
+}
+
+int
+rectisempty(struct rect *x, struct rect *r)
+{
+ return !r->data.i;
+}
+
+int
+rectisnotp(struct rect *x, struct rect *r)
+{
+ return r->data.p && x->p != r && r->p != x;
+}
+
+int
+rectisrandom(struct rect *x, struct rect *r)
+{
+ return 1;
+}
+
/*
-printf("%lu\t%lu\t%d\n", y1, y2, ii);
+ Basically https://www.roguebasin.com/index.php/Diffusion-limited_aggre…
+ Returns the list of carved rooms.
*/
- for (i = y1; i != y2; i += ii)
- map[i][x1].c = '.';
+struct rect *
+dla(struct rect *rects, size_t l, uint32_t prng) {
+ size_t rl, i, n;
+ struct rect *r, *t, *walk, *p;
- if (x1 > x2) {
- ii = -1;
- } else if (x2 > x1) {
- ii = 1;
- } else {
- ii = 0;
+ for (r = rects, rl = 0; r; r = r->next)
+ rl++;
+
+ if (l > rl)
+ l = rl;
+
+ /* get the rect which contains the map center */
+ for (r = rects; r; r = r->next) {
+ if (MAPHEIGHT / 2 >= r->y1 && MAPHEIGHT / 2 < r->y2 &&
+ MAPWIDTH / 2 >= r->x1 && MAPWIDTH / 2 < r->x2)
+ break;
}
- for (i = x1; i != x2; i += ii)
- map[y2][i].c = '.';
+ p = NULL;
+ walk = NULL;
+ i = 0;
+ for (;;) {
+ r->p = p;
+ r->data.i = 1;
+ r->next2 = walk;
+ walk = r;
+
+ if (i >= l - 1)
+ break;
+
+ t = NULL;
+ for (r = rects, n = 0; r; r = r->next) {
+ if (r->data.i)
+ continue;
+ n++;
+ if (ranqd1(&prng) / (1. + UINT16_MAX) < 1. / n)
+ t = r;
+ }
+
+ /* there is no free rect left */
+ if (!t)
+ break;
+
+ /* do a random walk starting from t until the walk collides wi…
+ while ((r = randomneighbor(t, rects, &prng, rectisrandom)) && …
+ t = r;
+
+ p = r;
+ r = t;
+
+ i++;
+ }
+
+ return walk;
+}
+
+void
+rendermapchar(size_t i, size_t j) {
+ if (map[i][j].tile->flags & Standout)
+ putp(tparm(enter_standout_mode, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+ putchar(map[i][j].tile->c);
+ if (map[i][j].tile->flags & Standout)
+ putp(tparm(exit_standout_mode, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+}
+
+void
+rendermapline(size_t i)
+{
+ size_t j;
+
+ for (j = ox; j < min(MAPWIDTH, ox + columns); j++)
+ rendermapchar(i, j);
}
void
rendermap(void)
{
- size_t i, j;
+ size_t i;
- for (i = 0; i < MAPHEIGHT; i++) {
- for (j = 0; j < MAPWIDTH; j++)
- putchar(map[i][j].c);
- putchar('\n');
+ if (px < columns / 2 || MAPWIDTH <= columns)
+ ox = 0;
+ else if (px >= MAPWIDTH - columns / 2 - 1)
+ ox = MAPWIDTH - columns;
+ else
+ ox = px - columns / 2;
+
+ if (py < maplines / 2 || MAPHEIGHT <= maplines)
+ oy = 0;
+ else if (py >= MAPHEIGHT - maplines / 2 - 1)
+ oy = MAPHEIGHT - maplines;
+ else
+ oy = py - maplines / 2;
+
+ for (i = oy; i < min(MAPHEIGHT, oy + (lines - 2)); i++) {
+ if (i != oy)
+ putp(tparm(cursor_down, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+ rendermapline(i);
}
}
@@ -366,92 +711,171 @@ placeitems_hash(Item *item, size_t *assocs, size_t k)
return k;
}
-#define POSITIONS_LENGTH 4
+#define POSITIONS_LENGTH 5
enum {
Portal,
StaircaseDown,
Bookshelf,
+ OtherStuff,
Back
};
-size_t px, py;
+enum {
+ FillEntireCell = 1
+};
+
+#define length(a) (sizeof(a) / sizeof(a[0]))
+static struct dungeontype {
+ char *name;
+ char flags;
+ size_t heightmin;
+ size_t heightmax;
+ size_t widthmin;
+ size_t widthmax;
+ size_t margin;
+ size_t wiggle;
+} dungeontypes[] = {
+ { "rogueish", 0, 2, 5, 3, 7, 2, 0 },
+ { "rogueish-wide", 0, 2, 5, 3, 7, 3, 1 },
+ { "compact", FillEntireCell, 2, 2, 3, 3, 1, 0 },
+};
void
-generatemap(Item *item, int new)
+generatemap(Item *item, Item *pitem)
{
Dir *dir;
Item *citem;
- size_t i, j, k, l, ir;
- size_t x, y;
- ssize_t n, m;
+ size_t l, i, j, k, ir, n, m, x, y;
+ struct rect *rects, *walk, *tr, *cr;
+ struct room *rooms, *room;
size_t *cassocs;
- struct room *rooms, *r;
+ int changedlevel, gonedown;
+ char buffer[10];
+ uint32_t prng;
struct {
- unsigned char x, y;
+ size_t x, y;
} positions[POSITIONS_LENGTH];
- uint32_t prng;
- char buffer[3];
+ size_t cellwidth, cellheight;
+ struct dungeontype *type;
+
+ type = &dungeontypes[fnv1a(3, item->host, item->port, "dungeontype") %…
+
+ cellheight = type->heightmin + 2 * type->margin + type->wiggle;
+ cellwidth = type->widthmin + 2 * type->margin + type->wiggle;
+
+ rects = generaterects(cellheight, cellwidth, fnv1a(4, item->host, item…
+
+ dir = item->dat;
+ for (j = l = 0; j < dir->nitems; j++) {
+ if (dir->items[j].type != 0 &&
+ dir->items[j].type != 'i' &&
+ dir->items[j].type != '3')
+ l++;
+ }
+
+ k = 1 + l / 10;
+ walk = dla(rects, k, fnv1a(4, item->host, item->port, item->selector, …
+ for (cr = walk, k = 0; cr; cr = cr->next2, k++);
+
+ for (cr = rects; cr; cr = cr->next)
+ cr->data.p = NULL;
+
+ rooms = calloc(k, sizeof(*rooms));
+ for (cr = walk, i = 0; cr; cr = cr->next2, i++)
+ cr->data.p = &rooms[i];
+
+ prng = fnv1a(4, item->host, item->port, item->selector, "roomsseed");
+ for (cr = walk; cr; cr = cr->next2) {
+ room = cr->data.p;
+
+ if (type->flags & FillEntireCell) {
+ room->w = cr->x2 - cr->x1 - 2 * type->margin;
+ room->x = cr->x1 + type->margin;
+ room->h = cr->y2 - cr->y1 - 2 * type->margin;
+ room->y = cr->y1 + type->margin;
+ } else {
+ room->w = type->widthmin + ranqd1(&prng) % (1 + min(cr…
+ room->x = cr->x1 + type->margin + ranqd1(&prng) % (1 +…
+ room->h = type->heightmin + ranqd1(&prng) % (1 + min(c…
+ room->y = cr->y1 + type->margin + ranqd1(&prng) % (1 +…
+ }
+ }
for (i = 0; i < MAPHEIGHT; i++) {
for (j = 0; j < MAPWIDTH; j++) {
- map[i][j].c = '#';
+ map[i][j].tile = &tile_void;
free(map[i][j].items);
map[i][j].items = NULL;
map[i][j].nitems = 0;
}
}
- dir = item->dat;
- for (j = l = 0; j < dir->nitems; j++) {
- if (dir->items[j].type == '0' ||
- dir->items[j].type == '1')
- l++;
+ for (cr = walk; cr; cr = cr->next2) {
+ room = cr->data.p;
+
+ for (x = room->x - 1; x < room->x + room->w + 1; x++)
+ map[room->y-1][x].tile = &tile_horizontalwall;
+ for (y = room->y; y < room->y + room->h; y++) {
+ map[y][room->x - 1].tile = &tile_verticalwall;
+ for (x = room->x; x < room->x + room->w; x++)
+ map[y][x].tile = &tile_floor;
+ map[y][room->x + room->w].tile = &tile_verticalwall;
+ }
+ for (x = room->x - 1; x < room->x + room->w + 1; x++)
+ map[room->y + room->h][x].tile = &tile_horizontalwall;
}
- k = 1 + l / 10;
- rooms = calloc(k, sizeof(*rooms));
- if (!rooms)
- return;
- k = generaterooms_gnarf(fnv1a(3, item->host, item->port, item->selecto…
+ for (cr = walk; cr; cr = cr->next2) {
+ if (cr->p)
+ connectadjacentrooms(cr, cr->data.p,
+ cr->p, cr->p->data.p);
+
+ /* Add some loop possibility */
+ if (tr = randomneighbor(cr, rects, &prng, rectisnotp))
+ connectadjacentrooms(cr, cr->data.p,
+ tr, tr->data.p);
+ }
cassocs = calloc(dir->nitems, sizeof(*cassocs));
- if (!cassocs)
- goto cleanup;
k = placeitems_hash(item, cassocs, k);
- /* Insert rooms */
- for (i = 0; i < k; i++) {
- for (y = rooms[i].y; y < rooms[i].y + rooms[i].h; y++) {
- for (x = rooms[i].x; x < rooms[i].x + rooms[i].w; x++)
- map[y][x].c = '.';
- }
- }
-
- /* Insert connections */
- for (i = 0; i < k; i++) {
- if (rooms[i].p)
- connectrooms(&rooms[i], rooms[i].p);
- }
+ changedlevel = item != pitem;
+ gonedown = pitem == item->entry;
/*
Insert items
- The placement of items affects the initial placement of the pl…
+ The placement of items affects the initial placement of the
+ player, because they could have gone back to this map, so they
+ should appear at the elevator/portal/stair they used.
*/
- ir = fnv1a(4, item->host, item->port, item->selector, "initial_room") …
+
+ /*
+ The initial room is everytime the first one. Reason: The count
+ of rooms is based on how many entries are in the gophermap and
+ how many rooms can fit on the map. There will be at minimum 1.
+ So when more entries get added there will be more rooms but the
+ first one stays at the same position. I think about the
+ retrying and clownflare things on bitreich.org, the selector
+ doesn't change...
+ */
+ ir = 0;
for (i = 0; i < k; i++) {
- snprintf(buffer, sizeof(buffer), "%d", i);
+ /* select random positions for different item types inside the…
+ snprintf(buffer, sizeof(buffer), "%lu", i);
prng = fnv1a(4, item->host, item->port, item->selector, buffer…
- for (j = 0, n = 0, m = rooms[i].h * rooms[i].w; j < m; j++) {
- if ((m - j) * (xorshift(&prng) / (double)UINT32_MAX) <…
+ for (j = 0, m = rooms[i].h * rooms[i].w; j < m; j++) {
+ n = j;
+ if (j >= POSITIONS_LENGTH)
+ n *= ranqd1(&prng) / (double)UINT16_MAX;
+
+ if (n < POSITIONS_LENGTH) {
positions[n].x = rooms[i].x + j % rooms[i].w;
positions[n].y = rooms[i].y + j / rooms[i].w;
- n++;
}
- if (n == POSITIONS_LENGTH)
- break;
}
+
for (j = 0; j < dir->nitems; j++) {
if (cassocs[j] != i)
continue;
@@ -462,35 +886,44 @@ generatemap(Item *item, int new)
x = positions[Bookshelf].x;
y = positions[Bookshelf].y;
if (map[y][x].nitems)
- map[y][x].c = 'E';
+ map[y][x].tile = &tile_bookshelf;
else
- map[y][x].c = '?';
+ map[y][x].tile = &tile_book;
break;
case '1':
if (strcmp(citem->host, item->host) || strcmp(…
x = positions[Portal].x;
y = positions[Portal].y;
if (map[y][x].nitems)
- map[y][x].c = 'O';
+ map[y][x].tile = &tile_portalm…
else
- map[y][x].c = '0';
+ map[y][x].tile = &tile_portal;
} else {
x = positions[StaircaseDown].x;
y = positions[StaircaseDown].y;
if (map[y][x].nitems)
- map[y][x].c = 'L';
+ map[y][x].tile = &tile_elevato…
else
- map[y][x].c = '>';
+ map[y][x].tile = &tile_stairsd…
}
break;
- default:
+ case 0:
+ case 'i':
+ case '3':
continue;
+ break;
+ default:
+ x = positions[OtherStuff].x;
+ y = positions[OtherStuff].y;
+ map[y][x].tile = &tile_heapofstuff;
+ break;
}
+
map[y][x].nitems++;
map[y][x].items = realloc(map[y][x].items, map[y][x].n…
map[y][x].items[map[y][x].nitems-1] = citem;
- if (new && j == dir->curline && citem->raw) {
+ if (changedlevel && citem == pitem) {
px = x;
py = y;
}
@@ -500,23 +933,28 @@ generatemap(Item *item, int new)
y = positions[Back].y;
x = positions[Back].x;
if (strcmp(item->entry->host, item->host) || strcmp(it…
- map[y][x].c = '0';
+ map[y][x].tile = &tile_backportal;
else
- map[y][x].c = '<';
+ map[y][x].tile = &tile_stairsup;
map[y][x].nitems++;
map[y][x].items = realloc(map[y][x].items, map[y][x].n…
map[y][x].items[map[y][x].nitems-1] = item->entry;
}
- if (i == ir && new && !dir->items[dir->curline].raw) {
+ if (changedlevel && i == ir && (gonedown || !pitem)) {
px = positions[Back].x;
py = positions[Back].y;
}
}
- free(cassocs);
-cleanup:
+ free(cassocs);
free(rooms);
+
+ for (cr = rects; cr;) {
+ tr = cr;
+ cr = cr->next;
+ free(tr);
+ }
}
void
@@ -544,6 +982,7 @@ uicleanup(void)
if (termset != OK)
return;
+ putp(tparm(change_scroll_region, 0, lines-1, 0, 0, 0, 0, 0, 0, 0));
putp(tparm(clear_screen, 0, 0, 0, 0, 0, 0, 0, 0, 0));
fflush(stdout);
}
@@ -655,7 +1094,7 @@ uistatus(char *fmt, ...)
putp(tparm(restore_cursor, 0, 0, 0, 0, 0, 0, 0, 0, 0));
fflush(stdout);
- getchar();
+ mygetchar();
}
void
@@ -668,225 +1107,287 @@ displayinfoline(char *fmt, ...)
va_end(ap);
}
-Item *
-showmenu(char *title, Item **item, size_t l)
+char *menutitle;
+Item **menuitems;
+size_t menunitems;
+volatile size_t menuoffset;
+size_t menuselected;
+
+void
+menudraw(void)
{
- size_t i;
+ size_t i, n;
+ putp(tparm(change_scroll_region, 1, lines-1, 0, 0, 0, 0, 0, 0, 0));
putp(tparm(clear_screen, 0, 0, 0, 0, 0, 0, 0, 0, 0));
putp(tparm(enter_standout_mode, 0, 0, 0, 0, 0, 0, 0, 0, 0));
- printf("%s\n", title);
+ puts(menutitle);
putp(tparm(exit_standout_mode, 0, 0, 0, 0, 0, 0, 0, 0, 0));
- for (i = 0; i < l; i++)
- printf("%lu\t%s\n", i, item[i]->username);
- if (!scanf("%lu", &i) || i >= l)
- return NULL;
+ if (menuselected - menuoffset >= lines - 1)
+ menuoffset = menuselected - (lines - 1) + 1;
+
+ for (i = menuoffset, n = 0; i < menunitems && n < lines - 1; i++, n++)…
+ if (i != menuoffset)
+ putp(tparm(cursor_down, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+ if (i == menuselected)
+ putp(tparm(enter_standout_mode, 0, 0, 0, 0, 0, 0, 0, 0…
+ mbsprint(menuitems[i]->username, columns);
+ if (i == menuselected)
+ putp(tparm(exit_standout_mode, 0, 0, 0, 0, 0, 0, 0, 0,…
+ putp(tparm(column_address, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+ }
fflush(stdout);
-
- return item[i];
}
Item *
-prompt(char *text, Item *item)
-{
- displayinfoline(text, item->username);
- getchar();
- return item;
-}
-
-Item *
-interact(Item *item)
+showmenu(char *title, Item **item, size_t l)
{
Item *selection;
- selection = NULL;
-
- switch (map[py][px].c) {
- case '?':
- case '0':
- case '>':
- case '<':
- selection = map[py][px].items[0];
- break;
- case 'E':
- selection = showmenu("Bookshelf", map[py][px].items, map[py][p…
- break;
- case 'O':
- selection = showmenu("Portal machine", map[py][px].items, map[…
- break;
- case 'L':
- selection = showmenu("Elevator", map[py][px].items, map[py][px…
- break;
- }
-
+ menutitle = title;
+ menuitems = item;
+ menunitems = l;
+ menuselected = 0;
+ menuoffset = 0;
+ screen = MenuScreen;
drawscreen();
- if (selection) {
- switch (map[py][px].c) {
- case '?':
- case 'E':
- displayinfoline("A loading bar?! In a book?!");
- break;
- case 'O':
- case '0':
- displayinfoline("You are getting transported through t…
+ selection = NULL;
+ for (;;) {
+ switch (mygetchar()) {
+ case 'j':
+ if (menuselected + 1 < menunitems) {
+ putp(tparm(cursor_address, 1 + menuselected - …
+ mbsprint(menuitems[menuselected]->username, co…
+ menuselected++;
+ putp(tparm(column_address, 0, 0, 0, 0, 0, 0, 0…
+ if (menuselected - menuoffset >= lines - 1) {
+ menuoffset++;
+ putp(tparm(scroll_forward, 0, 0, 0, 0,…
+ } else {
+ putp(tparm(cursor_down, 0, 0, 0, 0, 0,…
+ }
+ putp(tparm(enter_standout_mode, 0, 0, 0, 0, 0,…
+ mbsprint(menuitems[menuselected]->username, co…
+ putp(tparm(exit_standout_mode, 0, 0, 0, 0, 0, …
+ }
break;
- case 'L':
- displayinfoline("You hear elevator music...");
+ case 'k':
+ if (menuselected > 0) {
+ putp(tparm(cursor_address, 1 + menuselected - …
+ mbsprint(menuitems[menuselected]->username, co…
+ menuselected--;
+ putp(tparm(column_address, 0, 0, 0, 0, 0, 0, 0…
+ if (menuselected < menuoffset) {
+ menuoffset = menuselected;
+ putp(tparm(scroll_reverse, 0, 0, 0, 0,…
+ } else {
+ putp(tparm(cursor_up, 0, 0, 0, 0, 0, 0…
+ }
+ putp(tparm(enter_standout_mode, 0, 0, 0, 0, 0,…
+ mbsprint(menuitems[menuselected]->username, co…
+ putp(tparm(exit_standout_mode, 0, 0, 0, 0, 0, …
+ }
break;
- case '<':
- case '>':
- displayinfoline("Too many stairs...");
+ case ' ':
+ selection = menuitems[menuselected];
+ case 0x1b:
+ goto endloop;
break;
}
+ fflush(stdout);
}
+endloop:
+ screen = DungeonScreen;
+ drawscreen();
+
return selection;
}
+Item *
+interactitem(struct cell *c)
+{
+ displayinfoline(map[py][px].tile->afterinteract);
+
+ return map[py][px].items[0];
+}
+
+Item *
+interactmenu(struct cell *c)
+{
+ Item *selection;
+
+ if (selection = showmenu(map[py][px].tile->name, map[py][px].items, ma…
+ displayinfoline(map[py][px].tile->afterinteract);
+
+ return selection;
+}
+
+Item *
+interact(Item *item)
+{
+ if (map[py][px].tile->interact)
+ return map[py][px].tile->interact(&map[py][px]);
+
+ return NULL;
+}
+
void
describe(size_t x, size_t y, int verbose)
{
- switch (map[y][x].c) {
- case 'E':
- displayinfoline("A bookshelf.");
- break;
- case 'O':
- displayinfoline("A portal machine.");
- break;
- case 'L':
- displayinfoline("An elevator.");
- break;
- case '?':
- case '>':
- case '<':
- case '0':
+ char *name;
+
+ if (map[y][x].nitems) {
if (*map[y][x].items[0]->username) {
- displayinfoline("'%s'.", map[y][x].items[0]->username);
+ name = map[y][x].items[0]->username;
} else {
itemuri(map[y][x].items[0], bufout2, sizeof(bufout2));
- displayinfoline("'%s'.", bufout2);
+ name = bufout2;
}
- break;
- default:
- if (verbose) {
- switch (map[y][x].c) {
- case '.':
- displayinfoline("Floor.");
- break;
- case '#':
- displayinfoline("Wall.");
- break;
- }
- } else {
- displayinfoline("");
- }
- break;
+ } else {
+ name = NULL;
}
+ if (map[y][x].tile->flags & Important || verbose)
+ displayinfoline(map[y][x].tile->description, name);
+ else
+ displayinfoline("");
+}
+
+void
+dungeondraw(void)
+{
+ putp(tparm(change_scroll_region, 0, lines-3, 0, 0, 0, 0, 0, 0, 0));
+ putp(tparm(clear_screen, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+ rendermap();
+
+ putp(tparm(cursor_address, py - oy, px - ox, 0, 0, 0, 0, 0, 0, 0));
+ putchar('@');
+ putp(tparm(cursor_address, py - oy, px - ox, 0, 0, 0, 0, 0, 0, 0));
+
+ if (curentry->entry != curentry) {
+ displaybar(curentry->username);
+ } else {
+ itemuri(curentry, bufout, sizeof(bufout));
+ displaybar(bufout);
+ }
+
+ describe(px, py, 0);
}
void
move(ssize_t dx, ssize_t dy)
{
+ ssize_t i;
size_t x, y;
+ size_t noy, nox;
+
+ if ((ssize_t)py + dy >= MAPHEIGHT || (ssize_t)py + dy < 0)
+ return;
+ if ((ssize_t)px + dx >= MAPWIDTH || (ssize_t)px + dx < 0)
+ return;
- /* allow wraparound of the world for the lulz, even if it's not happen…
- y = (MAPHEIGHT + py + dy) % MAPHEIGHT;
- x = (MAPWIDTH + px + dx) % MAPWIDTH;
+ x = px + dx;
+ y = py + dy;
- if (map[y][x].c == '#')
+ if (map[y][x].tile->flags & Blocks)
return;
- putp(tparm(cursor_address, py, px, 0, 0, 0, 0, 0, 0, 0 ));
- putchar(map[py][px].c);
+ if (dx) {
+ if (x < columns / 2 || MAPWIDTH <= columns)
+ nox = 0;
+ else if (x >= MAPWIDTH - columns / 2 - 1)
+ nox = MAPWIDTH - columns;
+ else
+ nox = x - columns / 2;
+
+ if (ox != nox) {
+ putp(tparm(cursor_address, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+ rendermap();
+ } else {
+ putp(tparm(cursor_address, py - oy, px - ox, 0, 0, 0, …
+ rendermapchar(py, px);
+ }
+ } else if (dy) {
+ putp(tparm(cursor_address, py - oy, px - ox, 0, 0, 0, 0, 0, 0,…
+ rendermapchar(py, px);
+
+ if (y < maplines / 2 || MAPHEIGHT <= maplines) {
+ noy = 0;
+ } else if (y >= MAPHEIGHT - maplines / 2 - 1) {
+ noy = MAPHEIGHT - maplines;
+ } else {
+ noy = y - maplines / 2;
+ }
+
+ if (noy < oy) {
+ putp(tparm(cursor_address, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+ for (i = (ssize_t)oy - 1; i >= (ssize_t)noy; i--) {
+ putp(tparm(scroll_reverse, 0, 0, 0, 0, 0, 0, 0…
+ rendermapline(i);
+ putp(tparm(column_address, 0, 0, 0, 0, 0, 0, 0…
+ }
+ } else if (noy > oy) {
+ putp(tparm(cursor_address, lines-3, 0, 0, 0, 0, 0, 0, …
+ for (i = oy + 1; i <= noy; i++) {
+ putp(tparm(scroll_forward, 0, 0, 0, 0, 0, 0, 0…
+ rendermapline(i + maplines - 1);
+ putp(tparm(column_address, 0, 0, 0, 0, 0, 0, 0…
+ }
+ }
+ oy = noy;
+ }
py = y;
px = x;
- putp(tparm(cursor_address, py, px, 0, 0, 0, 0, 0, 0, 0 ));
+ putp(tparm(cursor_address, py - oy, px - ox, 0, 0, 0, 0, 0, 0, 0));
putchar('@');
- putp(tparm(cursor_address, py, px, 0, 0, 0, 0, 0, 0, 0 ));
+ putp(tparm(cursor_address, py - oy, px - ox, 0, 0, 0, 0, 0, 0, 0));
- describe(x, y, 0);
- putp(tparm(cursor_address, py, px, 0, 0, 0, 0, 0, 0, 0 ));
+ describe(px, py, 0);
}
void
drawscreen(void)
{
- Dir *dir;
-
- putp(tparm(clear_screen, 0, 0, 0, 0, 0, 0, 0, 0, 0));
- rendermap();
-
- if (curentry->entry != curentry && (dir = curentry->entry->dat)) {
- displaybar(dir->items[dir->curline].username);
- } else {
- itemuri(curentry, bufout, sizeof(bufout));
- displaybar(bufout);
+ switch (screen) {
+ case DungeonScreen:
+ dungeondraw();
+ break;
+ case MenuScreen:
+ menudraw();
+ break;
}
-
- move(0, 0);
-
+ fflush(stdout);
}
void
uidisplay(Item *entry)
{
- if (!entry || entry->type != '1')
+ if (!entry || !(entry->type == '1' || entry->type == '+' || entry->typ…
return;
- generatemap(entry, curentry != entry);
+ if (entry != curentry) {
+ generatemap(entry, curentry);
+ curentry = entry;
+ }
- curentry = entry;
drawscreen();
}
-void
-lookmode(void)
-{
- size_t x, y;
-
- x = px;
- y = py;
-
- for (;;) {
- switch (getchar()) {
- case 0x1B:
- case 'q':
- putp(tparm(cursor_address, py, px, 0, 0, 0, 0, 0, 0, 0…
- return;
- case 'h':
- x = (MAPWIDTH + x - 1) % MAPWIDTH;
- break;
- case 'j':
- y = (y + 1) % MAPHEIGHT;
- break;
- case 'k':
- y = (MAPHEIGHT + y - 1) % MAPHEIGHT;
- break;
- case 'l':
- x = (x + 1) % MAPWIDTH;
- break;
- }
- putp(tparm(cursor_address, y, x, 0, 0, 0, 0, 0, 0, 0));
- describe(x, y, 1);
- }
-}
-
Item *
uiselectitem(Item *entry)
{
- Dir *dir;
Item *e;
- size_t i;
- if (!entry || !(dir = entry->dat))
+ if (!entry || !entry->dat)
return NULL;
for (;;) {
- switch (getchar()) {
+ switch (mygetchar()) {
case 'h':
move(-1, 0);
break;
@@ -899,40 +1400,20 @@ uiselectitem(Item *entry)
case 'l':
move(1, 0);
break;
- case 'L':
- lookmode();
- break;
case ' ':
- /* Portals, stairs, bookshelfs */
- if (e = interact(entry)) {
- if (e->type == '1') {
- for (i = 0; i < dir->nitems; i++) {
- if (e == &dir->items[i]) {
- dir->curline = i;
- break;
- }
- }
- }
+ if (e = interact(entry))
return e;
- }
break;
case 'q':
+ case 0x1b:
return NULL;
}
+ fflush(stdout);
}
}
void
uisigwinch(int signal)
{
- Dir *dir;
-
- if (termset == OK)
- del_curterm(cur_term);
- termset = setupterm(NULL, 1, NULL);
-
- if (!curentry || !(dir = curentry->dat))
- return;
-
- uidisplay(curentry);
+ sigwinch = 1;
}
diff --git a/ui_rogue_notes b/ui_rogue_notes
@@ -0,0 +1,31 @@
+# Notes
+- in need for a big gopher directory? use gopher://bitreich.org/1/memecache/
+
+# Bugs
+- not all corridors have 2 doors
+
+# Future Features?
+- k-medoids clustering using selector strings in reasonable time...
+ - items with similar selectors should get inserted into the same rooms
+ - one could use some mapping (sammon mapping?) to place the rooms based on t…
+ - similar clusters are near together
+- examine mode
+ - allow the cursor to move freely and describe the tiles with describe() in …
+- running using H, J, K, L
+ - go into the direction until the floor tile changes?
+ - with wall sliding to go through corridors
+ - needs to stop at junctions
+- spells
+ - teleport to a random room on the current level
+ - teleport to a random already visited level
+ - inscribe a scroll to teleport later back to the current level
+- visibility thingies to declutter things
+ - maybe like hack: keep things visible after discovery
+ - and what's with persisting this information?
+ - only show the content of the current room
+- better dungeon generation
+ - analyse things to create clever corridors
+- different dungeon themes
+ - so basically an extended dungeontype thing, with different dungeon generat…
+ - maybe some special layouts for root directories (empty selector)
+ - i look at you, ultima castle generator! https://slash.itch.io/ultima-cas…
diff --git a/ui_rogue_readme b/ui_rogue_readme
@@ -0,0 +1,28 @@
+# Description
+This UI module (?) for sacc displays directories like rogue/hack dungeon level…
+
+The code is ugly. It's obvious that I (pazz0) don't know what I do.
+
+# Compiling
+Copy ui_rogue.c in the sacc source directory.
+Go in the sacc source directory and execute blindly the following commands:
+```
+make clean && make UI=rogue
+```
+sacc will now have the much more confusing ui_rogue interface.
+
+# Key mapping
+h, j, k, l: left, down, up, right
+space: interact (in dungeon), select (in menu)
+ESC or q: exit (in dungeon), close menu
+
+# Map explanation
+E or ?: bookshelf/book (gopher type '0')
+L or >: elevator/staircase down/staircase up (gopher type '1' on the curre…
+O or 0: portal machine/portal (gopher type '1' on another server)
+%: heap of stuff (other non-handled gopher types, apart from 'i' and …
+standout (inverse) 0 or <: a way to go back to the previous gopher directory
+
+. or #: floor
+/: doors (behaves like floor)
+| or -: wall
You are viewing proxied material from bitreich.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.