dumplog message history groundwork
[aNetHack.git] / src / mklev.c
blob6fd50f7fe0ffc4311096c8323d5254013ffc60a3
1 /* NetHack 3.6 mklev.c $NHDT-Date: 1446191876 2015/10/30 07:57:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.44 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 /* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
8 /* croom->lx etc are schar (width <= int), so % arith ensures that */
9 /* conversion of result to int is reasonable */
11 STATIC_DCL void FDECL(mkfount, (int, struct mkroom *));
12 STATIC_DCL void FDECL(mksink, (struct mkroom *));
13 STATIC_DCL void FDECL(mkaltar, (struct mkroom *));
14 STATIC_DCL void FDECL(mkgrave, (struct mkroom *));
15 STATIC_DCL void NDECL(makevtele);
16 STATIC_DCL void NDECL(clear_level_structures);
17 STATIC_DCL void NDECL(makelevel);
18 STATIC_DCL boolean FDECL(bydoor, (XCHAR_P, XCHAR_P));
19 STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *));
20 STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P));
21 STATIC_DCL boolean FDECL(place_niche, (struct mkroom *, int *, int *, int *));
22 STATIC_DCL void FDECL(makeniche, (int));
23 STATIC_DCL void NDECL(make_niches);
24 STATIC_PTR int FDECL(CFDECLSPEC do_comp, (const genericptr,
25 const genericptr));
26 STATIC_DCL void FDECL(dosdoor, (XCHAR_P, XCHAR_P, struct mkroom *, int));
27 STATIC_DCL void FDECL(join, (int, int, BOOLEAN_P));
28 STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *, int, int,
29 int, int, BOOLEAN_P,
30 SCHAR_P, BOOLEAN_P, BOOLEAN_P));
31 STATIC_DCL void NDECL(makerooms);
32 STATIC_DCL void FDECL(finddpos, (coord *, XCHAR_P, XCHAR_P,
33 XCHAR_P, XCHAR_P));
34 STATIC_DCL void FDECL(mkinvpos, (XCHAR_P, XCHAR_P, int));
35 STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P, XCHAR_P));
37 #define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
38 #define init_vault() vault_x = -1
39 #define do_vault() (vault_x != -1)
40 static xchar vault_x, vault_y;
41 static boolean made_branch; /* used only during level creation */
43 /* Args must be (const genericptr) so that qsort will always be happy. */
45 STATIC_PTR int CFDECLSPEC
46 do_comp(vx, vy)
47 const genericptr vx;
48 const genericptr vy;
50 #ifdef LINT
51 /* lint complains about possible pointer alignment problems, but we know
52 that vx and vy are always properly aligned. Hence, the following
53 bogus definition:
55 return (vx == vy) ? 0 : -1;
56 #else
57 register 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);
64 #endif /* LINT */
67 STATIC_OVL void
68 finddpos(cc, xl, yl, xh, yh)
69 coord *cc;
70 xchar xl, yl, xh, yh;
72 register xchar x, y;
74 x = rn1(xh - xl + 1, xl);
75 y = rn1(yh - yl + 1, yl);
76 if (okdoor(x, y))
77 goto gotit;
79 for (x = xl; x <= xh; x++)
80 for (y = yl; y <= yh; y++)
81 if (okdoor(x, y))
82 goto gotit;
84 for (x = xl; x <= xh; x++)
85 for (y = yl; y <= yh; y++)
86 if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
87 goto gotit;
88 /* cannot find something reasonable -- strange */
89 x = xl;
90 y = yh;
91 gotit:
92 cc->x = x;
93 cc->y = y;
94 return;
97 void
98 sort_rooms()
100 #if defined(SYSV) || defined(DGUX)
101 qsort((genericptr_t) rooms, (unsigned) nroom, sizeof(struct mkroom),
102 do_comp);
103 #else
104 qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp);
105 #endif
108 STATIC_OVL void
109 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room)
110 register struct mkroom *croom;
111 int lowx, lowy;
112 register int hix, hiy;
113 boolean lit;
114 schar rtype;
115 boolean special;
116 boolean is_room;
118 register int x, y;
119 struct rm *lev;
121 /* locations might bump level edges in wall-less rooms */
122 /* add/subtract 1 to allow for edge locations */
123 if (!lowx)
124 lowx++;
125 if (!lowy)
126 lowy++;
127 if (hix >= COLNO - 1)
128 hix = COLNO - 2;
129 if (hiy >= ROWNO - 1)
130 hiy = ROWNO - 2;
132 if (lit) {
133 for (x = lowx - 1; x <= hix + 1; x++) {
134 lev = &levl[x][max(lowy - 1, 0)];
135 for (y = lowy - 1; y <= hiy + 1; y++)
136 lev++->lit = 1;
138 croom->rlit = 1;
139 } else
140 croom->rlit = 0;
142 croom->lx = lowx;
143 croom->hx = hix;
144 croom->ly = lowy;
145 croom->hy = hiy;
146 croom->rtype = rtype;
147 croom->doorct = 0;
148 /* if we're not making a vault, doorindex will still be 0
149 * if we are, we'll have problems adding niches to the previous room
150 * unless fdoor is at least doorindex
152 croom->fdoor = doorindex;
153 croom->irregular = FALSE;
155 croom->nsubrooms = 0;
156 croom->sbrooms[0] = (struct mkroom *) 0;
157 if (!special) {
158 for (x = lowx - 1; x <= hix + 1; x++)
159 for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) {
160 levl[x][y].typ = HWALL;
161 levl[x][y].horizontal = 1; /* For open/secret doors. */
163 for (x = lowx - 1; x <= hix + 1; x += (hix - lowx + 2))
164 for (y = lowy; y <= hiy; y++) {
165 levl[x][y].typ = VWALL;
166 levl[x][y].horizontal = 0; /* For open/secret doors. */
168 for (x = lowx; x <= hix; x++) {
169 lev = &levl[x][lowy];
170 for (y = lowy; y <= hiy; y++)
171 lev++->typ = ROOM;
173 if (is_room) {
174 levl[lowx - 1][lowy - 1].typ = TLCORNER;
175 levl[hix + 1][lowy - 1].typ = TRCORNER;
176 levl[lowx - 1][hiy + 1].typ = BLCORNER;
177 levl[hix + 1][hiy + 1].typ = BRCORNER;
178 } else { /* a subroom */
179 wallification(lowx - 1, lowy - 1, hix + 1, hiy + 1);
184 void
185 add_room(lowx, lowy, hix, hiy, lit, rtype, special)
186 int lowx, lowy, hix, hiy;
187 boolean lit;
188 schar rtype;
189 boolean special;
191 register struct mkroom *croom;
193 croom = &rooms[nroom];
194 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special,
195 (boolean) TRUE);
196 croom++;
197 croom->hx = -1;
198 nroom++;
201 void
202 add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special)
203 struct mkroom *proom;
204 int lowx, lowy, hix, hiy;
205 boolean lit;
206 schar rtype;
207 boolean special;
209 register struct mkroom *croom;
211 croom = &subrooms[nsubroom];
212 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special,
213 (boolean) FALSE);
214 proom->sbrooms[proom->nsubrooms++] = croom;
215 croom++;
216 croom->hx = -1;
217 nsubroom++;
220 STATIC_OVL void
221 makerooms()
223 boolean tried_vault = FALSE;
225 /* make rooms until satisfied */
226 /* rnd_rect() will returns 0 if no more rects are available... */
227 while (nroom < MAXNROFROOMS && rnd_rect()) {
228 if (nroom >= (MAXNROFROOMS / 6) && rn2(2) && !tried_vault) {
229 tried_vault = TRUE;
230 if (create_vault()) {
231 vault_x = rooms[nroom].lx;
232 vault_y = rooms[nroom].ly;
233 rooms[nroom].hx = -1;
235 } else if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
236 return;
238 return;
241 STATIC_OVL void
242 join(a, b, nxcor)
243 register int a, b;
244 boolean nxcor;
246 coord cc, tt, org, dest;
247 register xchar tx, ty, xx, yy;
248 register struct mkroom *croom, *troom;
249 register int dx, dy;
251 croom = &rooms[a];
252 troom = &rooms[b];
254 /* find positions cc and tt for doors in croom and troom
255 and direction for a corridor between them */
257 if (troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX)
258 return;
259 if (troom->lx > croom->hx) {
260 dx = 1;
261 dy = 0;
262 xx = croom->hx + 1;
263 tx = troom->lx - 1;
264 finddpos(&cc, xx, croom->ly, xx, croom->hy);
265 finddpos(&tt, tx, troom->ly, tx, troom->hy);
266 } else if (troom->hy < croom->ly) {
267 dy = -1;
268 dx = 0;
269 yy = croom->ly - 1;
270 finddpos(&cc, croom->lx, yy, croom->hx, yy);
271 ty = troom->hy + 1;
272 finddpos(&tt, troom->lx, ty, troom->hx, ty);
273 } else if (troom->hx < croom->lx) {
274 dx = -1;
275 dy = 0;
276 xx = croom->lx - 1;
277 tx = troom->hx + 1;
278 finddpos(&cc, xx, croom->ly, xx, croom->hy);
279 finddpos(&tt, tx, troom->ly, tx, troom->hy);
280 } else {
281 dy = 1;
282 dx = 0;
283 yy = croom->hy + 1;
284 ty = troom->ly - 1;
285 finddpos(&cc, croom->lx, yy, croom->hx, yy);
286 finddpos(&tt, troom->lx, ty, troom->hx, ty);
288 xx = cc.x;
289 yy = cc.y;
290 tx = tt.x - dx;
291 ty = tt.y - dy;
292 if (nxcor && levl[xx + dx][yy + dy].typ)
293 return;
294 if (okdoor(xx, yy) || !nxcor)
295 dodoor(xx, yy, croom);
297 org.x = xx + dx;
298 org.y = yy + dy;
299 dest.x = tx;
300 dest.y = ty;
302 if (!dig_corridor(&org, &dest, nxcor, level.flags.arboreal ? ROOM : CORR,
303 STONE))
304 return;
306 /* we succeeded in digging the corridor */
307 if (okdoor(tt.x, tt.y) || !nxcor)
308 dodoor(tt.x, tt.y, troom);
310 if (smeq[a] < smeq[b])
311 smeq[b] = smeq[a];
312 else
313 smeq[a] = smeq[b];
316 void
317 makecorridors()
319 int a, b, i;
320 boolean any = TRUE;
322 for (a = 0; a < nroom - 1; a++) {
323 join(a, a + 1, FALSE);
324 if (!rn2(50))
325 break; /* allow some randomness */
327 for (a = 0; a < nroom - 2; a++)
328 if (smeq[a] != smeq[a + 2])
329 join(a, a + 2, FALSE);
330 for (a = 0; any && a < nroom; a++) {
331 any = FALSE;
332 for (b = 0; b < nroom; b++)
333 if (smeq[a] != smeq[b]) {
334 join(a, b, FALSE);
335 any = TRUE;
338 if (nroom > 2)
339 for (i = rn2(nroom) + 4; i; i--) {
340 a = rn2(nroom);
341 b = rn2(nroom - 2);
342 if (b >= a)
343 b += 2;
344 join(a, b, TRUE);
348 void
349 add_door(x, y, aroom)
350 register int x, y;
351 register struct mkroom *aroom;
353 register struct mkroom *broom;
354 register int tmp;
355 int i;
357 if (aroom->doorct == 0)
358 aroom->fdoor = doorindex;
360 aroom->doorct++;
362 for (tmp = doorindex; tmp > aroom->fdoor; tmp--)
363 doors[tmp] = doors[tmp - 1];
365 for (i = 0; i < nroom; i++) {
366 broom = &rooms[i];
367 if (broom != aroom && broom->doorct && broom->fdoor >= aroom->fdoor)
368 broom->fdoor++;
370 for (i = 0; i < nsubroom; i++) {
371 broom = &subrooms[i];
372 if (broom != aroom && broom->doorct && broom->fdoor >= aroom->fdoor)
373 broom->fdoor++;
376 doorindex++;
377 doors[aroom->fdoor].x = x;
378 doors[aroom->fdoor].y = y;
381 STATIC_OVL void
382 dosdoor(x, y, aroom, type)
383 register xchar x, y;
384 struct mkroom *aroom;
385 int type;
387 boolean shdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE;
389 if (!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */
390 type = DOOR;
391 levl[x][y].typ = type;
392 if (type == DOOR) {
393 if (!rn2(3)) { /* is it a locked door, closed, or a doorway? */
394 if (!rn2(5))
395 levl[x][y].doormask = D_ISOPEN;
396 else if (!rn2(6))
397 levl[x][y].doormask = D_LOCKED;
398 else
399 levl[x][y].doormask = D_CLOSED;
401 if (levl[x][y].doormask != D_ISOPEN && !shdoor
402 && level_difficulty() >= 5 && !rn2(25))
403 levl[x][y].doormask |= D_TRAPPED;
404 } else {
405 #ifdef STUPID
406 if (shdoor)
407 levl[x][y].doormask = D_ISOPEN;
408 else
409 levl[x][y].doormask = D_NODOOR;
410 #else
411 levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
412 #endif
415 /* also done in roguecorr(); doing it here first prevents
416 making mimics in place of trapped doors on rogue level */
417 if (Is_rogue_level(&u.uz))
418 levl[x][y].doormask = D_NODOOR;
420 if (levl[x][y].doormask & D_TRAPPED) {
421 struct monst *mtmp;
423 if (level_difficulty() >= 9 && !rn2(5)
424 && !((mvitals[PM_SMALL_MIMIC].mvflags & G_GONE)
425 && (mvitals[PM_LARGE_MIMIC].mvflags & G_GONE)
426 && (mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) {
427 /* make a mimic instead */
428 levl[x][y].doormask = D_NODOOR;
429 mtmp = makemon(mkclass(S_MIMIC, 0), x, y, NO_MM_FLAGS);
430 if (mtmp)
431 set_mimic_sym(mtmp);
434 /* newsym(x,y); */
435 } else { /* SDOOR */
436 if (shdoor || !rn2(5))
437 levl[x][y].doormask = D_LOCKED;
438 else
439 levl[x][y].doormask = D_CLOSED;
441 if (!shdoor && level_difficulty() >= 4 && !rn2(20))
442 levl[x][y].doormask |= D_TRAPPED;
445 add_door(x, y, aroom);
448 STATIC_OVL boolean
449 place_niche(aroom, dy, xx, yy)
450 register struct mkroom *aroom;
451 int *dy, *xx, *yy;
453 coord dd;
455 if (rn2(2)) {
456 *dy = 1;
457 finddpos(&dd, aroom->lx, aroom->hy + 1, aroom->hx, aroom->hy + 1);
458 } else {
459 *dy = -1;
460 finddpos(&dd, aroom->lx, aroom->ly - 1, aroom->hx, aroom->ly - 1);
462 *xx = dd.x;
463 *yy = dd.y;
464 return (boolean) ((isok(*xx, *yy + *dy)
465 && levl[*xx][*yy + *dy].typ == STONE)
466 && (isok(*xx, *yy - *dy)
467 && !IS_POOL(levl[*xx][*yy - *dy].typ)
468 && !IS_FURNITURE(levl[*xx][*yy - *dy].typ)));
471 /* there should be one of these per trap, in the same order as trap.h */
472 static NEARDATA const char *trap_engravings[TRAPNUM] = {
473 (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0,
474 (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0,
475 (char *) 0, (char *) 0, (char *) 0, (char *) 0,
476 /* 14..16: trap door, teleport, level-teleport */
477 "Vlad was here", "ad aerarium", "ad aerarium", (char *) 0, (char *) 0,
478 (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0,
481 STATIC_OVL void
482 makeniche(trap_type)
483 int trap_type;
485 register struct mkroom *aroom;
486 struct rm *rm;
487 int vct = 8;
488 int dy, xx, yy;
489 struct trap *ttmp;
491 if (doorindex < DOORMAX) {
492 while (vct--) {
493 aroom = &rooms[rn2(nroom)];
494 if (aroom->rtype != OROOM)
495 continue; /* not an ordinary room */
496 if (aroom->doorct == 1 && rn2(5))
497 continue;
498 if (!place_niche(aroom, &dy, &xx, &yy))
499 continue;
501 rm = &levl[xx][yy + dy];
502 if (trap_type || !rn2(4)) {
503 rm->typ = SCORR;
504 if (trap_type) {
505 if ((trap_type == HOLE || trap_type == TRAPDOOR)
506 && !Can_fall_thru(&u.uz))
507 trap_type = ROCKTRAP;
508 ttmp = maketrap(xx, yy + dy, trap_type);
509 if (ttmp) {
510 if (trap_type != ROCKTRAP)
511 ttmp->once = 1;
512 if (trap_engravings[trap_type]) {
513 make_engr_at(xx, yy - dy,
514 trap_engravings[trap_type], 0L,
515 DUST);
516 wipe_engr_at(xx, yy - dy, 5,
517 FALSE); /* age it a little */
521 dosdoor(xx, yy, aroom, SDOOR);
522 } else {
523 rm->typ = CORR;
524 if (rn2(7))
525 dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
526 else {
527 /* inaccessible niches occasionally have iron bars */
528 if (!rn2(5) && IS_WALL(levl[xx][yy].typ)) {
529 levl[xx][yy].typ = IRONBARS;
530 if (rn2(3))
531 (void) mkcorpstat(CORPSE, (struct monst *) 0,
532 mkclass(S_HUMAN, 0), xx,
533 yy + dy, TRUE);
535 if (!level.flags.noteleport)
536 (void) mksobj_at(SCR_TELEPORTATION, xx, yy + dy, TRUE,
537 FALSE);
538 if (!rn2(3))
539 (void) mkobj_at(0, xx, yy + dy, TRUE);
542 return;
547 STATIC_OVL void
548 make_niches()
550 int ct = rnd((nroom >> 1) + 1), dep = depth(&u.uz);
551 boolean ltptr = (!level.flags.noteleport && dep > 15),
552 vamp = (dep > 5 && dep < 25);
554 while (ct--) {
555 if (ltptr && !rn2(6)) {
556 ltptr = FALSE;
557 makeniche(LEVEL_TELEP);
558 } else if (vamp && !rn2(6)) {
559 vamp = FALSE;
560 makeniche(TRAPDOOR);
561 } else
562 makeniche(NO_TRAP);
566 STATIC_OVL void
567 makevtele()
569 makeniche(TELEP_TRAP);
572 /* clear out various globals that keep information on the current level.
573 * some of this is only necessary for some types of levels (maze, normal,
574 * special) but it's easier to put it all in one place than make sure
575 * each type initializes what it needs to separately.
577 STATIC_OVL void
578 clear_level_structures()
580 static struct rm zerorm = { cmap_to_glyph(S_stone),
581 0, 0, 0, 0, 0, 0, 0, 0, 0 };
582 register int x, y;
583 register struct rm *lev;
585 for (x = 0; x < COLNO; x++) {
586 lev = &levl[x][0];
587 for (y = 0; y < ROWNO; y++) {
588 *lev++ = zerorm;
590 * These used to be '#if MICROPORT_BUG',
591 * with use of memset(0) for '#if !MICROPORT_BUG' below,
592 * but memset is not appropriate for initializing pointers,
593 * so do these level.objects[][] and level.monsters[][]
594 * initializations unconditionally.
596 level.objects[x][y] = (struct obj *) 0;
597 level.monsters[x][y] = (struct monst *) 0;
600 level.objlist = (struct obj *) 0;
601 level.buriedobjlist = (struct obj *) 0;
602 level.monlist = (struct monst *) 0;
603 level.damagelist = (struct damage *) 0;
604 level.bonesinfo = (struct cemetery *) 0;
606 level.flags.nfountains = 0;
607 level.flags.nsinks = 0;
608 level.flags.has_shop = 0;
609 level.flags.has_vault = 0;
610 level.flags.has_zoo = 0;
611 level.flags.has_court = 0;
612 level.flags.has_morgue = level.flags.graveyard = 0;
613 level.flags.has_beehive = 0;
614 level.flags.has_barracks = 0;
615 level.flags.has_temple = 0;
616 level.flags.has_swamp = 0;
617 level.flags.noteleport = 0;
618 level.flags.hardfloor = 0;
619 level.flags.nommap = 0;
620 level.flags.hero_memory = 1;
621 level.flags.shortsighted = 0;
622 level.flags.sokoban_rules = 0;
623 level.flags.is_maze_lev = 0;
624 level.flags.is_cavernous_lev = 0;
625 level.flags.arboreal = 0;
626 level.flags.wizard_bones = 0;
627 level.flags.corrmaze = 0;
629 nroom = 0;
630 rooms[0].hx = -1;
631 nsubroom = 0;
632 subrooms[0].hx = -1;
633 doorindex = 0;
634 init_rect();
635 init_vault();
636 xdnstair = ydnstair = xupstair = yupstair = 0;
637 sstairs.sx = sstairs.sy = 0;
638 xdnladder = ydnladder = xupladder = yupladder = 0;
639 made_branch = FALSE;
640 clear_regions();
643 STATIC_OVL void
644 makelevel()
646 register struct mkroom *croom, *troom;
647 register int tryct;
648 register int x, y;
649 struct monst *tmonst; /* always put a web with a spider */
650 branch *branchp;
651 int room_threshold;
653 if (wiz1_level.dlevel == 0)
654 init_dungeons();
655 oinit(); /* assign level dependent obj probabilities */
656 clear_level_structures();
659 register s_level *slev = Is_special(&u.uz);
661 /* check for special levels */
662 if (slev && !Is_rogue_level(&u.uz)) {
663 makemaz(slev->proto);
664 return;
665 } else if (dungeons[u.uz.dnum].proto[0]) {
666 makemaz("");
667 return;
668 } else if (In_mines(&u.uz)) {
669 makemaz("minefill");
670 return;
671 } else if (In_quest(&u.uz)) {
672 char fillname[9];
673 s_level *loc_lev;
675 Sprintf(fillname, "%s-loca", urole.filecode);
676 loc_lev = find_level(fillname);
678 Sprintf(fillname, "%s-fil", urole.filecode);
679 Strcat(fillname,
680 (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
681 makemaz(fillname);
682 return;
683 } else if (In_hell(&u.uz)
684 || (rn2(5) && u.uz.dnum == medusa_level.dnum
685 && depth(&u.uz) > depth(&medusa_level))) {
686 makemaz("");
687 return;
691 /* otherwise, fall through - it's a "regular" level. */
693 if (Is_rogue_level(&u.uz)) {
694 makeroguerooms();
695 makerogueghost();
696 } else
697 makerooms();
698 sort_rooms();
700 /* construct stairs (up and down in different rooms if possible) */
701 croom = &rooms[rn2(nroom)];
702 if (!Is_botlevel(&u.uz))
703 mkstairs(somex(croom), somey(croom), 0, croom); /* down */
704 if (nroom > 1) {
705 troom = croom;
706 croom = &rooms[rn2(nroom - 1)];
707 if (croom == troom)
708 croom++;
711 if (u.uz.dlevel != 1) {
712 xchar sx, sy;
713 do {
714 sx = somex(croom);
715 sy = somey(croom);
716 } while (occupied(sx, sy));
717 mkstairs(sx, sy, 1, croom); /* up */
720 branchp = Is_branchlev(&u.uz); /* possible dungeon branch */
721 room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed
722 to allow a random special room */
723 if (Is_rogue_level(&u.uz))
724 goto skip0;
725 makecorridors();
726 make_niches();
728 /* make a secret treasure vault, not connected to the rest */
729 if (do_vault()) {
730 xchar w, h;
731 debugpline0("trying to make a vault...");
732 w = 1;
733 h = 1;
734 if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) {
735 fill_vault:
736 add_room(vault_x, vault_y, vault_x + w, vault_y + h, TRUE, VAULT,
737 FALSE);
738 level.flags.has_vault = 1;
739 ++room_threshold;
740 fill_room(&rooms[nroom - 1], FALSE);
741 mk_knox_portal(vault_x + w, vault_y + h);
742 if (!level.flags.noteleport && !rn2(3))
743 makevtele();
744 } else if (rnd_rect() && create_vault()) {
745 vault_x = rooms[nroom].lx;
746 vault_y = rooms[nroom].ly;
747 if (check_room(&vault_x, &w, &vault_y, &h, TRUE))
748 goto fill_vault;
749 else
750 rooms[nroom].hx = -1;
755 register int u_depth = depth(&u.uz);
757 if (wizard && nh_getenv("SHOPTYPE"))
758 mkroom(SHOPBASE);
759 else if (u_depth > 1 && u_depth < depth(&medusa_level)
760 && nroom >= room_threshold && rn2(u_depth) < 3)
761 mkroom(SHOPBASE);
762 else if (u_depth > 4 && !rn2(6))
763 mkroom(COURT);
764 else if (u_depth > 5 && !rn2(8)
765 && !(mvitals[PM_LEPRECHAUN].mvflags & G_GONE))
766 mkroom(LEPREHALL);
767 else if (u_depth > 6 && !rn2(7))
768 mkroom(ZOO);
769 else if (u_depth > 8 && !rn2(5))
770 mkroom(TEMPLE);
771 else if (u_depth > 9 && !rn2(5)
772 && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE))
773 mkroom(BEEHIVE);
774 else if (u_depth > 11 && !rn2(6))
775 mkroom(MORGUE);
776 else if (u_depth > 12 && !rn2(8) && antholemon())
777 mkroom(ANTHOLE);
778 else if (u_depth > 14 && !rn2(4)
779 && !(mvitals[PM_SOLDIER].mvflags & G_GONE))
780 mkroom(BARRACKS);
781 else if (u_depth > 15 && !rn2(6))
782 mkroom(SWAMP);
783 else if (u_depth > 16 && !rn2(8)
784 && !(mvitals[PM_COCKATRICE].mvflags & G_GONE))
785 mkroom(COCKNEST);
788 skip0:
789 /* Place multi-dungeon branch. */
790 place_branch(branchp, 0, 0);
792 /* for each room: put things inside */
793 for (croom = rooms; croom->hx > 0; croom++) {
794 if (croom->rtype != OROOM)
795 continue;
797 /* put a sleeping monster inside */
798 /* Note: monster may be on the stairs. This cannot be
799 avoided: maybe the player fell through a trap door
800 while a monster was on the stairs. Conclusion:
801 we have to check for monsters on the stairs anyway. */
803 if (u.uhave.amulet || !rn2(3)) {
804 x = somex(croom);
805 y = somey(croom);
806 tmonst = makemon((struct permonst *) 0, x, y, NO_MM_FLAGS);
807 if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER]
808 && !occupied(x, y))
809 (void) maketrap(x, y, WEB);
811 /* put traps and mimics inside */
812 x = 8 - (level_difficulty() / 6);
813 if (x <= 1)
814 x = 2;
815 while (!rn2(x))
816 mktrap(0, 0, croom, (coord *) 0);
817 if (!rn2(3))
818 (void) mkgold(0L, somex(croom), somey(croom));
819 if (Is_rogue_level(&u.uz))
820 goto skip_nonrogue;
821 if (!rn2(10))
822 mkfount(0, croom);
823 if (!rn2(60))
824 mksink(croom);
825 if (!rn2(60))
826 mkaltar(croom);
827 x = 80 - (depth(&u.uz) * 2);
828 if (x < 2)
829 x = 2;
830 if (!rn2(x))
831 mkgrave(croom);
833 /* put statues inside */
834 if (!rn2(20))
835 (void) mkcorpstat(STATUE, (struct monst *) 0,
836 (struct permonst *) 0, somex(croom),
837 somey(croom), CORPSTAT_INIT);
838 /* put box/chest inside;
839 * 40% chance for at least 1 box, regardless of number
840 * of rooms; about 5 - 7.5% for 2 boxes, least likely
841 * when few rooms; chance for 3 or more is negligible.
843 if (!rn2(nroom * 5 / 2))
844 (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, somex(croom),
845 somey(croom), TRUE, FALSE);
847 /* maybe make some graffiti */
848 if (!rn2(27 + 3 * abs(depth(&u.uz)))) {
849 char buf[BUFSZ];
850 const char *mesg = random_engraving(buf);
851 if (mesg) {
852 do {
853 x = somex(croom);
854 y = somey(croom);
855 } while (levl[x][y].typ != ROOM && !rn2(40));
856 if (!(IS_POOL(levl[x][y].typ)
857 || IS_FURNITURE(levl[x][y].typ)))
858 make_engr_at(x, y, mesg, 0L, MARK);
862 skip_nonrogue:
863 if (!rn2(3)) {
864 (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
865 tryct = 0;
866 while (!rn2(5)) {
867 if (++tryct > 100) {
868 impossible("tryct overflow4");
869 break;
871 (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
878 * Place deposits of minerals (gold and misc gems) in the stone
879 * surrounding the rooms on the map.
880 * Also place kelp in water.
881 * mineralize(-1, -1, -1, -1, FALSE); => "default" behaviour
883 void
884 mineralize(kelp_pool, kelp_moat, goldprob, gemprob, skip_lvl_checks)
885 int kelp_pool, kelp_moat, goldprob, gemprob;
886 boolean skip_lvl_checks;
888 s_level *sp;
889 struct obj *otmp;
890 int x, y, cnt;
892 if (kelp_pool < 0)
893 kelp_pool = 10;
894 if (kelp_moat < 0)
895 kelp_moat = 30;
897 /* Place kelp, except on the plane of water */
898 if (!skip_lvl_checks && In_endgame(&u.uz))
899 return;
900 for (x = 2; x < (COLNO - 2); x++)
901 for (y = 1; y < (ROWNO - 1); y++)
902 if ((kelp_pool && levl[x][y].typ == POOL && !rn2(kelp_pool))
903 || (kelp_moat && levl[x][y].typ == MOAT && !rn2(kelp_moat)))
904 (void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE);
906 /* determine if it is even allowed;
907 almost all special levels are excluded */
908 if (!skip_lvl_checks
909 && (In_hell(&u.uz) || In_V_tower(&u.uz) || Is_rogue_level(&u.uz)
910 || level.flags.arboreal
911 || ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz)
912 && (!In_mines(&u.uz) || sp->flags.town))))
913 return;
915 /* basic level-related probabilities */
916 if (goldprob < 0)
917 goldprob = 20 + depth(&u.uz) / 3;
918 if (gemprob < 0)
919 gemprob = goldprob / 4;
921 /* mines have ***MORE*** goodies - otherwise why mine? */
922 if (!skip_lvl_checks) {
923 if (In_mines(&u.uz)) {
924 goldprob *= 2;
925 gemprob *= 3;
926 } else if (In_quest(&u.uz)) {
927 goldprob /= 4;
928 gemprob /= 6;
933 * Seed rock areas with gold and/or gems.
934 * We use fairly low level object handling to avoid unnecessary
935 * overhead from placing things in the floor chain prior to burial.
937 for (x = 2; x < (COLNO - 2); x++)
938 for (y = 1; y < (ROWNO - 1); y++)
939 if (levl[x][y + 1].typ != STONE) { /* <x,y> spot not eligible */
940 y += 2; /* next two spots aren't eligible either */
941 } else if (levl[x][y].typ != STONE) { /* this spot not eligible */
942 y += 1; /* next spot isn't eligible either */
943 } else if (!(levl[x][y].wall_info & W_NONDIGGABLE)
944 && levl[x][y - 1].typ == STONE
945 && levl[x + 1][y - 1].typ == STONE
946 && levl[x - 1][y - 1].typ == STONE
947 && levl[x + 1][y].typ == STONE
948 && levl[x - 1][y].typ == STONE
949 && levl[x + 1][y + 1].typ == STONE
950 && levl[x - 1][y + 1].typ == STONE) {
951 if (rn2(1000) < goldprob) {
952 if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) {
953 otmp->ox = x, otmp->oy = y;
954 otmp->quan = 1L + rnd(goldprob * 3);
955 otmp->owt = weight(otmp);
956 if (!rn2(3))
957 add_to_buried(otmp);
958 else
959 place_object(otmp, x, y);
962 if (rn2(1000) < gemprob) {
963 for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--)
964 if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) {
965 if (otmp->otyp == ROCK) {
966 dealloc_obj(otmp); /* discard it */
967 } else {
968 otmp->ox = x, otmp->oy = y;
969 if (!rn2(3))
970 add_to_buried(otmp);
971 else
972 place_object(otmp, x, y);
979 void
980 mklev()
982 struct mkroom *croom;
983 int ridx;
985 init_mapseen(&u.uz);
986 if (getbones())
987 return;
989 in_mklev = TRUE;
990 makelevel();
991 bound_digging();
992 mineralize(-1, -1, -1, -1, FALSE);
993 in_mklev = FALSE;
994 /* has_morgue gets cleared once morgue is entered; graveyard stays
995 set (graveyard might already be set even when has_morgue is clear
996 [see fixup_special()], so don't update it unconditionally) */
997 if (level.flags.has_morgue)
998 level.flags.graveyard = 1;
999 if (!level.flags.is_maze_lev) {
1000 for (croom = &rooms[0]; croom != &rooms[nroom]; croom++)
1001 #ifdef SPECIALIZATION
1002 topologize(croom, FALSE);
1003 #else
1004 topologize(croom);
1005 #endif
1007 set_wall_state();
1008 /* for many room types, rooms[].rtype is zeroed once the room has been
1009 entered; rooms[].orig_rtype always retains original rtype value */
1010 for (ridx = 0; ridx < SIZE(rooms); ridx++)
1011 rooms[ridx].orig_rtype = rooms[ridx].rtype;
1014 void
1015 #ifdef SPECIALIZATION
1016 topologize(croom, do_ordinary)
1017 struct mkroom *croom;
1018 boolean do_ordinary;
1019 #else
1020 topologize(croom)
1021 struct mkroom *croom;
1022 #endif
1024 register int x, y, roomno = (int) ((croom - rooms) + ROOMOFFSET);
1025 int lowx = croom->lx, lowy = croom->ly;
1026 int hix = croom->hx, hiy = croom->hy;
1027 #ifdef SPECIALIZATION
1028 schar rtype = croom->rtype;
1029 #endif
1030 int subindex, nsubrooms = croom->nsubrooms;
1032 /* skip the room if already done; i.e. a shop handled out of order */
1033 /* also skip if this is non-rectangular (it _must_ be done already) */
1034 if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular)
1035 return;
1036 #ifdef SPECIALIZATION
1037 if (Is_rogue_level(&u.uz))
1038 do_ordinary = TRUE; /* vision routine helper */
1039 if ((rtype != OROOM) || do_ordinary)
1040 #endif
1042 /* do innards first */
1043 for (x = lowx; x <= hix; x++)
1044 for (y = lowy; y <= hiy; y++)
1045 #ifdef SPECIALIZATION
1046 if (rtype == OROOM)
1047 levl[x][y].roomno = NO_ROOM;
1048 else
1049 #endif
1050 levl[x][y].roomno = roomno;
1051 /* top and bottom edges */
1052 for (x = lowx - 1; x <= hix + 1; x++)
1053 for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) {
1054 levl[x][y].edge = 1;
1055 if (levl[x][y].roomno)
1056 levl[x][y].roomno = SHARED;
1057 else
1058 levl[x][y].roomno = roomno;
1060 /* sides */
1061 for (x = lowx - 1; x <= hix + 1; x += (hix - lowx + 2))
1062 for (y = lowy; y <= hiy; y++) {
1063 levl[x][y].edge = 1;
1064 if (levl[x][y].roomno)
1065 levl[x][y].roomno = SHARED;
1066 else
1067 levl[x][y].roomno = roomno;
1070 /* subrooms */
1071 for (subindex = 0; subindex < nsubrooms; subindex++)
1072 #ifdef SPECIALIZATION
1073 topologize(croom->sbrooms[subindex], (boolean) (rtype != OROOM));
1074 #else
1075 topologize(croom->sbrooms[subindex]);
1076 #endif
1079 /* Find an unused room for a branch location. */
1080 STATIC_OVL struct mkroom *
1081 find_branch_room(mp)
1082 coord *mp;
1084 struct mkroom *croom = 0;
1086 if (nroom == 0) {
1087 mazexy(mp); /* already verifies location */
1088 } else {
1089 /* not perfect - there may be only one stairway */
1090 if (nroom > 2) {
1091 int tryct = 0;
1094 croom = &rooms[rn2(nroom)];
1095 while ((croom == dnstairs_room || croom == upstairs_room
1096 || croom->rtype != OROOM) && (++tryct < 100));
1097 } else
1098 croom = &rooms[rn2(nroom)];
1100 do {
1101 if (!somexy(croom, mp))
1102 impossible("Can't place branch!");
1103 } while (occupied(mp->x, mp->y)
1104 || (levl[mp->x][mp->y].typ != CORR
1105 && levl[mp->x][mp->y].typ != ROOM));
1107 return croom;
1110 /* Find the room for (x,y). Return null if not in a room. */
1111 STATIC_OVL struct mkroom *
1112 pos_to_room(x, y)
1113 xchar x, y;
1115 int i;
1116 struct mkroom *curr;
1118 for (curr = rooms, i = 0; i < nroom; curr++, i++)
1119 if (inside_room(curr, x, y))
1120 return curr;
1122 return (struct mkroom *) 0;
1125 /* If given a branch, randomly place a special stair or portal. */
1126 void
1127 place_branch(br, x, y)
1128 branch *br; /* branch to place */
1129 xchar x, y; /* location */
1131 coord m;
1132 d_level *dest;
1133 boolean make_stairs;
1134 struct mkroom *br_room;
1137 * Return immediately if there is no branch to make or we have
1138 * already made one. This routine can be called twice when
1139 * a special level is loaded that specifies an SSTAIR location
1140 * as a favored spot for a branch.
1142 if (!br || made_branch)
1143 return;
1145 if (!x) { /* find random coordinates for branch */
1146 br_room = find_branch_room(&m);
1147 x = m.x;
1148 y = m.y;
1149 } else {
1150 br_room = pos_to_room(x, y);
1153 if (on_level(&br->end1, &u.uz)) {
1154 /* we're on end1 */
1155 make_stairs = br->type != BR_NO_END1;
1156 dest = &br->end2;
1157 } else {
1158 /* we're on end2 */
1159 make_stairs = br->type != BR_NO_END2;
1160 dest = &br->end1;
1163 if (br->type == BR_PORTAL) {
1164 mkportal(x, y, dest->dnum, dest->dlevel);
1165 } else if (make_stairs) {
1166 sstairs.sx = x;
1167 sstairs.sy = y;
1168 sstairs.up =
1169 (char) on_level(&br->end1, &u.uz) ? br->end1_up : !br->end1_up;
1170 assign_level(&sstairs.tolev, dest);
1171 sstairs_room = br_room;
1173 levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN;
1174 levl[x][y].typ = STAIRS;
1177 * Set made_branch to TRUE even if we didn't make a stairwell (i.e.
1178 * make_stairs is false) since there is currently only one branch
1179 * per level, if we failed once, we're going to fail again on the
1180 * next call.
1182 made_branch = TRUE;
1185 STATIC_OVL boolean
1186 bydoor(x, y)
1187 register xchar x, y;
1189 register int typ;
1191 if (isok(x + 1, y)) {
1192 typ = levl[x + 1][y].typ;
1193 if (IS_DOOR(typ) || typ == SDOOR)
1194 return TRUE;
1196 if (isok(x - 1, y)) {
1197 typ = levl[x - 1][y].typ;
1198 if (IS_DOOR(typ) || typ == SDOOR)
1199 return TRUE;
1201 if (isok(x, y + 1)) {
1202 typ = levl[x][y + 1].typ;
1203 if (IS_DOOR(typ) || typ == SDOOR)
1204 return TRUE;
1206 if (isok(x, y - 1)) {
1207 typ = levl[x][y - 1].typ;
1208 if (IS_DOOR(typ) || typ == SDOOR)
1209 return TRUE;
1211 return FALSE;
1214 /* see whether it is allowable to create a door at [x,y] */
1216 okdoor(x, y)
1217 xchar x, y;
1219 boolean near_door = bydoor(x, y);
1221 return ((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL)
1222 && doorindex < DOORMAX && !near_door);
1225 void
1226 dodoor(x, y, aroom)
1227 int x, y;
1228 struct mkroom *aroom;
1230 if (doorindex >= DOORMAX) {
1231 impossible("DOORMAX exceeded?");
1232 return;
1235 dosdoor(x, y, aroom, rn2(8) ? DOOR : SDOOR);
1238 boolean
1239 occupied(x, y)
1240 register xchar x, y;
1242 return (boolean) (t_at(x, y) || IS_FURNITURE(levl[x][y].typ)
1243 || is_lava(x, y) || is_pool(x, y)
1244 || invocation_pos(x, y));
1247 /* make a trap somewhere (in croom if mazeflag = 0 && !tm) */
1248 /* if tm != null, make trap at that location */
1249 void
1250 mktrap(num, mazeflag, croom, tm)
1251 int num, mazeflag;
1252 struct mkroom *croom;
1253 coord *tm;
1255 register int kind;
1256 coord m;
1258 /* no traps in pools */
1259 if (tm && is_pool(tm->x, tm->y))
1260 return;
1262 if (num > 0 && num < TRAPNUM) {
1263 kind = num;
1264 } else if (Is_rogue_level(&u.uz)) {
1265 switch (rn2(7)) {
1266 default:
1267 kind = BEAR_TRAP;
1268 break; /* 0 */
1269 case 1:
1270 kind = ARROW_TRAP;
1271 break;
1272 case 2:
1273 kind = DART_TRAP;
1274 break;
1275 case 3:
1276 kind = TRAPDOOR;
1277 break;
1278 case 4:
1279 kind = PIT;
1280 break;
1281 case 5:
1282 kind = SLP_GAS_TRAP;
1283 break;
1284 case 6:
1285 kind = RUST_TRAP;
1286 break;
1288 } else if (Inhell && !rn2(5)) {
1289 /* bias the frequency of fire traps in Gehennom */
1290 kind = FIRE_TRAP;
1291 } else {
1292 unsigned lvl = level_difficulty();
1294 do {
1295 kind = rnd(TRAPNUM - 1);
1296 /* reject "too hard" traps */
1297 switch (kind) {
1298 case MAGIC_PORTAL:
1299 case VIBRATING_SQUARE:
1300 kind = NO_TRAP;
1301 break;
1302 case ROLLING_BOULDER_TRAP:
1303 case SLP_GAS_TRAP:
1304 if (lvl < 2)
1305 kind = NO_TRAP;
1306 break;
1307 case LEVEL_TELEP:
1308 if (lvl < 5 || level.flags.noteleport)
1309 kind = NO_TRAP;
1310 break;
1311 case SPIKED_PIT:
1312 if (lvl < 5)
1313 kind = NO_TRAP;
1314 break;
1315 case LANDMINE:
1316 if (lvl < 6)
1317 kind = NO_TRAP;
1318 break;
1319 case WEB:
1320 if (lvl < 7)
1321 kind = NO_TRAP;
1322 break;
1323 case STATUE_TRAP:
1324 case POLY_TRAP:
1325 if (lvl < 8)
1326 kind = NO_TRAP;
1327 break;
1328 case FIRE_TRAP:
1329 if (!Inhell)
1330 kind = NO_TRAP;
1331 break;
1332 case TELEP_TRAP:
1333 if (level.flags.noteleport)
1334 kind = NO_TRAP;
1335 break;
1336 case HOLE:
1337 /* make these much less often than other traps */
1338 if (rn2(7))
1339 kind = NO_TRAP;
1340 break;
1342 } while (kind == NO_TRAP);
1345 if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz))
1346 kind = ROCKTRAP;
1348 if (tm)
1349 m = *tm;
1350 else {
1351 register int tryct = 0;
1352 boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT
1353 || kind == TRAPDOOR || kind == HOLE);
1355 do {
1356 if (++tryct > 200)
1357 return;
1358 if (mazeflag)
1359 mazexy(&m);
1360 else if (!somexy(croom, &m))
1361 return;
1362 } while (occupied(m.x, m.y)
1363 || (avoid_boulder && sobj_at(BOULDER, m.x, m.y)));
1366 (void) maketrap(m.x, m.y, kind);
1367 if (kind == WEB)
1368 (void) makemon(&mons[PM_GIANT_SPIDER], m.x, m.y, NO_MM_FLAGS);
1371 void
1372 mkstairs(x, y, up, croom)
1373 xchar x, y;
1374 char up;
1375 struct mkroom *croom;
1377 if (!x) {
1378 impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y);
1379 return;
1383 * We can't make a regular stair off an end of the dungeon. This
1384 * attempt can happen when a special level is placed at an end and
1385 * has an up or down stair specified in its description file.
1387 if ((dunlev(&u.uz) == 1 && up)
1388 || (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up))
1389 return;
1391 if (up) {
1392 xupstair = x;
1393 yupstair = y;
1394 upstairs_room = croom;
1395 } else {
1396 xdnstair = x;
1397 ydnstair = y;
1398 dnstairs_room = croom;
1401 levl[x][y].typ = STAIRS;
1402 levl[x][y].ladder = up ? LA_UP : LA_DOWN;
1405 STATIC_OVL void
1406 mkfount(mazeflag, croom)
1407 int mazeflag;
1408 struct mkroom *croom;
1410 coord m;
1411 register int tryct = 0;
1413 do {
1414 if (++tryct > 200)
1415 return;
1416 if (mazeflag)
1417 mazexy(&m);
1418 else if (!somexy(croom, &m))
1419 return;
1420 } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1422 /* Put a fountain at m.x, m.y */
1423 levl[m.x][m.y].typ = FOUNTAIN;
1424 /* Is it a "blessed" fountain? (affects drinking from fountain) */
1425 if (!rn2(7))
1426 levl[m.x][m.y].blessedftn = 1;
1428 level.flags.nfountains++;
1431 STATIC_OVL void
1432 mksink(croom)
1433 struct mkroom *croom;
1435 coord m;
1436 register int tryct = 0;
1438 do {
1439 if (++tryct > 200)
1440 return;
1441 if (!somexy(croom, &m))
1442 return;
1443 } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1445 /* Put a sink at m.x, m.y */
1446 levl[m.x][m.y].typ = SINK;
1448 level.flags.nsinks++;
1451 STATIC_OVL void
1452 mkaltar(croom)
1453 struct mkroom *croom;
1455 coord m;
1456 register int tryct = 0;
1457 aligntyp al;
1459 if (croom->rtype != OROOM)
1460 return;
1462 do {
1463 if (++tryct > 200)
1464 return;
1465 if (!somexy(croom, &m))
1466 return;
1467 } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1469 /* Put an altar at m.x, m.y */
1470 levl[m.x][m.y].typ = ALTAR;
1472 /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
1473 al = rn2((int) A_LAWFUL + 2) - 1;
1474 levl[m.x][m.y].altarmask = Align2amask(al);
1477 static void
1478 mkgrave(croom)
1479 struct mkroom *croom;
1481 coord m;
1482 register int tryct = 0;
1483 register struct obj *otmp;
1484 boolean dobell = !rn2(10);
1486 if (croom->rtype != OROOM)
1487 return;
1489 do {
1490 if (++tryct > 200)
1491 return;
1492 if (!somexy(croom, &m))
1493 return;
1494 } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1496 /* Put a grave at m.x, m.y */
1497 make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0);
1499 /* Possibly fill it with objects */
1500 if (!rn2(3))
1501 (void) mkgold(0L, m.x, m.y);
1502 for (tryct = rn2(5); tryct; tryct--) {
1503 otmp = mkobj(RANDOM_CLASS, TRUE);
1504 if (!otmp)
1505 return;
1506 curse(otmp);
1507 otmp->ox = m.x;
1508 otmp->oy = m.y;
1509 add_to_buried(otmp);
1512 /* Leave a bell, in case we accidentally buried someone alive */
1513 if (dobell)
1514 (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE);
1515 return;
1518 /* maze levels have slightly different constraints from normal levels */
1519 #define x_maze_min 2
1520 #define y_maze_min 2
1523 * Major level transmutation: add a set of stairs (to the Sanctum) after
1524 * an earthquake that leaves behind a a new topology, centered at inv_pos.
1525 * Assumes there are no rooms within the invocation area and that inv_pos
1526 * is not too close to the edge of the map. Also assume the hero can see,
1527 * which is guaranteed for normal play due to the fact that sight is needed
1528 * to read the Book of the Dead.
1530 void
1531 mkinvokearea()
1533 int dist;
1534 xchar xmin = inv_pos.x, xmax = inv_pos.x;
1535 xchar ymin = inv_pos.y, ymax = inv_pos.y;
1536 register xchar i;
1538 pline_The("floor shakes violently under you!");
1539 pline_The("walls around you begin to bend and crumble!");
1540 display_nhwindow(WIN_MESSAGE, TRUE);
1542 /* any trap hero is stuck in will be going away now */
1543 if (u.utrap) {
1544 u.utrap = 0;
1545 if (u.utraptype == TT_BURIEDBALL)
1546 buried_ball_to_punishment();
1548 mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */
1550 for (dist = 1; dist < 7; dist++) {
1551 xmin--;
1552 xmax++;
1554 /* top and bottom */
1555 if (dist != 3) { /* the area is wider that it is high */
1556 ymin--;
1557 ymax++;
1558 for (i = xmin + 1; i < xmax; i++) {
1559 mkinvpos(i, ymin, dist);
1560 mkinvpos(i, ymax, dist);
1564 /* left and right */
1565 for (i = ymin; i <= ymax; i++) {
1566 mkinvpos(xmin, i, dist);
1567 mkinvpos(xmax, i, dist);
1570 flush_screen(1); /* make sure the new glyphs shows up */
1571 delay_output();
1574 You("are standing at the top of a stairwell leading down!");
1575 mkstairs(u.ux, u.uy, 0, (struct mkroom *) 0); /* down */
1576 newsym(u.ux, u.uy);
1577 vision_full_recalc = 1; /* everything changed */
1580 /* Change level topology. Boulders in the vicinity are eliminated.
1581 * Temporarily overrides vision in the name of a nice effect.
1583 STATIC_OVL void
1584 mkinvpos(x, y, dist)
1585 xchar x, y;
1586 int dist;
1588 struct trap *ttmp;
1589 struct obj *otmp;
1590 boolean make_rocks;
1591 register struct rm *lev = &levl[x][y];
1593 /* clip at existing map borders if necessary */
1594 if (!within_bounded_area(x, y, x_maze_min + 1, y_maze_min + 1,
1595 x_maze_max - 1, y_maze_max - 1)) {
1596 /* only outermost 2 columns and/or rows may be truncated due to edge
1598 if (dist < (7 - 2))
1599 panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist);
1600 return;
1603 /* clear traps */
1604 if ((ttmp = t_at(x, y)) != 0)
1605 deltrap(ttmp);
1607 /* clear boulders; leave some rocks for non-{moat|trap} locations */
1608 make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE;
1609 while ((otmp = sobj_at(BOULDER, x, y)) != 0) {
1610 if (make_rocks) {
1611 fracture_rock(otmp);
1612 make_rocks = FALSE; /* don't bother with more rocks */
1613 } else {
1614 obj_extract_self(otmp);
1615 obfree(otmp, (struct obj *) 0);
1618 unblock_point(x, y); /* make sure vision knows this location is open */
1620 /* fake out saved state */
1621 lev->seenv = 0;
1622 lev->doormask = 0;
1623 if (dist < 6)
1624 lev->lit = TRUE;
1625 lev->waslit = TRUE;
1626 lev->horizontal = FALSE;
1627 /* short-circuit vision recalc */
1628 viz_array[y][x] = (dist < 6) ? (IN_SIGHT | COULD_SEE) : COULD_SEE;
1630 switch (dist) {
1631 case 1: /* fire traps */
1632 if (is_pool(x, y))
1633 break;
1634 lev->typ = ROOM;
1635 ttmp = maketrap(x, y, FIRE_TRAP);
1636 if (ttmp)
1637 ttmp->tseen = TRUE;
1638 break;
1639 case 0: /* lit room locations */
1640 case 2:
1641 case 3:
1642 case 6: /* unlit room locations */
1643 lev->typ = ROOM;
1644 break;
1645 case 4: /* pools (aka a wide moat) */
1646 case 5:
1647 lev->typ = MOAT;
1648 /* No kelp! */
1649 break;
1650 default:
1651 impossible("mkinvpos called with dist %d", dist);
1652 break;
1655 /* display new value of position; could have a monster/object on it */
1656 newsym(x, y);
1660 * The portal to Ludios is special. The entrance can only occur within a
1661 * vault in the main dungeon at a depth greater than 10. The Ludios branch
1662 * structure reflects this by having a bogus "source" dungeon: the value
1663 * of n_dgns (thus, Is_branchlev() will never find it).
1665 * Ludios will remain isolated until the branch is corrected by this function.
1667 STATIC_OVL void
1668 mk_knox_portal(x, y)
1669 xchar x, y;
1671 extern int n_dgns; /* from dungeon.c */
1672 d_level *source;
1673 branch *br;
1674 schar u_depth;
1676 br = dungeon_branch("Fort Ludios");
1677 if (on_level(&knox_level, &br->end1)) {
1678 source = &br->end2;
1679 } else {
1680 /* disallow Knox branch on a level with one branch already */
1681 if (Is_branchlev(&u.uz))
1682 return;
1683 source = &br->end1;
1686 /* Already set or 2/3 chance of deferring until a later level. */
1687 if (source->dnum < n_dgns || (rn2(3) && !wizard))
1688 return;
1690 if (!(u.uz.dnum == oracle_level.dnum /* in main dungeon */
1691 && !at_dgn_entrance("The Quest") /* but not Quest's entry */
1692 && (u_depth = depth(&u.uz)) > 10 /* beneath 10 */
1693 && u_depth < depth(&medusa_level))) /* and above Medusa */
1694 return;
1696 /* Adjust source to be current level and re-insert branch. */
1697 *source = u.uz;
1698 insert_branch(br, TRUE);
1700 debugpline0("Made knox portal.");
1701 place_branch(br, x, y);
1704 /*mklev.c*/