Annotation of early-roguelike/xrogue/passages.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: passages.c - Draw the connecting passages
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: Based on "Rogue: Exploring the Dungeons of Doom"
13: Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
14: All rights reserved.
15:
16: See the file LICENSE.TXT for full copyright and licensing information.
17: */
18:
19: #include <stdlib.h>
20: #include <curses.h>
21: #include "rogue.h"
22:
23: void conn(int r1, int r2);
24: void door(struct room *rm, coord *cp);
25:
26: /*
27: * do_passages:
28: * Draw all the passages on a level.
29: */
30:
31: void
32: do_passages(void)
33: {
34: register struct rdes *r1, *r2 = NULL;
35: register int i, j;
36: register int roomcount;
37: static struct rdes
38: {
39: bool conn[MAXROOMS]; /* possible to connect to room i? */
40: bool isconn[MAXROOMS]; /* connection been made to room i? */
41: bool ingraph; /* this room in graph already? */
42: } rdes[MAXROOMS] = {
43: { { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
44: { { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
45: { { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
46: { { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
47: { { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
48: { { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
49: { { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
50: { { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
51: { { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
52: };
53:
54: /*
55: * reinitialize room graph description
56: */
57: for (i = 0; i < MAXROOMS; i++)
58: {
59: r1 = &rdes[i];
60: for (j = 0; j < MAXROOMS; j++)
61: r1->isconn[j] = FALSE;
62: r1->ingraph = FALSE;
63: }
64:
65: /*
66: * starting with one room, connect it to a random adjacent room and
67: * then pick a new room to start with.
68: */
69: roomcount = 1;
70: r1 = &rdes[rnd(MAXROOMS)];
71: r1->ingraph = TRUE;
72: do
73: {
74: /*
75: * find a room to connect with
76: */
77: j = 0;
78: for (i = 0; i < MAXROOMS; i++)
79: if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0)
80: r2 = &rdes[i];
81: /*
82: * if no adjacent rooms are outside the graph, pick a new room
83: * to look from
84: */
85: if (j == 0)
86: {
87: do
88: r1 = &rdes[rnd(MAXROOMS)];
89: until (r1->ingraph);
90: }
91: /*
92: * otherwise, connect new room to the graph, and draw a tunnel
93: * to it
94: */
95: else
96: {
97: r2->ingraph = TRUE;
98: i = r1 - rdes;
99: j = r2 - rdes;
100: conn(i, j);
101: r1->isconn[j] = TRUE;
102: r2->isconn[i] = TRUE;
103: roomcount++;
104: }
105: } while (roomcount < MAXROOMS);
106:
107: /*
108: * attempt to add passages to the graph a random number of times so
109: * that there isn't just one unique passage through it.
110: */
111: for (roomcount = rnd(5); roomcount > 0; roomcount--)
112: {
113: r1 = &rdes[rnd(MAXROOMS)]; /* a random room to look from */
114: /*
115: * find an adjacent room not already connected
116: */
117: j = 0;
118: for (i = 0; i < MAXROOMS; i++)
119: if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0)
120: r2 = &rdes[i];
121: /*
122: * if there is one, connect it and look for the next added
123: * passage
124: */
125: if (j != 0)
126: {
127: i = r1 - rdes;
128: j = r2 - rdes;
129: conn(i, j);
130: r1->isconn[j] = TRUE;
131: r2->isconn[i] = TRUE;
132: }
133: }
134: }
135:
136: /*
137: * conn:
138: * Draw a corridor from a room in a certain direction.
139: */
140:
141: void
142: conn(int r1, int r2)
143: {
144: register struct room *rpf, *rpt = NULL;
145: register char rmt;
146: register int distance = 0, max_diag, offset = 0, i;
147: register int rm;
148: int turns[3], turn_dist[3];
149: register char direc;
150: coord delta = {0, 0}, curr, turn_delta = {0,0}, spos = {0,0}, epos = {0,0};
151:
152: if (r1 < r2)
153: {
154: rm = r1;
155: if (r1 + 1 == r2)
156: direc = 'r';
157: else
158: direc = 'd';
159: }
160: else
161: {
162: rm = r2;
163: if (r2 + 1 == r1)
164: direc = 'r';
165: else
166: direc = 'd';
167: }
168: rpf = &rooms[rm];
169: /*
170: * Set up the movement variables, in two cases:
171: * first drawing one down.
172: */
173: if (direc == 'd')
174: {
175: rmt = rm + 3; /* room # of dest */
176: rpt = &rooms[rmt]; /* room pointer of dest */
177: delta.x = 0; /* direction of move */
178: delta.y = 1;
179: spos.x = rpf->r_pos.x; /* start of move */
180: spos.y = rpf->r_pos.y;
181: epos.x = rpt->r_pos.x; /* end of move */
182: epos.y = rpt->r_pos.y;
183: if (!(rpf->r_flags & ISGONE)) /* if not gone pick door pos */
184: {
185: spos.x += rnd(rpf->r_max.x-2)+1;
186: spos.y += rpf->r_max.y-1;
187: }
188: if (!(rpt->r_flags & ISGONE))
189: epos.x += rnd(rpt->r_max.x-2)+1;
190: distance = abs(spos.y - epos.y) - 1; /* distance to move */
191: turn_delta.y = 0; /* direction to turn */
192: turn_delta.x = (spos.x < epos.x ? 1 : -1);
193: offset = abs(spos.x - epos.x); /* how far to turn */
194: }
195: else if (direc == 'r') /* setup for moving right */
196: {
197: rmt = rm + 1;
198: rpt = &rooms[rmt];
199: delta.x = 1;
200: delta.y = 0;
201: spos.x = rpf->r_pos.x;
202: spos.y = rpf->r_pos.y;
203: epos.x = rpt->r_pos.x;
204: epos.y = rpt->r_pos.y;
205: if (!(rpf->r_flags & ISGONE))
206: {
207: spos.x += rpf->r_max.x-1;
208: spos.y += rnd(rpf->r_max.y-2)+1;
209: }
210: if (!(rpt->r_flags & ISGONE))
211: epos.y += rnd(rpt->r_max.y-2)+1;
212: distance = abs(spos.x - epos.x) - 1;
213: turn_delta.y = (spos.y < epos.y ? 1 : -1);
214: turn_delta.x = 0;
215: offset = abs(spos.y - epos.y);
216: }
217: else
218: debug("error in connection tables");
219:
220: /*
221: * Draw in the doors on either side of the passage or just put #'s
222: * if the rooms are gone.
223: */
224: if (!(rpf->r_flags & ISGONE)) door(rpf, &spos);
225: else
226: {
227: cmov(spos);
228: addch('#');
229: }
230: if (!(rpt->r_flags & ISGONE)) door(rpt, &epos);
231: else
232: {
233: cmov(epos);
234: addch('#');
235: }
236:
237: /* How far can we move diagonally? */
238: max_diag = min(distance, offset);
239:
240: /*
241: * Decide how many turns we will have.
242: */
243: for (i=0; i<3; i++) turn_dist[i] = 0; /* Init distances */
244: if (max_diag > 0) {
245: int nturns;
246:
247: for (i=0, nturns=0; i<3; i++) {
248: if (rnd(3 - i + nturns) == 0) {
249: nturns++;
250: turns[i] = 0;
251: }
252: else turns[i] = -1;
253: }
254: }
255: else {
256: /* Just use a straight line (middle turn) */
257: turns[0] = turns[2] = -1;
258: turns[1] = 0;
259: }
260:
261: /*
262: * Now decide how long each turn will be (for those selected above).
263: */
264: while (max_diag > 0) {
265: for (i=0; i<3; i++) {
266: if (turns[i] >= 0 && max_diag > 0 && rnd(2) == 0) {
267: turn_dist[i]++;
268: max_diag--;
269: }
270: }
271: }
272:
273: /*
274: * If we have extra offset space, add it to the straight turn.
275: */
276: if (offset > distance) turn_dist[1] += offset - distance;
277:
278: /*
279: * Decide where we want to make our turns.
280: * First calculate the offsets, then use those offsets to calculate
281: * the exact position relative to "distance."
282: */
283: turns[0] = rnd(distance - turn_dist[0] - turn_dist[2]);
284: turns[2] = rnd(distance - turn_dist[0] - turn_dist[2] - turns[0]);
285: turns[1] = rnd(distance - turn_dist[0] - turn_dist[2] -
286: turns[0] - turns[2]);
287:
288: turns[0] = distance - turns[0];
289: turns[1] = turns[0] - turn_dist[0] - turns[1];
290: turns[2] = turns[1] - turns[2];
291:
292: /*
293: * Get ready to move...
294: */
295: curr.x = spos.x;
296: curr.y = spos.y;
297: while (distance > 0) {
298: /*
299: * Move to next row/column
300: */
301: curr.x += delta.x;
302: curr.y += delta.y;
303:
304: /*
305: * Check if we are at a turn place; if so make a turn
306: */
307: for (i=0; i<3; i++) {
308: if (distance == turns[i] && turn_dist[i] > 0) {
309: /*
310: * If this is the start of a straight path,
311: * we might put in a right-angle turn (33% chance).
312: */
313: if (i == 1 && rnd(3) == 0) {
314: cmov(curr);
315: addch(PASSAGE);
316: }
317:
318: /* Now dig the turn */
319: while (turn_dist[i]--) {
320: curr.x += turn_delta.x;
321: curr.y += turn_delta.y;
322: cmov(curr);
323: addch(PASSAGE);
324: if (i != 1) { /* A diagonal */
325: if (--distance > 0) {
326: curr.x += delta.x;
327: curr.y += delta.y;
328: }
329: }
330: }
331: }
332: }
333:
334: if (distance > 0) {
335: /*
336: * Dig the passage.
337: */
338: cmov(curr);
339: addch(PASSAGE);
340: distance--;
341: }
342: }
343: curr.x += delta.x;
344: curr.y += delta.y;
345: if (!ce(curr, epos))
346: msg("Warning, connectivity problem (%d, %d) to (%d, %d).",
347: curr.y, curr.x, epos.y, epos.x);
348: }
349:
350: /*
351: * Add a door or possibly a secret door
352: * also enters the door in the exits array of the room.
353: */
354:
355: void
356: door(struct room *rm, coord *cp)
357: {
358: struct linked_list *newroom;
359: coord *exit;
360:
361: cmov(*cp);
362:
363: if (rnd(10) < (level - 1) && rnd(100) < 20)
364: addch(SECRETDOOR);
365: else
366: addch(DOOR);
367:
368: /* Insert the new room into the linked list of rooms */
369: newroom = new_item(sizeof(coord));
370: exit = DOORPTR(newroom);
371: *exit = *cp;
372: attach(rm->r_exit, newroom);
373: }
374:
CVSweb