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
13struct 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
25static NEARDATA struct rogueroom r[3][3];
26STATIC_DCL void FDECL(roguejoin,(int,int,int,int,int));
27STATIC_DCL void FDECL(roguecorr,(int,int,int));
28STATIC_DCL void FDECL(miniwalk,(int,int));
29
30STATIC_OVL
31void
32roguejoin(x1,y1,x2,y2, horiz)
33int x1,y1,x2,y2;
34int 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
62STATIC_OVL
63void
64roguecorr(x, y, dir)
65int 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 */
147STATIC_OVL
148void
149miniwalk(x, y)
150int 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
197void
198makeroguerooms() {
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
277void
278corr(x,y)
279int x, y;
280{
281	if (rn2(50)) {
282		levl[x][y].typ = CORR;
283	} else {
284		levl[x][y].typ = SCORR;
285	}
286}
287
288void
289makerogueghost()
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