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. */ 4 5#include "hack.h" 6/* #define DEBUG */ /* uncomment to enable code debugging */ 7 8#ifdef NETHACK_DEBUG 9# ifdef WIZARD 10#define debugpline if (wizard) pline 11# else 12#define debugpline pline 13# endif 14#endif 15 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 */ 19 20 21STATIC_DCL void FDECL(mkfount,(int,struct mkroom *)); 22#ifdef SINKS 23STATIC_DCL void FDECL(mksink,(struct mkroom *)); 24#endif 25STATIC_DCL void FDECL(mkaltar,(struct mkroom *)); 26STATIC_DCL void FDECL(mkgrave,(struct mkroom *)); 27STATIC_DCL void NDECL(makevtele); 28STATIC_DCL void NDECL(clear_level_structures); 29STATIC_DCL void NDECL(makelevel); 30STATIC_DCL void NDECL(mineralize); 31STATIC_DCL boolean FDECL(bydoor,(XCHAR_P,XCHAR_P)); 32STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *)); 33STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P)); 34STATIC_DCL boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*)); 35STATIC_DCL void FDECL(makeniche,(int)); 36STATIC_DCL void NDECL(make_niches); 37 38STATIC_PTR int FDECL( CFDECLSPEC do_comp,(const genericptr,const genericptr)); 39 40STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int)); 41STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P)); 42STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int, 43 BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P)); 44STATIC_DCL void NDECL(makerooms); 45STATIC_DCL void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); 46STATIC_DCL void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int)); 47STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P)); 48 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) 52static xchar vault_x, vault_y; 53boolean goldseen; 54static boolean made_branch; /* used only during level creation */ 55 56/* Args must be (const genericptr) so that qsort will always be happy. */ 57 58STATIC_PTR int CFDECLSPEC 59do_comp(vx,vy) 60const genericptr vx; 61const genericptr vy; 62{ 63#ifdef LINT 64/* lint complains about possible pointer alignment problems, but we know 65 that vx and vy are always properly aligned. Hence, the following 66 bogus definition: 67*/ 68 return (vx == vy) ? 0 : -1; 69#else 70 register const struct mkroom *x, *y; 71 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); 76#endif /* LINT */ 77} 78 79STATIC_OVL void 80finddpos(cc, xl,yl,xh,yh) 81coord *cc; 82xchar xl,yl,xh,yh; 83{ 84 register xchar x, y; 85 86 x = (xl == xh) ? xl : (xl + rn2(xh-xl+1)); 87 y = (yl == yh) ? yl : (yl + rn2(yh-yl+1)); 88 if(okdoor(x, y)) 89 goto gotit; 90 91 for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++) 92 if(okdoor(x, y)) 93 goto gotit; 94 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) 97 goto gotit; 98 /* cannot find something reasonable -- strange */ 99 x = xl; 100 y = yh; 101gotit: 102 cc->x = x; 103 cc->y = y; 104 return; 105} 106 107void 108sort_rooms() 109{ 110#if defined(SYSV) || defined(DGUX) 111 qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp); 112#else 113 qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp); 114#endif 115} 116 117STATIC_OVL void 118do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room) 119 register struct mkroom *croom; 120 int lowx, lowy; 121 register int hix, hiy; 122 boolean lit; 123 schar rtype; 124 boolean special; 125 boolean is_room; 126{ 127 register int x, y; 128 struct rm *lev; 129 130 /* locations might bump level edges in wall-less rooms */ 131 /* add/subtract 1 to allow for edge locations */ 132 if(!lowx) lowx++; 133 if(!lowy) lowy++; 134 if(hix >= COLNO-1) hix = COLNO-2; 135 if(hiy >= ROWNO-1) hiy = ROWNO-2; 136 137 if(lit) { 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++) 141 lev++->lit = 1; 142 } 143 croom->rlit = 1; 144 } else 145 croom->rlit = 0; 146 147 croom->lx = lowx; 148 croom->hx = hix; 149 croom->ly = lowy; 150 croom->hy = hiy; 151 croom->rtype = rtype; 152 croom->doorct = 0; 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 156 */ 157 croom->fdoor = doorindex; 158 croom->irregular = FALSE; 159 160 croom->nsubrooms = 0; 161 croom->sbrooms[0] = (struct mkroom *) 0; 162 if (!special) { 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. */ 167 } 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. */ 172 } 173 for(x = lowx; x <= hix; x++) { 174 lev = &levl[x][lowy]; 175 for(y = lowy; y <= hiy; y++) 176 lev++->typ = ROOM; 177 } 178 if (is_room) { 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); 185 } 186 } 187} 188 189 190void 191add_room(lowx, lowy, hix, hiy, lit, rtype, special) 192register int lowx, lowy, hix, hiy; 193boolean lit; 194schar rtype; 195boolean special; 196{ 197 register struct mkroom *croom; 198 199 croom = &rooms[nroom]; 200 do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, 201 rtype, special, (boolean) TRUE); 202 croom++; 203 croom->hx = -1; 204 nroom++; 205} 206 207void 208add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special) 209struct mkroom *proom; 210register int lowx, lowy, hix, hiy; 211boolean lit; 212schar rtype; 213boolean special; 214{ 215 register struct mkroom *croom; 216 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; 221 croom++; 222 croom->hx = -1; 223 nsubroom++; 224} 225 226STATIC_OVL void 227makerooms() 228{ 229 boolean tried_vault = FALSE; 230 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) { 235 tried_vault = TRUE; 236 if (create_vault()) { 237 vault_x = rooms[nroom].lx; 238 vault_y = rooms[nroom].ly; 239 rooms[nroom].hx = -1; 240 } 241 } else 242 if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1)) 243 return; 244 } 245 return; 246} 247 248STATIC_OVL void 249join(a,b,nxcor) 250register int a, b; 251boolean nxcor; 252{ 253 coord cc,tt, org, dest; 254 register xchar tx, ty, xx, yy; 255 register struct mkroom *croom, *troom; 256 register int dx, dy; 257 258 croom = &rooms[a]; 259 troom = &rooms[b]; 260 261 /* find positions cc and tt for doors in croom and troom 262 and direction for a corridor between them */ 263 264 if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return; 265 if(troom->lx > croom->hx) { 266 dx = 1; 267 dy = 0; 268 xx = croom->hx+1; 269 tx = troom->lx-1; 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) { 273 dy = -1; 274 dx = 0; 275 yy = croom->ly-1; 276 finddpos(&cc, croom->lx, yy, croom->hx, yy); 277 ty = troom->hy+1; 278 finddpos(&tt, troom->lx, ty, troom->hx, ty); 279 } else if(troom->hx < croom->lx) { 280 dx = -1; 281 dy = 0; 282 xx = croom->lx-1; 283 tx = troom->hx+1; 284 finddpos(&cc, xx, croom->ly, xx, croom->hy); 285 finddpos(&tt, tx, troom->ly, tx, troom->hy); 286 } else { 287 dy = 1; 288 dx = 0; 289 yy = croom->hy+1; 290 ty = troom->ly-1; 291 finddpos(&cc, croom->lx, yy, croom->hx, yy); 292 finddpos(&tt, troom->lx, ty, troom->hx, ty); 293 } 294 xx = cc.x; 295 yy = cc.y; 296 tx = tt.x - dx; 297 ty = tt.y - dy; 298 if(nxcor && levl[xx+dx][yy+dy].typ) 299 return; 300 if (okdoor(xx,yy) || !nxcor) 301 dodoor(xx,yy,croom); 302 303 org.x = xx+dx; org.y = yy+dy; 304 dest.x = tx; dest.y = ty; 305 306 if (!dig_corridor(&org, &dest, nxcor, 307 level.flags.arboreal ? ROOM : CORR, STONE)) 308 return; 309 310 /* we succeeded in digging the corridor */ 311 if (okdoor(tt.x, tt.y) || !nxcor) 312 dodoor(tt.x, tt.y, troom); 313 314 if(smeq[a] < smeq[b]) 315 smeq[b] = smeq[a]; 316 else 317 smeq[a] = smeq[b]; 318} 319 320void 321makecorridors() 322{ 323 int a, b, i; 324 boolean any = TRUE; 325 326 for(a = 0; a < nroom-1; a++) { 327 join(a, a+1, FALSE); 328 if(!rn2(50)) break; /* allow some randomness */ 329 } 330 for(a = 0; a < nroom-2; a++) 331 if(smeq[a] != smeq[a+2]) 332 join(a, a+2, FALSE); 333 for(a = 0; any && a < nroom; a++) { 334 any = FALSE; 335 for(b = 0; b < nroom; b++) 336 if(smeq[a] != smeq[b]) { 337 join(a, b, FALSE); 338 any = TRUE; 339 } 340 } 341 if(nroom > 2) 342 for(i = rn2(nroom) + 4; i; i--) { 343 a = rn2(nroom); 344 b = rn2(nroom-2); 345 if(b >= a) b += 2; 346 join(a, b, TRUE); 347 } 348} 349 350void 351add_door(x,y,aroom) 352register int x, y; 353register struct mkroom *aroom; 354{ 355 register struct mkroom *broom; 356 register int tmp; 357 358 aroom->doorct++; 359 broom = aroom+1; 360 if(broom->hx < 0) 361 tmp = doorindex; 362 else 363 for(tmp = doorindex; tmp > broom->fdoor; tmp--) 364 doors[tmp] = doors[tmp-1]; 365 doorindex++; 366 doors[tmp].x = x; 367 doors[tmp].y = y; 368 for( ; broom->hx >= 0; broom++) broom->fdoor++; 369} 370 371STATIC_OVL void 372dosdoor(x,y,aroom,type) 373register xchar x, y; 374register struct mkroom *aroom; 375register int type; 376{ 377 boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE); 378 379 if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */ 380 type = DOOR; 381 levl[x][y].typ = type; 382 if(type == DOOR) { 383 if(!rn2(3)) { /* is it a locked door, closed, or a doorway? */ 384 if(!rn2(5)) 385 levl[x][y].doormask = D_ISOPEN; 386 else if(!rn2(6)) 387 levl[x][y].doormask = D_LOCKED; 388 else 389 levl[x][y].doormask = D_CLOSED; 390 391 if (levl[x][y].doormask != D_ISOPEN && !shdoor && 392 level_difficulty() >= 5 && !rn2(25)) 393 levl[x][y].doormask |= D_TRAPPED; 394 } else 395#ifdef STUPID 396 if (shdoor) 397 levl[x][y].doormask = D_ISOPEN; 398 else 399 levl[x][y].doormask = D_NODOOR; 400#else 401 levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR); 402#endif 403 if(levl[x][y].doormask & D_TRAPPED) { 404 struct monst *mtmp; 405 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); 413 if (mtmp) 414 set_mimic_sym(mtmp); 415 } 416 } 417 /* newsym(x,y); */ 418 } else { /* SDOOR */ 419 if(shdoor || !rn2(5)) levl[x][y].doormask = D_LOCKED; 420 else levl[x][y].doormask = D_CLOSED; 421 422 if(!shdoor && level_difficulty() >= 4 && !rn2(20)) 423 levl[x][y].doormask |= D_TRAPPED; 424 } 425 426 add_door(x,y,aroom); 427} 428 429STATIC_OVL boolean 430place_niche(aroom,dy,xx,yy) 431register struct mkroom *aroom; 432int *dy, *xx, *yy; 433{ 434 coord dd; 435 436 if(rn2(2)) { 437 *dy = 1; 438 finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1); 439 } else { 440 *dy = -1; 441 finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1); 442 } 443 *xx = dd.x; 444 *yy = dd.y; 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)))); 448} 449 450/* there should be one of these per trap, in the same order as trap.h */ 451static 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, 458 (char *)0, 459}; 460 461STATIC_OVL void 462makeniche(trap_type) 463int trap_type; 464{ 465 register struct mkroom *aroom; 466 register struct rm *rm; 467 register int vct = 8; 468 int dy, xx, yy; 469 register struct trap *ttmp; 470 471 if(doorindex < DOORMAX) 472 while(vct--) { 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; 477 478 rm = &levl[xx][yy+dy]; 479 if(trap_type || !rn2(4)) { 480 481 rm->typ = SCORR; 482 if(trap_type) { 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); 487 if (ttmp) { 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 */ 493 } 494 } 495 } 496 dosdoor(xx, yy, aroom, SDOOR); 497 } else { 498 rm->typ = CORR; 499 if(rn2(7)) 500 dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR); 501 else { 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); 506 } 507 } 508 return; 509 } 510} 511 512STATIC_OVL void 513make_niches() 514{ 515 register int ct = rnd((nroom>>1) + 1), dep = depth(&u.uz); 516 517 boolean ltptr = (!level.flags.noteleport && dep > 15), 518 vamp = (dep > 5 && dep < 25); 519 520 while(ct--) { 521 if (ltptr && !rn2(6)) { 522 ltptr = FALSE; 523 makeniche(LEVEL_TELEP); 524 } else if (vamp && !rn2(6)) { 525 vamp = FALSE; 526 makeniche(TRAPDOOR); 527 } else makeniche(NO_TRAP); 528 } 529} 530 531STATIC_OVL void 532makevtele() 533{ 534 makeniche(TELEP_TRAP); 535} 536 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. 541 */ 542STATIC_OVL void 543clear_level_structures() 544{ 545 static struct rm zerorm = { cmap_to_glyph(S_stone), 546 0, 0, 0, 0, 0, 0, 0, 0 }; 547 register int x,y; 548 register struct rm *lev; 549 550 for(x=0; x<COLNO; x++) { 551 lev = &levl[x][0]; 552 for(y=0; y<ROWNO; y++) { 553 *lev++ = zerorm; 554#ifdef MICROPORT_BUG 555 level.objects[x][y] = (struct obj *)0; 556 level.monsters[x][y] = (struct monst *)0; 557#endif 558 } 559 } 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)); 563#endif 564 level.objlist = (struct obj *)0; 565 level.buriedobjlist = (struct obj *)0; 566 level.monlist = (struct monst *)0; 567 level.damagelist = (struct damage *)0; 568 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; 588 589 nroom = 0; 590 rooms[0].hx = -1; 591 nsubroom = 0; 592 subrooms[0].hx = -1; 593 doorindex = 0; 594 init_rect(); 595 init_vault(); 596 xdnstair = ydnstair = xupstair = yupstair = 0; 597 sstairs.sx = sstairs.sy = 0; 598 xdnladder = ydnladder = xupladder = yupladder = 0; 599 made_branch = FALSE; 600 clear_regions(); 601} 602 603STATIC_OVL void 604makelevel() 605{ 606 register struct mkroom *croom, *troom; 607 register int tryct; 608 register int x, y; 609 struct monst *tmonst; /* always put a web with a spider */ 610 branch *branchp; 611 int room_threshold; 612 613 if(wiz1_level.dlevel == 0) init_dungeons(); 614 oinit(); /* assign level dependent obj probabilities */ 615 clear_level_structures(); 616 617 { 618 register s_level *slev = Is_special(&u.uz); 619 620 /* check for special levels */ 621#ifdef REINCARNATION 622 if (slev && !Is_rogue_level(&u.uz)) 623#else 624 if (slev) 625#endif 626 { 627 makemaz(slev->proto); 628 return; 629 } else if (dungeons[u.uz.dnum].proto[0]) { 630 makemaz(""); 631 return; 632 } else if (In_mines(&u.uz)) { 633 makemaz("minefill"); 634 return; 635 } else if (In_quest(&u.uz)) { 636 char fillname[9]; 637 s_level *loc_lev; 638 639 Sprintf(fillname, "%s-loca", urole.filecode); 640 loc_lev = find_level(fillname); 641 642 Sprintf(fillname, "%s-fil", urole.filecode); 643 Strcat(fillname, 644 (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b"); 645 makemaz(fillname); 646 return; 647 } else if(In_hell(&u.uz) || 648 (rn2(5) && u.uz.dnum == medusa_level.dnum 649 && depth(&u.uz) > depth(&medusa_level))) { 650 makemaz(""); 651 return; 652 } 653 } 654 655 /* otherwise, fall through - it's a "regular" level. */ 656 657#ifdef REINCARNATION 658 if (Is_rogue_level(&u.uz)) { 659 makeroguerooms(); 660 makerogueghost(); 661 } else 662#endif 663 makerooms(); 664 sort_rooms(); 665 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 */ 670 if (nroom > 1) { 671 troom = croom; 672 croom = &rooms[rn2(nroom-1)]; 673 if (croom == troom) croom++; 674 } 675 676 if (u.uz.dlevel != 1) { 677 xchar sx, sy; 678 do { 679 sx = somex(croom); 680 sy = somey(croom); 681 } while(occupied(sx, sy)); 682 mkstairs(sx, sy, 1, croom); /* up */ 683 } 684 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 */ 688#ifdef REINCARNATION 689 if (Is_rogue_level(&u.uz)) goto skip0; 690#endif 691 makecorridors(); 692 make_niches(); 693 694 /* make a secret treasure vault, not connected to the rest */ 695 if(do_vault()) { 696 xchar w,h; 697#ifdef NETHACK_DEBUG 698 debugpline("trying to make a vault..."); 699#endif 700 w = 1; 701 h = 1; 702 if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) { 703 fill_vault: 704 add_room(vault_x, vault_y, vault_x+w, 705 vault_y+h, TRUE, VAULT, FALSE); 706 level.flags.has_vault = 1; 707 ++room_threshold; 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)) 715 goto fill_vault; 716 else 717 rooms[nroom].hx = -1; 718 } 719 } 720 721 { 722 register int u_depth = depth(&u.uz); 723 724#ifdef WIZARD 725 if(wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else 726#endif 727 if (u_depth > 1 && 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); 745 } 746 747#ifdef REINCARNATION 748skip0: 749#endif 750 /* Place multi-dungeon branch. */ 751 place_branch(branchp, 0, 0); 752 753 /* for each room: put things inside */ 754 for(croom = rooms; croom->hx > 0; croom++) { 755 if(croom->rtype != OROOM) continue; 756 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. */ 762 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] && 767 !occupied(x, y)) 768 (void) maketrap(x, y, WEB); 769 } 770 /* put traps and mimics inside */ 771 goldseen = FALSE; 772 x = 8 - (level_difficulty()/6); 773 if (x <= 1) x = 2; 774 while (!rn2(x)) 775 mktrap(0,0,croom,(coord*)0); 776 if (!goldseen && !rn2(3)) 777 (void) mkgold(0L, somex(croom), somey(croom)); 778#ifdef REINCARNATION 779 if(Is_rogue_level(&u.uz)) goto skip_nonrogue; 780#endif 781 if(!rn2(10)) mkfount(0,croom); 782#ifdef SINKS 783 if(!rn2(60)) mksink(croom); 784#endif 785 if(!rn2(60)) mkaltar(croom); 786 x = 80 - (depth(&u.uz) * 2); 787 if (x < 2) x = 2; 788 if(!rn2(x)) mkgrave(croom); 789 790 /* put statues inside */ 791 if(!rn2(20)) 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. 799 */ 800 if(!rn2(nroom * 5 / 2)) 801 (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, 802 somex(croom), somey(croom), TRUE, FALSE); 803 804 /* maybe make some graffiti */ 805 if(!rn2(27 + 3 * abs(depth(&u.uz)))) { 806 char buf[BUFSZ]; 807 const char *mesg = random_engraving(buf); 808 if (mesg) { 809 do { 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); 815 } 816 } 817 818#ifdef REINCARNATION 819 skip_nonrogue: 820#endif 821 if(!rn2(3)) { 822 (void) mkobj_at(0, somex(croom), somey(croom), TRUE); 823 tryct = 0; 824 while(!rn2(5)) { 825 if(++tryct > 100) { 826 impossible("tryct overflow4"); 827 break; 828 } 829 (void) mkobj_at(0, somex(croom), somey(croom), TRUE); 830 } 831 } 832 } 833} 834 835/* 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. 839 */ 840STATIC_OVL void 841mineralize() 842{ 843 s_level *sp; 844 struct obj *otmp; 845 int goldprob, gemprob, x, y, cnt; 846 847 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); 855 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) || 859#ifdef REINCARNATION 860 Is_rogue_level(&u.uz) || 861#endif 862 level.flags.arboreal || 863 ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz) 864 && (!In_mines(&u.uz) || sp->flags.town) 865 )) return; 866 867 /* basic level-related probabilities */ 868 goldprob = 20 + depth(&u.uz) / 3; 869 gemprob = goldprob / 4; 870 871 /* mines have ***MORE*** goodies - otherwise why mine? */ 872 if (In_mines(&u.uz)) { 873 goldprob *= 2; 874 gemprob *= 3; 875 } else if (In_quest(&u.uz)) { 876 goldprob /= 4; 877 gemprob /= 6; 878 } 879 880 /* 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. 884 */ 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); 903 } 904 } 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 */ 910 } else { 911 otmp->ox = x, otmp->oy = y; 912 if (!rn2(3)) add_to_buried(otmp); 913 else place_object(otmp, x, y); 914 } 915 } 916 } 917 } 918} 919 920void 921mklev() 922{ 923 struct mkroom *croom; 924 925 if(getbones()) return; 926 in_mklev = TRUE; 927 makelevel(); 928 bound_digging(); 929 mineralize(); 930 in_mklev = FALSE; 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); 940#else 941 topologize(croom); 942#endif 943 } 944 set_wall_state(); 945} 946 947void 948#ifdef SPECIALIZATION 949topologize(croom, do_ordinary) 950register struct mkroom *croom; 951boolean do_ordinary; 952#else 953topologize(croom) 954register struct mkroom *croom; 955#endif 956{ 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; 962#endif 963 register int subindex, nsubrooms = croom->nsubrooms; 964 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) 968 return; 969#ifdef SPECIALIZATION 970# ifdef REINCARNATION 971 if (Is_rogue_level(&u.uz)) 972 do_ordinary = TRUE; /* vision routine helper */ 973# endif 974 if ((rtype != OROOM) || do_ordinary) 975#endif 976 { 977 /* do innards first */ 978 for(x = lowx; x <= hix; x++) 979 for(y = lowy; y <= hiy; y++) 980#ifdef SPECIALIZATION 981 if (rtype == OROOM) 982 levl[x][y].roomno = NO_ROOM; 983 else 984#endif 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)) { 989 levl[x][y].edge = 1; 990 if (levl[x][y].roomno) 991 levl[x][y].roomno = SHARED; 992 else 993 levl[x][y].roomno = roomno; 994 } 995 /* sides */ 996 for(x = lowx-1; x <= hix+1; x += (hix-lowx+2)) 997 for(y = lowy; y <= hiy; y++) { 998 levl[x][y].edge = 1; 999 if (levl[x][y].roomno) 1000 levl[x][y].roomno = SHARED; 1001 else 1002 levl[x][y].roomno = roomno; 1003 } 1004 } 1005 /* subrooms */ 1006 for (subindex = 0; subindex < nsubrooms; subindex++) 1007#ifdef SPECIALIZATION 1008 topologize(croom->sbrooms[subindex], (rtype != OROOM)); 1009#else 1010 topologize(croom->sbrooms[subindex]); 1011#endif 1012} 1013 1014/* Find an unused room for a branch location. */ 1015STATIC_OVL struct mkroom * 1016find_branch_room(mp) 1017 coord *mp; 1018{ 1019 struct mkroom *croom = 0; 1020 1021 if (nroom == 0) { 1022 mazexy(mp); /* already verifies location */ 1023 } else { 1024 /* not perfect - there may be only one stairway */ 1025 if(nroom > 2) { 1026 int tryct = 0; 1027 1028 do 1029 croom = &rooms[rn2(nroom)]; 1030 while((croom == dnstairs_room || croom == upstairs_room || 1031 croom->rtype != OROOM) && (++tryct < 100)); 1032 } else 1033 croom = &rooms[rn2(nroom)]; 1034 1035 do { 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)); 1040 } 1041 return croom; 1042} 1043 1044/* Find the room for (x,y). Return null if not in a room. */ 1045STATIC_OVL struct mkroom * 1046pos_to_room(x, y) 1047 xchar x, y; 1048{ 1049 int i; 1050 struct mkroom *curr; 1051 1052 for (curr = rooms, i = 0; i < nroom; curr++, i++) 1053 if (inside_room(curr, x, y)) return curr;; 1054 return (struct mkroom *) 0; 1055} 1056 1057 1058/* If given a branch, randomly place a special stair or portal. */ 1059void 1060place_branch(br, x, y) 1061branch *br; /* branch to place */ 1062xchar x, y; /* location */ 1063{ 1064 coord m; 1065 d_level *dest; 1066 boolean make_stairs; 1067 struct mkroom *br_room; 1068 1069 /* 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. 1074 */ 1075 if (!br || made_branch) return; 1076 1077 if (!x) { /* find random coordinates for branch */ 1078 br_room = find_branch_room(&m); 1079 x = m.x; 1080 y = m.y; 1081 } else { 1082 br_room = pos_to_room(x, y); 1083 } 1084 1085 if (on_level(&br->end1, &u.uz)) { 1086 /* we're on end1 */ 1087 make_stairs = br->type != BR_NO_END1; 1088 dest = &br->end2; 1089 } else { 1090 /* we're on end2 */ 1091 make_stairs = br->type != BR_NO_END2; 1092 dest = &br->end1; 1093 } 1094 1095 if (br->type == BR_PORTAL) { 1096 mkportal(x, y, dest->dnum, dest->dlevel); 1097 } else if (make_stairs) { 1098 sstairs.sx = x; 1099 sstairs.sy = y; 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; 1104 1105 levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN; 1106 levl[x][y].typ = STAIRS; 1107 } 1108 /* 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 1112 * next call. 1113 */ 1114 made_branch = TRUE; 1115} 1116 1117STATIC_OVL boolean 1118bydoor(x, y) 1119register xchar x, y; 1120{ 1121 register int typ; 1122 1123 if (isok(x+1, y)) { 1124 typ = levl[x+1][y].typ; 1125 if (IS_DOOR(typ) || typ == SDOOR) return TRUE; 1126 } 1127 if (isok(x-1, y)) { 1128 typ = levl[x-1][y].typ; 1129 if (IS_DOOR(typ) || typ == SDOOR) return TRUE; 1130 } 1131 if (isok(x, y+1)) { 1132 typ = levl[x][y+1].typ; 1133 if (IS_DOOR(typ) || typ == SDOOR) return TRUE; 1134 } 1135 if (isok(x, y-1)) { 1136 typ = levl[x][y-1].typ; 1137 if (IS_DOOR(typ) || typ == SDOOR) return TRUE; 1138 } 1139 return FALSE; 1140} 1141 1142/* see whether it is allowable to create a door at [x,y] */ 1143int 1144okdoor(x,y) 1145register xchar x, y; 1146{ 1147 register boolean near_door = bydoor(x, y); 1148 1149 return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) && 1150 doorindex < DOORMAX && !near_door); 1151} 1152 1153void 1154dodoor(x,y,aroom) 1155register int x, y; 1156register struct mkroom *aroom; 1157{ 1158 if(doorindex >= DOORMAX) { 1159 impossible("DOORMAX exceeded?"); 1160 return; 1161 } 1162 1163 dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR); 1164} 1165 1166boolean 1167occupied(x, y) 1168register xchar x, y; 1169{ 1170 return((boolean)(t_at(x, y) 1171 || IS_FURNITURE(levl[x][y].typ) 1172 || is_lava(x,y) 1173 || is_pool(x,y) 1174 || invocation_pos(x,y) 1175 )); 1176} 1177 1178/* make a trap somewhere (in croom if mazeflag = 0 && !tm) */ 1179/* if tm != null, make trap at that location */ 1180void 1181mktrap(num, mazeflag, croom, tm) 1182register int num, mazeflag; 1183register struct mkroom *croom; 1184coord *tm; 1185{ 1186 register int kind; 1187 coord m; 1188 1189 /* no traps in pools */ 1190 if (tm && is_pool(tm->x,tm->y)) return; 1191 1192 if (num > 0 && num < TRAPNUM) { 1193 kind = num; 1194#ifdef REINCARNATION 1195 } else if (Is_rogue_level(&u.uz)) { 1196 switch (rn2(7)) { 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; 1204 } 1205#endif 1206 } else if (Inhell && !rn2(5)) { 1207 /* bias the frequency of fire traps in Gehennom */ 1208 kind = FIRE_TRAP; 1209 } else { 1210 unsigned lvl = level_difficulty(); 1211 1212 do { 1213 kind = rnd(TRAPNUM-1); 1214 /* reject "too hard" traps */ 1215 switch (kind) { 1216 case MAGIC_PORTAL: 1217 kind = NO_TRAP; break; 1218 case ROLLING_BOULDER_TRAP: 1219 case SLP_GAS_TRAP: 1220 if (lvl < 2) kind = NO_TRAP; break; 1221 case LEVEL_TELEP: 1222 if (lvl < 5 || level.flags.noteleport) 1223 kind = NO_TRAP; break; 1224 case SPIKED_PIT: 1225 if (lvl < 5) kind = NO_TRAP; break; 1226 case LANDMINE: 1227 if (lvl < 6) kind = NO_TRAP; break; 1228 case WEB: 1229 if (lvl < 7) kind = NO_TRAP; break; 1230 case STATUE_TRAP: 1231 case POLY_TRAP: 1232 if (lvl < 8) kind = NO_TRAP; break; 1233 case FIRE_TRAP: 1234 if (!Inhell) kind = NO_TRAP; break; 1235 case TELEP_TRAP: 1236 if (level.flags.noteleport) kind = NO_TRAP; break; 1237 case HOLE: 1238 /* make these much less often than other traps */ 1239 if (rn2(7)) kind = NO_TRAP; break; 1240 } 1241 } while (kind == NO_TRAP); 1242 } 1243 1244 if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz)) 1245 kind = ROCKTRAP; 1246 1247 if (tm) 1248 m = *tm; 1249 else { 1250 register int tryct = 0; 1251 boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT || 1252 kind == TRAPDOOR || kind == HOLE); 1253 1254 do { 1255 if (++tryct > 200) 1256 return; 1257 if (mazeflag) 1258 mazexy(&m); 1259 else if (!somexy(croom,&m)) 1260 return; 1261 } while (occupied(m.x, m.y) || 1262 (avoid_boulder && sobj_at(BOULDER, m.x, m.y))); 1263 } 1264 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); 1268} 1269 1270void 1271mkstairs(x, y, up, croom) 1272xchar x, y; 1273char up; 1274struct mkroom *croom; 1275{ 1276 if (!x) { 1277 impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y); 1278 return; 1279 } 1280 1281 /* 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. 1285 */ 1286 if ((dunlev(&u.uz) == 1 && up) || 1287 (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up)) 1288 return; 1289 1290 if(up) { 1291 xupstair = x; 1292 yupstair = y; 1293 upstairs_room = croom; 1294 } else { 1295 xdnstair = x; 1296 ydnstair = y; 1297 dnstairs_room = croom; 1298 } 1299 1300 levl[x][y].typ = STAIRS; 1301 levl[x][y].ladder = up ? LA_UP : LA_DOWN; 1302} 1303 1304STATIC_OVL 1305void 1306mkfount(mazeflag,croom) 1307register int mazeflag; 1308register struct mkroom *croom; 1309{ 1310 coord m; 1311 register int tryct = 0; 1312 1313 do { 1314 if(++tryct > 200) return; 1315 if(mazeflag) 1316 mazexy(&m); 1317 else 1318 if (!somexy(croom, &m)) 1319 return; 1320 } while(occupied(m.x, m.y) || bydoor(m.x, m.y)); 1321 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; 1326 1327 level.flags.nfountains++; 1328} 1329 1330#ifdef SINKS 1331STATIC_OVL void 1332mksink(croom) 1333register struct mkroom *croom; 1334{ 1335 coord m; 1336 register int tryct = 0; 1337 1338 do { 1339 if(++tryct > 200) return; 1340 if (!somexy(croom, &m)) 1341 return; 1342 } while(occupied(m.x, m.y) || bydoor(m.x, m.y)); 1343 1344 /* Put a sink at m.x, m.y */ 1345 levl[m.x][m.y].typ = SINK; 1346 1347 level.flags.nsinks++; 1348} 1349#endif /* SINKS */ 1350 1351 1352STATIC_OVL void 1353mkaltar(croom) 1354register struct mkroom *croom; 1355{ 1356 coord m; 1357 register int tryct = 0; 1358 aligntyp al; 1359 1360 if (croom->rtype != OROOM) return; 1361 1362 do { 1363 if(++tryct > 200) return; 1364 if (!somexy(croom, &m)) 1365 return; 1366 } while (occupied(m.x, m.y) || bydoor(m.x, m.y)); 1367 1368 /* Put an altar at m.x, m.y */ 1369 levl[m.x][m.y].typ = ALTAR; 1370 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 ); 1374} 1375 1376static void 1377mkgrave(croom) 1378struct mkroom *croom; 1379{ 1380 coord m; 1381 register int tryct = 0; 1382 register struct obj *otmp; 1383 boolean dobell = !rn2(10); 1384 1385 1386 if(croom->rtype != OROOM) return; 1387 1388 do { 1389 if(++tryct > 200) return; 1390 if (!somexy(croom, &m)) 1391 return; 1392 } while (occupied(m.x, m.y) || bydoor(m.x, m.y)); 1393 1394 /* Put a grave at m.x, m.y */ 1395 make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0); 1396 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); 1401 if (!otmp) return; 1402 curse(otmp); 1403 otmp->ox = m.x; 1404 otmp->oy = m.y; 1405 add_to_buried(otmp); 1406 } 1407 1408 /* Leave a bell, in case we accidentally buried someone alive */ 1409 if (dobell) (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE); 1410 return; 1411} 1412 1413 1414/* maze levels have slightly different constraints from normal levels */ 1415#define x_maze_min 2 1416#define y_maze_min 2 1417/* 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. 1424 */ 1425void 1426mkinvokearea() 1427{ 1428 int dist; 1429 xchar xmin = inv_pos.x, xmax = inv_pos.x; 1430 xchar ymin = inv_pos.y, ymax = inv_pos.y; 1431 register xchar i; 1432 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); 1436 1437 mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */ 1438 1439 for(dist = 1; dist < 7; dist++) { 1440 xmin--; xmax++; 1441 1442 /* top and bottom */ 1443 if(dist != 3) { /* the area is wider that it is high */ 1444 ymin--; ymax++; 1445 for(i = xmin+1; i < xmax; i++) { 1446 mkinvpos(i, ymin, dist); 1447 mkinvpos(i, ymax, dist); 1448 } 1449 } 1450 1451 /* left and right */ 1452 for(i = ymin; i <= ymax; i++) { 1453 mkinvpos(xmin, i, dist); 1454 mkinvpos(xmax, i, dist); 1455 } 1456 1457 flush_screen(1); /* make sure the new glyphs shows up */ 1458 delay_output(); 1459 } 1460 1461 You("are standing at the top of a stairwell leading down!"); 1462 mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */ 1463 newsym(u.ux, u.uy); 1464 vision_full_recalc = 1; /* everything changed */ 1465} 1466 1467/* Change level topology. Boulders in the vicinity are eliminated. 1468 * Temporarily overrides vision in the name of a nice effect. 1469 */ 1470STATIC_OVL void 1471mkinvpos(x,y,dist) 1472xchar x,y; 1473int dist; 1474{ 1475 struct trap *ttmp; 1476 struct obj *otmp; 1477 boolean make_rocks; 1478 register struct rm *lev = &levl[x][y]; 1479 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 */ 1484 if (dist < (7 - 2)) 1485 panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist); 1486 return; 1487 } 1488 1489 /* clear traps */ 1490 if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp); 1491 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) { 1495 if (make_rocks) { 1496 fracture_rock(otmp); 1497 make_rocks = FALSE; /* don't bother with more rocks */ 1498 } else { 1499 obj_extract_self(otmp); 1500 obfree(otmp, (struct obj *)0); 1501 } 1502 } 1503 unblock_point(x,y); /* make sure vision knows this location is open */ 1504 1505 /* fake out saved state */ 1506 lev->seenv = 0; 1507 lev->doormask = 0; 1508 if(dist < 6) lev->lit = TRUE; 1509 lev->waslit = TRUE; 1510 lev->horizontal = FALSE; 1511 viz_array[y][x] = (dist < 6 ) ? 1512 (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */ 1513 COULD_SEE; 1514 1515 switch(dist) { 1516 case 1: /* fire traps */ 1517 if (is_pool(x,y)) break; 1518 lev->typ = ROOM; 1519 ttmp = maketrap(x, y, FIRE_TRAP); 1520 if (ttmp) ttmp->tseen = TRUE; 1521 break; 1522 case 0: /* lit room locations */ 1523 case 2: 1524 case 3: 1525 case 6: /* unlit room locations */ 1526 lev->typ = ROOM; 1527 break; 1528 case 4: /* pools (aka a wide moat) */ 1529 case 5: 1530 lev->typ = MOAT; 1531 /* No kelp! */ 1532 break; 1533 default: 1534 impossible("mkinvpos called with dist %d", dist); 1535 break; 1536 } 1537 1538 /* display new value of position; could have a monster/object on it */ 1539 newsym(x,y); 1540} 1541 1542/* 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). 1547 * 1548 * Ludios will remain isolated until the branch is corrected by this function. 1549 */ 1550STATIC_OVL void 1551mk_knox_portal(x, y) 1552xchar x, y; 1553{ 1554 extern int n_dgns; /* from dungeon.c */ 1555 d_level *source; 1556 branch *br; 1557 schar u_depth; 1558 1559 br = dungeon_branch("Fort Ludios"); 1560 if (on_level(&knox_level, &br->end1)) { 1561 source = &br->end2; 1562 } else { 1563 /* disallow Knox branch on a level with one branch already */ 1564 if(Is_branchlev(&u.uz)) 1565 return; 1566 source = &br->end1; 1567 } 1568 1569 /* Already set or 2/3 chance of deferring until a later level. */ 1570 if (source->dnum < n_dgns || (rn2(3) 1571#ifdef WIZARD 1572 && !wizard 1573#endif 1574 )) return; 1575 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 */ 1580 return; 1581 1582 /* Adjust source to be current level and re-insert branch. */ 1583 *source = u.uz; 1584 insert_branch(br, TRUE); 1585 1586#ifdef NETHACK_DEBUG 1587 pline("Made knox portal."); 1588#endif 1589 place_branch(br, x, y); 1590} 1591 1592/*mklev.c*/ 1593