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