comparison arogue7/passages.c @ 125:adfa37e67084

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