Annotation of early-roguelike/xrogue/maze.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: maze.c - functions for dealing with mazes
3:
4: XRogue: Expeditions into the Dungeons of Doom
5: Copyright (C) 1991 Robert Pietkivitch
6: All rights reserved.
7:
8: Based on "Advanced Rogue"
9: Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
10: All rights reserved.
11:
12: See the file LICENSE.TXT for full copyright and licensing information.
13: */
14:
15: #include <stdlib.h>
16: #include <curses.h>
17: #include "rogue.h"
18:
19: struct cell {
20: char y_pos;
21: char x_pos;
22: };
23: struct b_cellscells {
24: unsigned char num_pos; /* number of frontier cells next to you */
25: struct cell conn[4]; /* the y,x position of above cell */
26: } b_cells;
27:
28: static char *maze_frontier, *maze_bits;
29: static int maze_lines, maze_cols;
30: static char *moffset(int y, int x);
31: static char *foffset(int y, int x);
32: static void rmwall(int newy, int newx, int oldy, int oldx);
33: static void draw_maze(void);
34: static int findcells(int y, int x);
35:
36: /*
37: * crankout:
38: * Does actual drawing of maze to window
39: */
40:
41: static
42: void
43: crankout(void)
44: {
45: reg int x, y;
46:
47: for (y = 0; y < lines - 3; y++) {
48: move(y + 1, 0);
49: for (x = 0; x < cols - 1; x++) {
50: if (*moffset(y, x)) { /* here is a wall */
51: if(y==0 || y==lines-4) /* top or bottom line */
52: addch(HORZWALL);
53: else if(x==0 || x==cols-2) /* left | right side */
54: addch(VERTWALL);
55: else if (y % 2 == 0 && x % 2 == 0) {
56: if(*moffset(y, x-1) || *moffset(y, x+1))
57: addch(HORZWALL);
58: else
59: addch(VERTWALL);
60: }
61: else if (y % 2 == 0)
62: addch(HORZWALL);
63: else
64: addch(VERTWALL);
65: }
66: else
67: addch(FLOOR);
68: }
69: }
70: }
71:
72: /*
73: * domaze:
74: * Draw the maze on this level.
75: */
76:
77: void
78: do_maze(void)
79: {
80: reg int least;
81: reg struct room *rp;
82: reg struct linked_list *item;
83: reg struct object *obj;
84: int cnt;
85: bool treas;
86: coord tp;
87:
88: for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) {
89: rp->r_flags = ISGONE; /* kill all rooms */
90: rp->r_fires = NULL; /* no fires */
91: }
92: rp = &rooms[0]; /* point to only room */
93: rp->r_flags = ISDARK; /* mazes always dark */
94: rp->r_pos.x = 0; /* room fills whole screen */
95: rp->r_pos.y = 1;
96: rp->r_max.x = cols - 1;
97: rp->r_max.y = lines - 3;
98: draw_maze(); /* put maze into window */
99: /*
100: * add some gold to make it worth looking for
101: */
102: item = spec_item(GOLD, 0, 0, 0);
103: obj = OBJPTR(item);
104: obj->o_count *= (rnd(50) + 50); /* add in one large hunk */
105: attach(lvl_obj, item);
106: cnt = 0;
107: do {
108: rnd_pos(rp, &tp);
109: } until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 2500);
110: mvaddch(tp.y, tp.x, GOLD);
111: obj->o_pos = tp;
112: /*
113: * add in some food to make sure he has enough
114: */
115: item = spec_item(FOOD, 0, 0, 0);
116: obj = OBJPTR(item);
117: attach(lvl_obj, item);
118: do {
119: rnd_pos(rp, &tp);
120: } until (mvinch(tp.y, tp.x) == FLOOR || cnt++ > 2500);
121: mvaddch(tp.y, tp.x, FOOD);
122: obj->o_pos = tp;
123:
124: /* it doesn't mater if it's a treasure maze or a normal maze,
125: * more than enough monsters will be genned.
126: */
127: least = rnd(11)+5;
128: if (least < 6) {
129: least = 7;
130: treas = FALSE;
131: }
132: else treas = TRUE;
133: genmonsters(least, treas);
134:
135: /* sometimes they're real angry */
136: if (rnd(100) < 65) {
137: /* protect the good charactors */
138: if (player.t_ctype == C_PALADIN ||
139: player.t_ctype == C_RANGER || player.t_ctype == C_MONK) {
140: aggravate(TRUE, FALSE);
141: }
142: else {
143: aggravate(TRUE, TRUE);
144: }
145: }
146: }
147:
148: /*
149: * draw_maze:
150: * Generate and draw the maze on the screen
151: */
152:
153: static
154: void
155: draw_maze(void)
156: {
157: reg int i, j, more;
158: reg char *ptr;
159:
160: maze_lines = (lines - 3) / 2;
161: maze_cols = (cols - 1) / 2;
162: maze_bits = ALLOC((lines - 3) * (cols - 1));
163: maze_frontier = ALLOC(maze_lines * maze_cols);
164: ptr = maze_frontier;
165: while (ptr < (maze_frontier + (maze_lines * maze_cols)))
166: *ptr++ = TRUE;
167: for (i = 0; i < lines - 3; i++) {
168: for (j = 0; j < cols - 1; j++) {
169: if (i % 2 == 1 && j % 2 == 1)
170: *moffset(i, j) = FALSE; /* floor */
171: else
172: *moffset(i, j) = TRUE; /* wall */
173: }
174: }
175: for (i = 0; i < maze_lines; i++) {
176: for (j = 0; j < maze_cols; j++) {
177: do
178: more = findcells(i,j);
179: while(more != 0);
180: }
181: }
182: crankout();
183: FREE(maze_frontier);
184: FREE(maze_bits);
185: }
186:
187: /*
188: * findcells:
189: * Figure out cells to open up
190: */
191:
192: static int
193: findcells(int y, int x)
194: {
195: reg int rtpos, i;
196:
197: *foffset(y, x) = FALSE;
198: b_cells.num_pos = 0;
199: if (y < maze_lines - 1) { /* look below */
200: if (*foffset(y + 1, x)) {
201: b_cells.conn[b_cells.num_pos].y_pos = y + 1;
202: b_cells.conn[b_cells.num_pos].x_pos = x;
203: b_cells.num_pos += 1;
204: }
205: }
206: if (y > 0) { /* look above */
207: if (*foffset(y - 1, x)) {
208: b_cells.conn[b_cells.num_pos].y_pos = y - 1;
209: b_cells.conn[b_cells.num_pos].x_pos = x;
210: b_cells.num_pos += 1;
211:
212: }
213: }
214: if (x < maze_cols - 1) { /* look right */
215: if (*foffset(y, x + 1)) {
216: b_cells.conn[b_cells.num_pos].y_pos = y;
217: b_cells.conn[b_cells.num_pos].x_pos = x + 1;
218: b_cells.num_pos += 1;
219: }
220: }
221: if (x > 0) { /* look left */
222: if (*foffset(y, x - 1)) {
223: b_cells.conn[b_cells.num_pos].y_pos = y;
224: b_cells.conn[b_cells.num_pos].x_pos = x - 1;
225: b_cells.num_pos += 1;
226:
227: }
228: }
229: if (b_cells.num_pos == 0) /* no neighbors available */
230: return 0;
231: else {
232: i = rnd(b_cells.num_pos);
233: rtpos = b_cells.num_pos - 1;
234: rmwall(b_cells.conn[i].y_pos, b_cells.conn[i].x_pos, y, x);
235: return rtpos;
236: }
237: }
238:
239: /*
240: * foffset:
241: * Calculate memory address for frontier
242: */
243:
244: static char *
245: foffset(int y, int x)
246: {
247:
248: return (maze_frontier + (y * maze_cols) + x);
249: }
250:
251:
252: /*
253: * Maze_view:
254: * Returns true if the player can see the specified location within
255: * the confines of a maze (within one column or row)
256: */
257:
258: bool
259: maze_view(int y, int x)
260: {
261: register int start, goal, delta, ycheck = 0, xcheck = 0, absy, absx, see_radius;
262: register bool row;
263:
264: /* Get the absolute value of y and x differences */
265: absy = hero.y - y;
266: absx = hero.x - x;
267: if (absy < 0) absy = -absy;
268: if (absx < 0) absx = -absx;
269:
270: /* If we are standing in a wall, we can see a bit more */
271: switch (winat(hero.y, hero.x)) {
272: case VERTWALL:
273: case HORZWALL:
274: case WALL:
275: case SECRETDOOR:
276: case DOOR:
277: see_radius = 2;
278: otherwise:
279: see_radius = 1;
280: }
281:
282: /* Must be within one or two rows or columns */
283: if (absy > see_radius && absx > see_radius) return(FALSE);
284:
285: if (absx > see_radius) { /* Go along row */
286: start = hero.x;
287: goal = x;
288: ycheck = hero.y;
289: row = TRUE;
290: }
291: else { /* Go along column */
292: start = hero.y;
293: goal = y;
294: xcheck = hero.x;
295: row = FALSE;
296: }
297:
298: if (start <= goal) delta = 1;
299: else delta = -1;
300:
301: /* Start one past where we are standing */
302: if (start != goal) start += delta;
303:
304: /* If we are in a wall, we want to look in the area outside the wall */
305: if (see_radius > 1) {
306: if (row) {
307: /* See if above us it okay first */
308: switch (winat(ycheck, start)) {
309: case VERTWALL:
310: case HORZWALL:
311: case WALL:
312: case DOOR:
313: case SECRETDOOR:
314: /* No good, try one up */
315: if (y > hero.y) ycheck++;
316: else ycheck--;
317: otherwise:
318: see_radius = 1; /* Just look straight over the row */
319: }
320: }
321: else {
322: /* See if above us it okay first */
323: switch (winat(start, xcheck)) {
324: case VERTWALL:
325: case HORZWALL:
326: case WALL:
327: case DOOR:
328: case SECRETDOOR:
329: /* No good, try one over */
330: if (x > hero.x) xcheck++;
331: else xcheck--;
332: otherwise:
333: see_radius = 1; /* Just look straight up the column */
334: }
335: }
336: }
337:
338: /* Check boundary again */
339: if (absy > see_radius && absx > see_radius) return(FALSE);
340:
341: while (start != goal) {
342: if (row) xcheck = start;
343: else ycheck = start;
344:
345: if (xcheck < 0 || ycheck < 0)
346: return FALSE;
347: switch (winat(ycheck, xcheck)) {
348: case VERTWALL:
349: case HORZWALL:
350: case WALL:
351: case DOOR:
352: case SECRETDOOR:
353: return(FALSE);
354: }
355: start += delta;
356: }
357: return(TRUE);
358: }
359:
360:
361: /*
362: * moffset:
363: * Calculate memory address for bits
364: */
365:
366: static char *
367: moffset(int y, int x)
368: {
369: return (maze_bits + (y * (cols - 1)) + x);
370: }
371:
372: /*
373: * rmwall:
374: * Removes appropriate walls from the maze
375: */
376: static
377: void
378: rmwall(int newy, int newx, int oldy, int oldx)
379: {
380: reg int xdif,ydif;
381:
382: xdif = newx - oldx;
383: ydif = newy - oldy;
384:
385: *moffset((oldy * 2) + ydif + 1, (oldx * 2) + xdif + 1) = FALSE;
386: findcells(newy, newx);
387: }
388:
CVSweb