make rank() static again
[NetHack.git] / src / mklev.c
blob6cffe2a529f21fdcccd6903307c4c99894361a33
1 /* NetHack 3.7 mklev.c $NHDT-Date: 1737387068 2025/01/20 07:31:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.194 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Alex Smith, 2017. */
4 /* NetHack may be freely redistributed. See license for details. */
6 #include "hack.h"
8 /* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
9 /* croom->lx etc are schar (width <= int), so % arith ensures that */
10 /* conversion of result to int is reasonable */
12 staticfn boolean generate_stairs_room_good(struct mkroom *, int);
13 staticfn struct mkroom *generate_stairs_find_room(void);
14 staticfn void generate_stairs(void);
15 staticfn void mkfount(struct mkroom *);
16 staticfn boolean find_okay_roompos(struct mkroom *, coord *) NONNULLARG12;
17 staticfn void mksink(struct mkroom *);
18 staticfn void mkaltar(struct mkroom *);
19 staticfn void mkgrave(struct mkroom *);
20 staticfn void mkinvpos(coordxy, coordxy, int);
21 staticfn int mkinvk_check_wall(coordxy x, coordxy y);
22 staticfn void mk_knox_portal(coordxy, coordxy);
23 staticfn void makevtele(void);
24 staticfn void fill_ordinary_room(struct mkroom *, boolean) NONNULLARG1;
25 staticfn void themerooms_post_level_generate(void);
26 staticfn void makelevel(void);
27 staticfn boolean bydoor(coordxy, coordxy);
28 staticfn void mktrap_victim(struct trap *);
29 staticfn int traptype_rnd(unsigned);
30 staticfn int traptype_roguelvl(void);
31 staticfn struct mkroom *find_branch_room(coord *) NONNULLARG1;
32 staticfn struct mkroom *pos_to_room(coordxy, coordxy);
33 staticfn boolean cardinal_nextto_room(struct mkroom *, coordxy, coordxy);
34 staticfn boolean place_niche(struct mkroom *, int *, coordxy *, coordxy *);
35 staticfn void makeniche(int);
36 staticfn void make_niches(void);
37 staticfn int QSORTCALLBACK mkroom_cmp(const genericptr, const genericptr);
38 staticfn void dosdoor(coordxy, coordxy, struct mkroom *, int);
39 staticfn void join(int, int, boolean);
40 staticfn void alloc_doors(void);
41 staticfn void do_room_or_subroom(struct mkroom *,
42 coordxy, coordxy, coordxy, coordxy,
43 boolean, schar, boolean, boolean);
44 staticfn void makerooms(void);
45 staticfn boolean door_into_nonjoined(coordxy, coordxy);
46 staticfn boolean finddpos(coord *, coordxy, coordxy, coordxy, coordxy);
48 #define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
49 #define init_vault() gv.vault_x = -1
50 #define do_vault() (gv.vault_x != -1)
52 /* Args must be (const genericptr) so that qsort will always be happy. */
54 staticfn int QSORTCALLBACK
55 mkroom_cmp(const genericptr vx, const genericptr vy)
57 const struct mkroom *x, *y;
59 x = (const struct mkroom *) vx;
60 y = (const struct mkroom *) vy;
61 if (x->lx < y->lx)
62 return -1;
63 return (x->lx > y->lx);
66 /* Return TRUE if a door placed at (x, y) which otherwise passes okdoor()
67 * checks would be connecting into an area that was declared as joined=false.
68 * Checking for this in finddpos() enables us to have rooms with sub-areas
69 * (such as shops) that will never randomly generate unwanted doors in order
70 * to connect them up to other areas.
72 staticfn boolean
73 door_into_nonjoined(coordxy x, coordxy y)
75 coordxy tx, ty, i;
77 for (i = 0; i < 4; i++) {
78 tx = x + xdir[dirs_ord[i]];
79 ty = y + ydir[dirs_ord[i]];
80 if (!isok(tx, ty) || IS_OBSTRUCTED(levl[tx][ty].typ))
81 continue;
83 /* Is this connecting to a room that doesn't want joining? */
84 if (levl[tx][ty].roomno >= ROOMOFFSET
85 && !svr.rooms[levl[tx][ty].roomno - ROOMOFFSET].needjoining) {
86 return TRUE;
89 return FALSE;
92 staticfn boolean
93 finddpos(
94 coord *cc,
95 coordxy xl, coordxy yl,
96 coordxy xh, coordxy yh)
98 coordxy x, y;
100 x = rn1(xh - xl + 1, xl);
101 y = rn1(yh - yl + 1, yl);
102 if (okdoor(x, y) && !door_into_nonjoined(x, y))
103 goto gotit;
105 for (x = xl; x <= xh; x++)
106 for (y = yl; y <= yh; y++)
107 if (okdoor(x, y) && !door_into_nonjoined(x, y))
108 goto gotit;
110 for (x = xl; x <= xh; x++)
111 for (y = yl; y <= yh; y++)
112 if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
113 goto gotit;
114 /* cannot find something reasonable -- strange */
115 cc->x = xl;
116 cc->y = yh;
117 return FALSE;
118 gotit:
119 cc->x = x;
120 cc->y = y;
121 return TRUE;
124 /* Sort rooms on the level so they're ordered from left to right on the map.
125 makecorridors() by default links rooms N and N+1 */
126 void
127 sort_rooms(void)
129 coordxy x, y;
130 unsigned i, ri[MAXNROFROOMS + 1] = { 0U }, n = (unsigned) svn.nroom;
132 qsort((genericptr_t) svr.rooms, n, sizeof (struct mkroom), mkroom_cmp);
134 /* Update the roomnos on the map */
135 for (i = 0; i < n; i++)
136 ri[svr.rooms[i].roomnoidx] = i;
138 for (x = 1; x < COLNO; x++)
139 for (y = 0; y < ROWNO; y++) {
140 unsigned rno = levl[x][y].roomno;
142 if (rno >= ROOMOFFSET && rno < MAXNROFROOMS + 1)
143 levl[x][y].roomno = ri[rno - ROOMOFFSET] + ROOMOFFSET;
147 staticfn void
148 do_room_or_subroom(struct mkroom *croom,
149 coordxy lowx, coordxy lowy, coordxy hix, coordxy hiy,
150 boolean lit, schar rtype, boolean special, boolean is_room)
152 coordxy x, y;
153 struct rm *lev;
155 /* locations might bump level edges in wall-less rooms */
156 /* add/subtract 1 to allow for edge locations */
157 if (!lowx)
158 lowx++;
159 if (!lowy)
160 lowy++;
161 if (hix >= COLNO - 1)
162 hix = COLNO - 2;
163 if (hiy >= ROWNO - 1)
164 hiy = ROWNO - 2;
166 if (lit) {
167 for (x = lowx - 1; x <= hix + 1; x++) {
168 lev = &levl[x][max(lowy - 1, 0)];
169 for (y = lowy - 1; y <= hiy + 1; y++)
170 lev++->lit = 1;
172 croom->rlit = 1;
173 } else
174 croom->rlit = 0;
176 croom->roomnoidx = (croom - svr.rooms);
177 croom->lx = lowx;
178 croom->hx = hix;
179 croom->ly = lowy;
180 croom->hy = hiy;
181 croom->rtype = rtype;
182 croom->doorct = 0;
183 /* if we're not making a vault, gd.doorindex will still be 0
184 * if we are, we'll have problems adding niches to the previous room
185 * unless fdoor is at least gd.doorindex
187 croom->fdoor = gd.doorindex;
188 croom->irregular = FALSE;
190 croom->nsubrooms = 0;
191 croom->sbrooms[0] = (struct mkroom *) 0;
192 if (!special) {
193 croom->needjoining = TRUE;
194 for (x = lowx - 1; x <= hix + 1; x++)
195 for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) {
196 levl[x][y].typ = HWALL;
197 levl[x][y].horizontal = 1; /* For open/secret doors. */
199 for (x = lowx - 1; x <= hix + 1; x += (hix - lowx + 2))
200 for (y = lowy; y <= hiy; y++) {
201 levl[x][y].typ = VWALL;
202 levl[x][y].horizontal = 0; /* For open/secret doors. */
204 for (x = lowx; x <= hix; x++) {
205 lev = &levl[x][lowy];
206 for (y = lowy; y <= hiy; y++)
207 lev++->typ = ROOM;
209 if (is_room) {
210 levl[lowx - 1][lowy - 1].typ = TLCORNER;
211 levl[hix + 1][lowy - 1].typ = TRCORNER;
212 levl[lowx - 1][hiy + 1].typ = BLCORNER;
213 levl[hix + 1][hiy + 1].typ = BRCORNER;
214 } else { /* a subroom */
215 wallification(lowx - 1, lowy - 1, hix + 1, hiy + 1);
220 void
221 add_room(coordxy lowx, coordxy lowy, coordxy hix, coordxy hiy,
222 boolean lit, schar rtype, boolean special)
224 struct mkroom *croom;
226 croom = &svr.rooms[svn.nroom];
227 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special,
228 (boolean) TRUE);
229 croom++;
230 croom->hx = -1;
231 svn.nroom++;
234 void
235 add_subroom(struct mkroom *proom,
236 coordxy lowx, coordxy lowy,
237 coordxy hix, coordxy hiy,
238 boolean lit, schar rtype, boolean special)
240 struct mkroom *croom;
242 croom = &gs.subrooms[gn.nsubroom];
243 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special,
244 (boolean) FALSE);
245 proom->sbrooms[proom->nsubrooms++] = croom;
246 croom++;
247 croom->hx = -1;
248 gn.nsubroom++;
251 void
252 free_luathemes(enum lua_theme_group theme_group)
254 int i;
257 * Release which group(s)?
258 * tut_themes => leaving tutorial, free tutorial themes only;
259 * most_themes => entering endgame, free non-endgame themes;
260 * all_themes => end of game, free all themes.
262 for (i = 0; i < svn.n_dgns; ++i) {
263 if ((theme_group == tut_themes && i != tutorial_dnum)
264 || (theme_group == most_themes && i == astral_level.dnum))
265 continue;
266 if (gl.luathemes[i]) {
267 nhl_done((lua_State *) gl.luathemes[i]);
268 gl.luathemes[i] = (lua_State *) 0;
273 staticfn void
274 makerooms(void)
276 boolean tried_vault = FALSE;
277 int themeroom_tries = 0;
278 char *fname;
279 nhl_sandbox_info sbi = {NHL_SB_SAFE, 1*1024*1024, 0, 1*1024*1024};
280 lua_State *themes = (lua_State *) gl.luathemes[u.uz.dnum];
282 if (!themes && *(fname = svd.dungeons[u.uz.dnum].themerms)) {
283 if ((themes = nhl_init(&sbi)) != 0) {
284 if (!nhl_loadlua(themes, fname)) {
285 /* loading lua failed, don't use themed rooms */
286 nhl_done(themes);
287 themes = (lua_State *) 0;
288 } else {
289 /* success; save state for this dungeon branch */
290 gl.luathemes[u.uz.dnum] = (genericptr_t) themes;
291 /* keep themes context, so not 'nhl_done(themes);' */
292 iflags.in_lua = FALSE; /* can affect error messages */
295 if (!themes) /* don't try again when making next level */
296 *fname = '\0'; /* svd.dungeons[u.uz.dnum].themerms */
299 if (themes) {
300 create_des_coder();
301 iflags.in_lua = gi.in_mk_themerooms = TRUE;
302 gt.themeroom_failed = FALSE;
303 lua_getglobal(themes, "pre_themerooms_generate");
304 nhl_pcall_handle(themes, 0, 0, "makerooms-1", NHLpa_impossible);
305 iflags.in_lua = gi.in_mk_themerooms = FALSE;
308 /* make rooms until satisfied */
309 /* rnd_rect() will returns 0 if no more rects are available... */
310 while (svn.nroom < (MAXNROFROOMS - 1) && rnd_rect()) {
311 if (svn.nroom >= (MAXNROFROOMS / 6) && rn2(2) && !tried_vault) {
312 tried_vault = TRUE;
313 if (create_vault()) {
314 gv.vault_x = svr.rooms[svn.nroom].lx;
315 gv.vault_y = svr.rooms[svn.nroom].ly;
316 svr.rooms[svn.nroom].hx = -1;
318 } else {
319 if (themes) {
320 iflags.in_lua = gi.in_mk_themerooms = TRUE;
321 gt.themeroom_failed = FALSE;
322 lua_getglobal(themes, "themerooms_generate");
323 nhl_pcall_handle(themes, 0, 0, "makerooms-2", NHLpa_panic);
324 iflags.in_lua = gi.in_mk_themerooms = FALSE;
325 if (gt.themeroom_failed
326 && ((themeroom_tries++ > 10)
327 || (svn.nroom >= (MAXNROFROOMS / 6))))
328 break;
329 } else {
330 if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
331 break;;
335 if (themes) {
336 reset_xystart_size();
337 iflags.in_lua = gi.in_mk_themerooms = TRUE;
338 gt.themeroom_failed = FALSE;
339 lua_getglobal(themes, "post_themerooms_generate");
340 nhl_pcall_handle(themes, 0, 0, "makerooms-3", NHLpa_panic);
341 iflags.in_lua = gi.in_mk_themerooms = FALSE;
345 staticfn void
346 join(int a, int b, boolean nxcor)
348 coord cc, tt, org, dest;
349 coordxy tx, ty, xx, yy;
350 struct mkroom *croom, *troom;
351 int dx, dy;
353 croom = &svr.rooms[a];
354 troom = &svr.rooms[b];
356 if (!croom->needjoining || !troom->needjoining)
357 return;
359 /* find positions cc and tt for doors in croom and troom
360 and direction for a corridor between them */
362 if (troom->hx < 0 || croom->hx < 0)
363 return;
364 if (troom->lx > croom->hx) {
365 dx = 1;
366 dy = 0;
367 xx = croom->hx + 1;
368 tx = troom->lx - 1;
369 if (!finddpos(&cc, xx, croom->ly, xx, croom->hy))
370 return;
371 if (!finddpos(&tt, tx, troom->ly, tx, troom->hy))
372 return;
373 } else if (troom->hy < croom->ly) {
374 dy = -1;
375 dx = 0;
376 yy = croom->ly - 1;
377 ty = troom->hy + 1;
378 if (!finddpos(&cc, croom->lx, yy, croom->hx, yy))
379 return;
380 if (!finddpos(&tt, troom->lx, ty, troom->hx, ty))
381 return;
382 } else if (troom->hx < croom->lx) {
383 dx = -1;
384 dy = 0;
385 xx = croom->lx - 1;
386 tx = troom->hx + 1;
387 if (!finddpos(&cc, xx, croom->ly, xx, croom->hy))
388 return;
389 if (!finddpos(&tt, tx, troom->ly, tx, troom->hy))
390 return;
391 } else {
392 dy = 1;
393 dx = 0;
394 yy = croom->hy + 1;
395 ty = troom->ly - 1;
396 if (!finddpos(&cc, croom->lx, yy, croom->hx, yy))
397 return;
398 if (!finddpos(&tt, troom->lx, ty, troom->hx, ty))
399 return;
401 xx = cc.x;
402 yy = cc.y;
403 tx = tt.x - dx;
404 ty = tt.y - dy;
405 if (nxcor && levl[xx + dx][yy + dy].typ != STONE)
406 return;
407 if (okdoor(xx, yy) || !nxcor)
408 dodoor(xx, yy, croom);
410 org.x = xx + dx;
411 org.y = yy + dy;
412 dest.x = tx;
413 dest.y = ty;
415 if (!dig_corridor(&org, &dest, nxcor,
416 svl.level.flags.arboreal ? ROOM : CORR, STONE))
417 return;
419 /* we succeeded in digging the corridor */
420 if (okdoor(tt.x, tt.y) || !nxcor)
421 dodoor(tt.x, tt.y, troom);
423 if (gs.smeq[a] < gs.smeq[b])
424 gs.smeq[b] = gs.smeq[a];
425 else
426 gs.smeq[a] = gs.smeq[b];
429 /* create random corridors between rooms */
430 void
431 makecorridors(void)
433 int a, b, i;
434 boolean any = TRUE;
436 for (a = 0; a < svn.nroom - 1; a++) {
437 join(a, a + 1, FALSE);
438 if (!rn2(50))
439 break; /* allow some randomness */
441 for (a = 0; a < svn.nroom - 2; a++)
442 if (gs.smeq[a] != gs.smeq[a + 2])
443 join(a, a + 2, FALSE);
444 for (a = 0; any && a < svn.nroom; a++) {
445 any = FALSE;
446 for (b = 0; b < svn.nroom; b++)
447 if (gs.smeq[a] != gs.smeq[b]) {
448 join(a, b, FALSE);
449 any = TRUE;
452 /* add some extra corridors which may be blocked off */
453 if (svn.nroom > 2)
454 for (i = rn2(svn.nroom) + 4; i; i--) {
455 a = rn2(svn.nroom);
456 b = rn2(svn.nroom - 2);
457 if (b >= a)
458 b += 2;
459 join(a, b, TRUE);
463 /* (re)allocate space for svd.doors array */
464 staticfn void
465 alloc_doors(void)
467 if (!svd.doors || gd.doorindex >= svd.doors_alloc) {
468 int c = svd.doors_alloc + DOORINC;
469 coord *doortmp = (coord *) alloc(c * sizeof (coord));
471 (void) memset((genericptr_t) doortmp, 0, c * sizeof (coord));
472 if (svd.doors) {
473 (void) memcpy(doortmp, svd.doors,
474 svd.doors_alloc * sizeof (coord));
475 free(svd.doors);
477 svd.doors = doortmp;
478 svd.doors_alloc = c;
482 void
483 add_door(coordxy x, coordxy y, struct mkroom *aroom)
485 struct mkroom *broom;
486 int tmp;
487 int i;
489 alloc_doors();
491 if (aroom->doorct) {
492 for (i = 0; i < aroom->doorct; i++) {
493 tmp = aroom->fdoor + i;
494 if (svd.doors[tmp].x == x && svd.doors[tmp].y == y)
495 return;
499 if (aroom->doorct == 0)
500 aroom->fdoor = gd.doorindex;
502 aroom->doorct++;
504 for (tmp = gd.doorindex; tmp > aroom->fdoor; tmp--)
505 svd.doors[tmp] = svd.doors[tmp - 1];
507 for (i = 0; i < svn.nroom; i++) {
508 broom = &svr.rooms[i];
509 if (broom != aroom && broom->doorct && broom->fdoor >= aroom->fdoor)
510 broom->fdoor++;
512 for (i = 0; i < gn.nsubroom; i++) {
513 broom = &gs.subrooms[i];
514 if (broom != aroom && broom->doorct && broom->fdoor >= aroom->fdoor)
515 broom->fdoor++;
518 gd.doorindex++;
519 svd.doors[aroom->fdoor].x = x;
520 svd.doors[aroom->fdoor].y = y;
523 staticfn void
524 dosdoor(coordxy x, coordxy y, struct mkroom *aroom, int type)
526 boolean shdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE;
528 if (!IS_WALL(levl[x][y].typ)) /* avoid S.doors on already made doors */
529 type = DOOR;
530 levl[x][y].typ = type;
531 if (type == DOOR) {
532 if (!rn2(3)) { /* is it a locked door, closed, or a doorway? */
533 if (!rn2(5))
534 levl[x][y].doormask = D_ISOPEN;
535 else if (!rn2(6))
536 levl[x][y].doormask = D_LOCKED;
537 else
538 levl[x][y].doormask = D_CLOSED;
540 if (levl[x][y].doormask != D_ISOPEN && !shdoor
541 && level_difficulty() >= 5 && !rn2(25))
542 levl[x][y].doormask |= D_TRAPPED;
543 } else {
544 #ifdef STUPID
545 if (shdoor)
546 levl[x][y].doormask = D_ISOPEN;
547 else
548 levl[x][y].doormask = D_NODOOR;
549 #else
550 levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
551 #endif
554 /* also done in roguecorr(); doing it here first prevents
555 making mimics in place of trapped doors on rogue svl.level */
556 if (Is_rogue_level(&u.uz))
557 levl[x][y].doormask = D_NODOOR;
559 if (levl[x][y].doormask & D_TRAPPED) {
560 struct monst *mtmp;
562 if (level_difficulty() >= 9 && !rn2(5)
563 && !((svm.mvitals[PM_SMALL_MIMIC].mvflags & G_GONE)
564 && (svm.mvitals[PM_LARGE_MIMIC].mvflags & G_GONE)
565 && (svm.mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) {
566 /* make a mimic instead */
567 levl[x][y].doormask = D_NODOOR;
568 mtmp = makemon(mkclass(S_MIMIC, 0), x, y, NO_MM_FLAGS);
569 if (mtmp)
570 set_mimic_sym(mtmp);
573 /* newsym(x,y); */
574 } else { /* SDOOR */
575 if (shdoor || !rn2(5))
576 levl[x][y].doormask = D_LOCKED;
577 else
578 levl[x][y].doormask = D_CLOSED;
580 if (!shdoor && level_difficulty() >= 4 && !rn2(20))
581 levl[x][y].doormask |= D_TRAPPED;
584 add_door(x, y, aroom);
587 /* is x,y location such that NEWS direction from it is inside aroom,
588 excluding subrooms */
589 staticfn boolean
590 cardinal_nextto_room(struct mkroom *aroom, coordxy x, coordxy y)
592 int rmno = (int) ((aroom - svr.rooms) + ROOMOFFSET);
594 if (isok(x - 1, y) && !levl[x - 1][y].edge
595 && (int) levl[x - 1][y].roomno == rmno)
596 return TRUE;
597 if (isok(x + 1, y) && !levl[x + 1][y].edge
598 && (int) levl[x + 1][y].roomno == rmno)
599 return TRUE;
600 if (isok(x, y - 1) && !levl[x][y - 1].edge
601 && (int) levl[x][y - 1].roomno == rmno)
602 return TRUE;
603 if (isok(x, y + 1) && !levl[x][y + 1].edge
604 && (int) levl[x][y + 1].roomno == rmno)
605 return TRUE;
606 return FALSE;
609 staticfn boolean
610 place_niche(
611 struct mkroom *aroom,
612 int *dy,
613 coordxy *xx, coordxy *yy)
615 coord dd;
617 if (rn2(2)) {
618 *dy = 1;
619 if (!finddpos(&dd, aroom->lx, aroom->hy + 1,
620 aroom->hx, aroom->hy + 1))
621 return FALSE;
622 } else {
623 *dy = -1;
624 if (!finddpos(&dd, aroom->lx, aroom->ly - 1,
625 aroom->hx, aroom->ly - 1))
626 return FALSE;
628 *xx = dd.x;
629 *yy = dd.y;
630 return (boolean) ((isok(*xx, *yy + *dy)
631 && levl[*xx][*yy + *dy].typ == STONE)
632 && (isok(*xx, *yy - *dy)
633 && !IS_POOL(levl[*xx][*yy - *dy].typ)
634 && !IS_FURNITURE(levl[*xx][*yy - *dy].typ))
635 && cardinal_nextto_room(aroom, *xx, *yy));
638 /* there should be one of these per trap, in the same order as trap.h */
639 static NEARDATA const char *trap_engravings[TRAPNUM] = {
640 (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0,
641 (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0,
642 (char *) 0, (char *) 0, (char *) 0, (char *) 0,
643 /* 14..16: trap door, teleport, level-teleport */
644 "Vlad was here", "ad aerarium", "ad aerarium", (char *) 0, (char *) 0,
645 (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0,
646 /* 24..25 */
647 (char *) 0, (char *) 0,
650 staticfn void
651 makeniche(int trap_type)
653 struct mkroom *aroom;
654 struct rm *rm;
655 int dy, vct = 8;
656 coordxy xx, yy;
657 struct trap *ttmp;
659 while (vct--) {
660 aroom = &svr.rooms[rn2(svn.nroom)];
661 if (aroom->rtype != OROOM)
662 continue; /* not an ordinary room */
663 if (aroom->doorct == 1 && rn2(5))
664 continue;
665 if (!place_niche(aroom, &dy, &xx, &yy))
666 continue;
668 rm = &levl[xx][yy + dy];
669 if (trap_type || !rn2(4)) {
670 rm->typ = SCORR;
671 if (trap_type) {
672 if (is_hole(trap_type) && !Can_fall_thru(&u.uz))
673 trap_type = ROCKTRAP;
674 ttmp = maketrap(xx, yy + dy, trap_type);
675 if (ttmp) {
676 if (trap_type != ROCKTRAP)
677 ttmp->once = 1;
678 if (trap_engravings[trap_type]) {
679 make_engr_at(xx, yy - dy,
680 trap_engravings[trap_type], 0L,
681 DUST);
682 wipe_engr_at(xx, yy - dy, 5,
683 FALSE); /* age it a little */
687 dosdoor(xx, yy, aroom, SDOOR);
688 } else {
689 rm->typ = CORR;
690 if (rn2(7))
691 dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
692 else {
693 /* inaccessible niches occasionally have iron bars */
694 if (!rn2(5) && IS_WALL(levl[xx][yy].typ)) {
695 (void) set_levltyp(xx, yy, IRONBARS);
696 if (rn2(3))
697 (void) mkcorpstat(CORPSE, (struct monst *) 0,
698 mkclass(S_HUMAN, 0), xx,
699 yy + dy, TRUE);
701 if (!svl.level.flags.noteleport)
702 (void) mksobj_at(SCR_TELEPORTATION, xx, yy + dy, TRUE,
703 FALSE);
704 if (!rn2(3))
705 (void) mkobj_at(RANDOM_CLASS, xx, yy + dy, TRUE);
708 return;
712 staticfn void
713 make_niches(void)
715 int ct = rnd((svn.nroom >> 1) + 1), dep = depth(&u.uz);
716 boolean ltptr = (!svl.level.flags.noteleport && dep > 15),
717 vamp = (dep > 5 && dep < 25);
719 while (ct--) {
720 if (ltptr && !rn2(6)) {
721 ltptr = FALSE;
722 makeniche(LEVEL_TELEP);
723 } else if (vamp && !rn2(6)) {
724 vamp = FALSE;
725 makeniche(TRAPDOOR);
726 } else
727 makeniche(NO_TRAP);
731 staticfn void
732 makevtele(void)
734 makeniche(TELEP_TRAP);
737 /* count the tracked features (sinks, fountains) present on the level */
738 void
739 count_level_features(void)
741 coordxy x, y;
743 svl.level.flags.nfountains = svl.level.flags.nsinks = 0;
744 for (y = 0; y < ROWNO; y++)
745 for (x = 1; x < COLNO; x++) {
746 int typ = levl[x][y].typ;
748 if (typ == FOUNTAIN)
749 svl.level.flags.nfountains++;
750 else if (typ == SINK)
751 svl.level.flags.nsinks++;
755 /* clear out various globals that keep information on the current level.
756 * some of this is only necessary for some types of levels (maze, normal,
757 * special) but it's easier to put it all in one place than make sure
758 * each type initializes what it needs to separately.
760 void
761 clear_level_structures(void)
763 static struct rm zerorm = { GLYPH_UNEXPLORED,
764 0, 0, 0, 0, 0, 0, 0, 0, 0 };
765 coordxy x, y;
766 struct rm *lev;
768 /* note: normally we'd start at x=1 because map column #0 isn't used
769 (except for placing vault guard at <0,0> when removed from the map
770 but not from the level); explicitly reset column #0 along with the
771 rest so that we start the new level with a completely clean slate */
772 for (x = 0; x < COLNO; x++) {
773 lev = &levl[x][0];
774 for (y = 0; y < ROWNO; y++) {
775 *lev++ = zerorm;
776 svl.level.objects[x][y] = (struct obj *) 0;
777 svl.level.monsters[x][y] = (struct monst *) 0;
780 svl.level.objlist = (struct obj *) 0;
781 svl.level.buriedobjlist = (struct obj *) 0;
782 svl.level.monlist = (struct monst *) 0;
783 svl.level.damagelist = (struct damage *) 0;
784 svl.level.bonesinfo = (struct cemetery *) 0;
786 svl.level.flags.nfountains = 0;
787 svl.level.flags.nsinks = 0;
788 svl.level.flags.has_shop = 0;
789 svl.level.flags.has_vault = 0;
790 svl.level.flags.has_zoo = 0;
791 svl.level.flags.has_court = 0;
792 svl.level.flags.has_morgue = svl.level.flags.graveyard = 0;
793 svl.level.flags.has_beehive = 0;
794 svl.level.flags.has_barracks = 0;
795 svl.level.flags.has_temple = 0;
796 svl.level.flags.has_swamp = 0;
797 svl.level.flags.noteleport = 0;
798 svl.level.flags.hardfloor = 0;
799 svl.level.flags.nommap = 0;
800 svl.level.flags.hero_memory = 1;
801 svl.level.flags.shortsighted = 0;
802 svl.level.flags.sokoban_rules = 0;
803 svl.level.flags.is_maze_lev = 0;
804 svl.level.flags.is_cavernous_lev = 0;
805 svl.level.flags.arboreal = 0;
806 svl.level.flags.has_town = 0;
807 svl.level.flags.wizard_bones = 0;
808 svl.level.flags.corrmaze = 0;
809 svl.level.flags.temperature = In_hell(&u.uz) ? 1 : 0;
810 svl.level.flags.rndmongen = 1;
811 svl.level.flags.deathdrops = 1;
812 svl.level.flags.noautosearch = 0;
813 svl.level.flags.fumaroles = 0;
814 svl.level.flags.stormy = 0;
816 svn.nroom = 0;
817 svr.rooms[0].hx = -1;
818 gn.nsubroom = 0;
819 gs.subrooms[0].hx = -1;
820 gd.doorindex = 0;
821 if (svd.doors_alloc) {
822 free((genericptr_t) svd.doors);
823 svd.doors = (coord *) 0;
824 svd.doors_alloc = 0;
826 init_rect();
827 init_vault();
828 stairway_free_all();
829 gm.made_branch = FALSE;
830 clear_regions();
831 free_exclusions();
832 reset_xystart_size();
833 if (gl.lev_message) {
834 free(gl.lev_message);
835 gl.lev_message = (char *) 0;
839 #define ROOM_IS_FILLABLE(croom) \
840 ((croom->rtype == OROOM || croom->rtype == THEMEROOM) \
841 && croom->needfill == FILL_NORMAL)
843 /* Fill a "random" room (i.e. a typical non-special room in the Dungeons of
844 Doom) with random monsters, objects, and dungeon features.
846 If bonus_items is TRUE, there may be an additional special item
847 generated, depending on depth. */
848 staticfn void
849 fill_ordinary_room(
850 struct mkroom *croom,
851 boolean bonus_items)
853 int trycnt = 0;
854 coord pos;
855 struct monst *tmonst; /* always put a web with a spider */
856 coordxy x, y;
857 boolean skip_chests = FALSE;
859 if (croom->rtype != OROOM && croom->rtype != THEMEROOM)
860 return;
862 /* If there are subrooms, fill them now - we don't want an outer room
863 * that's specified to be unfilled to block an inner subroom that's
864 * specified to be filled. */
865 for (x = 0; x < croom->nsubrooms; ++x) {
866 struct mkroom *subroom = croom->sbrooms[x];
868 if (!subroom) {
869 impossible("fill_ordinary_room: Null subroom");
870 return;
872 fill_ordinary_room(subroom, FALSE);
875 if (croom->needfill != FILL_NORMAL)
876 return;
878 /* put a sleeping monster inside */
879 /* Note: monster may be on the stairs. This cannot be
880 avoided: maybe the player fell through a trap door
881 while a monster was on the stairs. Conclusion:
882 we have to check for monsters on the stairs anyway. */
884 if ((u.uhave.amulet || !rn2(3)) && somexyspace(croom, &pos)) {
885 tmonst = makemon((struct permonst *) 0, pos.x, pos.y, MM_NOGRP);
886 if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER]
887 && !occupied(pos.x, pos.y))
888 (void) maketrap(pos.x, pos.y, WEB);
890 /* put traps and mimics inside */
891 x = 8 - (level_difficulty() / 6);
892 if (x <= 1)
893 x = 2;
894 while (!rn2(x) && (++trycnt < 1000))
895 mktrap(0, MKTRAP_NOFLAGS, croom, (coord *) 0);
896 if (!rn2(3) && somexyspace(croom, &pos))
897 (void) mkgold(0L, pos.x, pos.y);
898 if (Is_rogue_level(&u.uz))
899 goto skip_nonrogue;
900 if (!rn2(10))
901 mkfount(croom);
902 if (!rn2(60))
903 mksink(croom);
904 if (!rn2(60))
905 mkaltar(croom);
906 x = 80 - (depth(&u.uz) * 2);
907 if (x < 2)
908 x = 2;
909 if (!rn2(x))
910 mkgrave(croom);
912 /* put statues inside */
913 if (!rn2(20) && somexyspace(croom, &pos))
914 (void) mkcorpstat(STATUE, (struct monst *) 0,
915 (struct permonst *) 0, pos.x,
916 pos.y, CORPSTAT_INIT);
919 * bonus_items means that this is the room where the bonus item
920 * should be placed, if there is one; but there might not be a
921 * bonus item on any given level.
923 * Bonus items are currently as follows:
924 * a) on the Mines branch level, 100% chance of a fairly filling
925 * comestible;
926 * b) on other levels above the Oracle, 2/3 chance of a "supply
927 * chest" that contains an early-game survivability item
928 * (there are therefore more of these when Sokoban is deep,
929 * which is intentional as those games are harder).
930 * This mechanism could be expanded in the future to place
931 * near-guaranteed items on particular levels (but, it is possible
932 * that no room will be given a bonus item if there is no suitable
933 * room to place it in, so it should not be used for plot-critical
934 * items).
936 if (bonus_items && somexyspace(croom, &pos)) {
937 branch *uz_branch = Is_branchlev(&u.uz);
939 if (uz_branch && u.uz.dnum != mines_dnum
940 && (uz_branch->end1.dnum == mines_dnum
941 || uz_branch->end2.dnum == mines_dnum)) {
942 (void) mksobj_at((rn2(5) < 3) ? FOOD_RATION
943 : rn2(2) ? CRAM_RATION
944 : LEMBAS_WAFER,
945 pos.x, pos.y, TRUE, FALSE);
946 } else if (u.uz.dnum == oracle_level.dnum
947 && u.uz.dlevel < oracle_level.dlevel && rn2(3)) {
948 struct obj *otmp;
949 int otyp, tryct = 0;
950 boolean cursed;
951 /* reverse probabilities compared to non-supply chests;
952 these are twice as likely to be chests than large
953 boxes, rather than vice versa */
954 struct obj *supply_chest = mksobj_at(rn2(3) ? CHEST : LARGE_BOX,
955 pos.x, pos.y, FALSE, FALSE);
957 supply_chest->olocked = !!(rn2(6));
959 do {
960 static const int supply_items[] = {
961 POT_EXTRA_HEALING,
962 POT_SPEED,
963 POT_GAIN_ENERGY,
964 SCR_ENCHANT_WEAPON,
965 SCR_ENCHANT_ARMOR,
966 SCR_CONFUSE_MONSTER,
967 SCR_SCARE_MONSTER,
968 WAN_DIGGING,
969 SPE_HEALING,
972 /* 50% this is a potion of healing */
973 otyp = rn2(2) ? POT_HEALING : ROLL_FROM(supply_items);
974 otmp = mksobj(otyp, TRUE, FALSE);
975 if (otyp == POT_HEALING && rn2(2)) {
976 otmp->quan = 2;
977 otmp->owt = weight(otmp);
979 cursed = otmp->cursed;
980 add_to_container(supply_chest, otmp); /* owt updated below */
982 ++tryct;
983 if (tryct == 50) {
984 impossible("couldn't generate supply chest item");
985 break;
987 /* guarantee at least one noncursed item, with a small
988 probability of more; if we generate a cursed item, it's
989 added to the supply chest but we reroll for a noncursed
990 item and add that too */
991 } while (cursed || !rn2(5));
993 /* maybe put a random item into the supply chest, biased
994 slightly towards low-level spellbooks; avoid tools
995 because chests don't fit into other chests */
996 if (rn2(3)) {
997 static const int extra_classes[] = {
998 FOOD_CLASS,
999 WEAPON_CLASS,
1000 ARMOR_CLASS,
1001 GEM_CLASS,
1002 SCROLL_CLASS,
1003 POTION_CLASS,
1004 RING_CLASS,
1005 SPBOOK_no_NOVEL,
1006 SPBOOK_no_NOVEL,
1007 SPBOOK_no_NOVEL
1009 int oclass = ROLL_FROM(extra_classes);
1011 otmp = mkobj(oclass, FALSE);
1012 if (oclass == SPBOOK_no_NOVEL) {
1013 int pass, maxpass = (depth(&u.uz) > 2) ? 2 : 3;
1015 /* bias towards lower level by generating again
1016 and taking the lower-level book; do that three
1017 times if on level 1 or 2, twice when deeper */
1018 for (pass = 1; pass <= maxpass; ++pass) {
1019 struct obj *otmp2 = mkobj(oclass, FALSE);
1021 if (objects[otmp->otyp].oc_level
1022 <= objects[otmp2->otyp].oc_level) {
1023 dealloc_obj(otmp2);
1024 } else {
1025 dealloc_obj(otmp);
1026 otmp = otmp2;
1030 add_to_container(supply_chest, otmp); /* owt updated below */
1033 /* add_to_container() doesn't update the container's weight */
1034 supply_chest->owt = weight(supply_chest);
1036 skip_chests = TRUE; /* don't want a second chest in this room */
1041 /* put box/chest inside;
1042 * 40% chance for at least 1 box, regardless of number
1043 * of rooms; about 5 - 7.5% for 2 boxes, least likely
1044 * when few rooms; chance for 3 or more is negligible.
1046 /*assert(svn.nroom > 0); // must be true because we're filling a room*/
1047 if (!skip_chests && !rn2(svn.nroom * 5 / 2) && somexyspace(croom, &pos))
1048 (void) mksobj_at(rn2(3) ? LARGE_BOX : CHEST,
1049 pos.x, pos.y, TRUE, FALSE);
1051 /* maybe make some graffiti */
1052 if (!rn2(27 + 3 * abs(depth(&u.uz)))) {
1053 char buf[BUFSZ];
1054 const char *mesg = random_engraving(buf);
1056 if (mesg) {
1057 do {
1058 (void) somexyspace(croom, &pos);
1059 x = pos.x;
1060 y = pos.y;
1061 } while (levl[x][y].typ != ROOM && !rn2(40));
1062 if (levl[x][y].typ == ROOM)
1063 make_engr_at(x, y, mesg, 0L, MARK);
1067 skip_nonrogue:
1068 if (!rn2(3) && somexyspace(croom, &pos)) {
1069 (void) mkobj_at(RANDOM_CLASS, pos.x, pos.y, TRUE);
1070 trycnt = 0;
1071 while (!rn2(5)) {
1072 if (++trycnt > 100) {
1073 impossible("trycnt overflow4");
1074 break;
1076 if (somexyspace(croom, &pos)) {
1077 (void) mkobj_at(RANDOM_CLASS, pos.x, pos.y, TRUE);
1083 staticfn void
1084 themerooms_post_level_generate(void)
1086 lua_State *themes = (lua_State *) gl.luathemes[u.uz.dnum];
1088 /* themes should already be loaded by makerooms();
1089 * if not, we don't run this either */
1090 if (!themes)
1091 return;
1093 reset_xystart_size();
1094 iflags.in_lua = gi.in_mk_themerooms = TRUE;
1095 gt.themeroom_failed = FALSE;
1096 lua_getglobal(themes, "post_level_generate");
1097 nhl_pcall_handle(themes, 0, 0, "post_level_generate", NHLpa_panic);
1098 iflags.in_lua = gi.in_mk_themerooms = FALSE;
1100 wallification(1, 0, COLNO - 1, ROWNO - 1);
1101 free(gc.coder);
1102 gc.coder = NULL;
1103 lua_gc(themes, LUA_GCCOLLECT);
1106 staticfn void
1107 makelevel(void)
1109 struct mkroom *croom;
1110 branch *branchp;
1111 stairway *prevstairs;
1112 int room_threshold;
1113 s_level *slev;
1114 int i;
1116 if (wiz1_level.dlevel == 0) {
1117 impossible("makelevel() called when dungeon not yet initialized.");
1118 init_dungeons();
1120 oinit(); /* assign level dependent obj probabilities */
1121 clear_level_structures();
1123 slev = Is_special(&u.uz);
1124 /* check for special levels */
1125 if (slev && !Is_rogue_level(&u.uz)) {
1126 makemaz(slev->proto);
1127 } else if (svd.dungeons[u.uz.dnum].proto[0]) {
1128 makemaz("");
1129 } else if (svd.dungeons[u.uz.dnum].fill_lvl[0]) {
1130 makemaz(svd.dungeons[u.uz.dnum].fill_lvl);
1131 } else if (In_quest(&u.uz)) {
1132 char fillname[9];
1133 s_level *loc_lev;
1135 Sprintf(fillname, "%s-loca", gu.urole.filecode);
1136 loc_lev = find_level(fillname);
1138 Sprintf(fillname, "%s-fil", gu.urole.filecode);
1139 Strcat(fillname,
1140 (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
1141 makemaz(fillname);
1142 } else if (In_hell(&u.uz)
1143 || (rn2(5) && u.uz.dnum == medusa_level.dnum
1144 && depth(&u.uz) > depth(&medusa_level))) {
1145 makemaz("");
1146 } else {
1147 /* otherwise, fall through - it's a "regular" level. */
1148 int u_depth = depth(&u.uz);
1150 if (Is_rogue_level(&u.uz)) {
1151 makeroguerooms();
1152 makerogueghost();
1153 } else {
1154 makerooms();
1156 assert(svn.nroom > 0);
1157 sort_rooms();
1159 generate_stairs(); /* up and down stairs */
1161 branchp = Is_branchlev(&u.uz); /* possible dungeon branch */
1162 room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed
1163 to allow a random special room */
1164 if (Is_rogue_level(&u.uz))
1165 goto skip0;
1166 makecorridors();
1167 make_niches();
1169 /* make a secret treasure vault, not connected to the rest */
1170 if (do_vault()) {
1171 coordxy w, h;
1173 debugpline0("trying to make a vault...");
1174 w = 1;
1175 h = 1;
1176 if (check_room(&gv.vault_x, &w, &gv.vault_y, &h, TRUE)) {
1177 fill_vault:
1178 add_room(gv.vault_x, gv.vault_y,
1179 gv.vault_x + w, gv.vault_y + h,
1180 TRUE, VAULT, FALSE);
1181 svl.level.flags.has_vault = 1;
1182 ++room_threshold;
1183 svr.rooms[svn.nroom - 1].needfill = FILL_NORMAL;
1184 fill_special_room(&svr.rooms[svn.nroom - 1]);
1185 mk_knox_portal(gv.vault_x + w, gv.vault_y + h);
1186 if (!svl.level.flags.noteleport && !rn2(3))
1187 makevtele();
1188 } else if (rnd_rect() && create_vault()) {
1189 gv.vault_x = svr.rooms[svn.nroom].lx;
1190 gv.vault_y = svr.rooms[svn.nroom].ly;
1191 if (check_room(&gv.vault_x, &w, &gv.vault_y, &h, TRUE))
1192 goto fill_vault;
1193 else
1194 svr.rooms[svn.nroom].hx = -1;
1198 /* make up to 1 special room, with type dependent on depth;
1199 note that mkroom doesn't guarantee a room gets created, and that
1200 this step only sets the room's rtype - it doesn't fill it yet. */
1201 if (wizard && nh_getenv("SHOPTYPE"))
1202 do_mkroom(SHOPBASE);
1203 else if (u_depth > 1 && u_depth < depth(&medusa_level)
1204 && svn.nroom >= room_threshold && rn2(u_depth) < 3)
1205 do_mkroom(SHOPBASE);
1206 else if (u_depth > 4 && !rn2(6))
1207 do_mkroom(COURT);
1208 else if (u_depth > 5 && !rn2(8)
1209 && !(svm.mvitals[PM_LEPRECHAUN].mvflags & G_GONE))
1210 do_mkroom(LEPREHALL);
1211 else if (u_depth > 6 && !rn2(7))
1212 do_mkroom(ZOO);
1213 else if (u_depth > 8 && !rn2(5))
1214 do_mkroom(TEMPLE);
1215 else if (u_depth > 9 && !rn2(5)
1216 && !(svm.mvitals[PM_KILLER_BEE].mvflags & G_GONE))
1217 do_mkroom(BEEHIVE);
1218 else if (u_depth > 11 && !rn2(6))
1219 do_mkroom(MORGUE);
1220 else if (u_depth > 12 && !rn2(8) && antholemon())
1221 do_mkroom(ANTHOLE);
1222 else if (u_depth > 14 && !rn2(4)
1223 && !(svm.mvitals[PM_SOLDIER].mvflags & G_GONE))
1224 do_mkroom(BARRACKS);
1225 else if (u_depth > 15 && !rn2(6))
1226 do_mkroom(SWAMP);
1227 else if (u_depth > 16 && !rn2(8)
1228 && !(svm.mvitals[PM_COCKATRICE].mvflags & G_GONE))
1229 do_mkroom(COCKNEST);
1231 skip0:
1232 prevstairs = gs.stairs; /* used to test for place_branch() success */
1233 /* Place multi-dungeon branch. */
1234 place_branch(branchp, 0, 0);
1236 /* for main dungeon level 1, the stairs up where the hero starts
1237 are branch stairs; treat them as if hero had just come down
1238 them by marking them as having been traversed; most recently
1239 created stairway is held in 'gs.stairs' */
1240 if (u.uz.dnum == 0 && u.uz.dlevel == 1 && gs.stairs != prevstairs)
1241 gs.stairs->u_traversed = TRUE;
1243 /* some levels have specially generated items in ordinary
1244 rooms (intended to be indistinguishable from the normally
1245 generated items); work out which room these will be placed in */
1246 int fillable_room_count = 0;
1247 for (croom = svr.rooms; croom->hx > 0; croom++) {
1248 if (ROOM_IS_FILLABLE(croom))
1249 fillable_room_count++;
1251 /* choose a random fillable room to be the one that gets the
1252 bonus items, if there are any; if there aren't any we don't
1253 generate the bonus items (but levels with no fillable rooms
1254 typically don't have any bonus items to generate anyway) */
1255 int bonus_item_room_countdown = fillable_room_count
1256 ? rn2(fillable_room_count) : -1;
1258 /* for each room: put things inside */
1259 for (croom = svr.rooms; croom->hx > 0; croom++) {
1260 boolean fillable = ROOM_IS_FILLABLE(croom);
1262 fill_ordinary_room(croom,
1263 fillable && bonus_item_room_countdown == 0);
1264 if (fillable)
1265 --bonus_item_room_countdown;
1268 /* Fill all special rooms now, regardless of whether this is a special
1269 * level, proto level, or ordinary level. */
1270 for (i = 0; i < svn.nroom; ++i) {
1271 fill_special_room(&svr.rooms[i]);
1274 themerooms_post_level_generate();
1276 if (gl.luacore && nhcb_counts[NHCB_LVL_ENTER]) {
1277 lua_getglobal(gl.luacore, "nh_callback_run");
1278 lua_pushstring(gl.luacore, nhcb_name[NHCB_LVL_ENTER]);
1279 nhl_pcall_handle(gl.luacore, 1, 0, "makelevel", NHLpa_panic);
1280 lua_settop(gl.luacore, 0);
1285 * Place deposits of minerals (gold and misc gems) in the stone
1286 * surrounding the rooms on the map.
1287 * Also place kelp in water.
1288 * mineralize(-1, -1, -1, -1, FALSE); => "default" behavior
1290 void
1291 mineralize(int kelp_pool, int kelp_moat, int goldprob, int gemprob,
1292 boolean skip_lvl_checks)
1294 s_level *sp;
1295 struct obj *otmp;
1296 coordxy x, y;
1297 int cnt;
1299 if (kelp_pool < 0)
1300 kelp_pool = 10;
1301 if (kelp_moat < 0)
1302 kelp_moat = 30;
1304 /* Place kelp, except on the plane of water */
1305 if (!skip_lvl_checks && In_endgame(&u.uz))
1306 return;
1307 for (x = 2; x < (COLNO - 2); x++)
1308 for (y = 1; y < (ROWNO - 1); y++)
1309 if ((kelp_pool && levl[x][y].typ == POOL && !rn2(kelp_pool))
1310 || (kelp_moat && levl[x][y].typ == MOAT && !rn2(kelp_moat)))
1311 (void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE);
1313 /* determine if it is even allowed;
1314 almost all special levels are excluded */
1315 if (!skip_lvl_checks
1316 && (In_hell(&u.uz) || In_V_tower(&u.uz) || Is_rogue_level(&u.uz)
1317 || svl.level.flags.arboreal
1318 || ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz)
1319 && (!In_mines(&u.uz) || sp->flags.town))))
1320 return;
1322 /* basic level-related probabilities */
1323 if (goldprob < 0)
1324 goldprob = 20 + depth(&u.uz) / 3;
1325 if (gemprob < 0)
1326 gemprob = goldprob / 4;
1328 /* mines have ***MORE*** goodies - otherwise why mine? */
1329 if (!skip_lvl_checks) {
1330 if (In_mines(&u.uz)) {
1331 goldprob *= 2;
1332 gemprob *= 3;
1333 } else if (In_quest(&u.uz)) {
1334 goldprob /= 4;
1335 gemprob /= 6;
1340 * Seed rock areas with gold and/or gems.
1341 * We use fairly low level object handling to avoid unnecessary
1342 * overhead from placing things in the floor chain prior to burial.
1344 for (x = 2; x < (COLNO - 2); x++)
1345 for (y = 1; y < (ROWNO - 1); y++)
1346 if (levl[x][y + 1].typ != STONE) { /* <x,y> spot not eligible */
1347 y += 2; /* next two spots aren't eligible either */
1348 } else if (levl[x][y].typ != STONE) { /* this spot not eligible */
1349 y += 1; /* next spot isn't eligible either */
1350 } else if (!(levl[x][y].wall_info & W_NONDIGGABLE)
1351 && levl[x][y - 1].typ == STONE
1352 && levl[x + 1][y - 1].typ == STONE
1353 && levl[x - 1][y - 1].typ == STONE
1354 && levl[x + 1][y].typ == STONE
1355 && levl[x - 1][y].typ == STONE
1356 && levl[x + 1][y + 1].typ == STONE
1357 && levl[x - 1][y + 1].typ == STONE) {
1358 if (rn2(1000) < goldprob) {
1359 if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) {
1360 otmp->ox = x, otmp->oy = y;
1361 otmp->quan = 1L + rnd(goldprob * 3);
1362 otmp->owt = weight(otmp);
1363 if (!rn2(3))
1364 add_to_buried(otmp);
1365 else
1366 place_object(otmp, x, y);
1369 if (rn2(1000) < gemprob) {
1370 for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--)
1371 if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) {
1372 if (otmp->otyp == ROCK) {
1373 dealloc_obj(otmp); /* discard it */
1374 } else {
1375 otmp->ox = x, otmp->oy = y;
1376 if (!rn2(3))
1377 add_to_buried(otmp);
1378 else
1379 place_object(otmp, x, y);
1386 void
1387 level_finalize_topology(void)
1389 struct mkroom *croom;
1390 int ridx;
1392 bound_digging();
1393 mineralize(-1, -1, -1, -1, FALSE);
1394 gi.in_mklev = FALSE;
1395 /* avoid coordinates in future lua-loads for this level being thrown off
1396 * because xstart and ystart aren't saved with the level and will be 0
1397 * after leaving and returning */
1398 gx.xstart = gy.ystart = 0;
1399 /* has_morgue gets cleared once morgue is entered; graveyard stays
1400 set (graveyard might already be set even when has_morgue is clear
1401 [see fixup_special()], so don't update it unconditionally) */
1402 if (svl.level.flags.has_morgue)
1403 svl.level.flags.graveyard = 1;
1404 if (!svl.level.flags.is_maze_lev) {
1405 for (croom = &svr.rooms[0]; croom != &svr.rooms[svn.nroom]; croom++)
1406 #ifdef SPECIALIZATION
1407 topologize(croom, FALSE);
1408 #else
1409 topologize(croom);
1410 #endif
1412 set_wall_state();
1413 /* for many room types, svr.rooms[].rtype is zeroed once the room has been
1414 entered; svr.rooms[].orig_rtype always retains original rtype value */
1415 for (ridx = 0; ridx < SIZE(svr.rooms); ridx++)
1416 svr.rooms[ridx].orig_rtype = svr.rooms[ridx].rtype;
1419 void
1420 mklev(void)
1422 reseed_random(rn2);
1423 reseed_random(rn2_on_display_rng);
1425 init_mapseen(&u.uz);
1426 if (getbones())
1427 return;
1429 gi.in_mklev = TRUE;
1430 makelevel();
1432 level_finalize_topology();
1434 reseed_random(rn2);
1435 reseed_random(rn2_on_display_rng);
1438 void
1439 #ifdef SPECIALIZATION
1440 topologize(struct mkroom *croom, boolean do_ordinary)
1441 #else
1442 topologize(struct mkroom *croom)
1443 #endif
1445 coordxy x, y;
1446 int roomno = (int) ((croom - svr.rooms) + ROOMOFFSET);
1447 coordxy lowx = croom->lx, lowy = croom->ly;
1448 coordxy hix = croom->hx, hiy = croom->hy;
1449 #ifdef SPECIALIZATION
1450 schar rtype = croom->rtype;
1451 #endif
1452 int subindex, nsubrooms = croom->nsubrooms;
1454 /* skip the room if already done; i.e. a shop handled out of order */
1455 /* also skip if this is non-rectangular (it _must_ be done already) */
1456 if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular)
1457 return;
1458 #ifdef SPECIALIZATION
1459 if (Is_rogue_level(&u.uz))
1460 do_ordinary = TRUE; /* vision routine helper */
1461 if ((rtype != OROOM) || do_ordinary)
1462 #endif
1464 /* do innards first */
1465 for (x = lowx; x <= hix; x++)
1466 for (y = lowy; y <= hiy; y++)
1467 #ifdef SPECIALIZATION
1468 if (rtype == OROOM)
1469 levl[x][y].roomno = NO_ROOM;
1470 else
1471 #endif
1472 levl[x][y].roomno = roomno;
1473 /* top and bottom edges */
1474 for (x = lowx - 1; x <= hix + 1; x++)
1475 for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) {
1476 levl[x][y].edge = 1;
1477 if (levl[x][y].roomno)
1478 levl[x][y].roomno = SHARED;
1479 else
1480 levl[x][y].roomno = roomno;
1482 /* sides */
1483 for (x = lowx - 1; x <= hix + 1; x += (hix - lowx + 2))
1484 for (y = lowy; y <= hiy; y++) {
1485 levl[x][y].edge = 1;
1486 if (levl[x][y].roomno)
1487 levl[x][y].roomno = SHARED;
1488 else
1489 levl[x][y].roomno = roomno;
1492 /* gs.subrooms */
1493 for (subindex = 0; subindex < nsubrooms; subindex++)
1494 #ifdef SPECIALIZATION
1495 topologize(croom->sbrooms[subindex], (boolean) (rtype != OROOM));
1496 #else
1497 topologize(croom->sbrooms[subindex]);
1498 #endif
1501 /* Find an unused room for a branch location. */
1502 staticfn struct mkroom *
1503 find_branch_room(coord *mp)
1505 struct mkroom *croom = 0;
1507 if (svn.nroom == 0) {
1508 mazexy(mp); /* already verifies location */
1509 } else {
1510 croom = generate_stairs_find_room();
1511 assert(croom != NULL); /* Null iff nroom==0 which won't get here */
1512 if (!somexyspace(croom, mp))
1513 impossible("Can't place branch!");
1515 return croom;
1518 /* Find the room for (x,y). Return null if not in a room. */
1519 staticfn struct mkroom *
1520 pos_to_room(coordxy x, coordxy y)
1522 int i;
1523 struct mkroom *curr;
1525 for (curr = svr.rooms, i = 0; i < svn.nroom; curr++, i++)
1526 if (inside_room(curr, x, y))
1527 return curr;
1529 return (struct mkroom *) 0;
1532 /* If given a branch, randomly place a special stair or portal. */
1533 void
1534 place_branch(
1535 branch *br, /* branch to place */
1536 coordxy x, coordxy y) /* location */
1538 coord m = {0};
1539 d_level *dest;
1540 boolean make_stairs;
1543 * Return immediately if there is no branch to make or we have
1544 * already made one. This routine can be called twice when
1545 * a special level is loaded that specifies an SSTAIR location
1546 * as a favored spot for a branch.
1548 if (!br || gm.made_branch)
1549 return;
1551 if (!x) { /* find random coordinates for branch */
1552 /* br_room = find_branch_room(&m); */
1553 (void) find_branch_room(&m); /* sets m via mazexy() or somexy() */
1554 x = m.x;
1555 y = m.y;
1556 } else {
1557 (void) pos_to_room(x, y);
1560 if (on_level(&br->end1, &u.uz)) {
1561 /* we're on end1 */
1562 make_stairs = br->type != BR_NO_END1;
1563 dest = &br->end2;
1564 } else {
1565 /* we're on end2 */
1566 make_stairs = br->type != BR_NO_END2;
1567 dest = &br->end1;
1570 if (br->type == BR_PORTAL) {
1571 if (iflags.debug_fuzzer && (u.ucamefrom.dnum || u.ucamefrom.dlevel))
1572 mkportal(x, y, u.ucamefrom.dnum, u.ucamefrom.dlevel);
1573 else
1574 mkportal(x, y, dest->dnum, dest->dlevel);
1575 } else if (make_stairs) {
1576 boolean goes_up = on_level(&br->end1, &u.uz) ? br->end1_up
1577 : !br->end1_up;
1579 stairway_add(x, y, goes_up, FALSE, dest);
1580 (void) set_levltyp(x, y, STAIRS);
1581 levl[x][y].ladder = goes_up ? LA_UP : LA_DOWN;
1584 * Set made_branch to TRUE even if we didn't make a stairwell (i.e.
1585 * make_stairs is false) since there is currently only one branch
1586 * per level, if we failed once, we're going to fail again on the
1587 * next call.
1589 gm.made_branch = TRUE;
1592 staticfn boolean
1593 bydoor(coordxy x, coordxy y)
1595 int typ;
1597 if (isok(x + 1, y)) {
1598 typ = levl[x + 1][y].typ;
1599 if (IS_DOOR(typ) || typ == SDOOR)
1600 return TRUE;
1602 if (isok(x - 1, y)) {
1603 typ = levl[x - 1][y].typ;
1604 if (IS_DOOR(typ) || typ == SDOOR)
1605 return TRUE;
1607 if (isok(x, y + 1)) {
1608 typ = levl[x][y + 1].typ;
1609 if (IS_DOOR(typ) || typ == SDOOR)
1610 return TRUE;
1612 if (isok(x, y - 1)) {
1613 typ = levl[x][y - 1].typ;
1614 if (IS_DOOR(typ) || typ == SDOOR)
1615 return TRUE;
1617 return FALSE;
1620 /* see whether it is allowable to create a door at [x,y] */
1622 okdoor(coordxy x, coordxy y)
1624 boolean near_door = bydoor(x, y);
1626 return ((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL)
1627 && ((isok(x - 1, y) && !IS_OBSTRUCTED(levl[x - 1][y].typ))
1628 || (isok(x + 1, y) && !IS_OBSTRUCTED(levl[x + 1][y].typ))
1629 || (isok(x, y - 1) && !IS_OBSTRUCTED(levl[x][y - 1].typ))
1630 || (isok(x, y + 1) && !IS_OBSTRUCTED(levl[x][y + 1].typ)))
1631 && !near_door);
1634 /* do we want a secret door/corridor? */
1635 boolean
1636 maybe_sdoor(int chance)
1638 return (depth(&u.uz) > 2) && !rn2(max(2, chance));
1641 /* create a door at x,y in room aroom */
1642 void
1643 dodoor(coordxy x, coordxy y, struct mkroom *aroom)
1645 dosdoor(x, y, aroom, maybe_sdoor(8) ? SDOOR : DOOR);
1648 boolean
1649 occupied(coordxy x, coordxy y)
1651 return (boolean) (t_at(x, y) || IS_FURNITURE(levl[x][y].typ)
1652 || is_lava(x, y) || is_pool(x, y)
1653 || invocation_pos(x, y));
1656 /* generate a corpse and some items on top of a trap */
1657 staticfn void
1658 mktrap_victim(struct trap *ttmp)
1660 /* Object generated by the trap; initially NULL, stays NULL if
1661 we fail to generate an object or if the trap doesn't
1662 generate objects. */
1663 struct obj *otmp = NULL;
1664 int victim_mnum; /* race of the victim */
1665 unsigned lvl = level_difficulty();
1666 int kind = ttmp->ttyp;
1667 coordxy x = ttmp->tx, y = ttmp->ty;
1669 assert(x > 0 && x < COLNO && y >= 0 && y < ROWNO);
1670 /* Not all trap types have special handling here; only the ones
1671 that kill in a specific way that's obvious after the fact. */
1672 switch (kind) {
1673 case ARROW_TRAP:
1674 otmp = mksobj(ARROW, TRUE, FALSE);
1675 otmp->opoisoned = 0;
1676 /* don't adjust the quantity; maybe the trap shot multiple
1677 times, there was an untrapping attempt, etc... */
1678 break;
1679 case DART_TRAP:
1680 otmp = mksobj(DART, TRUE, FALSE);
1681 break;
1682 case ROCKTRAP:
1683 otmp = mksobj(ROCK, TRUE, FALSE);
1684 break;
1685 default:
1686 /* no item dropped by the trap */
1687 break;
1689 if (otmp) {
1690 place_object(otmp, x, y);
1693 /* now otmp is reused for other items we're placing */
1695 /* Place a random possession. This could be a weapon, tool,
1696 food, or gem, i.e. the item classes that are typically
1697 nonmagical and not worthless. */
1698 do {
1699 int poss_class = RANDOM_CLASS; /* init => lint suppression */
1701 switch (rn2(4)) {
1702 case 0:
1703 poss_class = WEAPON_CLASS;
1704 break;
1705 case 1:
1706 poss_class = TOOL_CLASS;
1707 break;
1708 case 2:
1709 poss_class = FOOD_CLASS;
1710 break;
1711 case 3:
1712 poss_class = GEM_CLASS;
1713 break;
1716 otmp = mkobj(poss_class, FALSE);
1717 /* these items are always cursed, both for flavour (owned
1718 by a dead adventurer, bones-pile-style) and for balance
1719 (less useful to use, and encourage pets to avoid the trap) */
1720 if (otmp) {
1721 otmp->blessed = 0;
1722 otmp->cursed = 1;
1723 otmp->owt = weight(otmp);
1724 place_object(otmp, x, y);
1727 /* 20% chance of placing an additional item, recursively */
1728 } while (!rn2(5));
1730 /* Place a corpse. */
1731 switch (rn2(15)) {
1732 case 0:
1733 /* elf corpses are the rarest as they're the most useful */
1734 victim_mnum = PM_ELF;
1735 /* elven adventurers get sleep resistance early; so don't
1736 generate elf corpses on sleeping gas traps unless a)
1737 we're on dlvl 2 (1 is impossible) and b) we pass a coin
1738 flip */
1739 if (kind == SLP_GAS_TRAP && !(lvl <= 2 && rn2(2)))
1740 victim_mnum = PM_HUMAN;
1741 break;
1742 case 1: case 2:
1743 victim_mnum = PM_DWARF;
1744 break;
1745 case 3: case 4: case 5:
1746 victim_mnum = PM_ORC;
1747 break;
1748 case 6: case 7: case 8: case 9:
1749 /* more common as they could have come from the Mines */
1750 victim_mnum = PM_GNOME;
1751 /* 10% chance of a candle too */
1752 if (!rn2(10)) {
1753 otmp = mksobj(rn2(4) ? TALLOW_CANDLE : WAX_CANDLE, TRUE, FALSE);
1754 otmp->quan = 1;
1755 otmp->owt = weight(otmp);
1756 curse(otmp);
1757 place_object(otmp, x, y);
1758 if (!levl[x][y].lit)
1759 begin_burn(otmp, FALSE);
1761 break;
1762 default:
1763 /* human is the most common result */
1764 victim_mnum = PM_HUMAN;
1765 break;
1767 /* PM_HUMAN is a placeholder monster primarily used for zombie, mummy,
1768 and vampire corpses; usually change it into a fake player monster
1769 instead (always human); no role-specific equipment is provided */
1770 if (victim_mnum == PM_HUMAN && rn2(25))
1771 victim_mnum = rn1(PM_WIZARD - PM_ARCHEOLOGIST, PM_ARCHEOLOGIST);
1772 otmp = mkcorpstat(CORPSE, NULL, &mons[victim_mnum], x, y, CORPSTAT_INIT);
1773 otmp->age -= (TAINT_AGE + 1); /* died too long ago to safely eat */
1776 /* pick a random trap type, return NO_TRAP if "too hard" */
1777 staticfn int
1778 traptype_rnd(unsigned mktrapflags)
1780 unsigned lvl = level_difficulty();
1781 int kind = rnd(TRAPNUM - 1);
1783 switch (kind) {
1784 /* these are controlled by the feature or object they guard,
1785 not by the map so mustn't be created on it */
1786 case TRAPPED_DOOR:
1787 case TRAPPED_CHEST:
1788 kind = NO_TRAP;
1789 break;
1790 /* these can have a random location but can't be generated
1791 randomly */
1792 case MAGIC_PORTAL:
1793 case VIBRATING_SQUARE:
1794 kind = NO_TRAP;
1795 break;
1796 case ROLLING_BOULDER_TRAP:
1797 case SLP_GAS_TRAP:
1798 if (lvl < 2)
1799 kind = NO_TRAP;
1800 break;
1801 case LEVEL_TELEP:
1802 if (lvl < 5 || svl.level.flags.noteleport
1803 || single_level_branch(&u.uz))
1804 kind = NO_TRAP;
1805 break;
1806 case SPIKED_PIT:
1807 if (lvl < 5)
1808 kind = NO_TRAP;
1809 break;
1810 case LANDMINE:
1811 if (lvl < 6)
1812 kind = NO_TRAP;
1813 break;
1814 case WEB:
1815 if (lvl < 7 && !(mktrapflags & MKTRAP_NOSPIDERONWEB))
1816 kind = NO_TRAP;
1817 break;
1818 case STATUE_TRAP:
1819 case POLY_TRAP:
1820 if (lvl < 8)
1821 kind = NO_TRAP;
1822 break;
1823 case FIRE_TRAP:
1824 if (!Inhell)
1825 kind = NO_TRAP;
1826 break;
1827 case TELEP_TRAP:
1828 if (svl.level.flags.noteleport)
1829 kind = NO_TRAP;
1830 break;
1831 case HOLE:
1832 /* make these much less often than other traps */
1833 if (rn2(7))
1834 kind = NO_TRAP;
1835 break;
1837 return kind;
1840 /* random trap type for the Rogue level */
1841 staticfn int
1842 traptype_roguelvl(void)
1844 int kind;
1846 switch (rn2(7)) {
1847 default:
1848 kind = BEAR_TRAP;
1849 break; /* 0 */
1850 case 1:
1851 kind = ARROW_TRAP;
1852 break;
1853 case 2:
1854 kind = DART_TRAP;
1855 break;
1856 case 3:
1857 kind = TRAPDOOR;
1858 break;
1859 case 4:
1860 kind = PIT;
1861 break;
1862 case 5:
1863 kind = SLP_GAS_TRAP;
1864 break;
1865 case 6:
1866 kind = RUST_TRAP;
1867 break;
1869 return kind;
1872 /* mktrap(): select trap type and location, then use maketrap() to create it;
1873 make it at location 'tm' when that isn't Null, otherwise in 'croom'
1874 if mktrapflags doesn't have MKTRAP_MAZEFLAG set, else in maze corridor */
1875 void
1876 mktrap(
1877 int num, /* if non-zero, specific type of trap to make */
1878 unsigned mktrapflags, /* MKTRAP_{SEEN,MAZEFLAG,NOSPIDERONWEB,NOVICTIM} */
1879 struct mkroom *croom, /* room to hold trap */
1880 coord *tm) /* specific location for trap */
1882 static int mktrap_err = 0; /* move to struct g? */
1883 struct trap *t;
1884 coord m;
1885 int kind;
1886 unsigned lvl = level_difficulty();
1888 if (!tm && !croom && !(mktrapflags & MKTRAP_MAZEFLAG)) {
1889 /* complain when the combination of arguments will never set 'm' */
1890 if (!mktrap_err++) {
1891 char errbuf[BUFSZ];
1893 Snprintf(errbuf, sizeof errbuf,
1894 "args (%d,%d,%s,%s) are invalid",
1895 num, mktrapflags, "null room", "null location");
1896 paniclog("mktrap", errbuf);
1898 return;
1900 m.x = m.y = 0;
1902 /* no traps in pools */
1903 if (tm && is_pool(tm->x, tm->y))
1904 return;
1906 if (num > NO_TRAP && num < TRAPNUM) {
1907 kind = num;
1908 } else if (Is_rogue_level(&u.uz)) {
1909 kind = traptype_roguelvl();
1910 } else if (Inhell && !rn2(5)) {
1911 /* bias the frequency of fire traps in Gehennom */
1912 kind = FIRE_TRAP;
1913 } else {
1914 do {
1915 kind = traptype_rnd(mktrapflags);
1916 } while (kind == NO_TRAP);
1919 if (is_hole(kind) && !Can_fall_thru(&u.uz))
1920 kind = ROCKTRAP;
1922 if (tm) {
1923 m = *tm;
1924 } else {
1925 int tryct = 0;
1926 boolean avoid_boulder = (is_pit(kind) || is_hole(kind));
1928 do {
1929 if (++tryct > 200)
1930 return;
1931 if ((mktrapflags & MKTRAP_MAZEFLAG) != 0)
1932 mazexy(&m);
1933 else if (croom && !somexyspace(croom, &m))
1934 return;
1935 } while (occupied(m.x, m.y)
1936 || (avoid_boulder && sobj_at(BOULDER, m.x, m.y)));
1939 t = maketrap(m.x, m.y, kind);
1940 /* we should always get type of trap we're asking for (occupied() test
1941 should prevent cases where that might not happen) but be paranoid */
1942 kind = t ? t->ttyp : NO_TRAP;
1944 if (kind == WEB && !(mktrapflags & MKTRAP_NOSPIDERONWEB))
1945 (void) makemon(&mons[PM_GIANT_SPIDER], m.x, m.y, NO_MM_FLAGS);
1946 if (t && (mktrapflags & MKTRAP_SEEN))
1947 t->tseen = TRUE;
1948 if (kind == MAGIC_PORTAL && (u.ucamefrom.dnum || u.ucamefrom.dlevel)) {
1949 assign_level(&t->dst, &u.ucamefrom);
1952 /* The hero isn't the only person who's entered the dungeon in
1953 search of treasure. On the very shallowest levels, there's a
1954 chance that a created trap will have killed something already
1955 (and this is guaranteed on the first level).
1957 This isn't meant to give any meaningful treasure (in fact, any
1958 items we drop here are typically cursed, other than ammo fired
1959 by the trap). Rather, it's mostly just for flavour and to give
1960 players on very early levels a sufficient chance to avoid traps
1961 that may end up killing them before they have a fair chance to
1962 build max HP. Including cursed items gives the same fair chance
1963 to the starting pet, and fits the rule that possessions of the
1964 dead are normally cursed.
1966 Some types of traps are excluded because they're entirely
1967 nonlethal, even indirectly. We also exclude all of the
1968 later/fancier traps because they tend to have special
1969 considerations (e.g. webs, portals), often are indirectly
1970 lethal, and tend not to generate on shallower levels anyway
1971 (exception: magic traps can generate on dlvl 1 and be
1972 immediately lethal). Finally, pits are excluded because it's
1973 weird to see an item in a pit and yet not be able to identify
1974 that the pit is there. */
1975 if (kind != NO_TRAP && !(mktrapflags & MKTRAP_NOVICTIM)
1976 && lvl <= (unsigned) rnd(4)
1977 && kind != SQKY_BOARD && kind != RUST_TRAP
1978 /* rolling boulder trap might not have a boulder if there was no
1979 viable path (such as when placed in the corner of a room), in
1980 which case tx,ty==launch.x,y; no boulder => no dead predecessor */
1981 && !(kind == ROLLING_BOULDER_TRAP
1982 && t->launch.x == t->tx && t->launch.y == t->ty)
1983 && !is_pit(kind) && (kind < HOLE || kind == MAGIC_TRAP)) {
1984 mktrap_victim(t);
1988 /* Create stairs up or down at x,y.
1989 If force is TRUE, change the terrain to ROOM first */
1990 void
1991 mkstairs(
1992 coordxy x, coordxy y,
1993 char up, /* [why 'char' when usage is boolean?] */
1994 struct mkroom *croom UNUSED,
1995 boolean force)
1997 int ltyp;
1998 d_level dest;
2000 if (!x || !isok(x, y)) {
2001 impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y);
2002 return;
2004 if (force)
2005 levl[x][y].typ = ROOM;
2006 ltyp = levl[x][y].typ; /* somexyspace() allows ice */
2007 if (ltyp != ROOM && ltyp != CORR && ltyp != ICE) {
2008 int glyph = back_to_glyph(x, y),
2009 sidx = glyph_to_cmap(glyph);
2011 impossible("mkstairs: placing stairs %s on %s at <%d,%d>",
2012 up ? "up" : "down", defsyms[sidx].explanation, x, y);
2016 * We can't make a regular stair off an end of the dungeon. This
2017 * attempt can happen when a special level is placed at an end and
2018 * has an up or down stair specified in its description file.
2020 if (dunlev(&u.uz) == (up ? 1 : dunlevs_in_dungeon(&u.uz)))
2021 return;
2023 dest.dnum = u.uz.dnum;
2024 dest.dlevel = u.uz.dlevel + (up ? -1 : 1);
2025 stairway_add(x, y, up ? TRUE : FALSE, FALSE, &dest);
2027 (void) set_levltyp(x, y, STAIRS);
2028 levl[x][y].ladder = up ? LA_UP : LA_DOWN;
2031 /* is room a good one to generate up or down stairs in? */
2032 staticfn boolean
2033 generate_stairs_room_good(struct mkroom *croom, int phase)
2036 * phase values, smaller allows for more relaxed criteria:
2037 * 2 == no relaxed criteria;
2038 * 1 == allow a themed room;
2039 * 0 == allow same room as existing up/downstairs;
2040 * -1 == allow an unjoined room.
2042 return (croom && (croom->needjoining || (phase < 0))
2043 && ((!has_dnstairs(croom) && !has_upstairs(croom))
2044 || phase < 1)
2045 && (croom->rtype == OROOM
2046 || ((phase < 2) && croom->rtype == THEMEROOM)));
2049 /* find a good room to generate an up or down stairs in */
2050 staticfn struct mkroom *
2051 generate_stairs_find_room(void)
2053 struct mkroom *croom;
2054 int i, phase, ai;
2055 int *rmarr;
2057 if (!svn.nroom)
2058 return (struct mkroom *) 0;
2060 rmarr = (int *) alloc(sizeof(int) * svn.nroom);
2062 for (phase = 2; phase > -1; phase--) {
2063 ai = 0;
2064 for (i = 0; i < svn.nroom; i++)
2065 if (generate_stairs_room_good(&svr.rooms[i], phase))
2066 rmarr[ai++] = i;
2067 if (ai > 0) {
2068 i = rmarr[rn2(ai)];
2069 free(rmarr);
2070 return &svr.rooms[i];
2074 free(rmarr);
2075 croom = &svr.rooms[rn2(svn.nroom)];
2076 return croom;
2079 /* construct stairs up and down within the same branch,
2080 up and down in different rooms if possible */
2081 staticfn void
2082 generate_stairs(void)
2084 /* generate_stairs_find_room() returns Null if nroom == 0, but that
2085 should never happen for a rooms+corridors style level */
2086 static const char
2087 gen_stairs_panic[] = "generate_stairs: failed to find a room! (%d)";
2088 struct mkroom *croom;
2089 coord pos;
2091 if (!Is_botlevel(&u.uz)) {
2092 if ((croom = generate_stairs_find_room()) == NULL)
2093 panic(gen_stairs_panic, svn.nroom);
2095 if (!somexyspace(croom, &pos)) {
2096 pos.x = somex(croom);
2097 pos.y = somey(croom);
2099 mkstairs(pos.x, pos.y, 0, croom, FALSE); /* down */
2102 if (u.uz.dlevel != 1) {
2103 /* if there is only 1 room and we found it above, this will find
2104 it again */
2105 if ((croom = generate_stairs_find_room()) == NULL)
2106 panic(gen_stairs_panic, svn.nroom);
2108 if (!somexyspace(croom, &pos)) {
2109 pos.x = somex(croom);
2110 pos.y = somey(croom);
2112 mkstairs(pos.x, pos.y, 1, croom, FALSE); /* up */
2116 staticfn void
2117 mkfount(struct mkroom *croom)
2119 coord m;
2121 if (!find_okay_roompos(croom, &m))
2122 return;
2124 /* Put a fountain at m.x, m.y */
2125 if (!set_levltyp(m.x, m.y, FOUNTAIN))
2126 return;
2127 /* Is it a "blessed" fountain? (affects drinking from fountain) */
2128 if (!rn2(7))
2129 levl[m.x][m.y].blessedftn = 1;
2131 svl.level.flags.nfountains++;
2134 staticfn boolean
2135 find_okay_roompos(struct mkroom *croom, coord *crd)
2137 int tryct = 0;
2139 do {
2140 if (++tryct > 200)
2141 return FALSE;
2142 if (!somexyspace(croom, crd))
2143 return FALSE;
2144 } while (occupied(crd->x, crd->y) || bydoor(crd->x, crd->y));
2145 return TRUE;
2148 staticfn void
2149 mksink(struct mkroom *croom)
2151 coord m;
2153 if (!find_okay_roompos(croom, &m))
2154 return;
2156 /* Put a sink at m.x, m.y */
2157 if (!set_levltyp(m.x, m.y, SINK))
2158 return;
2160 svl.level.flags.nsinks++;
2163 staticfn void
2164 mkaltar(struct mkroom *croom)
2166 coord m;
2167 aligntyp al;
2169 if (croom->rtype != OROOM)
2170 return;
2172 if (!find_okay_roompos(croom, &m))
2173 return;
2175 /* Put an altar at m.x, m.y */
2176 if (!set_levltyp(m.x, m.y, ALTAR))
2177 return;
2179 /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
2180 al = rn2((int) A_LAWFUL + 2) - 1;
2181 levl[m.x][m.y].altarmask = Align2amask(al);
2184 staticfn void
2185 mkgrave(struct mkroom *croom)
2187 coord m;
2188 int tryct = 0;
2189 struct obj *otmp;
2190 boolean dobell = !rn2(10);
2192 if (croom->rtype != OROOM)
2193 return;
2195 if (!find_okay_roompos(croom, &m))
2196 return;
2198 /* Put a grave at <m.x,m.y> */
2199 make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0);
2201 /* Possibly fill it with objects */
2202 if (!rn2(3)) {
2203 /* this used to use mkgold(), which puts a stack of gold on
2204 the ground (or merges it with an existing one there if
2205 present), and didn't bother burying it; now we create a
2206 loose, easily buriable, stack but we make no attempt to
2207 replicate mkgold()'s level-based formula for the amount */
2208 struct obj *gold = mksobj(GOLD_PIECE, TRUE, FALSE);
2210 gold->quan = (long) (rnd(20) + level_difficulty() * rnd(5));
2211 gold->owt = weight(gold);
2212 gold->ox = m.x, gold->oy = m.y;
2213 add_to_buried(gold);
2215 for (tryct = rn2(5); tryct; tryct--) {
2216 otmp = mkobj(RANDOM_CLASS, TRUE);
2217 if (!otmp)
2218 return;
2219 curse(otmp);
2220 otmp->ox = m.x;
2221 otmp->oy = m.y;
2222 add_to_buried(otmp);
2225 /* Leave a bell, in case we accidentally buried someone alive */
2226 if (dobell)
2227 (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE);
2228 return;
2232 * Major level transmutation: add a set of stairs (to the Sanctum) after
2233 * an earthquake that leaves behind a new topology, centered at inv_pos.
2234 * Assumes there are no rooms within the invocation area and that svi.inv_pos
2235 * is not too close to the edge of the map. Also assume the hero can see,
2236 * which is guaranteed for normal play due to the fact that sight is needed
2237 * to read the Book of the Dead. [That assumption is not valid; it is
2238 * possible that "the Book reads the hero" rather than vice versa if
2239 * attempted while blind (in order to make blind-from-birth conduct viable).]
2241 void
2242 mkinvokearea(void)
2244 int dist, wallct;
2245 coordxy xmin, xmax, ymin, ymax;
2246 coordxy i;
2248 /* slightly odd if levitating, but not wrong */
2249 pline_The("floor shakes violently under you!");
2250 /* decide whether to issue the crumbling walls message */
2252 xmin = xmax = svi.inv_pos.x;
2253 ymin = ymax = svi.inv_pos.y;
2254 wallct = mkinvk_check_wall(xmin, ymin);
2255 /* this replicates the somewhat convoluted loop below, working
2256 out from the stair position, except for stopping early when
2257 walls are found */
2258 for (dist = 1; !wallct && dist < 7; ++dist) {
2259 xmin--, xmax++;
2260 /* top and bottom */
2261 if (dist != 3) { /* the area is wider that it is high */
2262 ymin--, ymax++;
2263 for (i = xmin + 1; i < xmax; i++) {
2264 if (mkinvk_check_wall(i, ymin))
2265 ++wallct; /* we could break after finding first wall
2266 * but it isn't a significant optimization
2267 * for code which only executes once */
2268 if (mkinvk_check_wall(i, ymax))
2269 ++wallct;
2272 /* left and right */
2273 if (!wallct) { /* skip y loop if x loop found any walls */
2274 for (i = ymin; i <= ymax; i++) {
2275 if (mkinvk_check_wall(xmin, i))
2276 ++wallct;
2277 if (mkinvk_check_wall(xmax, i))
2278 ++wallct;
2282 /* message won't appear if the maze 'walls' on this level are lava
2283 or if all the walls within range have been dug away; when it does
2284 appear, it will describe iron bars as "walls" (which is ok) */
2285 if (wallct)
2286 pline_The("walls around you begin to bend and crumble!");
2288 display_nhwindow(WIN_MESSAGE, TRUE);
2290 /* any trap hero is stuck in will be going away now */
2291 if (u.utrap) {
2292 if (u.utraptype == TT_BURIEDBALL)
2293 buried_ball_to_punishment();
2294 reset_utrap(FALSE);
2297 xmin = xmax = svi.inv_pos.x; /* reset after the check for walls */
2298 ymin = ymax = svi.inv_pos.y;
2299 mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */
2301 for (dist = 1; dist < 7; dist++) {
2302 xmin--;
2303 xmax++;
2305 /* top and bottom */
2306 if (dist != 3) { /* the area is wider that it is high */
2307 ymin--;
2308 ymax++;
2309 for (i = xmin + 1; i < xmax; i++) {
2310 mkinvpos(i, ymin, dist);
2311 mkinvpos(i, ymax, dist);
2315 /* left and right */
2316 for (i = ymin; i <= ymax; i++) {
2317 mkinvpos(xmin, i, dist);
2318 mkinvpos(xmax, i, dist);
2321 flush_screen(1); /* make sure the new glyphs shows up */
2322 nh_delay_output();
2325 You("are standing at the top of a stairwell leading down!");
2326 mkstairs(u.ux, u.uy, 0, (struct mkroom *) 0, FALSE); /* down */
2327 newsym(u.ux, u.uy);
2328 gv.vision_full_recalc = 1; /* everything changed */
2331 /* Change level topology. Boulders in the vicinity are eliminated.
2332 * Temporarily overrides vision in the name of a nice effect.
2334 staticfn void
2335 mkinvpos(coordxy x, coordxy y, int dist)
2337 struct trap *ttmp;
2338 struct obj *otmp;
2339 boolean make_rocks;
2340 struct rm *lev = &levl[x][y];
2341 struct monst *mon;
2342 /* maze levels have slightly different constraints from normal levels;
2343 these are also defined in mkmaze.c and may not be appropriate for
2344 mazes with corridors wider than 1 or for cavernous levels */
2345 #define x_maze_min 2
2346 #define y_maze_min 2
2348 /* clip at existing map borders if necessary */
2349 if (!within_bounded_area(x, y, x_maze_min, y_maze_min,
2350 gx.x_maze_max, gy.y_maze_max)) {
2351 /* outermost 2 columns and/or rows may be truncated due to edge */
2352 if (dist < (7 - 2)) { /* panic() or impossible() */
2353 void (*errfunc)(const char *, ...) PRINTF_F(1, 2);
2355 errfunc = !isok(x, y) ? panic : impossible;
2356 (*errfunc)("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist);
2358 return;
2361 /* clear traps */
2362 if ((ttmp = t_at(x, y)) != 0)
2363 deltrap(ttmp);
2365 /* clear boulders; leave some rocks for non-{moat|trap} locations */
2366 make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE;
2367 while ((otmp = sobj_at(BOULDER, x, y)) != 0) {
2368 if (make_rocks) {
2369 fracture_rock(otmp);
2370 make_rocks = FALSE; /* don't bother with more rocks */
2371 } else {
2372 obj_extract_self(otmp);
2373 obfree(otmp, (struct obj *) 0);
2377 /* fake out saved state */
2378 lev->seenv = 0;
2379 lev->doormask = 0;
2380 if (dist < 6)
2381 lev->lit = TRUE;
2382 lev->waslit = TRUE;
2383 lev->horizontal = FALSE;
2384 /* short-circuit vision recalc */
2385 gv.viz_array[y][x] = (dist < 6) ? (IN_SIGHT | COULD_SEE) : COULD_SEE;
2387 switch (dist) {
2388 case 1: /* fire traps */
2389 if (is_pool(x, y))
2390 break;
2391 lev->typ = ROOM;
2392 ttmp = maketrap(x, y, FIRE_TRAP);
2393 if (ttmp)
2394 ttmp->tseen = TRUE;
2395 break;
2396 case 0: /* lit room locations */
2397 case 2:
2398 case 3:
2399 case 6: /* unlit room locations */
2400 lev->typ = ROOM;
2401 break;
2402 case 4: /* pools (aka a wide moat) */
2403 case 5:
2404 lev->typ = MOAT;
2405 /* No kelp! */
2406 break;
2407 default:
2408 impossible("mkinvpos called with dist %d", dist);
2409 break;
2412 if ((mon = m_at(x, y)) != 0) {
2413 /* wake up mimics, don't want to deal with them blocking vision */
2414 if (mon->m_ap_type)
2415 seemimic(mon);
2417 if ((ttmp = t_at(x, y)) != 0)
2418 (void) mintrap(mon, NO_TRAP_FLAGS);
2419 else
2420 (void) minliquid(mon);
2423 if (!does_block(x, y, lev))
2424 unblock_point(x, y); /* make sure vision knows location is open */
2426 /* display new value of position; could have a monster/object on it */
2427 newsym(x, y);
2428 #undef x_maze_min
2429 #undef y_maze_min
2432 /* reduces clutter in mkinvokearea() while avoiding potential static analyzer
2433 confusion about using isok(x,y) to control access to levl[x][y] */
2434 staticfn int
2435 mkinvk_check_wall(coordxy x, coordxy y)
2437 unsigned ltyp;
2439 if (!isok(x, y))
2440 return 0;
2441 assert(x > 0 && x < COLNO);
2442 assert(y >= 0 && y < ROWNO);
2443 ltyp = levl[x][y].typ;
2444 return (IS_STWALL(ltyp) || ltyp == IRONBARS) ? 1 : 0;
2448 * The portal to Ludios is special. The entrance can only occur within a
2449 * vault in the main dungeon at a depth greater than 10. The Ludios branch
2450 * structure reflects this by having a bogus "source" dungeon: the value
2451 * of n_dgns (thus, Is_branchlev() will never find it).
2453 * Ludios will remain isolated until the branch is corrected by this function.
2455 staticfn void
2456 mk_knox_portal(coordxy x, coordxy y)
2458 d_level *source;
2459 branch *br;
2460 schar u_depth;
2462 br = dungeon_branch("Fort Ludios");
2463 /* dungeon_branch() panics (so never returns) if result would be Null */
2464 assert(br != NULL);
2466 if (on_level(&knox_level, &br->end1)) {
2467 source = &br->end2;
2468 } else {
2469 /* disallow Knox branch on a level with one branch already */
2470 if (Is_branchlev(&u.uz))
2471 return;
2472 source = &br->end1;
2475 /* Already set or 2/3 chance of deferring until a later level. */
2476 if (source->dnum < svn.n_dgns || (rn2(3) && !wizard))
2477 return;
2479 if (!(u.uz.dnum == oracle_level.dnum /* in main dungeon */
2480 && !at_dgn_entrance("The Quest") /* but not Quest's entry */
2481 && (u_depth = depth(&u.uz)) > 10 /* beneath 10 */
2482 && u_depth < depth(&medusa_level))) /* and above Medusa */
2483 return;
2485 /* Adjust source to be current level and re-insert branch. */
2486 *source = u.uz;
2487 insert_branch(br, TRUE);
2489 debugpline0("Made knox portal.");
2490 place_branch(br, x, y);
2493 /*mklev.c*/