1/* SCCS Id: @(#)dungeon.c 3.4 1999/10/30 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5#include "hack.h" 6#include "dgn_file.h" 7#include "dlb.h" 8 9#ifdef OVL1 10 11#define DUNGEON_FILE "dungeon" 12 13#define X_START "x-strt" 14#define X_LOCATE "x-loca" 15#define X_GOAL "x-goal" 16 17struct proto_dungeon { 18 struct tmpdungeon tmpdungeon[MAXDUNGEON]; 19 struct tmplevel tmplevel[LEV_LIMIT]; 20 s_level *final_lev[LEV_LIMIT]; /* corresponding level pointers */ 21 struct tmpbranch tmpbranch[BRANCH_LIMIT]; 22 23 int start; /* starting index of current dungeon sp levels */ 24 int n_levs; /* number of tmplevel entries */ 25 int n_brs; /* number of tmpbranch entries */ 26}; 27 28int n_dgns; /* number of dungeons (used here, */ 29 /* and mklev.c) */ 30static branch *branches = (branch *) 0; /* dungeon branch list */ 31 32struct lchoice { 33 int idx; 34 schar lev[MAXLINFO]; 35 schar playerlev[MAXLINFO]; 36 xchar dgn[MAXLINFO]; 37 char menuletter; 38}; 39 40static void FDECL(Fread, (genericptr_t, int, int, dlb *)); 41STATIC_DCL xchar FDECL(dname_to_dnum, (const char *)); 42STATIC_DCL int FDECL(find_branch, (const char *, struct proto_dungeon *)); 43STATIC_DCL xchar FDECL(parent_dnum, (const char *, struct proto_dungeon *)); 44STATIC_DCL int FDECL(level_range, (XCHAR_P,int,int,int,struct proto_dungeon *,int *)); 45STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *)); 46STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *)); 47STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *)); 48STATIC_DCL void FDECL(add_level, (s_level *)); 49STATIC_DCL void FDECL(init_level, (int,int,struct proto_dungeon *)); 50STATIC_DCL int FDECL(possible_places, (int, boolean *, struct proto_dungeon *)); 51STATIC_DCL xchar FDECL(pick_level, (boolean *, int)); 52STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *)); 53#ifdef WIZARD 54STATIC_DCL const char *FDECL(br_string, (int)); 55STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P, struct lchoice *)); 56#endif 57 58#ifdef NETHACK_DEBUG 59#define DD dungeons[i] 60STATIC_DCL void NDECL(dumpit); 61 62STATIC_OVL void 63dumpit() 64{ 65 int i; 66 s_level *x; 67 branch *br; 68 69 for(i = 0; i < n_dgns; i++) { 70 fprintf(stderr, "\n#%d \"%s\" (%s):\n", i, 71 DD.dname, DD.proto); 72 fprintf(stderr, " num_dunlevs %d, dunlev_ureached %d\n", 73 DD.num_dunlevs, DD.dunlev_ureached); 74 fprintf(stderr, " depth_start %d, ledger_start %d\n", 75 DD.depth_start, DD.ledger_start); 76 fprintf(stderr, " flags:%s%s%s\n", 77 DD.flags.rogue_like ? " rogue_like" : "", 78 DD.flags.maze_like ? " maze_like" : "", 79 DD.flags.hellish ? " hellish" : ""); 80 getchar(); 81 } 82 fprintf(stderr,"\nSpecial levels:\n"); 83 for(x = sp_levchn; x; x = x->next) { 84 fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs); 85 fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel); 86 fprintf(stderr, "flags:%s%s%s%s\n", 87 x->flags.rogue_like ? " rogue_like" : "", 88 x->flags.maze_like ? " maze_like" : "", 89 x->flags.hellish ? " hellish" : "", 90 x->flags.town ? " town" : ""); 91 getchar(); 92 } 93 fprintf(stderr,"\nBranches:\n"); 94 for (br = branches; br; br = br->next) { 95 fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n", 96 br->id, 97 br->type == BR_STAIR ? "stair" : 98 br->type == BR_NO_END1 ? "no end1" : 99 br->type == BR_NO_END2 ? "no end2" : 100 br->type == BR_PORTAL ? "portal" : 101 "unknown", 102 br->end1.dnum, br->end1.dlevel, 103 br->end2.dnum, br->end2.dlevel, 104 br->end1_up ? "end1 up" : "end1 down"); 105 } 106 getchar(); 107 fprintf(stderr,"\nDone\n"); 108 getchar(); 109} 110#endif 111 112/* Save the dungeon structures. */ 113void 114save_dungeon(fd, perform_write, free_data) 115 int fd; 116 boolean perform_write, free_data; 117{ 118 branch *curr, *next; 119 int count; 120 121 if (perform_write) { 122 bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns); 123 bwrite(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns); 124 bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology); 125 bwrite(fd, (genericptr_t) tune, sizeof tune); 126 127 for (count = 0, curr = branches; curr; curr = curr->next) 128 count++; 129 bwrite(fd, (genericptr_t) &count, sizeof(count)); 130 131 for (curr = branches; curr; curr = curr->next) 132 bwrite(fd, (genericptr_t) curr, sizeof (branch)); 133 134 count = maxledgerno(); 135 bwrite(fd, (genericptr_t) &count, sizeof count); 136 bwrite(fd, (genericptr_t) level_info, 137 (unsigned)count * sizeof (struct linfo)); 138 bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos); 139 } 140 141 if (free_data) { 142 for (curr = branches; curr; curr = next) { 143 next = curr->next; 144 free((genericptr_t) curr); 145 } 146 branches = 0; 147 } 148} 149 150/* Restore the dungeon structures. */ 151void 152restore_dungeon(fd) 153 int fd; 154{ 155 branch *curr, *last; 156 int count, i; 157 158 mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns)); 159 mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns); 160 mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology); 161 mread(fd, (genericptr_t) tune, sizeof tune); 162 163 last = branches = (branch *) 0; 164 165 mread(fd, (genericptr_t) &count, sizeof(count)); 166 for (i = 0; i < count; i++) { 167 curr = (branch *) alloc(sizeof(branch)); 168 mread(fd, (genericptr_t) curr, sizeof(branch)); 169 curr->next = (branch *) 0; 170 if (last) 171 last->next = curr; 172 else 173 branches = curr; 174 last = curr; 175 } 176 177 mread(fd, (genericptr_t) &count, sizeof(count)); 178 if (count >= MAXLINFO) 179 panic("level information count larger (%d) than allocated size", count); 180 mread(fd, (genericptr_t) level_info, (unsigned)count*sizeof(struct linfo)); 181 mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos); 182} 183 184static void 185Fread(ptr, size, nitems, stream) 186 genericptr_t ptr; 187 int size, nitems; 188 dlb *stream; 189{ 190 int cnt; 191 192 if((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) { 193 panic( 194 "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.", 195 (size * nitems), (size * cnt)); 196 terminate(EXIT_FAILURE); 197 } 198} 199 200STATIC_OVL xchar 201dname_to_dnum(s) 202const char *s; 203{ 204 xchar i; 205 206 for (i = 0; i < n_dgns; i++) 207 if (!strcmp(dungeons[i].dname, s)) return i; 208 209 panic("Couldn't resolve dungeon number for name \"%s\".", s); 210 /*NOT REACHED*/ 211 return (xchar)0; 212} 213 214s_level * 215find_level(s) 216 const char *s; 217{ 218 s_level *curr; 219 for(curr = sp_levchn; curr; curr = curr->next) 220 if (!strcmpi(s, curr->proto)) break; 221 return curr; 222} 223 224/* Find the branch that links the named dungeon. */ 225STATIC_OVL int 226find_branch(s, pd) 227 const char *s; /* dungeon name */ 228 struct proto_dungeon *pd; 229{ 230 int i; 231 232 if (pd) { 233 for (i = 0; i < pd->n_brs; i++) 234 if (!strcmp(pd->tmpbranch[i].name, s)) break; 235 if (i == pd->n_brs) panic("find_branch: can't find %s", s); 236 } else { 237 /* support for level tport by name */ 238 branch *br; 239 const char *dnam; 240 241 for (br = branches; br; br = br->next) { 242 dnam = dungeons[br->end2.dnum].dname; 243 if (!strcmpi(dnam, s) || 244 (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s))) 245 break; 246 } 247 i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1; 248 } 249 return i; 250} 251 252 253/* 254 * Find the "parent" by searching the prototype branch list for the branch 255 * listing, then figuring out to which dungeon it belongs. 256 */ 257STATIC_OVL xchar 258parent_dnum(s, pd) 259const char *s; /* dungeon name */ 260struct proto_dungeon *pd; 261{ 262 int i; 263 xchar pdnum; 264 265 i = find_branch(s, pd); 266 /* 267 * Got branch, now find parent dungeon. Stop if we have reached 268 * "this" dungeon (if we haven't found it by now it is an error). 269 */ 270 for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++) 271 if ((i -= pd->tmpdungeon[pdnum].branches) < 0) 272 return(pdnum); 273 274 panic("parent_dnum: couldn't resolve branch."); 275 /*NOT REACHED*/ 276 return (xchar)0; 277} 278 279/* 280 * Return a starting point and number of successive positions a level 281 * or dungeon entrance can occupy. 282 * 283 * Note: This follows the acouple (instead of the rcouple) rules for a 284 * negative random component (rand < 0). These rules are found 285 * in dgn_comp.y. The acouple [absolute couple] section says that 286 * a negative random component means from the (adjusted) base to the 287 * end of the dungeon. 288 */ 289STATIC_OVL int 290level_range(dgn, base, rand, chain, pd, adjusted_base) 291 xchar dgn; 292 int base, rand, chain; 293 struct proto_dungeon *pd; 294 int *adjusted_base; 295{ 296 int lmax = dungeons[dgn].num_dunlevs; 297 298 if (chain >= 0) { /* relative to a special level */ 299 s_level *levtmp = pd->final_lev[chain]; 300 if (!levtmp) panic("level_range: empty chain level!"); 301 302 base += levtmp->dlevel.dlevel; 303 } else { /* absolute in the dungeon */ 304 /* from end of dungeon */ 305 if (base < 0) base = (lmax + base + 1); 306 } 307 308 if (base < 1 || base > lmax) 309 panic("level_range: base value out of range"); 310 311 *adjusted_base = base; 312 313 if (rand == -1) { /* from base to end of dungeon */ 314 return (lmax - base + 1); 315 } else if (rand) { 316 /* make sure we don't run off the end of the dungeon */ 317 return (((base + rand - 1) > lmax) ? lmax-base+1 : rand); 318 } /* else only one choice */ 319 return 1; 320} 321 322STATIC_OVL xchar 323parent_dlevel(s, pd) 324 const char *s; 325 struct proto_dungeon *pd; 326{ 327 int i, j, num, base, dnum = parent_dnum(s, pd); 328 branch *curr; 329 330 331 i = find_branch(s, pd); 332 num = level_range(dnum, pd->tmpbranch[i].lev.base, 333 pd->tmpbranch[i].lev.rand, 334 pd->tmpbranch[i].chain, 335 pd, &base); 336 337 /* KMH -- Try our best to find a level without an existing branch */ 338 i = j = rn2(num); 339 do { 340 if (++i >= num) i = 0; 341 for (curr = branches; curr; curr = curr->next) 342 if ((curr->end1.dnum == dnum && curr->end1.dlevel == base+i) || 343 (curr->end2.dnum == dnum && curr->end2.dlevel == base+i)) 344 break; 345 } while (curr && i != j); 346 return (base + i); 347} 348 349/* Convert from the temporary branch type to the dungeon branch type. */ 350STATIC_OVL int 351correct_branch_type(tbr) 352 struct tmpbranch *tbr; 353{ 354 switch (tbr->type) { 355 case TBR_STAIR: return BR_STAIR; 356 case TBR_NO_UP: return tbr->up ? BR_NO_END1 : BR_NO_END2; 357 case TBR_NO_DOWN: return tbr->up ? BR_NO_END2 : BR_NO_END1; 358 case TBR_PORTAL: return BR_PORTAL; 359 } 360 impossible("correct_branch_type: unknown branch type"); 361 return BR_STAIR; 362} 363 364/* 365 * Add the given branch to the branch list. The branch list is ordered 366 * by end1 dungeon and level followed by end2 dungeon and level. If 367 * extract_first is true, then the branch is already part of the list 368 * but needs to be repositioned. 369 */ 370void 371insert_branch(new_branch, extract_first) 372 branch *new_branch; 373 boolean extract_first; 374{ 375 branch *curr, *prev; 376 long new_val, curr_val, prev_val; 377 378 if (extract_first) { 379 for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next) 380 if (curr == new_branch) break; 381 382 if (!curr) panic("insert_branch: not found"); 383 if (prev) 384 prev->next = curr->next; 385 else 386 branches = curr->next; 387 } 388 new_branch->next = (branch *) 0; 389 390/* Convert the branch into a unique number so we can sort them. */ 391#define branch_val(bp) \ 392 ((((long)(bp)->end1.dnum * (MAXLEVEL+1) + \ 393 (long)(bp)->end1.dlevel) * (MAXDUNGEON+1) * (MAXLEVEL+1)) + \ 394 ((long)(bp)->end2.dnum * (MAXLEVEL+1) + (long)(bp)->end2.dlevel)) 395 396 /* 397 * Insert the new branch into the correct place in the branch list. 398 */ 399 prev = (branch *) 0; 400 prev_val = -1; 401 new_val = branch_val(new_branch); 402 for (curr = branches; curr; 403 prev_val = curr_val, prev = curr, curr = curr->next) { 404 curr_val = branch_val(curr); 405 if (prev_val < new_val && new_val <= curr_val) break; 406 } 407 if (prev) { 408 new_branch->next = curr; 409 prev->next = new_branch; 410 } else { 411 new_branch->next = branches; 412 branches = new_branch; 413 } 414} 415 416/* Add a dungeon branch to the branch list. */ 417STATIC_OVL branch * 418add_branch(dgn, child_entry_level, pd) 419 int dgn; 420 int child_entry_level; 421 struct proto_dungeon *pd; 422{ 423 static int branch_id = 0; 424 int branch_num; 425 branch *new_branch; 426 427 branch_num = find_branch(dungeons[dgn].dname,pd); 428 new_branch = (branch *) alloc(sizeof(branch)); 429 new_branch->next = (branch *) 0; 430 new_branch->id = branch_id++; 431 new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]); 432 new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd); 433 new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd); 434 new_branch->end2.dnum = dgn; 435 new_branch->end2.dlevel = child_entry_level; 436 new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE; 437 438 insert_branch(new_branch, FALSE); 439 return new_branch; 440} 441 442/* 443 * Add new level to special level chain. Insert it in level order with the 444 * other levels in this dungeon. This assumes that we are never given a 445 * level that has a dungeon number less than the dungeon number of the 446 * last entry. 447 */ 448STATIC_OVL void 449add_level(new_lev) 450 s_level *new_lev; 451{ 452 s_level *prev, *curr; 453 454 prev = (s_level *) 0; 455 for (curr = sp_levchn; curr; curr = curr->next) { 456 if (curr->dlevel.dnum == new_lev->dlevel.dnum && 457 curr->dlevel.dlevel > new_lev->dlevel.dlevel) 458 break; 459 prev = curr; 460 } 461 if (!prev) { 462 new_lev->next = sp_levchn; 463 sp_levchn = new_lev; 464 } else { 465 new_lev->next = curr; 466 prev->next = new_lev; 467 } 468} 469 470STATIC_OVL void 471init_level(dgn, proto_index, pd) 472 int dgn, proto_index; 473 struct proto_dungeon *pd; 474{ 475 s_level *new_level; 476 struct tmplevel *tlevel = &pd->tmplevel[proto_index]; 477 478 pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */ 479#ifdef WIZARD 480 if (!wizard) 481#endif 482 if (tlevel->chance <= rn2(100)) return; 483 484 pd->final_lev[proto_index] = new_level = 485 (s_level *) alloc(sizeof(s_level)); 486 /* load new level with data */ 487 Strcpy(new_level->proto, tlevel->name); 488 new_level->boneid = tlevel->boneschar; 489 new_level->dlevel.dnum = dgn; 490 new_level->dlevel.dlevel = 0; /* for now */ 491 492 new_level->flags.town = !!(tlevel->flags & TOWN); 493 new_level->flags.hellish = !!(tlevel->flags & HELLISH); 494 new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE); 495 new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE); 496 new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4); 497 if (!new_level->flags.align) 498 new_level->flags.align = 499 ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4); 500 501 new_level->rndlevs = tlevel->rndlevs; 502 new_level->next = (s_level *) 0; 503} 504 505STATIC_OVL int 506possible_places(idx, map, pd) 507 int idx; /* prototype index */ 508 boolean *map; /* array MAXLEVEL+1 in length */ 509 struct proto_dungeon *pd; 510{ 511 int i, start, count; 512 s_level *lev = pd->final_lev[idx]; 513 514 /* init level possibilities */ 515 for (i = 0; i <= MAXLEVEL; i++) map[i] = FALSE; 516 517 /* get base and range and set those entried to true */ 518 count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base, 519 pd->tmplevel[idx].lev.rand, 520 pd->tmplevel[idx].chain, 521 pd, &start); 522 for (i = start; i < start+count; i++) 523 map[i] = TRUE; 524 525 /* mark off already placed levels */ 526 for (i = pd->start; i < idx; i++) { 527 if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) { 528 map[pd->final_lev[i]->dlevel.dlevel] = FALSE; 529 --count; 530 } 531 } 532 533 return count; 534} 535 536/* Pick the nth TRUE entry in the given boolean array. */ 537STATIC_OVL xchar 538pick_level(map, nth) 539 boolean *map; /* an array MAXLEVEL+1 in size */ 540 int nth; 541{ 542 int i; 543 for (i = 1; i <= MAXLEVEL; i++) 544 if (map[i] && !nth--) return (xchar) i; 545 panic("pick_level: ran out of valid levels"); 546 return 0; 547} 548 549#ifdef DDEBUG 550static void FDECL(indent,(int)); 551 552static void 553indent(d) 554int d; 555{ 556 while (d-- > 0) fputs(" ", stderr); 557} 558#endif 559 560/* 561 * Place a level. First, find the possible places on a dungeon map 562 * template. Next pick one. Then try to place the next level. If 563 * sucessful, we're done. Otherwise, try another (and another) until 564 * all possible places have been tried. If all possible places have 565 * been exausted, return false. 566 */ 567STATIC_OVL boolean 568place_level(proto_index, pd) 569 int proto_index; 570 struct proto_dungeon *pd; 571{ 572 boolean map[MAXLEVEL+1]; /* valid levels are 1..MAXLEVEL inclusive */ 573 s_level *lev; 574 int npossible; 575#ifdef DDEBUG 576 int i; 577#endif 578 579 if (proto_index == pd->n_levs) return TRUE; /* at end of proto levels */ 580 581 lev = pd->final_lev[proto_index]; 582 583 /* No level created for this prototype, goto next. */ 584 if (!lev) return place_level(proto_index+1, pd); 585 586 npossible = possible_places(proto_index, map, pd); 587 588 for (; npossible; --npossible) { 589 lev->dlevel.dlevel = pick_level(map, rn2(npossible)); 590#ifdef DDEBUG 591 indent(proto_index-pd->start); 592 fprintf(stderr,"%s: trying %d [ ", lev->proto, lev->dlevel.dlevel); 593 for (i = 1; i <= MAXLEVEL; i++) 594 if (map[i]) fprintf(stderr,"%d ", i); 595 fprintf(stderr,"]\n"); 596#endif 597 if (place_level(proto_index+1, pd)) return TRUE; 598 map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */ 599 } 600#ifdef DDEBUG 601 indent(proto_index-pd->start); 602 fprintf(stderr,"%s: failed\n", lev->proto); 603#endif 604 return FALSE; 605} 606 607 608struct level_map { 609 const char *lev_name; 610 d_level *lev_spec; 611} level_map[] = { 612 { "air", &air_level }, 613 { "asmodeus", &asmodeus_level }, 614 { "astral", &astral_level }, 615 { "baalz", &baalzebub_level }, 616 { "bigroom", &bigroom_level }, 617 { "castle", &stronghold_level }, 618 { "earth", &earth_level }, 619 { "fakewiz1", &portal_level }, 620 { "fire", &fire_level }, 621 { "juiblex", &juiblex_level }, 622 { "knox", &knox_level }, 623 { "medusa", &medusa_level }, 624 { "oracle", &oracle_level }, 625 { "orcus", &orcus_level }, 626#ifdef REINCARNATION 627 { "rogue", &rogue_level }, 628#endif 629 { "sanctum", &sanctum_level }, 630 { "valley", &valley_level }, 631 { "water", &water_level }, 632 { "wizard1", &wiz1_level }, 633 { "wizard2", &wiz2_level }, 634 { "wizard3", &wiz3_level }, 635 { X_START, &qstart_level }, 636 { X_LOCATE, &qlocate_level }, 637 { X_GOAL, &nemesis_level }, 638 { "", (d_level *)0 } 639}; 640 641void 642init_dungeons() /* initialize the "dungeon" structs */ 643{ 644 dlb *dgn_file; 645 register int i, cl = 0, cb = 0; 646 register s_level *x; 647 struct proto_dungeon pd; 648 struct level_map *lev_map; 649 struct version_info vers_info; 650 651 pd.n_levs = pd.n_brs = 0; 652 653 dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE); 654 if (!dgn_file) { 655 char tbuf[BUFSZ]; 656 Sprintf(tbuf, "Cannot open dungeon description - \"%s", 657 DUNGEON_FILE); 658#ifdef DLBRSRC /* using a resource from the executable */ 659 Strcat(tbuf, "\" resource!"); 660#else /* using a file or DLB file */ 661# if defined(DLB) 662 Strcat(tbuf, "\" from "); 663# ifdef PREFIXES_IN_USE 664 Strcat(tbuf, "\n\""); 665 if (fqn_prefix[DATAPREFIX]) Strcat(tbuf, fqn_prefix[DATAPREFIX]); 666# else 667 Strcat(tbuf, "\""); 668# endif 669 Strcat(tbuf, DLBFILE); 670# endif 671 Strcat(tbuf, "\" file!"); 672#endif 673#ifdef WIN32 674 interject_assistance(1, INTERJECT_PANIC, (genericptr_t)tbuf, 675 (genericptr_t)fqn_prefix[DATAPREFIX]); 676#endif 677 panic(tbuf); 678 } 679 680 /* validate the data's version against the program's version */ 681 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file); 682 /* we'd better clear the screen now, since when error messages come from 683 * check_version() they will be printed using pline(), which doesn't 684 * mix with the raw messages that might be already on the screen 685 */ 686 if (iflags.window_inited) clear_nhwindow(WIN_MAP); 687 if (!check_version(&vers_info, DUNGEON_FILE, TRUE)) 688 panic("Dungeon description not valid."); 689 690 /* 691 * Read in each dungeon and transfer the results to the internal 692 * dungeon arrays. 693 */ 694 sp_levchn = (s_level *) 0; 695 Fread((genericptr_t)&n_dgns, sizeof(int), 1, dgn_file); 696 if (n_dgns >= MAXDUNGEON) 697 panic("init_dungeons: too many dungeons"); 698 699 for (i = 0; i < n_dgns; i++) { 700 Fread((genericptr_t)&pd.tmpdungeon[i], 701 sizeof(struct tmpdungeon), 1, dgn_file); 702#ifdef WIZARD 703 if(!wizard) 704#endif 705 if(pd.tmpdungeon[i].chance && (pd.tmpdungeon[i].chance <= rn2(100))) { 706 int j; 707 708 /* skip over any levels or branches */ 709 for(j = 0; j < pd.tmpdungeon[i].levels; j++) 710 Fread((genericptr_t)&pd.tmplevel[cl], sizeof(struct tmplevel), 711 1, dgn_file); 712 713 for(j = 0; j < pd.tmpdungeon[i].branches; j++) 714 Fread((genericptr_t)&pd.tmpbranch[cb], 715 sizeof(struct tmpbranch), 1, dgn_file); 716 n_dgns--; i--; 717 continue; 718 } 719 720 Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name); 721 Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname); 722 dungeons[i].boneid = pd.tmpdungeon[i].boneschar; 723 724 if(pd.tmpdungeon[i].lev.rand) 725 dungeons[i].num_dunlevs = (xchar)rn1(pd.tmpdungeon[i].lev.rand, 726 pd.tmpdungeon[i].lev.base); 727 else dungeons[i].num_dunlevs = (xchar)pd.tmpdungeon[i].lev.base; 728 729 if(!i) { 730 dungeons[i].ledger_start = 0; 731 dungeons[i].depth_start = 1; 732 dungeons[i].dunlev_ureached = 1; 733 } else { 734 dungeons[i].ledger_start = dungeons[i-1].ledger_start + 735 dungeons[i-1].num_dunlevs; 736 dungeons[i].dunlev_ureached = 0; 737 } 738 739 dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH); 740 dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE); 741 dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE); 742 dungeons[i].flags.align = ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4); 743 /* 744 * Set the entry level for this dungeon. The pd.tmpdungeon entry 745 * value means: 746 * < 0 from bottom (-1 == bottom level) 747 * 0 default (top) 748 * > 0 actual level (1 = top) 749 * 750 * Note that the entry_lev field in the dungeon structure is 751 * redundant. It is used only here and in print_dungeon(). 752 */ 753 if (pd.tmpdungeon[i].entry_lev < 0) { 754 dungeons[i].entry_lev = dungeons[i].num_dunlevs + 755 pd.tmpdungeon[i].entry_lev + 1; 756 if (dungeons[i].entry_lev <= 0) dungeons[i].entry_lev = 1; 757 } else if (pd.tmpdungeon[i].entry_lev > 0) { 758 dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev; 759 if (dungeons[i].entry_lev > dungeons[i].num_dunlevs) 760 dungeons[i].entry_lev = dungeons[i].num_dunlevs; 761 } else { /* default */ 762 dungeons[i].entry_lev = 1; /* defaults to top level */ 763 } 764 765 if (i) { /* set depth */ 766 branch *br; 767 schar from_depth; 768 boolean from_up; 769 770 br = add_branch(i, dungeons[i].entry_lev, &pd); 771 772 /* Get the depth of the connecting end. */ 773 if (br->end1.dnum == i) { 774 from_depth = depth(&br->end2); 775 from_up = !br->end1_up; 776 } else { 777 from_depth = depth(&br->end1); 778 from_up = br->end1_up; 779 } 780 781 /* 782 * Calculate the depth of the top of the dungeon via 783 * its branch. First, the depth of the entry point: 784 * 785 * depth of branch from "parent" dungeon 786 * + -1 or 1 depending on a up or down stair or 787 * 0 if portal 788 * 789 * Followed by the depth of the top of the dungeon: 790 * 791 * - (entry depth - 1) 792 * 793 * We'll say that portals stay on the same depth. 794 */ 795 dungeons[i].depth_start = from_depth 796 + (br->type == BR_PORTAL ? 0 : 797 (from_up ? -1 : 1)) 798 - (dungeons[i].entry_lev - 1); 799 } 800 801 /* this is redundant - it should have been flagged by dgn_comp */ 802 if(dungeons[i].num_dunlevs > MAXLEVEL) 803 dungeons[i].num_dunlevs = MAXLEVEL; 804 805 pd.start = pd.n_levs; /* save starting point */ 806 pd.n_levs += pd.tmpdungeon[i].levels; 807 if (pd.n_levs > LEV_LIMIT) 808 panic("init_dungeon: too many special levels"); 809 /* 810 * Read in the prototype special levels. Don't add generated 811 * special levels until they are all placed. 812 */ 813 for(; cl < pd.n_levs; cl++) { 814 Fread((genericptr_t)&pd.tmplevel[cl], 815 sizeof(struct tmplevel), 1, dgn_file); 816 init_level(i, cl, &pd); 817 } 818 /* 819 * Recursively place the generated levels for this dungeon. This 820 * routine will attempt all possible combinations before giving 821 * up. 822 */ 823 if (!place_level(pd.start, &pd)) 824 panic("init_dungeon: couldn't place levels"); 825#ifdef DDEBUG 826 fprintf(stderr, "--- end of dungeon %d ---\n", i); 827 fflush(stderr); 828 getchar(); 829#endif 830 for (; pd.start < pd.n_levs; pd.start++) 831 if (pd.final_lev[pd.start]) add_level(pd.final_lev[pd.start]); 832 833 834 pd.n_brs += pd.tmpdungeon[i].branches; 835 if (pd.n_brs > BRANCH_LIMIT) 836 panic("init_dungeon: too many branches"); 837 for(; cb < pd.n_brs; cb++) 838 Fread((genericptr_t)&pd.tmpbranch[cb], 839 sizeof(struct tmpbranch), 1, dgn_file); 840 } 841 (void) dlb_fclose(dgn_file); 842 843 for (i = 0; i < 5; i++) tune[i] = 'A' + rn2(7); 844 tune[5] = 0; 845 846 /* 847 * Find most of the special levels and dungeons so we can access their 848 * locations quickly. 849 */ 850 for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) { 851 x = find_level(lev_map->lev_name); 852 if (x) { 853 assign_level(lev_map->lev_spec, &x->dlevel); 854 if (!strncmp(lev_map->lev_name, "x-", 2)) { 855 /* This is where the name substitution on the 856 * levels of the quest dungeon occur. 857 */ 858 Sprintf(x->proto, "%s%s", urole.filecode, &lev_map->lev_name[1]); 859 } else if (lev_map->lev_spec == &knox_level) { 860 branch *br; 861 /* 862 * Kludge to allow floating Knox entrance. We 863 * specify a floating entrance by the fact that 864 * its entrance (end1) has a bogus dnum, namely 865 * n_dgns. 866 */ 867 for (br = branches; br; br = br->next) 868 if (on_level(&br->end2, &knox_level)) break; 869 870 if (br) br->end1.dnum = n_dgns; 871 /* adjust the branch's position on the list */ 872 insert_branch(br, TRUE); 873 } 874 } 875 } 876/* 877 * I hate hardwiring these names. :-( 878 */ 879 quest_dnum = dname_to_dnum("The Quest"); 880 sokoban_dnum = dname_to_dnum("Sokoban"); 881 mines_dnum = dname_to_dnum("The Gnomish Mines"); 882 tower_dnum = dname_to_dnum("Vlad's Tower"); 883 884 /* one special fixup for dummy surface level */ 885 if ((x = find_level("dummy")) != 0) { 886 i = x->dlevel.dnum; 887 /* the code above puts earth one level above dungeon level #1, 888 making the dummy level overlay level 1; but the whole reason 889 for having the dummy level is to make earth have depth -1 890 instead of 0, so adjust the start point to shift endgame up */ 891 if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start) 892 dungeons[i].depth_start -= 1; 893 /* TO DO: strip "dummy" out all the way here, 894 so that it's hidden from <ctrl/O> feedback. */ 895 } 896 897#ifdef NETHACK_DEBUG 898 dumpit(); 899#endif 900} 901 902xchar 903dunlev(lev) /* return the level number for lev in *this* dungeon */ 904d_level *lev; 905{ 906 return(lev->dlevel); 907} 908 909xchar 910dunlevs_in_dungeon(lev) /* return the lowest level number for *this* dungeon*/ 911d_level *lev; 912{ 913 return(dungeons[lev->dnum].num_dunlevs); 914} 915 916xchar 917deepest_lev_reached(noquest) /* return the lowest level explored in the game*/ 918boolean noquest; 919{ 920 /* this function is used for three purposes: to provide a factor 921 * of difficulty in monster generation; to provide a factor of 922 * difficulty in experience calculations (botl.c and end.c); and 923 * to insert the deepest level reached in the game in the topten 924 * display. the 'noquest' arg switch is required for the latter. 925 * 926 * from the player's point of view, going into the Quest is _not_ 927 * going deeper into the dungeon -- it is going back "home", where 928 * the dungeon starts at level 1. given the setup in dungeon.def, 929 * the depth of the Quest (thought of as starting at level 1) is 930 * never lower than the level of entry into the Quest, so we exclude 931 * the Quest from the topten "deepest level reached" display 932 * calculation. _However_ the Quest is a difficult dungeon, so we 933 * include it in the factor of difficulty calculations. 934 */ 935 register int i; 936 d_level tmp; 937 register schar ret = 0; 938 939 for(i = 0; i < n_dgns; i++) { 940 if((tmp.dlevel = dungeons[i].dunlev_ureached) == 0) continue; 941 if(!strcmp(dungeons[i].dname, "The Quest") && noquest) continue; 942 943 tmp.dnum = i; 944 if(depth(&tmp) > ret) ret = depth(&tmp); 945 } 946 return((xchar) ret); 947} 948 949/* return a bookkeeping level number for purpose of comparisons and 950 * save/restore */ 951xchar 952ledger_no(lev) 953d_level *lev; 954{ 955 return((xchar)(lev->dlevel + dungeons[lev->dnum].ledger_start)); 956} 957 958/* 959 * The last level in the bookkeeping list of level is the bottom of the last 960 * dungeon in the dungeons[] array. 961 * 962 * Maxledgerno() -- which is the max number of levels in the bookkeeping 963 * list, should not be confused with dunlevs_in_dungeon(lev) -- which 964 * returns the max number of levels in lev's dungeon, and both should 965 * not be confused with deepest_lev_reached() -- which returns the lowest 966 * depth visited by the player. 967 */ 968xchar 969maxledgerno() 970{ 971 return (xchar) (dungeons[n_dgns-1].ledger_start + 972 dungeons[n_dgns-1].num_dunlevs); 973} 974 975/* return the dungeon that this ledgerno exists in */ 976xchar 977ledger_to_dnum(ledgerno) 978xchar ledgerno; 979{ 980 register int i; 981 982 /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */ 983 for (i = 0; i < n_dgns; i++) 984 if (dungeons[i].ledger_start < ledgerno && 985 ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs) 986 return (xchar)i; 987 988 panic("level number out of range [ledger_to_dnum(%d)]", (int)ledgerno); 989 /*NOT REACHED*/ 990 return (xchar)0; 991} 992 993/* return the level of the dungeon this ledgerno exists in */ 994xchar 995ledger_to_dlev(ledgerno) 996xchar ledgerno; 997{ 998 return((xchar)(ledgerno - dungeons[ledger_to_dnum(ledgerno)].ledger_start)); 999} 1000 1001#endif /* OVL1 */ 1002#ifdef OVL0 1003 1004/* returns the depth of a level, in floors below the surface */ 1005/* (note levels in different dungeons can have the same depth). */ 1006schar 1007depth(lev) 1008d_level *lev; 1009{ 1010 return((schar)( dungeons[lev->dnum].depth_start + lev->dlevel - 1)); 1011} 1012 1013boolean 1014on_level(lev1, lev2) /* are "lev1" and "lev2" actually the same? */ 1015d_level *lev1, *lev2; 1016{ 1017 return((boolean)((lev1->dnum == lev2->dnum) && (lev1->dlevel == lev2->dlevel))); 1018} 1019 1020#endif /* OVL0 */ 1021#ifdef OVL1 1022 1023/* is this level referenced in the special level chain? */ 1024s_level * 1025Is_special(lev) 1026d_level *lev; 1027{ 1028 s_level *levtmp; 1029 1030 for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next) 1031 if (on_level(lev, &levtmp->dlevel)) return(levtmp); 1032 1033 return((s_level *)0); 1034} 1035 1036/* 1037 * Is this a multi-dungeon branch level? If so, return a pointer to the 1038 * branch. Otherwise, return null. 1039 */ 1040branch * 1041Is_branchlev(lev) 1042 d_level *lev; 1043{ 1044 branch *curr; 1045 1046 for (curr = branches; curr; curr = curr->next) { 1047 if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2)) 1048 return curr; 1049 } 1050 return (branch *) 0; 1051} 1052 1053/* goto the next level (or appropriate dungeon) */ 1054void 1055next_level(at_stairs) 1056boolean at_stairs; 1057{ 1058 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) { 1059 /* Taking a down dungeon branch. */ 1060 goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE); 1061 } else { 1062 /* Going down a stairs or jump in a trap door. */ 1063 d_level newlevel; 1064 1065 newlevel.dnum = u.uz.dnum; 1066 newlevel.dlevel = u.uz.dlevel + 1; 1067 goto_level(&newlevel, at_stairs, !at_stairs, FALSE); 1068 } 1069} 1070 1071/* goto the previous level (or appropriate dungeon) */ 1072void 1073prev_level(at_stairs) 1074boolean at_stairs; 1075{ 1076 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) { 1077 /* Taking an up dungeon branch. */ 1078 /* KMH -- Upwards branches are okay if not level 1 */ 1079 /* (Just make sure it doesn't go above depth 1) */ 1080 if(!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet) done(ESCAPED); 1081 else goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE); 1082 } else { 1083 /* Going up a stairs or rising through the ceiling. */ 1084 d_level newlevel; 1085 newlevel.dnum = u.uz.dnum; 1086 newlevel.dlevel = u.uz.dlevel - 1; 1087 goto_level(&newlevel, at_stairs, FALSE, FALSE); 1088 } 1089} 1090 1091void 1092u_on_newpos(x, y) 1093int x, y; 1094{ 1095 u.ux = x; 1096 u.uy = y; 1097#ifdef CLIPPING 1098 cliparound(u.ux, u.uy); 1099#endif 1100#ifdef STEED 1101 /* ridden steed always shares hero's location */ 1102 if (u.usteed) u.usteed->mx = u.ux, u.usteed->my = u.uy; 1103#endif 1104} 1105 1106void 1107u_on_sstairs() { /* place you on the special staircase */ 1108 1109 if (sstairs.sx) { 1110 u_on_newpos(sstairs.sx, sstairs.sy); 1111 } else { 1112 /* code stolen from goto_level */ 1113 int trycnt = 0; 1114 xchar x, y; 1115#ifdef NETHACK_DEBUG 1116 pline("u_on_sstairs: picking random spot"); 1117#endif 1118#define badspot(x,y) ((levl[x][y].typ != ROOM && levl[x][y].typ != CORR) || MON_AT(x, y)) 1119 do { 1120 x = rnd(COLNO-1); 1121 y = rn2(ROWNO); 1122 if (!badspot(x, y)) { 1123 u_on_newpos(x, y); 1124 return; 1125 } 1126 } while (++trycnt <= 500); 1127 panic("u_on_sstairs: could not relocate player!"); 1128#undef badspot 1129 } 1130} 1131 1132void 1133u_on_upstairs() /* place you on upstairs (or special equivalent) */ 1134{ 1135 if (xupstair) { 1136 u_on_newpos(xupstair, yupstair); 1137 } else 1138 u_on_sstairs(); 1139} 1140 1141void 1142u_on_dnstairs() /* place you on dnstairs (or special equivalent) */ 1143{ 1144 if (xdnstair) { 1145 u_on_newpos(xdnstair, ydnstair); 1146 } else 1147 u_on_sstairs(); 1148} 1149 1150boolean 1151On_stairs(x, y) 1152xchar x, y; 1153{ 1154 return((boolean)((x == xupstair && y == yupstair) || 1155 (x == xdnstair && y == ydnstair) || 1156 (x == xdnladder && y == ydnladder) || 1157 (x == xupladder && y == yupladder) || 1158 (x == sstairs.sx && y == sstairs.sy))); 1159} 1160 1161boolean 1162Is_botlevel(lev) 1163d_level *lev; 1164{ 1165 return((boolean)(lev->dlevel == dungeons[lev->dnum].num_dunlevs)); 1166} 1167 1168boolean 1169Can_dig_down(lev) 1170d_level *lev; 1171{ 1172 return((boolean)(!level.flags.hardfloor 1173 && !Is_botlevel(lev) && !Invocation_lev(lev))); 1174} 1175 1176/* 1177 * Like Can_dig_down (above), but also allows falling through on the 1178 * stronghold level. Normally, the bottom level of a dungeon resists 1179 * both digging and falling. 1180 */ 1181boolean 1182Can_fall_thru(lev) 1183d_level *lev; 1184{ 1185 return((boolean)(Can_dig_down(lev) || Is_stronghold(lev))); 1186} 1187 1188/* 1189 * True if one can rise up a level (e.g. cursed gain level). 1190 * This happens on intermediate dungeon levels or on any top dungeon 1191 * level that has a stairwell style branch to the next higher dungeon. 1192 * Checks for amulets and such must be done elsewhere. 1193 */ 1194boolean 1195Can_rise_up(x, y, lev) 1196int x, y; 1197d_level *lev; 1198{ 1199 /* can't rise up from inside the top of the Wizard's tower */ 1200 /* KMH -- or in sokoban */ 1201 if (In_endgame(lev) || In_sokoban(lev) || 1202 (Is_wiz1_level(lev) && In_W_tower(x, y, lev))) 1203 return FALSE; 1204 return (boolean)(lev->dlevel > 1 || 1205 (dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 && 1206 sstairs.sx && sstairs.up)); 1207} 1208 1209/* 1210 * It is expected that the second argument of get_level is a depth value, 1211 * either supplied by the user (teleport control) or randomly generated. 1212 * But more than one level can be at the same depth. If the target level 1213 * is "above" the present depth location, get_level must trace "up" from 1214 * the player's location (through the ancestors dungeons) the dungeon 1215 * within which the target level is located. With only one exception 1216 * which does not pass through this routine (see level_tele), teleporting 1217 * "down" is confined to the current dungeon. At present, level teleport 1218 * in dungeons that build up is confined within them. 1219 */ 1220void 1221get_level(newlevel, levnum) 1222d_level *newlevel; 1223int levnum; 1224{ 1225 branch *br; 1226 xchar dgn = u.uz.dnum; 1227 1228 if (levnum <= 0) { 1229 /* can only currently happen in endgame */ 1230 levnum = u.uz.dlevel; 1231 } else if (levnum > dungeons[dgn].depth_start 1232 + dungeons[dgn].num_dunlevs - 1) { 1233 /* beyond end of dungeon, jump to last level */ 1234 levnum = dungeons[dgn].num_dunlevs; 1235 } else { 1236 /* The desired level is in this dungeon or a "higher" one. */ 1237 1238 /* 1239 * Branch up the tree until we reach a dungeon that contains the 1240 * levnum. 1241 */ 1242 if (levnum < dungeons[dgn].depth_start) { 1243 1244 do { 1245 /* 1246 * Find the parent dungeon of this dungeon. 1247 * 1248 * This assumes that end2 is always the "child" and it is 1249 * unique. 1250 */ 1251 for (br = branches; br; br = br->next) 1252 if (br->end2.dnum == dgn) break; 1253 if (!br) 1254 panic("get_level: can't find parent dungeon"); 1255 1256 dgn = br->end1.dnum; 1257 } while (levnum < dungeons[dgn].depth_start); 1258 } 1259 1260 /* We're within the same dungeon; calculate the level. */ 1261 levnum = levnum - dungeons[dgn].depth_start + 1; 1262 } 1263 1264 newlevel->dnum = dgn; 1265 newlevel->dlevel = levnum; 1266} 1267 1268#endif /* OVL1 */ 1269#ifdef OVL0 1270 1271boolean 1272In_quest(lev) /* are you in the quest dungeon? */ 1273d_level *lev; 1274{ 1275 return((boolean)(lev->dnum == quest_dnum)); 1276} 1277 1278#endif /* OVL0 */ 1279#ifdef OVL1 1280 1281boolean 1282In_mines(lev) /* are you in the mines dungeon? */ 1283d_level *lev; 1284{ 1285 return((boolean)(lev->dnum == mines_dnum)); 1286} 1287 1288/* 1289 * Return the branch for the given dungeon. 1290 * 1291 * This function assumes: 1292 * + This is not called with "Dungeons of Doom". 1293 * + There is only _one_ branch to a given dungeon. 1294 * + Field end2 is the "child" dungeon. 1295 */ 1296branch * 1297dungeon_branch(s) 1298 const char *s; 1299{ 1300 branch *br; 1301 xchar dnum; 1302 1303 dnum = dname_to_dnum(s); 1304 1305 /* Find the branch that connects to dungeon i's branch. */ 1306 for (br = branches; br; br = br->next) 1307 if (br->end2.dnum == dnum) break; 1308 1309 if (!br) panic("dgn_entrance: can't find entrance to %s", s); 1310 1311 return br; 1312} 1313 1314/* 1315 * This returns true if the hero is on the same level as the entrance to 1316 * the named dungeon. 1317 * 1318 * Called from do.c and mklev.c. 1319 * 1320 * Assumes that end1 is always the "parent". 1321 */ 1322boolean 1323at_dgn_entrance(s) 1324 const char *s; 1325{ 1326 branch *br; 1327 1328 br = dungeon_branch(s); 1329 return((boolean)(on_level(&u.uz, &br->end1) ? TRUE : FALSE)); 1330} 1331 1332boolean 1333In_V_tower(lev) /* is `lev' part of Vlad's tower? */ 1334d_level *lev; 1335{ 1336 return((boolean)(lev->dnum == tower_dnum)); 1337} 1338 1339boolean 1340On_W_tower_level(lev) /* is `lev' a level containing the Wizard's tower? */ 1341d_level *lev; 1342{ 1343 return (boolean)(Is_wiz1_level(lev) || 1344 Is_wiz2_level(lev) || 1345 Is_wiz3_level(lev)); 1346} 1347 1348boolean 1349In_W_tower(x, y, lev) /* is <x,y> of `lev' inside the Wizard's tower? */ 1350int x, y; 1351d_level *lev; 1352{ 1353 if (!On_W_tower_level(lev)) return FALSE; 1354 /* 1355 * Both of the exclusion regions for arriving via level teleport 1356 * (from above or below) define the tower's boundary. 1357 * assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} ); 1358 */ 1359 if (dndest.nlx > 0) 1360 return (boolean)within_bounded_area(x, y, dndest.nlx, dndest.nly, 1361 dndest.nhx, dndest.nhy); 1362 else 1363 impossible("No boundary for Wizard's Tower?"); 1364 return FALSE; 1365} 1366 1367#endif /* OVL1 */ 1368#ifdef OVL0 1369 1370boolean 1371In_hell(lev) /* are you in one of the Hell levels? */ 1372d_level *lev; 1373{ 1374 return((boolean)(dungeons[lev->dnum].flags.hellish)); 1375} 1376 1377#endif /* OVL0 */ 1378#ifdef OVL1 1379 1380void 1381find_hell(lev) /* sets *lev to be the gateway to Gehennom... */ 1382d_level *lev; 1383{ 1384 lev->dnum = valley_level.dnum; 1385 lev->dlevel = 1; 1386} 1387 1388void 1389goto_hell(at_stairs, falling) /* go directly to hell... */ 1390boolean at_stairs, falling; 1391{ 1392 d_level lev; 1393 1394 find_hell(&lev); 1395 goto_level(&lev, at_stairs, falling, FALSE); 1396} 1397 1398void 1399assign_level(dest, src) /* equivalent to dest = source */ 1400d_level *dest, *src; 1401{ 1402 dest->dnum = src->dnum; 1403 dest->dlevel = src->dlevel; 1404} 1405 1406void 1407assign_rnd_level(dest, src, range) /* dest = src + rn1(range) */ 1408d_level *dest, *src; 1409int range; 1410{ 1411 dest->dnum = src->dnum; 1412 dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range)) ; 1413 1414 if(dest->dlevel > dunlevs_in_dungeon(dest)) 1415 dest->dlevel = dunlevs_in_dungeon(dest); 1416 else if(dest->dlevel < 1) 1417 dest->dlevel = 1; 1418} 1419 1420#endif /* OVL1 */ 1421#ifdef OVL0 1422 1423int 1424induced_align(pct) 1425int pct; 1426{ 1427 s_level *lev = Is_special(&u.uz); 1428 aligntyp al; 1429 1430 if (lev && lev->flags.align) 1431 if(rn2(100) < pct) return(lev->flags.align); 1432 1433 if(dungeons[u.uz.dnum].flags.align) 1434 if(rn2(100) < pct) return(dungeons[u.uz.dnum].flags.align); 1435 1436 al = rn2(3) - 1; 1437 return(Align2amask(al)); 1438} 1439 1440#endif /* OVL0 */ 1441#ifdef OVL1 1442 1443boolean 1444Invocation_lev(lev) 1445d_level *lev; 1446{ 1447 return((boolean)(In_hell(lev) && 1448 lev->dlevel == (dungeons[lev->dnum].num_dunlevs - 1))); 1449} 1450 1451/* use instead of depth() wherever a degree of difficulty is made 1452 * dependent on the location in the dungeon (eg. monster creation). 1453 */ 1454xchar 1455level_difficulty() 1456{ 1457 if (In_endgame(&u.uz)) 1458 return((xchar)(depth(&sanctum_level) + u.ulevel/2)); 1459 else 1460 if (u.uhave.amulet) 1461 return(deepest_lev_reached(FALSE)); 1462 else 1463 return((xchar) depth(&u.uz)); 1464} 1465 1466/* Take one word and try to match it to a level. 1467 * Recognized levels are as shown by print_dungeon(). 1468 */ 1469schar 1470lev_by_name(nam) 1471const char *nam; 1472{ 1473 schar lev = 0; 1474 s_level *slev; 1475 d_level dlev; 1476 const char *p; 1477 int idx, idxtoo; 1478 char buf[BUFSZ]; 1479 1480 /* allow strings like "the oracle level" to find "oracle" */ 1481 if (!strncmpi(nam, "the ", 4)) nam += 4; 1482 if ((p = strstri(nam, " level")) != 0 && p == eos((char*)nam) - 6) { 1483 nam = strcpy(buf, nam); 1484 *(eos(buf) - 6) = '\0'; 1485 } 1486 /* hell is the old name, and wouldn't match; gehennom would match its 1487 branch, yielding the castle level instead of the valley of the dead */ 1488 if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) { 1489 if (In_V_tower(&u.uz)) nam = " to Vlad's tower"; /* branch to... */ 1490 else nam = "valley"; 1491 } 1492 1493 if ((slev = find_level(nam)) != 0) { 1494 dlev = slev->dlevel; 1495 idx = ledger_no(&dlev); 1496 if ((dlev.dnum == u.uz.dnum || 1497 /* within same branch, or else main dungeon <-> gehennom */ 1498 (u.uz.dnum == valley_level.dnum && 1499 dlev.dnum == medusa_level.dnum) || 1500 (u.uz.dnum == medusa_level.dnum && 1501 dlev.dnum == valley_level.dnum)) && 1502 ( /* either wizard mode or else seen and not forgotten */ 1503#ifdef WIZARD 1504 wizard || 1505#endif 1506 (level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED)) { 1507 lev = depth(&slev->dlevel); 1508 } 1509 } else { /* not a specific level; try branch names */ 1510 idx = find_branch(nam, (struct proto_dungeon *)0); 1511 /* "<branch> to Xyzzy" */ 1512 if (idx < 0 && (p = strstri(nam, " to ")) != 0) 1513 idx = find_branch(p + 4, (struct proto_dungeon *)0); 1514 1515 if (idx >= 0) { 1516 idxtoo = (idx >> 8) & 0x00FF; 1517 idx &= 0x00FF; 1518 if ( /* either wizard mode, or else _both_ sides of branch seen */ 1519#ifdef WIZARD 1520 wizard || 1521#endif 1522 ((level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED && 1523 (level_info[idxtoo].flags & (FORGOTTEN|VISITED)) == VISITED)) { 1524 if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo; 1525 dlev.dnum = ledger_to_dnum(idx); 1526 dlev.dlevel = ledger_to_dlev(idx); 1527 lev = depth(&dlev); 1528 } 1529 } 1530 } 1531 return lev; 1532} 1533 1534#ifdef WIZARD 1535 1536/* Convert a branch type to a string usable by print_dungeon(). */ 1537STATIC_OVL const char * 1538br_string(type) 1539 int type; 1540{ 1541 switch (type) { 1542 case BR_PORTAL: return "Portal"; 1543 case BR_NO_END1: return "Connection"; 1544 case BR_NO_END2: return "One way stair"; 1545 case BR_STAIR: return "Stair"; 1546 } 1547 return " (unknown)"; 1548} 1549 1550/* Print all child branches between the lower and upper bounds. */ 1551STATIC_OVL void 1552print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices) 1553 winid win; 1554 int dnum; 1555 int lower_bound; 1556 int upper_bound; 1557 boolean bymenu; 1558 struct lchoice *lchoices; 1559{ 1560 branch *br; 1561 char buf[BUFSZ]; 1562 anything any; 1563 1564 /* This assumes that end1 is the "parent". */ 1565 for (br = branches; br; br = br->next) { 1566 if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel && 1567 br->end1.dlevel <= upper_bound) { 1568 Sprintf(buf," %s to %s: %d", 1569 br_string(br->type), 1570 dungeons[br->end2.dnum].dname, 1571 depth(&br->end1)); 1572 if (bymenu) { 1573 lchoices->lev[lchoices->idx] = br->end1.dlevel; 1574 lchoices->dgn[lchoices->idx] = br->end1.dnum; 1575 lchoices->playerlev[lchoices->idx] = depth(&br->end1); 1576 any.a_void = 0; 1577 any.a_int = lchoices->idx + 1; 1578 add_menu(win, NO_GLYPH, &any, lchoices->menuletter, 1579 0, ATR_NONE, buf, MENU_UNSELECTED); 1580 if (lchoices->menuletter == 'z') lchoices->menuletter = 'A'; 1581 else lchoices->menuletter++; 1582 lchoices->idx++; 1583 } else 1584 putstr(win, 0, buf); 1585 } 1586 } 1587} 1588 1589/* Print available dungeon information. */ 1590schar 1591print_dungeon(bymenu, rlev, rdgn) 1592boolean bymenu; 1593schar *rlev; 1594xchar *rdgn; 1595{ 1596 int i, last_level, nlev; 1597 char buf[BUFSZ]; 1598 boolean first; 1599 s_level *slev; 1600 dungeon *dptr; 1601 branch *br; 1602 anything any; 1603 struct lchoice lchoices; 1604 1605 winid win = create_nhwindow(NHW_MENU); 1606 if (bymenu) { 1607 start_menu(win); 1608 lchoices.idx = 0; 1609 lchoices.menuletter = 'a'; 1610 } 1611 1612 for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) { 1613 nlev = dptr->num_dunlevs; 1614 if (nlev > 1) 1615 Sprintf(buf, "%s: levels %d to %d", dptr->dname, dptr->depth_start, 1616 dptr->depth_start + nlev - 1); 1617 else 1618 Sprintf(buf, "%s: level %d", dptr->dname, dptr->depth_start); 1619 1620 /* Most entrances are uninteresting. */ 1621 if (dptr->entry_lev != 1) { 1622 if (dptr->entry_lev == nlev) 1623 Strcat(buf, ", entrance from below"); 1624 else 1625 Sprintf(eos(buf), ", entrance on %d", 1626 dptr->depth_start + dptr->entry_lev - 1); 1627 } 1628 if (bymenu) { 1629 any.a_void = 0; 1630 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED); 1631 } else 1632 putstr(win, 0, buf); 1633 1634 /* 1635 * Circle through the special levels to find levels that are in 1636 * this dungeon. 1637 */ 1638 for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) { 1639 if (slev->dlevel.dnum != i) continue; 1640 1641 /* print any branches before this level */ 1642 print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu, &lchoices); 1643 1644 Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel)); 1645 if (Is_stronghold(&slev->dlevel)) 1646 Sprintf(eos(buf), " (tune %s)", tune); 1647 if (bymenu) { 1648 /* If other floating branches are added, this will need to change */ 1649 if (i != knox_level.dnum) { 1650 lchoices.lev[lchoices.idx] = slev->dlevel.dlevel; 1651 lchoices.dgn[lchoices.idx] = i; 1652 } else { 1653 lchoices.lev[lchoices.idx] = depth(&slev->dlevel); 1654 lchoices.dgn[lchoices.idx] = 0; 1655 } 1656 lchoices.playerlev[lchoices.idx] = depth(&slev->dlevel); 1657 any.a_void = 0; 1658 any.a_int = lchoices.idx + 1; 1659 add_menu(win, NO_GLYPH, &any, lchoices.menuletter, 1660 0, ATR_NONE, buf, MENU_UNSELECTED); 1661 if (lchoices.menuletter == 'z') lchoices.menuletter = 'A'; 1662 else lchoices.menuletter++; 1663 lchoices.idx++; 1664 } else 1665 putstr(win, 0, buf); 1666 1667 last_level = slev->dlevel.dlevel; 1668 } 1669 /* print branches after the last special level */ 1670 print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices); 1671 } 1672 1673 /* Print out floating branches (if any). */ 1674 for (first = TRUE, br = branches; br; br = br->next) { 1675 if (br->end1.dnum == n_dgns) { 1676 if (first) { 1677 if (!bymenu) { 1678 putstr(win, 0, ""); 1679 putstr(win, 0, "Floating branches"); 1680 } 1681 first = FALSE; 1682 } 1683 Sprintf(buf, " %s to %s", 1684 br_string(br->type), dungeons[br->end2.dnum].dname); 1685 if (!bymenu) 1686 putstr(win, 0, buf); 1687 } 1688 } 1689 if (bymenu) { 1690 int n; 1691 menu_item *selected; 1692 int idx; 1693 1694 end_menu(win, "Level teleport to where:"); 1695 n = select_menu(win, PICK_ONE, &selected); 1696 destroy_nhwindow(win); 1697 if (n > 0) { 1698 idx = selected[0].item.a_int - 1; 1699 free((genericptr_t)selected); 1700 if (rlev && rdgn) { 1701 *rlev = lchoices.lev[idx]; 1702 *rdgn = lchoices.dgn[idx]; 1703 return lchoices.playerlev[idx]; 1704 } 1705 } 1706 return 0; 1707 } 1708 1709 /* I hate searching for the invocation pos while debugging. -dean */ 1710 if (Invocation_lev(&u.uz)) { 1711 putstr(win, 0, ""); 1712 Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)", 1713 inv_pos.x, inv_pos.y, u.ux, u.uy); 1714 putstr(win, 0, buf); 1715 } 1716 /* 1717 * The following is based on the assumption that the inter-level portals 1718 * created by the level compiler (not the dungeon compiler) only exist 1719 * one per level (currently true, of course). 1720 */ 1721 else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz) 1722 || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) { 1723 struct trap *trap; 1724 for (trap = ftrap; trap; trap = trap->ntrap) 1725 if (trap->ttyp == MAGIC_PORTAL) break; 1726 1727 putstr(win, 0, ""); 1728 if (trap) 1729 Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)", 1730 trap->tx, trap->ty, u.ux, u.uy); 1731 else 1732 Sprintf(buf, "No portal found."); 1733 putstr(win, 0, buf); 1734 } 1735 1736 display_nhwindow(win, TRUE); 1737 destroy_nhwindow(win); 1738 return 0; 1739} 1740#endif /* WIZARD */ 1741 1742#endif /* OVL1 */ 1743 1744/*dungeon.c*/ 1745