1 /*	SCCS Id: @(#)extralev.c	3.4	2001/09/06	*/
2 /*	Copyright 1988, 1989 by Ken Arromdee				*/
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 /*
6  * Support code for "rogue"-style level.
7  */
8 
9 #include "hack.h"
10 
11 #ifdef REINCARNATION
12 
13 struct rogueroom {
14 	xchar rlx, rly;
15 	xchar dx, dy;
16 	boolean real;
17 	uchar doortable;
18 	int nroom; /* Only meaningful for "real" rooms */
19 };
20 #define UP 1
21 #define DOWN 2
22 #define LEFT 4
23 #define RIGHT 8
24 
25 static NEARDATA struct rogueroom r[3][3];
26 STATIC_DCL void FDECL(roguejoin,(int,int,int,int,int));
27 STATIC_DCL void FDECL(roguecorr,(int,int,int));
28 STATIC_DCL void FDECL(miniwalk,(int,int));
29 
30 STATIC_OVL
31 void
roguejoin(x1,y1,x2,y2,horiz)32 roguejoin(x1,y1,x2,y2, horiz)
33 int x1,y1,x2,y2;
34 int horiz;
35 {
36 	register int x,y,middle;
37 #ifndef MAX
38 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
39 #endif
40 #ifndef MIN
41 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
42 #endif
43 	if (horiz) {
44 		middle = x1 + rn2(x2-x1+1);
45 		for(x=MIN(x1,middle); x<=MAX(x1,middle); x++)
46 			corr(x, y1);
47 		for(y=MIN(y1,y2); y<=MAX(y1,y2); y++)
48 			corr(middle,y);
49 		for(x=MIN(middle,x2); x<=MAX(middle,x2); x++)
50 			corr(x, y2);
51 	} else {
52 		middle = y1 + rn2(y2-y1+1);
53 		for(y=MIN(y1,middle); y<=MAX(y1,middle); y++)
54 			corr(x1, y);
55 		for(x=MIN(x1,x2); x<=MAX(x1,x2); x++)
56 			corr(x, middle);
57 		for(y=MIN(middle,y2); y<=MAX(middle,y2); y++)
58 			corr(x2,y);
59 	}
60 }
61 
62 STATIC_OVL
63 void
roguecorr(x,y,dir)64 roguecorr(x, y, dir)
65 int x,y,dir;
66 {
67 	register int fromx, fromy, tox, toy;
68 
69 	if (dir==DOWN) {
70 		r[x][y].doortable &= ~DOWN;
71 		if (!r[x][y].real) {
72 			fromx = r[x][y].rlx; fromy = r[x][y].rly;
73 			fromx += 1 + 26*x; fromy += 7*y;
74 		} else {
75 			fromx = r[x][y].rlx + rn2(r[x][y].dx);
76 			fromy = r[x][y].rly + r[x][y].dy;
77 			fromx += 1 + 26*x; fromy += 7*y;
78 			if (!IS_WALL(levl[fromx][fromy].typ))
79 				impossible("down: no wall at %d,%d?",fromx,
80 									fromy);
81 			dodoor(fromx, fromy, &rooms[r[x][y].nroom]);
82 			levl[fromx][fromy].doormask = D_NODOOR;
83 			fromy++;
84 		}
85 		if(y >= 2) {
86 			impossible("down door from %d,%d going nowhere?",x,y);
87 			return;
88 		}
89 		y++;
90 		r[x][y].doortable &= ~UP;
91 		if (!r[x][y].real) {
92 			tox = r[x][y].rlx; toy = r[x][y].rly;
93 			tox += 1 + 26*x; toy += 7*y;
94 		} else {
95 			tox = r[x][y].rlx + rn2(r[x][y].dx);
96 			toy = r[x][y].rly - 1;
97 			tox += 1 + 26*x; toy += 7*y;
98 			if (!IS_WALL(levl[tox][toy].typ))
99 				impossible("up: no wall at %d,%d?",tox,toy);
100 			dodoor(tox, toy, &rooms[r[x][y].nroom]);
101 			levl[tox][toy].doormask = D_NODOOR;
102 			toy--;
103 		}
104 		roguejoin(fromx, fromy, tox, toy, FALSE);
105 		return;
106 	} else if (dir == RIGHT) {
107 		r[x][y].doortable &= ~RIGHT;
108 		if (!r[x][y].real) {
109 			fromx = r[x][y].rlx; fromy = r[x][y].rly;
110 			fromx += 1 + 26*x; fromy += 7*y;
111 		} else {
112 			fromx = r[x][y].rlx + r[x][y].dx;
113 			fromy = r[x][y].rly + rn2(r[x][y].dy);
114 			fromx += 1 + 26*x; fromy += 7*y;
115 			if (!IS_WALL(levl[fromx][fromy].typ))
116 				impossible("down: no wall at %d,%d?",fromx,
117 									fromy);
118 			dodoor(fromx, fromy, &rooms[r[x][y].nroom]);
119 			levl[fromx][fromy].doormask = D_NODOOR;
120 			fromx++;
121 		}
122 		if(x >= 2) {
123 			impossible("right door from %d,%d going nowhere?",x,y);
124 			return;
125 		}
126 		x++;
127 		r[x][y].doortable &= ~LEFT;
128 		if (!r[x][y].real) {
129 			tox = r[x][y].rlx; toy = r[x][y].rly;
130 			tox += 1 + 26*x; toy += 7*y;
131 		} else {
132 			tox = r[x][y].rlx - 1;
133 			toy = r[x][y].rly + rn2(r[x][y].dy);
134 			tox += 1 + 26*x; toy += 7*y;
135 			if (!IS_WALL(levl[tox][toy].typ))
136 				impossible("left: no wall at %d,%d?",tox,toy);
137 			dodoor(tox, toy, &rooms[r[x][y].nroom]);
138 			levl[tox][toy].doormask = D_NODOOR;
139 			tox--;
140 		}
141 		roguejoin(fromx, fromy, tox, toy, TRUE);
142 		return;
143 	} else impossible("corridor in direction %d?",dir);
144 }
145 
146 /* Modified walkfrom() from mkmaze.c */
147 STATIC_OVL
148 void
miniwalk(x,y)149 miniwalk(x, y)
150 int x,y;
151 {
152 	register int q, dir;
153 	int dirs[4];
154 
155 	while(1) {
156 		q = 0;
157 #define doorhere (r[x][y].doortable)
158 		if (x>0 && (!(doorhere & LEFT)) &&
159 					(!r[x-1][y].doortable || !rn2(10)))
160 			dirs[q++] = 0;
161 		if (x<2 && (!(doorhere & RIGHT)) &&
162 					(!r[x+1][y].doortable || !rn2(10)))
163 			dirs[q++] = 1;
164 		if (y>0 && (!(doorhere & UP)) &&
165 					(!r[x][y-1].doortable || !rn2(10)))
166 			dirs[q++] = 2;
167 		if (y<2 && (!(doorhere & DOWN)) &&
168 					(!r[x][y+1].doortable || !rn2(10)))
169 			dirs[q++] = 3;
170 	/* Rogue levels aren't just 3 by 3 mazes; they have some extra
171 	 * connections, thus that 1/10 chance
172 	 */
173 		if (!q) return;
174 		dir = dirs[rn2(q)];
175 		switch(dir) { /* Move in direction */
176 			case 0: doorhere |= LEFT;
177 				x--;
178 				doorhere |= RIGHT;
179 				break;
180 			case 1: doorhere |= RIGHT;
181 				x++;
182 				doorhere |= LEFT;
183 				break;
184 			case 2: doorhere |= UP;
185 				y--;
186 				doorhere |= DOWN;
187 				break;
188 			case 3: doorhere |= DOWN;
189 				y++;
190 				doorhere |= UP;
191 				break;
192 		}
193 		miniwalk(x,y);
194 	}
195 }
196 
197 void
makeroguerooms()198 makeroguerooms() {
199 	register int x,y;
200 	/* Rogue levels are structured 3 by 3, with each section containing
201 	 * a room or an intersection.  The minimum width is 2 each way.
202 	 * One difference between these and "real" Rogue levels: real Rogue
203 	 * uses 24 rows and NetHack only 23.  So we cheat a bit by making the
204 	 * second row of rooms not as deep.
205 	 *
206 	 * Each normal space has 6/7 rows and 25 columns in which a room may
207 	 * actually be placed.  Walls go from rows 0-5/6 and columns 0-24.
208 	 * Not counting walls, the room may go in
209 	 * rows 1-5 and columns 1-23 (numbering starting at 0).  A room
210 	 * coordinate of this type may be converted to a level coordinate
211 	 * by adding 1+28*x to the column, and 7*y to the row.  (The 1
212 	 * is because column 0 isn't used [we only use 1-78]).
213 	 * Room height may be 2-4 (2-5 on last row), length 2-23 (not
214 	 * counting walls)
215 	 */
216 #define here r[x][y]
217 
218 	nroom = 0;
219 	for(y=0; y<3; y++) for(x=0; x<3; x++) {
220 		/* Note: we want to insure at least 1 room.  So, if the
221 		 * first 8 are all dummies, force the last to be a room.
222 		 */
223 		if (!rn2(5) && (nroom || (x<2 && y<2))) {
224 			/* Arbitrary: dummy rooms may only go where real
225 			 * ones do.
226 			 */
227 			here.real = FALSE;
228 			here.rlx = rn1(22, 2);
229 			here.rly = rn1((y==2)?4:3, 2);
230 		} else {
231 			here.real = TRUE;
232 			here.dx = rn1(22, 2); /* 2-23 long, plus walls */
233 			here.dy = rn1((y==2)?4:3, 2); /* 2-5 high, plus walls */
234 
235 			/* boundaries of room floor */
236 			here.rlx = rnd(23 - here.dx + 1);
237 			here.rly = rnd(((y==2) ? 5 : 4)- here.dy + 1);
238 			nroom++;
239 		}
240 		here.doortable = 0;
241 	}
242 	miniwalk(rn2(3), rn2(3));
243 	nroom = 0;
244 	for(y=0; y<3; y++) for(x=0; x<3; x++) {
245 		if (here.real) { /* Make a room */
246 			int lowx, lowy, hix, hiy;
247 
248 			r[x][y].nroom = nroom;
249 			smeq[nroom] = nroom;
250 
251 			lowx = 1 + 26*x + here.rlx;
252 			lowy = 7*y + here.rly;
253 			hix = 1 + 26*x + here.rlx + here.dx - 1;
254 			hiy = 7*y + here.rly + here.dy - 1;
255 			/* Strictly speaking, it should be lit only if above
256 			 * level 10, but since Rogue rooms are only
257 			 * encountered below level 10, use !rn2(7).
258 			 */
259 			add_room(lowx, lowy, hix, hiy,
260 				 (boolean) !rn2(7), OROOM, FALSE);
261 		}
262 	}
263 
264 	/* Now, add connecting corridors. */
265 	for(y=0; y<3; y++) for(x=0; x<3; x++) {
266 		if (here.doortable & DOWN)
267 			roguecorr(x, y, DOWN);
268 		if (here.doortable & RIGHT)
269 			roguecorr(x, y, RIGHT);
270 		if (here.doortable & LEFT)
271 			impossible ("left end of %d, %d never connected?",x,y);
272 		if (here.doortable & UP)
273 			impossible ("up end of %d, %d never connected?",x,y);
274 	}
275 }
276 
277 void
corr(x,y)278 corr(x,y)
279 int x, y;
280 {
281 	if (rn2(50)) {
282 		levl[x][y].typ = CORR;
283 	} else {
284 		levl[x][y].typ = SCORR;
285 	}
286 }
287 
288 void
makerogueghost()289 makerogueghost()
290 {
291 	register struct monst *ghost;
292 	struct obj *ghostobj;
293 	struct mkroom *croom;
294 	int x,y;
295 
296 	if (!nroom) return; /* Should never happen */
297 	croom = &rooms[rn2(nroom)];
298 	x = somex(croom); y = somey(croom);
299 	if (!(ghost = makemon(&mons[PM_GHOST], x, y, NO_MM_FLAGS)))
300 		return;
301 	ghost->msleeping = 1;
302 	ghost = christen_monst(ghost, roguename());
303 
304 	if (rn2(4)) {
305 		ghostobj = mksobj_at(FOOD_RATION, x, y, FALSE, FALSE);
306 		ghostobj->quan = (long) rnd(7);
307 		ghostobj->owt = weight(ghostobj);
308 	}
309 	if (rn2(2)) {
310 		ghostobj = mksobj_at(MACE, x, y, FALSE, FALSE);
311 		ghostobj->spe = rnd(3);
312 		if (rn2(4)) curse(ghostobj);
313 	} else {
314 		ghostobj = mksobj_at(TWO_HANDED_SWORD, x, y, FALSE, FALSE);
315 		ghostobj->spe = rnd(5) - 2;
316 		if (rn2(4)) curse(ghostobj);
317 	}
318 	ghostobj = mksobj_at(BOW, x, y, FALSE, FALSE);
319 	ghostobj->spe = 1;
320 	if (rn2(4)) curse(ghostobj);
321 
322 	ghostobj = mksobj_at(ARROW, x, y, FALSE, FALSE);
323 	ghostobj->spe = 0;
324 	ghostobj->quan = (long) rn1(10,25);
325 	ghostobj->owt = weight(ghostobj);
326 	if (rn2(4)) curse(ghostobj);
327 
328 	if (rn2(2)) {
329 		ghostobj = mksobj_at(RING_MAIL, x, y, FALSE, FALSE);
330 		ghostobj->spe = rn2(3);
331 		if (!rn2(3)) ghostobj->oerodeproof = TRUE;
332 		if (rn2(4)) curse(ghostobj);
333 	} else {
334 		ghostobj = mksobj_at(PLATE_MAIL, x, y, FALSE, FALSE);
335 		ghostobj->spe = rnd(5) - 2;
336 		if (!rn2(3)) ghostobj->oerodeproof = TRUE;
337 		if (rn2(4)) curse(ghostobj);
338 	}
339 	if (rn2(2)) {
340 		ghostobj = mksobj_at(FAKE_AMULET_OF_YENDOR, x, y, TRUE, FALSE);
341 		ghostobj->known = TRUE;
342 	}
343 }
344 #endif /* REINCARNATION */
345 
346 /*extralev.c*/
347