1 /* SCCS Id: @(#)mklev.c 3.4 2001/11/29 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
6 /* #define DEBUG */ /* uncomment to enable code debugging */
10 #define debugpline if (wizard) pline
12 #define debugpline pline
16 /* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
17 /* croom->lx etc are schar (width <= int), so % arith ensures that */
18 /* conversion of result to int is reasonable */
21 STATIC_DCL void FDECL(mkfount,(int,struct mkroom *));
23 STATIC_DCL void FDECL(mksink,(struct mkroom *));
25 STATIC_DCL void FDECL(mkaltar,(struct mkroom *));
26 STATIC_DCL void FDECL(mkgrave,(struct mkroom *));
27 STATIC_DCL void NDECL(makevtele);
28 STATIC_DCL void NDECL(clear_level_structures);
29 STATIC_DCL void NDECL(makelevel);
30 STATIC_DCL void NDECL(mineralize);
31 STATIC_DCL boolean FDECL(bydoor,(XCHAR_P,XCHAR_P));
32 STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *));
33 STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P));
34 STATIC_DCL boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*));
35 STATIC_DCL void FDECL(makeniche,(int));
36 STATIC_DCL void NDECL(make_niches);
38 STATIC_PTR int FDECL( CFDECLSPEC do_comp,(const genericptr,const genericptr));
40 STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int));
41 STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P));
42 STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int,
43 BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P));
44 STATIC_DCL void NDECL(makerooms);
45 STATIC_DCL void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
46 STATIC_DCL void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int));
47 STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P));
49 #define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
50 #define init_vault() vault_x = -1
51 #define do_vault() (vault_x != -1)
52 static xchar vault_x, vault_y;
54 static boolean made_branch; /* used only during level creation */
56 /* Args must be (const genericptr) so that qsort will always be happy. */
58 STATIC_PTR int CFDECLSPEC
64 /* lint complains about possible pointer alignment problems, but we know
65 that vx and vy are always properly aligned. Hence, the following
68 return (vx == vy) ? 0 : -1;
70 register const struct mkroom *x, *y;
72 x = (const struct mkroom *)vx;
73 y = (const struct mkroom *)vy;
74 if(x->lx < y->lx) return(-1);
75 return(x->lx > y->lx);
80 finddpos(cc, xl,yl,xh,yh)
86 x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
87 y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
91 for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
95 for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
96 if(IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
98 /* cannot find something reasonable -- strange */
110 #if defined(SYSV) || defined(DGUX)
111 qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp);
113 qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp);
118 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room)
119 register struct mkroom *croom;
121 register int hix, hiy;
130 /* locations might bump level edges in wall-less rooms */
131 /* add/subtract 1 to allow for edge locations */
134 if(hix >= COLNO-1) hix = COLNO-2;
135 if(hiy >= ROWNO-1) hiy = ROWNO-2;
138 for(x = lowx-1; x <= hix+1; x++) {
139 lev = &levl[x][max(lowy-1,0)];
140 for(y = lowy-1; y <= hiy+1; y++)
151 croom->rtype = rtype;
153 /* if we're not making a vault, doorindex will still be 0
154 * if we are, we'll have problems adding niches to the previous room
155 * unless fdoor is at least doorindex
157 croom->fdoor = doorindex;
158 croom->irregular = FALSE;
160 croom->nsubrooms = 0;
161 croom->sbrooms[0] = (struct mkroom *) 0;
163 for(x = lowx-1; x <= hix+1; x++)
164 for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
165 levl[x][y].typ = HWALL;
166 levl[x][y].horizontal = 1; /* For open/secret doors. */
168 for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
169 for(y = lowy; y <= hiy; y++) {
170 levl[x][y].typ = VWALL;
171 levl[x][y].horizontal = 0; /* For open/secret doors. */
173 for(x = lowx; x <= hix; x++) {
174 lev = &levl[x][lowy];
175 for(y = lowy; y <= hiy; y++)
179 levl[lowx-1][lowy-1].typ = TLCORNER;
180 levl[hix+1][lowy-1].typ = TRCORNER;
181 levl[lowx-1][hiy+1].typ = BLCORNER;
182 levl[hix+1][hiy+1].typ = BRCORNER;
183 } else { /* a subroom */
184 wallification(lowx-1, lowy-1, hix+1, hiy+1);
191 add_room(lowx, lowy, hix, hiy, lit, rtype, special)
192 register int lowx, lowy, hix, hiy;
197 register struct mkroom *croom;
199 croom = &rooms[nroom];
200 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
201 rtype, special, (boolean) TRUE);
208 add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special)
209 struct mkroom *proom;
210 register int lowx, lowy, hix, hiy;
215 register struct mkroom *croom;
217 croom = &subrooms[nsubroom];
218 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
219 rtype, special, (boolean) FALSE);
220 proom->sbrooms[proom->nsubrooms++] = croom;
229 boolean tried_vault = FALSE;
231 /* make rooms until satisfied */
232 /* rnd_rect() will returns 0 if no more rects are available... */
233 while(nroom < MAXNROFROOMS && rnd_rect()) {
234 if(nroom >= (MAXNROFROOMS/6) && rn2(2) && !tried_vault) {
236 if (create_vault()) {
237 vault_x = rooms[nroom].lx;
238 vault_y = rooms[nroom].ly;
239 rooms[nroom].hx = -1;
242 if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
253 coord cc,tt, org, dest;
254 register xchar tx, ty, xx, yy;
255 register struct mkroom *croom, *troom;
261 /* find positions cc and tt for doors in croom and troom
262 and direction for a corridor between them */
264 if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
265 if(troom->lx > croom->hx) {
270 finddpos(&cc, xx, croom->ly, xx, croom->hy);
271 finddpos(&tt, tx, troom->ly, tx, troom->hy);
272 } else if(troom->hy < croom->ly) {
276 finddpos(&cc, croom->lx, yy, croom->hx, yy);
278 finddpos(&tt, troom->lx, ty, troom->hx, ty);
279 } else if(troom->hx < croom->lx) {
284 finddpos(&cc, xx, croom->ly, xx, croom->hy);
285 finddpos(&tt, tx, troom->ly, tx, troom->hy);
291 finddpos(&cc, croom->lx, yy, croom->hx, yy);
292 finddpos(&tt, troom->lx, ty, troom->hx, ty);
298 if(nxcor && levl[xx+dx][yy+dy].typ)
300 if (okdoor(xx,yy) || !nxcor)
303 org.x = xx+dx; org.y = yy+dy;
304 dest.x = tx; dest.y = ty;
306 if (!dig_corridor(&org, &dest, nxcor,
307 level.flags.arboreal ? ROOM : CORR, STONE))
310 /* we succeeded in digging the corridor */
311 if (okdoor(tt.x, tt.y) || !nxcor)
312 dodoor(tt.x, tt.y, troom);
314 if(smeq[a] < smeq[b])
326 for(a = 0; a < nroom-1; a++) {
328 if(!rn2(50)) break; /* allow some randomness */
330 for(a = 0; a < nroom-2; a++)
331 if(smeq[a] != smeq[a+2])
333 for(a = 0; any && a < nroom; a++) {
335 for(b = 0; b < nroom; b++)
336 if(smeq[a] != smeq[b]) {
342 for(i = rn2(nroom) + 4; i; i--) {
353 register struct mkroom *aroom;
355 register struct mkroom *broom;
363 for(tmp = doorindex; tmp > broom->fdoor; tmp--)
364 doors[tmp] = doors[tmp-1];
368 for( ; broom->hx >= 0; broom++) broom->fdoor++;
372 dosdoor(x,y,aroom,type)
374 register struct mkroom *aroom;
377 boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE);
379 if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */
381 levl[x][y].typ = type;
383 if(!rn2(3)) { /* is it a locked door, closed, or a doorway? */
385 levl[x][y].doormask = D_ISOPEN;
387 levl[x][y].doormask = D_LOCKED;
389 levl[x][y].doormask = D_CLOSED;
391 if (levl[x][y].doormask != D_ISOPEN && !shdoor &&
392 level_difficulty() >= 5 && !rn2(25))
393 levl[x][y].doormask |= D_TRAPPED;
397 levl[x][y].doormask = D_ISOPEN;
399 levl[x][y].doormask = D_NODOOR;
401 levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
403 if(levl[x][y].doormask & D_TRAPPED) {
406 if (level_difficulty() >= 9 && !rn2(5) &&
407 !((mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) &&
408 (mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) &&
409 (mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) {
410 /* make a mimic instead */
411 levl[x][y].doormask = D_NODOOR;
412 mtmp = makemon(mkclass(S_MIMIC,0), x, y, NO_MM_FLAGS);
419 if(shdoor || !rn2(5)) levl[x][y].doormask = D_LOCKED;
420 else levl[x][y].doormask = D_CLOSED;
422 if(!shdoor && level_difficulty() >= 4 && !rn2(20))
423 levl[x][y].doormask |= D_TRAPPED;
430 place_niche(aroom,dy,xx,yy)
431 register struct mkroom *aroom;
438 finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1);
441 finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1);
445 return((boolean)((isok(*xx,*yy+*dy) && levl[*xx][*yy+*dy].typ == STONE)
446 && (isok(*xx,*yy-*dy) && !IS_POOL(levl[*xx][*yy-*dy].typ)
447 && !IS_FURNITURE(levl[*xx][*yy-*dy].typ))));
450 /* there should be one of these per trap, in the same order as trap.h */
451 static NEARDATA const char *trap_engravings[TRAPNUM] = {
452 (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
453 (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
454 (char *)0, (char *)0, (char *)0, (char *)0,
455 /* 14..16: trap door, teleport, level-teleport */
456 "Vlad was here", "ad aerarium", "ad aerarium",
457 (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
465 register struct mkroom *aroom;
466 register struct rm *rm;
467 register int vct = 8;
469 register struct trap *ttmp;
471 if(doorindex < DOORMAX)
473 aroom = &rooms[rn2(nroom)];
474 if(aroom->rtype != OROOM) continue; /* not an ordinary room */
475 if(aroom->doorct == 1 && rn2(5)) continue;
476 if(!place_niche(aroom,&dy,&xx,&yy)) continue;
478 rm = &levl[xx][yy+dy];
479 if(trap_type || !rn2(4)) {
483 if((trap_type == HOLE || trap_type == TRAPDOOR)
484 && !Can_fall_thru(&u.uz))
485 trap_type = ROCKTRAP;
486 ttmp = maketrap(xx, yy+dy, trap_type);
488 if (trap_type != ROCKTRAP) ttmp->once = 1;
489 if (trap_engravings[trap_type]) {
490 make_engr_at(xx, yy-dy,
491 trap_engravings[trap_type], 0L, DUST);
492 wipe_engr_at(xx, yy-dy, 5); /* age it a little */
496 dosdoor(xx, yy, aroom, SDOOR);
500 dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
502 if (!level.flags.noteleport)
503 (void) mksobj_at(SCR_TELEPORTATION,
504 xx, yy+dy, TRUE, FALSE);
505 if (!rn2(3)) (void) mkobj_at(0, xx, yy+dy, TRUE);
515 register int ct = rnd((nroom>>1) + 1), dep = depth(&u.uz);
517 boolean ltptr = (!level.flags.noteleport && dep > 15),
518 vamp = (dep > 5 && dep < 25);
521 if (ltptr && !rn2(6)) {
523 makeniche(LEVEL_TELEP);
524 } else if (vamp && !rn2(6)) {
527 } else makeniche(NO_TRAP);
534 makeniche(TELEP_TRAP);
537 /* clear out various globals that keep information on the current level.
538 * some of this is only necessary for some types of levels (maze, normal,
539 * special) but it's easier to put it all in one place than make sure
540 * each type initializes what it needs to separately.
543 clear_level_structures()
545 static struct rm zerorm = { cmap_to_glyph(S_stone),
546 0, 0, 0, 0, 0, 0, 0, 0 };
548 register struct rm *lev;
550 for(x=0; x<COLNO; x++) {
552 for(y=0; y<ROWNO; y++) {
555 level.objects[x][y] = (struct obj *)0;
556 level.monsters[x][y] = (struct monst *)0;
560 #ifndef MICROPORT_BUG
561 (void) memset((genericptr_t)level.objects, 0, sizeof(level.objects));
562 (void) memset((genericptr_t)level.monsters, 0, sizeof(level.monsters));
564 level.objlist = (struct obj *)0;
565 level.buriedobjlist = (struct obj *)0;
566 level.monlist = (struct monst *)0;
567 level.damagelist = (struct damage *)0;
569 level.flags.nfountains = 0;
570 level.flags.nsinks = 0;
571 level.flags.has_shop = 0;
572 level.flags.has_vault = 0;
573 level.flags.has_zoo = 0;
574 level.flags.has_court = 0;
575 level.flags.has_morgue = level.flags.graveyard = 0;
576 level.flags.has_beehive = 0;
577 level.flags.has_barracks = 0;
578 level.flags.has_temple = 0;
579 level.flags.has_swamp = 0;
580 level.flags.noteleport = 0;
581 level.flags.hardfloor = 0;
582 level.flags.nommap = 0;
583 level.flags.hero_memory = 1;
584 level.flags.shortsighted = 0;
585 level.flags.arboreal = 0;
586 level.flags.is_maze_lev = 0;
587 level.flags.is_cavernous_lev = 0;
596 xdnstair = ydnstair = xupstair = yupstair = 0;
597 sstairs.sx = sstairs.sy = 0;
598 xdnladder = ydnladder = xupladder = yupladder = 0;
606 register struct mkroom *croom, *troom;
609 struct monst *tmonst; /* always put a web with a spider */
613 if(wiz1_level.dlevel == 0) init_dungeons();
614 oinit(); /* assign level dependent obj probabilities */
615 clear_level_structures();
618 register s_level *slev = Is_special(&u.uz);
620 /* check for special levels */
622 if (slev && !Is_rogue_level(&u.uz))
627 makemaz(slev->proto);
629 } else if (dungeons[u.uz.dnum].proto[0]) {
632 } else if (In_mines(&u.uz)) {
635 } else if (In_quest(&u.uz)) {
639 Sprintf(fillname, "%s-loca", urole.filecode);
640 loc_lev = find_level(fillname);
642 Sprintf(fillname, "%s-fil", urole.filecode);
644 (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
647 } else if(In_hell(&u.uz) ||
648 (rn2(5) && u.uz.dnum == medusa_level.dnum
649 && depth(&u.uz) > depth(&medusa_level))) {
655 /* otherwise, fall through - it's a "regular" level. */
658 if (Is_rogue_level(&u.uz)) {
666 /* construct stairs (up and down in different rooms if possible) */
667 croom = &rooms[rn2(nroom)];
668 if (!Is_botlevel(&u.uz))
669 mkstairs(somex(croom), somey(croom), 0, croom); /* down */
672 croom = &rooms[rn2(nroom-1)];
673 if (croom == troom) croom++;
676 if (u.uz.dlevel != 1) {
681 } while(occupied(sx, sy));
682 mkstairs(sx, sy, 1, croom); /* up */
685 branchp = Is_branchlev(&u.uz); /* possible dungeon branch */
686 room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed
687 to allow a random special room */
689 if (Is_rogue_level(&u.uz)) goto skip0;
694 /* make a secret treasure vault, not connected to the rest */
698 debugpline("trying to make a vault...");
702 if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) {
704 add_room(vault_x, vault_y, vault_x+w,
705 vault_y+h, TRUE, VAULT, FALSE);
706 level.flags.has_vault = 1;
708 fill_room(&rooms[nroom - 1], FALSE);
709 mk_knox_portal(vault_x+w, vault_y+h);
710 if(!level.flags.noteleport && !rn2(3)) makevtele();
711 } else if(rnd_rect() && create_vault()) {
712 vault_x = rooms[nroom].lx;
713 vault_y = rooms[nroom].ly;
714 if (check_room(&vault_x, &w, &vault_y, &h, TRUE))
717 rooms[nroom].hx = -1;
722 register int u_depth = depth(&u.uz);
725 if(wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else
728 u_depth < depth(&medusa_level) &&
729 nroom >= room_threshold &&
730 rn2(u_depth) < 3) mkroom(SHOPBASE);
731 else if (u_depth > 4 && !rn2(6)) mkroom(COURT);
732 else if (u_depth > 5 && !rn2(8) &&
733 !(mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) mkroom(LEPREHALL);
734 else if (u_depth > 6 && !rn2(7)) mkroom(ZOO);
735 else if (u_depth > 8 && !rn2(5)) mkroom(TEMPLE);
736 else if (u_depth > 9 && !rn2(5) &&
737 !(mvitals[PM_KILLER_BEE].mvflags & G_GONE)) mkroom(BEEHIVE);
738 else if (u_depth > 11 && !rn2(6)) mkroom(MORGUE);
739 else if (u_depth > 12 && !rn2(8)) mkroom(ANTHOLE);
740 else if (u_depth > 14 && !rn2(4) &&
741 !(mvitals[PM_SOLDIER].mvflags & G_GONE)) mkroom(BARRACKS);
742 else if (u_depth > 15 && !rn2(6)) mkroom(SWAMP);
743 else if (u_depth > 16 && !rn2(8) &&
744 !(mvitals[PM_COCKATRICE].mvflags & G_GONE)) mkroom(COCKNEST);
750 /* Place multi-dungeon branch. */
751 place_branch(branchp, 0, 0);
753 /* for each room: put things inside */
754 for(croom = rooms; croom->hx > 0; croom++) {
755 if(croom->rtype != OROOM) continue;
757 /* put a sleeping monster inside */
758 /* Note: monster may be on the stairs. This cannot be
759 avoided: maybe the player fell through a trap door
760 while a monster was on the stairs. Conclusion:
761 we have to check for monsters on the stairs anyway. */
763 if(u.uhave.amulet || !rn2(3)) {
764 x = somex(croom); y = somey(croom);
765 tmonst = makemon((struct permonst *) 0, x,y,NO_MM_FLAGS);
766 if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] &&
768 (void) maketrap(x, y, WEB);
770 /* put traps and mimics inside */
772 x = 8 - (level_difficulty()/6);
775 mktrap(0,0,croom,(coord*)0);
776 if (!goldseen && !rn2(3))
777 (void) mkgold(0L, somex(croom), somey(croom));
779 if(Is_rogue_level(&u.uz)) goto skip_nonrogue;
781 if(!rn2(10)) mkfount(0,croom);
783 if(!rn2(60)) mksink(croom);
785 if(!rn2(60)) mkaltar(croom);
786 x = 80 - (depth(&u.uz) * 2);
788 if(!rn2(x)) mkgrave(croom);
790 /* put statues inside */
792 (void) mkcorpstat(STATUE, (struct monst *)0,
793 (struct permonst *)0,
794 somex(croom), somey(croom), TRUE);
795 /* put box/chest inside;
796 * 40% chance for at least 1 box, regardless of number
797 * of rooms; about 5 - 7.5% for 2 boxes, least likely
798 * when few rooms; chance for 3 or more is neglible.
800 if(!rn2(nroom * 5 / 2))
801 (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
802 somex(croom), somey(croom), TRUE, FALSE);
804 /* maybe make some graffiti */
805 if(!rn2(27 + 3 * abs(depth(&u.uz)))) {
807 const char *mesg = random_engraving(buf);
810 x = somex(croom); y = somey(croom);
811 } while(levl[x][y].typ != ROOM && !rn2(40));
812 if (!(IS_POOL(levl[x][y].typ) ||
813 IS_FURNITURE(levl[x][y].typ)))
814 make_engr_at(x, y, mesg, 0L, MARK);
822 (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
826 impossible("tryct overflow4");
829 (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
836 * Place deposits of minerals (gold and misc gems) in the stone
837 * surrounding the rooms on the map.
838 * Also place kelp in water.
845 int goldprob, gemprob, x, y, cnt;
848 /* Place kelp, except on the plane of water */
849 if (In_endgame(&u.uz)) return;
850 for (x = 2; x < (COLNO - 2); x++)
851 for (y = 1; y < (ROWNO - 1); y++)
852 if ((levl[x][y].typ == POOL && !rn2(10)) ||
853 (levl[x][y].typ == MOAT && !rn2(30)))
854 (void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE);
856 /* determine if it is even allowed;
857 almost all special levels are excluded */
858 if (In_hell(&u.uz) || In_V_tower(&u.uz) ||
860 Is_rogue_level(&u.uz) ||
862 level.flags.arboreal ||
863 ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz)
864 && (!In_mines(&u.uz) || sp->flags.town)
867 /* basic level-related probabilities */
868 goldprob = 20 + depth(&u.uz) / 3;
869 gemprob = goldprob / 4;
871 /* mines have ***MORE*** goodies - otherwise why mine? */
872 if (In_mines(&u.uz)) {
875 } else if (In_quest(&u.uz)) {
881 * Seed rock areas with gold and/or gems.
882 * We use fairly low level object handling to avoid unnecessary
883 * overhead from placing things in the floor chain prior to burial.
885 for (x = 2; x < (COLNO - 2); x++)
886 for (y = 1; y < (ROWNO - 1); y++)
887 if (levl[x][y+1].typ != STONE) { /* <x,y> spot not eligible */
888 y += 2; /* next two spots aren't eligible either */
889 } else if (levl[x][y].typ != STONE) { /* this spot not eligible */
890 y += 1; /* next spot isn't eligible either */
891 } else if (!(levl[x][y].wall_info & W_NONDIGGABLE) &&
892 levl[x][y-1].typ == STONE &&
893 levl[x+1][y-1].typ == STONE && levl[x-1][y-1].typ == STONE &&
894 levl[x+1][y].typ == STONE && levl[x-1][y].typ == STONE &&
895 levl[x+1][y+1].typ == STONE && levl[x-1][y+1].typ == STONE) {
896 if (rn2(1000) < goldprob) {
897 if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) {
898 otmp->ox = x, otmp->oy = y;
899 otmp->quan = 1L + rnd(goldprob * 3);
900 otmp->owt = weight(otmp);
901 if (!rn2(3)) add_to_buried(otmp);
902 else place_object(otmp, x, y);
905 if (rn2(1000) < gemprob) {
906 for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--)
907 if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) {
908 if (otmp->otyp == ROCK) {
909 dealloc_obj(otmp); /* discard it */
911 otmp->ox = x, otmp->oy = y;
912 if (!rn2(3)) add_to_buried(otmp);
913 else place_object(otmp, x, y);
923 struct mkroom *croom;
925 if(getbones()) return;
931 /* has_morgue gets cleared once morgue is entered; graveyard stays
932 set (graveyard might already be set even when has_morgue is clear
933 [see fixup_special()], so don't update it unconditionally) */
934 if (level.flags.has_morgue)
935 level.flags.graveyard = 1;
936 if (!level.flags.is_maze_lev) {
937 for (croom = &rooms[0]; croom != &rooms[nroom]; croom++)
938 #ifdef SPECIALIZATION
939 topologize(croom, FALSE);
948 #ifdef SPECIALIZATION
949 topologize(croom, do_ordinary)
950 register struct mkroom *croom;
954 register struct mkroom *croom;
957 register int x, y, roomno = (croom - rooms) + ROOMOFFSET;
958 register int lowx = croom->lx, lowy = croom->ly;
959 register int hix = croom->hx, hiy = croom->hy;
960 #ifdef SPECIALIZATION
961 register schar rtype = croom->rtype;
963 register int subindex, nsubrooms = croom->nsubrooms;
965 /* skip the room if already done; i.e. a shop handled out of order */
966 /* also skip if this is non-rectangular (it _must_ be done already) */
967 if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular)
969 #ifdef SPECIALIZATION
970 # ifdef REINCARNATION
971 if (Is_rogue_level(&u.uz))
972 do_ordinary = TRUE; /* vision routine helper */
974 if ((rtype != OROOM) || do_ordinary)
977 /* do innards first */
978 for(x = lowx; x <= hix; x++)
979 for(y = lowy; y <= hiy; y++)
980 #ifdef SPECIALIZATION
982 levl[x][y].roomno = NO_ROOM;
985 levl[x][y].roomno = roomno;
986 /* top and bottom edges */
987 for(x = lowx-1; x <= hix+1; x++)
988 for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
990 if (levl[x][y].roomno)
991 levl[x][y].roomno = SHARED;
993 levl[x][y].roomno = roomno;
996 for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
997 for(y = lowy; y <= hiy; y++) {
999 if (levl[x][y].roomno)
1000 levl[x][y].roomno = SHARED;
1002 levl[x][y].roomno = roomno;
1006 for (subindex = 0; subindex < nsubrooms; subindex++)
1007 #ifdef SPECIALIZATION
1008 topologize(croom->sbrooms[subindex], (rtype != OROOM));
1010 topologize(croom->sbrooms[subindex]);
1014 /* Find an unused room for a branch location. */
1015 STATIC_OVL struct mkroom *
1016 find_branch_room(mp)
1019 struct mkroom *croom = 0;
1022 mazexy(mp); /* already verifies location */
1024 /* not perfect - there may be only one stairway */
1029 croom = &rooms[rn2(nroom)];
1030 while((croom == dnstairs_room || croom == upstairs_room ||
1031 croom->rtype != OROOM) && (++tryct < 100));
1033 croom = &rooms[rn2(nroom)];
1036 if (!somexy(croom, mp))
1037 impossible("Can't place branch!");
1038 } while(occupied(mp->x, mp->y) ||
1039 (levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM));
1044 /* Find the room for (x,y). Return null if not in a room. */
1045 STATIC_OVL struct mkroom *
1050 struct mkroom *curr;
1052 for (curr = rooms, i = 0; i < nroom; curr++, i++)
1053 if (inside_room(curr, x, y)) return curr;;
1054 return (struct mkroom *) 0;
1058 /* If given a branch, randomly place a special stair or portal. */
1060 place_branch(br, x, y)
1061 branch *br; /* branch to place */
1062 xchar x, y; /* location */
1066 boolean make_stairs;
1067 struct mkroom *br_room;
1070 * Return immediately if there is no branch to make or we have
1071 * already made one. This routine can be called twice when
1072 * a special level is loaded that specifies an SSTAIR location
1073 * as a favored spot for a branch.
1075 if (!br || made_branch) return;
1077 if (!x) { /* find random coordinates for branch */
1078 br_room = find_branch_room(&m);
1082 br_room = pos_to_room(x, y);
1085 if (on_level(&br->end1, &u.uz)) {
1087 make_stairs = br->type != BR_NO_END1;
1091 make_stairs = br->type != BR_NO_END2;
1095 if (br->type == BR_PORTAL) {
1096 mkportal(x, y, dest->dnum, dest->dlevel);
1097 } else if (make_stairs) {
1100 sstairs.up = (char) on_level(&br->end1, &u.uz) ?
1101 br->end1_up : !br->end1_up;
1102 assign_level(&sstairs.tolev, dest);
1103 sstairs_room = br_room;
1105 levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN;
1106 levl[x][y].typ = STAIRS;
1109 * Set made_branch to TRUE even if we didn't make a stairwell (i.e.
1110 * make_stairs is false) since there is currently only one branch
1111 * per level, if we failed once, we're going to fail again on the
1119 register xchar x, y;
1124 typ = levl[x+1][y].typ;
1125 if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1128 typ = levl[x-1][y].typ;
1129 if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1132 typ = levl[x][y+1].typ;
1133 if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1136 typ = levl[x][y-1].typ;
1137 if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1142 /* see whether it is allowable to create a door at [x,y] */
1145 register xchar x, y;
1147 register boolean near_door = bydoor(x, y);
1149 return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) &&
1150 doorindex < DOORMAX && !near_door);
1156 register struct mkroom *aroom;
1158 if(doorindex >= DOORMAX) {
1159 impossible("DOORMAX exceeded?");
1163 dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
1168 register xchar x, y;
1170 return((boolean)(t_at(x, y)
1171 || IS_FURNITURE(levl[x][y].typ)
1174 || invocation_pos(x,y)
1178 /* make a trap somewhere (in croom if mazeflag = 0 && !tm) */
1179 /* if tm != null, make trap at that location */
1181 mktrap(num, mazeflag, croom, tm)
1182 register int num, mazeflag;
1183 register struct mkroom *croom;
1189 /* no traps in pools */
1190 if (tm && is_pool(tm->x,tm->y)) return;
1192 if (num > 0 && num < TRAPNUM) {
1194 #ifdef REINCARNATION
1195 } else if (Is_rogue_level(&u.uz)) {
1197 default: kind = BEAR_TRAP; break; /* 0 */
1198 case 1: kind = ARROW_TRAP; break;
1199 case 2: kind = DART_TRAP; break;
1200 case 3: kind = TRAPDOOR; break;
1201 case 4: kind = PIT; break;
1202 case 5: kind = SLP_GAS_TRAP; break;
1203 case 6: kind = RUST_TRAP; break;
1206 } else if (Inhell && !rn2(5)) {
1207 /* bias the frequency of fire traps in Gehennom */
1210 unsigned lvl = level_difficulty();
1213 kind = rnd(TRAPNUM-1);
1214 /* reject "too hard" traps */
1217 kind = NO_TRAP; break;
1218 case ROLLING_BOULDER_TRAP:
1220 if (lvl < 2) kind = NO_TRAP; break;
1222 if (lvl < 5 || level.flags.noteleport)
1223 kind = NO_TRAP; break;
1225 if (lvl < 5) kind = NO_TRAP; break;
1227 if (lvl < 6) kind = NO_TRAP; break;
1229 if (lvl < 7) kind = NO_TRAP; break;
1232 if (lvl < 8) kind = NO_TRAP; break;
1234 if (!Inhell) kind = NO_TRAP; break;
1236 if (level.flags.noteleport) kind = NO_TRAP; break;
1238 /* make these much less often than other traps */
1239 if (rn2(7)) kind = NO_TRAP; break;
1241 } while (kind == NO_TRAP);
1244 if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz))
1250 register int tryct = 0;
1251 boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT ||
1252 kind == TRAPDOOR || kind == HOLE);
1259 else if (!somexy(croom,&m))
1261 } while (occupied(m.x, m.y) ||
1262 (avoid_boulder && sobj_at(BOULDER, m.x, m.y)));
1265 (void) maketrap(m.x, m.y, kind);
1266 if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER],
1267 m.x, m.y, NO_MM_FLAGS);
1271 mkstairs(x, y, up, croom)
1274 struct mkroom *croom;
1277 impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y);
1282 * We can't make a regular stair off an end of the dungeon. This
1283 * attempt can happen when a special level is placed at an end and
1284 * has an up or down stair specified in its description file.
1286 if ((dunlev(&u.uz) == 1 && up) ||
1287 (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up))
1293 upstairs_room = croom;
1297 dnstairs_room = croom;
1300 levl[x][y].typ = STAIRS;
1301 levl[x][y].ladder = up ? LA_UP : LA_DOWN;
1306 mkfount(mazeflag,croom)
1307 register int mazeflag;
1308 register struct mkroom *croom;
1311 register int tryct = 0;
1314 if(++tryct > 200) return;
1318 if (!somexy(croom, &m))
1320 } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
1322 /* Put a fountain at m.x, m.y */
1323 levl[m.x][m.y].typ = FOUNTAIN;
1324 /* Is it a "blessed" fountain? (affects drinking from fountain) */
1325 if(!rn2(7)) levl[m.x][m.y].blessedftn = 1;
1327 level.flags.nfountains++;
1333 register struct mkroom *croom;
1336 register int tryct = 0;
1339 if(++tryct > 200) return;
1340 if (!somexy(croom, &m))
1342 } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
1344 /* Put a sink at m.x, m.y */
1345 levl[m.x][m.y].typ = SINK;
1347 level.flags.nsinks++;
1354 register struct mkroom *croom;
1357 register int tryct = 0;
1360 if (croom->rtype != OROOM) return;
1363 if(++tryct > 200) return;
1364 if (!somexy(croom, &m))
1366 } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1368 /* Put an altar at m.x, m.y */
1369 levl[m.x][m.y].typ = ALTAR;
1371 /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
1372 al = rn2((int)A_LAWFUL+2) - 1;
1373 levl[m.x][m.y].altarmask = Align2amask( al );
1378 struct mkroom *croom;
1381 register int tryct = 0;
1382 register struct obj *otmp;
1383 boolean dobell = !rn2(10);
1386 if(croom->rtype != OROOM) return;
1389 if(++tryct > 200) return;
1390 if (!somexy(croom, &m))
1392 } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1394 /* Put a grave at m.x, m.y */
1395 make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0);
1397 /* Possibly fill it with objects */
1398 if (!rn2(3)) (void) mkgold(0L, m.x, m.y);
1399 for (tryct = rn2(5); tryct; tryct--) {
1400 otmp = mkobj(RANDOM_CLASS, TRUE);
1405 add_to_buried(otmp);
1408 /* Leave a bell, in case we accidentally buried someone alive */
1409 if (dobell) (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE);
1414 /* maze levels have slightly different constraints from normal levels */
1415 #define x_maze_min 2
1416 #define y_maze_min 2
1418 * Major level transmutation: add a set of stairs (to the Sanctum) after
1419 * an earthquake that leaves behind a a new topology, centered at inv_pos.
1420 * Assumes there are no rooms within the invocation area and that inv_pos
1421 * is not too close to the edge of the map. Also assume the hero can see,
1422 * which is guaranteed for normal play due to the fact that sight is needed
1423 * to read the Book of the Dead.
1429 xchar xmin = inv_pos.x, xmax = inv_pos.x;
1430 xchar ymin = inv_pos.y, ymax = inv_pos.y;
1433 pline_The("floor shakes violently under you!");
1434 pline_The("walls around you begin to bend and crumble!");
1435 display_nhwindow(WIN_MESSAGE, TRUE);
1437 mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */
1439 for(dist = 1; dist < 7; dist++) {
1442 /* top and bottom */
1443 if(dist != 3) { /* the area is wider that it is high */
1445 for(i = xmin+1; i < xmax; i++) {
1446 mkinvpos(i, ymin, dist);
1447 mkinvpos(i, ymax, dist);
1451 /* left and right */
1452 for(i = ymin; i <= ymax; i++) {
1453 mkinvpos(xmin, i, dist);
1454 mkinvpos(xmax, i, dist);
1457 flush_screen(1); /* make sure the new glyphs shows up */
1461 You("are standing at the top of a stairwell leading down!");
1462 mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */
1464 vision_full_recalc = 1; /* everything changed */
1467 /* Change level topology. Boulders in the vicinity are eliminated.
1468 * Temporarily overrides vision in the name of a nice effect.
1478 register struct rm *lev = &levl[x][y];
1480 /* clip at existing map borders if necessary */
1481 if (!within_bounded_area(x, y, x_maze_min + 1, y_maze_min + 1,
1482 x_maze_max - 1, y_maze_max - 1)) {
1483 /* only outermost 2 columns and/or rows may be truncated due to edge */
1485 panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist);
1490 if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
1492 /* clear boulders; leave some rocks for non-{moat|trap} locations */
1493 make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE;
1494 while ((otmp = sobj_at(BOULDER, x, y)) != 0) {
1496 fracture_rock(otmp);
1497 make_rocks = FALSE; /* don't bother with more rocks */
1499 obj_extract_self(otmp);
1500 obfree(otmp, (struct obj *)0);
1503 unblock_point(x,y); /* make sure vision knows this location is open */
1505 /* fake out saved state */
1508 if(dist < 6) lev->lit = TRUE;
1510 lev->horizontal = FALSE;
1511 viz_array[y][x] = (dist < 6 ) ?
1512 (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
1516 case 1: /* fire traps */
1517 if (is_pool(x,y)) break;
1519 ttmp = maketrap(x, y, FIRE_TRAP);
1520 if (ttmp) ttmp->tseen = TRUE;
1522 case 0: /* lit room locations */
1525 case 6: /* unlit room locations */
1528 case 4: /* pools (aka a wide moat) */
1534 impossible("mkinvpos called with dist %d", dist);
1538 /* display new value of position; could have a monster/object on it */
1543 * The portal to Ludios is special. The entrance can only occur within a
1544 * vault in the main dungeon at a depth greater than 10. The Ludios branch
1545 * structure reflects this by having a bogus "source" dungeon: the value
1546 * of n_dgns (thus, Is_branchlev() will never find it).
1548 * Ludios will remain isolated until the branch is corrected by this function.
1551 mk_knox_portal(x, y)
1554 extern int n_dgns; /* from dungeon.c */
1559 br = dungeon_branch("Fort Ludios");
1560 if (on_level(&knox_level, &br->end1)) {
1563 /* disallow Knox branch on a level with one branch already */
1564 if(Is_branchlev(&u.uz))
1569 /* Already set or 2/3 chance of deferring until a later level. */
1570 if (source->dnum < n_dgns || (rn2(3)
1576 if (! (u.uz.dnum == oracle_level.dnum /* in main dungeon */
1577 && !at_dgn_entrance("The Quest") /* but not Quest's entry */
1578 && (u_depth = depth(&u.uz)) > 10 /* beneath 10 */
1579 && u_depth < depth(&medusa_level))) /* and above Medusa */
1582 /* Adjust source to be current level and re-insert branch. */
1584 insert_branch(br, TRUE);
1587 pline("Made knox portal.");
1589 place_branch(br, x, y);