ref: d370912d4a7fc88b8262269b83aecee30dbf4990
parent: 0397462f0ae8a0e097a0004738f870f898e325b4
author: henesy <henesy.dev@gmail.com>
date: Wed Feb 23 22:22:31 EST 2022
update with working test/demo program
--- /dev/null
+++ b/.gitignore
@@ -1,0 +1,3 @@
+*.[8qkv5967o]
+*.acid
+[8qkv5967o].out
--- a/.hgignore
+++ /dev/null
@@ -1,4 +1,0 @@
-syntax: glob
-*.[8qkv5967o]
-*.acid
-[8qkv5967o].out
--- a/9curses/9curses.c
+++ b/9curses/9curses.c
@@ -19,6 +19,13 @@
return w;
}
+// Delete and free a WINDOW
+void
+delwin(WINDOW *w)
+{
+ return;
+}
+
// Clean up and close a WINDOW
int
endwin()
@@ -107,3 +114,11 @@
// Stub
return 0;
}
+
+// Enable/disable the keypad
+void
+keypad(WINDOW* w, int enable)
+{
+ return;
+}
+
--- a/9curses/9curses.h
+++ b/9curses/9curses.h
@@ -20,6 +20,9 @@
// Initialize a new WINDOW
WINDOW* newwin(int, int, int, int);
+// Delete and free a WINDOW
+void delwin(WINDOW*);
+
// Clean up and close a WINDOW
int endwin();
@@ -56,3 +59,6 @@
struct WINDOW{
s8int naught;// Stub
};
+
+// Enable/disable the keypad
+void keypad(WINDOW*, int);
--- a/9curses/mkfile
+++ b/9curses/mkfile
@@ -1,7 +1,7 @@
</$objtype/mkfile
-#LIB=/$objtype/lib/lib9curses.a
-LIB=$home/lib/$objtype/lib9curses.a
+LIB=/$objtype/lib/lib9curses.a
+#LIB=$home/lib/$objtype/lib9curses.a
FILES=\
9curses
--- /dev/null
+++ b/demo/CHANGELOG
@@ -1,0 +1,12 @@
+10/15@02:05pm: re-structured code prior to tackling ncurses, shrank the size of main.c as a result
+10/15@03:40pm: can print and monster movement is intact, pc isn't moving yet
+10/15@09:08pm: added player movement at full functionality, many cores were dumped during creation of this change
+10/15@10:34pm: added most input commands
+10/17@07:36pm: added monster list functionality bar scrolling
+10/17@07:42pm: added monster list scrolling ;; was more simple than expected
+10/17@08:31pm: added dungeon re-generation and as such, stairwells
+10/17@08:45pm: fixed a memory leak issue and reduced all leaks to native ncurses leaks ;; fixed stairs overlapping occasionally
+10/17@08:52pm: composed and edited README
+10/18@02:26pm: tweaked the ncurses escape delay
+10/18@02:34pm: fixed a bug where the monster list viewing was treated as a valid move
+
--- /dev/null
+++ b/demo/Makefile
@@ -1,0 +1,7 @@
+all: main
+
+main: main.c binheap.c monsters.c world.c printing.c
+ ape/cc main.c binheap.c monsters.c world.c printing.c -lm -o dungeon_generator
+
+clean: dungeon_generator
+ rm dungeon_generator
--- /dev/null
+++ b/demo/README
@@ -1,0 +1,1 @@
+A straightforward dungeon generator that utilizes Dijkstra's algorithm for pathing of specific monsters and pseudo-random room and monster generation. Stairs are present which can be activated by invoking the matching symbol as the stairwell, '<' for up and '>' for down. Monsters are indexed and can be viewed by utilizing the 'm' key menu which is scrollable should the list of monsters exceed the standard terminal size of 24 rows. NCurses is utilized as the means of creating an interactive an non-buffered-input user interface. NCurses induces a minor memory leak report by Valgrind, standardized at around 181,068 bytes with a slight increase if the 'm' menu is used, as it creates a new window, to around 206,249 bytes.
--- /dev/null
+++ b/demo/binheap.c
@@ -1,0 +1,377 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "binheap.h"
+
+#define BINHEAP_START_SIZE 128
+
+struct binheap_node {
+ void *datum;
+ uint32_t index;
+};
+
+static void percolate_up(binheap_t *h, uint32_t index)
+{
+ uint32_t parent;
+ binheap_node_t *tmp;
+
+ for (parent = (index - 1) / 2;
+ index && h->compare(h->array[index]->datum, h->array[parent]->datum) < 0;
+ index = parent, parent = (index - 1) / 2) {
+ tmp = h->array[index];
+ h->array[index] = h->array[parent];
+ h->array[parent] = tmp;
+ h->array[index]->index = index;
+ h->array[parent]->index = parent;
+ }
+}
+
+static void percolate_down(binheap_t *h, uint32_t index)
+{
+ uint32_t child;
+ void *tmp;
+
+ for (child = (2 * index) + 1;
+ child < h->size;
+ index = child, child = (2 * index) + 1) {
+ if (child + 1 < h->size &&
+ h->compare(h->array[child]->datum, h->array[child + 1]->datum) > 0) {
+ child++;
+ }
+ if (h->compare(h->array[index]->datum, h->array[child]->datum) > 0) {
+ tmp = h->array[index];
+ h->array[index] = h->array[child];
+ h->array[child] = tmp;
+ h->array[index]->index = index;
+ h->array[child]->index = child;
+ }
+ }
+}
+
+static void heapify(binheap_t *h)
+{
+ uint32_t i;
+
+ for (i = (h->size + 1) / 2; i; i--) {
+ percolate_down(h, i);
+ }
+ percolate_down(h, 0);
+}
+
+void binheap_init(binheap_t *h,
+ int32_t (*compare)(const void *key, const void *with),
+ void (*datum_delete)(void *))
+{
+ h->size = 0;
+ h->array_size = BINHEAP_START_SIZE;
+ h->compare = compare;
+ h->datum_delete = datum_delete;
+
+ h->array = calloc(h->array_size, sizeof (*h->array));
+}
+
+void binheap_init_from_array(binheap_t *h,
+ void *array,
+ uint32_t size,
+ uint32_t nmemb,
+ int32_t (*compare)(const void *key,
+ const void *with),
+ void (*datum_delete)(void *))
+{
+ uint32_t i;
+ char *a;
+
+ h->size = h->array_size = nmemb;
+ h->compare = compare;
+ h->datum_delete = datum_delete;
+
+ h->array = calloc(h->array_size, sizeof (*h->array));
+
+ for (i = 0, a = array; i < h->size; i++) {
+ h->array[i] = malloc(sizeof (*h->array[i]));
+ h->array[i]->index = i;
+ h->array[i]->datum = a + (i * size);
+ }
+
+ heapify(h);
+}
+
+void binheap_delete(binheap_t *h)
+{
+ uint32_t i;
+
+ for (i = 0; i < h->size; i++) {
+ if (h->datum_delete) {
+ h->datum_delete(h->array[i]->datum);
+ }
+ free(h->array[i]);
+ }
+ free(h->array);
+ memset(h, 0, sizeof (*h));
+}
+
+binheap_node_t *binheap_insert(binheap_t *h, void *v)
+{
+ binheap_node_t **tmp;
+ binheap_node_t *retval;
+
+ if (h->size == h->array_size) {
+ h->array_size *= 2;
+ tmp = realloc(h->array, h->array_size * sizeof (*h->array));
+ if (!tmp) {
+ /* Error */
+ } else {
+ h->array = tmp;
+ }
+ }
+
+ h->array[h->size] = retval = malloc(sizeof (*h->array[h->size]));
+ h->array[h->size]->datum = v;
+ h->array[h->size]->index = h->size;
+
+ percolate_up(h, h->size);
+ h->size++;
+
+ return retval;
+}
+
+void *binheap_peek_min(binheap_t *h)
+{
+ return h->size ? h->array[0]->datum : NULL;
+}
+
+void *binheap_remove_min(binheap_t *h)
+{
+ void *tmp;
+
+ if (!h->size) {
+ return NULL;
+ }
+
+ tmp = h->array[0]->datum;
+ free(h->array[0]);
+ h->size--;
+ h->array[0] = h->array[h->size];
+ percolate_down(h, 0);
+
+ return tmp;
+}
+
+void binheap_decrease_key(binheap_t *h, binheap_node_t *n)
+{
+ percolate_up(h, n->index);
+}
+
+uint32_t binheap_is_empty(binheap_t *h)
+{
+ return !h->size;
+}
+
+#ifdef TESTING
+
+#include <stdio.h>
+
+int32_t compare_int(const void *key, const void *with)
+{
+ return *(const int32_t *) key - *(const int32_t *) with;
+}
+
+int main(int argc, char *argv[])
+{
+ binheap_t h;
+ int32_t a[1024];
+ int32_t i, j, r;
+ int32_t parent, child;
+ binheap_node_t *nodes[1024];
+
+ for (i = 0; i < 1024; i++) {
+ a[i] = 1024 - i;
+ }
+
+ binheap_init(&h, compare_int, NULL);
+ for (i = 0; i < 1024; i++) {
+ binheap_insert(&h, a + i);
+ }
+
+ for (i = 0; i < 1024; i++) {
+ parent = (i - 1) / 2;
+ child = (2 * i) + 1;
+ if (!i) {
+ if (*(int *) h.array[i]->datum > *(int *) h.array[child]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child + 1]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[i]->datum,
+ *(int *) h.array[child]->datum,
+ *(int *) h.array[child + 1]->datum);
+ } else if (i < (h.size - 1) / 2) {
+ if (*(int *) h.array[i]->datum < *(int *) h.array[parent]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child + 1]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[parent]->datum,
+ *(int *) h.array[i]->datum,
+ *(int *) h.array[child]->datum,
+ *(int *) h.array[child + 1]->datum);
+ } else {
+ if (*(int *) h.array[i]->datum < *(int *) h.array[parent]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[parent]->datum,
+ *(int *) h.array[i]->datum);
+ }
+ }
+
+ binheap_delete(&h);
+
+ binheap_init_from_array(&h, a, sizeof (*a), 1024, compare_int, NULL);
+
+ for (i = 0; i < 1024; i++) {
+ parent = (i - 1) / 2;
+ child = (2 * i) + 1;
+ if (!i) {
+ if (*(int *) h.array[i]->datum > *(int *) h.array[child]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child + 1]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[i]->datum,
+ *(int *) h.array[child]->datum,
+ *(int *) h.array[child + 1]->datum);
+ } else if (i < (h.size - 1) / 2) {
+ if (*(int *) h.array[i]->datum < *(int *) h.array[parent]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child + 1]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[parent]->datum,
+ *(int *) h.array[i]->datum,
+ *(int *) h.array[child]->datum,
+ *(int *) h.array[child + 1]->datum);
+ } else {
+ if (*(int *) h.array[i]->datum < *(int *) h.array[parent]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[parent]->datum,
+ *(int *) h.array[i]->datum);
+ }
+ }
+
+ while (!binheap_is_empty(&h)) {
+ binheap_remove_min(&h);
+
+ for (i = 0; i < h.size; i++) {
+ parent = (i - 1) / 2;
+ child = (2 * i) + 1;
+ if (h.size == 1) {
+ printf("%4d: %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[i]->datum);
+ } else if (!i) {
+ if (*(int *) h.array[i]->datum > *(int *) h.array[child]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child + 1]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[i]->datum,
+ *(int *) h.array[child]->datum,
+ *(int *) h.array[child + 1]->datum);
+ } else if (i < (h.size - 1) / 2) {
+ if (*(int *) h.array[i]->datum < *(int *) h.array[parent]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child + 1]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[parent]->datum,
+ *(int *) h.array[i]->datum,
+ *(int *) h.array[child]->datum,
+ *(int *) h.array[child + 1]->datum);
+ } else {
+ if (*(int *) h.array[i]->datum < *(int *) h.array[parent]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[parent]->datum,
+ *(int *) h.array[i]->datum);
+ }
+ }
+ }
+
+ binheap_delete(&h);
+
+ binheap_init(&h, compare_int, NULL);
+ for (i = 0; i < 1024; i++) {
+ nodes[i] = binheap_insert(&h, a + i);
+ }
+
+ for (i = 0; i < 1024; i++) {
+ printf("%d\n", *(int *) nodes[i]->datum);
+ }
+
+ for (j = 0; j < 1; j++) {
+ r = 1020;
+ a[r] = 0;
+ binheap_decrease_key(&h, nodes[r]);
+ for (i = 0; i < h.size; i++) {
+ parent = (i - 1) / 2;
+ child = (2 * i) + 1;
+ if (h.size == 1) {
+ printf("%4d: %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[i]->datum);
+ } else if (!i) {
+ if (*(int *) h.array[i]->datum > *(int *) h.array[child]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child + 1]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[i]->datum,
+ *(int *) h.array[child]->datum,
+ *(int *) h.array[child + 1]->datum);
+ } else if (i < (h.size - 1) / 2) {
+ if (*(int *) h.array[i]->datum < *(int *) h.array[parent]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child]->datum ||
+ *(int *) h.array[i]->datum > *(int *) h.array[child + 1]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[parent]->datum,
+ *(int *) h.array[i]->datum,
+ *(int *) h.array[child]->datum,
+ *(int *) h.array[child + 1]->datum);
+ } else {
+ if (*(int *) h.array[i]->datum < *(int *) h.array[parent]->datum) {
+ printf("Error follows:\n");
+ }
+ printf("%4d: %4d %4d\n",
+ h.array[i]->index,
+ *(int *) h.array[parent]->datum,
+ *(int *) h.array[i]->datum);
+ }
+ }
+ }
+
+ binheap_delete(&h);
+
+ return 0;
+}
+
+#endif
--- /dev/null
+++ b/demo/binheap.h
@@ -1,0 +1,42 @@
+#ifndef BINHEAP_H
+# define BINHEAP_H
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# include <stdint.h>
+
+struct binheap_node;
+typedef struct binheap_node binheap_node_t;
+
+typedef struct binheap {
+ binheap_node_t **array;
+ uint32_t size;
+ uint32_t array_size;
+ int32_t (*compare)(const void *key, const void *with);
+ void (*datum_delete)(void *);
+} binheap_t;
+
+void binheap_init(binheap_t *h,
+ int32_t (*compare)(const void *key, const void *with),
+ void (*datum_delete)(void *));
+void binheap_init_from_array(binheap_t *h,
+ void *array,
+ uint32_t size,
+ uint32_t nmemb,
+ int32_t (*compare)(const void *key,
+ const void *with),
+ void (*datum_delete)(void *));
+void binheap_delete(binheap_t *h);
+binheap_node_t *binheap_insert(binheap_t *h, void *v);
+void *binheap_peek_min(binheap_t *h);
+void *binheap_remove_min(binheap_t *h);
+void binheap_decrease_key(binheap_t *h, binheap_node_t *n);
+uint32_t binheap_is_empty(binheap_t *h);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
binary files /dev/null b/demo/dungeon_generator differ
--- /dev/null
+++ b/demo/dungeon_generator.h
@@ -1,0 +1,118 @@
+#ifndef dungeon_generator
+#define dungeon_generator
+#include "binheap.h"
+/* set up Booleans */
+#define TRUE 1
+#define FALSE 0
+typedef int Bool;
+
+/* custom structures */
+typedef struct {
+ int h; /* hardness */
+ char c; /* visual character */
+ int p; /* mark 1 if path, 0 if not a path (corridors) */
+} Tile;
+
+typedef struct {
+ int x; /* x coordinate */
+ int y; /* y coordinate */
+} Position;
+
+/* maybe make these pointers? */
+typedef struct {
+ int prev; /* previous room in the path (using Room.id) */
+ int next; /* room the path leads to (using Room.id) */
+} Path;
+
+typedef struct {
+ Bool in; /* intelligence */
+ Bool te; /* telepathy */
+ Bool tu; /* tunneling ability */
+ Bool eb; /* erratic behaviour */
+ int s; /* speed ;; pc has 10 ; 5-20 */
+} Stats;
+
+typedef struct {
+ Position p; /* position of the sprite in the dungeon */
+ char c; /* character to print for the sprite */
+ Stats s; /* stats for a sprite */
+ int t; /* turn count */
+ Position to; /* to move to */
+ int sn; /* sprite number */
+ Position pc; /* last known location of the PC */
+ Bool a; /* alive T/F */
+} Sprite;
+
+typedef struct {
+ Position tl; /* top left coordinate of the room, used as the core point of reference */
+ Position br; /* bottom right coordinate of the room as per above */
+ int w; /* width */
+ int h; /* height */
+ int id; /* room ID, potentially useful for organization */
+ int p; /* mark 1 if processed; 0 if not processed (corridors) */
+ Position ctr; /* "center" point; very rough, might need improved */
+ int c; /* if connected or not; TRUE/FALSE switch */
+} Room;
+
+typedef struct {
+ Tile ** d; /* dungeon buffer */
+ Tile ** p; /* print buffer */
+ int h; /* height */
+ int w; /* width */
+ int nr; /* number of rooms */
+ int mr; /* max rooms */
+ Room * r; /* rooms buffer */
+ int v; /* file version */
+ int s; /* file size */
+ Sprite * ss; /* sprite array */
+ int ns; /* number of sprites */
+ int ms; /* max number of sprites */
+ int ** csnt;
+ int ** cst; /* costs for djikstra's map */
+ int pc; /* location of PC in SpriteS array (.ss) */
+ int t; /* turn number */
+ Bool go; /* game over T/F */
+ Position su; /* location of the dungeon's up staircase */
+ Position sd; /* location of the dungeon's down staircase */
+} Dungeon;
+
+typedef struct {
+ int x;
+ int y;
+ int cost;
+ int v;
+} Tile_Node;
+
+typedef struct {
+ int sn; /* sprite number */
+ int speed; /* speed of the Sprite */
+ int turn; /* turn counter */
+ Position to; /* where we move to */
+} Event;
+
+/*** Function prototypes ***/
+/* monsters.c */
+void add_sprite(Dungeon * dungeon, Sprite s);
+Sprite gen_sprite(Dungeon * dungeon, char c, int x, int y, int r);
+void gen_move_sprite(Dungeon * dungeon, int sn);
+void parse_move(Dungeon * dungeon, int sn);
+Bool check_any_monsters(Dungeon * dungeon);
+Bool test_loc(Dungeon * dungeon, int x, int y, Sprite *s);
+void with_pc(Dungeon * dungeon, Sprite * s, Bool *in);
+
+/* world.c */
+void gen_corridors(Dungeon * dungeon);
+void gen_dungeon(Dungeon * dungeon);
+Dungeon* init_dungeon(int h, int w, int mr);
+
+/* printing.c */
+void print_hardness(Dungeon * dungeon);
+void print_t_heatmap(Dungeon * dungeon);
+void print_nont_heatmap(Dungeon * dungeon);
+void print_dungeon(Dungeon * dungeon, int nt, int t);
+void print_dungeon_nnc(Dungeon * dungeon, int nt, int t);
+
+/* main.c */
+void map_dungeon_t(Dungeon * dungeon);
+
+#endif
--- /dev/null
+++ b/demo/endian.h
@@ -1,0 +1,13 @@
+typedef unsigned int uint;
+typedef long intptr;
+typedef unsigned long uintptr;
+typedef uint Rune;
+typedef unsigned int mpdigit; /* for /sys/include/mp.h */
+typedef unsigned char u8int;
+typedef unsigned short u16int;
+typedef unsigned int u32int;
+typedef unsigned long long u64int;
+typedef signed char s8int;
+typedef signed short s16int;
+typedef signed int s32int;
+typedef signed long long s64int;
--- /dev/null
+++ b/demo/main.c
@@ -1,0 +1,805 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <stdint.h>
+#include "endian.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <unistd.h>
+#include "/sys/include/9curses.h"
+#include "binheap.h"
+#include "dungeon_generator.h"
+
+
+/* compare two ints used as costs ;; 0 if same, <0 if higher than key; >0 if lower than key */
+int compare_int(const void *key, const void *with) {
+ //printf("%d\n", *(const int *) key);
+ return (const int) ((*(Tile_Node *) key).cost - (*(Tile_Node *) with).cost);
+}
+
+/* returns the hardness cost of an int hardness */
+int h_calc(int h) {
+ int hc = 0;
+
+ if(h >= 0 && h < 85) {
+ return 1;
+ }
+ if(h > 84 && h < 171) {
+ return 2;
+ }
+ if(h > 170 && h < 255) {
+ return 3;
+ }
+
+ return hc;
+}
+
+/* djikstra's take 2; with tunnelling */
+void map_dungeon_t(Dungeon * dungeon) {
+ binheap_t h;
+ int i;
+ //Tile_Node tiles[dungeon->h][dungeon->w];
+ Tile_Node **tiles = calloc(dungeon->h, sizeof (Tile_Node*));
+ for(i = 0; i < dungeon->h; i++)
+ tiles[i] = calloc(dungeon->w, sizeof (Tile_Node));
+
+ binheap_init(&h, compare_int, NULL);
+
+ /* starts from top left */
+ int xs[8] = {-1,0,1,1,1,0,-1,-1};
+ int ys[8] = {-1,-1,-1,0,1,1,1,0};
+
+ int j;
+
+ /* set all indices and insert the default values */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ tiles[i][j].y = i;
+ tiles[i][j].x = j;
+ tiles[i][j].cost = INT_MAX;
+ tiles[i][j].v = FALSE;
+ }
+ }
+
+ /* set the player's cost as 0: */
+ int px = dungeon->ss[dungeon->pc].p.x;
+ int py = dungeon->ss[dungeon->pc].p.y;
+ tiles[py][px].cost = 0;
+ tiles[py][px].v = TRUE;
+ binheap_insert(&h, &tiles[py][px]);
+
+ /* primary cost calculation logic */
+
+ binheap_node_t *p;
+
+ while((p = binheap_remove_min(&h))) {
+ int hx = ((Tile_Node *) p)->x;
+ int hy = ((Tile_Node *) p)->y;
+ int tc = ((Tile_Node *) p)->cost;
+
+ int i;
+ for(i = 0; i < 8; i++) {
+ int x = hx + xs[i];
+ int y = hy + ys[i];
+ if(x > 0 && x < dungeon->w-1 && y > 0 && y < dungeon->h-1) {
+ int hard = dungeon->d[y][x].h;
+ if(hard < 255) {
+ int trial_cost = tc + h_calc(hard);
+ if((tiles[y][x].cost > trial_cost && tiles[y][x].v == TRUE) || tiles[y][x].v == FALSE) {
+ tiles[y][x].cost = tc + h_calc(hard);
+ tiles[y][x].v = TRUE;
+
+ binheap_insert(&h, (void *) &tiles[y][x]);
+ }
+ }
+ }
+ }
+ }
+
+ /* copy the heatmap to the dungeon */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ dungeon->cst[i][j] = tiles[i][j].cost;
+ }
+ }
+
+
+ /* clean up the heap */
+ binheap_delete(&h);
+}
+
+/* djikstra's take 2 */
+void map_dungeon_nont(Dungeon * dungeon) {
+ binheap_t h;
+ //Tile_Node tiles[dungeon->h][dungeon->w];
+ //printf("h=%d w=%d tile_node size=%d\n", dungeon->h, dungeon->w, sizeof(Tile_Node));
+ Tile_Node **tiles = calloc(dungeon->h, sizeof (Tile_Node*));
+ int i;
+ for(i = 0; i < dungeon->h; i++)
+ tiles[i] = calloc(dungeon->w, sizeof (Tile_Node));
+
+ binheap_init(&h, compare_int, NULL);
+
+ /* starts from top left */
+ int xs[8] = {-1,0,1,1,1,0,-1,-1};
+ int ys[8] = {-1,-1,-1,0,1,1,1,0};
+
+ int j;
+
+ /* set all indices and insert the default values */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ //printf("i=%d j=%d\n", i, j);
+ tiles[i][j].y = i;
+ tiles[i][j].x = j;
+ tiles[i][j].cost = INT_MAX;
+ tiles[i][j].v = FALSE;
+ }
+ }
+
+ /* set the player's cost as 0: */
+ int px = dungeon->ss[dungeon->pc].p.x;
+ int py = dungeon->ss[dungeon->pc].p.y;
+ tiles[py][px].cost = 0;
+ tiles[py][px].v = TRUE;
+ binheap_insert(&h, &tiles[py][px]);
+
+ /* primary cost calculation logic */
+
+ binheap_node_t *p;
+
+ while((p = binheap_remove_min(&h))) {
+ int hx = ((Tile_Node *) p)->x;
+ int hy = ((Tile_Node *) p)->y;
+ int tc = ((Tile_Node *) p)->cost;
+
+ int i;
+ for(i = 0; i < 8; i++) {
+ int x = hx + xs[i];
+ int y = hy + ys[i];
+ if(x > 0 && x < dungeon->w-1 && y > 0 && y < dungeon->h-1) {
+ int hard = dungeon->d[y][x].h;
+ if(hard == 0) {
+ int trial_cost = tc + h_calc(hard);
+ if((tiles[y][x].cost > trial_cost && tiles[y][x].v == TRUE) || tiles[y][x].v == FALSE) {
+ tiles[y][x].cost = tc + h_calc(hard);
+ tiles[y][x].v = TRUE;
+
+ binheap_insert(&h, (void *) &tiles[y][x]);
+ }
+ }
+ }
+ }
+
+ }
+
+ /* copy the heatmap to the dungeon */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ dungeon->csnt[i][j] = tiles[i][j].cost;
+ }
+ }
+
+
+ /* clean up the heap */
+ binheap_delete(&h);
+}
+
+/* reads from a dungeon file */
+void read_dungeon(Dungeon * dungeon, char * path) {
+ FILE * file;
+ file = fopen(path, "rb+");
+ if(file == NULL) {
+ fprintf(stderr, "FILE ERROR: Could not open dungeon file at %s! read_dungeon()\n", path);
+ exit(1);
+ }
+
+ /* read the file-type marker */
+ fseek(file, 0, SEEK_SET);
+ char marker[6];
+ fread(marker, 1, 6, file);
+
+ /* read the file version marker */
+ fseek(file, 6, SEEK_SET);
+ uint32_t file_version;
+ uint32_t file_version_be;
+ fread(&file_version_be, sizeof(uint32_t), 1, file);
+ // endian is miss
+ //file_version = be32toh(file_version_be);
+ dungeon->v = file_version;
+
+ /* read the size of file */
+ fseek(file, 10, SEEK_SET);
+ uint32_t size;
+ uint32_t size_be;
+ fread(&size_be, sizeof(uint32_t), 1, file);
+ //size = be32toh(size_be);
+ size = size_be;
+ dungeon->s = size;
+
+ /* read the hardness values in */
+ fseek(file, 14, SEEK_SET);
+ int i;
+ int j;
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ int h;
+ int8_t h_8;
+ fread(&h_8, sizeof(int8_t), 1, file);
+ h = (int) h_8;
+ dungeon->d[i][j].h = h;
+ }
+ }
+
+ /* read in rooms in dungeon */
+ fseek(file, 1694, SEEK_SET);
+ /* might want to make this just counted in 4's by the loop below, but w/e, math, amirite? */
+ int room_i = 0;
+ int room_count = (size - 1693) / 4;
+ dungeon->nr = room_count;
+ dungeon->r = calloc(room_count, sizeof(Room));
+ /* could probably be replaced with a getpos() call for complete-ness */
+ int pos;
+ for(pos = 1694; pos < size; pos += 4) {
+ int x_8;
+ int w_8;
+ int y_8;
+ int h_8;
+ fread(&x_8, sizeof(int8_t), 1, file);
+ fread(&w_8, sizeof(int8_t), 1, file);
+ fread(&y_8, sizeof(int8_t), 1, file);
+ fread(&h_8, sizeof(int8_t), 1, file);
+
+ dungeon->r[room_i].tl.x = (int8_t) x_8;
+ dungeon->r[room_i].w = (int8_t) w_8;
+ dungeon->r[room_i].tl.y = (int8_t) y_8;
+ dungeon->r[room_i].h = (int8_t) h_8;
+ dungeon->r[room_i].br.x = ((int8_t) x_8) + dungeon->r[room_i].w-1;
+ dungeon->r[room_i].br.y = ((int8_t) y_8) + dungeon->r[room_i].h-1;
+
+
+
+ room_i++;
+ }
+
+
+ /* populate the rooms and corridors if not in rooms */
+ /* add rooms to the dungeon buffer */
+ int h;
+ for(h = 0; h < dungeon->nr; h++) {
+ for(i = dungeon->r[h].tl.y; i < dungeon->r[h].br.y+1; i++) {
+ for(j = dungeon->r[h].tl.x; j < dungeon->r[h].br.x+1; j++) {
+ dungeon->d[i][j].c = '.';
+ }
+ }
+ }
+
+ /* add corridors to the dungeon buffer */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ if(dungeon->d[i][j].c != '.' && dungeon->d[i][j].h == 0) {
+ dungeon->d[i][j].c = '#';
+ dungeon->d[i][j].p = 1;
+ }
+ }
+ }
+
+
+ fclose(file);
+}
+
+/* writes the dungeon file to ~/.rlg327/dungeon */
+void write_dungeon(Dungeon * dungeon, char * path) {
+ FILE * file;
+
+ /* folder creation logic */
+ char * env_home = getenv("HOME");
+ char * fdir_path;
+ fdir_path = calloc(strlen(env_home) + 9, sizeof(char));
+ strcpy(fdir_path, env_home);
+ strcat(fdir_path, "/.rlg327");
+ mkdir(fdir_path, S_IRWXU);
+ /* mkdir will return -1 when it fails, but it will fail if the file exists so it doesn't especially matter to catch it as no output would be provided */
+
+
+ file = fopen(path, "wb+");
+ if(file == NULL) {
+ fprintf(stderr, "FILE ERROR: Could not open dungeon file at %s! write_dungeon()\n", path);
+ exit(1);
+ }
+
+ /* write the file-type marker */
+ fseek(file, 0, SEEK_SET);
+ char marker[7];
+ strcpy(marker, "RLG327");
+ fwrite(marker, sizeof(char), 6, file);
+
+ /* write the file version marker */
+ fseek(file, 6, SEEK_SET);
+ uint32_t file_version = 0;
+ //uint32_t file_version_be = htobe32(file_version);
+ uint32_t file_version_be = file_version;
+ fwrite(&file_version_be, sizeof(uint32_t), 1, file);
+
+ /* write the size of the file ;; unsure how to properly calculate */
+ fseek(file, 10, SEEK_SET);
+ uint32_t size = 1693 + (4 * dungeon->nr);
+ //uint32_t size_be = htobe32(size);
+ uint32_t size_be = size;
+ fwrite(&size_be, sizeof(uint32_t), 1, file);
+
+ /* row-major dungeon matrix */
+ fseek(file, 14, SEEK_SET);
+ int pos = 14;
+ int i;
+ int j;
+
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ fseek(file, pos, SEEK_SET);
+ int8_t h;
+ h = (int8_t)(dungeon->d[i][j].h);
+ fwrite(&h, sizeof(int8_t), 1, file);
+ pos++;
+ }
+ }
+
+ /* room positions ;; 4 bytes per room */
+ fseek(file, 1694, SEEK_SET);
+ for(i = 0; i < dungeon->nr; i++) {
+ int8_t x = (int8_t) dungeon->r[i].tl.x;
+ int8_t w = (int8_t) dungeon->r[i].w;
+ int8_t y = (int8_t) dungeon->r[i].tl.y;
+ int8_t h = (int8_t) dungeon->r[i].h;
+
+ fwrite(&x, sizeof(int8_t), 1, file);
+ fwrite(&w, sizeof(int8_t), 1, file);
+ fwrite(&y, sizeof(int8_t), 1, file);
+ fwrite(&h, sizeof(int8_t), 1, file);
+ }
+
+ free(fdir_path);
+ fclose(file);
+}
+
+/* parses commandline arguments */
+void test_args(int argc, char ** argv, int this, int * s, int * l, int *p, int *cp, int *nm, int *nnc) {
+ if(strcmp(argv[this], "--save") == 0) {
+ *s = TRUE;
+ } else if(strcmp(argv[this], "--load") == 0) {
+ *l = TRUE;
+ } else if(strcmp(argv[this], "-f") == 0) {
+ *p = TRUE;
+ *cp = this+1;
+ if(this+1 > argc-1) {
+ printf("Invalid filename argument!\n");
+ *p = FALSE;
+ }
+ } else if(strcmp(argv[this], "--nummon") == 0) {
+ *nm = atoi(argv[this+1]);
+ } else if(strcmp(argv[this], "--no-ncurses") == 0) {
+ *nnc = TRUE;
+ }
+}
+
+/* monster list view */
+void monster_list(Dungeon * dungeon) {
+ clear();
+
+ /* monster view array and population */
+ //char mons [dungeon->ns-1][30];
+ char **mons = calloc(dungeon->ns-1, sizeof(char*));
+ int i;
+ for(i = 0; i < dungeon->ns-1; i++)
+ mons[i] = calloc(30, sizeof(char));
+
+ for(i = 1; i < dungeon->ns; i++) {
+ char ns[6];
+ char ew[5];
+
+ int hd = dungeon->ss[0].p.y - dungeon->ss[i].p.y;
+ int wd = dungeon->ss[0].p.x - dungeon->ss[i].p.x;
+
+ if(hd > 0)
+ strcpy(ns, "north");
+ else
+ strcpy(ns, "south");
+
+ if(wd > 0)
+ strcpy(ew, "west");
+ else
+ strcpy(ew, "east");
+
+ sprintf(mons[i-1], "%c, %2d %s and %2d %s", dungeon->ss[i].c, abs(hd), ns, abs(wd), ew);
+ }
+
+ /* secondary window */
+ WINDOW *w;
+ w = newwin(24, 80, 0, 0);
+ Bool scroll = FALSE;
+ int top = 0;
+ int bot;
+ if(24 < dungeon->ns -1) {
+ scroll = TRUE;
+ bot = 23;
+ } else {
+ bot = dungeon->ns -2;
+ }
+
+ int j;
+ for(;;) {
+ /* put the monster view to the screen */
+ for(i = top, j = 0; i < dungeon->ns -1 && i <= bot && j < 24; i++, j++) {
+ mvprintw(j, 0, mons[i]);
+ }
+
+ /* handle user interaction */
+ MLV: ;
+ int32_t k;
+ k = getch();
+
+ switch(k) {
+ case KEY_UP:
+ /* scroll up */
+ if(scroll == FALSE)
+ goto MLV;
+
+ if(top-1 >= 0) {
+ top--;
+ bot--;
+ }
+ clear();
+
+ break;
+ case KEY_DOWN:
+ /* scroll down */
+ if(scroll == FALSE)
+ goto MLV;
+
+ if(bot+1 < dungeon->ns-1) {
+ bot++;
+ top++;
+ }
+ clear();
+
+ break;
+ case 27:
+ /* ESC */
+ return;
+ break;
+ default:
+ goto MLV;
+ }
+
+ wrefresh(w);
+ }
+
+ delwin(w);
+ print_dungeon(dungeon, 0, 0);
+}
+
+/* processes pc movements ;; validity checking is in monsters.c's gen_move_sprite() */
+void parse_pc(Dungeon * dungeon, Bool * run, Bool * regen) {
+ GCH: ;
+ int32_t k;
+ k = getch();
+ if(k == 'Q') {
+ *run = FALSE;
+ return;
+ }
+
+ switch(k) {
+ case 'h':
+ H: ;
+ dungeon->ss[dungeon->pc].to.x = dungeon->ss[dungeon->pc].p.x - 1;
+ break;
+ case '4':
+ goto H;
+ case 'l':
+ L: ;
+ dungeon->ss[dungeon->pc].to.x = dungeon->ss[dungeon->pc].p.x + 1;
+ break;
+ case '6':
+ goto L;
+ case 'k':
+ K: ;
+ dungeon->ss[dungeon->pc].to.y = dungeon->ss[dungeon->pc].p.y - 1;
+ break;
+ case '8':
+ goto K;
+ case 'j':
+ J: ;
+ dungeon->ss[dungeon->pc].to.y = dungeon->ss[dungeon->pc].p.y + 1;
+ break;
+ case '2':
+ goto J;
+ case 'y':
+ Y: ;
+ dungeon->ss[dungeon->pc].to.y = dungeon->ss[dungeon->pc].p.y - 1;
+ dungeon->ss[dungeon->pc].to.x = dungeon->ss[dungeon->pc].p.x - 1;
+ break;
+ case '7':
+ goto Y;
+ case 'u':
+ U: ;
+ dungeon->ss[dungeon->pc].to.y = dungeon->ss[dungeon->pc].p.y - 1;
+ dungeon->ss[dungeon->pc].to.x = dungeon->ss[dungeon->pc].p.x + 1;
+ break;
+ case '9':
+ goto U;
+ case 'n':
+ N: ;
+ dungeon->ss[dungeon->pc].to.y = dungeon->ss[dungeon->pc].p.y + 1;
+ dungeon->ss[dungeon->pc].to.x = dungeon->ss[dungeon->pc].p.x + 1;
+ break;
+ case '3':
+ goto N;
+ case 'b':
+ B: ;
+ dungeon->ss[dungeon->pc].to.y = dungeon->ss[dungeon->pc].p.y + 1;
+ dungeon->ss[dungeon->pc].to.x = dungeon->ss[dungeon->pc].p.x - 1;
+ break;
+ case '1':
+ goto B;
+ case '<':
+ /* stair up */
+ if(dungeon->ss[0].p.x == dungeon->su.x && dungeon->ss[0].p.y == dungeon->su.y)
+ *regen = TRUE;
+ break;
+ case '>':
+ /* stair down */
+ if(dungeon->ss[0].p.x == dungeon->sd.x && dungeon->ss[0].p.y == dungeon->sd.y)
+ *regen = TRUE;
+ break;
+ case '5':
+ break;
+ case ' ':
+ break;
+ case 'm':
+ monster_list(dungeon);
+ print_dungeon(dungeon, 0, 0);
+ goto GCH;
+ default:
+ goto GCH;
+ }
+
+ /* movement validity check */
+ if(dungeon->d[dungeon->ss[dungeon->pc].to.y][dungeon->ss[dungeon->pc].to.x].h > 0) {
+ dungeon->ss[dungeon->pc].to.x = dungeon->ss[dungeon->pc].p.x;
+ dungeon->ss[dungeon->pc].to.y = dungeon->ss[dungeon->pc].p.y;
+ } else {
+ dungeon->ss[dungeon->pc].p.x = dungeon->ss[dungeon->pc].to.x;
+ dungeon->ss[dungeon->pc].p.y = dungeon->ss[dungeon->pc].to.y;
+ }
+ dungeon->ss[0].t += (100 / dungeon->ss[0].s.s);
+
+ /* check for killing an NPC */
+ int sn = 0;
+ int i;
+ for(i = 1; i < dungeon->ns; i++) {
+ if(i != sn) {
+ if((dungeon->ss[i].to.x == dungeon->ss[sn].to.x) && (dungeon->ss[i].to.y == dungeon->ss[sn].to.y) && dungeon->ss[sn].a == TRUE)
+ dungeon->ss[i].a = FALSE;
+ }
+ }
+}
+
+
+/* Basic procedural dungeon generator */
+int main(int argc, char * argv[]) {
+ /*** process commandline arguments ***/
+ int max_args = 8;
+ int saving = FALSE;
+ int loading = FALSE;
+ int pathing = FALSE;
+ int nnc = FALSE;
+ int num_mon = 1;
+ int custom_path = 0;
+ if(argc > 2 && argc <= max_args) {
+ /* both --save and --load */
+ int i;
+ for(i = 1; i < argc; i++) {
+ test_args(argc, argv, i, &saving, &loading, &pathing, &custom_path, &num_mon, &nnc);
+ }
+ } else if(argc == 2) {
+ /* one arg */
+ test_args(argc, argv, 1, &saving, &loading, &pathing, &custom_path, &num_mon, &nnc);
+ } else if(argc > max_args) {
+ /* more than 2 commandline arguments, argv[0] is gratuitous */
+ printf("Too many arguments!\n");
+ } else {
+ /* other; most likely 0 */
+ }
+ /*** end processing commandline arguments ***/
+
+
+ /* init the dungeon with default dungeon size and a max of 12 rooms */
+ srand(time(NULL));
+
+ /* create 2 char pointers so as not to pollute the original HOME variable */
+ char * env_path = getenv("home");
+ if(env_path == NULL)
+ env_path = "/usr/seh/";
+ /* char * path = calloc(strlen(env_path) + 17, sizeof(char)); */
+ char * path = calloc(strlen(env_path) + 50, sizeof(char));
+ strcpy(path, env_path);
+ strcat(path, "/.rlg327");
+ if(pathing == TRUE) {
+ strcat(path, "/");
+ strcat(path, argv[custom_path]);
+ } else {
+ strcat(path, "/dungeon");
+ }
+
+ /* persistent player character */
+ Bool regen = FALSE;
+ Sprite p_pc;
+
+ /*** dungeon generation starts here ***/
+ DUNGEN: ;
+
+ Dungeon *dungeon = init_dungeon(21, 80, 12);
+
+ if(loading == FALSE) {
+ gen_dungeon(dungeon);
+ gen_corridors(dungeon);
+ } else {
+ read_dungeon(dungeon, path);
+ }
+ /*** dungeon is fully initiated ***/
+ Sprite pc = gen_sprite(dungeon, '@', -1, -1, 1);
+ add_sprite(dungeon, pc);
+
+ int i;
+ for(i = 0; i < num_mon; i++) {
+ Sprite m = gen_sprite(dungeon,'m' , -1, -1, 1);
+ m.sn = i;
+ add_sprite(dungeon, m);
+ }
+
+ map_dungeon_nont(dungeon);
+ map_dungeon_t(dungeon);
+ /*** dungeon is fully generated ***/
+
+ //binheap_t h;
+ //binheap_init(&h, compare_move, NULL);
+
+ /* main loop */
+ //Event nexts[dungeon->ns]
+
+ if(regen == TRUE) {
+ int px = dungeon->ss[0].p.x;
+ int py = dungeon->ss[0].p.y;
+ dungeon->ss[0] = p_pc;
+ dungeon->ss[0].p.x = px;
+ dungeon->ss[0].p.y = py;
+ dungeon->ss[0].to.x = px;
+ dungeon->ss[0].to.y = py;
+ }
+
+
+ for(i = 1; i < dungeon->ns; i++) {
+ gen_move_sprite(dungeon, i);
+ //nexts[i] = next;
+ }
+
+ if(regen == TRUE)
+ goto PNC;
+
+ /* ncurses or not ;; this will likely amount to nothing */
+ void (*printer)(Dungeon*, int, int);
+ if(nnc == FALSE) {
+ printer = &print_dungeon;
+ initscr();
+ raw();
+ noecho();
+ curs_set(0);
+ set_escdelay(25);
+ keypad(stdscr, TRUE);
+ } else {
+ printer = &print_dungeon_nnc;
+ }
+
+ PNC: ;
+ regen = FALSE;
+
+ print_dungeon(dungeon, 0, 0);
+ Bool first = TRUE;
+ Bool run = TRUE;
+ while(run == TRUE) {
+ //int32_t key;
+ //key = getch();
+
+ int l = 0;
+ for(i = 0; i < dungeon->ns; i++) {
+ if(dungeon->ss[i].t < dungeon->ss[l].t) {
+ l = i;
+ }
+ }
+
+
+ if(l == dungeon->pc || first == TRUE) {
+ parse_pc(dungeon, &run, ®en);
+ if(regen == TRUE) {
+ p_pc = dungeon->ss[0];
+ goto DUNFREE;
+ }
+
+ //gen_move_sprite(dungeon, l);
+ map_dungeon_nont(dungeon);
+ map_dungeon_t(dungeon);
+
+ int sn = 0;
+ for(i = 1; i < dungeon->ns; i++) {
+ if(i != sn) {
+ if((dungeon->ss[i].p.x == dungeon->ss[sn].p.x) && (dungeon->ss[i].p.y == dungeon->ss[sn].p.y) && dungeon->ss[sn].a == TRUE)
+ dungeon->ss[i].a = FALSE;
+ }
+ }
+
+ print_dungeon(dungeon, 0, 0);
+ } else {
+ parse_move(dungeon, l);
+ gen_move_sprite(dungeon, l);
+ }
+
+
+ //print_dungeon(dungeon, 1, 0); /* prints non-tunneling dijkstra's */
+ //print_dungeon(dungeon, 0, 1); /* prints tunneling dijkstra's */
+
+ //clear();
+ refresh();
+ /** --- game over sequence checking --- **/
+ /* note: this will stop the game before the new world gets drawn since the monster will move to the player and thus kill him */
+ if(dungeon->go == TRUE || dungeon->ss[dungeon->pc].a == FALSE)
+ break;
+
+ Bool any = check_any_monsters(dungeon);
+ if(any == FALSE) {
+ //printf("You win!\n");
+ goto END;
+ }
+ first = FALSE;
+ }
+ printer(dungeon, 0, 0);
+ //printf("Game Over!\n");
+
+ /*** tear down sequence ***/
+ //binheap_delete(&h);
+ END: ;
+ delwin(stdscr);
+ endwin();
+
+ if(saving == TRUE) {
+ write_dungeon(dungeon, path);
+ }
+
+ DUNFREE: ;
+ /* free our arrays */
+ for(i = 0; i < dungeon->h; i++) {
+ free(dungeon->d[i]);
+ }
+ free(dungeon->d);
+ for(i = 0; i < dungeon->h; i++) {
+ free(dungeon->p[i]);
+ }
+ free(dungeon->p);
+ free(dungeon->r);
+ free(dungeon->ss);
+ for(i = 0; i < dungeon->h; i++) {
+ free(dungeon->csnt[i]);
+ }
+ free(dungeon->csnt);
+ for(i = 0; i < dungeon->h; i++) {
+ free(dungeon->cst[i]);
+ }
+ free(dungeon->cst);
+
+ if(regen == TRUE)
+ goto DUNGEN;
+
+ free(path);
+ return 0;
+}
--- /dev/null
+++ b/demo/monsters.c
@@ -1,0 +1,476 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "dungeon_generator.h"
+#include "binheap.h"
+
+/* check if we can move to a location (objectively) */
+Bool test_loc(Dungeon * dungeon, int x, int y, Sprite *s) {
+ if(x > 0 && x < dungeon->w-1 && y > 0 && y < dungeon->h-1) {
+ int hard = dungeon->d[y][x].h;
+ if(dungeon->d[y][x].h < 255) {
+ if(s->s.tu == FALSE && hard > 0)
+ return FALSE;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* checks if a given sprite shares a room with the PC */
+void with_pc(Dungeon * dungeon, Sprite * s, Bool *in) {
+ int pc_rid = -1;
+ int s_rid = -1;
+ Sprite *pc = &(dungeon->ss[dungeon->pc]);
+
+ int i;
+ for(i = 0; i < dungeon->nr; i++) {
+ if(s->p.x <= dungeon->r[i].br.x && s->p.y <= dungeon->r[i].br.y && s->p.x >= dungeon->r[i].tl.x && s->p.y >= dungeon->r[i].tl.y) {
+ s_rid = i;
+ }
+ if(pc->p.x <= dungeon->r[i].br.x && pc->p.y <= dungeon->r[i].br.y && pc->p.x >= dungeon->r[i].tl.x && pc->p.y >= dungeon->r[i].tl.y) {
+ pc_rid = i;
+ }
+ }
+ if(pc_rid > 0 && s_rid > 0 && pc_rid == s_rid)
+ *in = TRUE;
+}
+
+void gen_move_sprite(Dungeon * dungeon, int sn) {
+ //make ss[sn] when possible
+ int sx = dungeon->ss[sn].p.x;
+ int sy = dungeon->ss[sn].p.y;
+ int xs[8] = {-1,0,1,1,1,0,-1,-1};
+ int ys[8] = {-1,-1,-1,0,1,1,1,0};
+
+ Sprite *s = &(dungeon->ss[sn]);
+
+ /* increment the turn */
+ dungeon->ss[sn].t += (100 / s->s.s);
+
+ Position new = {-1, -1};
+
+ dungeon->d[s->p.y][s->p.x].h -= 85;
+ if(dungeon->d[s->p.y][s->p.x].h < 0)
+ dungeon->d[s->p.y][s->p.x].h = 0;
+
+ // make sure we're alive
+ if(s->a == TRUE) {
+ int i;
+ int j;
+ int eb = rand() % 2; /* we have a 50% chance to behave erratically */
+ for(i = 0; i < 8; i++) {
+ int px = sx + xs[i];
+ int py = sy + ys[i];
+
+ if(px >= 0 && px < dungeon->w && py >= 0 && py < dungeon->h) {
+ /* drunken PC movement as per assignment 1.04 */
+
+ /* check erratic behaviour */
+ if(s->s.eb == FALSE || (s->s.eb == TRUE && eb)) {
+ /** check if intelligent / telepathic **/
+ //new.x = sx;
+ //new.y = sy;
+ if(s->s.te == FALSE) {
+ /* see if you're in the same room */
+ Bool in_room = FALSE;
+ with_pc(dungeon, s, &in_room);
+ if(in_room == TRUE) {
+ //cache PC location
+ s->pc = dungeon->ss[dungeon->pc].p;
+
+ IN: ;
+ if(s->s.in == TRUE) {
+ /* we are intelligent and can see our mark (tele or otherwise) */
+ int k;
+ int lowest = 0;
+ Bool set = FALSE;
+ if(s->s.tu) {
+ //tunneling
+ for(k = 0; k < 8; k++) {
+ if(xs[k]+sx >= 0 && xs[k]+sx < dungeon->w && ys[k]+sy >= 0 && ys[k]+sy < dungeon->h) {
+ if(dungeon->d[ys[k]+sy][xs[k]+sx].h < 255 && dungeon->cst[ys[k]+sy][xs[k]+sx] < dungeon->cst[ys[lowest]+sy][xs[lowest]+sx] && test_loc(dungeon, xs[k]+sx, ys[k]+sy, s) == TRUE && test_loc(dungeon, xs[lowest]+sx, ys[lowest]+sy, s) == TRUE) {
+ lowest = k;
+ set = TRUE;
+ }
+ }
+ }
+ } else {
+ //non-tunneling
+ for(k = 0; k < 8; k++) {
+ px = xs[k]+sx;
+ py = ys[k]+sy;
+ if(px >= 0 && px < dungeon->w && py >= 0 && py < dungeon->h) {
+ if(dungeon->d[py][px].h == 0 && dungeon->csnt[py][px] <= dungeon->csnt[ys[lowest]+sy][xs[lowest]+sx]) {
+ lowest = k;
+ set = TRUE;
+ }
+ }
+ }
+ /*
+ for(k = 0; k < 8; k++) {
+ if(xs[k]+sx >= 0 && xs[k]+sx < dungeon->w && ys[k]+sy >= 0 && ys[k]+sy < dungeon->h) {
+ if(dungeon->d[ys[k]+sy][xs[k]+sx].h < 255 && dungeon->csnt[ys[k]+sy][xs[k]+sx] < dungeon->csnt[ys[lowest]+sy][xs[lowest]+sx] && test_loc(dungeon, xs[k]+sx, ys[k]+sy, s) == TRUE && test_loc(dungeon, xs[lowest]+sx, ys[lowest]+sy, s) == TRUE) {
+ lowest = k;
+ set = TRUE;
+ }
+ }
+ }
+ */
+ }
+ if(set == TRUE) {
+ new.x = xs[lowest] + sx;
+ new.y = ys[lowest] + sy;
+ break;
+ } else {
+ new.x = sx;
+ new.y = sy;
+ break;
+ }
+
+ /*
+ if(test_loc(dungeon, px, py, s) == TRUE) {
+ //if we can move to the point
+ if(s->s.tu) {
+ //tunneling
+ if(new.x > 0 && new.y > 0 && new.x != sx && new.y != sy) {
+ if(dungeon->cst[py][px] < dungeon->cst[new.y][new.x]) {
+ new.x = px;
+ new.y = py;
+ }
+ } else {
+ new.x = px;
+ new.y = py;
+ }
+ } else {
+ //non-tunneling
+ if(new.x > 0 && new.y > 0 && new.x != sx && new.y != sy) {
+ if(dungeon->csnt[py][px] < dungeon->csnt[new.y][new.x]) {
+ new.x = px;
+ new.y = py;
+ }
+ } else {
+ new.x = px;
+ new.y = py;
+ }
+ }
+ }
+ */
+ } else {
+ //if not intelligent
+ if(s->pc.x < sx)
+ px = sx - 1;
+ if(s->pc.x > sx)
+ px = sx + 1;
+ if(s->pc.y < sy)
+ py = sy - 1;
+ if(s->pc.y > sy)
+ py = sy + 1;
+
+ if(test_loc(dungeon, px, py, s) == TRUE) {
+ new.x = px;
+ new.y = py;
+ break;
+ }
+ }
+ } else {
+ //not in the same room and not telepathic
+ //randomize
+ goto PCEB;
+ }
+ } else {
+ //we know where the PC is
+ s->pc = dungeon->ss[dungeon->pc].p;
+ /**
+ intelligence test still applies
+ we just treat it as if we're always in the room " "
+ **/
+ goto IN;
+ }
+
+ //printf("%c in room? %d\n",s->c , in_room);
+ } else {
+ /* we are erratically behaving */
+ PCEB: ;
+ j = 0;
+ EB: ;
+ int c = rand() % 9;
+ px = xs[c] + sx;
+ py = ys[c] + sy;
+ /* try to find a place to go up to n times */
+ if(test_loc(dungeon, px, py, s) == FALSE && j < 8) {
+ j++;
+ goto EB;
+ }
+ if(test_loc(dungeon, px, py, s) == TRUE) {
+ /* if the location is okay, commit it*/
+ new.x = px;
+ new.y = py;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ /* safety net */
+ if(new.x < 0)
+ new.x = sx;
+ if(new.y < 0)
+ new.y = sy;
+
+ dungeon->ss[sn].to.x = new.x;
+ dungeon->ss[sn].to.y = new.y;
+
+ if(new.x == dungeon->ss[dungeon->pc].p.x && new.y == dungeon->ss[dungeon->pc].p.y)
+ dungeon->go = TRUE;
+
+ /* check if we have to kill another sprite */
+ int i;
+ for(i = 0; i < dungeon->ns; i++) {
+ if(i != sn) {
+ if((dungeon->ss[i].to.x == dungeon->ss[sn].to.x) && (dungeon->ss[i].to.y == dungeon->ss[sn].to.y) && dungeon->ss[sn].a == TRUE)
+ dungeon->ss[i].a = FALSE;
+ /*
+ else if(dungeon->ss[i].p.x == dungeon->ss[sn].p.x && dungeon->ss[i].p.y == dungeon->ss[sn].p.y && dungeon->ss[i].a == TRUE)
+ dungeon->ss[sn].a = FALSE;
+ */
+ }
+ }
+}
+
+/* parse and apply a movement */
+void parse_move(Dungeon * dungeon, int sn) {
+ dungeon->ss[sn].p.x = dungeon->ss[sn].to.x;
+ dungeon->ss[sn].p.y = dungeon->ss[sn].to.y;
+}
+
+/* move a sprite following its built in rules */
+Event gen_move_sprite_old(Dungeon * dungeon, int sn) {
+ Event e;
+
+ int xs[8] = {-1,0,1,1,1,0,-1,-1};
+ int ys[8] = {-1,-1,-1,0,1,1,1,0};
+
+ int sx = dungeon->ss[sn].p.x;
+ int sy = dungeon->ss[sn].p.y;
+ Sprite s = dungeon->ss[sn];
+ int qp = -1;
+
+ /* increment the turn */
+ dungeon->ss[sn].t += (100 / s.s.s);
+
+ int i;
+ for(i = 0; i < 8; i++) {
+ int x = sx + xs[i];
+ int y = sy + ys[i];
+ if(x > 0 && x < dungeon->w-1 && y > 0 && y < dungeon->h-1) {
+ int hard = dungeon->d[y][x].h;
+ if(hard < 255) {
+ /* check for erratic behaviour */
+ if(s.s.eb == TRUE) {
+ int b = rand() % 2;
+ if(b) {
+ goto RP;
+ }
+ }
+
+ /* check if tunneling */
+ if(hard > 0 && s.s.tu == FALSE) {
+ continue;
+ }
+
+
+ /* check for line of sight / telepathic */
+ if(s.s.te == FALSE) {
+ /* if line of sight ;; path and cache -> exit ;; else go to RP ; */
+ if(dungeon->d[y][x].c == '.') {
+
+ } else {
+ goto RP;
+ }
+
+ } else {
+ /* path direct to PC if possible */
+ Sprite pc = dungeon->ss[dungeon->pc];
+ if(sx < pc.p.x)
+ x = sx + 1;
+ if(sx > pc.p.x)
+ x = sx - 1;
+ if(sy < pc.p.y)
+ y = sy + 1;
+ if(sy > pc.p.y)
+ y = sy - 1;
+
+ }
+
+
+ /* check for lowest if intelligent */
+ if(s.s.in == TRUE) {
+ if(s.s.tu == TRUE) {
+ if(dungeon->cst[ys[qp]+sy][xs[qp]+sx] > dungeon->cst[y][x] || qp == -1) {
+ qp = i;
+ }
+ } else {
+ if(dungeon->csnt[ys[qp]+sy][xs[qp]+sx] > dungeon->csnt[y][x] || qp == -1) {
+ qp = i;
+ }
+ }
+ } else {
+ RP: ;
+ qp = rand() % 9;
+ break;
+ }
+
+ }
+ }
+ }
+ return e;
+}
+
+/* add a sprite to the dungeon */
+void add_sprite(Dungeon * dungeon, Sprite s) {
+ if(dungeon->ns < dungeon->ms) {
+ dungeon->ns++;
+ } else {
+ goto END;
+ }
+
+ if(s.c == '@') {
+ dungeon->pc = dungeon->ns - 1;
+ }
+
+ dungeon->ss[dungeon->ns - 1] = s;
+
+ END: ;
+}
+
+/*
+generate a sprite, because in-line structs are icky
+if r(oom) = 1 then x and y will be ignored and should be passed as -1 as such (normally meaning random)
+*/
+Sprite gen_sprite(Dungeon * dungeon, char c, int x, int y, int r) {
+ Sprite s;
+
+ s.c = c;
+ s.a = TRUE;
+
+ /* set stats */
+ if(s.c == '@') {
+ s.s.s = 10;
+ s.s.tu = FALSE;
+ s.s.eb = FALSE;
+ s.s.te = FALSE;
+ s.s.in = FALSE;
+ } else {
+ /* if not the pc a value 5-20 */
+ s.s.s = (rand() % 16) + 5;
+ /* generate stats */
+ s.s.in = rand() % 2;
+ s.s.te = rand() % 2;
+ s.s.tu = rand() % 2;
+ s.s.eb = rand() % 2;
+
+ /* set character as per assignment 4 */
+ if(s.s.in == FALSE && s.s.te == FALSE && s.s.tu == FALSE && s.s.eb == FALSE)
+ s.c = '0';
+ else if(s.s.in == FALSE && s.s.te == FALSE && s.s.tu == FALSE && s.s.eb == TRUE)
+ s.c = '1';
+ else if(s.s.in == FALSE && s.s.te == FALSE && s.s.tu == TRUE && s.s.eb == FALSE)
+ s.c = '2';
+ else if(s.s.in == FALSE && s.s.te == FALSE && s.s.tu == TRUE && s.s.eb == TRUE)
+ s.c = '3';
+ else if(s.s.in == FALSE && s.s.te == TRUE && s.s.tu == FALSE && s.s.eb == FALSE)
+ s.c = '4';
+ else if(s.s.in == FALSE && s.s.te == TRUE && s.s.tu == FALSE && s.s.eb == TRUE)
+ s.c = '5';
+ else if(s.s.in == FALSE && s.s.te == TRUE && s.s.tu == TRUE && s.s.eb == FALSE)
+ s.c = '6';
+ else if(s.s.in == FALSE && s.s.te == TRUE && s.s.tu == TRUE && s.s.eb == TRUE)
+ s.c = '7';
+ else if(s.s.in == TRUE && s.s.te == FALSE && s.s.tu == FALSE && s.s.eb == FALSE)
+ s.c = '8';
+ else if(s.s.in == TRUE && s.s.te == FALSE && s.s.tu == FALSE && s.s.eb == TRUE)
+ s.c = '9';
+ else if(s.s.in == TRUE && s.s.te == FALSE && s.s.tu == TRUE && s.s.eb == FALSE)
+ s.c = 'a';
+ else if(s.s.in == TRUE && s.s.te == FALSE && s.s.tu == TRUE && s.s.eb == TRUE)
+ s.c = 'b';
+ else if(s.s.in == TRUE && s.s.te == TRUE && s.s.tu == FALSE && s.s.eb == FALSE)
+ s.c = 'c';
+ else if(s.s.in == TRUE && s.s.te == TRUE && s.s.tu == FALSE && s.s.eb == TRUE)
+ s.c = 'd';
+ else if(s.s.in == TRUE && s.s.te == TRUE && s.s.tu == TRUE && s.s.eb == FALSE)
+ s.c = 'e';
+ else if(s.s.in == TRUE && s.s.te == TRUE && s.s.tu == TRUE && s.s.eb == TRUE)
+ s.c = 'f';
+ }
+
+ /* put the tunneling monsters anywhere */
+ if(s.s.tu == TRUE) {
+ int t = 0;
+ PRT: ;
+ /* randomize location anywhere in the dungeon */
+ if(x < 0 || x > dungeon->w) {
+ x = (rand() % (dungeon->w-2)) + 1;
+ }
+ if(y < 0 || y > dungeon->h) {
+ y = (rand() % (dungeon->h-2)) + 1;
+ }
+
+ if(s.c != '@' && dungeon->nr > 1) {
+ s.p.x = x;
+ s.p.y = y;
+
+ Bool w_pc = FALSE;
+ with_pc(dungeon, &s, &w_pc);
+ if(w_pc == TRUE && t < 8) {
+ t++;
+ goto PRT;
+ }
+ }
+ }
+
+ /* place in a room if 1 or more. implicitly random ;; force in a room even if tunneling */
+ if(r > 0 || s.s.tu == FALSE) {
+ int t = 0;
+ PRNT: ;
+ int r_id = rand() % dungeon->nr;
+ x = (rand() % dungeon->r[r_id].w) + dungeon->r[r_id].tl.x;
+ y = (rand() % dungeon->r[r_id].h) + dungeon->r[r_id].tl.y;
+
+ if(s.c != '@' && dungeon->nr > 1) {
+ s.p.x = x;
+ s.p.y = y;
+
+ Bool w_pc = FALSE;
+ with_pc(dungeon, &s, &w_pc);
+ if(w_pc == TRUE && t < 8) {
+ t++;
+ goto PRNT;
+ }
+ }
+ } else {
+
+ }
+
+ s.p.x = x;
+ s.p.y = y;
+ s.to.x = x;
+ s.to.y = y;
+ //s.t = 100/s.s.s;
+ s.t = 0;
+
+ return s;
+}
+
+/* checks if any monsters other than the player are alive */
+Bool check_any_monsters(Dungeon * dungeon) {
+ int i;
+ for(i = 0; i < dungeon->ns; i++) {
+ if(dungeon->ss[i].a == TRUE && i != 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
--- /dev/null
+++ b/demo/printing.c
@@ -1,0 +1,222 @@
+#include <stdio.h>
+#include "endian.h"
+#include "/sys/include/9curses.h"
+#include "dungeon_generator.h"
+
+
+/* print hardness */
+void print_hardness(Dungeon * dungeon) {
+}
+
+/* prints heatmap */
+void print_t_heatmap(Dungeon * dungeon) {
+ int i;
+ int j;
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ int c = dungeon->cst[i][j];
+ if(c >= 0 && c < 10) {
+ printf("%d", c);
+ } else if(c >= 10 && c < 36) {
+ printf("%c", 'a' + (c - 10));
+ } else if(c >= 36 && c < 62) {
+ printf("%c", 'A' + (c - 36));
+ } else {
+ printf("%c", dungeon->d[i][j].c);
+ }
+ }
+ printf("\n");
+ }
+
+}
+
+/* prints heatmap */
+void print_nont_heatmap(Dungeon * dungeon) {
+ int i;
+ int j;
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ int c = dungeon->csnt[i][j];
+ if(c >= 0 && c < 10) {
+ printf("%d", c);
+ } else if(c >= 10 && c < 36) {
+ printf("%c", 'a' + (c - 10));
+ } else if(c >= 36 && c < 62) {
+ printf("%c", 'A' + (c - 36));
+ } else {
+ printf("%c", dungeon->d[i][j].c);
+ }
+ }
+ printf("\n");
+ }
+
+}
+
+/* prints the dungeon */
+void print_dungeon(Dungeon * dungeon, int nt, int t) {
+ clear();
+
+ int i;
+ int j;
+ int h;
+
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ dungeon->p[i][j].c = ' ';
+ }
+ }
+
+ /* add corridors to the print buffer */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ if(dungeon->d[i][j].p == 1 || dungeon->d[i][j].c == '#' || dungeon->d[i][j].h == 0) {
+ dungeon->p[i][j].c = '#';
+ }
+ }
+ }
+
+ /* add rooms to the print buffer */
+ for(h = 0; h < dungeon->nr; h++) {
+ for(i = dungeon->r[h].tl.y; i < dungeon->r[h].br.y+1; i++) {
+ for(j = dungeon->r[h].tl.x; j < dungeon->r[h].br.x+1; j++) {
+ dungeon->p[i][j].c = '.';
+ }
+ }
+ }
+
+ dungeon->p[dungeon->su.y][dungeon->su.x].c = '<';
+ dungeon->p[dungeon->sd.y][dungeon->sd.x].c = '>';
+
+ /* add sprites to the print buffer */
+ for(i = 0; i < dungeon->ns; i++) {
+ //printf("%d, %d: %c speed: %d turn: %d\n", dungeon->ss[i].p.y, dungeon->ss[i].p.x, dungeon->ss[i].c, dungeon->ss[i].s.s, dungeon->ss[i].t);
+ if(dungeon->ss[i].a == TRUE)
+ dungeon->p[dungeon->ss[i].p.y][dungeon->ss[i].p.x].c = dungeon->ss[i].c;
+ }
+
+ /* print non-tunnelling dijkstra's */
+ if(nt > 0) {
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ if(dungeon->d[i][j].h == 0) {
+ int c = dungeon->csnt[i][j];
+ if(c >= 0 && c < 10) {
+ dungeon->p[i][j].c = '0' + c;
+ } else if(c >= 10 && c < 36) {
+ dungeon->p[i][j].c = 'a' + (c - 10);
+ } else if(c >= 36 && c < 62) {
+ dungeon->p[i][j].c = 'A' + (c - 36);
+ }
+ }
+ }
+ }
+ }
+
+ /* print tunnelling dijkstra's */
+ if(t > 0) {
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ int c = dungeon->cst[i][j];
+ if(c >= 0 && c < 10) {
+ dungeon->p[i][j].c = '0' + c;
+ } else if(c >= 10 && c < 36) {
+ dungeon->p[i][j].c = 'a' + (c - 10);
+ } else if(c >= 36 && c < 62) {
+ dungeon->p[i][j].c = 'A' + (c - 36);
+ }
+ }
+ }
+ }
+
+ /* print the print buffer */
+ for(i = 0; i < dungeon->h; i++) {
+ int j;
+ for(j = 0; j < dungeon->w; j++) {
+ //printf("%c", (dungeon->p[i][j]).c);
+ mvaddch(i+1, j, (dungeon->p[i][j]).c);
+ }
+ }
+ //clear();
+ refresh();
+}
+
+/* prints the dungeon */
+void print_dungeon_nnc(Dungeon * dungeon, int nt, int t) {
+ int i;
+ int j;
+ int h;
+
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ dungeon->p[i][j].c = ' ';
+ }
+ }
+
+ /* add corridors to the print buffer */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ if(dungeon->d[i][j].p == 1 || dungeon->d[i][j].c == '#' || dungeon->d[i][j].h == 0) {
+ dungeon->p[i][j].c = '#';
+ }
+ }
+ }
+
+ /* add rooms to the print buffer */
+ for(h = 0; h < dungeon->nr; h++) {
+ for(i = dungeon->r[h].tl.y; i < dungeon->r[h].br.y+1; i++) {
+ for(j = dungeon->r[h].tl.x; j < dungeon->r[h].br.x+1; j++) {
+ dungeon->p[i][j].c = '.';
+ }
+ }
+ }
+
+ /* add sprites to the print buffer */
+ for(i = 0; i < dungeon->ns; i++) {
+ //printf("%d, %d: %c speed: %d turn: %d\n", dungeon->ss[i].p.y, dungeon->ss[i].p.x, dungeon->ss[i].c, dungeon->ss[i].s.s, dungeon->ss[i].t);
+ if(dungeon->ss[i].a == TRUE)
+ dungeon->p[dungeon->ss[i].p.y][dungeon->ss[i].p.x].c = dungeon->ss[i].c;
+ }
+
+ /* print non-tunnelling dijkstra's */
+ if(nt > 0) {
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ if(dungeon->d[i][j].h == 0) {
+ int c = dungeon->csnt[i][j];
+ if(c >= 0 && c < 10) {
+ dungeon->p[i][j].c = '0' + c;
+ } else if(c >= 10 && c < 36) {
+ dungeon->p[i][j].c = 'a' + (c - 10);
+ } else if(c >= 36 && c < 62) {
+ dungeon->p[i][j].c = 'A' + (c - 36);
+ }
+ }
+ }
+ }
+ }
+
+ /* print tunnelling dijkstra's */
+ if(t > 0) {
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ int c = dungeon->cst[i][j];
+ if(c >= 0 && c < 10) {
+ dungeon->p[i][j].c = '0' + c;
+ } else if(c >= 10 && c < 36) {
+ dungeon->p[i][j].c = 'a' + (c - 10);
+ } else if(c >= 36 && c < 62) {
+ dungeon->p[i][j].c = 'A' + (c - 36);
+ }
+ }
+ }
+ }
+
+ /* print the print buffer */
+ for(i = 0; i < dungeon->h; i++) {
+ int j;
+ for(j = 0; j < dungeon->w; j++) {
+ printf("%c", (dungeon->p[i][j]).c);
+ }
+ printf("\n");
+ }
+}
--- /dev/null
+++ b/demo/world.c
@@ -1,0 +1,362 @@
+#include <stdlib.h>
+#include <math.h>
+#include "dungeon_generator.h"
+
+
+/* (attempt to) place a room within a given dungeon */
+int place_room(Dungeon * dungeon) {
+ int x = (rand() % (dungeon->w-1)) +1;
+ int y = (rand() % (dungeon->h-1)) +1;
+ Room new_room;
+ /*
+ set top right to rng number; might be worth making a more detailed placer with a lower
+ fail rate
+ */
+ new_room.tl.x = x;
+ new_room.tl.y = y;
+ /* for RNG, maybe do a rando room width/height and re-set .br */
+
+ HW: ;
+
+ int we = (rand() % 4) + 4; /* width, expanded, up to 4 more */
+ int he = (rand() % 4) + 3; /* height, expanded, up to 4 more */
+
+ if(we == he) {
+ /* if we have a square, re-generate */
+ goto HW;
+ }
+
+ new_room.h = he;
+ new_room.w = we;
+
+ new_room.br.x = x + new_room.w-1;
+ new_room.br.y = y + new_room.h-1;
+
+ /* check for rooms loaded into the dungeon buffer already */
+ int i;
+ int j;
+ int placed = -1;
+ int passed = 0;
+ for(i = y; i < dungeon->h-1 && i < y+he; i++) {
+ for(j = x; j < dungeon->w-1 && j < x+we; j++) {
+ if(dungeon->p[i][j].c != '.') {
+ passed++;
+ }
+ }
+ }
+
+ /* return a failure if not all cells within the "Room" passed */
+ if(passed < we*he) {
+ return placed; /* should be -1 */
+ }
+
+ /* return a failure if part of the room is out of bounds */
+ if(new_room.br.x >= dungeon->w || new_room.br.y >= dungeon->h) {
+ return placed;
+ }
+
+
+ /* check for surrounding rooms */
+
+ /* top row */
+ for(i = new_room.tl.x-1; i < new_room.br.x+2 && new_room.tl.x-1 >= 0 && new_room.br.x+1 < dungeon->w && new_room.tl.y-1 >= 0; i++) {
+ if((dungeon->p[new_room.tl.y-1][i]).c == '.') {
+ return placed;
+ }
+ }
+
+ /* bottom row */
+ for(i = new_room.tl.x-1; i < new_room.br.x+2 && new_room.tl.x-1 >= 0 && new_room.br.x+1 < dungeon->w && new_room.br.y+1 < dungeon->h; i++) {
+ if((dungeon->p[new_room.br.y+1][i]).c == '.') {
+ return placed;
+ }
+ }
+
+ /* left side */
+ for(i = new_room.tl.y; i < new_room.br.y+1 && new_room.br.y+1 < dungeon->h && new_room.tl.x-1 >= 0; i++) {
+ if((dungeon->p[i][new_room.tl.x-1]).c == '.') {
+ return placed;
+ }
+ }
+
+ /* right side */
+ for(i = new_room.tl.y; i < new_room.br.y+1 && new_room.br.y+1 < dungeon->h && new_room.br.x+1 < dungeon->w; i++) {
+ if((dungeon->p[i][new_room.br.x+1]).c == '.') {
+ return placed;
+ }
+ }
+
+
+ /* successful placement */
+ placed = 0;
+
+ /* fill the room into the dungeon buffer and add to room array */
+ for(i = y; i < y+he; i++) {
+ for(j = x; j < x+we; j++) {
+ dungeon->p[i][j].c = '.';
+ dungeon->d[i][j].h = 0;
+ }
+ }
+
+
+ if(dungeon->nr < dungeon->mr) {
+ dungeon->nr++;
+ new_room.id = dungeon->nr-1; /* reflects position in the array */
+ new_room.ctr.x = (new_room.w)/2 + new_room.tl.x;
+ new_room.ctr.y = (new_room.h)/2 + new_room.tl.y;
+ /* printf("%d: (%d, %d)\n", new_room.id, new_room.ctr.x, new_room.ctr.y); */
+ dungeon->r[dungeon->nr-1] = new_room;
+ } else {
+ return -1;
+ }
+
+
+ return placed;
+}
+
+/* assistant function for gen_corridors() to check if all rooms are connected */
+int all_connected(int * cnxns, Dungeon * dungeon) {
+ int i;
+
+ for(i = 0; i < dungeon->nr; i++) {
+ if(cnxns[i] != 1 || dungeon->r[i].c != TRUE) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* generates and marks corridors */
+void gen_corridors(Dungeon * dungeon) {
+ int i;
+ //int connected[dungeon->nr];
+ int *connected = calloc(dungeon->nr, 1);
+ for(i = 0; i < dungeon->nr; i++) {
+ connected[i] = 0;
+ }
+ //memset(connected, 0, dungeon->nr * sizeof(int));
+ //double dists[dungeon->nr];
+ double *dists = calloc(dungeon->nr, 1);
+ for(i = 0; i < dungeon->nr; i++) {
+ dists[i] = 0;
+ }
+ //memset(dists, 0.0, dungeon->nr * sizeof(double));
+ int max_paths = dungeon->nr * 3;
+ //Path paths[max_paths]; /* max paths is 3 * number of rooms */
+ Path *paths = calloc(max_paths, 1);
+ int path_cnt = 0;
+ int room_pos = 0; /* current room in use */
+
+ for(i = 0; i < dungeon->nr; i++) {
+ dists[i] = -1; /* infinite at -1 */
+ }
+ dists[0] = 0;
+
+ /* ensure all rooms are disconnected */
+ for(i = 0; i < dungeon->nr; i++) {
+ dungeon->r[i].c = FALSE;
+ }
+
+ /* primary loop, goal is to connect all rooms; 0 means true */
+ while(all_connected(connected, dungeon) == FALSE && path_cnt < max_paths) {
+ int i;
+ double d;
+ Path new_path;
+
+ /* populate dists from the current position */
+ for(i = 0; i < dungeon->nr; i++) {
+ /* calculate distance */
+ d = sqrt(pow(dungeon->r[i].ctr.x - dungeon->r[room_pos].ctr.x, 2) + pow(dungeon->r[i].ctr.y - dungeon->r[room_pos].ctr.y, 2));
+ dists[i] = d;
+ }
+
+ /* find the room to path to ;; if not connected already and the distance is shorter and isn't our current position */
+
+ int next = -1;
+ for(i = 0; i < dungeon->nr; i++) {
+ if(connected[i] != 1 && next == -1 && room_pos != i) {
+ next = i;
+ } else if(connected[i] != 1 && dists[i] < dists[next] && room_pos != i) {
+ next = i;
+ }
+ }
+
+ /** this would - in the future - be the point of adding extraneous paths **/
+ if(next != -1) {
+ dungeon->r[room_pos].c = TRUE;
+ dungeon->r[next].c = TRUE;
+ connected[room_pos] = 1;
+ new_path.prev = room_pos;
+ new_path.next = next;
+ paths[path_cnt] = new_path;
+ room_pos = next;
+ path_cnt++;
+ } else {
+ break;
+ }
+
+ }
+
+ /* populate the dungeon grid (draw the paths using x/y chasing/pathing) */
+
+ /* draw dungeon paths in the dungeon grid; start at room 0 as per above */
+
+ for(i = 0; i < path_cnt; i++) {
+ int x = dungeon->r[paths[i].prev].ctr.x;
+ int y = dungeon->r[paths[i].prev].ctr.y;
+
+ /*printf("%d: (%d, %d)\n", i, x, y);*/
+
+ while(x != dungeon->r[paths[i].next].ctr.x || y != dungeon->r[paths[i].next].ctr.y) {
+ int dirx = 0; /* -1 for left, 1 for right */
+ int diry = 0; /* -1 for down, 1 for up */
+
+ if(x < dungeon->r[paths[i].next].ctr.x) {
+ dirx = 1;
+ } else if(x > dungeon->r[paths[i].next].ctr.x) {
+ dirx = -1;
+ }
+
+ if(y < dungeon->r[paths[i].next].ctr.y) {
+ diry = 1;
+ } else if(y > dungeon->r[paths[i].next].ctr.y) {
+ diry = -1;
+ }
+
+ dungeon->d[y][x].p = 1;
+ /* don't place corridors in rooms */
+ if(dungeon->d[y][x].c != '.') {
+ dungeon->d[y][x].c = '#';
+ dungeon->d[y][x].h = 0;
+ }
+
+ if(dirx == -1) {
+ x--;
+ } else if(dirx == 1) {
+ x++;
+ } else if(diry == -1) {
+ y--;
+ } else if(diry == 1) {
+ y++;
+ }
+ }
+
+ }
+
+}
+
+/* generate a blank dungeon */
+void gen_dungeon(Dungeon * dungeon) {
+ /*** top 3 (0, 1, 2) are reserved for the pseudo-HUD ***/
+ int i, j;
+
+ /* set all slots to spaces originally */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ (dungeon->d[i][j]).c = ' '; /* all basic rooms are spaces */
+ int h = (rand() % 254) + 1;
+ (dungeon->d[i][j]).h = h;
+ }
+ }
+
+ /* immut-ify the outside rim */
+ for(i = 0; i < dungeon->w; i++) {
+ (dungeon->d[0][i]).h = 255;
+ }
+ for(i = 0; i < dungeon->w; i++) {
+ (dungeon->d[dungeon->h-1][i]).h = 255;
+ }
+ for(i = 0; i < dungeon->h; i++) {
+ (dungeon->d[i][0]).h = 255;
+ }
+ for(i = 0; i < dungeon->h; i++) {
+ (dungeon->d[i][dungeon->w-1]).h = 255;
+ }
+
+ /* make p equal to d */
+ for(i = 0; i < dungeon->h; i++) {
+ for(j = 0; j < dungeon->w; j++) {
+ dungeon->p[i][j] = dungeon->d[i][j];
+ }
+ }
+
+ /* populate the rooms */
+ int cnt = 0;
+ int tst = 0;
+ for(i = 0; dungeon->nr < dungeon->mr && cnt < 2000; i++) {
+ tst = place_room(dungeon);
+ if(tst < 0) {
+ cnt++;
+ }
+ }
+
+ /* set the stairs */
+ int x;
+ int y;
+
+ int r_id = rand() % dungeon->nr;
+ x = (rand() % dungeon->r[r_id].w) + dungeon->r[r_id].tl.x;
+ y = (rand() % dungeon->r[r_id].h) + dungeon->r[r_id].tl.y;
+ dungeon->sd.x = x;
+ dungeon->sd.y = y;
+
+ SD: ;
+ r_id = rand() % dungeon->nr;
+ x = (rand() % dungeon->r[r_id].w) + dungeon->r[r_id].tl.x;
+ y = (rand() % dungeon->r[r_id].h) + dungeon->r[r_id].tl.y;
+ dungeon->su.x = x;
+ dungeon->su.y = y;
+
+ if(dungeon->su.x == dungeon->sd.x && dungeon->su.y == dungeon->sd.y)
+ goto SD;
+
+}
+
+/* initializes the dungeon structure */
+Dungeon* init_dungeon(int h, int w, int mr) {
+ Dungeon *new_dungeon = calloc(sizeof (Dungeon), 1);
+ new_dungeon->h = h;
+ new_dungeon->w = w;
+ new_dungeon->mr = mr;
+ new_dungeon->nr = 0;
+ new_dungeon->ns = 0;
+ new_dungeon->ms = w*h; /* max sprites would be 1 per dungeon slot */
+ new_dungeon->t = 0;
+ new_dungeon->go = FALSE;
+
+ /* dungeon buffer allocation+0'ing */
+ new_dungeon->d = calloc(new_dungeon->h, sizeof(Tile *));
+
+ int i;
+ for(i = 0; i < new_dungeon->h; i++) {
+ new_dungeon->d[i] = calloc(new_dungeon->w, sizeof(Tile));
+ }
+
+ /* dungeon visual buffer allocation+0'ing */
+ new_dungeon->p = calloc(new_dungeon->h, sizeof(Tile *));
+
+ for(i = 0; i < new_dungeon->h; i++) {
+ new_dungeon->p[i] = calloc(new_dungeon->w, sizeof(Tile));
+ }
+
+ /* rooms allocation+0'ing */
+ new_dungeon->r = calloc(new_dungeon->mr, sizeof(Room));
+
+ /* sprites allocation */
+ new_dungeon->ss = calloc(new_dungeon->ms, sizeof(Sprite));
+
+ /* djikstra-based cost map allocation */
+ new_dungeon->cst = calloc(w*h, sizeof(int *));
+ for(i = 0; i < new_dungeon->h; i++) {
+ new_dungeon->cst[i] = calloc(new_dungeon->w, sizeof(int));
+ }
+
+ /* djikstra-based cost map allocation */
+ new_dungeon->csnt = calloc(w*h, sizeof(int *));
+ for(i = 0; i < new_dungeon->h; i++) {
+ new_dungeon->csnt[i] = calloc(new_dungeon->w, sizeof(int));
+ }
+
+ return new_dungeon;
+}