1/* SCCS Id: @(#)sp_lev.c 3.4 2001/09/06 */ 2/* Copyright (c) 1989 by Jean-Christophe Collet */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5/* 6 * This file contains the various functions that are related to the special 7 * levels. 8 * It contains also the special level loader. 9 * 10 */ 11 12#include "hack.h" 13#include "dlb.h" 14/* #define DEBUG */ /* uncomment to enable code debugging */ 15 16#ifdef NETHACK_DEBUG 17# ifdef WIZARD 18#define debugpline if (wizard) pline 19# else 20#define debugpline pline 21# endif 22#endif 23 24#include "sp_lev.h" 25#include "rect.h" 26 27extern void FDECL(mkmap, (lev_init *)); 28 29STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *)); 30STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *, struct mkroom *)); 31STATIC_DCL void FDECL(create_trap, (trap *, struct mkroom *)); 32STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P)); 33STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *)); 34STATIC_DCL void FDECL(create_object, (object *, struct mkroom *)); 35STATIC_DCL void FDECL(create_engraving, (engraving *,struct mkroom *)); 36STATIC_DCL void FDECL(create_stairs, (stair *, struct mkroom *)); 37STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *)); 38STATIC_DCL void FDECL(create_gold, (gold *, struct mkroom *)); 39STATIC_DCL void FDECL(create_feature, (int,int,struct mkroom *,int)); 40STATIC_DCL boolean FDECL(search_door, (struct mkroom *, xchar *, xchar *, 41 XCHAR_P, int)); 42STATIC_DCL void NDECL(fix_stair_rooms); 43STATIC_DCL void FDECL(create_corridor, (corridor *)); 44 45STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P, 46 XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); 47 48#define LEFT 1 49#define H_LEFT 2 50#define CENTER 3 51#define H_RIGHT 4 52#define RIGHT 5 53 54#define TOP 1 55#define BOTTOM 5 56 57#define sq(x) ((x)*(x)) 58 59#define XLIM 4 60#define YLIM 3 61 62#define Fread (void)dlb_fread 63#define Fgetc (schar)dlb_fgetc 64#define New(type) (type *) alloc(sizeof(type)) 65#define NewTab(type, size) (type **) alloc(sizeof(type *) * (unsigned)size) 66#define Free(ptr) if(ptr) free((genericptr_t) (ptr)) 67 68static NEARDATA walk walklist[50]; 69extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */ 70 71static char Map[COLNO][ROWNO]; 72static char robjects[10], rloc_x[10], rloc_y[10], rmonst[10]; 73static aligntyp ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL }; 74static NEARDATA xchar xstart, ystart; 75static NEARDATA char xsize, ysize; 76 77STATIC_DCL void FDECL(set_wall_property, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,int)); 78STATIC_DCL int NDECL(rnddoor); 79STATIC_DCL int NDECL(rndtrap); 80STATIC_DCL void FDECL(get_location, (schar *,schar *,int)); 81STATIC_DCL void FDECL(sp_lev_shuffle, (char *,char *,int)); 82STATIC_DCL void FDECL(light_region, (region *)); 83STATIC_DCL void FDECL(load_common_data, (dlb *,int)); 84STATIC_DCL void FDECL(load_one_monster, (dlb *,monster *)); 85STATIC_DCL void FDECL(load_one_object, (dlb *,object *)); 86STATIC_DCL void FDECL(load_one_engraving, (dlb *,engraving *)); 87STATIC_DCL boolean FDECL(load_rooms, (dlb *)); 88STATIC_DCL void FDECL(maze1xy, (coord *,int)); 89STATIC_DCL boolean FDECL(load_maze, (dlb *)); 90STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *)); 91STATIC_DCL void FDECL(free_rooms,(room **, int)); 92STATIC_DCL void FDECL(build_room, (room *, room*)); 93 94char *lev_message = 0; 95lev_region *lregions = 0; 96int num_lregions = 0; 97lev_init init_lev; 98 99/* 100 * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able 101 */ 102 103STATIC_OVL void 104set_wall_property(x1,y1,x2,y2, prop) 105xchar x1, y1, x2, y2; 106int prop; 107{ 108 register xchar x, y; 109 110 for(y = y1; y <= y2; y++) 111 for(x = x1; x <= x2; x++) 112 if(IS_STWALL(levl[x][y].typ)) 113 levl[x][y].wall_info |= prop; 114} 115 116/* 117 * Choose randomly the state (nodoor, open, closed or locked) for a door 118 */ 119STATIC_OVL int 120rnddoor() 121{ 122 int i = 1 << rn2(5); 123 i >>= 1; 124 return i; 125} 126 127/* 128 * Select a random trap 129 */ 130STATIC_OVL int 131rndtrap() 132{ 133 int rtrap; 134 135 do { 136 rtrap = rnd(TRAPNUM-1); 137 switch (rtrap) { 138 case HOLE: /* no random holes on special levels */ 139 case MAGIC_PORTAL: rtrap = NO_TRAP; 140 break; 141 case TRAPDOOR: if (!Can_dig_down(&u.uz)) rtrap = NO_TRAP; 142 break; 143 case LEVEL_TELEP: 144 case TELEP_TRAP: if (level.flags.noteleport) rtrap = NO_TRAP; 145 break; 146 case ROLLING_BOULDER_TRAP: 147 case ROCKTRAP: if (In_endgame(&u.uz)) rtrap = NO_TRAP; 148 break; 149 } 150 } while (rtrap == NO_TRAP); 151 return rtrap; 152} 153 154/* 155 * Coordinates in special level files are handled specially: 156 * 157 * if x or y is -11, we generate a random coordinate. 158 * if x or y is between -1 and -10, we read one from the corresponding 159 * register (x0, x1, ... x9). 160 * if x or y is nonnegative, we convert it from relative to the local map 161 * to global coordinates. 162 * The "humidity" flag is used to insure that engravings aren't 163 * created underwater, or eels on dry land. 164 */ 165#define DRY 0x1 166#define WET 0x2 167 168STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int)); 169 170STATIC_OVL void 171get_location(x, y, humidity) 172schar *x, *y; 173int humidity; 174{ 175 int cpt = 0; 176 177 if (*x >= 0) { /* normal locations */ 178 *x += xstart; 179 *y += ystart; 180 } else if (*x > -11) { /* special locations */ 181 *y = ystart + rloc_y[ - *y - 1]; 182 *x = xstart + rloc_x[ - *x - 1]; 183 } else { /* random location */ 184 do { 185 *x = xstart + rn2((int)xsize); 186 *y = ystart + rn2((int)ysize); 187 if (is_ok_location(*x,*y,humidity)) break; 188 } while (++cpt < 100); 189 if (cpt >= 100) { 190 register int xx, yy; 191 /* last try */ 192 for (xx = 0; xx < xsize; xx++) 193 for (yy = 0; yy < ysize; yy++) { 194 *x = xstart + xx; 195 *y = ystart + yy; 196 if (is_ok_location(*x,*y,humidity)) goto found_it; 197 } 198 panic("get_location: can't find a place!"); 199 } 200 } 201found_it:; 202 203 if (!isok(*x,*y)) { 204 impossible("get_location: (%d,%d) out of bounds", *x, *y); 205 *x = x_maze_max; *y = y_maze_max; 206 } 207} 208 209STATIC_OVL boolean 210is_ok_location(x, y, humidity) 211register schar x, y; 212register int humidity; 213{ 214 register int typ; 215 216 if (Is_waterlevel(&u.uz)) return TRUE; /* accept any spot */ 217 218 if (humidity & DRY) { 219 typ = levl[x][y].typ; 220 if (typ == ROOM || typ == AIR || 221 typ == CLOUD || typ == ICE || typ == CORR) 222 return TRUE; 223 } 224 if (humidity & WET) { 225 if (is_pool(x,y) || is_lava(x,y)) 226 return TRUE; 227 } 228 return FALSE; 229} 230 231/* 232 * Shuffle the registers for locations, objects or monsters 233 */ 234 235STATIC_OVL void 236sp_lev_shuffle(list1, list2, n) 237char list1[], list2[]; 238int n; 239{ 240 register int i, j; 241 register char k; 242 243 for (i = n - 1; i > 0; i--) { 244 if ((j = rn2(i + 1)) == i) continue; 245 k = list1[j]; 246 list1[j] = list1[i]; 247 list1[i] = k; 248 if (list2) { 249 k = list2[j]; 250 list2[j] = list2[i]; 251 list2[i] = k; 252 } 253 } 254} 255 256/* 257 * Get a relative position inside a room. 258 * negative values for x or y means RANDOM! 259 */ 260 261STATIC_OVL void 262get_room_loc(x,y, croom) 263schar *x, *y; 264struct mkroom *croom; 265{ 266 coord c; 267 268 if (*x <0 && *y <0) { 269 if (somexy(croom, &c)) { 270 *x = c.x; 271 *y = c.y; 272 } else 273 panic("get_room_loc : can't find a place!"); 274 } else { 275 if (*x < 0) 276 *x = rn2(croom->hx - croom->lx + 1); 277 if (*y < 0) 278 *y = rn2(croom->hy - croom->ly + 1); 279 *x += croom->lx; 280 *y += croom->ly; 281 } 282} 283 284/* 285 * Get a relative position inside a room. 286 * negative values for x or y means RANDOM! 287 */ 288 289STATIC_OVL void 290get_free_room_loc(x,y, croom) 291schar *x, *y; 292struct mkroom *croom; 293{ 294 schar try_x, try_y; 295 register int trycnt = 0; 296 297 do { 298 try_x = *x, try_y = *y; 299 get_room_loc(&try_x, &try_y, croom); 300 } while (levl[try_x][try_y].typ != ROOM && ++trycnt <= 100); 301 302 if (trycnt > 100) 303 panic("get_free_room_loc: can't find a place!"); 304 *x = try_x, *y = try_y; 305} 306 307boolean 308check_room(lowx, ddx, lowy, ddy, vault) 309xchar *lowx, *ddx, *lowy, *ddy; 310boolean vault; 311{ 312 register int x,y,hix = *lowx + *ddx, hiy = *lowy + *ddy; 313 register struct rm *lev; 314 int xlim, ylim, ymax; 315 316 xlim = XLIM + (vault ? 1 : 0); 317 ylim = YLIM + (vault ? 1 : 0); 318 319 if (*lowx < 3) *lowx = 3; 320 if (*lowy < 2) *lowy = 2; 321 if (hix > COLNO-3) hix = COLNO-3; 322 if (hiy > ROWNO-3) hiy = ROWNO-3; 323chk: 324 if (hix <= *lowx || hiy <= *lowy) return FALSE; 325 326 /* check area around room (and make room smaller if necessary) */ 327 for (x = *lowx - xlim; x<= hix + xlim; x++) { 328 if(x <= 0 || x >= COLNO) continue; 329 y = *lowy - ylim; ymax = hiy + ylim; 330 if(y < 0) y = 0; 331 if(ymax >= ROWNO) ymax = (ROWNO-1); 332 lev = &levl[x][y]; 333 for (; y <= ymax; y++) { 334 if (lev++->typ) { 335#ifdef NETHACK_DEBUG 336 if(!vault) 337 debugpline("strange area [%d,%d] in check_room.",x,y); 338#endif 339 if (!rn2(3)) return FALSE; 340 if (x < *lowx) 341 *lowx = x + xlim + 1; 342 else 343 hix = x - xlim - 1; 344 if (y < *lowy) 345 *lowy = y + ylim + 1; 346 else 347 hiy = y - ylim - 1; 348 goto chk; 349 } 350 } 351 } 352 *ddx = hix - *lowx; 353 *ddy = hiy - *lowy; 354 return TRUE; 355} 356 357/* 358 * Create a new room. 359 * This is still very incomplete... 360 */ 361 362boolean 363create_room(x,y,w,h,xal,yal,rtype,rlit) 364xchar x,y; 365xchar w,h; 366xchar xal,yal; 367xchar rtype, rlit; 368{ 369 xchar xabs, yabs; 370 int wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp; 371 NhRect *r1 = 0, r2; 372 int trycnt = 0; 373 boolean vault = FALSE; 374 int xlim = XLIM, ylim = YLIM; 375 376 if (rtype == -1) /* Is the type random ? */ 377 rtype = OROOM; 378 379 if (rtype == VAULT) { 380 vault = TRUE; 381 xlim++; 382 ylim++; 383 } 384 385 /* on low levels the room is lit (usually) */ 386 /* some other rooms may require lighting */ 387 388 /* is light state random ? */ 389 if (rlit == -1) 390 rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE; 391 392 /* 393 * Here we will try to create a room. If some parameters are 394 * random we are willing to make several try before we give 395 * it up. 396 */ 397 do { 398 xchar xborder, yborder; 399 wtmp = w; htmp = h; 400 xtmp = x; ytmp = y; 401 xaltmp = xal; yaltmp = yal; 402 403 /* First case : a totaly random room */ 404 405 if((xtmp < 0 && ytmp <0 && wtmp < 0 && xaltmp < 0 && 406 yaltmp < 0) || vault) { 407 xchar hx, hy, lx, ly, dx, dy; 408 r1 = rnd_rect(); /* Get a random rectangle */ 409 410 if (!r1) { /* No more free rectangles ! */ 411#ifdef NETHACK_DEBUG 412 debugpline("No more rects..."); 413#endif 414 return FALSE; 415 } 416 hx = r1->hx; 417 hy = r1->hy; 418 lx = r1->lx; 419 ly = r1->ly; 420 if (vault) 421 dx = dy = 1; 422 else { 423 dx = 2 + rn2((hx-lx > 28) ? 12 : 8); 424 dy = 2 + rn2(4); 425 if(dx*dy > 50) 426 dy = 50/dx; 427 } 428 xborder = (lx > 0 && hx < COLNO -1) ? 2*xlim : xlim+1; 429 yborder = (ly > 0 && hy < ROWNO -1) ? 2*ylim : ylim+1; 430 if(hx-lx < dx + 3 + xborder || 431 hy-ly < dy + 3 + yborder) { 432 r1 = 0; 433 continue; 434 } 435 xabs = lx + (lx > 0 ? xlim : 3) 436 + rn2(hx - (lx>0?lx : 3) - dx - xborder + 1); 437 yabs = ly + (ly > 0 ? ylim : 2) 438 + rn2(hy - (ly>0?ly : 2) - dy - yborder + 1); 439 if (ly == 0 && hy >= (ROWNO-1) && 440 (!nroom || !rn2(nroom)) && (yabs+dy > ROWNO/2)) { 441 yabs = rn1(3, 2); 442 if(nroom < 4 && dy>1) dy--; 443 } 444 if (!check_room(&xabs, &dx, &yabs, &dy, vault)) { 445 r1 = 0; 446 continue; 447 } 448 wtmp = dx+1; 449 htmp = dy+1; 450 r2.lx = xabs-1; r2.ly = yabs-1; 451 r2.hx = xabs + wtmp; 452 r2.hy = yabs + htmp; 453 } else { /* Only some parameters are random */ 454 int rndpos = 0; 455 if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */ 456 xtmp = rnd(5); 457 ytmp = rnd(5); 458 rndpos = 1; 459 } 460 if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */ 461 wtmp = rn1(15, 3); 462 htmp = rn1(8, 2); 463 } 464 if (xaltmp == -1) /* Horizontal alignment is RANDOM */ 465 xaltmp = rnd(3); 466 if (yaltmp == -1) /* Vertical alignment is RANDOM */ 467 yaltmp = rnd(3); 468 469 /* Try to generate real (absolute) coordinates here! */ 470 471 xabs = (((xtmp-1) * COLNO) / 5) + 1; 472 yabs = (((ytmp-1) * ROWNO) / 5) + 1; 473 switch (xaltmp) { 474 case LEFT: 475 break; 476 case RIGHT: 477 xabs += (COLNO / 5) - wtmp; 478 break; 479 case CENTER: 480 xabs += ((COLNO / 5) - wtmp) / 2; 481 break; 482 } 483 switch (yaltmp) { 484 case TOP: 485 break; 486 case BOTTOM: 487 yabs += (ROWNO / 5) - htmp; 488 break; 489 case CENTER: 490 yabs += ((ROWNO / 5) - htmp) / 2; 491 break; 492 } 493 494 if (xabs + wtmp - 1 > COLNO - 2) 495 xabs = COLNO - wtmp - 3; 496 if (xabs < 2) 497 xabs = 2; 498 if (yabs + htmp - 1> ROWNO - 2) 499 yabs = ROWNO - htmp - 3; 500 if (yabs < 2) 501 yabs = 2; 502 503 /* Try to find a rectangle that fit our room ! */ 504 505 r2.lx = xabs-1; r2.ly = yabs-1; 506 r2.hx = xabs + wtmp + rndpos; 507 r2.hy = yabs + htmp + rndpos; 508 r1 = get_rect(&r2); 509 } 510 } while (++trycnt <= 100 && !r1); 511 if (!r1) { /* creation of room failed ? */ 512 return FALSE; 513 } 514 split_rects(r1, &r2); 515 516 if (!vault) { 517 smeq[nroom] = nroom; 518 add_room(xabs, yabs, xabs+wtmp-1, yabs+htmp-1, 519 rlit, rtype, FALSE); 520 } else { 521 rooms[nroom].lx = xabs; 522 rooms[nroom].ly = yabs; 523 } 524 return TRUE; 525} 526 527/* 528 * Create a subroom in room proom at pos x,y with width w & height h. 529 * x & y are relative to the parent room. 530 */ 531 532STATIC_OVL boolean 533create_subroom(proom, x, y, w, h, rtype, rlit) 534struct mkroom *proom; 535xchar x,y; 536xchar w,h; 537xchar rtype, rlit; 538{ 539 xchar width, height; 540 541 width = proom->hx - proom->lx + 1; 542 height = proom->hy - proom->ly + 1; 543 544 /* There is a minimum size for the parent room */ 545 if (width < 4 || height < 4) 546 return FALSE; 547 548 /* Check for random position, size, etc... */ 549 550 if (w == -1) 551 w = rnd(width - 3); 552 if (h == -1) 553 h = rnd(height - 3); 554 if (x == -1) 555 x = rnd(width - w - 1) - 1; 556 if (y == -1) 557 y = rnd(height - h - 1) - 1; 558 if (x == 1) 559 x = 0; 560 if (y == 1) 561 y = 0; 562 if ((x + w + 1) == width) 563 x++; 564 if ((y + h + 1) == height) 565 y++; 566 if (rtype == -1) 567 rtype = OROOM; 568 if (rlit == -1) 569 rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE; 570 add_subroom(proom, proom->lx + x, proom->ly + y, 571 proom->lx + x + w - 1, proom->ly + y + h - 1, 572 rlit, rtype, FALSE); 573 return TRUE; 574} 575 576/* 577 * Create a new door in a room. 578 * It's placed on a wall (north, south, east or west). 579 */ 580 581STATIC_OVL void 582create_door(dd, broom) 583room_door *dd; 584struct mkroom *broom; 585{ 586 int x, y; 587 int trycnt = 0; 588 589 if (dd->secret == -1) 590 dd->secret = rn2(2); 591 592 if (dd->mask == -1) { 593 /* is it a locked door, closed, or a doorway? */ 594 if (!dd->secret) { 595 if(!rn2(3)) { 596 if(!rn2(5)) 597 dd->mask = D_ISOPEN; 598 else if(!rn2(6)) 599 dd->mask = D_LOCKED; 600 else 601 dd->mask = D_CLOSED; 602 if (dd->mask != D_ISOPEN && !rn2(25)) 603 dd->mask |= D_TRAPPED; 604 } else 605 dd->mask = D_NODOOR; 606 } else { 607 if(!rn2(5)) dd->mask = D_LOCKED; 608 else dd->mask = D_CLOSED; 609 610 if(!rn2(20)) dd->mask |= D_TRAPPED; 611 } 612 } 613 614 do { 615 register int dwall, dpos; 616 617 dwall = dd->wall; 618 if (dwall == -1) /* The wall is RANDOM */ 619 dwall = 1 << rn2(4); 620 621 dpos = dd->pos; 622 if (dpos == -1) /* The position is RANDOM */ 623 dpos = rn2((dwall == W_WEST || dwall == W_EAST) ? 624 (broom->hy - broom->ly) : (broom->hx - broom->lx)); 625 626 /* Convert wall and pos into an absolute coordinate! */ 627 628 switch (dwall) { 629 case W_NORTH: 630 y = broom->ly - 1; 631 x = broom->lx + dpos; 632 break; 633 case W_SOUTH: 634 y = broom->hy + 1; 635 x = broom->lx + dpos; 636 break; 637 case W_WEST: 638 x = broom->lx - 1; 639 y = broom->ly + dpos; 640 break; 641 case W_EAST: 642 x = broom->hx + 1; 643 y = broom->ly + dpos; 644 break; 645 default: 646 x = y = 0; 647 panic("create_door: No wall for door!"); 648 break; 649 } 650 if (okdoor(x,y)) 651 break; 652 } while (++trycnt <= 100); 653 if (trycnt > 100) { 654 impossible("create_door: Can't find a proper place!"); 655 return; 656 } 657 add_door(x,y,broom); 658 levl[x][y].typ = (dd->secret ? SDOOR : DOOR); 659 levl[x][y].doormask = dd->mask; 660} 661 662/* 663 * Create a secret door in croom on any one of the specified walls. 664 */ 665void 666create_secret_door(croom, walls) 667 struct mkroom *croom; 668 xchar walls; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */ 669{ 670 xchar sx, sy; /* location of the secret door */ 671 int count; 672 673 for(count = 0; count < 100; count++) { 674 sx = rn1(croom->hx - croom->lx + 1, croom->lx); 675 sy = rn1(croom->hy - croom->ly + 1, croom->ly); 676 677 switch(rn2(4)) { 678 case 0: /* top */ 679 if(!(walls & W_NORTH)) continue; 680 sy = croom->ly-1; break; 681 case 1: /* bottom */ 682 if(!(walls & W_SOUTH)) continue; 683 sy = croom->hy+1; break; 684 case 2: /* left */ 685 if(!(walls & W_EAST)) continue; 686 sx = croom->lx-1; break; 687 case 3: /* right */ 688 if(!(walls & W_WEST)) continue; 689 sx = croom->hx+1; break; 690 } 691 692 if(okdoor(sx,sy)) { 693 levl[sx][sy].typ = SDOOR; 694 levl[sx][sy].doormask = D_CLOSED; 695 add_door(sx,sy,croom); 696 return; 697 } 698 } 699 700 impossible("couldn't create secret door on any walls 0x%x", walls); 701} 702 703/* 704 * Create a trap in a room. 705 */ 706 707STATIC_OVL void 708create_trap(t,croom) 709trap *t; 710struct mkroom *croom; 711{ 712 schar x,y; 713 coord tm; 714 715 if (rn2(100) < t->chance) { 716 x = t->x; 717 y = t->y; 718 if (croom) 719 get_free_room_loc(&x, &y, croom); 720 else 721 get_location(&x, &y, DRY); 722 723 tm.x = x; 724 tm.y = y; 725 726 mktrap(t->type, 1, (struct mkroom*) 0, &tm); 727 } 728} 729 730/* 731 * Create a monster in a room. 732 */ 733 734STATIC_OVL int 735noncoalignment(alignment) 736aligntyp alignment; 737{ 738 int k; 739 740 k = rn2(2); 741 if (!alignment) 742 return(k ? -1 : 1); 743 return(k ? -alignment : 0); 744} 745 746STATIC_OVL void 747create_monster(m,croom) 748monster *m; 749struct mkroom *croom; 750{ 751 struct monst *mtmp; 752 schar x, y; 753 char class; 754 aligntyp amask; 755 coord cc; 756 struct permonst *pm; 757 unsigned g_mvflags; 758 759 if (rn2(100) < m->chance) { 760 761 if (m->class >= 0) 762 class = (char) def_char_to_monclass((char)m->class); 763 else if (m->class > -11) 764 class = (char) def_char_to_monclass(rmonst[- m->class - 1]); 765 else 766 class = 0; 767 768 if (class == MAXMCLASSES) 769 panic("create_monster: unknown monster class '%c'", m->class); 770 771 amask = (m->align == AM_SPLEV_CO) ? 772 Align2amask(u.ualignbase[A_ORIGINAL]) : 773 (m->align == AM_SPLEV_NONCO) ? 774 Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) : 775 (m->align <= -11) ? induced_align(80) : 776 (m->align < 0 ? ralign[-m->align-1] : m->align); 777 778 if (!class) 779 pm = (struct permonst *) 0; 780 else if (m->id != NON_PM) { 781 pm = &mons[m->id]; 782 g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags; 783 if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT)) 784 goto m_done; 785 else if (g_mvflags & G_GONE) /* genocided or extinct */ 786 pm = (struct permonst *) 0; /* make random monster */ 787 } else { 788 pm = mkclass(class,G_NOGEN); 789 /* if we can't get a specific monster type (pm == 0) then the 790 class has been genocided, so settle for a random monster */ 791 } 792 if (In_mines(&u.uz) && pm && your_race(pm) && 793 (Race_if(PM_DWARF) || Race_if(PM_GNOME)) && rn2(3)) 794 pm = (struct permonst *) 0; 795 796 x = m->x; 797 y = m->y; 798 if (croom) 799 get_room_loc(&x, &y, croom); 800 else { 801 if (!pm || !is_swimmer(pm)) 802 get_location(&x, &y, DRY); 803 else if (pm->mlet == S_EEL) 804 get_location(&x, &y, WET); 805 else 806 get_location(&x, &y, DRY|WET); 807 } 808 /* try to find a close place if someone else is already there */ 809 if (MON_AT(x,y) && enexto(&cc, x, y, pm)) 810 x = cc.x, y = cc.y; 811 812 if(m->align != -12) 813 mtmp = mk_roamer(pm, Amask2align(amask), x, y, m->peaceful); 814 else if(PM_ARCHEOLOGIST <= m->id && m->id <= PM_WIZARD) 815 mtmp = mk_mplayer(pm, x, y, FALSE); 816 else mtmp = makemon(pm, x, y, NO_MM_FLAGS); 817 818 if (mtmp) { 819 /* handle specific attributes for some special monsters */ 820 if (m->name.str) mtmp = christen_monst(mtmp, m->name.str); 821 822 /* 823 * This is currently hardwired for mimics only. It should 824 * eventually be expanded. 825 */ 826 if (m->appear_as.str && mtmp->data->mlet == S_MIMIC) { 827 int i; 828 829 switch (m->appear) { 830 case M_AP_NOTHING: 831 impossible( 832 "create_monster: mon has an appearance, \"%s\", but no type", 833 m->appear_as.str); 834 break; 835 836 case M_AP_FURNITURE: 837 for (i = 0; i < MAXPCHARS; i++) 838 if (!strcmp(defsyms[i].explanation, 839 m->appear_as.str)) 840 break; 841 if (i == MAXPCHARS) { 842 impossible( 843 "create_monster: can't find feature \"%s\"", 844 m->appear_as.str); 845 } else { 846 mtmp->m_ap_type = M_AP_FURNITURE; 847 mtmp->mappearance = i; 848 } 849 break; 850 851 case M_AP_OBJECT: 852 for (i = 0; i < NUM_OBJECTS; i++) 853 if (OBJ_NAME(objects[i]) && 854 !strcmp(OBJ_NAME(objects[i]),m->appear_as.str)) 855 break; 856 if (i == NUM_OBJECTS) { 857 impossible( 858 "create_monster: can't find object \"%s\"", 859 m->appear_as.str); 860 } else { 861 mtmp->m_ap_type = M_AP_OBJECT; 862 mtmp->mappearance = i; 863 } 864 break; 865 866 case M_AP_MONSTER: 867 /* note: mimics don't appear as monsters! */ 868 /* (but chameleons can :-) */ 869 default: 870 impossible( 871 "create_monster: unimplemented mon appear type [%d,\"%s\"]", 872 m->appear, m->appear_as.str); 873 break; 874 } 875 if (does_block(x, y, &levl[x][y])) 876 block_point(x, y); 877 } 878 879 if (m->peaceful >= 0) { 880 mtmp->mpeaceful = m->peaceful; 881 /* changed mpeaceful again; have to reset malign */ 882 set_malign(mtmp); 883 } 884 if (m->asleep >= 0) { 885#ifdef UNIXPC 886 /* optimizer bug strikes again */ 887 if (m->asleep) 888 mtmp->msleeping = 1; 889 else 890 mtmp->msleeping = 0; 891#else 892 mtmp->msleeping = m->asleep; 893#endif 894 } 895 } 896 897 } /* if (rn2(100) < m->chance) */ 898 m_done: 899 Free(m->name.str); 900 Free(m->appear_as.str); 901} 902 903/* 904 * Create an object in a room. 905 */ 906 907STATIC_OVL void 908create_object(o,croom) 909object *o; 910struct mkroom *croom; 911{ 912 struct obj *otmp; 913 schar x, y; 914 char c; 915 boolean named; /* has a name been supplied in level description? */ 916 917 if (rn2(100) < o->chance) { 918 named = o->name.str ? TRUE : FALSE; 919 920 x = o->x; y = o->y; 921 if (croom) 922 get_room_loc(&x, &y, croom); 923 else 924 get_location(&x, &y, DRY); 925 926 if (o->class >= 0) 927 c = o->class; 928 else if (o->class > -11) 929 c = robjects[ -(o->class+1)]; 930 else 931 c = 0; 932 933 if (!c) 934 otmp = mkobj_at(RANDOM_CLASS, x, y, !named); 935 else if (o->id != -1) 936 otmp = mksobj_at(o->id, x, y, TRUE, !named); 937 else { 938 /* 939 * The special levels are compiled with the default "text" object 940 * class characters. We must convert them to the internal format. 941 */ 942 char oclass = (char) def_char_to_objclass(c); 943 944 if (oclass == MAXOCLASSES) 945 panic("create_object: unexpected object class '%c'",c); 946 947 /* KMH -- Create piles of gold properly */ 948 if (oclass == COIN_CLASS) 949 otmp = mkgold(0L, x, y); 950 else 951 otmp = mkobj_at(oclass, x, y, !named); 952 } 953 954 if (o->spe != -127) /* That means NOT RANDOM! */ 955 otmp->spe = (schar)o->spe; 956 957 switch (o->curse_state) { 958 case 1: bless(otmp); break; /* BLESSED */ 959 case 2: unbless(otmp); uncurse(otmp); break; /* uncursed */ 960 case 3: curse(otmp); break; /* CURSED */ 961 default: break; /* Otherwise it's random and we're happy 962 * with what mkobj gave us! */ 963 } 964 965 /* corpsenm is "empty" if -1, random if -2, otherwise specific */ 966 if (o->corpsenm == NON_PM - 1) otmp->corpsenm = rndmonnum(); 967 else if (o->corpsenm != NON_PM) otmp->corpsenm = o->corpsenm; 968 969 /* assume we wouldn't be given an egg corpsenm unless it was 970 hatchable */ 971 if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) { 972 if (dead_species(otmp->otyp, TRUE)) 973 kill_egg(otmp); /* make sure nothing hatches */ 974 else 975 attach_egg_hatch_timeout(otmp); /* attach new hatch timeout */ 976 } 977 978 if (named) 979 otmp = oname(otmp, o->name.str); 980 981 switch(o->containment) { 982 static struct obj *container = 0; 983 984 /* contents */ 985 case 1: 986 if (!container) { 987 impossible("create_object: no container"); 988 break; 989 } 990 remove_object(otmp); 991 (void) add_to_container(container, otmp); 992 goto o_done; /* don't stack, but do other cleanup */ 993 /* container */ 994 case 2: 995 delete_contents(otmp); 996 container = otmp; 997 break; 998 /* nothing */ 999 case 0: break; 1000 1001 default: impossible("containment type %d?", (int) o->containment); 1002 } 1003 1004 /* Medusa level special case: statues are petrified monsters, so they 1005 * are not stone-resistant and have monster inventory. They also lack 1006 * other contents, but that can be specified as an empty container. 1007 */ 1008 if (o->id == STATUE && Is_medusa_level(&u.uz) && 1009 o->corpsenm == NON_PM) { 1010 struct monst *was; 1011 struct obj *obj; 1012 int wastyp; 1013 1014 /* Named random statues are of player types, and aren't stone- 1015 * resistant (if they were, we'd have to reset the name as well as 1016 * setting corpsenm). 1017 */ 1018 for (wastyp = otmp->corpsenm; ; wastyp = rndmonnum()) { 1019 /* makemon without rndmonst() might create a group */ 1020 was = makemon(&mons[wastyp], 0, 0, NO_MM_FLAGS); 1021 if (!resists_ston(was)) break; 1022 mongone(was); 1023 } 1024 otmp->corpsenm = wastyp; 1025 while(was->minvent) { 1026 obj = was->minvent; 1027 obj->owornmask = 0; 1028 obj_extract_self(obj); 1029 (void) add_to_container(otmp, obj); 1030 } 1031 otmp->owt = weight(otmp); 1032 mongone(was); 1033 } 1034 1035 stackobj(otmp); 1036 1037 } /* if (rn2(100) < o->chance) */ 1038 o_done: 1039 Free(o->name.str); 1040} 1041 1042/* 1043 * Randomly place a specific engraving, then release its memory. 1044 */ 1045STATIC_OVL void 1046create_engraving(e, croom) 1047engraving *e; 1048struct mkroom *croom; 1049{ 1050 xchar x, y; 1051 1052 x = e->x, y = e->y; 1053 if (croom) 1054 get_room_loc(&x, &y, croom); 1055 else 1056 get_location(&x, &y, DRY); 1057 1058 make_engr_at(x, y, e->engr.str, 0L, e->etype); 1059 free((genericptr_t) e->engr.str); 1060} 1061 1062/* 1063 * Create stairs in a room. 1064 * 1065 */ 1066 1067STATIC_OVL void 1068create_stairs(s,croom) 1069stair *s; 1070struct mkroom *croom; 1071{ 1072 schar x,y; 1073 1074 x = s->x; y = s->y; 1075 get_free_room_loc(&x, &y, croom); 1076 mkstairs(x,y,(char)s->up, croom); 1077} 1078 1079/* 1080 * Create an altar in a room. 1081 */ 1082 1083STATIC_OVL void 1084create_altar(a, croom) 1085 altar *a; 1086 struct mkroom *croom; 1087{ 1088 schar sproom,x,y; 1089 aligntyp amask; 1090 boolean croom_is_temple = TRUE; 1091 int oldtyp; 1092 1093 x = a->x; y = a->y; 1094 1095 if (croom) { 1096 get_free_room_loc(&x, &y, croom); 1097 if (croom->rtype != TEMPLE) 1098 croom_is_temple = FALSE; 1099 } else { 1100 get_location(&x, &y, DRY); 1101 if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0) 1102 croom = &rooms[sproom - ROOMOFFSET]; 1103 else 1104 croom_is_temple = FALSE; 1105 } 1106 1107 /* check for existing features */ 1108 oldtyp = levl[x][y].typ; 1109 if (oldtyp == STAIRS || oldtyp == LADDER) 1110 return; 1111 1112 a->x = x; 1113 a->y = y; 1114 1115 /* Is the alignment random ? 1116 * If so, it's an 80% chance that the altar will be co-aligned. 1117 * 1118 * The alignment is encoded as amask values instead of alignment 1119 * values to avoid conflicting with the rest of the encoding, 1120 * shared by many other parts of the special level code. 1121 */ 1122 1123 amask = (a->align == AM_SPLEV_CO) ? 1124 Align2amask(u.ualignbase[A_ORIGINAL]) : 1125 (a->align == AM_SPLEV_NONCO) ? 1126 Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) : 1127 (a->align == -11) ? induced_align(80) : 1128 (a->align < 0 ? ralign[-a->align-1] : a->align); 1129 1130 levl[x][y].typ = ALTAR; 1131 levl[x][y].altarmask = amask; 1132 1133 if (a->shrine < 0) a->shrine = rn2(2); /* handle random case */ 1134 1135 if (oldtyp == FOUNTAIN) 1136 level.flags.nfountains--; 1137 else if (oldtyp == SINK) 1138 level.flags.nsinks--; 1139 1140 if (!croom_is_temple || !a->shrine) return; 1141 1142 if (a->shrine) { /* Is it a shrine or sanctum? */ 1143 priestini(&u.uz, croom, x, y, (a->shrine > 1)); 1144 levl[x][y].altarmask |= AM_SHRINE; 1145 level.flags.has_temple = TRUE; 1146 } 1147} 1148 1149/* 1150 * Create a gold pile in a room. 1151 */ 1152 1153STATIC_OVL void 1154create_gold(g,croom) 1155gold *g; 1156struct mkroom *croom; 1157{ 1158 schar x,y; 1159 1160 x = g->x; y= g->y; 1161 if (croom) 1162 get_room_loc(&x, &y, croom); 1163 else 1164 get_location(&x, &y, DRY); 1165 1166 if (g->amount == -1) 1167 g->amount = rnd(200); 1168 (void) mkgold((long) g->amount, x, y); 1169} 1170 1171/* 1172 * Create a feature (e.g a fountain) in a room. 1173 */ 1174 1175STATIC_OVL void 1176create_feature(fx, fy, croom, typ) 1177int fx, fy; 1178struct mkroom *croom; 1179int typ; 1180{ 1181 schar x,y; 1182 int trycnt = 0; 1183 1184 x = fx; y = fy; 1185 if (croom) { 1186 if (x < 0 && y < 0) 1187 do { 1188 x = -1; y = -1; 1189 get_room_loc(&x, &y, croom); 1190 } while (++trycnt <= 200 && occupied(x,y)); 1191 else 1192 get_room_loc(&x, &y, croom); 1193 if(trycnt > 200) 1194 return; 1195 } else { 1196 get_location(&x, &y, DRY); 1197 } 1198 /* Don't cover up an existing feature (particularly randomly 1199 placed stairs). However, if the _same_ feature is already 1200 here, it came from the map drawing and we still need to 1201 update the special counters. */ 1202 if (IS_FURNITURE(levl[x][y].typ) && levl[x][y].typ != typ) 1203 return; 1204 1205 levl[x][y].typ = typ; 1206 if (typ == FOUNTAIN) 1207 level.flags.nfountains++; 1208 else if (typ == SINK) 1209 level.flags.nsinks++; 1210} 1211 1212/* 1213 * Search for a door in a room on a specified wall. 1214 */ 1215 1216STATIC_OVL boolean 1217search_door(croom,x,y,wall,cnt) 1218struct mkroom *croom; 1219xchar *x, *y; 1220xchar wall; 1221int cnt; 1222{ 1223 int dx, dy; 1224 int xx,yy; 1225 1226 switch(wall) { 1227 case W_NORTH: 1228 dy = 0; dx = 1; 1229 xx = croom->lx; 1230 yy = croom->hy + 1; 1231 break; 1232 case W_SOUTH: 1233 dy = 0; dx = 1; 1234 xx = croom->lx; 1235 yy = croom->ly - 1; 1236 break; 1237 case W_EAST: 1238 dy = 1; dx = 0; 1239 xx = croom->hx + 1; 1240 yy = croom->ly; 1241 break; 1242 case W_WEST: 1243 dy = 1; dx = 0; 1244 xx = croom->lx - 1; 1245 yy = croom->ly; 1246 break; 1247 default: 1248 dx = dy = xx = yy = 0; 1249 panic("search_door: Bad wall!"); 1250 break; 1251 } 1252 while (xx <= croom->hx+1 && yy <= croom->hy+1) { 1253 if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) { 1254 *x = xx; 1255 *y = yy; 1256 if (cnt-- <= 0) 1257 return TRUE; 1258 } 1259 xx += dx; 1260 yy += dy; 1261 } 1262 return FALSE; 1263} 1264 1265/* 1266 * Dig a corridor between two points. 1267 */ 1268 1269boolean 1270dig_corridor(org,dest,nxcor,ftyp,btyp) 1271coord *org, *dest; 1272boolean nxcor; 1273schar ftyp, btyp; 1274{ 1275 register int dx=0, dy=0, dix, diy, cct; 1276 register struct rm *crm; 1277 register int tx, ty, xx, yy; 1278 1279 xx = org->x; yy = org->y; 1280 tx = dest->x; ty = dest->y; 1281 if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 || 1282 xx > COLNO-1 || tx > COLNO-1 || 1283 yy > ROWNO-1 || ty > ROWNO-1) { 1284#ifdef NETHACK_DEBUG 1285 debugpline("dig_corridor: bad coords : (%d,%d) (%d,%d).", 1286 xx,yy,tx,ty); 1287#endif 1288 return FALSE; 1289 } 1290 if (tx > xx) dx = 1; 1291 else if (ty > yy) dy = 1; 1292 else if (tx < xx) dx = -1; 1293 else dy = -1; 1294 1295 xx -= dx; 1296 yy -= dy; 1297 cct = 0; 1298 while(xx != tx || yy != ty) { 1299 /* loop: dig corridor at [xx,yy] and find new [xx,yy] */ 1300 if(cct++ > 500 || (nxcor && !rn2(35))) 1301 return FALSE; 1302 1303 xx += dx; 1304 yy += dy; 1305 1306 if(xx >= COLNO-1 || xx <= 0 || yy <= 0 || yy >= ROWNO-1) 1307 return FALSE; /* impossible */ 1308 1309 crm = &levl[xx][yy]; 1310 if(crm->typ == btyp) { 1311 if(ftyp != CORR || rn2(100)) { 1312 crm->typ = ftyp; 1313 if(nxcor && !rn2(50)) 1314 (void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE); 1315 } else { 1316 crm->typ = SCORR; 1317 } 1318 } else 1319 if(crm->typ != ftyp && crm->typ != SCORR) { 1320 /* strange ... */ 1321 return FALSE; 1322 } 1323 1324 /* find next corridor position */ 1325 dix = abs(xx-tx); 1326 diy = abs(yy-ty); 1327 1328 /* do we have to change direction ? */ 1329 if(dy && dix > diy) { 1330 register int ddx = (xx > tx) ? -1 : 1; 1331 1332 crm = &levl[xx+ddx][yy]; 1333 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) { 1334 dx = ddx; 1335 dy = 0; 1336 continue; 1337 } 1338 } else if(dx && diy > dix) { 1339 register int ddy = (yy > ty) ? -1 : 1; 1340 1341 crm = &levl[xx][yy+ddy]; 1342 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) { 1343 dy = ddy; 1344 dx = 0; 1345 continue; 1346 } 1347 } 1348 1349 /* continue straight on? */ 1350 crm = &levl[xx+dx][yy+dy]; 1351 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) 1352 continue; 1353 1354 /* no, what must we do now?? */ 1355 if(dx) { 1356 dx = 0; 1357 dy = (ty < yy) ? -1 : 1; 1358 } else { 1359 dy = 0; 1360 dx = (tx < xx) ? -1 : 1; 1361 } 1362 crm = &levl[xx+dx][yy+dy]; 1363 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) 1364 continue; 1365 dy = -dy; 1366 dx = -dx; 1367 } 1368 return TRUE; 1369} 1370 1371/* 1372 * Disgusting hack: since special levels have their rooms filled before 1373 * sorting the rooms, we have to re-arrange the speed values upstairs_room 1374 * and dnstairs_room after the rooms have been sorted. On normal levels, 1375 * stairs don't get created until _after_ sorting takes place. 1376 */ 1377STATIC_OVL void 1378fix_stair_rooms() 1379{ 1380 int i; 1381 struct mkroom *croom; 1382 1383 if(xdnstair && 1384 !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx) && 1385 (dnstairs_room->ly <= ydnstair && ydnstair <= dnstairs_room->hy))) { 1386 for(i=0; i < nroom; i++) { 1387 croom = &rooms[i]; 1388 if((croom->lx <= xdnstair && xdnstair <= croom->hx) && 1389 (croom->ly <= ydnstair && ydnstair <= croom->hy)) { 1390 dnstairs_room = croom; 1391 break; 1392 } 1393 } 1394 if(i == nroom) 1395 panic("Couldn't find dnstair room in fix_stair_rooms!"); 1396 } 1397 if(xupstair && 1398 !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx) && 1399 (upstairs_room->ly <= yupstair && yupstair <= upstairs_room->hy))) { 1400 for(i=0; i < nroom; i++) { 1401 croom = &rooms[i]; 1402 if((croom->lx <= xupstair && xupstair <= croom->hx) && 1403 (croom->ly <= yupstair && yupstair <= croom->hy)) { 1404 upstairs_room = croom; 1405 break; 1406 } 1407 } 1408 if(i == nroom) 1409 panic("Couldn't find upstair room in fix_stair_rooms!"); 1410 } 1411} 1412 1413/* 1414 * Corridors always start from a door. But it can end anywhere... 1415 * Basically we search for door coordinates or for endpoints coordinates 1416 * (from a distance). 1417 */ 1418 1419STATIC_OVL void 1420create_corridor(c) 1421corridor *c; 1422{ 1423 coord org, dest; 1424 1425 if (c->src.room == -1) { 1426 sort_rooms(); 1427 fix_stair_rooms(); 1428 makecorridors(); 1429 return; 1430 } 1431 1432 if( !search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall, 1433 c->src.door)) 1434 return; 1435 1436 if (c->dest.room != -1) { 1437 if(!search_door(&rooms[c->dest.room], &dest.x, &dest.y, 1438 c->dest.wall, c->dest.door)) 1439 return; 1440 switch(c->src.wall) { 1441 case W_NORTH: org.y--; break; 1442 case W_SOUTH: org.y++; break; 1443 case W_WEST: org.x--; break; 1444 case W_EAST: org.x++; break; 1445 } 1446 switch(c->dest.wall) { 1447 case W_NORTH: dest.y--; break; 1448 case W_SOUTH: dest.y++; break; 1449 case W_WEST: dest.x--; break; 1450 case W_EAST: dest.x++; break; 1451 } 1452 (void) dig_corridor(&org, &dest, FALSE, CORR, STONE); 1453 } 1454} 1455 1456 1457/* 1458 * Fill a room (shop, zoo, etc...) with appropriate stuff. 1459 */ 1460 1461void 1462fill_room(croom, prefilled) 1463struct mkroom *croom; 1464boolean prefilled; 1465{ 1466 if (!croom || croom->rtype == OROOM) 1467 return; 1468 1469 if (!prefilled) { 1470 int x,y; 1471 1472 /* Shop ? */ 1473 if (croom->rtype >= SHOPBASE) { 1474 stock_room(croom->rtype - SHOPBASE, croom); 1475 level.flags.has_shop = TRUE; 1476 return; 1477 } 1478 1479 switch (croom->rtype) { 1480 case VAULT: 1481 for (x=croom->lx;x<=croom->hx;x++) 1482 for (y=croom->ly;y<=croom->hy;y++) 1483 (void) mkgold((long)rn1(abs(depth(&u.uz))*100, 51), x, y); 1484 break; 1485 case COURT: 1486 case ZOO: 1487 case BEEHIVE: 1488 case MORGUE: 1489 case BARRACKS: 1490 fill_zoo(croom); 1491 break; 1492 } 1493 } 1494 switch (croom->rtype) { 1495 case VAULT: 1496 level.flags.has_vault = TRUE; 1497 break; 1498 case ZOO: 1499 level.flags.has_zoo = TRUE; 1500 break; 1501 case COURT: 1502 level.flags.has_court = TRUE; 1503 break; 1504 case MORGUE: 1505 level.flags.has_morgue = TRUE; 1506 break; 1507 case BEEHIVE: 1508 level.flags.has_beehive = TRUE; 1509 break; 1510 case BARRACKS: 1511 level.flags.has_barracks = TRUE; 1512 break; 1513 case TEMPLE: 1514 level.flags.has_temple = TRUE; 1515 break; 1516 case SWAMP: 1517 level.flags.has_swamp = TRUE; 1518 break; 1519 } 1520} 1521 1522STATIC_OVL void 1523free_rooms(ro, n) 1524room **ro; 1525int n; 1526{ 1527 short j; 1528 room *r; 1529 1530 while(n--) { 1531 r = ro[n]; 1532 Free(r->name); 1533 Free(r->parent); 1534 if ((j = r->ndoor) != 0) { 1535 while(j--) 1536 Free(r->doors[j]); 1537 Free(r->doors); 1538 } 1539 if ((j = r->nstair) != 0) { 1540 while(j--) 1541 Free(r->stairs[j]); 1542 Free(r->stairs); 1543 } 1544 if ((j = r->naltar) != 0) { 1545 while (j--) 1546 Free(r->altars[j]); 1547 Free(r->altars); 1548 } 1549 if ((j = r->nfountain) != 0) { 1550 while(j--) 1551 Free(r->fountains[j]); 1552 Free(r->fountains); 1553 } 1554 if ((j = r->nsink) != 0) { 1555 while(j--) 1556 Free(r->sinks[j]); 1557 Free(r->sinks); 1558 } 1559 if ((j = r->npool) != 0) { 1560 while(j--) 1561 Free(r->pools[j]); 1562 Free(r->pools); 1563 } 1564 if ((j = r->ntrap) != 0) { 1565 while (j--) 1566 Free(r->traps[j]); 1567 Free(r->traps); 1568 } 1569 if ((j = r->nmonster) != 0) { 1570 while (j--) 1571 Free(r->monsters[j]); 1572 Free(r->monsters); 1573 } 1574 if ((j = r->nobject) != 0) { 1575 while (j--) 1576 Free(r->objects[j]); 1577 Free(r->objects); 1578 } 1579 if ((j = r->ngold) != 0) { 1580 while(j--) 1581 Free(r->golds[j]); 1582 Free(r->golds); 1583 } 1584 if ((j = r->nengraving) != 0) { 1585 while (j--) 1586 Free(r->engravings[j]); 1587 Free(r->engravings); 1588 } 1589 Free(r); 1590 } 1591 Free(ro); 1592} 1593 1594STATIC_OVL void 1595build_room(r, pr) 1596room *r, *pr; 1597{ 1598 boolean okroom; 1599 struct mkroom *aroom; 1600 short i; 1601 xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM; 1602 1603 if(pr) { 1604 aroom = &subrooms[nsubroom]; 1605 okroom = create_subroom(pr->mkr, r->x, r->y, r->w, r->h, 1606 rtype, r->rlit); 1607 } else { 1608 aroom = &rooms[nroom]; 1609 okroom = create_room(r->x, r->y, r->w, r->h, r->xalign, 1610 r->yalign, rtype, r->rlit); 1611 r->mkr = aroom; 1612 } 1613 1614 if (okroom) { 1615 /* Create subrooms if necessary... */ 1616 for(i=0; i < r->nsubroom; i++) 1617 build_room(r->subrooms[i], r); 1618 /* And now we can fill the room! */ 1619 1620 /* Priority to the stairs */ 1621 1622 for(i=0; i <r->nstair; i++) 1623 create_stairs(r->stairs[i], aroom); 1624 1625 /* Then to the various elements (sinks, etc..) */ 1626 for(i = 0; i<r->nsink; i++) 1627 create_feature(r->sinks[i]->x, r->sinks[i]->y, aroom, SINK); 1628 for(i = 0; i<r->npool; i++) 1629 create_feature(r->pools[i]->x, r->pools[i]->y, aroom, POOL); 1630 for(i = 0; i<r->nfountain; i++) 1631 create_feature(r->fountains[i]->x, r->fountains[i]->y, 1632 aroom, FOUNTAIN); 1633 for(i = 0; i<r->naltar; i++) 1634 create_altar(r->altars[i], aroom); 1635 for(i = 0; i<r->ndoor; i++) 1636 create_door(r->doors[i], aroom); 1637 1638 /* The traps */ 1639 for(i = 0; i<r->ntrap; i++) 1640 create_trap(r->traps[i], aroom); 1641 1642 /* The monsters */ 1643 for(i = 0; i<r->nmonster; i++) 1644 create_monster(r->monsters[i], aroom); 1645 1646 /* The objects */ 1647 for(i = 0; i<r->nobject; i++) 1648 create_object(r->objects[i], aroom); 1649 1650 /* The gold piles */ 1651 for(i = 0; i<r->ngold; i++) 1652 create_gold(r->golds[i], aroom); 1653 1654 /* The engravings */ 1655 for (i = 0; i < r->nengraving; i++) 1656 create_engraving(r->engravings[i], aroom); 1657 1658#ifdef SPECIALIZATION 1659 topologize(aroom,FALSE); /* set roomno */ 1660#else 1661 topologize(aroom); /* set roomno */ 1662#endif 1663 /* MRS - 07/04/91 - This is temporary but should result 1664 * in proper filling of shops, etc. 1665 * DLC - this can fail if corridors are added to this room 1666 * at a later point. Currently no good way to fix this. 1667 */ 1668 if(aroom->rtype != OROOM && r->filled) fill_room(aroom, FALSE); 1669 } 1670} 1671 1672/* 1673 * set lighting in a region that will not become a room. 1674 */ 1675STATIC_OVL void 1676light_region(tmpregion) 1677 region *tmpregion; 1678{ 1679 register boolean litstate = tmpregion->rlit ? 1 : 0; 1680 register int hiy = tmpregion->y2; 1681 register int x, y; 1682 register struct rm *lev; 1683 int lowy = tmpregion->y1; 1684 int lowx = tmpregion->x1, hix = tmpregion->x2; 1685 1686 if(litstate) { 1687 /* adjust region size for walls, but only if lighted */ 1688 lowx = max(lowx-1,1); 1689 hix = min(hix+1,COLNO-1); 1690 lowy = max(lowy-1,0); 1691 hiy = min(hiy+1, ROWNO-1); 1692 } 1693 for(x = lowx; x <= hix; x++) { 1694 lev = &levl[x][lowy]; 1695 for(y = lowy; y <= hiy; y++) { 1696 if (lev->typ != LAVAPOOL) /* this overrides normal lighting */ 1697 lev->lit = litstate; 1698 lev++; 1699 } 1700 } 1701} 1702 1703/* initialization common to all special levels */ 1704STATIC_OVL void 1705load_common_data(fd, typ) 1706dlb *fd; 1707int typ; 1708{ 1709 uchar n; 1710 long lev_flags; 1711 int i; 1712 1713 { 1714 aligntyp atmp; 1715 /* shuffle 3 alignments; can't use sp_lev_shuffle() on aligntyp's */ 1716 i = rn2(3); atmp=ralign[2]; ralign[2]=ralign[i]; ralign[i]=atmp; 1717 if (rn2(2)) { atmp=ralign[1]; ralign[1]=ralign[0]; ralign[0]=atmp; } 1718 } 1719 1720 level.flags.is_maze_lev = typ == SP_LEV_MAZE; 1721 1722 /* Read the level initialization data */ 1723 Fread((genericptr_t) &init_lev, 1, sizeof(lev_init), fd); 1724 if(init_lev.init_present) { 1725 if(init_lev.lit < 0) 1726 init_lev.lit = rn2(2); 1727 mkmap(&init_lev); 1728 } 1729 1730 /* Read the per level flags */ 1731 Fread((genericptr_t) &lev_flags, 1, sizeof(lev_flags), fd); 1732 if (lev_flags & NOTELEPORT) 1733 level.flags.noteleport = 1; 1734 if (lev_flags & HARDFLOOR) 1735 level.flags.hardfloor = 1; 1736 if (lev_flags & NOMMAP) 1737 level.flags.nommap = 1; 1738 if (lev_flags & SHORTSIGHTED) 1739 level.flags.shortsighted = 1; 1740 if (lev_flags & ARBOREAL) 1741 level.flags.arboreal = 1; 1742 1743 /* Read message */ 1744 Fread((genericptr_t) &n, 1, sizeof(n), fd); 1745 if (n) { 1746 lev_message = (char *) alloc(n + 1); 1747 Fread((genericptr_t) lev_message, 1, (int) n, fd); 1748 lev_message[n] = 0; 1749 } 1750} 1751 1752STATIC_OVL void 1753load_one_monster(fd, m) 1754dlb *fd; 1755monster *m; 1756{ 1757 int size; 1758 1759 Fread((genericptr_t) m, 1, sizeof *m, fd); 1760 if ((size = m->name.len) != 0) { 1761 m->name.str = (char *) alloc((unsigned)size + 1); 1762 Fread((genericptr_t) m->name.str, 1, size, fd); 1763 m->name.str[size] = '\0'; 1764 } else 1765 m->name.str = (char *) 0; 1766 if ((size = m->appear_as.len) != 0) { 1767 m->appear_as.str = (char *) alloc((unsigned)size + 1); 1768 Fread((genericptr_t) m->appear_as.str, 1, size, fd); 1769 m->appear_as.str[size] = '\0'; 1770 } else 1771 m->appear_as.str = (char *) 0; 1772} 1773 1774STATIC_OVL void 1775load_one_object(fd, o) 1776dlb *fd; 1777object *o; 1778{ 1779 int size; 1780 1781 Fread((genericptr_t) o, 1, sizeof *o, fd); 1782 if ((size = o->name.len) != 0) { 1783 o->name.str = (char *) alloc((unsigned)size + 1); 1784 Fread((genericptr_t) o->name.str, 1, size, fd); 1785 o->name.str[size] = '\0'; 1786 } else 1787 o->name.str = (char *) 0; 1788} 1789 1790STATIC_OVL void 1791load_one_engraving(fd, e) 1792dlb *fd; 1793engraving *e; 1794{ 1795 int size; 1796 1797 Fread((genericptr_t) e, 1, sizeof *e, fd); 1798 size = e->engr.len; 1799 e->engr.str = (char *) alloc((unsigned)size+1); 1800 Fread((genericptr_t) e->engr.str, 1, size, fd); 1801 e->engr.str[size] = '\0'; 1802} 1803 1804STATIC_OVL boolean 1805load_rooms(fd) 1806dlb *fd; 1807{ 1808 xchar nrooms, ncorr; 1809 char n; 1810 short size; 1811 corridor tmpcor; 1812 room** tmproom; 1813 int i, j; 1814 1815 load_common_data(fd, SP_LEV_ROOMS); 1816 1817 Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrobjects */ 1818 if (n) { 1819 Fread((genericptr_t)robjects, sizeof(*robjects), n, fd); 1820 sp_lev_shuffle(robjects, (char *)0, (int)n); 1821 } 1822 1823 Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrmonst */ 1824 if (n) { 1825 Fread((genericptr_t)rmonst, sizeof(*rmonst), n, fd); 1826 sp_lev_shuffle(rmonst, (char *)0, (int)n); 1827 } 1828 1829 Fread((genericptr_t) &nrooms, 1, sizeof(nrooms), fd); 1830 /* Number of rooms to read */ 1831 tmproom = NewTab(room,nrooms); 1832 for (i=0;i<nrooms;i++) { 1833 room *r; 1834 1835 r = tmproom[i] = New(room); 1836 1837 /* Let's see if this room has a name */ 1838 Fread((genericptr_t) &size, 1, sizeof(size), fd); 1839 if (size > 0) { /* Yup, it does! */ 1840 r->name = (char *) alloc((unsigned)size + 1); 1841 Fread((genericptr_t) r->name, 1, size, fd); 1842 r->name[size] = 0; 1843 } else 1844 r->name = (char *) 0; 1845 1846 /* Let's see if this room has a parent */ 1847 Fread((genericptr_t) &size, 1, sizeof(size), fd); 1848 if (size > 0) { /* Yup, it does! */ 1849 r->parent = (char *) alloc((unsigned)size + 1); 1850 Fread((genericptr_t) r->parent, 1, size, fd); 1851 r->parent[size] = 0; 1852 } else 1853 r->parent = (char *) 0; 1854 1855 Fread((genericptr_t) &r->x, 1, sizeof(r->x), fd); 1856 /* x pos on the grid (1-5) */ 1857 Fread((genericptr_t) &r->y, 1, sizeof(r->y), fd); 1858 /* y pos on the grid (1-5) */ 1859 Fread((genericptr_t) &r->w, 1, sizeof(r->w), fd); 1860 /* width of the room */ 1861 Fread((genericptr_t) &r->h, 1, sizeof(r->h), fd); 1862 /* height of the room */ 1863 Fread((genericptr_t) &r->xalign, 1, sizeof(r->xalign), fd); 1864 /* horizontal alignment */ 1865 Fread((genericptr_t) &r->yalign, 1, sizeof(r->yalign), fd); 1866 /* vertical alignment */ 1867 Fread((genericptr_t) &r->rtype, 1, sizeof(r->rtype), fd); 1868 /* type of room (zoo, shop, etc.) */ 1869 Fread((genericptr_t) &r->chance, 1, sizeof(r->chance), fd); 1870 /* chance of room being special. */ 1871 Fread((genericptr_t) &r->rlit, 1, sizeof(r->rlit), fd); 1872 /* lit or not ? */ 1873 Fread((genericptr_t) &r->filled, 1, sizeof(r->filled), fd); 1874 /* to be filled? */ 1875 r->nsubroom= 0; 1876 1877 /* read the doors */ 1878 Fread((genericptr_t) &r->ndoor, 1, sizeof(r->ndoor), fd); 1879 if ((n = r->ndoor) != 0) 1880 r->doors = NewTab(room_door, n); 1881 while(n--) { 1882 r->doors[(int)n] = New(room_door); 1883 Fread((genericptr_t) r->doors[(int)n], 1, 1884 sizeof(room_door), fd); 1885 } 1886 1887 /* read the stairs */ 1888 Fread((genericptr_t) &r->nstair, 1, sizeof(r->nstair), fd); 1889 if ((n = r->nstair) != 0) 1890 r->stairs = NewTab(stair, n); 1891 while (n--) { 1892 r->stairs[(int)n] = New(stair); 1893 Fread((genericptr_t) r->stairs[(int)n], 1, 1894 sizeof(stair), fd); 1895 } 1896 1897 /* read the altars */ 1898 Fread((genericptr_t) &r->naltar, 1, sizeof(r->naltar), fd); 1899 if ((n = r->naltar) != 0) 1900 r->altars = NewTab(altar, n); 1901 while (n--) { 1902 r->altars[(int)n] = New(altar); 1903 Fread((genericptr_t) r->altars[(int)n], 1, 1904 sizeof(altar), fd); 1905 } 1906 1907 /* read the fountains */ 1908 Fread((genericptr_t) &r->nfountain, 1, 1909 sizeof(r->nfountain), fd); 1910 if ((n = r->nfountain) != 0) 1911 r->fountains = NewTab(fountain, n); 1912 while (n--) { 1913 r->fountains[(int)n] = New(fountain); 1914 Fread((genericptr_t) r->fountains[(int)n], 1, 1915 sizeof(fountain), fd); 1916 } 1917 1918 /* read the sinks */ 1919 Fread((genericptr_t) &r->nsink, 1, sizeof(r->nsink), fd); 1920 if ((n = r->nsink) != 0) 1921 r->sinks = NewTab(sink, n); 1922 while (n--) { 1923 r->sinks[(int)n] = New(sink); 1924 Fread((genericptr_t) r->sinks[(int)n], 1, sizeof(sink), fd); 1925 } 1926 1927 /* read the pools */ 1928 Fread((genericptr_t) &r->npool, 1, sizeof(r->npool), fd); 1929 if ((n = r->npool) != 0) 1930 r->pools = NewTab(pool,n); 1931 while (n--) { 1932 r->pools[(int)n] = New(pool); 1933 Fread((genericptr_t) r->pools[(int)n], 1, sizeof(pool), fd); 1934 } 1935 1936 /* read the traps */ 1937 Fread((genericptr_t) &r->ntrap, 1, sizeof(r->ntrap), fd); 1938 if ((n = r->ntrap) != 0) 1939 r->traps = NewTab(trap, n); 1940 while(n--) { 1941 r->traps[(int)n] = New(trap); 1942 Fread((genericptr_t) r->traps[(int)n], 1, sizeof(trap), fd); 1943 } 1944 1945 /* read the monsters */ 1946 Fread((genericptr_t) &r->nmonster, 1, sizeof(r->nmonster), fd); 1947 if ((n = r->nmonster) != 0) { 1948 r->monsters = NewTab(monster, n); 1949 while(n--) { 1950 r->monsters[(int)n] = New(monster); 1951 load_one_monster(fd, r->monsters[(int)n]); 1952 } 1953 } else 1954 r->monsters = 0; 1955 1956 /* read the objects, in same order as mazes */ 1957 Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd); 1958 if ((n = r->nobject) != 0) { 1959 r->objects = NewTab(object, n); 1960 for (j = 0; j < n; ++j) { 1961 r->objects[j] = New(object); 1962 load_one_object(fd, r->objects[j]); 1963 } 1964 } else 1965 r->objects = 0; 1966 1967 /* read the gold piles */ 1968 Fread((genericptr_t) &r->ngold, 1, sizeof(r->ngold), fd); 1969 if ((n = r->ngold) != 0) 1970 r->golds = NewTab(gold, n); 1971 while (n--) { 1972 r->golds[(int)n] = New(gold); 1973 Fread((genericptr_t) r->golds[(int)n], 1, sizeof(gold), fd); 1974 } 1975 1976 /* read the engravings */ 1977 Fread((genericptr_t) &r->nengraving, 1, 1978 sizeof(r->nengraving), fd); 1979 if ((n = r->nengraving) != 0) { 1980 r->engravings = NewTab(engraving,n); 1981 while (n--) { 1982 r->engravings[(int)n] = New(engraving); 1983 load_one_engraving(fd, r->engravings[(int)n]); 1984 } 1985 } else 1986 r->engravings = 0; 1987 1988 } 1989 1990 /* Now that we have loaded all the rooms, search the 1991 * subrooms and create the links. 1992 */ 1993 1994 for (i = 0; i<nrooms; i++) 1995 if (tmproom[i]->parent) { 1996 /* Search the parent room */ 1997 for(j=0; j<nrooms; j++) 1998 if (tmproom[j]->name && !strcmp(tmproom[j]->name, 1999 tmproom[i]->parent)) { 2000 n = tmproom[j]->nsubroom++; 2001 tmproom[j]->subrooms[(int)n] = tmproom[i]; 2002 break; 2003 } 2004 } 2005 2006 /* 2007 * Create the rooms now... 2008 */ 2009 2010 for (i=0; i < nrooms; i++) 2011 if(!tmproom[i]->parent) 2012 build_room(tmproom[i], (room *) 0); 2013 2014 free_rooms(tmproom, nrooms); 2015 2016 /* read the corridors */ 2017 2018 Fread((genericptr_t) &ncorr, sizeof(ncorr), 1, fd); 2019 for (i=0; i<ncorr; i++) { 2020 Fread((genericptr_t) &tmpcor, 1, sizeof(tmpcor), fd); 2021 create_corridor(&tmpcor); 2022 } 2023 2024 return TRUE; 2025} 2026 2027/* 2028 * Select a random coordinate in the maze. 2029 * 2030 * We want a place not 'touched' by the loader. That is, a place in 2031 * the maze outside every part of the special level. 2032 */ 2033 2034STATIC_OVL void 2035maze1xy(m, humidity) 2036coord *m; 2037int humidity; 2038{ 2039 register int x, y, tryct = 2000; 2040 /* tryct: normally it won't take more than ten or so tries due 2041 to the circumstances under which we'll be called, but the 2042 `humidity' screening might drastically change the chances */ 2043 2044 do { 2045 x = rn1(x_maze_max - 3, 3); 2046 y = rn1(y_maze_max - 3, 3); 2047 if (--tryct < 0) break; /* give up */ 2048 } while (!(x % 2) || !(y % 2) || Map[x][y] || 2049 !is_ok_location((schar)x, (schar)y, humidity)); 2050 2051 m->x = (xchar)x, m->y = (xchar)y; 2052} 2053 2054/* 2055 * The Big Thing: special maze loader 2056 * 2057 * Could be cleaner, but it works. 2058 */ 2059 2060STATIC_OVL boolean 2061load_maze(fd) 2062dlb *fd; 2063{ 2064 xchar x, y, typ; 2065 boolean prefilled, room_not_needed; 2066 2067 char n, numpart = 0; 2068 xchar nwalk = 0, nwalk_sav; 2069 schar filling; 2070 char halign, valign; 2071 2072 int xi, dir, size; 2073 coord mm; 2074 int mapcount, mapcountmax, mapfact; 2075 2076 lev_region tmplregion; 2077 region tmpregion; 2078 door tmpdoor; 2079 trap tmptrap; 2080 monster tmpmons; 2081 object tmpobj; 2082 drawbridge tmpdb; 2083 walk tmpwalk; 2084 digpos tmpdig; 2085 lad tmplad; 2086 stair tmpstair, prevstair; 2087 altar tmpaltar; 2088 gold tmpgold; 2089 fountain tmpfountain; 2090 engraving tmpengraving; 2091 xchar mustfill[(MAXNROFROOMS+1)*2]; 2092 struct trap *badtrap; 2093 boolean has_bounds; 2094 2095 (void) memset((genericptr_t)&Map[0][0], 0, sizeof Map); 2096 load_common_data(fd, SP_LEV_MAZE); 2097 2098 /* Initialize map */ 2099 Fread((genericptr_t) &filling, 1, sizeof(filling), fd); 2100 if (!init_lev.init_present) { /* don't init if mkmap() has been called */ 2101 for(x = 2; x <= x_maze_max; x++) 2102 for(y = 0; y <= y_maze_max; y++) 2103 if (filling == -1) { 2104#ifndef WALLIFIED_MAZE 2105 levl[x][y].typ = STONE; 2106#else 2107 levl[x][y].typ = 2108 (y < 2 || ((x % 2) && (y % 2))) ? STONE : HWALL; 2109#endif 2110 } else { 2111 levl[x][y].typ = filling; 2112 } 2113 } 2114 2115 /* Start reading the file */ 2116 Fread((genericptr_t) &numpart, 1, sizeof(numpart), fd); 2117 /* Number of parts */ 2118 if (!numpart || numpart > 9) 2119 panic("load_maze error: numpart = %d", (int) numpart); 2120 2121 while (numpart--) { 2122 Fread((genericptr_t) &halign, 1, sizeof(halign), fd); 2123 /* Horizontal alignment */ 2124 Fread((genericptr_t) &valign, 1, sizeof(valign), fd); 2125 /* Vertical alignment */ 2126 Fread((genericptr_t) &xsize, 1, sizeof(xsize), fd); 2127 /* size in X */ 2128 Fread((genericptr_t) &ysize, 1, sizeof(ysize), fd); 2129 /* size in Y */ 2130 switch((int) halign) { 2131 case LEFT: xstart = 3; break; 2132 case H_LEFT: xstart = 2+((x_maze_max-2-xsize)/4); break; 2133 case CENTER: xstart = 2+((x_maze_max-2-xsize)/2); break; 2134 case H_RIGHT: xstart = 2+((x_maze_max-2-xsize)*3/4); break; 2135 case RIGHT: xstart = x_maze_max-xsize-1; break; 2136 } 2137 switch((int) valign) { 2138 case TOP: ystart = 3; break; 2139 case CENTER: ystart = 2+((y_maze_max-2-ysize)/2); break; 2140 case BOTTOM: ystart = y_maze_max-ysize-1; break; 2141 } 2142 if (!(xstart % 2)) xstart++; 2143 if (!(ystart % 2)) ystart++; 2144 if ((ystart < 0) || (ystart + ysize > ROWNO)) { 2145 /* try to move the start a bit */ 2146 ystart += (ystart > 0) ? -2 : 2; 2147 if(ysize == ROWNO) ystart = 0; 2148 if(ystart < 0 || ystart + ysize > ROWNO) 2149 panic("reading special level with ysize too large"); 2150 } 2151 2152 /* 2153 * If any CROSSWALLs are found, must change to ROOM after REGION's 2154 * are laid out. CROSSWALLS are used to specify "invisible" 2155 * boundaries where DOOR syms look bad or aren't desirable. 2156 */ 2157 has_bounds = FALSE; 2158 2159 if(init_lev.init_present && xsize <= 1 && ysize <= 1) { 2160 xstart = 1; 2161 ystart = 0; 2162 xsize = COLNO-1; 2163 ysize = ROWNO; 2164 } else { 2165 /* Load the map */ 2166 for(y = ystart; y < ystart+ysize; y++) 2167 for(x = xstart; x < xstart+xsize; x++) { 2168 levl[x][y].typ = Fgetc(fd); 2169 levl[x][y].lit = FALSE; 2170 /* clear out levl: load_common_data may set them */ 2171 levl[x][y].flags = 0; 2172 levl[x][y].horizontal = 0; 2173 levl[x][y].roomno = 0; 2174 levl[x][y].edge = 0; 2175 /* 2176 * Note: Even though levl[x][y].typ is type schar, 2177 * lev_comp.y saves it as type char. Since schar != char 2178 * all the time we must make this exception or hack 2179 * through lev_comp.y to fix. 2180 */ 2181 2182 /* 2183 * Set secret doors to closed (why not trapped too?). Set 2184 * the horizontal bit. 2185 */ 2186 if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) { 2187 if(levl[x][y].typ == SDOOR) 2188 levl[x][y].doormask = D_CLOSED; 2189 /* 2190 * If there is a wall to the left that connects to a 2191 * (secret) door, then it is horizontal. This does 2192 * not allow (secret) doors to be corners of rooms. 2193 */ 2194 if (x != xstart && (IS_WALL(levl[x-1][y].typ) || 2195 levl[x-1][y].horizontal)) 2196 levl[x][y].horizontal = 1; 2197 } else if(levl[x][y].typ == HWALL || 2198 levl[x][y].typ == IRONBARS) 2199 levl[x][y].horizontal = 1; 2200 else if(levl[x][y].typ == LAVAPOOL) 2201 levl[x][y].lit = 1; 2202 else if(levl[x][y].typ == CROSSWALL) 2203 has_bounds = TRUE; 2204 Map[x][y] = 1; 2205 } 2206 if (init_lev.init_present && init_lev.joined) 2207 remove_rooms(xstart, ystart, xstart+xsize, ystart+ysize); 2208 } 2209 2210 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2211 /* Number of level regions */ 2212 if(n) { 2213 if(num_lregions) { 2214 /* realloc the lregion space to add the new ones */ 2215 /* don't really free it up until the whole level is done */ 2216 lev_region *newl = (lev_region *) alloc(sizeof(lev_region) * 2217 (unsigned)(n+num_lregions)); 2218 (void) memcpy((genericptr_t)(newl+n), (genericptr_t)lregions, 2219 sizeof(lev_region) * num_lregions); 2220 Free(lregions); 2221 num_lregions += n; 2222 lregions = newl; 2223 } else { 2224 num_lregions = n; 2225 lregions = (lev_region *) 2226 alloc(sizeof(lev_region) * (unsigned)n); 2227 } 2228 } 2229 2230 while(n--) { 2231 Fread((genericptr_t) &tmplregion, sizeof(tmplregion), 1, fd); 2232 if ((size = tmplregion.rname.len) != 0) { 2233 tmplregion.rname.str = (char *) alloc((unsigned)size + 1); 2234 Fread((genericptr_t) tmplregion.rname.str, size, 1, fd); 2235 tmplregion.rname.str[size] = '\0'; 2236 } else 2237 tmplregion.rname.str = (char *) 0; 2238 if(!tmplregion.in_islev) { 2239 get_location(&tmplregion.inarea.x1, &tmplregion.inarea.y1, 2240 DRY|WET); 2241 get_location(&tmplregion.inarea.x2, &tmplregion.inarea.y2, 2242 DRY|WET); 2243 } 2244 if(!tmplregion.del_islev) { 2245 get_location(&tmplregion.delarea.x1, &tmplregion.delarea.y1, 2246 DRY|WET); 2247 get_location(&tmplregion.delarea.x2, &tmplregion.delarea.y2, 2248 DRY|WET); 2249 } 2250 lregions[(int)n] = tmplregion; 2251 } 2252 2253 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2254 /* Random objects */ 2255 if(n) { 2256 Fread((genericptr_t)robjects, sizeof(*robjects), (int) n, fd); 2257 sp_lev_shuffle(robjects, (char *)0, (int)n); 2258 } 2259 2260 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2261 /* Random locations */ 2262 if(n) { 2263 Fread((genericptr_t)rloc_x, sizeof(*rloc_x), (int) n, fd); 2264 Fread((genericptr_t)rloc_y, sizeof(*rloc_y), (int) n, fd); 2265 sp_lev_shuffle(rloc_x, rloc_y, (int)n); 2266 } 2267 2268 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2269 /* Random monsters */ 2270 if(n) { 2271 Fread((genericptr_t)rmonst, sizeof(*rmonst), (int) n, fd); 2272 sp_lev_shuffle(rmonst, (char *)0, (int)n); 2273 } 2274 2275 (void) memset((genericptr_t)mustfill, 0, sizeof(mustfill)); 2276 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2277 /* Number of subrooms */ 2278 while(n--) { 2279 register struct mkroom *troom; 2280 2281 Fread((genericptr_t)&tmpregion, 1, sizeof(tmpregion), fd); 2282 2283 if(tmpregion.rtype > MAXRTYPE) { 2284 tmpregion.rtype -= MAXRTYPE+1; 2285 prefilled = TRUE; 2286 } else 2287 prefilled = FALSE; 2288 2289 if(tmpregion.rlit < 0) 2290 tmpregion.rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) 2291 ? TRUE : FALSE; 2292 2293 get_location(&tmpregion.x1, &tmpregion.y1, DRY|WET); 2294 get_location(&tmpregion.x2, &tmpregion.y2, DRY|WET); 2295 2296 /* for an ordinary room, `prefilled' is a flag to force 2297 an actual room to be created (such rooms are used to 2298 control placement of migrating monster arrivals) */ 2299 room_not_needed = (tmpregion.rtype == OROOM && 2300 !tmpregion.rirreg && !prefilled); 2301 if (room_not_needed || nroom >= MAXNROFROOMS) { 2302 if (!room_not_needed) 2303 impossible("Too many rooms on new level!"); 2304 light_region(&tmpregion); 2305 continue; 2306 } 2307 2308 troom = &rooms[nroom]; 2309 2310 /* mark rooms that must be filled, but do it later */ 2311 if (tmpregion.rtype != OROOM) 2312 mustfill[nroom] = (prefilled ? 2 : 1); 2313 2314 if(tmpregion.rirreg) { 2315 min_rx = max_rx = tmpregion.x1; 2316 min_ry = max_ry = tmpregion.y1; 2317 flood_fill_rm(tmpregion.x1, tmpregion.y1, 2318 nroom+ROOMOFFSET, tmpregion.rlit, TRUE); 2319 add_room(min_rx, min_ry, max_rx, max_ry, 2320 FALSE, tmpregion.rtype, TRUE); 2321 troom->rlit = tmpregion.rlit; 2322 troom->irregular = TRUE; 2323 } else { 2324 add_room(tmpregion.x1, tmpregion.y1, 2325 tmpregion.x2, tmpregion.y2, 2326 tmpregion.rlit, tmpregion.rtype, TRUE); 2327#ifdef SPECIALIZATION 2328 topologize(troom,FALSE); /* set roomno */ 2329#else 2330 topologize(troom); /* set roomno */ 2331#endif 2332 } 2333 } 2334 2335 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2336 /* Number of doors */ 2337 while(n--) { 2338 struct mkroom *croom = &rooms[0]; 2339 2340 Fread((genericptr_t)&tmpdoor, 1, sizeof(tmpdoor), fd); 2341 2342 x = tmpdoor.x; y = tmpdoor.y; 2343 typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask; 2344 2345 get_location(&x, &y, DRY); 2346 if(levl[x][y].typ != SDOOR) 2347 levl[x][y].typ = DOOR; 2348 else { 2349 if(typ < D_CLOSED) 2350 typ = D_CLOSED; /* force it to be closed */ 2351 } 2352 levl[x][y].doormask = typ; 2353 2354 /* Now the complicated part, list it with each subroom */ 2355 /* The dog move and mail daemon routines use this */ 2356 while(croom->hx >= 0 && doorindex < DOORMAX) { 2357 if(croom->hx >= x-1 && croom->lx <= x+1 && 2358 croom->hy >= y-1 && croom->ly <= y+1) { 2359 /* Found it */ 2360 add_door(x, y, croom); 2361 } 2362 croom++; 2363 } 2364 } 2365 2366 /* now that we have rooms _and_ associated doors, fill the rooms */ 2367 for(n = 0; n < SIZE(mustfill); n++) 2368 if(mustfill[(int)n]) 2369 fill_room(&rooms[(int)n], (mustfill[(int)n] == 2)); 2370 2371 /* if special boundary syms (CROSSWALL) in map, remove them now */ 2372 if(has_bounds) { 2373 for(x = xstart; x < xstart+xsize; x++) 2374 for(y = ystart; y < ystart+ysize; y++) 2375 if(levl[x][y].typ == CROSSWALL) 2376 levl[x][y].typ = ROOM; 2377 } 2378 2379 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2380 /* Number of drawbridges */ 2381 while(n--) { 2382 Fread((genericptr_t)&tmpdb, 1, sizeof(tmpdb), fd); 2383 2384 x = tmpdb.x; y = tmpdb.y; 2385 get_location(&x, &y, DRY|WET); 2386 2387 if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.db_open)) 2388 impossible("Cannot create drawbridge."); 2389 } 2390 2391 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2392 /* Number of mazewalks */ 2393 while(n--) { 2394 Fread((genericptr_t)&tmpwalk, 1, sizeof(tmpwalk), fd); 2395 2396 get_location(&tmpwalk.x, &tmpwalk.y, DRY|WET); 2397 2398 walklist[nwalk++] = tmpwalk; 2399 } 2400 2401 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2402 /* Number of non_diggables */ 2403 while(n--) { 2404 Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd); 2405 2406 get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET); 2407 get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET); 2408 2409 set_wall_property(tmpdig.x1, tmpdig.y1, 2410 tmpdig.x2, tmpdig.y2, W_NONDIGGABLE); 2411 } 2412 2413 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2414 /* Number of non_passables */ 2415 while(n--) { 2416 Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd); 2417 2418 get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET); 2419 get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET); 2420 2421 set_wall_property(tmpdig.x1, tmpdig.y1, 2422 tmpdig.x2, tmpdig.y2, W_NONPASSWALL); 2423 } 2424 2425 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2426 /* Number of ladders */ 2427 while(n--) { 2428 Fread((genericptr_t)&tmplad, 1, sizeof(tmplad), fd); 2429 2430 x = tmplad.x; y = tmplad.y; 2431 get_location(&x, &y, DRY); 2432 2433 levl[x][y].typ = LADDER; 2434 if (tmplad.up == 1) { 2435 xupladder = x; yupladder = y; 2436 levl[x][y].ladder = LA_UP; 2437 } else { 2438 xdnladder = x; ydnladder = y; 2439 levl[x][y].ladder = LA_DOWN; 2440 } 2441 } 2442 2443 prevstair.x = prevstair.y = 0; 2444 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2445 /* Number of stairs */ 2446 while(n--) { 2447 Fread((genericptr_t)&tmpstair, 1, sizeof(tmpstair), fd); 2448 2449 xi = 0; 2450 do { 2451 x = tmpstair.x; y = tmpstair.y; 2452 get_location(&x, &y, DRY); 2453 } while(prevstair.x && xi++ < 100 && 2454 distmin(x,y,prevstair.x,prevstair.y) <= 8); 2455 if ((badtrap = t_at(x,y)) != 0) deltrap(badtrap); 2456 mkstairs(x, y, (char)tmpstair.up, (struct mkroom *)0); 2457 prevstair.x = x; 2458 prevstair.y = y; 2459 } 2460 2461 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2462 /* Number of altars */ 2463 while(n--) { 2464 Fread((genericptr_t)&tmpaltar, 1, sizeof(tmpaltar), fd); 2465 2466 create_altar(&tmpaltar, (struct mkroom *)0); 2467 } 2468 2469 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2470 /* Number of fountains */ 2471 while (n--) { 2472 Fread((genericptr_t)&tmpfountain, 1, sizeof(tmpfountain), fd); 2473 2474 create_feature(tmpfountain.x, tmpfountain.y, 2475 (struct mkroom *)0, FOUNTAIN); 2476 } 2477 2478 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2479 /* Number of traps */ 2480 while(n--) { 2481 Fread((genericptr_t)&tmptrap, 1, sizeof(tmptrap), fd); 2482 2483 create_trap(&tmptrap, (struct mkroom *)0); 2484 } 2485 2486 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2487 /* Number of monsters */ 2488 while(n--) { 2489 load_one_monster(fd, &tmpmons); 2490 2491 create_monster(&tmpmons, (struct mkroom *)0); 2492 } 2493 2494 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2495 /* Number of objects */ 2496 while(n--) { 2497 load_one_object(fd, &tmpobj); 2498 2499 create_object(&tmpobj, (struct mkroom *)0); 2500 } 2501 2502 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2503 /* Number of gold piles */ 2504 while (n--) { 2505 Fread((genericptr_t)&tmpgold, 1, sizeof(tmpgold), fd); 2506 2507 create_gold(&tmpgold, (struct mkroom *)0); 2508 } 2509 2510 Fread((genericptr_t) &n, 1, sizeof(n), fd); 2511 /* Number of engravings */ 2512 while(n--) { 2513 load_one_engraving(fd, &tmpengraving); 2514 2515 create_engraving(&tmpengraving, (struct mkroom *)0); 2516 } 2517 2518 } /* numpart loop */ 2519 2520 nwalk_sav = nwalk; 2521 while(nwalk--) { 2522 x = (xchar) walklist[nwalk].x; 2523 y = (xchar) walklist[nwalk].y; 2524 dir = walklist[nwalk].dir; 2525 2526 /* don't use move() - it doesn't use W_NORTH, etc. */ 2527 switch (dir) { 2528 case W_NORTH: --y; break; 2529 case W_SOUTH: y++; break; 2530 case W_EAST: x++; break; 2531 case W_WEST: --x; break; 2532 default: panic("load_maze: bad MAZEWALK direction"); 2533 } 2534 2535 if(!IS_DOOR(levl[x][y].typ)) { 2536#ifndef WALLIFIED_MAZE 2537 levl[x][y].typ = CORR; 2538#else 2539 levl[x][y].typ = ROOM; 2540#endif 2541 levl[x][y].flags = 0; 2542 } 2543 2544 /* 2545 * We must be sure that the parity of the coordinates for 2546 * walkfrom() is odd. But we must also take into account 2547 * what direction was chosen. 2548 */ 2549 if(!(x % 2)) { 2550 if (dir == W_EAST) 2551 x++; 2552 else 2553 x--; 2554 2555 /* no need for IS_DOOR check; out of map bounds */ 2556#ifndef WALLIFIED_MAZE 2557 levl[x][y].typ = CORR; 2558#else 2559 levl[x][y].typ = ROOM; 2560#endif 2561 levl[x][y].flags = 0; 2562 } 2563 2564 if (!(y % 2)) { 2565 if (dir == W_SOUTH) 2566 y++; 2567 else 2568 y--; 2569 } 2570 2571 walkfrom(x, y); 2572 } 2573 wallification(1, 0, COLNO-1, ROWNO-1); 2574 2575 /* 2576 * If there's a significant portion of maze unused by the special level, 2577 * we don't want it empty. 2578 * 2579 * Makes the number of traps, monsters, etc. proportional 2580 * to the size of the maze. 2581 */ 2582 mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2); 2583 2584 for(x = 2; x < x_maze_max; x++) 2585 for(y = 0; y < y_maze_max; y++) 2586 if(Map[x][y]) mapcount--; 2587 2588 if (nwalk_sav && (mapcount > (int) (mapcountmax / 10))) { 2589 mapfact = (int) ((mapcount * 100L) / mapcountmax); 2590 for(x = rnd((int) (20 * mapfact) / 100); x; x--) { 2591 maze1xy(&mm, DRY); 2592 (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS, 2593 mm.x, mm.y, TRUE); 2594 } 2595 for(x = rnd((int) (12 * mapfact) / 100); x; x--) { 2596 maze1xy(&mm, DRY); 2597 (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE); 2598 } 2599 for (x = rn2(2); x; x--) { 2600 maze1xy(&mm, DRY); 2601 (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS); 2602 } 2603 for(x = rnd((int) (12 * mapfact) / 100); x; x--) { 2604 maze1xy(&mm, WET|DRY); 2605 (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS); 2606 } 2607 for(x = rn2((int) (15 * mapfact) / 100); x; x--) { 2608 maze1xy(&mm, DRY); 2609 (void) mkgold(0L,mm.x,mm.y); 2610 } 2611 for(x = rn2((int) (15 * mapfact) / 100); x; x--) { 2612 int trytrap; 2613 2614 maze1xy(&mm, DRY); 2615 trytrap = rndtrap(); 2616 if (sobj_at(BOULDER, mm.x, mm.y)) 2617 while (trytrap == PIT || trytrap == SPIKED_PIT || 2618 trytrap == TRAPDOOR || trytrap == HOLE) 2619 trytrap = rndtrap(); 2620 (void) maketrap(mm.x, mm.y, trytrap); 2621 } 2622 } 2623 return TRUE; 2624} 2625 2626/* 2627 * General loader 2628 */ 2629 2630boolean 2631load_special(name) 2632const char *name; 2633{ 2634 dlb *fd; 2635 boolean result = FALSE; 2636 char c; 2637 struct version_info vers_info; 2638 2639 fd = dlb_fopen(name, RDBMODE); 2640 if (!fd) return FALSE; 2641 2642 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd); 2643 if (!check_version(&vers_info, name, TRUE)) 2644 goto give_up; 2645 2646 Fread((genericptr_t) &c, sizeof c, 1, fd); /* c Header */ 2647 2648 switch (c) { 2649 case SP_LEV_ROOMS: 2650 result = load_rooms(fd); 2651 break; 2652 case SP_LEV_MAZE: 2653 result = load_maze(fd); 2654 break; 2655 default: /* ??? */ 2656 result = FALSE; 2657 } 2658 give_up: 2659 (void)dlb_fclose(fd); 2660 return result; 2661} 2662 2663/*sp_lev.c*/ 2664