Add key rebinding
[aNetHack.git] / src / dungeon.c
blob78dd19d6ca4047fdb8802738d11d150f8cb8ba75
1 /* NetHack 3.6 dungeon.c $NHDT-Date: 1470275509 2016/08/04 01:51:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.76 $ */
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 (void) memset((genericptr_t)new_branch, 0, sizeof(branch));
494 new_branch->next = (branch *) 0;
495 new_branch->id = branch_id++;
496 new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
497 new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd);
498 new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd);
499 new_branch->end2.dnum = dgn;
500 new_branch->end2.dlevel = child_entry_level;
501 new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE;
503 insert_branch(new_branch, FALSE);
504 return new_branch;
508 * Add new level to special level chain. Insert it in level order with the
509 * other levels in this dungeon. This assumes that we are never given a
510 * level that has a dungeon number less than the dungeon number of the
511 * last entry.
513 STATIC_OVL void
514 add_level(new_lev)
515 s_level *new_lev;
517 s_level *prev, *curr;
519 prev = (s_level *) 0;
520 for (curr = sp_levchn; curr; curr = curr->next) {
521 if (curr->dlevel.dnum == new_lev->dlevel.dnum
522 && curr->dlevel.dlevel > new_lev->dlevel.dlevel)
523 break;
524 prev = curr;
526 if (!prev) {
527 new_lev->next = sp_levchn;
528 sp_levchn = new_lev;
529 } else {
530 new_lev->next = curr;
531 prev->next = new_lev;
535 STATIC_OVL void
536 init_level(dgn, proto_index, pd)
537 int dgn, proto_index;
538 struct proto_dungeon *pd;
540 s_level *new_level;
541 struct tmplevel *tlevel = &pd->tmplevel[proto_index];
543 pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
544 if (!wizard && tlevel->chance <= rn2(100))
545 return;
547 pd->final_lev[proto_index] = new_level =
548 (s_level *) alloc(sizeof(s_level));
549 (void) memset((genericptr_t)new_level, 0, sizeof(s_level));
550 /* load new level with data */
551 Strcpy(new_level->proto, tlevel->name);
552 new_level->boneid = tlevel->boneschar;
553 new_level->dlevel.dnum = dgn;
554 new_level->dlevel.dlevel = 0; /* for now */
556 new_level->flags.town = !!(tlevel->flags & TOWN);
557 new_level->flags.hellish = !!(tlevel->flags & HELLISH);
558 new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
559 new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
560 new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);
561 if (!new_level->flags.align)
562 new_level->flags.align =
563 ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4);
565 new_level->rndlevs = tlevel->rndlevs;
566 new_level->next = (s_level *) 0;
569 STATIC_OVL int
570 possible_places(idx, map, pd)
571 int idx; /* prototype index */
572 boolean *map; /* array MAXLEVEL+1 in length */
573 struct proto_dungeon *pd;
575 int i, start, count;
576 s_level *lev = pd->final_lev[idx];
578 /* init level possibilities */
579 for (i = 0; i <= MAXLEVEL; i++)
580 map[i] = FALSE;
582 /* get base and range and set those entries to true */
583 count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base,
584 pd->tmplevel[idx].lev.rand, pd->tmplevel[idx].chain,
585 pd, &start);
586 for (i = start; i < start + count; i++)
587 map[i] = TRUE;
589 /* mark off already placed levels */
590 for (i = pd->start; i < idx; i++) {
591 if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) {
592 map[pd->final_lev[i]->dlevel.dlevel] = FALSE;
593 --count;
597 return count;
600 /* Pick the nth TRUE entry in the given boolean array. */
601 STATIC_OVL xchar
602 pick_level(map, nth)
603 boolean *map; /* an array MAXLEVEL+1 in size */
604 int nth;
606 int i;
607 for (i = 1; i <= MAXLEVEL; i++)
608 if (map[i] && !nth--)
609 return (xchar) i;
610 panic("pick_level: ran out of valid levels");
611 return 0;
614 #ifdef DDEBUG
615 static void FDECL(indent, (int));
617 static void
618 indent(d)
619 int d;
621 while (d-- > 0)
622 fputs(" ", stderr);
624 #endif
627 * Place a level. First, find the possible places on a dungeon map
628 * template. Next pick one. Then try to place the next level. If
629 * successful, we're done. Otherwise, try another (and another) until
630 * all possible places have been tried. If all possible places have
631 * been exhausted, return false.
633 STATIC_OVL boolean
634 place_level(proto_index, pd)
635 int proto_index;
636 struct proto_dungeon *pd;
638 boolean map[MAXLEVEL + 1]; /* valid levels are 1..MAXLEVEL inclusive */
639 s_level *lev;
640 int npossible;
641 #ifdef DDEBUG
642 int i;
643 #endif
645 if (proto_index == pd->n_levs)
646 return TRUE; /* at end of proto levels */
648 lev = pd->final_lev[proto_index];
650 /* No level created for this prototype, goto next. */
651 if (!lev)
652 return place_level(proto_index + 1, pd);
654 npossible = possible_places(proto_index, map, pd);
656 for (; npossible; --npossible) {
657 lev->dlevel.dlevel = pick_level(map, rn2(npossible));
658 #ifdef DDEBUG
659 indent(proto_index - pd->start);
660 fprintf(stderr, "%s: trying %d [ ", lev->proto, lev->dlevel.dlevel);
661 for (i = 1; i <= MAXLEVEL; i++)
662 if (map[i])
663 fprintf(stderr, "%d ", i);
664 fprintf(stderr, "]\n");
665 #endif
666 if (place_level(proto_index + 1, pd))
667 return TRUE;
668 map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */
670 #ifdef DDEBUG
671 indent(proto_index - pd->start);
672 fprintf(stderr, "%s: failed\n", lev->proto);
673 #endif
674 return FALSE;
677 struct level_map {
678 const char *lev_name;
679 d_level *lev_spec;
680 } level_map[] = { { "air", &air_level },
681 { "asmodeus", &asmodeus_level },
682 { "astral", &astral_level },
683 { "baalz", &baalzebub_level },
684 { "bigrm", &bigroom_level },
685 { "castle", &stronghold_level },
686 { "earth", &earth_level },
687 { "fakewiz1", &portal_level },
688 { "fire", &fire_level },
689 { "juiblex", &juiblex_level },
690 { "knox", &knox_level },
691 { "medusa", &medusa_level },
692 { "oracle", &oracle_level },
693 { "orcus", &orcus_level },
694 { "rogue", &rogue_level },
695 { "sanctum", &sanctum_level },
696 { "valley", &valley_level },
697 { "water", &water_level },
698 { "wizard1", &wiz1_level },
699 { "wizard2", &wiz2_level },
700 { "wizard3", &wiz3_level },
701 { "minend", &mineend_level },
702 { "soko1", &sokoend_level },
703 { X_START, &qstart_level },
704 { X_LOCATE, &qlocate_level },
705 { X_GOAL, &nemesis_level },
706 { "", (d_level *) 0 } };
708 /* initialize the "dungeon" structs */
709 void
710 init_dungeons()
712 dlb *dgn_file;
713 register int i, cl = 0, cb = 0;
714 register s_level *x;
715 struct proto_dungeon pd;
716 struct level_map *lev_map;
717 struct version_info vers_info;
719 pd.n_levs = pd.n_brs = 0;
721 dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
722 if (!dgn_file) {
723 char tbuf[BUFSZ];
724 Sprintf(tbuf, "Cannot open dungeon description - \"%s", DUNGEON_FILE);
725 #ifdef DLBRSRC /* using a resource from the executable */
726 Strcat(tbuf, "\" resource!");
727 #else /* using a file or DLB file */
728 #if defined(DLB)
729 Strcat(tbuf, "\" from ");
730 #ifdef PREFIXES_IN_USE
731 Strcat(tbuf, "\n\"");
732 if (fqn_prefix[DATAPREFIX])
733 Strcat(tbuf, fqn_prefix[DATAPREFIX]);
734 #else
735 Strcat(tbuf, "\"");
736 #endif
737 Strcat(tbuf, DLBFILE);
738 #endif
739 Strcat(tbuf, "\" file!");
740 #endif
741 #ifdef WIN32
742 interject_assistance(1, INTERJECT_PANIC, (genericptr_t) tbuf,
743 (genericptr_t) fqn_prefix[DATAPREFIX]);
744 #endif
745 panic1(tbuf);
748 /* validate the data's version against the program's version */
749 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file);
750 /* we'd better clear the screen now, since when error messages come from
751 * check_version() they will be printed using pline(), which doesn't
752 * mix with the raw messages that might be already on the screen
754 if (iflags.window_inited)
755 clear_nhwindow(WIN_MAP);
756 if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
757 panic("Dungeon description not valid.");
760 * Read in each dungeon and transfer the results to the internal
761 * dungeon arrays.
763 sp_levchn = (s_level *) 0;
764 Fread((genericptr_t) &n_dgns, sizeof(int), 1, dgn_file);
765 if (n_dgns >= MAXDUNGEON)
766 panic("init_dungeons: too many dungeons");
768 for (i = 0; i < n_dgns; i++) {
769 Fread((genericptr_t) &pd.tmpdungeon[i], sizeof(struct tmpdungeon), 1,
770 dgn_file);
771 if (!wizard && pd.tmpdungeon[i].chance
772 && (pd.tmpdungeon[i].chance <= rn2(100))) {
773 int j;
775 /* skip over any levels or branches */
776 for (j = 0; j < pd.tmpdungeon[i].levels; j++)
777 Fread((genericptr_t) &pd.tmplevel[cl],
778 sizeof(struct tmplevel), 1, dgn_file);
780 for (j = 0; j < pd.tmpdungeon[i].branches; j++)
781 Fread((genericptr_t) &pd.tmpbranch[cb],
782 sizeof(struct tmpbranch), 1, dgn_file);
783 n_dgns--;
784 i--;
785 continue;
788 Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name);
789 Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname);
790 dungeons[i].boneid = pd.tmpdungeon[i].boneschar;
792 if (pd.tmpdungeon[i].lev.rand)
793 dungeons[i].num_dunlevs = (xchar) rn1(pd.tmpdungeon[i].lev.rand,
794 pd.tmpdungeon[i].lev.base);
795 else
796 dungeons[i].num_dunlevs = (xchar) pd.tmpdungeon[i].lev.base;
798 if (!i) {
799 dungeons[i].ledger_start = 0;
800 dungeons[i].depth_start = 1;
801 dungeons[i].dunlev_ureached = 1;
802 } else {
803 dungeons[i].ledger_start =
804 dungeons[i - 1].ledger_start + dungeons[i - 1].num_dunlevs;
805 dungeons[i].dunlev_ureached = 0;
808 dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH);
809 dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE);
810 dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE);
811 dungeons[i].flags.align =
812 ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4);
814 * Set the entry level for this dungeon. The pd.tmpdungeon entry
815 * value means:
816 * < 0 from bottom (-1 == bottom level)
817 * 0 default (top)
818 * > 0 actual level (1 = top)
820 * Note that the entry_lev field in the dungeon structure is
821 * redundant. It is used only here and in print_dungeon().
823 if (pd.tmpdungeon[i].entry_lev < 0) {
824 dungeons[i].entry_lev =
825 dungeons[i].num_dunlevs + pd.tmpdungeon[i].entry_lev + 1;
826 if (dungeons[i].entry_lev <= 0)
827 dungeons[i].entry_lev = 1;
828 } else if (pd.tmpdungeon[i].entry_lev > 0) {
829 dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
830 if (dungeons[i].entry_lev > dungeons[i].num_dunlevs)
831 dungeons[i].entry_lev = dungeons[i].num_dunlevs;
832 } else { /* default */
833 dungeons[i].entry_lev = 1; /* defaults to top level */
836 if (i) { /* set depth */
837 branch *br;
838 schar from_depth;
839 boolean from_up;
841 br = add_branch(i, dungeons[i].entry_lev, &pd);
843 /* Get the depth of the connecting end. */
844 if (br->end1.dnum == i) {
845 from_depth = depth(&br->end2);
846 from_up = !br->end1_up;
847 } else {
848 from_depth = depth(&br->end1);
849 from_up = br->end1_up;
853 * Calculate the depth of the top of the dungeon via
854 * its branch. First, the depth of the entry point:
856 * depth of branch from "parent" dungeon
857 * + -1 or 1 depending on an up or down stair or
858 * 0 if portal
860 * Followed by the depth of the top of the dungeon:
862 * - (entry depth - 1)
864 * We'll say that portals stay on the same depth.
866 dungeons[i].depth_start =
867 from_depth + (br->type == BR_PORTAL ? 0 : (from_up ? -1 : 1))
868 - (dungeons[i].entry_lev - 1);
871 /* this is redundant - it should have been flagged by dgn_comp */
872 if (dungeons[i].num_dunlevs > MAXLEVEL)
873 dungeons[i].num_dunlevs = MAXLEVEL;
875 pd.start = pd.n_levs; /* save starting point */
876 pd.n_levs += pd.tmpdungeon[i].levels;
877 if (pd.n_levs > LEV_LIMIT)
878 panic("init_dungeon: too many special levels");
880 * Read in the prototype special levels. Don't add generated
881 * special levels until they are all placed.
883 for (; cl < pd.n_levs; cl++) {
884 Fread((genericptr_t) &pd.tmplevel[cl], sizeof(struct tmplevel), 1,
885 dgn_file);
886 init_level(i, cl, &pd);
889 * Recursively place the generated levels for this dungeon. This
890 * routine will attempt all possible combinations before giving
891 * up.
893 if (!place_level(pd.start, &pd))
894 panic("init_dungeon: couldn't place levels");
895 #ifdef DDEBUG
896 fprintf(stderr, "--- end of dungeon %d ---\n", i);
897 fflush(stderr);
898 getchar();
899 #endif
900 for (; pd.start < pd.n_levs; pd.start++)
901 if (pd.final_lev[pd.start])
902 add_level(pd.final_lev[pd.start]);
904 pd.n_brs += pd.tmpdungeon[i].branches;
905 if (pd.n_brs > BRANCH_LIMIT)
906 panic("init_dungeon: too many branches");
907 for (; cb < pd.n_brs; cb++)
908 Fread((genericptr_t) &pd.tmpbranch[cb], sizeof(struct tmpbranch),
909 1, dgn_file);
911 (void) dlb_fclose(dgn_file);
913 for (i = 0; i < 5; i++)
914 tune[i] = 'A' + rn2(7);
915 tune[5] = 0;
918 * Find most of the special levels and dungeons so we can access their
919 * locations quickly.
921 for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
922 x = find_level(lev_map->lev_name);
923 if (x) {
924 assign_level(lev_map->lev_spec, &x->dlevel);
925 if (!strncmp(lev_map->lev_name, "x-", 2)) {
926 /* This is where the name substitution on the
927 * levels of the quest dungeon occur.
929 Sprintf(x->proto, "%s%s", urole.filecode,
930 &lev_map->lev_name[1]);
931 } else if (lev_map->lev_spec == &knox_level) {
932 branch *br;
934 * Kludge to allow floating Knox entrance. We
935 * specify a floating entrance by the fact that
936 * its entrance (end1) has a bogus dnum, namely
937 * n_dgns.
939 for (br = branches; br; br = br->next)
940 if (on_level(&br->end2, &knox_level))
941 break;
943 if (br)
944 br->end1.dnum = n_dgns;
945 /* adjust the branch's position on the list */
946 insert_branch(br, TRUE);
951 * I hate hardwiring these names. :-(
953 quest_dnum = dname_to_dnum("The Quest");
954 sokoban_dnum = dname_to_dnum("Sokoban");
955 mines_dnum = dname_to_dnum("The Gnomish Mines");
956 tower_dnum = dname_to_dnum("Vlad's Tower");
958 /* one special fixup for dummy surface level */
959 if ((x = find_level("dummy")) != 0) {
960 i = x->dlevel.dnum;
961 /* the code above puts earth one level above dungeon level #1,
962 making the dummy level overlay level 1; but the whole reason
963 for having the dummy level is to make earth have depth -1
964 instead of 0, so adjust the start point to shift endgame up */
965 if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start)
966 dungeons[i].depth_start -= 1;
967 /* TO DO: strip "dummy" out all the way here,
968 so that it's hidden from <ctrl/O> feedback. */
971 #ifdef DEBUG
972 dumpit();
973 #endif
976 /* return the level number for lev in *this* dungeon */
977 xchar
978 dunlev(lev)
979 d_level *lev;
981 return lev->dlevel;
984 /* return the lowest level number for *this* dungeon */
985 xchar
986 dunlevs_in_dungeon(lev)
987 d_level *lev;
989 return dungeons[lev->dnum].num_dunlevs;
992 /* return the lowest level explored in the game*/
993 xchar
994 deepest_lev_reached(noquest)
995 boolean noquest;
997 /* this function is used for three purposes: to provide a factor
998 * of difficulty in monster generation; to provide a factor of
999 * difficulty in experience calculations (botl.c and end.c); and
1000 * to insert the deepest level reached in the game in the topten
1001 * display. the 'noquest' arg switch is required for the latter.
1003 * from the player's point of view, going into the Quest is _not_
1004 * going deeper into the dungeon -- it is going back "home", where
1005 * the dungeon starts at level 1. given the setup in dungeon.def,
1006 * the depth of the Quest (thought of as starting at level 1) is
1007 * never lower than the level of entry into the Quest, so we exclude
1008 * the Quest from the topten "deepest level reached" display
1009 * calculation. _However_ the Quest is a difficult dungeon, so we
1010 * include it in the factor of difficulty calculations.
1012 register int i;
1013 d_level tmp;
1014 register schar ret = 0;
1016 for (i = 0; i < n_dgns; i++) {
1017 if (noquest && i == quest_dnum)
1018 continue;
1019 tmp.dlevel = dungeons[i].dunlev_ureached;
1020 if (tmp.dlevel == 0)
1021 continue;
1022 tmp.dnum = i;
1023 if (depth(&tmp) > ret)
1024 ret = depth(&tmp);
1026 return (xchar) ret;
1029 /* return a bookkeeping level number for purpose of comparisons and
1030 save/restore */
1031 xchar
1032 ledger_no(lev)
1033 d_level *lev;
1035 return (xchar) (lev->dlevel + dungeons[lev->dnum].ledger_start);
1039 * The last level in the bookkeeping list of level is the bottom of the last
1040 * dungeon in the dungeons[] array.
1042 * Maxledgerno() -- which is the max number of levels in the bookkeeping
1043 * list, should not be confused with dunlevs_in_dungeon(lev) -- which
1044 * returns the max number of levels in lev's dungeon, and both should
1045 * not be confused with deepest_lev_reached() -- which returns the lowest
1046 * depth visited by the player.
1048 xchar
1049 maxledgerno()
1051 return (xchar) (dungeons[n_dgns - 1].ledger_start
1052 + dungeons[n_dgns - 1].num_dunlevs);
1055 /* return the dungeon that this ledgerno exists in */
1056 xchar
1057 ledger_to_dnum(ledgerno)
1058 xchar ledgerno;
1060 register int i;
1062 /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */
1063 for (i = 0; i < n_dgns; i++)
1064 if (dungeons[i].ledger_start < ledgerno
1065 && ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs)
1066 return (xchar) i;
1068 panic("level number out of range [ledger_to_dnum(%d)]", (int) ledgerno);
1069 /*NOT REACHED*/
1070 return (xchar) 0;
1073 /* return the level of the dungeon this ledgerno exists in */
1074 xchar
1075 ledger_to_dlev(ledgerno)
1076 xchar ledgerno;
1078 return (xchar) (ledgerno
1079 - dungeons[ledger_to_dnum(ledgerno)].ledger_start);
1082 /* returns the depth of a level, in floors below the surface
1083 (note levels in different dungeons can have the same depth) */
1084 schar
1085 depth(lev)
1086 d_level *lev;
1088 return (schar) (dungeons[lev->dnum].depth_start + lev->dlevel - 1);
1091 /* are "lev1" and "lev2" actually the same? */
1092 boolean
1093 on_level(lev1, lev2)
1094 d_level *lev1, *lev2;
1096 return (boolean) (lev1->dnum == lev2->dnum
1097 && lev1->dlevel == lev2->dlevel);
1100 /* is this level referenced in the special level chain? */
1101 s_level *
1102 Is_special(lev)
1103 d_level *lev;
1105 s_level *levtmp;
1107 for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
1108 if (on_level(lev, &levtmp->dlevel))
1109 return levtmp;
1111 return (s_level *) 0;
1115 * Is this a multi-dungeon branch level? If so, return a pointer to the
1116 * branch. Otherwise, return null.
1118 branch *
1119 Is_branchlev(lev)
1120 d_level *lev;
1122 branch *curr;
1124 for (curr = branches; curr; curr = curr->next) {
1125 if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
1126 return curr;
1128 return (branch *) 0;
1131 /* returns True iff the branch 'lev' is in a branch which builds up */
1132 boolean
1133 builds_up(lev)
1134 d_level *lev;
1136 dungeon *dptr = &dungeons[lev->dnum];
1138 * FIXME: this misclassifies a single level branch reached via stairs
1139 * from below. Saving grace is that no such branches currently exist.
1141 return (boolean) (dptr->num_dunlevs > 1
1142 && dptr->entry_lev == dptr->num_dunlevs);
1145 /* goto the next level (or appropriate dungeon) */
1146 void
1147 next_level(at_stairs)
1148 boolean at_stairs;
1150 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1151 /* Taking a down dungeon branch. */
1152 goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1153 } else {
1154 /* Going down a stairs or jump in a trap door. */
1155 d_level newlevel;
1157 newlevel.dnum = u.uz.dnum;
1158 newlevel.dlevel = u.uz.dlevel + 1;
1159 goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
1163 /* goto the previous level (or appropriate dungeon) */
1164 void
1165 prev_level(at_stairs)
1166 boolean at_stairs;
1168 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1169 /* Taking an up dungeon branch. */
1170 /* KMH -- Upwards branches are okay if not level 1 */
1171 /* (Just make sure it doesn't go above depth 1) */
1172 if (!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet)
1173 done(ESCAPED);
1174 else
1175 goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1176 } else {
1177 /* Going up a stairs or rising through the ceiling. */
1178 d_level newlevel;
1179 newlevel.dnum = u.uz.dnum;
1180 newlevel.dlevel = u.uz.dlevel - 1;
1181 goto_level(&newlevel, at_stairs, FALSE, FALSE);
1185 void
1186 u_on_newpos(x, y)
1187 int x, y;
1189 u.ux = x;
1190 u.uy = y;
1191 #ifdef CLIPPING
1192 cliparound(u.ux, u.uy);
1193 #endif
1194 /* ridden steed always shares hero's location */
1195 if (u.usteed)
1196 u.usteed->mx = u.ux, u.usteed->my = u.uy;
1197 /* when changing levels, don't leave old position set with
1198 stale values from previous level */
1199 if (!on_level(&u.uz, &u.uz0))
1200 u.ux0 = u.ux, u.uy0 = u.uy;
1203 /* place you on a random location */
1204 void
1205 u_on_rndspot(upflag)
1206 int upflag;
1208 int up = (upflag & 1), was_in_W_tower = (upflag & 2);
1211 * Place the hero at a random location within the relevant region.
1212 * place_lregion(xTELE) -> put_lregion_here(xTELE) -> u_on_newpos()
1213 * Unspecified region (.lx == 0) defaults to entire level.
1215 if (was_in_W_tower && On_W_tower_level(&u.uz))
1216 /* Stay inside the Wizard's tower when feasible.
1217 We use the W Tower's exclusion region for the
1218 destination instead of its enclosing region.
1219 Note: up vs down doesn't matter in this case
1220 because both specify the same exclusion area. */
1221 place_lregion(dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy, 0, 0, 0,
1222 0, LR_DOWNTELE, (d_level *) 0);
1223 else if (up)
1224 place_lregion(updest.lx, updest.ly, updest.hx, updest.hy, updest.nlx,
1225 updest.nly, updest.nhx, updest.nhy, LR_UPTELE,
1226 (d_level *) 0);
1227 else
1228 place_lregion(dndest.lx, dndest.ly, dndest.hx, dndest.hy, dndest.nlx,
1229 dndest.nly, dndest.nhx, dndest.nhy, LR_DOWNTELE,
1230 (d_level *) 0);
1233 /* place you on the special staircase */
1234 void
1235 u_on_sstairs(upflag)
1236 int upflag;
1238 if (sstairs.sx)
1239 u_on_newpos(sstairs.sx, sstairs.sy);
1240 else
1241 u_on_rndspot(upflag);
1244 /* place you on upstairs (or special equivalent) */
1245 void
1246 u_on_upstairs()
1248 if (xupstair)
1249 u_on_newpos(xupstair, yupstair);
1250 else
1251 u_on_sstairs(0); /* destination upstairs implies moving down */
1254 /* place you on dnstairs (or special equivalent) */
1255 void
1256 u_on_dnstairs()
1258 if (xdnstair)
1259 u_on_newpos(xdnstair, ydnstair);
1260 else
1261 u_on_sstairs(1); /* destination dnstairs implies moving up */
1264 boolean
1265 On_stairs(x, y)
1266 xchar x, y;
1268 return (boolean) ((x == xupstair && y == yupstair)
1269 || (x == xdnstair && y == ydnstair)
1270 || (x == xdnladder && y == ydnladder)
1271 || (x == xupladder && y == yupladder)
1272 || (x == sstairs.sx && y == sstairs.sy));
1275 boolean
1276 Is_botlevel(lev)
1277 d_level *lev;
1279 return (boolean) (lev->dlevel == dungeons[lev->dnum].num_dunlevs);
1282 boolean
1283 Can_dig_down(lev)
1284 d_level *lev;
1286 return (boolean) (!level.flags.hardfloor
1287 && !Is_botlevel(lev)
1288 && !Invocation_lev(lev));
1292 * Like Can_dig_down (above), but also allows falling through on the
1293 * stronghold level. Normally, the bottom level of a dungeon resists
1294 * both digging and falling.
1296 boolean
1297 Can_fall_thru(lev)
1298 d_level *lev;
1300 return (boolean) (Can_dig_down(lev) || Is_stronghold(lev));
1304 * True if one can rise up a level (e.g. cursed gain level).
1305 * This happens on intermediate dungeon levels or on any top dungeon
1306 * level that has a stairwell style branch to the next higher dungeon.
1307 * Checks for amulets and such must be done elsewhere.
1309 boolean
1310 Can_rise_up(x, y, lev)
1311 int x, y;
1312 d_level *lev;
1314 /* can't rise up from inside the top of the Wizard's tower */
1315 /* KMH -- or in sokoban */
1316 if (In_endgame(lev) || In_sokoban(lev)
1317 || (Is_wiz1_level(lev) && In_W_tower(x, y, lev)))
1318 return FALSE;
1319 return (boolean) (lev->dlevel > 1
1320 || (dungeons[lev->dnum].entry_lev == 1
1321 && ledger_no(lev) != 1
1322 && sstairs.sx && sstairs.up));
1325 boolean
1326 has_ceiling(lev)
1327 d_level *lev;
1329 /* [what about level 1 of the quest?] */
1330 return (boolean) (!Is_airlevel(lev) && !Is_waterlevel(lev));
1334 * It is expected that the second argument of get_level is a depth value,
1335 * either supplied by the user (teleport control) or randomly generated.
1336 * But more than one level can be at the same depth. If the target level
1337 * is "above" the present depth location, get_level must trace "up" from
1338 * the player's location (through the ancestors dungeons) the dungeon
1339 * within which the target level is located. With only one exception
1340 * which does not pass through this routine (see level_tele), teleporting
1341 * "down" is confined to the current dungeon. At present, level teleport
1342 * in dungeons that build up is confined within them.
1344 void
1345 get_level(newlevel, levnum)
1346 d_level *newlevel;
1347 int levnum;
1349 branch *br;
1350 xchar dgn = u.uz.dnum;
1352 if (levnum <= 0) {
1353 /* can only currently happen in endgame */
1354 levnum = u.uz.dlevel;
1355 } else if (levnum
1356 > dungeons[dgn].depth_start + dungeons[dgn].num_dunlevs - 1) {
1357 /* beyond end of dungeon, jump to last level */
1358 levnum = dungeons[dgn].num_dunlevs;
1359 } else {
1360 /* The desired level is in this dungeon or a "higher" one. */
1363 * Branch up the tree until we reach a dungeon that contains the
1364 * levnum.
1366 if (levnum < dungeons[dgn].depth_start) {
1367 do {
1369 * Find the parent dungeon of this dungeon.
1371 * This assumes that end2 is always the "child" and it is
1372 * unique.
1374 for (br = branches; br; br = br->next)
1375 if (br->end2.dnum == dgn)
1376 break;
1377 if (!br)
1378 panic("get_level: can't find parent dungeon");
1380 dgn = br->end1.dnum;
1381 } while (levnum < dungeons[dgn].depth_start);
1384 /* We're within the same dungeon; calculate the level. */
1385 levnum = levnum - dungeons[dgn].depth_start + 1;
1388 newlevel->dnum = dgn;
1389 newlevel->dlevel = levnum;
1392 /* are you in the quest dungeon? */
1393 boolean
1394 In_quest(lev)
1395 d_level *lev;
1397 return (boolean) (lev->dnum == quest_dnum);
1400 /* are you in the mines dungeon? */
1401 boolean
1402 In_mines(lev)
1403 d_level *lev;
1405 return (boolean) (lev->dnum == mines_dnum);
1409 * Return the branch for the given dungeon.
1411 * This function assumes:
1412 * + This is not called with "Dungeons of Doom".
1413 * + There is only _one_ branch to a given dungeon.
1414 * + Field end2 is the "child" dungeon.
1416 branch *
1417 dungeon_branch(s)
1418 const char *s;
1420 branch *br;
1421 xchar dnum;
1423 dnum = dname_to_dnum(s);
1425 /* Find the branch that connects to dungeon i's branch. */
1426 for (br = branches; br; br = br->next)
1427 if (br->end2.dnum == dnum)
1428 break;
1430 if (!br)
1431 panic("dgn_entrance: can't find entrance to %s", s);
1433 return br;
1437 * This returns true if the hero is on the same level as the entrance to
1438 * the named dungeon.
1440 * Called from do.c and mklev.c.
1442 * Assumes that end1 is always the "parent".
1444 boolean
1445 at_dgn_entrance(s)
1446 const char *s;
1448 branch *br;
1450 br = dungeon_branch(s);
1451 return on_level(&u.uz, &br->end1) ? TRUE : FALSE;
1454 /* is `lev' part of Vlad's tower? */
1455 boolean
1456 In_V_tower(lev)
1457 d_level *lev;
1459 return (boolean) (lev->dnum == tower_dnum);
1462 /* is `lev' a level containing the Wizard's tower? */
1463 boolean
1464 On_W_tower_level(lev)
1465 d_level *lev;
1467 return (boolean) (Is_wiz1_level(lev)
1468 || Is_wiz2_level(lev)
1469 || Is_wiz3_level(lev));
1472 /* is <x,y> of `lev' inside the Wizard's tower? */
1473 boolean
1474 In_W_tower(x, y, lev)
1475 int x, y;
1476 d_level *lev;
1478 if (!On_W_tower_level(lev))
1479 return FALSE;
1481 * Both of the exclusion regions for arriving via level teleport
1482 * (from above or below) define the tower's boundary.
1483 * assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} );
1485 if (dndest.nlx > 0)
1486 return (boolean) within_bounded_area(x, y, dndest.nlx, dndest.nly,
1487 dndest.nhx, dndest.nhy);
1488 else
1489 impossible("No boundary for Wizard's Tower?");
1490 return FALSE;
1493 /* are you in one of the Hell levels? */
1494 boolean
1495 In_hell(lev)
1496 d_level *lev;
1498 return (boolean) (dungeons[lev->dnum].flags.hellish);
1501 /* sets *lev to be the gateway to Gehennom... */
1502 void
1503 find_hell(lev)
1504 d_level *lev;
1506 lev->dnum = valley_level.dnum;
1507 lev->dlevel = 1;
1510 /* go directly to hell... */
1511 void
1512 goto_hell(at_stairs, falling)
1513 boolean at_stairs, falling;
1515 d_level lev;
1517 find_hell(&lev);
1518 goto_level(&lev, at_stairs, falling, FALSE);
1521 /* equivalent to dest = source */
1522 void
1523 assign_level(dest, src)
1524 d_level *dest, *src;
1526 dest->dnum = src->dnum;
1527 dest->dlevel = src->dlevel;
1530 /* dest = src + rn1(range) */
1531 void
1532 assign_rnd_level(dest, src, range)
1533 d_level *dest, *src;
1534 int range;
1536 dest->dnum = src->dnum;
1537 dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range));
1539 if (dest->dlevel > dunlevs_in_dungeon(dest))
1540 dest->dlevel = dunlevs_in_dungeon(dest);
1541 else if (dest->dlevel < 1)
1542 dest->dlevel = 1;
1546 induced_align(pct)
1547 int pct;
1549 s_level *lev = Is_special(&u.uz);
1550 aligntyp al;
1552 if (lev && lev->flags.align)
1553 if (rn2(100) < pct)
1554 return lev->flags.align;
1556 if (dungeons[u.uz.dnum].flags.align)
1557 if (rn2(100) < pct)
1558 return dungeons[u.uz.dnum].flags.align;
1560 al = rn2(3) - 1;
1561 return Align2amask(al);
1564 boolean
1565 Invocation_lev(lev)
1566 d_level *lev;
1568 return (boolean) (In_hell(lev)
1569 && lev->dlevel == dungeons[lev->dnum].num_dunlevs - 1);
1572 /* use instead of depth() wherever a degree of difficulty is made
1573 * dependent on the location in the dungeon (eg. monster creation).
1575 xchar
1576 level_difficulty()
1578 int res;
1580 if (In_endgame(&u.uz)) {
1581 res = depth(&sanctum_level) + u.ulevel / 2;
1582 } else if (u.uhave.amulet) {
1583 res = deepest_lev_reached(FALSE);
1584 } else {
1585 res = depth(&u.uz);
1586 /* depth() is the number of elevation units (levels) below
1587 the theoretical surface; in a builds-up branch, that value
1588 ends up making the harder to reach levels be treated as if
1589 they were easier; adjust for the extra effort involved in
1590 going down to the entrance and then up to the location */
1591 if (builds_up(&u.uz))
1592 res += 2 * (dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1);
1594 * 'Proof' by example: suppose the entrance to sokoban is
1595 * on dungeon level 9, leading up to bottom sokoban level
1596 * of 8 [entry_lev]. When the hero is on sokoban level 8
1597 * [uz.dlevel], depth() yields eight but he has ventured
1598 * one level beyond 9, so difficulty depth should be 10:
1599 * 8 + 2 * (8 - 8 + 1) => 10.
1600 * Going up to 7, depth is 7 but hero will be two beyond 9:
1601 * 7 + 2 * (8 - 7 + 1) => 11.
1602 * When he goes up to level 6, three levels beyond 9:
1603 * 6 + 2 * (8 - 6 + 1) => 12.
1604 * And the top level of sokoban at 5, four levels beyond 9:
1605 * 5 + 2 * (8 - 5 + 1) => 13.
1606 * The same applies to Vlad's Tower, although the increment
1607 * there is inconsequential compared to overall depth.
1609 #if 0
1611 * The inside of the Wizard's Tower is also effectively a
1612 * builds-up area, reached from a portal an arbitrary distance
1613 * below rather than stairs 1 level beneath the entry level.
1615 else if (On_W_tower_level(&u.uz) && In_W_tower(some_X, some_Y, &u.uz))
1616 res += (fakewiz1.dlev - u.uz.dlev);
1618 * Handling this properly would need more information here:
1619 * an inside/outside flag, or coordinates to calculate it.
1620 * Unfortunately level difficulty may be wanted before
1621 * coordinates have been chosen so simply extending this
1622 * routine to take extra arguments is not sufficient to cope.
1623 * The difference beyond naive depth-from-surface is small
1624 * relative to the overall depth, so just ignore complications
1625 * posed by W_tower.
1627 #endif /*0*/
1629 return (xchar) res;
1632 /* Take one word and try to match it to a level.
1633 * Recognized levels are as shown by print_dungeon().
1635 schar
1636 lev_by_name(nam)
1637 const char *nam;
1639 schar lev = 0;
1640 s_level *slev;
1641 d_level dlev;
1642 const char *p;
1643 int idx, idxtoo;
1644 char buf[BUFSZ];
1646 /* allow strings like "the oracle level" to find "oracle" */
1647 if (!strncmpi(nam, "the ", 4))
1648 nam += 4;
1649 if ((p = strstri(nam, " level")) != 0 && p == eos((char *) nam) - 6) {
1650 nam = strcpy(buf, nam);
1651 *(eos(buf) - 6) = '\0';
1653 /* hell is the old name, and wouldn't match; gehennom would match its
1654 branch, yielding the castle level instead of the valley of the dead */
1655 if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) {
1656 if (In_V_tower(&u.uz))
1657 nam = " to Vlad's tower"; /* branch to... */
1658 else
1659 nam = "valley";
1662 if ((slev = find_level(nam)) != 0) {
1663 dlev = slev->dlevel;
1664 idx = ledger_no(&dlev);
1665 if ((dlev.dnum == u.uz.dnum
1666 /* within same branch, or else main dungeon <-> gehennom */
1667 || (u.uz.dnum == valley_level.dnum
1668 && dlev.dnum == medusa_level.dnum)
1669 || (u.uz.dnum == medusa_level.dnum
1670 && dlev.dnum == valley_level.dnum))
1671 && (/* either wizard mode or else seen and not forgotten */
1672 wizard
1673 || (level_info[idx].flags & (FORGOTTEN | VISITED))
1674 == VISITED)) {
1675 lev = depth(&slev->dlevel);
1677 } else { /* not a specific level; try branch names */
1678 idx = find_branch(nam, (struct proto_dungeon *) 0);
1679 /* "<branch> to Xyzzy" */
1680 if (idx < 0 && (p = strstri(nam, " to ")) != 0)
1681 idx = find_branch(p + 4, (struct proto_dungeon *) 0);
1683 if (idx >= 0) {
1684 idxtoo = (idx >> 8) & 0x00FF;
1685 idx &= 0x00FF;
1686 if (/* either wizard mode, or else _both_ sides of branch seen */
1687 wizard
1688 || ((level_info[idx].flags & (FORGOTTEN | VISITED)) == VISITED
1689 && (level_info[idxtoo].flags & (FORGOTTEN | VISITED))
1690 == VISITED)) {
1691 if (ledger_to_dnum(idxtoo) == u.uz.dnum)
1692 idx = idxtoo;
1693 dlev.dnum = ledger_to_dnum(idx);
1694 dlev.dlevel = ledger_to_dlev(idx);
1695 lev = depth(&dlev);
1699 return lev;
1702 STATIC_OVL boolean
1703 unplaced_floater(dptr)
1704 struct dungeon *dptr;
1706 branch *br;
1707 int idx = (int) (dptr - dungeons);
1709 /* if other floating branches are added, this will need to change */
1710 if (idx != knox_level.dnum)
1711 return FALSE;
1712 for (br = branches; br; br = br->next)
1713 if (br->end1.dnum == n_dgns && br->end2.dnum == idx)
1714 return TRUE;
1715 return FALSE;
1718 STATIC_OVL boolean
1719 unreachable_level(lvl_p, unplaced)
1720 d_level *lvl_p;
1721 boolean unplaced;
1723 s_level *dummy;
1725 if (unplaced)
1726 return TRUE;
1727 if (In_endgame(&u.uz) && !In_endgame(lvl_p))
1728 return TRUE;
1729 if ((dummy = find_level("dummy")) != 0 && on_level(lvl_p, &dummy->dlevel))
1730 return TRUE;
1731 return FALSE;
1734 static void
1735 tport_menu(win, entry, lchoices, lvl_p, unreachable)
1736 winid win;
1737 char *entry;
1738 struct lchoice *lchoices;
1739 d_level *lvl_p;
1740 boolean unreachable;
1742 char tmpbuf[BUFSZ];
1743 anything any;
1745 lchoices->lev[lchoices->idx] = lvl_p->dlevel;
1746 lchoices->dgn[lchoices->idx] = lvl_p->dnum;
1747 lchoices->playerlev[lchoices->idx] = depth(lvl_p);
1748 any = zeroany;
1749 if (unreachable) {
1750 /* not selectable, but still consumes next menuletter;
1751 prepend padding in place of missing menu selector */
1752 Sprintf(tmpbuf, " %s", entry);
1753 entry = tmpbuf;
1754 } else {
1755 any.a_int = lchoices->idx + 1;
1757 add_menu(win, NO_GLYPH, &any, lchoices->menuletter, 0, ATR_NONE, entry,
1758 MENU_UNSELECTED);
1759 /* this assumes there are at most 52 interesting levels */
1760 if (lchoices->menuletter == 'z')
1761 lchoices->menuletter = 'A';
1762 else
1763 lchoices->menuletter++;
1764 lchoices->idx++;
1765 return;
1768 /* Convert a branch type to a string usable by print_dungeon(). */
1769 STATIC_OVL const char *
1770 br_string(type)
1771 int type;
1773 switch (type) {
1774 case BR_PORTAL:
1775 return "Portal";
1776 case BR_NO_END1:
1777 return "Connection";
1778 case BR_NO_END2:
1779 return "One way stair";
1780 case BR_STAIR:
1781 return "Stair";
1783 return " (unknown)";
1786 /* Print all child branches between the lower and upper bounds. */
1787 STATIC_OVL void
1788 print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices_p)
1789 winid win;
1790 int dnum;
1791 int lower_bound;
1792 int upper_bound;
1793 boolean bymenu;
1794 struct lchoice *lchoices_p;
1796 branch *br;
1797 char buf[BUFSZ];
1799 /* This assumes that end1 is the "parent". */
1800 for (br = branches; br; br = br->next) {
1801 if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel
1802 && br->end1.dlevel <= upper_bound) {
1803 Sprintf(buf, " %s to %s: %d", br_string(br->type),
1804 dungeons[br->end2.dnum].dname, depth(&br->end1));
1805 if (bymenu)
1806 tport_menu(win, buf, lchoices_p, &br->end1,
1807 unreachable_level(&br->end1, FALSE));
1808 else
1809 putstr(win, 0, buf);
1814 /* Print available dungeon information. */
1815 schar
1816 print_dungeon(bymenu, rlev, rdgn)
1817 boolean bymenu;
1818 schar *rlev;
1819 xchar *rdgn;
1821 int i, last_level, nlev;
1822 char buf[BUFSZ];
1823 const char *descr;
1824 boolean first, unplaced;
1825 s_level *slev;
1826 dungeon *dptr;
1827 branch *br;
1828 anything any;
1829 struct lchoice lchoices;
1831 winid win = create_nhwindow(NHW_MENU);
1832 if (bymenu) {
1833 start_menu(win);
1834 lchoices.idx = 0;
1835 lchoices.menuletter = 'a';
1838 for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
1839 if (bymenu && In_endgame(&u.uz) && i != astral_level.dnum)
1840 continue;
1841 unplaced = unplaced_floater(dptr);
1842 descr = unplaced ? "depth" : "level";
1843 nlev = dptr->num_dunlevs;
1844 if (nlev > 1)
1845 Sprintf(buf, "%s: %s %d to %d", dptr->dname, makeplural(descr),
1846 dptr->depth_start, dptr->depth_start + nlev - 1);
1847 else
1848 Sprintf(buf, "%s: %s %d", dptr->dname, descr, dptr->depth_start);
1850 /* Most entrances are uninteresting. */
1851 if (dptr->entry_lev != 1) {
1852 if (dptr->entry_lev == nlev)
1853 Strcat(buf, ", entrance from below");
1854 else
1855 Sprintf(eos(buf), ", entrance on %d",
1856 dptr->depth_start + dptr->entry_lev - 1);
1858 if (bymenu) {
1859 any = zeroany;
1860 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf,
1861 MENU_UNSELECTED);
1862 } else
1863 putstr(win, 0, buf);
1866 * Circle through the special levels to find levels that are in
1867 * this dungeon.
1869 for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
1870 if (slev->dlevel.dnum != i)
1871 continue;
1873 /* print any branches before this level */
1874 print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu,
1875 &lchoices);
1877 Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel));
1878 if (Is_stronghold(&slev->dlevel))
1879 Sprintf(eos(buf), " (tune %s)", tune);
1880 if (bymenu)
1881 tport_menu(win, buf, &lchoices, &slev->dlevel,
1882 unreachable_level(&slev->dlevel, unplaced));
1883 else
1884 putstr(win, 0, buf);
1886 last_level = slev->dlevel.dlevel;
1888 /* print branches after the last special level */
1889 print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices);
1892 if (bymenu) {
1893 int n;
1894 menu_item *selected;
1895 int idx;
1897 end_menu(win, "Level teleport to where:");
1898 n = select_menu(win, PICK_ONE, &selected);
1899 destroy_nhwindow(win);
1900 if (n > 0) {
1901 idx = selected[0].item.a_int - 1;
1902 free((genericptr_t) selected);
1903 if (rlev && rdgn) {
1904 *rlev = lchoices.lev[idx];
1905 *rdgn = lchoices.dgn[idx];
1906 return lchoices.playerlev[idx];
1909 return 0;
1912 /* Print out floating branches (if any). */
1913 for (first = TRUE, br = branches; br; br = br->next) {
1914 if (br->end1.dnum == n_dgns) {
1915 if (first) {
1916 putstr(win, 0, "");
1917 putstr(win, 0, "Floating branches");
1918 first = FALSE;
1920 Sprintf(buf, " %s to %s", br_string(br->type),
1921 dungeons[br->end2.dnum].dname);
1922 putstr(win, 0, buf);
1926 /* I hate searching for the invocation pos while debugging. -dean */
1927 if (Invocation_lev(&u.uz)) {
1928 putstr(win, 0, "");
1929 Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)",
1930 inv_pos.x, inv_pos.y, u.ux, u.uy);
1931 putstr(win, 0, buf);
1934 * The following is based on the assumption that the inter-level portals
1935 * created by the level compiler (not the dungeon compiler) only exist
1936 * one per level (currently true, of course).
1938 else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
1939 || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
1940 struct trap *trap;
1941 for (trap = ftrap; trap; trap = trap->ntrap)
1942 if (trap->ttyp == MAGIC_PORTAL)
1943 break;
1945 putstr(win, 0, "");
1946 if (trap)
1947 Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)", trap->tx,
1948 trap->ty, u.ux, u.uy);
1949 else
1950 Sprintf(buf, "No portal found.");
1951 putstr(win, 0, buf);
1954 display_nhwindow(win, TRUE);
1955 destroy_nhwindow(win);
1956 return 0;
1959 /* Record that the player knows about a branch from a level. This function
1960 * will determine whether or not it was a "real" branch that was taken.
1961 * This function should not be called for a transition done via level
1962 * teleport or via the Eye.
1964 void
1965 recbranch_mapseen(source, dest)
1966 d_level *source;
1967 d_level *dest;
1969 mapseen *mptr;
1970 branch *br;
1972 /* not a branch */
1973 if (source->dnum == dest->dnum)
1974 return;
1976 /* we only care about forward branches */
1977 for (br = branches; br; br = br->next) {
1978 if (on_level(source, &br->end1) && on_level(dest, &br->end2))
1979 break;
1980 if (on_level(source, &br->end2) && on_level(dest, &br->end1))
1981 return;
1984 /* branch not found, so not a real branch. */
1985 if (!br)
1986 return;
1988 if ((mptr = find_mapseen(source)) != 0) {
1989 if (mptr->br && br != mptr->br)
1990 impossible("Two branches on the same level?");
1991 mptr->br = br;
1992 } else {
1993 impossible("Can't note branch for unseen level (%d, %d)",
1994 source->dnum, source->dlevel);
1998 char *
1999 get_annotation(lev)
2000 d_level *lev;
2002 mapseen *mptr;
2004 if ((mptr = find_mapseen(lev)))
2005 return mptr->custom;
2006 return NULL;
2009 /* #annotate command - add a custom name to the current level */
2011 donamelevel()
2013 mapseen *mptr;
2014 char nbuf[BUFSZ]; /* Buffer for response */
2016 if (!(mptr = find_mapseen(&u.uz)))
2017 return 0;
2019 if (mptr->custom) {
2020 char tmpbuf[BUFSZ];
2021 Sprintf(tmpbuf, "Replace annotation \"%.30s%s\" with?", mptr->custom,
2022 strlen(mptr->custom) > 30 ? "..." : "");
2023 getlin(tmpbuf, nbuf);
2024 } else
2025 getlin("What do you want to call this dungeon level?", nbuf);
2026 if (index(nbuf, '\033'))
2027 return 0;
2028 (void) mungspaces(nbuf);
2030 /* discard old annotation, if any */
2031 if (mptr->custom) {
2032 free((genericptr_t) mptr->custom);
2033 mptr->custom = (char *) 0;
2034 mptr->custom_lth = 0;
2036 /* add new annotation, unless it's empty or a single space */
2037 if (*nbuf && strcmp(nbuf, " ")) {
2038 mptr->custom = dupstr(nbuf);
2039 mptr->custom_lth = strlen(mptr->custom);
2041 return 0;
2044 /* find the particular mapseen object in the chain; may return null */
2045 STATIC_OVL mapseen *
2046 find_mapseen(lev)
2047 d_level *lev;
2049 mapseen *mptr;
2051 for (mptr = mapseenchn; mptr; mptr = mptr->next)
2052 if (on_level(&(mptr->lev), lev))
2053 break;
2055 return mptr;
2058 void
2059 forget_mapseen(ledger_num)
2060 int ledger_num;
2062 mapseen *mptr;
2063 struct cemetery *bp;
2065 for (mptr = mapseenchn; mptr; mptr = mptr->next)
2066 if (dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel
2067 == ledger_num)
2068 break;
2070 /* if not found, then nothing to forget */
2071 if (mptr) {
2072 mptr->flags.forgot = 1;
2073 mptr->br = (branch *) 0;
2075 /* custom names are erased, not just forgotten until revisited */
2076 if (mptr->custom) {
2077 mptr->custom_lth = 0;
2078 free((genericptr_t) mptr->custom);
2079 mptr->custom = (char *) 0;
2081 (void) memset((genericptr_t) mptr->msrooms, 0, sizeof mptr->msrooms);
2082 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2083 bp->bonesknown = FALSE;
2087 STATIC_OVL void
2088 save_mapseen(fd, mptr)
2089 int fd;
2090 mapseen *mptr;
2092 branch *curr;
2093 int brindx;
2095 for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx)
2096 if (curr == mptr->br)
2097 break;
2098 bwrite(fd, (genericptr_t) &brindx, sizeof brindx);
2100 bwrite(fd, (genericptr_t) &mptr->lev, sizeof mptr->lev);
2101 bwrite(fd, (genericptr_t) &mptr->feat, sizeof mptr->feat);
2102 bwrite(fd, (genericptr_t) &mptr->flags, sizeof mptr->flags);
2103 bwrite(fd, (genericptr_t) &mptr->custom_lth, sizeof mptr->custom_lth);
2104 if (mptr->custom_lth)
2105 bwrite(fd, (genericptr_t) mptr->custom, mptr->custom_lth);
2106 bwrite(fd, (genericptr_t) &mptr->msrooms, sizeof mptr->msrooms);
2107 savecemetery(fd, WRITE_SAVE, &mptr->final_resting_place);
2110 STATIC_OVL mapseen *
2111 load_mapseen(fd)
2112 int fd;
2114 int branchnum, brindx;
2115 mapseen *load;
2116 branch *curr;
2118 load = (mapseen *) alloc(sizeof *load);
2120 mread(fd, (genericptr_t) &branchnum, sizeof branchnum);
2121 for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx)
2122 if (brindx == branchnum)
2123 break;
2124 load->br = curr;
2126 mread(fd, (genericptr_t) &load->lev, sizeof load->lev);
2127 mread(fd, (genericptr_t) &load->feat, sizeof load->feat);
2128 mread(fd, (genericptr_t) &load->flags, sizeof load->flags);
2129 mread(fd, (genericptr_t) &load->custom_lth, sizeof load->custom_lth);
2130 if (load->custom_lth) {
2131 /* length doesn't include terminator (which isn't saved & restored) */
2132 load->custom = (char *) alloc(load->custom_lth + 1);
2133 mread(fd, (genericptr_t) load->custom, load->custom_lth);
2134 load->custom[load->custom_lth] = '\0';
2135 } else
2136 load->custom = 0;
2137 mread(fd, (genericptr_t) &load->msrooms, sizeof load->msrooms);
2138 restcemetery(fd, &load->final_resting_place);
2140 return load;
2143 /* to support '#stats' wizard-mode command */
2144 void
2145 overview_stats(win, statsfmt, total_count, total_size)
2146 winid win;
2147 const char *statsfmt;
2148 long *total_count, *total_size;
2150 char buf[BUFSZ], hdrbuf[QBUFSZ];
2151 long ocount, osize, bcount, bsize, acount, asize;
2152 struct cemetery *ce;
2153 mapseen *mptr = find_mapseen(&u.uz);
2155 ocount = bcount = acount = osize = bsize = asize = 0L;
2156 for (mptr = mapseenchn; mptr; mptr = mptr->next) {
2157 ++ocount;
2158 osize += (long) sizeof *mptr;
2159 for (ce = mptr->final_resting_place; ce; ce = ce->next) {
2160 ++bcount;
2161 bsize += (long) sizeof *ce;
2163 if (mptr->custom_lth) {
2164 ++acount;
2165 asize += (long) (mptr->custom_lth + 1);
2169 Sprintf(hdrbuf, "general, size %ld", (long) sizeof (mapseen));
2170 Sprintf(buf, statsfmt, hdrbuf, ocount, osize);
2171 putstr(win, 0, buf);
2172 if (bcount) {
2173 Sprintf(hdrbuf, "cemetery, size %ld",
2174 (long) sizeof (struct cemetery));
2175 Sprintf(buf, statsfmt, hdrbuf, bcount, bsize);
2176 putstr(win, 0, buf);
2178 if (acount) {
2179 Sprintf(hdrbuf, "annotations, text");
2180 Sprintf(buf, statsfmt, hdrbuf, acount, asize);
2181 putstr(win, 0, buf);
2183 *total_count += ocount + bcount + acount;
2184 *total_size += osize + bsize + asize;
2187 /* Remove all mapseen objects for a particular dnum.
2188 * Useful during quest expulsion to remove quest levels.
2189 * [No longer deleted, just marked as unreachable. #overview will
2190 * ignore such levels, end of game disclosure will include them.]
2192 void
2193 remdun_mapseen(dnum)
2194 int dnum;
2196 mapseen *mptr, **mptraddr;
2198 mptraddr = &mapseenchn;
2199 while ((mptr = *mptraddr) != 0) {
2200 if (mptr->lev.dnum == dnum) {
2201 #if 1 /* use this... */
2202 mptr->flags.unreachable = 1;
2204 #else /* old deletion code */
2205 *mptraddr = mptr->next;
2206 if (mptr->custom)
2207 free((genericptr_t) mptr->custom);
2208 if (mptr->final_resting_place)
2209 savecemetery(-1, FREE_SAVE, &mptr->final_resting_place);
2210 free((genericptr_t) mptr);
2211 } else
2212 #endif
2213 mptraddr = &mptr->next;
2217 void
2218 init_mapseen(lev)
2219 d_level *lev;
2221 /* Create a level and insert in "sorted" order. This is an insertion
2222 * sort first by dungeon (in order of discovery) and then by level number.
2224 mapseen *mptr, *init, *prev;
2226 init = (mapseen *) alloc(sizeof *init);
2227 (void) memset((genericptr_t) init, 0, sizeof *init);
2228 /* memset is fine for feature bits, flags, and rooms array;
2229 explicitly initialize pointers to null */
2230 init->next = 0, init->br = 0, init->custom = 0;
2231 init->final_resting_place = 0;
2232 /* lastseentyp[][] is reused for each level, so get rid of
2233 previous level's data */
2234 (void) memset((genericptr_t) lastseentyp, 0, sizeof lastseentyp);
2236 init->lev.dnum = lev->dnum;
2237 init->lev.dlevel = lev->dlevel;
2239 /* walk until we get to the place where we should insert init */
2240 for (mptr = mapseenchn, prev = 0; mptr; prev = mptr, mptr = mptr->next)
2241 if (mptr->lev.dnum > init->lev.dnum
2242 || (mptr->lev.dnum == init->lev.dnum
2243 && mptr->lev.dlevel > init->lev.dlevel))
2244 break;
2245 if (!prev) {
2246 init->next = mapseenchn;
2247 mapseenchn = init;
2248 } else {
2249 mptr = prev->next;
2250 prev->next = init;
2251 init->next = mptr;
2255 #define INTEREST(feat) \
2256 ((feat).nfount || (feat).nsink || (feat).nthrone || (feat).naltar \
2257 || (feat).ngrave || (feat).ntree || (feat).nshop || (feat).ntemple)
2258 /* || (feat).water || (feat).ice || (feat).lava */
2260 /* returns true if this level has something interesting to print out */
2261 STATIC_OVL boolean
2262 interest_mapseen(mptr)
2263 mapseen *mptr;
2265 if (on_level(&u.uz, &mptr->lev))
2266 return TRUE;
2267 if (mptr->flags.unreachable || mptr->flags.forgot)
2268 return FALSE;
2269 /* level is of interest if it has an auto-generated annotation */
2270 if (mptr->flags.oracle || mptr->flags.bigroom || mptr->flags.roguelevel
2271 || mptr->flags.castle || mptr->flags.valley || mptr->flags.msanctum
2272 || mptr->flags.quest_summons || mptr->flags.questing)
2273 return TRUE;
2274 /* when in Sokoban, list all sokoban levels visited; when not in it,
2275 list any visited Sokoban level which remains unsolved (will usually
2276 only be furthest one reached, but it's possible to enter pits and
2277 climb out on the far side on the first Sokoban level; also, wizard
2278 mode overrides teleport restrictions) */
2279 if (In_sokoban(&mptr->lev)
2280 && (In_sokoban(&u.uz) || !mptr->flags.sokosolved))
2281 return TRUE;
2282 /* when in the endgame, list all endgame levels visited, whether they
2283 have annotations or not, so that #overview doesn't become extremely
2284 sparse once the rest of the dungeon has been flagged as unreachable */
2285 if (In_endgame(&u.uz))
2286 return (boolean) In_endgame(&mptr->lev);
2287 /* level is of interest if it has non-zero feature count or known bones
2288 or user annotation or known connection to another dungeon branch
2289 or is the furthest level reached in its branch */
2290 return (boolean) (INTEREST(mptr->feat)
2291 || (mptr->final_resting_place
2292 && (mptr->flags.knownbones || wizard))
2293 || mptr->custom || mptr->br
2294 || (mptr->lev.dlevel
2295 == dungeons[mptr->lev.dnum].dunlev_ureached));
2298 /* recalculate mapseen for the current level */
2299 void
2300 recalc_mapseen()
2302 mapseen *mptr;
2303 struct monst *mtmp;
2304 struct cemetery *bp, **bonesaddr;
2305 unsigned i, ridx;
2306 int x, y, ltyp, count, atmp;
2308 /* Should not happen in general, but possible if in the process
2309 * of being booted from the quest. The mapseen object gets
2310 * removed during the expulsion but prior to leaving the level
2311 * [Since quest expulsion no longer deletes quest mapseen data,
2312 * null return from find_mapseen() should now be impossible.]
2314 if (!(mptr = find_mapseen(&u.uz)))
2315 return;
2317 /* reset all features; mptr->feat.* = 0; */
2318 (void) memset((genericptr_t) &mptr->feat, 0, sizeof mptr->feat);
2319 /* reset most flags; some level-specific ones are left as-is */
2320 if (mptr->flags.unreachable) {
2321 mptr->flags.unreachable = 0; /* reached it; Eye of the Aethiopica? */
2322 if (In_quest(&u.uz)) {
2323 mapseen *mptrtmp = mapseenchn;
2325 /* when quest was unreachable due to ejection and portal removal,
2326 getting back to it via arti-invoke should revive annotation
2327 data for all quest levels, not just the one we're on now */
2328 do {
2329 if (mptrtmp->lev.dnum == mptr->lev.dnum)
2330 mptrtmp->flags.unreachable = 0;
2331 mptrtmp = mptrtmp->next;
2332 } while (mptrtmp);
2335 mptr->flags.knownbones = 0;
2336 mptr->flags.sokosolved = In_sokoban(&u.uz) && !Sokoban;
2337 /* mptr->flags.bigroom retains previous value when hero can't see */
2338 if (!Blind)
2339 mptr->flags.bigroom = Is_bigroom(&u.uz);
2340 else if (mptr->flags.forgot)
2341 mptr->flags.bigroom = 0;
2342 mptr->flags.roguelevel = Is_rogue_level(&u.uz);
2343 mptr->flags.oracle = 0; /* recalculated during room traversal below */
2344 mptr->flags.castletune = 0;
2345 /* flags.castle, flags.valley, flags.msanctum retain previous value */
2346 mptr->flags.forgot = 0;
2347 /* flags.quest_summons disabled once quest finished */
2348 mptr->flags.quest_summons = (at_dgn_entrance("The Quest")
2349 && u.uevent.qcalled
2350 && !(u.uevent.qcompleted
2351 || u.uevent.qexpelled
2352 || quest_status.leader_is_dead));
2353 mptr->flags.questing = (on_level(&u.uz, &qstart_level)
2354 && quest_status.got_quest);
2356 /* track rooms the hero is in */
2357 for (i = 0; i < SIZE(u.urooms); ++i) {
2358 if (!u.urooms[i])
2359 continue;
2361 ridx = u.urooms[i] - ROOMOFFSET;
2362 mptr->msrooms[ridx].seen = 1;
2363 mptr->msrooms[ridx].untended =
2364 (rooms[ridx].rtype >= SHOPBASE)
2365 ? (!(mtmp = shop_keeper(u.urooms[i])) || !inhishop(mtmp))
2366 : (rooms[ridx].rtype == TEMPLE)
2367 ? (!(mtmp = findpriest(u.urooms[i]))
2368 || !inhistemple(mtmp))
2369 : 0;
2372 /* recalculate room knowledge: for now, just shops and temples
2373 * this could be extended to an array of 0..SHOPBASE
2375 for (i = 0; i < SIZE(mptr->msrooms); ++i) {
2376 if (mptr->msrooms[i].seen) {
2377 if (rooms[i].rtype >= SHOPBASE) {
2378 if (mptr->msrooms[i].untended)
2379 mptr->feat.shoptype = SHOPBASE - 1;
2380 else if (!mptr->feat.nshop)
2381 mptr->feat.shoptype = rooms[i].rtype;
2382 else if (mptr->feat.shoptype != (unsigned) rooms[i].rtype)
2383 mptr->feat.shoptype = 0;
2384 count = mptr->feat.nshop + 1;
2385 if (count <= 3)
2386 mptr->feat.nshop = count;
2387 } else if (rooms[i].rtype == TEMPLE) {
2388 /* altar and temple alignment handled below */
2389 count = mptr->feat.ntemple + 1;
2390 if (count <= 3)
2391 mptr->feat.ntemple = count;
2392 } else if (rooms[i].orig_rtype == DELPHI) {
2393 mptr->flags.oracle = 1;
2398 /* Update lastseentyp with typ if and only if it is in sight or the
2399 * hero can feel it on their current location (i.e. not levitating).
2400 * This *should* give the "last known typ" for each dungeon location.
2401 * (At the very least, it's a better assumption than determining what
2402 * the player knows from the glyph and the typ (which is isn't quite
2403 * enough information in some cases)).
2405 * It was reluctantly added to struct rm to track. Alternatively
2406 * we could track "features" and then update them all here, and keep
2407 * track of when new features are created or destroyed, but this
2408 * seemed the most elegant, despite adding more data to struct rm.
2409 * [3.6.0: we're using lastseentyp[][] rather than level.locations
2410 * to track the features seen.]
2412 * Although no current windowing systems (can) do this, this would add
2413 * the ability to have non-dungeon glyphs float above the last known
2414 * dungeon glyph (i.e. items on fountains).
2416 for (x = 1; x < COLNO; x++) {
2417 for (y = 0; y < ROWNO; y++) {
2418 if (cansee(x, y) || (x == u.ux && y == u.uy && !Levitation)) {
2419 ltyp = levl[x][y].typ;
2420 if (ltyp == DRAWBRIDGE_UP)
2421 ltyp = db_under_typ(levl[x][y].drawbridgemask);
2422 if ((mtmp = m_at(x, y)) != 0
2423 && mtmp->m_ap_type == M_AP_FURNITURE && canseemon(mtmp))
2424 ltyp = cmap_to_type(mtmp->mappearance);
2425 lastseentyp[x][y] = ltyp;
2428 switch (lastseentyp[x][y]) {
2429 #if 0
2430 case ICE:
2431 count = mptr->feat.ice + 1;
2432 if (count <= 3)
2433 mptr->feat.ice = count;
2434 break;
2435 case POOL:
2436 case MOAT:
2437 case WATER:
2438 count = mptr->feat.water + 1;
2439 if (count <= 3)
2440 mptr->feat.water = count;
2441 break;
2442 case LAVAPOOL:
2443 count = mptr->feat.lava + 1;
2444 if (count <= 3)
2445 mptr->feat.lava = count;
2446 break;
2447 #endif
2448 case TREE:
2449 count = mptr->feat.ntree + 1;
2450 if (count <= 3)
2451 mptr->feat.ntree = count;
2452 break;
2453 case FOUNTAIN:
2454 count = mptr->feat.nfount + 1;
2455 if (count <= 3)
2456 mptr->feat.nfount = count;
2457 break;
2458 case THRONE:
2459 count = mptr->feat.nthrone + 1;
2460 if (count <= 3)
2461 mptr->feat.nthrone = count;
2462 break;
2463 case SINK:
2464 count = mptr->feat.nsink + 1;
2465 if (count <= 3)
2466 mptr->feat.nsink = count;
2467 break;
2468 case GRAVE:
2469 count = mptr->feat.ngrave + 1;
2470 if (count <= 3)
2471 mptr->feat.ngrave = count;
2472 break;
2473 case ALTAR:
2474 atmp = (Is_astralevel(&u.uz)
2475 && (levl[x][y].seenv & SVALL) != SVALL)
2476 ? MSA_NONE
2477 : Amask2msa(levl[x][y].altarmask);
2478 if (!mptr->feat.naltar)
2479 mptr->feat.msalign = atmp;
2480 else if (mptr->feat.msalign != atmp)
2481 mptr->feat.msalign = MSA_NONE;
2482 count = mptr->feat.naltar + 1;
2483 if (count <= 3)
2484 mptr->feat.naltar = count;
2485 break;
2486 /* An automatic annotation is added to the Castle and
2487 * to Fort Ludios once their structure's main entrance
2488 * has been seen (in person or via magic mapping).
2489 * For the Fort, that entrance is just a secret door
2490 * which will be converted into a regular one when
2491 * located (or destroyed).
2492 * DOOR: possibly a lowered drawbridge's open portcullis;
2493 * DBWALL: a raised drawbridge's "closed door";
2494 * DRAWBRIDGE_DOWN: the span provided by lowered bridge,
2495 * with moat or other terrain hidden underneath;
2496 * DRAWBRIDGE_UP: moat in front of a raised drawbridge,
2497 * not recognizable as a bridge location unless/until
2498 * the adjacent DBWALL has been seen.
2500 case DOOR:
2501 if (Is_knox(&u.uz)) {
2502 int ty, tx = x - 4;
2504 /* Throne is four columns left, either directly in
2505 * line or one row higher or lower, and doesn't have
2506 * to have been seen yet.
2507 * ......|}}}.
2508 * ..\...S}...
2509 * ..\...S}...
2510 * ......|}}}.
2511 * For 3.6.0 and earlier, it was always in direct line:
2512 * both throne and door on the lower of the two rows.
2514 for (ty = y - 1; ty <= y + 1; ++ty)
2515 if (isok(tx, ty) && IS_THRONE(levl[tx][ty].typ)) {
2516 mptr->flags.ludios = 1;
2517 break;
2519 break;
2521 if (is_drawbridge_wall(x, y) < 0)
2522 break;
2523 /* else FALLTHRU */
2524 case DBWALL:
2525 case DRAWBRIDGE_DOWN:
2526 if (Is_stronghold(&u.uz))
2527 mptr->flags.castle = 1, mptr->flags.castletune = 1;
2528 break;
2529 default:
2530 break;
2535 if (level.bonesinfo && !mptr->final_resting_place) {
2536 /* clone the bonesinfo so we aren't dependent upon this
2537 level being in memory */
2538 bonesaddr = &mptr->final_resting_place;
2539 bp = level.bonesinfo;
2540 do {
2541 *bonesaddr = (struct cemetery *) alloc(sizeof **bonesaddr);
2542 **bonesaddr = *bp;
2543 bp = bp->next;
2544 bonesaddr = &(*bonesaddr)->next;
2545 } while (bp);
2546 *bonesaddr = 0;
2548 /* decide which past hero deaths have become known; there's no
2549 guarantee of either a grave or a ghost, so we go by whether the
2550 current hero has seen the map location where each old one died */
2551 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2552 if (lastseentyp[bp->frpx][bp->frpy]) {
2553 bp->bonesknown = TRUE;
2554 mptr->flags.knownbones = 1;
2558 /*ARGUSED*/
2559 /* valley and sanctum levels get automatic annotation once temple is entered
2561 void
2562 mapseen_temple(priest)
2563 struct monst *priest UNUSED; /* currently unused; might be useful someday */
2565 mapseen *mptr = find_mapseen(&u.uz);
2567 if (Is_valley(&u.uz))
2568 mptr->flags.valley = 1;
2569 else if (Is_sanctum(&u.uz))
2570 mptr->flags.msanctum = 1;
2573 /* room entry message has just been delivered so learn room even if blind */
2574 void
2575 room_discovered(roomno)
2576 int roomno;
2578 mapseen *mptr = find_mapseen(&u.uz);
2580 mptr->msrooms[roomno].seen = 1;
2583 /* #overview command */
2585 dooverview()
2587 show_overview(0, 0);
2588 return 0;
2591 /* called for #overview or for end of game disclosure */
2592 void
2593 show_overview(why, reason)
2594 int why; /* 0 => #overview command,
2595 1 or 2 => final disclosure (1: hero lived, 2: hero died) */
2596 int reason; /* how hero died; used when disclosing end-of-game level */
2598 winid win;
2599 int lastdun = -1;
2601 /* lazy initialization */
2602 (void) recalc_mapseen();
2604 win = create_nhwindow(NHW_MENU);
2605 /* show the endgame levels before the rest of the dungeon,
2606 so that the Planes (dnum 5-ish) come out above main dungeon (dnum 0) */
2607 if (In_endgame(&u.uz))
2608 traverse_mapseenchn(TRUE, win, why, reason, &lastdun);
2609 /* if game is over or we're not in the endgame yet, show the dungeon */
2610 if (why > 0 || !In_endgame(&u.uz))
2611 traverse_mapseenchn(FALSE, win, why, reason, &lastdun);
2612 display_nhwindow(win, TRUE);
2613 destroy_nhwindow(win);
2616 /* display endgame levels or non-endgame levels, not both */
2617 STATIC_OVL void
2618 traverse_mapseenchn(viewendgame, win, why, reason, lastdun_p)
2619 boolean viewendgame;
2620 winid win;
2621 int why, reason, *lastdun_p;
2623 mapseen *mptr;
2624 boolean showheader;
2626 for (mptr = mapseenchn; mptr; mptr = mptr->next) {
2627 if (viewendgame ^ In_endgame(&mptr->lev))
2628 continue;
2630 /* only print out info for a level or a dungeon if interest */
2631 if (why > 0 || interest_mapseen(mptr)) {
2632 showheader = (boolean) (mptr->lev.dnum != *lastdun_p);
2633 print_mapseen(win, mptr, why, reason, showheader);
2634 *lastdun_p = mptr->lev.dnum;
2639 STATIC_OVL const char *
2640 seen_string(x, obj)
2641 xchar x;
2642 const char *obj;
2644 /* players are computer scientists: 0, 1, 2, n */
2645 switch (x) {
2646 case 0:
2647 return "no";
2648 /* an() returns too much. index is ok in this case */
2649 case 1:
2650 return index(vowels, *obj) ? "an" : "a";
2651 case 2:
2652 return "some";
2653 case 3:
2654 return "many";
2657 return "(unknown)";
2660 /* better br_string */
2661 STATIC_OVL const char *
2662 br_string2(br)
2663 branch *br;
2665 /* Special case: quest portal says closed if kicked from quest */
2666 boolean closed_portal = (br->end2.dnum == quest_dnum
2667 && u.uevent.qexpelled);
2669 switch (br->type) {
2670 case BR_PORTAL:
2671 return closed_portal ? "Sealed portal" : "Portal";
2672 case BR_NO_END1:
2673 return "Connection";
2674 case BR_NO_END2:
2675 return br->end1_up ? "One way stairs up" : "One way stairs down";
2676 case BR_STAIR:
2677 return br->end1_up ? "Stairs up" : "Stairs down";
2680 return "(unknown)";
2683 /* get the name of an endgame level; topten.c does something similar */
2684 STATIC_OVL const char *
2685 endgamelevelname(outbuf, indx)
2686 char *outbuf;
2687 int indx;
2689 const char *planename = 0;
2691 *outbuf = '\0';
2692 switch (indx) {
2693 case -5:
2694 Strcpy(outbuf, "Astral Plane");
2695 break;
2696 case -4:
2697 planename = "Water";
2698 break;
2699 case -3:
2700 planename = "Fire";
2701 break;
2702 case -2:
2703 planename = "Air";
2704 break;
2705 case -1:
2706 planename = "Earth";
2707 break;
2709 if (planename)
2710 Sprintf(outbuf, "Plane of %s", planename);
2711 else if (!*outbuf)
2712 Sprintf(outbuf, "unknown plane #%d", indx);
2713 return outbuf;
2716 STATIC_OVL const char *
2717 shop_string(rtype)
2718 int rtype;
2720 const char *str = "shop"; /* catchall */
2722 /* Yuck, redundancy...but shclass.name doesn't cut it as a noun */
2723 switch (rtype) {
2724 case SHOPBASE - 1:
2725 str = "untended shop";
2726 break; /* see recalc_mapseen */
2727 case SHOPBASE:
2728 str = "general store";
2729 break;
2730 case ARMORSHOP:
2731 str = "armor shop";
2732 break;
2733 case SCROLLSHOP:
2734 str = "scroll shop";
2735 break;
2736 case POTIONSHOP:
2737 str = "potion shop";
2738 break;
2739 case WEAPONSHOP:
2740 str = "weapon shop";
2741 break;
2742 case FOODSHOP:
2743 str = "delicatessen";
2744 break;
2745 case RINGSHOP:
2746 str = "jewelers";
2747 break;
2748 case WANDSHOP:
2749 str = "wand shop";
2750 break;
2751 case BOOKSHOP:
2752 str = "bookstore";
2753 break;
2754 case FODDERSHOP:
2755 str = "health food store";
2756 break;
2757 case CANDLESHOP:
2758 str = "lighting shop";
2759 break;
2760 default:
2761 break;
2763 return str;
2766 /* if player knows about the mastermind tune, append it to Castle annotation;
2767 if drawbridge has been destroyed, flags.castletune will be zero */
2768 STATIC_OVL char *
2769 tunesuffix(mptr, outbuf)
2770 mapseen *mptr;
2771 char *outbuf;
2773 *outbuf = '\0';
2774 if (mptr->flags.castletune && u.uevent.uheard_tune) {
2775 char tmp[BUFSZ];
2777 if (u.uevent.uheard_tune == 2)
2778 Sprintf(tmp, "notes \"%s\"", tune);
2779 else
2780 Strcpy(tmp, "5-note tune");
2781 Sprintf(outbuf, " (play %s to open or close drawbridge)", tmp);
2783 return outbuf;
2786 /* some utility macros for print_mapseen */
2787 #define TAB " " /* three spaces */
2788 #if 0
2789 #define BULLET "" /* empty; otherwise output becomes cluttered */
2790 #define PREFIX TAB TAB BULLET
2791 #else /*!0*/
2792 /* K&R: don't require support for concatenation of adjacent string literals */
2793 #define PREFIX " " /* two TABs + empty BULLET: six spaces */
2794 #endif
2795 #define COMMA (i++ > 0 ? ", " : PREFIX)
2796 /* "iterate" once; safe to use as ``if (cond) ADDTOBUF(); else whatever;'' */
2797 #define ADDNTOBUF(nam, var) \
2798 do { \
2799 if (var) \
2800 Sprintf(eos(buf), "%s%s %s%s", COMMA, seen_string((var), (nam)), \
2801 (nam), plur(var)); \
2802 } while (0)
2803 #define ADDTOBUF(nam, var) \
2804 do { \
2805 if (var) \
2806 Sprintf(eos(buf), "%s%s", COMMA, (nam)); \
2807 } while (0)
2809 STATIC_OVL void
2810 print_mapseen(win, mptr, final, how, printdun)
2811 winid win;
2812 mapseen *mptr;
2813 int final; /* 0: not final; 1: game over, alive; 2: game over, dead */
2814 int how; /* cause of death; only used if final==2 and mptr->lev==u.uz */
2815 boolean printdun;
2817 char buf[BUFSZ], tmpbuf[BUFSZ];
2818 int i, depthstart, dnum;
2819 boolean died_here = (final == 2 && on_level(&u.uz, &mptr->lev));
2821 /* Damnable special cases */
2822 /* The quest and knox should appear to be level 1 to match
2823 * other text.
2825 dnum = mptr->lev.dnum;
2826 if (dnum == quest_dnum || dnum == knox_level.dnum)
2827 depthstart = 1;
2828 else
2829 depthstart = dungeons[dnum].depth_start;
2831 if (printdun) {
2832 if (dungeons[dnum].dunlev_ureached == dungeons[dnum].entry_lev
2833 /* suppress the negative numbers in the endgame */
2834 || In_endgame(&mptr->lev))
2835 Sprintf(buf, "%s:", dungeons[dnum].dname);
2836 else if (builds_up(&mptr->lev))
2837 Sprintf(buf, "%s: levels %d up to %d",
2838 dungeons[dnum].dname,
2839 depthstart + dungeons[dnum].entry_lev - 1,
2840 depthstart + dungeons[dnum].dunlev_ureached - 1);
2841 else
2842 Sprintf(buf, "%s: levels %d to %d",
2843 dungeons[dnum].dname, depthstart,
2844 depthstart + dungeons[dnum].dunlev_ureached - 1);
2845 putstr(win, !final ? ATR_INVERSE : 0, buf);
2848 /* calculate level number */
2849 i = depthstart + mptr->lev.dlevel - 1;
2850 if (In_endgame(&mptr->lev))
2851 Sprintf(buf, "%s%s:", TAB, endgamelevelname(tmpbuf, i));
2852 else
2853 Sprintf(buf, "%sLevel %d:", TAB, i);
2855 /* wizmode prints out proto dungeon names for clarity */
2856 if (wizard) {
2857 s_level *slev;
2859 if ((slev = Is_special(&mptr->lev)) != 0)
2860 Sprintf(eos(buf), " [%s]", slev->proto);
2862 /* [perhaps print custom annotation on its own line when it's long] */
2863 if (mptr->custom)
2864 Sprintf(eos(buf), " \"%s\"", mptr->custom);
2865 if (on_level(&u.uz, &mptr->lev))
2866 Sprintf(eos(buf), " <- You %s here.",
2867 (!final || (final == 1 && how == ASCENDED)) ? "are"
2868 : (final == 1 && how == ESCAPED) ? "left from"
2869 : "were");
2870 putstr(win, !final ? ATR_BOLD : 0, buf);
2872 if (mptr->flags.forgot)
2873 return;
2875 if (INTEREST(mptr->feat)) {
2876 buf[0] = 0;
2878 i = 0; /* interest counter */
2879 /* List interests in an order vaguely corresponding to
2880 * how important they are.
2882 if (mptr->feat.nshop > 0) {
2883 if (mptr->feat.nshop > 1)
2884 ADDNTOBUF("shop", mptr->feat.nshop);
2885 else
2886 Sprintf(eos(buf), "%s%s", COMMA,
2887 an(shop_string(mptr->feat.shoptype)));
2889 if (mptr->feat.naltar > 0) {
2890 /* Temples + non-temple altars get munged into just "altars" */
2891 if (mptr->feat.ntemple != mptr->feat.naltar)
2892 ADDNTOBUF("altar", mptr->feat.naltar);
2893 else
2894 ADDNTOBUF("temple", mptr->feat.ntemple);
2896 /* only print out altar's god if they are all to your god */
2897 if (Amask2align(Msa2amask(mptr->feat.msalign)) == u.ualign.type)
2898 Sprintf(eos(buf), " to %s", align_gname(u.ualign.type));
2900 ADDNTOBUF("throne", mptr->feat.nthrone);
2901 ADDNTOBUF("fountain", mptr->feat.nfount);
2902 ADDNTOBUF("sink", mptr->feat.nsink);
2903 ADDNTOBUF("grave", mptr->feat.ngrave);
2904 ADDNTOBUF("tree", mptr->feat.ntree);
2905 #if 0
2906 ADDTOBUF("water", mptr->feat.water);
2907 ADDTOBUF("lava", mptr->feat.lava);
2908 ADDTOBUF("ice", mptr->feat.ice);
2909 #endif
2910 /* capitalize afterwards */
2911 i = strlen(PREFIX);
2912 buf[i] = highc(buf[i]);
2913 /* capitalizing it makes it a sentence; terminate with '.' */
2914 Strcat(buf, ".");
2915 putstr(win, 0, buf);
2918 /* we assume that these are mutually exclusive */
2919 *buf = '\0';
2920 if (mptr->flags.oracle) {
2921 Sprintf(buf, "%sOracle of Delphi.", PREFIX);
2922 } else if (In_sokoban(&mptr->lev)) {
2923 Sprintf(buf, "%s%s.", PREFIX,
2924 mptr->flags.sokosolved ? "Solved" : "Unsolved");
2925 } else if (mptr->flags.bigroom) {
2926 Sprintf(buf, "%sA very big room.", PREFIX);
2927 } else if (mptr->flags.roguelevel) {
2928 Sprintf(buf, "%sA primitive area.", PREFIX);
2929 } else if (mptr->flags.quest_summons) {
2930 Sprintf(buf, "%sSummoned by %s.", PREFIX, ldrname());
2931 } else if (on_level(&mptr->lev, &qstart_level)) {
2932 Sprintf(buf, "%sHome%s.", PREFIX,
2933 mptr->flags.unreachable ? " (no way back...)" : "");
2934 if (u.uevent.qcompleted)
2935 Sprintf(buf, "%sCompleted quest for %s.", PREFIX, ldrname());
2936 else if (mptr->flags.questing)
2937 Sprintf(buf, "%sGiven quest by %s.", PREFIX, ldrname());
2938 } else if (mptr->flags.ludios) {
2939 /* presence of the ludios branch in #overview output indicates that
2940 the player has made it onto the level; presence of this annotation
2941 indicates that the fort's entrance has been seen (or mapped) */
2942 Sprintf(buf, "%sFort Ludios.", PREFIX);
2943 } else if (mptr->flags.castle) {
2944 Sprintf(buf, "%sThe castle%s.", PREFIX, tunesuffix(mptr, tmpbuf));
2945 } else if (mptr->flags.valley) {
2946 Sprintf(buf, "%sValley of the Dead.", PREFIX);
2947 } else if (mptr->flags.msanctum) {
2948 Sprintf(buf, "%sMoloch's Sanctum.", PREFIX);
2950 if (*buf)
2951 putstr(win, 0, buf);
2953 /* print out branches */
2954 if (mptr->br) {
2955 Sprintf(buf, "%s%s to %s", PREFIX, br_string2(mptr->br),
2956 dungeons[mptr->br->end2.dnum].dname);
2958 /* Since mapseen objects are printed out in increasing order
2959 * of dlevel, clarify which level this branch is going to
2960 * if the branch goes upwards. Unless it's the end game.
2962 if (mptr->br->end1_up && !In_endgame(&(mptr->br->end2)))
2963 Sprintf(eos(buf), ", level %d", depth(&(mptr->br->end2)));
2964 Strcat(buf, ".");
2965 putstr(win, 0, buf);
2968 /* maybe print out bones details */
2969 if (mptr->final_resting_place || final) {
2970 struct cemetery *bp;
2971 int kncnt = !died_here ? 0 : 1;
2973 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2974 if (bp->bonesknown || wizard || final)
2975 ++kncnt;
2976 if (kncnt) {
2977 Sprintf(buf, "%s%s", PREFIX, "Final resting place for");
2978 putstr(win, 0, buf);
2979 if (died_here) {
2980 /* disclosure occurs before bones creation, so listing dead
2981 hero here doesn't give away whether bones are produced */
2982 formatkiller(tmpbuf, sizeof tmpbuf, how, TRUE);
2983 /* rephrase a few death reasons to work with "you" */
2984 (void) strsubst(tmpbuf, " himself", " yourself");
2985 (void) strsubst(tmpbuf, " herself", " yourself");
2986 (void) strsubst(tmpbuf, " his ", " your ");
2987 (void) strsubst(tmpbuf, " her ", " your ");
2988 Sprintf(buf, "%s%syou, %s%c", PREFIX, TAB, tmpbuf,
2989 --kncnt ? ',' : '.');
2990 putstr(win, 0, buf);
2992 for (bp = mptr->final_resting_place; bp; bp = bp->next) {
2993 if (bp->bonesknown || wizard || final) {
2994 Sprintf(buf, "%s%s%s, %s%c", PREFIX, TAB, bp->who,
2995 bp->how, --kncnt ? ',' : '.');
2996 putstr(win, 0, buf);
3003 /*dungeon.c*/