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. */
11 #define DUNGEON_FILE "dungeon"
13 #define X_START "x-strt"
14 #define X_LOCATE "x-loca"
15 #define X_GOAL "x-goal"
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];
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 */
28 int n_dgns; /* number of dungeons (used here, */
30 static branch *branches = (branch *) 0; /* dungeon branch list */
35 schar playerlev[MAXLINFO];
40 static void FDECL(Fread, (genericptr_t, int, int, dlb *));
41 STATIC_DCL xchar FDECL(dname_to_dnum, (const char *));
42 STATIC_DCL int FDECL(find_branch, (const char *, struct proto_dungeon *));
43 STATIC_DCL xchar FDECL(parent_dnum, (const char *, struct proto_dungeon *));
44 STATIC_DCL int FDECL(level_range, (XCHAR_P,int,int,int,struct proto_dungeon *,int *));
45 STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *));
46 STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *));
47 STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *));
48 STATIC_DCL void FDECL(add_level, (s_level *));
49 STATIC_DCL void FDECL(init_level, (int,int,struct proto_dungeon *));
50 STATIC_DCL int FDECL(possible_places, (int, boolean *, struct proto_dungeon *));
51 STATIC_DCL xchar FDECL(pick_level, (boolean *, int));
52 STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *));
54 STATIC_DCL const char *FDECL(br_string, (int));
55 STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P, struct lchoice *));
59 #define DD dungeons[i]
60 STATIC_DCL void NDECL(dumpit);
69 for(i = 0; i < n_dgns; i++) {
70 fprintf(stderr, "\n#%d \"%s\" (%s):\n", i,
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" : "");
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" : "");
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",
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" :
102 br->end1.dnum, br->end1.dlevel,
103 br->end2.dnum, br->end2.dlevel,
104 br->end1_up ? "end1 up" : "end1 down");
107 fprintf(stderr,"\nDone\n");
112 /* Save the dungeon structures. */
114 save_dungeon(fd, perform_write, free_data)
116 boolean perform_write, free_data;
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);
127 for (count = 0, curr = branches; curr; curr = curr->next)
129 bwrite(fd, (genericptr_t) &count, sizeof(count));
131 for (curr = branches; curr; curr = curr->next)
132 bwrite(fd, (genericptr_t) curr, sizeof (branch));
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);
142 for (curr = branches; curr; curr = next) {
144 free((genericptr_t) curr);
150 /* Restore the dungeon structures. */
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);
163 last = branches = (branch *) 0;
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;
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);
185 Fread(ptr, size, nitems, stream)
192 if((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
194 "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.",
195 (size * nitems), (size * cnt));
196 terminate(EXIT_FAILURE);
206 for (i = 0; i < n_dgns; i++)
207 if (!strcmp(dungeons[i].dname, s)) return i;
209 panic("Couldn't resolve dungeon number for name \"%s\".", s);
219 for(curr = sp_levchn; curr; curr = curr->next)
220 if (!strcmpi(s, curr->proto)) break;
224 /* Find the branch that links the named dungeon. */
227 const char *s; /* dungeon name */
228 struct proto_dungeon *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);
237 /* support for level tport by name */
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)))
247 i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1;
254 * Find the "parent" by searching the prototype branch list for the branch
255 * listing, then figuring out to which dungeon it belongs.
259 const char *s; /* dungeon name */
260 struct proto_dungeon *pd;
265 i = find_branch(s, pd);
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).
270 for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++)
271 if ((i -= pd->tmpdungeon[pdnum].branches) < 0)
274 panic("parent_dnum: couldn't resolve branch.");
280 * Return a starting point and number of successive positions a level
281 * or dungeon entrance can occupy.
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.
290 level_range(dgn, base, rand, chain, pd, adjusted_base)
292 int base, rand, chain;
293 struct proto_dungeon *pd;
296 int lmax = dungeons[dgn].num_dunlevs;
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!");
302 base += levtmp->dlevel.dlevel;
303 } else { /* absolute in the dungeon */
304 /* from end of dungeon */
305 if (base < 0) base = (lmax + base + 1);
308 if (base < 1 || base > lmax)
309 panic("level_range: base value out of range");
311 *adjusted_base = base;
313 if (rand == -1) { /* from base to end of dungeon */
314 return (lmax - base + 1);
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 */
325 struct proto_dungeon *pd;
327 int i, j, num, base, dnum = parent_dnum(s, pd);
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,
337 /* KMH -- Try our best to find a level without an existing branch */
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))
345 } while (curr && i != j);
349 /* Convert from the temporary branch type to the dungeon branch type. */
351 correct_branch_type(tbr)
352 struct tmpbranch *tbr;
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;
360 impossible("correct_branch_type: unknown branch type");
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.
371 insert_branch(new_branch, extract_first)
373 boolean extract_first;
376 long new_val, curr_val, prev_val;
379 for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next)
380 if (curr == new_branch) break;
382 if (!curr) panic("insert_branch: not found");
384 prev->next = curr->next;
386 branches = curr->next;
388 new_branch->next = (branch *) 0;
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))
397 * Insert the new branch into the correct place in the branch list.
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;
408 new_branch->next = curr;
409 prev->next = new_branch;
411 new_branch->next = branches;
412 branches = new_branch;
416 /* Add a dungeon branch to the branch list. */
418 add_branch(dgn, child_entry_level, pd)
420 int child_entry_level;
421 struct proto_dungeon *pd;
423 static int branch_id = 0;
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;
438 insert_branch(new_branch, FALSE);
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
452 s_level *prev, *curr;
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)
462 new_lev->next = sp_levchn;
465 new_lev->next = curr;
466 prev->next = new_lev;
471 init_level(dgn, proto_index, pd)
472 int dgn, proto_index;
473 struct proto_dungeon *pd;
476 struct tmplevel *tlevel = &pd->tmplevel[proto_index];
478 pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
482 if (tlevel->chance <= rn2(100)) return;
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 */
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);
501 new_level->rndlevs = tlevel->rndlevs;
502 new_level->next = (s_level *) 0;
506 possible_places(idx, map, pd)
507 int idx; /* prototype index */
508 boolean *map; /* array MAXLEVEL+1 in length */
509 struct proto_dungeon *pd;
512 s_level *lev = pd->final_lev[idx];
514 /* init level possibilities */
515 for (i = 0; i <= MAXLEVEL; i++) map[i] = FALSE;
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,
522 for (i = start; i < start+count; i++)
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;
536 /* Pick the nth TRUE entry in the given boolean array. */
539 boolean *map; /* an array MAXLEVEL+1 in size */
543 for (i = 1; i <= MAXLEVEL; i++)
544 if (map[i] && !nth--) return (xchar) i;
545 panic("pick_level: ran out of valid levels");
550 static void FDECL(indent,(int));
556 while (d-- > 0) fputs(" ", stderr);
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.
568 place_level(proto_index, pd)
570 struct proto_dungeon *pd;
572 boolean map[MAXLEVEL+1]; /* valid levels are 1..MAXLEVEL inclusive */
579 if (proto_index == pd->n_levs) return TRUE; /* at end of proto levels */
581 lev = pd->final_lev[proto_index];
583 /* No level created for this prototype, goto next. */
584 if (!lev) return place_level(proto_index+1, pd);
586 npossible = possible_places(proto_index, map, pd);
588 for (; npossible; --npossible) {
589 lev->dlevel.dlevel = pick_level(map, rn2(npossible));
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");
597 if (place_level(proto_index+1, pd)) return TRUE;
598 map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */
601 indent(proto_index-pd->start);
602 fprintf(stderr,"%s: failed\n", lev->proto);
609 const char *lev_name;
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 },
627 { "rogue", &rogue_level },
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 },
642 init_dungeons() /* initialize the "dungeon" structs */
645 register int i, cl = 0, cb = 0;
647 struct proto_dungeon pd;
648 struct level_map *lev_map;
649 struct version_info vers_info;
651 pd.n_levs = pd.n_brs = 0;
653 dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
656 Sprintf(tbuf, "Cannot open dungeon description - \"%s",
658 #ifdef DLBRSRC /* using a resource from the executable */
659 Strcat(tbuf, "\" resource!");
660 #else /* using a file or DLB file */
662 Strcat(tbuf, "\" from ");
663 # ifdef PREFIXES_IN_USE
664 Strcat(tbuf, "\n\"");
665 if (fqn_prefix[DATAPREFIX]) Strcat(tbuf, fqn_prefix[DATAPREFIX]);
669 Strcat(tbuf, DLBFILE);
671 Strcat(tbuf, "\" file!");
674 interject_assistance(1, INTERJECT_PANIC, (genericptr_t)tbuf,
675 (genericptr_t)fqn_prefix[DATAPREFIX]);
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
686 if (iflags.window_inited) clear_nhwindow(WIN_MAP);
687 if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
688 panic("Dungeon description not valid.");
691 * Read in each dungeon and transfer the results to the internal
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");
699 for (i = 0; i < n_dgns; i++) {
700 Fread((genericptr_t)&pd.tmpdungeon[i],
701 sizeof(struct tmpdungeon), 1, dgn_file);
705 if(pd.tmpdungeon[i].chance && (pd.tmpdungeon[i].chance <= rn2(100))) {
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),
713 for(j = 0; j < pd.tmpdungeon[i].branches; j++)
714 Fread((genericptr_t)&pd.tmpbranch[cb],
715 sizeof(struct tmpbranch), 1, dgn_file);
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;
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;
730 dungeons[i].ledger_start = 0;
731 dungeons[i].depth_start = 1;
732 dungeons[i].dunlev_ureached = 1;
734 dungeons[i].ledger_start = dungeons[i-1].ledger_start +
735 dungeons[i-1].num_dunlevs;
736 dungeons[i].dunlev_ureached = 0;
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);
744 * Set the entry level for this dungeon. The pd.tmpdungeon entry
746 * < 0 from bottom (-1 == bottom level)
748 * > 0 actual level (1 = top)
750 * Note that the entry_lev field in the dungeon structure is
751 * redundant. It is used only here and in print_dungeon().
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 */
765 if (i) { /* set depth */
770 br = add_branch(i, dungeons[i].entry_lev, &pd);
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;
777 from_depth = depth(&br->end1);
778 from_up = br->end1_up;
782 * Calculate the depth of the top of the dungeon via
783 * its branch. First, the depth of the entry point:
785 * depth of branch from "parent" dungeon
786 * + -1 or 1 depending on a up or down stair or
789 * Followed by the depth of the top of the dungeon:
791 * - (entry depth - 1)
793 * We'll say that portals stay on the same depth.
795 dungeons[i].depth_start = from_depth
796 + (br->type == BR_PORTAL ? 0 :
798 - (dungeons[i].entry_lev - 1);
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;
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");
810 * Read in the prototype special levels. Don't add generated
811 * special levels until they are all placed.
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);
819 * Recursively place the generated levels for this dungeon. This
820 * routine will attempt all possible combinations before giving
823 if (!place_level(pd.start, &pd))
824 panic("init_dungeon: couldn't place levels");
826 fprintf(stderr, "--- end of dungeon %d ---\n", i);
830 for (; pd.start < pd.n_levs; pd.start++)
831 if (pd.final_lev[pd.start]) add_level(pd.final_lev[pd.start]);
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);
841 (void) dlb_fclose(dgn_file);
843 for (i = 0; i < 5; i++) tune[i] = 'A' + rn2(7);
847 * Find most of the special levels and dungeons so we can access their
850 for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
851 x = find_level(lev_map->lev_name);
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.
858 Sprintf(x->proto, "%s%s", urole.filecode, &lev_map->lev_name[1]);
859 } else if (lev_map->lev_spec == &knox_level) {
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
867 for (br = branches; br; br = br->next)
868 if (on_level(&br->end2, &knox_level)) break;
870 if (br) br->end1.dnum = n_dgns;
871 /* adjust the branch's position on the list */
872 insert_branch(br, TRUE);
877 * I hate hardwiring these names. :-(
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");
884 /* one special fixup for dummy surface level */
885 if ((x = find_level("dummy")) != 0) {
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. */
903 dunlev(lev) /* return the level number for lev in *this* dungeon */
910 dunlevs_in_dungeon(lev) /* return the lowest level number for *this* dungeon*/
913 return(dungeons[lev->dnum].num_dunlevs);
917 deepest_lev_reached(noquest) /* return the lowest level explored in the game*/
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.
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.
937 register schar ret = 0;
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;
944 if(depth(&tmp) > ret) ret = depth(&tmp);
949 /* return a bookkeeping level number for purpose of comparisons and
955 return((xchar)(lev->dlevel + dungeons[lev->dnum].ledger_start));
959 * The last level in the bookkeeping list of level is the bottom of the last
960 * dungeon in the dungeons[] array.
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.
971 return (xchar) (dungeons[n_dgns-1].ledger_start +
972 dungeons[n_dgns-1].num_dunlevs);
975 /* return the dungeon that this ledgerno exists in */
977 ledger_to_dnum(ledgerno)
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)
988 panic("level number out of range [ledger_to_dnum(%d)]", (int)ledgerno);
993 /* return the level of the dungeon this ledgerno exists in */
995 ledger_to_dlev(ledgerno)
998 return((xchar)(ledgerno - dungeons[ledger_to_dnum(ledgerno)].ledger_start));
1004 /* returns the depth of a level, in floors below the surface */
1005 /* (note levels in different dungeons can have the same depth). */
1010 return((schar)( dungeons[lev->dnum].depth_start + lev->dlevel - 1));
1014 on_level(lev1, lev2) /* are "lev1" and "lev2" actually the same? */
1015 d_level *lev1, *lev2;
1017 return((boolean)((lev1->dnum == lev2->dnum) && (lev1->dlevel == lev2->dlevel)));
1023 /* is this level referenced in the special level chain? */
1030 for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
1031 if (on_level(lev, &levtmp->dlevel)) return(levtmp);
1033 return((s_level *)0);
1037 * Is this a multi-dungeon branch level? If so, return a pointer to the
1038 * branch. Otherwise, return null.
1046 for (curr = branches; curr; curr = curr->next) {
1047 if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
1050 return (branch *) 0;
1053 /* goto the next level (or appropriate dungeon) */
1055 next_level(at_stairs)
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);
1062 /* Going down a stairs or jump in a trap door. */
1065 newlevel.dnum = u.uz.dnum;
1066 newlevel.dlevel = u.uz.dlevel + 1;
1067 goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
1071 /* goto the previous level (or appropriate dungeon) */
1073 prev_level(at_stairs)
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);
1083 /* Going up a stairs or rising through the ceiling. */
1085 newlevel.dnum = u.uz.dnum;
1086 newlevel.dlevel = u.uz.dlevel - 1;
1087 goto_level(&newlevel, at_stairs, FALSE, FALSE);
1098 cliparound(u.ux, u.uy);
1101 /* ridden steed always shares hero's location */
1102 if (u.usteed) u.usteed->mx = u.ux, u.usteed->my = u.uy;
1107 u_on_sstairs() { /* place you on the special staircase */
1110 u_on_newpos(sstairs.sx, sstairs.sy);
1112 /* code stolen from goto_level */
1116 pline("u_on_sstairs: picking random spot");
1118 #define badspot(x,y) ((levl[x][y].typ != ROOM && levl[x][y].typ != CORR) || MON_AT(x, y))
1122 if (!badspot(x, y)) {
1126 } while (++trycnt <= 500);
1127 panic("u_on_sstairs: could not relocate player!");
1133 u_on_upstairs() /* place you on upstairs (or special equivalent) */
1136 u_on_newpos(xupstair, yupstair);
1142 u_on_dnstairs() /* place you on dnstairs (or special equivalent) */
1145 u_on_newpos(xdnstair, ydnstair);
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)));
1165 return((boolean)(lev->dlevel == dungeons[lev->dnum].num_dunlevs));
1172 return((boolean)(!level.flags.hardfloor
1173 && !Is_botlevel(lev) && !Invocation_lev(lev)));
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.
1185 return((boolean)(Can_dig_down(lev) || Is_stronghold(lev)));
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.
1195 Can_rise_up(x, y, lev)
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)))
1204 return (boolean)(lev->dlevel > 1 ||
1205 (dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 &&
1206 sstairs.sx && sstairs.up));
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.
1221 get_level(newlevel, levnum)
1226 xchar dgn = u.uz.dnum;
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;
1236 /* The desired level is in this dungeon or a "higher" one. */
1239 * Branch up the tree until we reach a dungeon that contains the
1242 if (levnum < dungeons[dgn].depth_start) {
1246 * Find the parent dungeon of this dungeon.
1248 * This assumes that end2 is always the "child" and it is
1251 for (br = branches; br; br = br->next)
1252 if (br->end2.dnum == dgn) break;
1254 panic("get_level: can't find parent dungeon");
1256 dgn = br->end1.dnum;
1257 } while (levnum < dungeons[dgn].depth_start);
1260 /* We're within the same dungeon; calculate the level. */
1261 levnum = levnum - dungeons[dgn].depth_start + 1;
1264 newlevel->dnum = dgn;
1265 newlevel->dlevel = levnum;
1272 In_quest(lev) /* are you in the quest dungeon? */
1275 return((boolean)(lev->dnum == quest_dnum));
1282 In_mines(lev) /* are you in the mines dungeon? */
1285 return((boolean)(lev->dnum == mines_dnum));
1289 * Return the branch for the given dungeon.
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.
1303 dnum = dname_to_dnum(s);
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;
1309 if (!br) panic("dgn_entrance: can't find entrance to %s", s);
1315 * This returns true if the hero is on the same level as the entrance to
1316 * the named dungeon.
1318 * Called from do.c and mklev.c.
1320 * Assumes that end1 is always the "parent".
1328 br = dungeon_branch(s);
1329 return((boolean)(on_level(&u.uz, &br->end1) ? TRUE : FALSE));
1333 In_V_tower(lev) /* is `lev' part of Vlad's tower? */
1336 return((boolean)(lev->dnum == tower_dnum));
1340 On_W_tower_level(lev) /* is `lev' a level containing the Wizard's tower? */
1343 return (boolean)(Is_wiz1_level(lev) ||
1344 Is_wiz2_level(lev) ||
1345 Is_wiz3_level(lev));
1349 In_W_tower(x, y, lev) /* is <x,y> of `lev' inside the Wizard's tower? */
1353 if (!On_W_tower_level(lev)) return FALSE;
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} );
1360 return (boolean)within_bounded_area(x, y, dndest.nlx, dndest.nly,
1361 dndest.nhx, dndest.nhy);
1363 impossible("No boundary for Wizard's Tower?");
1371 In_hell(lev) /* are you in one of the Hell levels? */
1374 return((boolean)(dungeons[lev->dnum].flags.hellish));
1381 find_hell(lev) /* sets *lev to be the gateway to Gehennom... */
1384 lev->dnum = valley_level.dnum;
1389 goto_hell(at_stairs, falling) /* go directly to hell... */
1390 boolean at_stairs, falling;
1395 goto_level(&lev, at_stairs, falling, FALSE);
1399 assign_level(dest, src) /* equivalent to dest = source */
1400 d_level *dest, *src;
1402 dest->dnum = src->dnum;
1403 dest->dlevel = src->dlevel;
1407 assign_rnd_level(dest, src, range) /* dest = src + rn1(range) */
1408 d_level *dest, *src;
1411 dest->dnum = src->dnum;
1412 dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range)) ;
1414 if(dest->dlevel > dunlevs_in_dungeon(dest))
1415 dest->dlevel = dunlevs_in_dungeon(dest);
1416 else if(dest->dlevel < 1)
1427 s_level *lev = Is_special(&u.uz);
1430 if (lev && lev->flags.align)
1431 if(rn2(100) < pct) return(lev->flags.align);
1433 if(dungeons[u.uz.dnum].flags.align)
1434 if(rn2(100) < pct) return(dungeons[u.uz.dnum].flags.align);
1437 return(Align2amask(al));
1447 return((boolean)(In_hell(lev) &&
1448 lev->dlevel == (dungeons[lev->dnum].num_dunlevs - 1)));
1451 /* use instead of depth() wherever a degree of difficulty is made
1452 * dependent on the location in the dungeon (eg. monster creation).
1457 if (In_endgame(&u.uz))
1458 return((xchar)(depth(&sanctum_level) + u.ulevel/2));
1461 return(deepest_lev_reached(FALSE));
1463 return((xchar) depth(&u.uz));
1466 /* Take one word and try to match it to a level.
1467 * Recognized levels are as shown by print_dungeon().
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';
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";
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 */
1506 (level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED)) {
1507 lev = depth(&slev->dlevel);
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);
1516 idxtoo = (idx >> 8) & 0x00FF;
1518 if ( /* either wizard mode, or else _both_ sides of branch seen */
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);
1536 /* Convert a branch type to a string usable by print_dungeon(). */
1537 STATIC_OVL const char *
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";
1547 return " (unknown)";
1550 /* Print all child branches between the lower and upper bounds. */
1552 print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices)
1558 struct lchoice *lchoices;
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,
1573 lchoices->lev[lchoices->idx] = br->end1.dlevel;
1574 lchoices->dgn[lchoices->idx] = br->end1.dnum;
1575 lchoices->playerlev[lchoices->idx] = depth(&br->end1);
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++;
1584 putstr(win, 0, buf);
1589 /* Print available dungeon information. */
1591 print_dungeon(bymenu, rlev, rdgn)
1596 int i, last_level, nlev;
1603 struct lchoice lchoices;
1605 winid win = create_nhwindow(NHW_MENU);
1609 lchoices.menuletter = 'a';
1612 for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
1613 nlev = dptr->num_dunlevs;
1615 Sprintf(buf, "%s: levels %d to %d", dptr->dname, dptr->depth_start,
1616 dptr->depth_start + nlev - 1);
1618 Sprintf(buf, "%s: level %d", dptr->dname, dptr->depth_start);
1620 /* Most entrances are uninteresting. */
1621 if (dptr->entry_lev != 1) {
1622 if (dptr->entry_lev == nlev)
1623 Strcat(buf, ", entrance from below");
1625 Sprintf(eos(buf), ", entrance on %d",
1626 dptr->depth_start + dptr->entry_lev - 1);
1630 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED);
1632 putstr(win, 0, buf);
1635 * Circle through the special levels to find levels that are in
1638 for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
1639 if (slev->dlevel.dnum != i) continue;
1641 /* print any branches before this level */
1642 print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu, &lchoices);
1644 Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel));
1645 if (Is_stronghold(&slev->dlevel))
1646 Sprintf(eos(buf), " (tune %s)", tune);
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;
1653 lchoices.lev[lchoices.idx] = depth(&slev->dlevel);
1654 lchoices.dgn[lchoices.idx] = 0;
1656 lchoices.playerlev[lchoices.idx] = depth(&slev->dlevel);
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++;
1665 putstr(win, 0, buf);
1667 last_level = slev->dlevel.dlevel;
1669 /* print branches after the last special level */
1670 print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices);
1673 /* Print out floating branches (if any). */
1674 for (first = TRUE, br = branches; br; br = br->next) {
1675 if (br->end1.dnum == n_dgns) {
1679 putstr(win, 0, "Floating branches");
1683 Sprintf(buf, " %s to %s",
1684 br_string(br->type), dungeons[br->end2.dnum].dname);
1686 putstr(win, 0, buf);
1691 menu_item *selected;
1694 end_menu(win, "Level teleport to where:");
1695 n = select_menu(win, PICK_ONE, &selected);
1696 destroy_nhwindow(win);
1698 idx = selected[0].item.a_int - 1;
1699 free((genericptr_t)selected);
1701 *rlev = lchoices.lev[idx];
1702 *rdgn = lchoices.dgn[idx];
1703 return lchoices.playerlev[idx];
1709 /* I hate searching for the invocation pos while debugging. -dean */
1710 if (Invocation_lev(&u.uz)) {
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);
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).
1721 else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
1722 || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
1724 for (trap = ftrap; trap; trap = trap->ntrap)
1725 if (trap->ttyp == MAGIC_PORTAL) break;
1729 Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)",
1730 trap->tx, trap->ty, u.ux, u.uy);
1732 Sprintf(buf, "No portal found.");
1733 putstr(win, 0, buf);
1736 display_nhwindow(win, TRUE);
1737 destroy_nhwindow(win);