1    | /*	SCCS Id: @(#)extralev.c	3.3	1999/11/26	*/
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
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
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
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
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
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
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);
306  | 		ghostobj->quan = (long) rnd(7);
307  | 		ghostobj->owt = weight(ghostobj);
308  | 	}
309  | 	if (rn2(2)) {
310  | 		ghostobj = mksobj_at(MACE,x,y,FALSE);
311  | 		ghostobj->spe = rnd(3);
312  | 		if (rn2(4)) curse(ghostobj);
313  | 	} else {
314  | 		ghostobj = mksobj_at(TWO_HANDED_SWORD,x,y,FALSE);
315  | 		ghostobj->spe = rnd(5) - 2;
316  | 		if (rn2(4)) curse(ghostobj);
317  | 	}
318  | 	ghostobj = mksobj_at(BOW,x,y,FALSE);
319  | 	ghostobj->spe = 1;
320  | 	if (rn2(4)) curse(ghostobj);
321  | 
322  | 	ghostobj = mksobj_at(ARROW,x,y,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);
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);
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);
341  | 		ghostobj->known = TRUE;
342  | 	}
343  | }
344  | #endif /* REINCARNATION */
345  | 
346  | /*extralev.c*/