diff xrogue/maze.c @ 133:e6179860cb76

Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 21 Apr 2015 08:55:20 -0400
parents
children f54901b9c39b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xrogue/maze.c	Tue Apr 21 08:55:20 2015 -0400
@@ -0,0 +1,385 @@
+/*
+    maze.c  -  functions for dealing with mazes
+    
+    XRogue: Expeditions into the Dungeons of Doom
+    Copyright (C) 1991 Robert Pietkivitch
+    All rights reserved.
+    
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <curses.h>
+#include "rogue.h"
+
+struct cell {
+        char y_pos;
+        char x_pos;
+};
+struct b_cellscells {
+        char num_pos;           /* number of frontier cells next to you */
+        struct cell conn[4];    /* the y,x position of above cell */
+} b_cells;
+
+static char     *maze_frontier, *maze_bits;
+static int      maze_lines, maze_cols;
+static char     *moffset(), *foffset();
+static int      rmwall(),findcells(),crankout(),draw_maze();
+
+/*
+ * crankout:
+ *      Does actual drawing of maze to window
+ */
+
+static
+crankout()
+{
+    reg int x, y;
+
+    for (y = 0; y < lines - 3; y++) {
+        move(y + 1, 0);
+        for (x = 0; x < cols - 1; x++) {
+            if (*moffset(y, x)) {           /* here is a wall */
+                if(y==0 || y==lines-4) /* top or bottom line */
+                    addch(HORZWALL);
+                else if(x==0 || x==cols-2) /* left | right side */
+                    addch(VERTWALL);
+                else if (y % 2 == 0 && x % 2 == 0) {
+                    if(*moffset(y, x-1) || *moffset(y, x+1))
+                        addch(HORZWALL);
+                    else
+                        addch(VERTWALL);
+                }
+                else if (y % 2 == 0)
+                    addch(HORZWALL);
+                else
+                    addch(VERTWALL);
+            }
+            else
+                addch(FLOOR);
+        }
+    }
+}
+
+/*
+ * domaze:
+ *      Draw the maze on this level.
+ */
+
+do_maze()
+{
+        reg int least;
+        reg struct room *rp;
+        reg struct linked_list *item;
+        reg struct object *obj;
+        int cnt;
+        bool treas;
+        coord tp;
+
+        for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) {
+                rp->r_flags = ISGONE;           /* kill all rooms */
+                rp->r_fires = NULL;             /* no fires */
+        }
+        rp = &rooms[0];                         /* point to only room */
+        rp->r_flags = ISDARK;                   /* mazes always dark */
+        rp->r_pos.x = 0;                        /* room fills whole screen */
+        rp->r_pos.y = 1;
+        rp->r_max.x = cols - 1;
+        rp->r_max.y = lines - 3;
+        draw_maze();                            /* put maze into window */
+        /*
+         * add some gold to make it worth looking for 
+         */
+        item = spec_item(GOLD, NULL, NULL, NULL);
+        obj = OBJPTR(item);
+        obj->o_count *= (rnd(50) + 50);         /* add in one large hunk */
+        attach(lvl_obj, item);
+        cnt = 0;
+        do {
+            rnd_pos(rp, &tp);
+        } until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 2500);
+        mvaddch(tp.y, tp.x, GOLD);
+        obj->o_pos = tp;
+        /*
+         * add in some food to make sure he has enough
+         */
+        item = spec_item(FOOD, NULL, NULL, NULL);
+        obj = OBJPTR(item);
+        attach(lvl_obj, item);
+        do {
+            rnd_pos(rp, &tp);
+        } until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 2500);
+        mvaddch(tp.y, tp.x, FOOD);
+        obj->o_pos = tp;
+
+        /* it doesn't mater if it's a treasure maze or a normal maze,
+         * more than enough monsters will be genned. 
+         */
+        least = rnd(11)+5;
+        if (least < 6) {
+        least = 7;
+        treas = FALSE;
+    }
+    else treas = TRUE;
+        genmonsters(least, treas);
+
+        /* sometimes they're real angry */
+        if (rnd(100) < 65) {
+            /* protect the good charactors */
+            if (player.t_ctype == C_PALADIN ||
+                player.t_ctype == C_RANGER  || player.t_ctype == C_MONK) {
+                aggravate(TRUE, FALSE);
+            }
+            else {
+                aggravate(TRUE, TRUE);
+            }
+        }
+}
+
+/*
+ * draw_maze:
+ *      Generate and draw the maze on the screen
+ */
+
+static
+draw_maze()
+{
+        reg int i, j, more;
+        reg char *ptr;
+
+        maze_lines = (lines - 3) / 2;
+        maze_cols = (cols - 1) / 2;
+        maze_bits = ALLOC((lines - 3) * (cols - 1));
+        maze_frontier = ALLOC(maze_lines * maze_cols);
+        ptr = maze_frontier;
+        while (ptr < (maze_frontier + (maze_lines * maze_cols)))
+                *ptr++ = TRUE;
+        for (i = 0; i < lines - 3; i++) {
+                for (j = 0; j < cols - 1; j++) {
+                        if (i % 2 == 1 && j % 2 == 1)
+                                *moffset(i, j) = FALSE;         /* floor */
+                        else
+                                *moffset(i, j) = TRUE;          /* wall */
+                }
+        }
+        for (i = 0; i < maze_lines; i++) {
+                for (j = 0; j < maze_cols; j++) {
+                        do
+                                more = findcells(i,j);
+                        while(more != 0);
+                }
+        }
+        crankout();
+        FREE(maze_frontier);
+        FREE(maze_bits);
+}
+
+/*
+ * findcells:
+ *      Figure out cells to open up 
+ */
+
+static findcells(y,x)
+reg int x, y;
+{
+        reg int rtpos, i;
+
+        *foffset(y, x) = FALSE;
+        b_cells.num_pos = 0;
+        if (y < maze_lines - 1) {                               /* look below */
+                if (*foffset(y + 1, x)) {
+                        b_cells.conn[b_cells.num_pos].y_pos = y + 1;
+                        b_cells.conn[b_cells.num_pos].x_pos = x;
+                        b_cells.num_pos += 1;
+                }
+        }
+        if (y > 0) {                                    /* look above */
+                if (*foffset(y - 1, x)) {
+                        b_cells.conn[b_cells.num_pos].y_pos = y - 1;
+                        b_cells.conn[b_cells.num_pos].x_pos = x;
+                        b_cells.num_pos += 1;
+
+                }
+        }
+        if (x < maze_cols - 1) {                                /* look right */
+                if (*foffset(y, x + 1)) {
+                        b_cells.conn[b_cells.num_pos].y_pos = y;
+                        b_cells.conn[b_cells.num_pos].x_pos = x + 1;
+                        b_cells.num_pos += 1;
+                }
+        }
+        if (x > 0) {                                    /* look left */
+                if (*foffset(y, x - 1)) {
+                        b_cells.conn[b_cells.num_pos].y_pos = y;
+                        b_cells.conn[b_cells.num_pos].x_pos = x - 1;
+                        b_cells.num_pos += 1;
+
+                }
+        }
+        if (b_cells.num_pos == 0)               /* no neighbors available */
+                return 0;
+        else {
+                i = rnd(b_cells.num_pos);
+                rtpos = b_cells.num_pos - 1;
+                rmwall(b_cells.conn[i].y_pos, b_cells.conn[i].x_pos, y, x);
+                return rtpos;
+        }
+}
+
+/*
+ * foffset:
+ *      Calculate memory address for frontier
+ */
+
+static char *
+foffset(y, x)
+int y, x;
+{
+
+        return (maze_frontier + (y * maze_cols) + x);
+}
+
+
+/*
+ * Maze_view:
+ *      Returns true if the player can see the specified location within
+ *      the confines of a maze (within one column or row)
+ */
+
+bool
+maze_view(y, x)
+int y, x;
+{
+    register int start, goal, delta, ycheck = 0, xcheck = 0, absy, absx, see_radius;
+    register bool row;
+
+    /* Get the absolute value of y and x differences */
+    absy = hero.y - y;
+    absx = hero.x - x;
+    if (absy < 0) absy = -absy;
+    if (absx < 0) absx = -absx;
+
+    /* If we are standing in a wall, we can see a bit more */
+    switch (winat(hero.y, hero.x)) {
+        case VERTWALL:
+        case HORZWALL:
+        case WALL:
+        case SECRETDOOR:
+        case DOOR:
+            see_radius = 2;
+        otherwise:
+            see_radius = 1;
+    }
+
+    /* Must be within one or two rows or columns */
+    if (absy > see_radius && absx > see_radius) return(FALSE);
+
+    if (absx > see_radius) {            /* Go along row */
+        start = hero.x;
+        goal = x;
+        ycheck = hero.y;
+        row = TRUE;
+    }
+    else {                      /* Go along column */
+        start = hero.y;
+        goal = y;
+        xcheck = hero.x;
+        row = FALSE;
+    }
+
+    if (start <= goal) delta = 1;
+    else delta = -1;
+
+    /* Start one past where we are standing */
+    if (start != goal) start += delta;
+
+    /* If we are in a wall, we want to look in the area outside the wall */
+    if (see_radius > 1) {
+        if (row) {
+            /* See if above us it okay first */
+            switch (winat(ycheck, start)) {
+                case VERTWALL:
+                case HORZWALL:
+                case WALL:
+                case DOOR:
+                case SECRETDOOR:
+                    /* No good, try one up */
+                    if (y > hero.y) ycheck++;
+                    else ycheck--;
+                otherwise:
+                    see_radius = 1;     /* Just look straight over the row */
+            }
+        }
+        else {
+            /* See if above us it okay first */
+            switch (winat(start, xcheck)) {
+                case VERTWALL:
+                case HORZWALL:
+                case WALL:
+                case DOOR:
+                case SECRETDOOR:
+                    /* No good, try one over */
+                    if (x > hero.x) xcheck++;
+                    else xcheck--;
+                otherwise:
+                    see_radius = 1;     /* Just look straight up the column */
+            }
+        }
+    }
+
+    /* Check boundary again */
+    if (absy > see_radius && absx > see_radius) return(FALSE);
+
+    while (start != goal) {
+        if (row) xcheck = start;
+        else     ycheck = start;
+
+        if (xcheck < 0 || ycheck < 0)
+            return FALSE;
+        switch (winat(ycheck, xcheck)) {
+            case VERTWALL:
+            case HORZWALL:
+            case WALL:
+            case DOOR:
+            case SECRETDOOR:
+                return(FALSE);
+        }
+        start += delta;
+    }
+    return(TRUE);
+}
+
+
+/*
+ * moffset:
+ *      Calculate memory address for bits
+ */
+
+static char *
+moffset(y, x)
+int y, x;
+{
+    return (maze_bits + (y * (cols - 1)) + x);
+}
+
+/*
+ * rmwall:
+ *      Removes appropriate walls from the maze
+ */
+static
+rmwall(newy, newx, oldy, oldx)
+int newy, newx, oldy, oldx;
+{
+        reg int xdif,ydif;
+        
+        xdif = newx - oldx;
+        ydif = newy - oldy;
+
+        *moffset((oldy * 2) + ydif + 1, (oldx * 2) + xdif + 1) = FALSE;
+        findcells(newy, newx);
+}
+