fix 'crash when reviving shopkeeper'
[aNetHack.git] / src / dungeon.c
blob9c531e967565d24ee985203ba3d274a5f8c5a500
1 /* NetHack 3.6 dungeon.c $NHDT-Date: 1462486971 2016/05/05 22:22:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.73 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
6 #include "dgn_file.h"
7 #include "dlb.h"
8 #include "lev.h"
10 #define DUNGEON_FILE "dungeon"
12 #define X_START "x-strt"
13 #define X_LOCATE "x-loca"
14 #define X_GOAL "x-goal"
16 struct proto_dungeon {
17 struct tmpdungeon tmpdungeon[MAXDUNGEON];
18 struct tmplevel tmplevel[LEV_LIMIT];
19 s_level *final_lev[LEV_LIMIT]; /* corresponding level pointers */
20 struct tmpbranch tmpbranch[BRANCH_LIMIT];
22 int start; /* starting index of current dungeon sp levels */
23 int n_levs; /* number of tmplevel entries */
24 int n_brs; /* number of tmpbranch entries */
27 int n_dgns; /* number of dungeons (also used in mklev.c and do.c) */
28 static branch *branches = (branch *) 0; /* dungeon branch list */
30 mapseen *mapseenchn = (struct mapseen *) 0; /*DUNGEON_OVERVIEW*/
32 struct lchoice {
33 int idx;
34 schar lev[MAXLINFO];
35 schar playerlev[MAXLINFO];
36 xchar dgn[MAXLINFO];
37 char menuletter;
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,
45 struct proto_dungeon *, int *));
46 STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *));
47 STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *));
48 STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *));
49 STATIC_DCL void FDECL(add_level, (s_level *));
50 STATIC_DCL void FDECL(init_level, (int, int, struct proto_dungeon *));
51 STATIC_DCL int FDECL(possible_places, (int, boolean *,
52 struct proto_dungeon *));
53 STATIC_DCL xchar FDECL(pick_level, (boolean *, int));
54 STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *));
55 STATIC_DCL boolean FDECL(unplaced_floater, (struct dungeon *));
56 STATIC_DCL boolean FDECL(unreachable_level, (d_level *, BOOLEAN_P));
57 STATIC_DCL void FDECL(tport_menu, (winid, char *, struct lchoice *, d_level *,
58 BOOLEAN_P));
59 STATIC_DCL const char *FDECL(br_string, (int));
60 STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P,
61 struct lchoice *));
62 STATIC_DCL mapseen *FDECL(load_mapseen, (int));
63 STATIC_DCL void FDECL(save_mapseen, (int, mapseen *));
64 STATIC_DCL mapseen *FDECL(find_mapseen, (d_level *));
65 STATIC_DCL void FDECL(print_mapseen, (winid, mapseen *, int, int, BOOLEAN_P));
66 STATIC_DCL boolean FDECL(interest_mapseen, (mapseen *));
67 STATIC_DCL void FDECL(traverse_mapseenchn, (BOOLEAN_P, winid,
68 int, int, int *));
69 STATIC_DCL const char *FDECL(seen_string, (XCHAR_P, const char *));
70 STATIC_DCL const char *FDECL(br_string2, (branch *));
71 STATIC_DCL const char *FDECL(endgamelevelname, (char *, int));
72 STATIC_DCL const char *FDECL(shop_string, (int));
73 STATIC_DCL char *FDECL(tunesuffix, (mapseen *, char *));
75 #ifdef DEBUG
76 #define DD dungeons[i]
77 STATIC_DCL void NDECL(dumpit);
79 STATIC_OVL void
80 dumpit()
82 int i;
83 s_level *x;
84 branch *br;
86 if (!explicitdebug(__FILE__))
87 return;
89 for (i = 0; i < n_dgns; i++) {
90 fprintf(stderr, "\n#%d \"%s\" (%s):\n", i, DD.dname, DD.proto);
91 fprintf(stderr, " num_dunlevs %d, dunlev_ureached %d\n",
92 DD.num_dunlevs, DD.dunlev_ureached);
93 fprintf(stderr, " depth_start %d, ledger_start %d\n",
94 DD.depth_start, DD.ledger_start);
95 fprintf(stderr, " flags:%s%s%s\n",
96 DD.flags.rogue_like ? " rogue_like" : "",
97 DD.flags.maze_like ? " maze_like" : "",
98 DD.flags.hellish ? " hellish" : "");
99 getchar();
101 fprintf(stderr, "\nSpecial levels:\n");
102 for (x = sp_levchn; x; x = x->next) {
103 fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs);
104 fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel);
105 fprintf(stderr, "flags:%s%s%s%s\n",
106 x->flags.rogue_like ? " rogue_like" : "",
107 x->flags.maze_like ? " maze_like" : "",
108 x->flags.hellish ? " hellish" : "",
109 x->flags.town ? " town" : "");
110 getchar();
112 fprintf(stderr, "\nBranches:\n");
113 for (br = branches; br; br = br->next) {
114 fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n", br->id,
115 br->type == BR_STAIR
116 ? "stair"
117 : br->type == BR_NO_END1
118 ? "no end1"
119 : br->type == BR_NO_END2
120 ? "no end2"
121 : br->type == BR_PORTAL
122 ? "portal"
123 : "unknown",
124 br->end1.dnum, br->end1.dlevel, br->end2.dnum,
125 br->end2.dlevel, br->end1_up ? "end1 up" : "end1 down");
127 getchar();
128 fprintf(stderr, "\nDone\n");
129 getchar();
131 #endif
133 /* Save the dungeon structures. */
134 void
135 save_dungeon(fd, perform_write, free_data)
136 int fd;
137 boolean perform_write, free_data;
139 branch *curr, *next;
140 mapseen *curr_ms, *next_ms;
141 int count;
143 if (perform_write) {
144 bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns);
145 bwrite(fd, (genericptr_t) dungeons,
146 sizeof(dungeon) * (unsigned) n_dgns);
147 bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
148 bwrite(fd, (genericptr_t) tune, sizeof tune);
150 for (count = 0, curr = branches; curr; curr = curr->next)
151 count++;
152 bwrite(fd, (genericptr_t) &count, sizeof(count));
154 for (curr = branches; curr; curr = curr->next)
155 bwrite(fd, (genericptr_t) curr, sizeof(branch));
157 count = maxledgerno();
158 bwrite(fd, (genericptr_t) &count, sizeof count);
159 bwrite(fd, (genericptr_t) level_info,
160 (unsigned) count * sizeof(struct linfo));
161 bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
163 for (count = 0, curr_ms = mapseenchn; curr_ms;
164 curr_ms = curr_ms->next)
165 count++;
166 bwrite(fd, (genericptr_t) &count, sizeof(count));
168 for (curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next)
169 save_mapseen(fd, curr_ms);
172 if (free_data) {
173 for (curr = branches; curr; curr = next) {
174 next = curr->next;
175 free((genericptr_t) curr);
177 branches = 0;
178 for (curr_ms = mapseenchn; curr_ms; curr_ms = next_ms) {
179 next_ms = curr_ms->next;
180 if (curr_ms->custom)
181 free((genericptr_t) curr_ms->custom);
182 free((genericptr_t) curr_ms);
184 mapseenchn = 0;
188 /* Restore the dungeon structures. */
189 void
190 restore_dungeon(fd)
191 int fd;
193 branch *curr, *last;
194 int count, i;
195 mapseen *curr_ms, *last_ms;
197 mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns));
198 mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned) n_dgns);
199 mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
200 mread(fd, (genericptr_t) tune, sizeof tune);
202 last = branches = (branch *) 0;
204 mread(fd, (genericptr_t) &count, sizeof(count));
205 for (i = 0; i < count; i++) {
206 curr = (branch *) alloc(sizeof(branch));
207 mread(fd, (genericptr_t) curr, sizeof(branch));
208 curr->next = (branch *) 0;
209 if (last)
210 last->next = curr;
211 else
212 branches = curr;
213 last = curr;
216 mread(fd, (genericptr_t) &count, sizeof(count));
217 if (count >= MAXLINFO)
218 panic("level information count larger (%d) than allocated size",
219 count);
220 mread(fd, (genericptr_t) level_info,
221 (unsigned) count * sizeof(struct linfo));
222 mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
224 mread(fd, (genericptr_t) &count, sizeof(count));
225 last_ms = (mapseen *) 0;
226 for (i = 0; i < count; i++) {
227 curr_ms = load_mapseen(fd);
228 curr_ms->next = (mapseen *) 0;
229 if (last_ms)
230 last_ms->next = curr_ms;
231 else
232 mapseenchn = curr_ms;
233 last_ms = curr_ms;
237 static void
238 Fread(ptr, size, nitems, stream)
239 genericptr_t ptr;
240 int size, nitems;
241 dlb *stream;
243 int cnt;
245 if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
246 panic(
247 "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.",
248 (size * nitems), (size * cnt));
249 terminate(EXIT_FAILURE);
253 STATIC_OVL xchar
254 dname_to_dnum(s)
255 const char *s;
257 xchar i;
259 for (i = 0; i < n_dgns; i++)
260 if (!strcmp(dungeons[i].dname, s))
261 return i;
263 panic("Couldn't resolve dungeon number for name \"%s\".", s);
264 /*NOT REACHED*/
265 return (xchar) 0;
268 s_level *
269 find_level(s)
270 const char *s;
272 s_level *curr;
273 for (curr = sp_levchn; curr; curr = curr->next)
274 if (!strcmpi(s, curr->proto))
275 break;
276 return curr;
279 /* Find the branch that links the named dungeon. */
280 STATIC_OVL int
281 find_branch(s, pd)
282 const char *s; /* dungeon name */
283 struct proto_dungeon *pd;
285 int i;
287 if (pd) {
288 for (i = 0; i < pd->n_brs; i++)
289 if (!strcmp(pd->tmpbranch[i].name, s))
290 break;
291 if (i == pd->n_brs)
292 panic("find_branch: can't find %s", s);
293 } else {
294 /* support for level tport by name */
295 branch *br;
296 const char *dnam;
298 for (br = branches; br; br = br->next) {
299 dnam = dungeons[br->end2.dnum].dname;
300 if (!strcmpi(dnam, s)
301 || (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s)))
302 break;
304 i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1;
306 return i;
310 * Find the "parent" by searching the prototype branch list for the branch
311 * listing, then figuring out to which dungeon it belongs.
313 STATIC_OVL xchar
314 parent_dnum(s, pd)
315 const char *s; /* dungeon name */
316 struct proto_dungeon *pd;
318 int i;
319 xchar pdnum;
321 i = find_branch(s, pd);
323 * Got branch, now find parent dungeon. Stop if we have reached
324 * "this" dungeon (if we haven't found it by now it is an error).
326 for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++)
327 if ((i -= pd->tmpdungeon[pdnum].branches) < 0)
328 return pdnum;
330 panic("parent_dnum: couldn't resolve branch.");
331 /*NOT REACHED*/
332 return (xchar) 0;
336 * Return a starting point and number of successive positions a level
337 * or dungeon entrance can occupy.
339 * Note: This follows the acouple (instead of the rcouple) rules for a
340 * negative random component (randc < 0). These rules are found
341 * in dgn_comp.y. The acouple [absolute couple] section says that
342 * a negative random component means from the (adjusted) base to the
343 * end of the dungeon.
345 STATIC_OVL int
346 level_range(dgn, base, randc, chain, pd, adjusted_base)
347 xchar dgn;
348 int base, randc, chain;
349 struct proto_dungeon *pd;
350 int *adjusted_base;
352 int lmax = dungeons[dgn].num_dunlevs;
354 if (chain >= 0) { /* relative to a special level */
355 s_level *levtmp = pd->final_lev[chain];
356 if (!levtmp)
357 panic("level_range: empty chain level!");
359 base += levtmp->dlevel.dlevel;
360 } else { /* absolute in the dungeon */
361 /* from end of dungeon */
362 if (base < 0)
363 base = (lmax + base + 1);
366 if (base < 1 || base > lmax)
367 panic("level_range: base value out of range");
369 *adjusted_base = base;
371 if (randc == -1) { /* from base to end of dungeon */
372 return (lmax - base + 1);
373 } else if (randc) {
374 /* make sure we don't run off the end of the dungeon */
375 return (((base + randc - 1) > lmax) ? lmax - base + 1 : randc);
376 } /* else only one choice */
377 return 1;
380 STATIC_OVL xchar
381 parent_dlevel(s, pd)
382 const char *s;
383 struct proto_dungeon *pd;
385 int i, j, num, base, dnum = parent_dnum(s, pd);
386 branch *curr;
388 i = find_branch(s, pd);
389 num = level_range(dnum, pd->tmpbranch[i].lev.base,
390 pd->tmpbranch[i].lev.rand, pd->tmpbranch[i].chain, pd,
391 &base);
393 /* KMH -- Try our best to find a level without an existing branch */
394 i = j = rn2(num);
395 do {
396 if (++i >= num)
397 i = 0;
398 for (curr = branches; curr; curr = curr->next)
399 if ((curr->end1.dnum == dnum && curr->end1.dlevel == base + i)
400 || (curr->end2.dnum == dnum && curr->end2.dlevel == base + i))
401 break;
402 } while (curr && i != j);
403 return (base + i);
406 /* Convert from the temporary branch type to the dungeon branch type. */
407 STATIC_OVL int
408 correct_branch_type(tbr)
409 struct tmpbranch *tbr;
411 switch (tbr->type) {
412 case TBR_STAIR:
413 return BR_STAIR;
414 case TBR_NO_UP:
415 return tbr->up ? BR_NO_END1 : BR_NO_END2;
416 case TBR_NO_DOWN:
417 return tbr->up ? BR_NO_END2 : BR_NO_END1;
418 case TBR_PORTAL:
419 return BR_PORTAL;
421 impossible("correct_branch_type: unknown branch type");
422 return BR_STAIR;
426 * Add the given branch to the branch list. The branch list is ordered
427 * by end1 dungeon and level followed by end2 dungeon and level. If
428 * extract_first is true, then the branch is already part of the list
429 * but needs to be repositioned.
431 void
432 insert_branch(new_branch, extract_first)
433 branch *new_branch;
434 boolean extract_first;
436 branch *curr, *prev;
437 long new_val, curr_val, prev_val;
439 if (extract_first) {
440 for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next)
441 if (curr == new_branch)
442 break;
444 if (!curr)
445 panic("insert_branch: not found");
446 if (prev)
447 prev->next = curr->next;
448 else
449 branches = curr->next;
451 new_branch->next = (branch *) 0;
453 /* Convert the branch into a unique number so we can sort them. */
454 #define branch_val(bp) \
455 ((((long) (bp)->end1.dnum * (MAXLEVEL + 1) + (long) (bp)->end1.dlevel) \
456 * (MAXDUNGEON + 1) * (MAXLEVEL + 1)) \
457 + ((long) (bp)->end2.dnum * (MAXLEVEL + 1) + (long) (bp)->end2.dlevel))
460 * Insert the new branch into the correct place in the branch list.
462 prev = (branch *) 0;
463 prev_val = -1;
464 new_val = branch_val(new_branch);
465 for (curr = branches; curr;
466 prev_val = curr_val, prev = curr, curr = curr->next) {
467 curr_val = branch_val(curr);
468 if (prev_val < new_val && new_val <= curr_val)
469 break;
471 if (prev) {
472 new_branch->next = curr;
473 prev->next = new_branch;
474 } else {
475 new_branch->next = branches;
476 branches = new_branch;
480 /* Add a dungeon branch to the branch list. */
481 STATIC_OVL branch *
482 add_branch(dgn, child_entry_level, pd)
483 int dgn;
484 int child_entry_level;
485 struct proto_dungeon *pd;
487 static int branch_id = 0;
488 int branch_num;
489 branch *new_branch;
491 branch_num = find_branch(dungeons[dgn].dname, pd);
492 new_branch = (branch *) alloc(sizeof(branch));
493 new_branch->next = (branch *) 0;
494 new_branch->id = branch_id++;
495 new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
496 new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd);
497 new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd);
498 new_branch->end2.dnum = dgn;
499 new_branch->end2.dlevel = child_entry_level;
500 new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE;
502 insert_branch(new_branch, FALSE);
503 return new_branch;
507 * Add new level to special level chain. Insert it in level order with the
508 * other levels in this dungeon. This assumes that we are never given a
509 * level that has a dungeon number less than the dungeon number of the
510 * last entry.
512 STATIC_OVL void
513 add_level(new_lev)
514 s_level *new_lev;
516 s_level *prev, *curr;
518 prev = (s_level *) 0;
519 for (curr = sp_levchn; curr; curr = curr->next) {
520 if (curr->dlevel.dnum == new_lev->dlevel.dnum
521 && curr->dlevel.dlevel > new_lev->dlevel.dlevel)
522 break;
523 prev = curr;
525 if (!prev) {
526 new_lev->next = sp_levchn;
527 sp_levchn = new_lev;
528 } else {
529 new_lev->next = curr;
530 prev->next = new_lev;
534 STATIC_OVL void
535 init_level(dgn, proto_index, pd)
536 int dgn, proto_index;
537 struct proto_dungeon *pd;
539 s_level *new_level;
540 struct tmplevel *tlevel = &pd->tmplevel[proto_index];
542 pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
543 if (!wizard && tlevel->chance <= rn2(100))
544 return;
546 pd->final_lev[proto_index] = new_level =
547 (s_level *) alloc(sizeof(s_level));
548 /* load new level with data */
549 Strcpy(new_level->proto, tlevel->name);
550 new_level->boneid = tlevel->boneschar;
551 new_level->dlevel.dnum = dgn;
552 new_level->dlevel.dlevel = 0; /* for now */
554 new_level->flags.town = !!(tlevel->flags & TOWN);
555 new_level->flags.hellish = !!(tlevel->flags & HELLISH);
556 new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
557 new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
558 new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);
559 if (!new_level->flags.align)
560 new_level->flags.align =
561 ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4);
563 new_level->rndlevs = tlevel->rndlevs;
564 new_level->next = (s_level *) 0;
567 STATIC_OVL int
568 possible_places(idx, map, pd)
569 int idx; /* prototype index */
570 boolean *map; /* array MAXLEVEL+1 in length */
571 struct proto_dungeon *pd;
573 int i, start, count;
574 s_level *lev = pd->final_lev[idx];
576 /* init level possibilities */
577 for (i = 0; i <= MAXLEVEL; i++)
578 map[i] = FALSE;
580 /* get base and range and set those entries to true */
581 count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base,
582 pd->tmplevel[idx].lev.rand, pd->tmplevel[idx].chain,
583 pd, &start);
584 for (i = start; i < start + count; i++)
585 map[i] = TRUE;
587 /* mark off already placed levels */
588 for (i = pd->start; i < idx; i++) {
589 if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) {
590 map[pd->final_lev[i]->dlevel.dlevel] = FALSE;
591 --count;
595 return count;
598 /* Pick the nth TRUE entry in the given boolean array. */
599 STATIC_OVL xchar
600 pick_level(map, nth)
601 boolean *map; /* an array MAXLEVEL+1 in size */
602 int nth;
604 int i;
605 for (i = 1; i <= MAXLEVEL; i++)
606 if (map[i] && !nth--)
607 return (xchar) i;
608 panic("pick_level: ran out of valid levels");
609 return 0;
612 #ifdef DDEBUG
613 static void FDECL(indent, (int));
615 static void
616 indent(d)
617 int d;
619 while (d-- > 0)
620 fputs(" ", stderr);
622 #endif
625 * Place a level. First, find the possible places on a dungeon map
626 * template. Next pick one. Then try to place the next level. If
627 * successful, we're done. Otherwise, try another (and another) until
628 * all possible places have been tried. If all possible places have
629 * been exhausted, return false.
631 STATIC_OVL boolean
632 place_level(proto_index, pd)
633 int proto_index;
634 struct proto_dungeon *pd;
636 boolean map[MAXLEVEL + 1]; /* valid levels are 1..MAXLEVEL inclusive */
637 s_level *lev;
638 int npossible;
639 #ifdef DDEBUG
640 int i;
641 #endif
643 if (proto_index == pd->n_levs)
644 return TRUE; /* at end of proto levels */
646 lev = pd->final_lev[proto_index];
648 /* No level created for this prototype, goto next. */
649 if (!lev)
650 return place_level(proto_index + 1, pd);
652 npossible = possible_places(proto_index, map, pd);
654 for (; npossible; --npossible) {
655 lev->dlevel.dlevel = pick_level(map, rn2(npossible));
656 #ifdef DDEBUG
657 indent(proto_index - pd->start);
658 fprintf(stderr, "%s: trying %d [ ", lev->proto, lev->dlevel.dlevel);
659 for (i = 1; i <= MAXLEVEL; i++)
660 if (map[i])
661 fprintf(stderr, "%d ", i);
662 fprintf(stderr, "]\n");
663 #endif
664 if (place_level(proto_index + 1, pd))
665 return TRUE;
666 map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */
668 #ifdef DDEBUG
669 indent(proto_index - pd->start);
670 fprintf(stderr, "%s: failed\n", lev->proto);
671 #endif
672 return FALSE;
675 struct level_map {
676 const char *lev_name;
677 d_level *lev_spec;
678 } level_map[] = { { "air", &air_level },
679 { "asmodeus", &asmodeus_level },
680 { "astral", &astral_level },
681 { "baalz", &baalzebub_level },
682 { "bigrm", &bigroom_level },
683 { "castle", &stronghold_level },
684 { "earth", &earth_level },
685 { "fakewiz1", &portal_level },
686 { "fire", &fire_level },
687 { "juiblex", &juiblex_level },
688 { "knox", &knox_level },
689 { "medusa", &medusa_level },
690 { "oracle", &oracle_level },
691 { "orcus", &orcus_level },
692 { "rogue", &rogue_level },
693 { "sanctum", &sanctum_level },
694 { "valley", &valley_level },
695 { "water", &water_level },
696 { "wizard1", &wiz1_level },
697 { "wizard2", &wiz2_level },
698 { "wizard3", &wiz3_level },
699 { "minend", &mineend_level },
700 { "soko1", &sokoend_level },
701 { X_START, &qstart_level },
702 { X_LOCATE, &qlocate_level },
703 { X_GOAL, &nemesis_level },
704 { "", (d_level *) 0 } };
706 /* initialize the "dungeon" structs */
707 void
708 init_dungeons()
710 dlb *dgn_file;
711 register int i, cl = 0, cb = 0;
712 register s_level *x;
713 struct proto_dungeon pd;
714 struct level_map *lev_map;
715 struct version_info vers_info;
717 pd.n_levs = pd.n_brs = 0;
719 dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
720 if (!dgn_file) {
721 char tbuf[BUFSZ];
722 Sprintf(tbuf, "Cannot open dungeon description - \"%s", DUNGEON_FILE);
723 #ifdef DLBRSRC /* using a resource from the executable */
724 Strcat(tbuf, "\" resource!");
725 #else /* using a file or DLB file */
726 #if defined(DLB)
727 Strcat(tbuf, "\" from ");
728 #ifdef PREFIXES_IN_USE
729 Strcat(tbuf, "\n\"");
730 if (fqn_prefix[DATAPREFIX])
731 Strcat(tbuf, fqn_prefix[DATAPREFIX]);
732 #else
733 Strcat(tbuf, "\"");
734 #endif
735 Strcat(tbuf, DLBFILE);
736 #endif
737 Strcat(tbuf, "\" file!");
738 #endif
739 #ifdef WIN32
740 interject_assistance(1, INTERJECT_PANIC, (genericptr_t) tbuf,
741 (genericptr_t) fqn_prefix[DATAPREFIX]);
742 #endif
743 panic1(tbuf);
746 /* validate the data's version against the program's version */
747 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file);
748 /* we'd better clear the screen now, since when error messages come from
749 * check_version() they will be printed using pline(), which doesn't
750 * mix with the raw messages that might be already on the screen
752 if (iflags.window_inited)
753 clear_nhwindow(WIN_MAP);
754 if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
755 panic("Dungeon description not valid.");
758 * Read in each dungeon and transfer the results to the internal
759 * dungeon arrays.
761 sp_levchn = (s_level *) 0;
762 Fread((genericptr_t) &n_dgns, sizeof(int), 1, dgn_file);
763 if (n_dgns >= MAXDUNGEON)
764 panic("init_dungeons: too many dungeons");
766 for (i = 0; i < n_dgns; i++) {
767 Fread((genericptr_t) &pd.tmpdungeon[i], sizeof(struct tmpdungeon), 1,
768 dgn_file);
769 if (!wizard && pd.tmpdungeon[i].chance
770 && (pd.tmpdungeon[i].chance <= rn2(100))) {
771 int j;
773 /* skip over any levels or branches */
774 for (j = 0; j < pd.tmpdungeon[i].levels; j++)
775 Fread((genericptr_t) &pd.tmplevel[cl],
776 sizeof(struct tmplevel), 1, dgn_file);
778 for (j = 0; j < pd.tmpdungeon[i].branches; j++)
779 Fread((genericptr_t) &pd.tmpbranch[cb],
780 sizeof(struct tmpbranch), 1, dgn_file);
781 n_dgns--;
782 i--;
783 continue;
786 Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name);
787 Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname);
788 dungeons[i].boneid = pd.tmpdungeon[i].boneschar;
790 if (pd.tmpdungeon[i].lev.rand)
791 dungeons[i].num_dunlevs = (xchar) rn1(pd.tmpdungeon[i].lev.rand,
792 pd.tmpdungeon[i].lev.base);
793 else
794 dungeons[i].num_dunlevs = (xchar) pd.tmpdungeon[i].lev.base;
796 if (!i) {
797 dungeons[i].ledger_start = 0;
798 dungeons[i].depth_start = 1;
799 dungeons[i].dunlev_ureached = 1;
800 } else {
801 dungeons[i].ledger_start =
802 dungeons[i - 1].ledger_start + dungeons[i - 1].num_dunlevs;
803 dungeons[i].dunlev_ureached = 0;
806 dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH);
807 dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE);
808 dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE);
809 dungeons[i].flags.align =
810 ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4);
812 * Set the entry level for this dungeon. The pd.tmpdungeon entry
813 * value means:
814 * < 0 from bottom (-1 == bottom level)
815 * 0 default (top)
816 * > 0 actual level (1 = top)
818 * Note that the entry_lev field in the dungeon structure is
819 * redundant. It is used only here and in print_dungeon().
821 if (pd.tmpdungeon[i].entry_lev < 0) {
822 dungeons[i].entry_lev =
823 dungeons[i].num_dunlevs + pd.tmpdungeon[i].entry_lev + 1;
824 if (dungeons[i].entry_lev <= 0)
825 dungeons[i].entry_lev = 1;
826 } else if (pd.tmpdungeon[i].entry_lev > 0) {
827 dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
828 if (dungeons[i].entry_lev > dungeons[i].num_dunlevs)
829 dungeons[i].entry_lev = dungeons[i].num_dunlevs;
830 } else { /* default */
831 dungeons[i].entry_lev = 1; /* defaults to top level */
834 if (i) { /* set depth */
835 branch *br;
836 schar from_depth;
837 boolean from_up;
839 br = add_branch(i, dungeons[i].entry_lev, &pd);
841 /* Get the depth of the connecting end. */
842 if (br->end1.dnum == i) {
843 from_depth = depth(&br->end2);
844 from_up = !br->end1_up;
845 } else {
846 from_depth = depth(&br->end1);
847 from_up = br->end1_up;
851 * Calculate the depth of the top of the dungeon via
852 * its branch. First, the depth of the entry point:
854 * depth of branch from "parent" dungeon
855 * + -1 or 1 depending on a up or down stair or
856 * 0 if portal
858 * Followed by the depth of the top of the dungeon:
860 * - (entry depth - 1)
862 * We'll say that portals stay on the same depth.
864 dungeons[i].depth_start =
865 from_depth + (br->type == BR_PORTAL ? 0 : (from_up ? -1 : 1))
866 - (dungeons[i].entry_lev - 1);
869 /* this is redundant - it should have been flagged by dgn_comp */
870 if (dungeons[i].num_dunlevs > MAXLEVEL)
871 dungeons[i].num_dunlevs = MAXLEVEL;
873 pd.start = pd.n_levs; /* save starting point */
874 pd.n_levs += pd.tmpdungeon[i].levels;
875 if (pd.n_levs > LEV_LIMIT)
876 panic("init_dungeon: too many special levels");
878 * Read in the prototype special levels. Don't add generated
879 * special levels until they are all placed.
881 for (; cl < pd.n_levs; cl++) {
882 Fread((genericptr_t) &pd.tmplevel[cl], sizeof(struct tmplevel), 1,
883 dgn_file);
884 init_level(i, cl, &pd);
887 * Recursively place the generated levels for this dungeon. This
888 * routine will attempt all possible combinations before giving
889 * up.
891 if (!place_level(pd.start, &pd))
892 panic("init_dungeon: couldn't place levels");
893 #ifdef DDEBUG
894 fprintf(stderr, "--- end of dungeon %d ---\n", i);
895 fflush(stderr);
896 getchar();
897 #endif
898 for (; pd.start < pd.n_levs; pd.start++)
899 if (pd.final_lev[pd.start])
900 add_level(pd.final_lev[pd.start]);
902 pd.n_brs += pd.tmpdungeon[i].branches;
903 if (pd.n_brs > BRANCH_LIMIT)
904 panic("init_dungeon: too many branches");
905 for (; cb < pd.n_brs; cb++)
906 Fread((genericptr_t) &pd.tmpbranch[cb], sizeof(struct tmpbranch),
907 1, dgn_file);
909 (void) dlb_fclose(dgn_file);
911 for (i = 0; i < 5; i++)
912 tune[i] = 'A' + rn2(7);
913 tune[5] = 0;
916 * Find most of the special levels and dungeons so we can access their
917 * locations quickly.
919 for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
920 x = find_level(lev_map->lev_name);
921 if (x) {
922 assign_level(lev_map->lev_spec, &x->dlevel);
923 if (!strncmp(lev_map->lev_name, "x-", 2)) {
924 /* This is where the name substitution on the
925 * levels of the quest dungeon occur.
927 Sprintf(x->proto, "%s%s", urole.filecode,
928 &lev_map->lev_name[1]);
929 } else if (lev_map->lev_spec == &knox_level) {
930 branch *br;
932 * Kludge to allow floating Knox entrance. We
933 * specify a floating entrance by the fact that
934 * its entrance (end1) has a bogus dnum, namely
935 * n_dgns.
937 for (br = branches; br; br = br->next)
938 if (on_level(&br->end2, &knox_level))
939 break;
941 if (br)
942 br->end1.dnum = n_dgns;
943 /* adjust the branch's position on the list */
944 insert_branch(br, TRUE);
949 * I hate hardwiring these names. :-(
951 quest_dnum = dname_to_dnum("The Quest");
952 sokoban_dnum = dname_to_dnum("Sokoban");
953 mines_dnum = dname_to_dnum("The Gnomish Mines");
954 tower_dnum = dname_to_dnum("Vlad's Tower");
956 /* one special fixup for dummy surface level */
957 if ((x = find_level("dummy")) != 0) {
958 i = x->dlevel.dnum;
959 /* the code above puts earth one level above dungeon level #1,
960 making the dummy level overlay level 1; but the whole reason
961 for having the dummy level is to make earth have depth -1
962 instead of 0, so adjust the start point to shift endgame up */
963 if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start)
964 dungeons[i].depth_start -= 1;
965 /* TO DO: strip "dummy" out all the way here,
966 so that it's hidden from <ctrl/O> feedback. */
969 #ifdef DEBUG
970 dumpit();
971 #endif
974 /* return the level number for lev in *this* dungeon */
975 xchar
976 dunlev(lev)
977 d_level *lev;
979 return lev->dlevel;
982 /* return the lowest level number for *this* dungeon */
983 xchar
984 dunlevs_in_dungeon(lev)
985 d_level *lev;
987 return dungeons[lev->dnum].num_dunlevs;
990 /* return the lowest level explored in the game*/
991 xchar
992 deepest_lev_reached(noquest)
993 boolean noquest;
995 /* this function is used for three purposes: to provide a factor
996 * of difficulty in monster generation; to provide a factor of
997 * difficulty in experience calculations (botl.c and end.c); and
998 * to insert the deepest level reached in the game in the topten
999 * display. the 'noquest' arg switch is required for the latter.
1001 * from the player's point of view, going into the Quest is _not_
1002 * going deeper into the dungeon -- it is going back "home", where
1003 * the dungeon starts at level 1. given the setup in dungeon.def,
1004 * the depth of the Quest (thought of as starting at level 1) is
1005 * never lower than the level of entry into the Quest, so we exclude
1006 * the Quest from the topten "deepest level reached" display
1007 * calculation. _However_ the Quest is a difficult dungeon, so we
1008 * include it in the factor of difficulty calculations.
1010 register int i;
1011 d_level tmp;
1012 register schar ret = 0;
1014 for (i = 0; i < n_dgns; i++) {
1015 if (noquest && i == quest_dnum)
1016 continue;
1017 tmp.dlevel = dungeons[i].dunlev_ureached;
1018 if (tmp.dlevel == 0)
1019 continue;
1020 tmp.dnum = i;
1021 if (depth(&tmp) > ret)
1022 ret = depth(&tmp);
1024 return (xchar) ret;
1027 /* return a bookkeeping level number for purpose of comparisons and
1028 save/restore */
1029 xchar
1030 ledger_no(lev)
1031 d_level *lev;
1033 return (xchar) (lev->dlevel + dungeons[lev->dnum].ledger_start);
1037 * The last level in the bookkeeping list of level is the bottom of the last
1038 * dungeon in the dungeons[] array.
1040 * Maxledgerno() -- which is the max number of levels in the bookkeeping
1041 * list, should not be confused with dunlevs_in_dungeon(lev) -- which
1042 * returns the max number of levels in lev's dungeon, and both should
1043 * not be confused with deepest_lev_reached() -- which returns the lowest
1044 * depth visited by the player.
1046 xchar
1047 maxledgerno()
1049 return (xchar) (dungeons[n_dgns - 1].ledger_start
1050 + dungeons[n_dgns - 1].num_dunlevs);
1053 /* return the dungeon that this ledgerno exists in */
1054 xchar
1055 ledger_to_dnum(ledgerno)
1056 xchar ledgerno;
1058 register int i;
1060 /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */
1061 for (i = 0; i < n_dgns; i++)
1062 if (dungeons[i].ledger_start < ledgerno
1063 && ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs)
1064 return (xchar) i;
1066 panic("level number out of range [ledger_to_dnum(%d)]", (int) ledgerno);
1067 /*NOT REACHED*/
1068 return (xchar) 0;
1071 /* return the level of the dungeon this ledgerno exists in */
1072 xchar
1073 ledger_to_dlev(ledgerno)
1074 xchar ledgerno;
1076 return (xchar) (ledgerno
1077 - dungeons[ledger_to_dnum(ledgerno)].ledger_start);
1080 /* returns the depth of a level, in floors below the surface
1081 (note levels in different dungeons can have the same depth) */
1082 schar
1083 depth(lev)
1084 d_level *lev;
1086 return (schar) (dungeons[lev->dnum].depth_start + lev->dlevel - 1);
1089 /* are "lev1" and "lev2" actually the same? */
1090 boolean
1091 on_level(lev1, lev2)
1092 d_level *lev1, *lev2;
1094 return (boolean) (lev1->dnum == lev2->dnum
1095 && lev1->dlevel == lev2->dlevel);
1098 /* is this level referenced in the special level chain? */
1099 s_level *
1100 Is_special(lev)
1101 d_level *lev;
1103 s_level *levtmp;
1105 for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
1106 if (on_level(lev, &levtmp->dlevel))
1107 return levtmp;
1109 return (s_level *) 0;
1113 * Is this a multi-dungeon branch level? If so, return a pointer to the
1114 * branch. Otherwise, return null.
1116 branch *
1117 Is_branchlev(lev)
1118 d_level *lev;
1120 branch *curr;
1122 for (curr = branches; curr; curr = curr->next) {
1123 if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
1124 return curr;
1126 return (branch *) 0;
1129 /* returns True iff the branch 'lev' is in a branch which builds up */
1130 boolean
1131 builds_up(lev)
1132 d_level *lev;
1134 dungeon *dptr = &dungeons[lev->dnum];
1136 * FIXME: this misclassifies a single level branch reached via stairs
1137 * from below. Saving grace is that no such branches currently exist.
1139 return (boolean) (dptr->num_dunlevs > 1
1140 && dptr->entry_lev == dptr->num_dunlevs);
1143 /* goto the next level (or appropriate dungeon) */
1144 void
1145 next_level(at_stairs)
1146 boolean at_stairs;
1148 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1149 /* Taking a down dungeon branch. */
1150 goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1151 } else {
1152 /* Going down a stairs or jump in a trap door. */
1153 d_level newlevel;
1155 newlevel.dnum = u.uz.dnum;
1156 newlevel.dlevel = u.uz.dlevel + 1;
1157 goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
1161 /* goto the previous level (or appropriate dungeon) */
1162 void
1163 prev_level(at_stairs)
1164 boolean at_stairs;
1166 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1167 /* Taking an up dungeon branch. */
1168 /* KMH -- Upwards branches are okay if not level 1 */
1169 /* (Just make sure it doesn't go above depth 1) */
1170 if (!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet)
1171 done(ESCAPED);
1172 else
1173 goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1174 } else {
1175 /* Going up a stairs or rising through the ceiling. */
1176 d_level newlevel;
1177 newlevel.dnum = u.uz.dnum;
1178 newlevel.dlevel = u.uz.dlevel - 1;
1179 goto_level(&newlevel, at_stairs, FALSE, FALSE);
1183 void
1184 u_on_newpos(x, y)
1185 int x, y;
1187 u.ux = x;
1188 u.uy = y;
1189 #ifdef CLIPPING
1190 cliparound(u.ux, u.uy);
1191 #endif
1192 /* ridden steed always shares hero's location */
1193 if (u.usteed)
1194 u.usteed->mx = u.ux, u.usteed->my = u.uy;
1195 /* when changing levels, don't leave old position set with
1196 stale values from previous level */
1197 if (!on_level(&u.uz, &u.uz0))
1198 u.ux0 = u.ux, u.uy0 = u.uy;
1201 /* place you on a random location */
1202 void
1203 u_on_rndspot(upflag)
1204 int upflag;
1206 int up = (upflag & 1), was_in_W_tower = (upflag & 2);
1209 * Place the hero at a random location within the relevant region.
1210 * place_lregion(xTELE) -> put_lregion_here(xTELE) -> u_on_newpos()
1211 * Unspecified region (.lx == 0) defaults to entire level.
1213 if (was_in_W_tower && On_W_tower_level(&u.uz))
1214 /* Stay inside the Wizard's tower when feasible.
1215 We use the W Tower's exclusion region for the
1216 destination instead of its enclosing region.
1217 Note: up vs down doesn't matter in this case
1218 because both specify the same exclusion area. */
1219 place_lregion(dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy, 0, 0, 0,
1220 0, LR_DOWNTELE, (d_level *) 0);
1221 else if (up)
1222 place_lregion(updest.lx, updest.ly, updest.hx, updest.hy, updest.nlx,
1223 updest.nly, updest.nhx, updest.nhy, LR_UPTELE,
1224 (d_level *) 0);
1225 else
1226 place_lregion(dndest.lx, dndest.ly, dndest.hx, dndest.hy, dndest.nlx,
1227 dndest.nly, dndest.nhx, dndest.nhy, LR_DOWNTELE,
1228 (d_level *) 0);
1231 /* place you on the special staircase */
1232 void
1233 u_on_sstairs(upflag)
1234 int upflag;
1236 if (sstairs.sx)
1237 u_on_newpos(sstairs.sx, sstairs.sy);
1238 else
1239 u_on_rndspot(upflag);
1242 /* place you on upstairs (or special equivalent) */
1243 void
1244 u_on_upstairs()
1246 if (xupstair)
1247 u_on_newpos(xupstair, yupstair);
1248 else
1249 u_on_sstairs(0); /* destination upstairs implies moving down */
1252 /* place you on dnstairs (or special equivalent) */
1253 void
1254 u_on_dnstairs()
1256 if (xdnstair)
1257 u_on_newpos(xdnstair, ydnstair);
1258 else
1259 u_on_sstairs(1); /* destination dnstairs implies moving up */
1262 boolean
1263 On_stairs(x, y)
1264 xchar x, y;
1266 return (boolean) ((x == xupstair && y == yupstair)
1267 || (x == xdnstair && y == ydnstair)
1268 || (x == xdnladder && y == ydnladder)
1269 || (x == xupladder && y == yupladder)
1270 || (x == sstairs.sx && y == sstairs.sy));
1273 boolean
1274 Is_botlevel(lev)
1275 d_level *lev;
1277 return (boolean) (lev->dlevel == dungeons[lev->dnum].num_dunlevs);
1280 boolean
1281 Can_dig_down(lev)
1282 d_level *lev;
1284 return (boolean) (!level.flags.hardfloor
1285 && !Is_botlevel(lev)
1286 && !Invocation_lev(lev));
1290 * Like Can_dig_down (above), but also allows falling through on the
1291 * stronghold level. Normally, the bottom level of a dungeon resists
1292 * both digging and falling.
1294 boolean
1295 Can_fall_thru(lev)
1296 d_level *lev;
1298 return (boolean) (Can_dig_down(lev) || Is_stronghold(lev));
1302 * True if one can rise up a level (e.g. cursed gain level).
1303 * This happens on intermediate dungeon levels or on any top dungeon
1304 * level that has a stairwell style branch to the next higher dungeon.
1305 * Checks for amulets and such must be done elsewhere.
1307 boolean
1308 Can_rise_up(x, y, lev)
1309 int x, y;
1310 d_level *lev;
1312 /* can't rise up from inside the top of the Wizard's tower */
1313 /* KMH -- or in sokoban */
1314 if (In_endgame(lev) || In_sokoban(lev)
1315 || (Is_wiz1_level(lev) && In_W_tower(x, y, lev)))
1316 return FALSE;
1317 return (boolean) (lev->dlevel > 1
1318 || (dungeons[lev->dnum].entry_lev == 1
1319 && ledger_no(lev) != 1
1320 && sstairs.sx && sstairs.up));
1323 boolean
1324 has_ceiling(lev)
1325 d_level *lev;
1327 /* [what about level 1 of the quest?] */
1328 return (boolean) (!Is_airlevel(lev) && !Is_waterlevel(lev));
1332 * It is expected that the second argument of get_level is a depth value,
1333 * either supplied by the user (teleport control) or randomly generated.
1334 * But more than one level can be at the same depth. If the target level
1335 * is "above" the present depth location, get_level must trace "up" from
1336 * the player's location (through the ancestors dungeons) the dungeon
1337 * within which the target level is located. With only one exception
1338 * which does not pass through this routine (see level_tele), teleporting
1339 * "down" is confined to the current dungeon. At present, level teleport
1340 * in dungeons that build up is confined within them.
1342 void
1343 get_level(newlevel, levnum)
1344 d_level *newlevel;
1345 int levnum;
1347 branch *br;
1348 xchar dgn = u.uz.dnum;
1350 if (levnum <= 0) {
1351 /* can only currently happen in endgame */
1352 levnum = u.uz.dlevel;
1353 } else if (levnum
1354 > dungeons[dgn].depth_start + dungeons[dgn].num_dunlevs - 1) {
1355 /* beyond end of dungeon, jump to last level */
1356 levnum = dungeons[dgn].num_dunlevs;
1357 } else {
1358 /* The desired level is in this dungeon or a "higher" one. */
1361 * Branch up the tree until we reach a dungeon that contains the
1362 * levnum.
1364 if (levnum < dungeons[dgn].depth_start) {
1365 do {
1367 * Find the parent dungeon of this dungeon.
1369 * This assumes that end2 is always the "child" and it is
1370 * unique.
1372 for (br = branches; br; br = br->next)
1373 if (br->end2.dnum == dgn)
1374 break;
1375 if (!br)
1376 panic("get_level: can't find parent dungeon");
1378 dgn = br->end1.dnum;
1379 } while (levnum < dungeons[dgn].depth_start);
1382 /* We're within the same dungeon; calculate the level. */
1383 levnum = levnum - dungeons[dgn].depth_start + 1;
1386 newlevel->dnum = dgn;
1387 newlevel->dlevel = levnum;
1390 /* are you in the quest dungeon? */
1391 boolean
1392 In_quest(lev)
1393 d_level *lev;
1395 return (boolean) (lev->dnum == quest_dnum);
1398 /* are you in the mines dungeon? */
1399 boolean
1400 In_mines(lev)
1401 d_level *lev;
1403 return (boolean) (lev->dnum == mines_dnum);
1407 * Return the branch for the given dungeon.
1409 * This function assumes:
1410 * + This is not called with "Dungeons of Doom".
1411 * + There is only _one_ branch to a given dungeon.
1412 * + Field end2 is the "child" dungeon.
1414 branch *
1415 dungeon_branch(s)
1416 const char *s;
1418 branch *br;
1419 xchar dnum;
1421 dnum = dname_to_dnum(s);
1423 /* Find the branch that connects to dungeon i's branch. */
1424 for (br = branches; br; br = br->next)
1425 if (br->end2.dnum == dnum)
1426 break;
1428 if (!br)
1429 panic("dgn_entrance: can't find entrance to %s", s);
1431 return br;
1435 * This returns true if the hero is on the same level as the entrance to
1436 * the named dungeon.
1438 * Called from do.c and mklev.c.
1440 * Assumes that end1 is always the "parent".
1442 boolean
1443 at_dgn_entrance(s)
1444 const char *s;
1446 branch *br;
1448 br = dungeon_branch(s);
1449 return on_level(&u.uz, &br->end1) ? TRUE : FALSE;
1452 /* is `lev' part of Vlad's tower? */
1453 boolean
1454 In_V_tower(lev)
1455 d_level *lev;
1457 return (boolean) (lev->dnum == tower_dnum);
1460 /* is `lev' a level containing the Wizard's tower? */
1461 boolean
1462 On_W_tower_level(lev)
1463 d_level *lev;
1465 return (boolean) (Is_wiz1_level(lev)
1466 || Is_wiz2_level(lev)
1467 || Is_wiz3_level(lev));
1470 /* is <x,y> of `lev' inside the Wizard's tower? */
1471 boolean
1472 In_W_tower(x, y, lev)
1473 int x, y;
1474 d_level *lev;
1476 if (!On_W_tower_level(lev))
1477 return FALSE;
1479 * Both of the exclusion regions for arriving via level teleport
1480 * (from above or below) define the tower's boundary.
1481 * assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} );
1483 if (dndest.nlx > 0)
1484 return (boolean) within_bounded_area(x, y, dndest.nlx, dndest.nly,
1485 dndest.nhx, dndest.nhy);
1486 else
1487 impossible("No boundary for Wizard's Tower?");
1488 return FALSE;
1491 /* are you in one of the Hell levels? */
1492 boolean
1493 In_hell(lev)
1494 d_level *lev;
1496 return (boolean) (dungeons[lev->dnum].flags.hellish);
1499 /* sets *lev to be the gateway to Gehennom... */
1500 void
1501 find_hell(lev)
1502 d_level *lev;
1504 lev->dnum = valley_level.dnum;
1505 lev->dlevel = 1;
1508 /* go directly to hell... */
1509 void
1510 goto_hell(at_stairs, falling)
1511 boolean at_stairs, falling;
1513 d_level lev;
1515 find_hell(&lev);
1516 goto_level(&lev, at_stairs, falling, FALSE);
1519 /* equivalent to dest = source */
1520 void
1521 assign_level(dest, src)
1522 d_level *dest, *src;
1524 dest->dnum = src->dnum;
1525 dest->dlevel = src->dlevel;
1528 /* dest = src + rn1(range) */
1529 void
1530 assign_rnd_level(dest, src, range)
1531 d_level *dest, *src;
1532 int range;
1534 dest->dnum = src->dnum;
1535 dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range));
1537 if (dest->dlevel > dunlevs_in_dungeon(dest))
1538 dest->dlevel = dunlevs_in_dungeon(dest);
1539 else if (dest->dlevel < 1)
1540 dest->dlevel = 1;
1544 induced_align(pct)
1545 int pct;
1547 s_level *lev = Is_special(&u.uz);
1548 aligntyp al;
1550 if (lev && lev->flags.align)
1551 if (rn2(100) < pct)
1552 return lev->flags.align;
1554 if (dungeons[u.uz.dnum].flags.align)
1555 if (rn2(100) < pct)
1556 return dungeons[u.uz.dnum].flags.align;
1558 al = rn2(3) - 1;
1559 return Align2amask(al);
1562 boolean
1563 Invocation_lev(lev)
1564 d_level *lev;
1566 return (boolean) (In_hell(lev)
1567 && lev->dlevel == dungeons[lev->dnum].num_dunlevs - 1);
1570 /* use instead of depth() wherever a degree of difficulty is made
1571 * dependent on the location in the dungeon (eg. monster creation).
1573 xchar
1574 level_difficulty()
1576 int res;
1578 if (In_endgame(&u.uz)) {
1579 res = depth(&sanctum_level) + u.ulevel / 2;
1580 } else if (u.uhave.amulet) {
1581 res = deepest_lev_reached(FALSE);
1582 } else {
1583 res = depth(&u.uz);
1584 /* depth() is the number of elevation units (levels) below
1585 the theoretical surface; in a builds-up branch, that value
1586 ends up making the harder to reach levels be treated as if
1587 they were easier; adjust for the extra effort involved in
1588 going down to the entrance and then up to the location */
1589 if (builds_up(&u.uz))
1590 res += 2 * (dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1);
1592 * 'Proof' by example: suppose the entrance to sokoban is
1593 * on dungeon level 9, leading up to bottom sokoban level
1594 * of 8 [entry_lev]. When the hero is on sokoban level 8
1595 * [uz.dlevel], depth() yields eight but he has ventured
1596 * one level beyond 9, so difficulty depth should be 10:
1597 * 8 + 2 * (8 - 8 + 1) => 10.
1598 * Going up to 7, depth is 7 but hero will be two beyond 9:
1599 * 7 + 2 * (8 - 7 + 1) => 11.
1600 * When he goes up to level 6, three levels beyond 9:
1601 * 6 + 2 * (8 - 6 + 1) => 12.
1602 * And the top level of sokoban at 5, four levels beyond 9:
1603 * 5 + 2 * (8 - 5 + 1) => 13.
1604 * The same applies to Vlad's Tower, although the increment
1605 * there is inconsequential compared to overall depth.
1608 return (xchar) res;
1611 /* Take one word and try to match it to a level.
1612 * Recognized levels are as shown by print_dungeon().
1614 schar
1615 lev_by_name(nam)
1616 const char *nam;
1618 schar lev = 0;
1619 s_level *slev;
1620 d_level dlev;
1621 const char *p;
1622 int idx, idxtoo;
1623 char buf[BUFSZ];
1625 /* allow strings like "the oracle level" to find "oracle" */
1626 if (!strncmpi(nam, "the ", 4))
1627 nam += 4;
1628 if ((p = strstri(nam, " level")) != 0 && p == eos((char *) nam) - 6) {
1629 nam = strcpy(buf, nam);
1630 *(eos(buf) - 6) = '\0';
1632 /* hell is the old name, and wouldn't match; gehennom would match its
1633 branch, yielding the castle level instead of the valley of the dead */
1634 if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) {
1635 if (In_V_tower(&u.uz))
1636 nam = " to Vlad's tower"; /* branch to... */
1637 else
1638 nam = "valley";
1641 if ((slev = find_level(nam)) != 0) {
1642 dlev = slev->dlevel;
1643 idx = ledger_no(&dlev);
1644 if ((dlev.dnum == u.uz.dnum
1645 /* within same branch, or else main dungeon <-> gehennom */
1646 || (u.uz.dnum == valley_level.dnum
1647 && dlev.dnum == medusa_level.dnum)
1648 || (u.uz.dnum == medusa_level.dnum
1649 && dlev.dnum == valley_level.dnum))
1650 && (/* either wizard mode or else seen and not forgotten */
1651 wizard
1652 || (level_info[idx].flags & (FORGOTTEN | VISITED))
1653 == VISITED)) {
1654 lev = depth(&slev->dlevel);
1656 } else { /* not a specific level; try branch names */
1657 idx = find_branch(nam, (struct proto_dungeon *) 0);
1658 /* "<branch> to Xyzzy" */
1659 if (idx < 0 && (p = strstri(nam, " to ")) != 0)
1660 idx = find_branch(p + 4, (struct proto_dungeon *) 0);
1662 if (idx >= 0) {
1663 idxtoo = (idx >> 8) & 0x00FF;
1664 idx &= 0x00FF;
1665 if (/* either wizard mode, or else _both_ sides of branch seen */
1666 wizard
1667 || ((level_info[idx].flags & (FORGOTTEN | VISITED)) == VISITED
1668 && (level_info[idxtoo].flags & (FORGOTTEN | VISITED))
1669 == VISITED)) {
1670 if (ledger_to_dnum(idxtoo) == u.uz.dnum)
1671 idx = idxtoo;
1672 dlev.dnum = ledger_to_dnum(idx);
1673 dlev.dlevel = ledger_to_dlev(idx);
1674 lev = depth(&dlev);
1678 return lev;
1681 STATIC_OVL boolean
1682 unplaced_floater(dptr)
1683 struct dungeon *dptr;
1685 branch *br;
1686 int idx = (int) (dptr - dungeons);
1688 /* if other floating branches are added, this will need to change */
1689 if (idx != knox_level.dnum)
1690 return FALSE;
1691 for (br = branches; br; br = br->next)
1692 if (br->end1.dnum == n_dgns && br->end2.dnum == idx)
1693 return TRUE;
1694 return FALSE;
1697 STATIC_OVL boolean
1698 unreachable_level(lvl_p, unplaced)
1699 d_level *lvl_p;
1700 boolean unplaced;
1702 s_level *dummy;
1704 if (unplaced)
1705 return TRUE;
1706 if (In_endgame(&u.uz) && !In_endgame(lvl_p))
1707 return TRUE;
1708 if ((dummy = find_level("dummy")) != 0 && on_level(lvl_p, &dummy->dlevel))
1709 return TRUE;
1710 return FALSE;
1713 static void
1714 tport_menu(win, entry, lchoices, lvl_p, unreachable)
1715 winid win;
1716 char *entry;
1717 struct lchoice *lchoices;
1718 d_level *lvl_p;
1719 boolean unreachable;
1721 char tmpbuf[BUFSZ];
1722 anything any;
1724 lchoices->lev[lchoices->idx] = lvl_p->dlevel;
1725 lchoices->dgn[lchoices->idx] = lvl_p->dnum;
1726 lchoices->playerlev[lchoices->idx] = depth(lvl_p);
1727 any = zeroany;
1728 if (unreachable) {
1729 /* not selectable, but still consumes next menuletter;
1730 prepend padding in place of missing menu selector */
1731 Sprintf(tmpbuf, " %s", entry);
1732 entry = tmpbuf;
1733 } else {
1734 any.a_int = lchoices->idx + 1;
1736 add_menu(win, NO_GLYPH, &any, lchoices->menuletter, 0, ATR_NONE, entry,
1737 MENU_UNSELECTED);
1738 /* this assumes there are at most 52 interesting levels */
1739 if (lchoices->menuletter == 'z')
1740 lchoices->menuletter = 'A';
1741 else
1742 lchoices->menuletter++;
1743 lchoices->idx++;
1744 return;
1747 /* Convert a branch type to a string usable by print_dungeon(). */
1748 STATIC_OVL const char *
1749 br_string(type)
1750 int type;
1752 switch (type) {
1753 case BR_PORTAL:
1754 return "Portal";
1755 case BR_NO_END1:
1756 return "Connection";
1757 case BR_NO_END2:
1758 return "One way stair";
1759 case BR_STAIR:
1760 return "Stair";
1762 return " (unknown)";
1765 /* Print all child branches between the lower and upper bounds. */
1766 STATIC_OVL void
1767 print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices_p)
1768 winid win;
1769 int dnum;
1770 int lower_bound;
1771 int upper_bound;
1772 boolean bymenu;
1773 struct lchoice *lchoices_p;
1775 branch *br;
1776 char buf[BUFSZ];
1778 /* This assumes that end1 is the "parent". */
1779 for (br = branches; br; br = br->next) {
1780 if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel
1781 && br->end1.dlevel <= upper_bound) {
1782 Sprintf(buf, " %s to %s: %d", br_string(br->type),
1783 dungeons[br->end2.dnum].dname, depth(&br->end1));
1784 if (bymenu)
1785 tport_menu(win, buf, lchoices_p, &br->end1,
1786 unreachable_level(&br->end1, FALSE));
1787 else
1788 putstr(win, 0, buf);
1793 /* Print available dungeon information. */
1794 schar
1795 print_dungeon(bymenu, rlev, rdgn)
1796 boolean bymenu;
1797 schar *rlev;
1798 xchar *rdgn;
1800 int i, last_level, nlev;
1801 char buf[BUFSZ];
1802 const char *descr;
1803 boolean first, unplaced;
1804 s_level *slev;
1805 dungeon *dptr;
1806 branch *br;
1807 anything any;
1808 struct lchoice lchoices;
1810 winid win = create_nhwindow(NHW_MENU);
1811 if (bymenu) {
1812 start_menu(win);
1813 lchoices.idx = 0;
1814 lchoices.menuletter = 'a';
1817 for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
1818 if (bymenu && In_endgame(&u.uz) && i != astral_level.dnum)
1819 continue;
1820 unplaced = unplaced_floater(dptr);
1821 descr = unplaced ? "depth" : "level";
1822 nlev = dptr->num_dunlevs;
1823 if (nlev > 1)
1824 Sprintf(buf, "%s: %s %d to %d", dptr->dname, makeplural(descr),
1825 dptr->depth_start, dptr->depth_start + nlev - 1);
1826 else
1827 Sprintf(buf, "%s: %s %d", dptr->dname, descr, dptr->depth_start);
1829 /* Most entrances are uninteresting. */
1830 if (dptr->entry_lev != 1) {
1831 if (dptr->entry_lev == nlev)
1832 Strcat(buf, ", entrance from below");
1833 else
1834 Sprintf(eos(buf), ", entrance on %d",
1835 dptr->depth_start + dptr->entry_lev - 1);
1837 if (bymenu) {
1838 any = zeroany;
1839 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf,
1840 MENU_UNSELECTED);
1841 } else
1842 putstr(win, 0, buf);
1845 * Circle through the special levels to find levels that are in
1846 * this dungeon.
1848 for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
1849 if (slev->dlevel.dnum != i)
1850 continue;
1852 /* print any branches before this level */
1853 print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu,
1854 &lchoices);
1856 Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel));
1857 if (Is_stronghold(&slev->dlevel))
1858 Sprintf(eos(buf), " (tune %s)", tune);
1859 if (bymenu)
1860 tport_menu(win, buf, &lchoices, &slev->dlevel,
1861 unreachable_level(&slev->dlevel, unplaced));
1862 else
1863 putstr(win, 0, buf);
1865 last_level = slev->dlevel.dlevel;
1867 /* print branches after the last special level */
1868 print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices);
1871 if (bymenu) {
1872 int n;
1873 menu_item *selected;
1874 int idx;
1876 end_menu(win, "Level teleport to where:");
1877 n = select_menu(win, PICK_ONE, &selected);
1878 destroy_nhwindow(win);
1879 if (n > 0) {
1880 idx = selected[0].item.a_int - 1;
1881 free((genericptr_t) selected);
1882 if (rlev && rdgn) {
1883 *rlev = lchoices.lev[idx];
1884 *rdgn = lchoices.dgn[idx];
1885 return lchoices.playerlev[idx];
1888 return 0;
1891 /* Print out floating branches (if any). */
1892 for (first = TRUE, br = branches; br; br = br->next) {
1893 if (br->end1.dnum == n_dgns) {
1894 if (first) {
1895 putstr(win, 0, "");
1896 putstr(win, 0, "Floating branches");
1897 first = FALSE;
1899 Sprintf(buf, " %s to %s", br_string(br->type),
1900 dungeons[br->end2.dnum].dname);
1901 putstr(win, 0, buf);
1905 /* I hate searching for the invocation pos while debugging. -dean */
1906 if (Invocation_lev(&u.uz)) {
1907 putstr(win, 0, "");
1908 Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)",
1909 inv_pos.x, inv_pos.y, u.ux, u.uy);
1910 putstr(win, 0, buf);
1913 * The following is based on the assumption that the inter-level portals
1914 * created by the level compiler (not the dungeon compiler) only exist
1915 * one per level (currently true, of course).
1917 else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
1918 || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
1919 struct trap *trap;
1920 for (trap = ftrap; trap; trap = trap->ntrap)
1921 if (trap->ttyp == MAGIC_PORTAL)
1922 break;
1924 putstr(win, 0, "");
1925 if (trap)
1926 Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)", trap->tx,
1927 trap->ty, u.ux, u.uy);
1928 else
1929 Sprintf(buf, "No portal found.");
1930 putstr(win, 0, buf);
1933 display_nhwindow(win, TRUE);
1934 destroy_nhwindow(win);
1935 return 0;
1938 /* Record that the player knows about a branch from a level. This function
1939 * will determine whether or not it was a "real" branch that was taken.
1940 * This function should not be called for a transition done via level
1941 * teleport or via the Eye.
1943 void
1944 recbranch_mapseen(source, dest)
1945 d_level *source;
1946 d_level *dest;
1948 mapseen *mptr;
1949 branch *br;
1951 /* not a branch */
1952 if (source->dnum == dest->dnum)
1953 return;
1955 /* we only care about forward branches */
1956 for (br = branches; br; br = br->next) {
1957 if (on_level(source, &br->end1) && on_level(dest, &br->end2))
1958 break;
1959 if (on_level(source, &br->end2) && on_level(dest, &br->end1))
1960 return;
1963 /* branch not found, so not a real branch. */
1964 if (!br)
1965 return;
1967 if ((mptr = find_mapseen(source)) != 0) {
1968 if (mptr->br && br != mptr->br)
1969 impossible("Two branches on the same level?");
1970 mptr->br = br;
1971 } else {
1972 impossible("Can't note branch for unseen level (%d, %d)",
1973 source->dnum, source->dlevel);
1977 char *
1978 get_annotation(lev)
1979 d_level *lev;
1981 mapseen *mptr;
1983 if ((mptr = find_mapseen(lev)))
1984 return mptr->custom;
1985 return NULL;
1988 /* #annotate command - add a custom name to the current level */
1990 donamelevel()
1992 mapseen *mptr;
1993 char nbuf[BUFSZ]; /* Buffer for response */
1995 if (!(mptr = find_mapseen(&u.uz)))
1996 return 0;
1998 if (mptr->custom) {
1999 char tmpbuf[BUFSZ];
2000 Sprintf(tmpbuf, "Replace annotation \"%.30s%s\" with?", mptr->custom,
2001 strlen(mptr->custom) > 30 ? "..." : "");
2002 getlin(tmpbuf, nbuf);
2003 } else
2004 getlin("What do you want to call this dungeon level?", nbuf);
2005 if (index(nbuf, '\033'))
2006 return 0;
2007 (void) mungspaces(nbuf);
2009 /* discard old annotation, if any */
2010 if (mptr->custom) {
2011 free((genericptr_t) mptr->custom);
2012 mptr->custom = (char *) 0;
2013 mptr->custom_lth = 0;
2015 /* add new annotation, unless it's empty or a single space */
2016 if (*nbuf && strcmp(nbuf, " ")) {
2017 mptr->custom = dupstr(nbuf);
2018 mptr->custom_lth = strlen(mptr->custom);
2020 return 0;
2023 /* find the particular mapseen object in the chain; may return null */
2024 STATIC_OVL mapseen *
2025 find_mapseen(lev)
2026 d_level *lev;
2028 mapseen *mptr;
2030 for (mptr = mapseenchn; mptr; mptr = mptr->next)
2031 if (on_level(&(mptr->lev), lev))
2032 break;
2034 return mptr;
2037 void
2038 forget_mapseen(ledger_num)
2039 int ledger_num;
2041 mapseen *mptr;
2042 struct cemetery *bp;
2044 for (mptr = mapseenchn; mptr; mptr = mptr->next)
2045 if (dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel
2046 == ledger_num)
2047 break;
2049 /* if not found, then nothing to forget */
2050 if (mptr) {
2051 mptr->flags.forgot = 1;
2052 mptr->br = (branch *) 0;
2054 /* custom names are erased, not just forgotten until revisited */
2055 if (mptr->custom) {
2056 mptr->custom_lth = 0;
2057 free((genericptr_t) mptr->custom);
2058 mptr->custom = (char *) 0;
2060 (void) memset((genericptr_t) mptr->msrooms, 0, sizeof mptr->msrooms);
2061 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2062 bp->bonesknown = FALSE;
2066 STATIC_OVL void
2067 save_mapseen(fd, mptr)
2068 int fd;
2069 mapseen *mptr;
2071 branch *curr;
2072 int brindx;
2074 for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx)
2075 if (curr == mptr->br)
2076 break;
2077 bwrite(fd, (genericptr_t) &brindx, sizeof brindx);
2079 bwrite(fd, (genericptr_t) &mptr->lev, sizeof mptr->lev);
2080 bwrite(fd, (genericptr_t) &mptr->feat, sizeof mptr->feat);
2081 bwrite(fd, (genericptr_t) &mptr->flags, sizeof mptr->flags);
2082 bwrite(fd, (genericptr_t) &mptr->custom_lth, sizeof mptr->custom_lth);
2083 if (mptr->custom_lth)
2084 bwrite(fd, (genericptr_t) mptr->custom, mptr->custom_lth);
2085 bwrite(fd, (genericptr_t) &mptr->msrooms, sizeof mptr->msrooms);
2086 savecemetery(fd, WRITE_SAVE, &mptr->final_resting_place);
2089 STATIC_OVL mapseen *
2090 load_mapseen(fd)
2091 int fd;
2093 int branchnum, brindx;
2094 mapseen *load;
2095 branch *curr;
2097 load = (mapseen *) alloc(sizeof *load);
2099 mread(fd, (genericptr_t) &branchnum, sizeof branchnum);
2100 for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx)
2101 if (brindx == branchnum)
2102 break;
2103 load->br = curr;
2105 mread(fd, (genericptr_t) &load->lev, sizeof load->lev);
2106 mread(fd, (genericptr_t) &load->feat, sizeof load->feat);
2107 mread(fd, (genericptr_t) &load->flags, sizeof load->flags);
2108 mread(fd, (genericptr_t) &load->custom_lth, sizeof load->custom_lth);
2109 if (load->custom_lth) {
2110 /* length doesn't include terminator (which isn't saved & restored) */
2111 load->custom = (char *) alloc(load->custom_lth + 1);
2112 mread(fd, (genericptr_t) load->custom, load->custom_lth);
2113 load->custom[load->custom_lth] = '\0';
2114 } else
2115 load->custom = 0;
2116 mread(fd, (genericptr_t) &load->msrooms, sizeof load->msrooms);
2117 restcemetery(fd, &load->final_resting_place);
2119 return load;
2122 /* to support '#stats' wizard-mode command */
2123 void
2124 overview_stats(win, statsfmt, total_count, total_size)
2125 winid win;
2126 const char *statsfmt;
2127 long *total_count, *total_size;
2129 char buf[BUFSZ], hdrbuf[QBUFSZ];
2130 long ocount, osize, bcount, bsize, acount, asize;
2131 struct cemetery *ce;
2132 mapseen *mptr = find_mapseen(&u.uz);
2134 ocount = bcount = acount = osize = bsize = asize = 0L;
2135 for (mptr = mapseenchn; mptr; mptr = mptr->next) {
2136 ++ocount;
2137 osize += (long) sizeof *mptr;
2138 for (ce = mptr->final_resting_place; ce; ce = ce->next) {
2139 ++bcount;
2140 bsize += (long) sizeof *ce;
2142 if (mptr->custom_lth) {
2143 ++acount;
2144 asize += (long) (mptr->custom_lth + 1);
2148 Sprintf(hdrbuf, "general, size %ld", (long) sizeof (mapseen));
2149 Sprintf(buf, statsfmt, hdrbuf, ocount, osize);
2150 putstr(win, 0, buf);
2151 if (bcount) {
2152 Sprintf(hdrbuf, "cemetery, size %ld",
2153 (long) sizeof (struct cemetery));
2154 Sprintf(buf, statsfmt, hdrbuf, bcount, bsize);
2155 putstr(win, 0, buf);
2157 if (acount) {
2158 Sprintf(hdrbuf, "annotations, text");
2159 Sprintf(buf, statsfmt, hdrbuf, acount, asize);
2160 putstr(win, 0, buf);
2162 *total_count += ocount + bcount + acount;
2163 *total_size += osize + bsize + asize;
2166 /* Remove all mapseen objects for a particular dnum.
2167 * Useful during quest expulsion to remove quest levels.
2168 * [No longer deleted, just marked as unreachable. #overview will
2169 * ignore such levels, end of game disclosure will include them.]
2171 void
2172 remdun_mapseen(dnum)
2173 int dnum;
2175 mapseen *mptr, **mptraddr;
2177 mptraddr = &mapseenchn;
2178 while ((mptr = *mptraddr) != 0) {
2179 if (mptr->lev.dnum == dnum) {
2180 #if 1 /* use this... */
2181 mptr->flags.unreachable = 1;
2183 #else /* old deletion code */
2184 *mptraddr = mptr->next;
2185 if (mptr->custom)
2186 free((genericptr_t) mptr->custom);
2187 if (mptr->final_resting_place)
2188 savecemetery(-1, FREE_SAVE, &mptr->final_resting_place);
2189 free((genericptr_t) mptr);
2190 } else
2191 #endif
2192 mptraddr = &mptr->next;
2196 void
2197 init_mapseen(lev)
2198 d_level *lev;
2200 /* Create a level and insert in "sorted" order. This is an insertion
2201 * sort first by dungeon (in order of discovery) and then by level number.
2203 mapseen *mptr, *init, *prev;
2205 init = (mapseen *) alloc(sizeof *init);
2206 (void) memset((genericptr_t) init, 0, sizeof *init);
2207 /* memset is fine for feature bits, flags, and rooms array;
2208 explicitly initialize pointers to null */
2209 init->next = 0, init->br = 0, init->custom = 0;
2210 init->final_resting_place = 0;
2211 /* lastseentyp[][] is reused for each level, so get rid of
2212 previous level's data */
2213 (void) memset((genericptr_t) lastseentyp, 0, sizeof lastseentyp);
2215 init->lev.dnum = lev->dnum;
2216 init->lev.dlevel = lev->dlevel;
2218 /* walk until we get to the place where we should insert init */
2219 for (mptr = mapseenchn, prev = 0; mptr; prev = mptr, mptr = mptr->next)
2220 if (mptr->lev.dnum > init->lev.dnum
2221 || (mptr->lev.dnum == init->lev.dnum
2222 && mptr->lev.dlevel > init->lev.dlevel))
2223 break;
2224 if (!prev) {
2225 init->next = mapseenchn;
2226 mapseenchn = init;
2227 } else {
2228 mptr = prev->next;
2229 prev->next = init;
2230 init->next = mptr;
2234 #define INTEREST(feat) \
2235 ((feat).nfount || (feat).nsink || (feat).nthrone || (feat).naltar \
2236 || (feat).ngrave || (feat).ntree || (feat).nshop || (feat).ntemple)
2237 /* || (feat).water || (feat).ice || (feat).lava */
2239 /* returns true if this level has something interesting to print out */
2240 STATIC_OVL boolean
2241 interest_mapseen(mptr)
2242 mapseen *mptr;
2244 if (on_level(&u.uz, &mptr->lev))
2245 return TRUE;
2246 if (mptr->flags.unreachable || mptr->flags.forgot)
2247 return FALSE;
2248 /* level is of interest if it has an auto-generated annotation */
2249 if (mptr->flags.oracle || mptr->flags.bigroom || mptr->flags.roguelevel
2250 || mptr->flags.castle || mptr->flags.valley || mptr->flags.msanctum
2251 || mptr->flags.quest_summons || mptr->flags.questing)
2252 return TRUE;
2253 /* when in Sokoban, list all sokoban levels visited; when not in it,
2254 list any visited Sokoban level which remains unsolved (will usually
2255 only be furthest one reached, but it's possible to enter pits and
2256 climb out on the far side on the first Sokoban level; also, wizard
2257 mode overrides teleport restrictions) */
2258 if (In_sokoban(&mptr->lev)
2259 && (In_sokoban(&u.uz) || !mptr->flags.sokosolved))
2260 return TRUE;
2261 /* when in the endgame, list all endgame levels visited, whether they
2262 have annotations or not, so that #overview doesn't become extremely
2263 sparse once the rest of the dungeon has been flagged as unreachable */
2264 if (In_endgame(&u.uz))
2265 return (boolean) In_endgame(&mptr->lev);
2266 /* level is of interest if it has non-zero feature count or known bones
2267 or user annotation or known connection to another dungeon branch
2268 or is the furthest level reached in its branch */
2269 return (boolean) (INTEREST(mptr->feat)
2270 || (mptr->final_resting_place
2271 && (mptr->flags.knownbones || wizard))
2272 || mptr->custom || mptr->br
2273 || (mptr->lev.dlevel
2274 == dungeons[mptr->lev.dnum].dunlev_ureached));
2277 /* recalculate mapseen for the current level */
2278 void
2279 recalc_mapseen()
2281 mapseen *mptr;
2282 struct monst *mtmp;
2283 struct cemetery *bp, **bonesaddr;
2284 unsigned i, ridx;
2285 int x, y, ltyp, count, atmp;
2287 /* Should not happen in general, but possible if in the process
2288 * of being booted from the quest. The mapseen object gets
2289 * removed during the expulsion but prior to leaving the level
2290 * [Since quest expulsion no longer deletes quest mapseen data,
2291 * null return from find_mapseen() should now be impossible.]
2293 if (!(mptr = find_mapseen(&u.uz)))
2294 return;
2296 /* reset all features; mptr->feat.* = 0; */
2297 (void) memset((genericptr_t) &mptr->feat, 0, sizeof mptr->feat);
2298 /* reset most flags; some level-specific ones are left as-is */
2299 if (mptr->flags.unreachable) {
2300 mptr->flags.unreachable = 0; /* reached it; Eye of the Aethiopica? */
2301 if (In_quest(&u.uz)) {
2302 mapseen *mptrtmp = mapseenchn;
2304 /* when quest was unreachable due to ejection and portal removal,
2305 getting back to it via arti-invoke should revive annotation
2306 data for all quest levels, not just the one we're on now */
2307 do {
2308 if (mptrtmp->lev.dnum == mptr->lev.dnum)
2309 mptrtmp->flags.unreachable = 0;
2310 mptrtmp = mptrtmp->next;
2311 } while (mptrtmp);
2314 mptr->flags.knownbones = 0;
2315 mptr->flags.sokosolved = In_sokoban(&u.uz) && !Sokoban;
2316 /* mptr->flags.bigroom retains previous value when hero can't see */
2317 if (!Blind)
2318 mptr->flags.bigroom = Is_bigroom(&u.uz);
2319 else if (mptr->flags.forgot)
2320 mptr->flags.bigroom = 0;
2321 mptr->flags.roguelevel = Is_rogue_level(&u.uz);
2322 mptr->flags.oracle = 0; /* recalculated during room traversal below */
2323 mptr->flags.castletune = 0;
2324 /* flags.castle, flags.valley, flags.msanctum retain previous value */
2325 mptr->flags.forgot = 0;
2326 /* flags.quest_summons disabled once quest finished */
2327 mptr->flags.quest_summons = (at_dgn_entrance("The Quest")
2328 && u.uevent.qcalled
2329 && !(u.uevent.qcompleted
2330 || u.uevent.qexpelled
2331 || quest_status.leader_is_dead));
2332 mptr->flags.questing = (on_level(&u.uz, &qstart_level)
2333 && quest_status.got_quest);
2335 /* track rooms the hero is in */
2336 for (i = 0; i < SIZE(u.urooms); ++i) {
2337 if (!u.urooms[i])
2338 continue;
2340 ridx = u.urooms[i] - ROOMOFFSET;
2341 mptr->msrooms[ridx].seen = 1;
2342 mptr->msrooms[ridx].untended =
2343 (rooms[ridx].rtype >= SHOPBASE)
2344 ? (!(mtmp = shop_keeper(u.urooms[i])) || !inhishop(mtmp))
2345 : (rooms[ridx].rtype == TEMPLE)
2346 ? (!(mtmp = findpriest(u.urooms[i]))
2347 || !inhistemple(mtmp))
2348 : 0;
2351 /* recalculate room knowledge: for now, just shops and temples
2352 * this could be extended to an array of 0..SHOPBASE
2354 for (i = 0; i < SIZE(mptr->msrooms); ++i) {
2355 if (mptr->msrooms[i].seen) {
2356 if (rooms[i].rtype >= SHOPBASE) {
2357 if (mptr->msrooms[i].untended)
2358 mptr->feat.shoptype = SHOPBASE - 1;
2359 else if (!mptr->feat.nshop)
2360 mptr->feat.shoptype = rooms[i].rtype;
2361 else if (mptr->feat.shoptype != (unsigned) rooms[i].rtype)
2362 mptr->feat.shoptype = 0;
2363 count = mptr->feat.nshop + 1;
2364 if (count <= 3)
2365 mptr->feat.nshop = count;
2366 } else if (rooms[i].rtype == TEMPLE) {
2367 /* altar and temple alignment handled below */
2368 count = mptr->feat.ntemple + 1;
2369 if (count <= 3)
2370 mptr->feat.ntemple = count;
2371 } else if (rooms[i].orig_rtype == DELPHI) {
2372 mptr->flags.oracle = 1;
2377 /* Update lastseentyp with typ if and only if it is in sight or the
2378 * hero can feel it on their current location (i.e. not levitating).
2379 * This *should* give the "last known typ" for each dungeon location.
2380 * (At the very least, it's a better assumption than determining what
2381 * the player knows from the glyph and the typ (which is isn't quite
2382 * enough information in some cases)).
2384 * It was reluctantly added to struct rm to track. Alternatively
2385 * we could track "features" and then update them all here, and keep
2386 * track of when new features are created or destroyed, but this
2387 * seemed the most elegant, despite adding more data to struct rm.
2388 * [3.6.0: we're using lastseentyp[][] rather than level.locations
2389 * to track the features seen.]
2391 * Although no current windowing systems (can) do this, this would add
2392 * the ability to have non-dungeon glyphs float above the last known
2393 * dungeon glyph (i.e. items on fountains).
2395 for (x = 1; x < COLNO; x++) {
2396 for (y = 0; y < ROWNO; y++) {
2397 if (cansee(x, y) || (x == u.ux && y == u.uy && !Levitation)) {
2398 ltyp = levl[x][y].typ;
2399 if (ltyp == DRAWBRIDGE_UP)
2400 ltyp = db_under_typ(levl[x][y].drawbridgemask);
2401 if ((mtmp = m_at(x, y)) != 0
2402 && mtmp->m_ap_type == M_AP_FURNITURE && canseemon(mtmp))
2403 ltyp = cmap_to_type(mtmp->mappearance);
2404 lastseentyp[x][y] = ltyp;
2407 switch (lastseentyp[x][y]) {
2408 #if 0
2409 case ICE:
2410 count = mptr->feat.ice + 1;
2411 if (count <= 3)
2412 mptr->feat.ice = count;
2413 break;
2414 case POOL:
2415 case MOAT:
2416 case WATER:
2417 count = mptr->feat.water + 1;
2418 if (count <= 3)
2419 mptr->feat.water = count;
2420 break;
2421 case LAVAPOOL:
2422 count = mptr->feat.lava + 1;
2423 if (count <= 3)
2424 mptr->feat.lava = count;
2425 break;
2426 #endif
2427 case TREE:
2428 count = mptr->feat.ntree + 1;
2429 if (count <= 3)
2430 mptr->feat.ntree = count;
2431 break;
2432 case FOUNTAIN:
2433 count = mptr->feat.nfount + 1;
2434 if (count <= 3)
2435 mptr->feat.nfount = count;
2436 break;
2437 case THRONE:
2438 count = mptr->feat.nthrone + 1;
2439 if (count <= 3)
2440 mptr->feat.nthrone = count;
2441 break;
2442 case SINK:
2443 count = mptr->feat.nsink + 1;
2444 if (count <= 3)
2445 mptr->feat.nsink = count;
2446 break;
2447 case GRAVE:
2448 count = mptr->feat.ngrave + 1;
2449 if (count <= 3)
2450 mptr->feat.ngrave = count;
2451 break;
2452 case ALTAR:
2453 atmp = (Is_astralevel(&u.uz)
2454 && (levl[x][y].seenv & SVALL) != SVALL)
2455 ? MSA_NONE
2456 : Amask2msa(levl[x][y].altarmask);
2457 if (!mptr->feat.naltar)
2458 mptr->feat.msalign = atmp;
2459 else if (mptr->feat.msalign != atmp)
2460 mptr->feat.msalign = MSA_NONE;
2461 count = mptr->feat.naltar + 1;
2462 if (count <= 3)
2463 mptr->feat.naltar = count;
2464 break;
2465 /* An automatic annotation is added to the Castle and
2466 * to Fort Ludios once their structure's main entrance
2467 * has been seen (in person or via magic mapping).
2468 * For the Fort, that entrance is just a secret door
2469 * which will be converted into a regular one when
2470 * located (or destroyed).
2471 * DOOR: possibly a lowered drawbridge's open portcullis;
2472 * DBWALL: a raised drawbridge's "closed door";
2473 * DRAWBRIDGE_DOWN: the span provided by lowered bridge,
2474 * with moat or other terrain hidden underneath;
2475 * DRAWBRIDGE_UP: moat in front of a raised drawbridge,
2476 * not recognizable as a bridge location unless/until
2477 * the adjacent DBWALL has been seen.
2479 case DOOR:
2480 if (Is_knox(&u.uz)) {
2481 int ty, tx = x - 4;
2483 /* Throne is four columns left, either directly in
2484 * line or one row higher or lower, and doesn't have
2485 * to have been seen yet.
2486 * ......|}}}.
2487 * ..\...S}...
2488 * ..\...S}...
2489 * ......|}}}.
2490 * For 3.6.0 and earlier, it was always in direct line:
2491 * both throne and door on the lower of the two rows.
2493 for (ty = y - 1; ty <= y + 1; ++ty)
2494 if (isok(tx, ty) && IS_THRONE(levl[tx][ty].typ)) {
2495 mptr->flags.ludios = 1;
2496 break;
2498 break;
2500 if (is_drawbridge_wall(x, y) < 0)
2501 break;
2502 /* else FALLTHRU */
2503 case DBWALL:
2504 case DRAWBRIDGE_DOWN:
2505 if (Is_stronghold(&u.uz))
2506 mptr->flags.castle = 1, mptr->flags.castletune = 1;
2507 break;
2508 default:
2509 break;
2514 if (level.bonesinfo && !mptr->final_resting_place) {
2515 /* clone the bonesinfo so we aren't dependent upon this
2516 level being in memory */
2517 bonesaddr = &mptr->final_resting_place;
2518 bp = level.bonesinfo;
2519 do {
2520 *bonesaddr = (struct cemetery *) alloc(sizeof **bonesaddr);
2521 **bonesaddr = *bp;
2522 bp = bp->next;
2523 bonesaddr = &(*bonesaddr)->next;
2524 } while (bp);
2525 *bonesaddr = 0;
2527 /* decide which past hero deaths have become known; there's no
2528 guarantee of either a grave or a ghost, so we go by whether the
2529 current hero has seen the map location where each old one died */
2530 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2531 if (lastseentyp[bp->frpx][bp->frpy]) {
2532 bp->bonesknown = TRUE;
2533 mptr->flags.knownbones = 1;
2537 /*ARGUSED*/
2538 /* valley and sanctum levels get automatic annotation once temple is entered
2540 void
2541 mapseen_temple(priest)
2542 struct monst *priest UNUSED; /* currently unused; might be useful someday */
2544 mapseen *mptr = find_mapseen(&u.uz);
2546 if (Is_valley(&u.uz))
2547 mptr->flags.valley = 1;
2548 else if (Is_sanctum(&u.uz))
2549 mptr->flags.msanctum = 1;
2552 /* room entry message has just been delivered so learn room even if blind */
2553 void
2554 room_discovered(roomno)
2555 int roomno;
2557 mapseen *mptr = find_mapseen(&u.uz);
2559 mptr->msrooms[roomno].seen = 1;
2562 /* #overview command */
2564 dooverview()
2566 show_overview(0, 0);
2567 return 0;
2570 /* called for #overview or for end of game disclosure */
2571 void
2572 show_overview(why, reason)
2573 int why; /* 0 => #overview command,
2574 1 or 2 => final disclosure (1: hero lived, 2: hero died) */
2575 int reason; /* how hero died; used when disclosing end-of-game level */
2577 winid win;
2578 int lastdun = -1;
2580 /* lazy initialization */
2581 (void) recalc_mapseen();
2583 win = create_nhwindow(NHW_MENU);
2584 /* show the endgame levels before the rest of the dungeon,
2585 so that the Planes (dnum 5-ish) come out above main dungeon (dnum 0) */
2586 if (In_endgame(&u.uz))
2587 traverse_mapseenchn(TRUE, win, why, reason, &lastdun);
2588 /* if game is over or we're not in the endgame yet, show the dungeon */
2589 if (why > 0 || !In_endgame(&u.uz))
2590 traverse_mapseenchn(FALSE, win, why, reason, &lastdun);
2591 display_nhwindow(win, TRUE);
2592 destroy_nhwindow(win);
2595 /* display endgame levels or non-endgame levels, not both */
2596 STATIC_OVL void
2597 traverse_mapseenchn(viewendgame, win, why, reason, lastdun_p)
2598 boolean viewendgame;
2599 winid win;
2600 int why, reason, *lastdun_p;
2602 mapseen *mptr;
2603 boolean showheader;
2605 for (mptr = mapseenchn; mptr; mptr = mptr->next) {
2606 if (viewendgame ^ In_endgame(&mptr->lev))
2607 continue;
2609 /* only print out info for a level or a dungeon if interest */
2610 if (why > 0 || interest_mapseen(mptr)) {
2611 showheader = (boolean) (mptr->lev.dnum != *lastdun_p);
2612 print_mapseen(win, mptr, why, reason, showheader);
2613 *lastdun_p = mptr->lev.dnum;
2618 STATIC_OVL const char *
2619 seen_string(x, obj)
2620 xchar x;
2621 const char *obj;
2623 /* players are computer scientists: 0, 1, 2, n */
2624 switch (x) {
2625 case 0:
2626 return "no";
2627 /* an() returns too much. index is ok in this case */
2628 case 1:
2629 return index(vowels, *obj) ? "an" : "a";
2630 case 2:
2631 return "some";
2632 case 3:
2633 return "many";
2636 return "(unknown)";
2639 /* better br_string */
2640 STATIC_OVL const char *
2641 br_string2(br)
2642 branch *br;
2644 /* Special case: quest portal says closed if kicked from quest */
2645 boolean closed_portal = (br->end2.dnum == quest_dnum
2646 && u.uevent.qexpelled);
2648 switch (br->type) {
2649 case BR_PORTAL:
2650 return closed_portal ? "Sealed portal" : "Portal";
2651 case BR_NO_END1:
2652 return "Connection";
2653 case BR_NO_END2:
2654 return br->end1_up ? "One way stairs up" : "One way stairs down";
2655 case BR_STAIR:
2656 return br->end1_up ? "Stairs up" : "Stairs down";
2659 return "(unknown)";
2662 /* get the name of an endgame level; topten.c does something similar */
2663 STATIC_OVL const char *
2664 endgamelevelname(outbuf, indx)
2665 char *outbuf;
2666 int indx;
2668 const char *planename = 0;
2670 *outbuf = '\0';
2671 switch (indx) {
2672 case -5:
2673 Strcpy(outbuf, "Astral Plane");
2674 break;
2675 case -4:
2676 planename = "Water";
2677 break;
2678 case -3:
2679 planename = "Fire";
2680 break;
2681 case -2:
2682 planename = "Air";
2683 break;
2684 case -1:
2685 planename = "Earth";
2686 break;
2688 if (planename)
2689 Sprintf(outbuf, "Plane of %s", planename);
2690 else if (!*outbuf)
2691 Sprintf(outbuf, "unknown plane #%d", indx);
2692 return outbuf;
2695 STATIC_OVL const char *
2696 shop_string(rtype)
2697 int rtype;
2699 const char *str = "shop"; /* catchall */
2701 /* Yuck, redundancy...but shclass.name doesn't cut it as a noun */
2702 switch (rtype) {
2703 case SHOPBASE - 1:
2704 str = "untended shop";
2705 break; /* see recalc_mapseen */
2706 case SHOPBASE:
2707 str = "general store";
2708 break;
2709 case ARMORSHOP:
2710 str = "armor shop";
2711 break;
2712 case SCROLLSHOP:
2713 str = "scroll shop";
2714 break;
2715 case POTIONSHOP:
2716 str = "potion shop";
2717 break;
2718 case WEAPONSHOP:
2719 str = "weapon shop";
2720 break;
2721 case FOODSHOP:
2722 str = "delicatessen";
2723 break;
2724 case RINGSHOP:
2725 str = "jewelers";
2726 break;
2727 case WANDSHOP:
2728 str = "wand shop";
2729 break;
2730 case BOOKSHOP:
2731 str = "bookstore";
2732 break;
2733 case FODDERSHOP:
2734 str = "health food store";
2735 break;
2736 case CANDLESHOP:
2737 str = "lighting shop";
2738 break;
2739 default:
2740 break;
2742 return str;
2745 /* if player knows about the mastermind tune, append it to Castle annotation;
2746 if drawbridge has been destroyed, flags.castletune will be zero */
2747 STATIC_OVL char *
2748 tunesuffix(mptr, outbuf)
2749 mapseen *mptr;
2750 char *outbuf;
2752 *outbuf = '\0';
2753 if (mptr->flags.castletune && u.uevent.uheard_tune) {
2754 char tmp[BUFSZ];
2756 if (u.uevent.uheard_tune == 2)
2757 Sprintf(tmp, "notes \"%s\"", tune);
2758 else
2759 Strcpy(tmp, "5-note tune");
2760 Sprintf(outbuf, " (play %s to open or close drawbridge)", tmp);
2762 return outbuf;
2765 /* some utility macros for print_mapseen */
2766 #define TAB " " /* three spaces */
2767 #if 0
2768 #define BULLET "" /* empty; otherwise output becomes cluttered */
2769 #define PREFIX TAB TAB BULLET
2770 #else /*!0*/
2771 /* K&R: don't require support for concatenation of adjacent string literals */
2772 #define PREFIX " " /* two TABs + empty BULLET: six spaces */
2773 #endif
2774 #define COMMA (i++ > 0 ? ", " : PREFIX)
2775 /* "iterate" once; safe to use as ``if (cond) ADDTOBUF(); else whatever;'' */
2776 #define ADDNTOBUF(nam, var) \
2777 do { \
2778 if (var) \
2779 Sprintf(eos(buf), "%s%s %s%s", COMMA, seen_string((var), (nam)), \
2780 (nam), plur(var)); \
2781 } while (0)
2782 #define ADDTOBUF(nam, var) \
2783 do { \
2784 if (var) \
2785 Sprintf(eos(buf), "%s%s", COMMA, (nam)); \
2786 } while (0)
2788 STATIC_OVL void
2789 print_mapseen(win, mptr, final, how, printdun)
2790 winid win;
2791 mapseen *mptr;
2792 int final; /* 0: not final; 1: game over, alive; 2: game over, dead */
2793 int how; /* cause of death; only used if final==2 and mptr->lev==u.uz */
2794 boolean printdun;
2796 char buf[BUFSZ], tmpbuf[BUFSZ];
2797 int i, depthstart, dnum;
2798 boolean died_here = (final == 2 && on_level(&u.uz, &mptr->lev));
2800 /* Damnable special cases */
2801 /* The quest and knox should appear to be level 1 to match
2802 * other text.
2804 dnum = mptr->lev.dnum;
2805 if (dnum == quest_dnum || dnum == knox_level.dnum)
2806 depthstart = 1;
2807 else
2808 depthstart = dungeons[dnum].depth_start;
2810 if (printdun) {
2811 if (dungeons[dnum].dunlev_ureached == dungeons[dnum].entry_lev
2812 /* suppress the negative numbers in the endgame */
2813 || In_endgame(&mptr->lev))
2814 Sprintf(buf, "%s:", dungeons[dnum].dname);
2815 else if (builds_up(&mptr->lev))
2816 Sprintf(buf, "%s: levels %d up to %d",
2817 dungeons[dnum].dname,
2818 depthstart + dungeons[dnum].entry_lev - 1,
2819 depthstart + dungeons[dnum].dunlev_ureached - 1);
2820 else
2821 Sprintf(buf, "%s: levels %d to %d",
2822 dungeons[dnum].dname, depthstart,
2823 depthstart + dungeons[dnum].dunlev_ureached - 1);
2824 putstr(win, !final ? ATR_INVERSE : 0, buf);
2827 /* calculate level number */
2828 i = depthstart + mptr->lev.dlevel - 1;
2829 if (In_endgame(&mptr->lev))
2830 Sprintf(buf, "%s%s:", TAB, endgamelevelname(tmpbuf, i));
2831 else
2832 Sprintf(buf, "%sLevel %d:", TAB, i);
2834 /* wizmode prints out proto dungeon names for clarity */
2835 if (wizard) {
2836 s_level *slev;
2838 if ((slev = Is_special(&mptr->lev)) != 0)
2839 Sprintf(eos(buf), " [%s]", slev->proto);
2841 /* [perhaps print custom annotation on its own line when it's long] */
2842 if (mptr->custom)
2843 Sprintf(eos(buf), " \"%s\"", mptr->custom);
2844 if (on_level(&u.uz, &mptr->lev))
2845 Sprintf(eos(buf), " <- You %s here.",
2846 (!final || (final == 1 && how == ASCENDED)) ? "are" : "were");
2847 putstr(win, !final ? ATR_BOLD : 0, buf);
2849 if (mptr->flags.forgot)
2850 return;
2852 if (INTEREST(mptr->feat)) {
2853 buf[0] = 0;
2855 i = 0; /* interest counter */
2856 /* List interests in an order vaguely corresponding to
2857 * how important they are.
2859 if (mptr->feat.nshop > 0) {
2860 if (mptr->feat.nshop > 1)
2861 ADDNTOBUF("shop", mptr->feat.nshop);
2862 else
2863 Sprintf(eos(buf), "%s%s", COMMA,
2864 an(shop_string(mptr->feat.shoptype)));
2866 if (mptr->feat.naltar > 0) {
2867 /* Temples + non-temple altars get munged into just "altars" */
2868 if (mptr->feat.ntemple != mptr->feat.naltar)
2869 ADDNTOBUF("altar", mptr->feat.naltar);
2870 else
2871 ADDNTOBUF("temple", mptr->feat.ntemple);
2873 /* only print out altar's god if they are all to your god */
2874 if (Amask2align(Msa2amask(mptr->feat.msalign)) == u.ualign.type)
2875 Sprintf(eos(buf), " to %s", align_gname(u.ualign.type));
2877 ADDNTOBUF("throne", mptr->feat.nthrone);
2878 ADDNTOBUF("fountain", mptr->feat.nfount);
2879 ADDNTOBUF("sink", mptr->feat.nsink);
2880 ADDNTOBUF("grave", mptr->feat.ngrave);
2881 ADDNTOBUF("tree", mptr->feat.ntree);
2882 #if 0
2883 ADDTOBUF("water", mptr->feat.water);
2884 ADDTOBUF("lava", mptr->feat.lava);
2885 ADDTOBUF("ice", mptr->feat.ice);
2886 #endif
2887 /* capitalize afterwards */
2888 i = strlen(PREFIX);
2889 buf[i] = highc(buf[i]);
2890 /* capitalizing it makes it a sentence; terminate with '.' */
2891 Strcat(buf, ".");
2892 putstr(win, 0, buf);
2895 /* we assume that these are mutually exclusive */
2896 *buf = '\0';
2897 if (mptr->flags.oracle) {
2898 Sprintf(buf, "%sOracle of Delphi.", PREFIX);
2899 } else if (In_sokoban(&mptr->lev)) {
2900 Sprintf(buf, "%s%s.", PREFIX,
2901 mptr->flags.sokosolved ? "Solved" : "Unsolved");
2902 } else if (mptr->flags.bigroom) {
2903 Sprintf(buf, "%sA very big room.", PREFIX);
2904 } else if (mptr->flags.roguelevel) {
2905 Sprintf(buf, "%sA primitive area.", PREFIX);
2906 } else if (mptr->flags.quest_summons) {
2907 Sprintf(buf, "%sSummoned by %s.", PREFIX, ldrname());
2908 } else if (on_level(&mptr->lev, &qstart_level)) {
2909 Sprintf(buf, "%sHome%s.", PREFIX,
2910 mptr->flags.unreachable ? " (no way back...)" : "");
2911 if (u.uevent.qcompleted)
2912 Sprintf(buf, "%sCompleted quest for %s.", PREFIX, ldrname());
2913 else if (mptr->flags.questing)
2914 Sprintf(buf, "%sGiven quest by %s.", PREFIX, ldrname());
2915 } else if (mptr->flags.ludios) {
2916 /* presence of the ludios branch in #overview output indicates that
2917 the player has made it onto the level; presence of this annotation
2918 indicates that the fort's entrance has been seen (or mapped) */
2919 Sprintf(buf, "%sFort Ludios.", PREFIX);
2920 } else if (mptr->flags.castle) {
2921 Sprintf(buf, "%sThe castle%s.", PREFIX, tunesuffix(mptr, tmpbuf));
2922 } else if (mptr->flags.valley) {
2923 Sprintf(buf, "%sValley of the Dead.", PREFIX);
2924 } else if (mptr->flags.msanctum) {
2925 Sprintf(buf, "%sMoloch's Sanctum.", PREFIX);
2927 if (*buf)
2928 putstr(win, 0, buf);
2930 /* print out branches */
2931 if (mptr->br) {
2932 Sprintf(buf, "%s%s to %s", PREFIX, br_string2(mptr->br),
2933 dungeons[mptr->br->end2.dnum].dname);
2935 /* Since mapseen objects are printed out in increasing order
2936 * of dlevel, clarify which level this branch is going to
2937 * if the branch goes upwards. Unless it's the end game.
2939 if (mptr->br->end1_up && !In_endgame(&(mptr->br->end2)))
2940 Sprintf(eos(buf), ", level %d", depth(&(mptr->br->end2)));
2941 Strcat(buf, ".");
2942 putstr(win, 0, buf);
2945 /* maybe print out bones details */
2946 if (mptr->final_resting_place || final) {
2947 struct cemetery *bp;
2948 int kncnt = !died_here ? 0 : 1;
2950 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2951 if (bp->bonesknown || wizard || final)
2952 ++kncnt;
2953 if (kncnt) {
2954 Sprintf(buf, "%s%s", PREFIX, "Final resting place for");
2955 putstr(win, 0, buf);
2956 if (died_here) {
2957 /* disclosure occurs before bones creation, so listing dead
2958 hero here doesn't give away whether bones are produced */
2959 formatkiller(tmpbuf, sizeof tmpbuf, how, TRUE);
2960 /* rephrase a few death reasons to work with "you" */
2961 (void) strsubst(tmpbuf, " himself", " yourself");
2962 (void) strsubst(tmpbuf, " herself", " yourself");
2963 (void) strsubst(tmpbuf, " his ", " your ");
2964 (void) strsubst(tmpbuf, " her ", " your ");
2965 Sprintf(buf, "%s%syou, %s%c", PREFIX, TAB, tmpbuf,
2966 --kncnt ? ',' : '.');
2967 putstr(win, 0, buf);
2969 for (bp = mptr->final_resting_place; bp; bp = bp->next) {
2970 if (bp->bonesknown || wizard || final) {
2971 Sprintf(buf, "%s%s%s, %s%c", PREFIX, TAB, bp->who,
2972 bp->how, --kncnt ? ',' : '.');
2973 putstr(win, 0, buf);
2980 /*dungeon.c*/