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