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