Blindfold removal fix
[slashemextended.git] / src / extralev.c
bloba59a5dddce9bd9acb7b0cbcabf96cb92ff787b02
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. */
5 /*
6 * Support code for "rogue"-style level.
7 */
9 #include "hack.h"
11 #ifdef REINCARNATION
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 */
20 #define UP 1
21 #define DOWN 2
22 #define LEFT 4
23 #define RIGHT 8
25 static NEARDATA struct rogueroom r[3][3];
26 STATIC_DCL void roguejoin(int,int,int,int,int);
27 STATIC_DCL void roguecorr(int,int,int);
28 STATIC_DCL void miniwalk(int,int);
30 STATIC_OVL
31 void
32 roguejoin(x1,y1,x2,y2, horiz)
33 int x1,y1,x2,y2;
34 int horiz;
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);
62 STATIC_OVL
63 void
64 roguecorr(x, y, dir)
65 int x,y,dir;
67 register int fromx, fromy, tox, toy;
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++;
85 if(y >= 2) {
86 impossible("down door from %d,%d going nowhere?",x,y);
87 return;
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--;
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++;
122 if(x >= 2) {
123 impossible("right door from %d,%d going nowhere?",x,y);
124 return;
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--;
141 roguejoin(fromx, fromy, tox, toy, TRUE);
142 return;
143 } else impossible("corridor in direction %d?",dir);
146 /* Modified walkfrom() from mkmaze.c */
147 STATIC_OVL
148 void
149 miniwalk(x, y)
150 int x,y;
152 register int q, dir;
153 int dirs[4];
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
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;
193 miniwalk(x,y);
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.
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)
216 #define here r[x][y]
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.
223 if (!rn2(5) && (nroom || (x<2 && y<2))) {
224 /* Arbitrary: dummy rooms may only go where real
225 * ones do.
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 */
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++;
240 here.doortable = 0;
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;
248 r[x][y].nroom = nroom;
249 smeq[nroom] = nroom;
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).
259 add_room(lowx, lowy, hix, hiy,
260 (boolean) !rn2(7), OROOM, FALSE, FALSE, FALSE);
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);
277 void
278 corr(x,y)
279 int x, y;
281 if (rn2(50)) {
282 levl[x][y].typ = CORR;
283 } else {
284 levl[x][y].typ = SCORR;
288 void
289 makerogueghost()
291 register struct monst *ghost;
292 struct obj *ghostobj;
293 struct mkroom *croom;
294 int x,y;
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());
304 if (rn2(4)) {
305 ghostobj = mksobj_at(FOOD_RATION, x, y, FALSE, FALSE, FALSE);
306 if (ghostobj) {
307 ghostobj->quan = (long) rnd(7);
308 ghostobj->owt = weight(ghostobj);
311 if (rn2(2)) {
312 ghostobj = mksobj_at(MACE, x, y, FALSE, FALSE, FALSE);
313 if (ghostobj) {
314 ghostobj->spe = rnd(3);
315 if (rn2(4)) curse(ghostobj);
317 } else {
318 ghostobj = mksobj_at(TWO_HANDED_SWORD, x, y, FALSE, FALSE, FALSE);
319 if (ghostobj) {
320 ghostobj->spe = rnd(5) - 2;
321 if (rn2(4)) curse(ghostobj);
324 ghostobj = mksobj_at(BOW, x, y, FALSE, FALSE, FALSE);
325 if (ghostobj) {
326 ghostobj->spe = 1;
327 if (rn2(4)) curse(ghostobj);
330 ghostobj = mksobj_at(ARROW, x, y, FALSE, FALSE, FALSE);
331 if (ghostobj) {
332 ghostobj->spe = 0;
333 ghostobj->quan = (long) rn1(10,25);
334 ghostobj->owt = weight(ghostobj);
335 if (rn2(4)) curse(ghostobj);
338 if (rn2(2)) {
339 ghostobj = mksobj_at(RING_MAIL, x, y, FALSE, FALSE, FALSE);
340 if (ghostobj) {
341 ghostobj->spe = rn2(3);
342 if (!rn2(3)) ghostobj->oerodeproof = TRUE;
343 if (rn2(4)) curse(ghostobj);
345 } else {
346 ghostobj = mksobj_at(PLATE_MAIL, x, y, FALSE, FALSE, FALSE);
347 if (ghostobj) {
348 ghostobj->spe = rnd(5) - 2;
349 if (!rn2(3)) ghostobj->oerodeproof = TRUE;
350 if (rn2(4)) curse(ghostobj);
353 if (rn2(2)) {
354 ghostobj = mksobj_at(FAKE_AMULET_OF_YENDOR, x, y, TRUE, FALSE, FALSE);
355 if (ghostobj) {
356 ghostobj->known = TRUE;
360 #endif /* REINCARNATION */
362 /*extralev.c*/