1 /*
2  * Draw the connecting passages
3  *
4  * passages.c	1.4 (A.I. Design)	12/14/84
5  */
6 
7 #include "rogue.h"
8 #include "curses.h"
9 
10 /*
11  * conn:
12  *	Draw a corridor from a room in a certain direction.
13  */
14 conn(r1, r2)
15 int r1, r2;
16 {
17 	struct room *rpf, *rpt;
18 	register int rmt, rm;
19 	int distance, turn_spot, turn_distance, index;
20 	int direc;
21 	coord del, curr, turn_delta, spos, epos;
22 
23 	if (r1 < r2) {
24 		rm = r1;
25 		if (r1 + 1 == r2)
26 			direc = 'r';
27 		else
28 			direc = 'd';
29 	} else {
30 		rm = r2;
31 		if (r2 + 1 == r1)
32 			direc = 'r';
33 		else
34 			direc = 'd';
35     }
36 	rpf = &rooms[rm];
37 	/*
38 	 * Set up the movement variables, in two cases:
39 	 * first drawing one down.
40 	 */
41 	if (direc == 'd') {
42 		rmt = rm + 3;				/* room # of dest */
43 		rpt = &rooms[rmt];			/* room pointer of dest */
44 		del.x = 0;				/* direction of move */
45 		del.y = 1;
46 		/*
47 		 * If we are drawing from/to regular or maze rooms, we have
48 		 * to pick the spot we draw from/to
49 		 */
50 		if ((rpf->r_flags & ISGONE) == 0 || (rpf->r_flags & ISMAZE)) {
51 			spos.y = rpf->r_pos.y + rpf->r_max.y - 1;
52 			do {
53 				spos.x = rpf->r_pos.x + rnd(rpf->r_max.x - 2) + 1;
54 			} while (chat(spos.y,spos.x) == ' ');
55 		} else {
56 			spos.x = rpf->r_pos.x;
57 			spos.y = rpf->r_pos.y;
58 		}
59 		epos.y = rpt->r_pos.y;
60 		if ((rpt->r_flags & ISGONE) == 0 || (rpt->r_flags & ISMAZE)) {
61 			do {
62 				epos.x = rpt->r_pos.x + rnd(rpt->r_max.x - 2) + 1;
63 			} while (chat(epos.y,epos.x) == ' ');
64 		} else
65 			epos.x = rpt->r_pos.x;
66 		distance = abs(spos.y - epos.y) - 1;	/* distance to move */
67 		turn_delta.y = 0;			/* direction to turn */
68 		turn_delta.x = (spos.x < epos.x ? 1 : -1);
69 		turn_distance = abs(spos.x - epos.x);	/* how far to turn */
70 	} else if (direc == 'r') {			/* setup for moving right */
71 		rmt = rm + 1;
72 		rpt = &rooms[rmt];
73 		del.x = 1;
74 		del.y = 0;
75 		if ((rpf->r_flags & ISGONE) == 0 || (rpf->r_flags & ISMAZE)) {
76 			spos.x = rpf->r_pos.x + rpf->r_max.x-1;
77 			do {
78 				spos.y = rpf->r_pos.y + rnd(rpf->r_max.y-2)+1;
79 			} while (chat(spos.y,spos.x) == ' ');
80 		} else {
81 			spos.x = rpf->r_pos.x;
82 			spos.y = rpf->r_pos.y;
83 		}
84 		epos.x = rpt->r_pos.x;
85 		if ((rpt->r_flags & ISGONE) == 0 || (rpt->r_flags & ISMAZE)) {
86 			do {
87 				epos.y = rpt->r_pos.y + rnd(rpt->r_max.y-2)+1;
88 			} while (chat(epos.y, epos.x) == ' ');
89 		} else
90 			epos.y = rpt->r_pos.y;
91 		distance = abs(spos.x - epos.x) - 1;
92 		turn_delta.y = (spos.y < epos.y ? 1 : -1);
93 		turn_delta.x = 0;
94 		turn_distance = abs(spos.y - epos.y);
95 	}
96 #ifdef DEBUG
97 	else
98 		debug("error in connection tables");
99 #endif
100     turn_spot = rnd(distance-1) + 1;
101     /*
102      * Draw in the doors on either side of the passage or just put #'s
103      * if the rooms are gone.
104      */
105     if (!(rpf->r_flags & ISGONE))
106 	door(rpf, &spos);
107     else
108 	psplat(spos.y, spos.x);
109     if (!(rpt->r_flags & ISGONE))
110 	door(rpt, &epos);
111     else
112 	psplat(epos.y, epos.x);
113     /*
114      * Get ready to move...
115      */
116     curr.x = spos.x;
117     curr.y = spos.y;
118     while (distance)
119     {
120 	/*
121 	 * Move to new position
122 	 */
123 	curr.x += del.x;
124 	curr.y += del.y;
125 	/*
126 	 * Check if we are at the turn place, if so do the turn
127 	 */
128 	if (distance == turn_spot) 
129 	{
130 	    while (turn_distance--)
131 	    {
132 		psplat(curr.y, curr.x);
133 		curr.x += turn_delta.x;
134 		curr.y += turn_delta.y;
135 	    }
136 	}
137 	/*
138 	 * Continue digging along
139 	 */
140 	psplat(curr.y, curr.x);
141 	distance--;
142     }
143     curr.x += del.x;
144     curr.y += del.y;
145     if (!ce(curr, epos)) {
146 	epos.x -= del.x;
147 	epos.y -= del.y;
148 	psplat(epos.y, epos.x);
149     }
150 }
151 
152 /*
153  * do_passages:
154  *	Draw all the passages on a level.
155  */
156 do_passages()
157 {
158     register int i, j;
159     int roomcount;
160     static struct rdes
161     {
162 	char	conn[MAXROOMS];		/* possible to connect to room i? */
163 	char	isconn[MAXROOMS];	/* connection been made to room i? */
164 	char	ingraph;		/* this room in graph already? */
165     } rdes[MAXROOMS] = {
166 	{ { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
167 	{ { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
168 	{ { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
169 	{ { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
170 	{ { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
171 	{ { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
172 	{ { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
173 	{ { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
174 	{ { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 }
175     };
176     struct rdes *r1, *r2;
177 
178     /*
179      * reinitialize room graph description
180      */
181     for (r1 = rdes; r1 < &rdes[MAXROOMS]; r1++)
182     {
183 	for (j = 0; j < MAXROOMS; j++)
184 	    r1->isconn[j] = FALSE;
185 	r1->ingraph = FALSE;
186     }
187 
188     /*
189      * starting with one room, connect it to a random adjacent room and
190      * then pick a new room to start with.
191      */
192     roomcount = 1;
193     r1 = &rdes[rnd(MAXROOMS)];
194     r1->ingraph = TRUE;
195     do
196     {
197 	/*
198 	 * find a room to connect with
199 	 */
200 	j = 0;
201 	for (i = 0; i < MAXROOMS; i++)
202 	    if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0)
203 		r2 = &rdes[i];
204 	/*
205 	 * if no adjacent rooms are outside the graph, pick a new room
206 	 * to look from
207 	 */
208 	if (j == 0)
209 	{
210 	    do
211 		r1 = &rdes[rnd(MAXROOMS)];
212 	    while (!r1->ingraph);
213 	}
214 	/*
215 	 * otherwise, connect new room to the graph, and draw a tunnel
216 	 * to it
217 	 */
218 	else
219 	{
220 	    r2->ingraph = TRUE;
221 	    i = r1 - rdes;
222 	    j = r2 - rdes;
223 	    conn(i, j);
224 	    r1->isconn[j] = TRUE;
225 	    r2->isconn[i] = TRUE;
226 	    roomcount++;
227 	}
228     } while (roomcount < MAXROOMS);
229 
230     /*
231      * attempt to add passages to the graph a random number of times so
232      * that there isn't always just one unique passage through it.
233      */
234     for (roomcount = rnd(5); roomcount > 0; roomcount--)
235     {
236 	r1 = &rdes[rnd(MAXROOMS)];	/* a random room to look from */
237 	/*
238 	 * find an adjacent room not already connected
239 	 */
240 	j = 0;
241 	for (i = 0; i < MAXROOMS; i++)
242 	    if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0)
243 		r2 = &rdes[i];
244 	/*
245 	 * if there is one, connect it and look for the next added
246 	 * passage
247 	 */
248 	if (j != 0)
249 	{
250 	    i = r1 - rdes;
251 	    j = r2 - rdes;
252 	    conn(i, j);
253 	    r1->isconn[j] = TRUE;
254 	    r2->isconn[i] = TRUE;
255 	}
256     }
257     passnum();
258 }
259 
260 
261 /*
262  * door:
263  *	Add a door or possibly a secret door.  Also enters the door in
264  *	the exits array of the room.
265  */
266 door(rm, cp)
267 struct room *rm;
268 coord *cp;
269 {
270     register int index, xit;
271 
272     index = INDEX(cp->y, cp->x);
273     if (rnd(10) + 1 < level && rnd(5) == 0)
274     {
275 	_level[index] = (cp->y == rm->r_pos.y || cp->y == rm->r_pos.y + rm->r_max.y - 1) ? HWALL : VWALL;
276 	_flags[index] &= ~F_REAL;
277     }
278     else
279 	_level[index] = DOOR;
280     xit = rm->r_nexits++;
281     rm->r_exit[xit].y = cp->y;
282     rm->r_exit[xit].x = cp->x;
283 }
284 
285 #ifdef WIZARD
286 /*
287  * add_pass:
288  *	Add the passages to the current window (wizard command)
289  */
290 add_pass()
291 {
292     register int y, x, ch;
293 
294     for (y = 1; y < maxrow; y++)
295 	for (x = 0; x < COLS; x++)
296 	    if ((ch = chat(y, x)) == DOOR || ch == PASSAGE)
297 		mvaddch(y, x, ch);
298 }
299 #endif
300 
301 /*
302  * passnum:
303  *	Assign a number to each passageway
304  */
305 static int pnum;
306 static byte newpnum;
307 
308 passnum()
309 {
310     register struct room *rp;
311     register int i;
312 
313     pnum = 0;
314     newpnum = FALSE;
315     for (rp = passages; rp < &passages[MAXPASS]; rp++)
316 	rp->r_nexits = 0;
317     for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
318 	for (i = 0; i < rp->r_nexits; i++)
319 	{
320 	    newpnum++;
321 	    numpass(rp->r_exit[i].y, rp->r_exit[i].x);
322 	}
323 }
324 /*
325  * numpass:
326  *	Number a passageway square and its brethren
327  */
328 numpass(y, x)
329 int y, x;
330 {
331     register byte *fp;
332     register struct room *rp;
333     register byte ch;
334 
335 	if (offmap(y,x))
336 		return;
337 	fp = &flat(y, x);
338 	if (*fp & F_PNUM)
339 		return;
340 	if (newpnum) {
341 		pnum++;
342 		newpnum = FALSE;
343     }
344     /*
345      * check to see if it is a door or secret door, i.e., a new exit,
346      * or a numerable type of place
347      */
348 	if ((ch = chat(y, x)) == DOOR || (!(*fp & F_REAL) && ch != FLOOR)) {
349 		rp = &passages[pnum];
350 		rp->r_exit[rp->r_nexits].y = y;
351 		rp->r_exit[rp->r_nexits++].x = x;
352     } else if (!(*fp & F_PASS))
353 		return;
354 	*fp |= pnum;
355 	/*
356 	 * recurse on the surrounding places
357 	 */
358 	numpass(y + 1, x);
359 	numpass(y - 1, x);
360 	numpass(y, x + 1);
361 	numpass(y, x - 1);
362 }
363 
364 psplat(y, x)
365 shint y, x;
366 {
367     register int idx;
368 
369     _level[idx = INDEX(y, x)] = PASSAGE;
370     _flags[idx] |= F_PASS;
371 }
372 