NHDT->ANH, in most cases
[aNetHack.git] / src / dungeon.c
blob798dde577994a3c91e709bff1bb2496d3ecbe133
1 /* NetHack 3.6 dungeon.c $ANH-Date: 1470275509 2016/08/04 01:51:49 $ $ANH-Branch: master $:$ANH-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 mapseen *FDECL(find_mapseen_by_str, (const char *));
66 STATIC_DCL void FDECL(print_mapseen, (winid, mapseen *, int, int, BOOLEAN_P));
67 STATIC_DCL boolean FDECL(interest_mapseen, (mapseen *));
68 STATIC_DCL void FDECL(traverse_mapseenchn, (BOOLEAN_P, winid,
69 int, int, int *));
70 STATIC_DCL const char *FDECL(seen_string, (XCHAR_P, const char *));
71 STATIC_DCL const char *FDECL(br_string2, (branch *));
72 STATIC_DCL const char *FDECL(endgamelevelname, (char *, int));
73 STATIC_DCL const char *FDECL(shop_string, (int));
74 STATIC_DCL char *FDECL(tunesuffix, (mapseen *, char *));
76 #ifdef DEBUG
77 #define DD dungeons[i]
78 STATIC_DCL void NDECL(dumpit);
80 STATIC_OVL void
81 dumpit()
83 int i;
84 s_level *x;
85 branch *br;
87 if (!explicitdebug(__FILE__))
88 return;
90 for (i = 0; i < n_dgns; i++) {
91 fprintf(stderr, "\n#%d \"%s\" (%s):\n", i, DD.dname, DD.proto);
92 fprintf(stderr, " num_dunlevs %d, dunlev_ureached %d\n",
93 DD.num_dunlevs, DD.dunlev_ureached);
94 fprintf(stderr, " depth_start %d, ledger_start %d\n",
95 DD.depth_start, DD.ledger_start);
96 fprintf(stderr, " flags:%s%s%s\n",
97 DD.flags.rogue_like ? " rogue_like" : "",
98 DD.flags.maze_like ? " maze_like" : "",
99 DD.flags.hellish ? " hellish" : "");
100 getchar();
102 fprintf(stderr, "\nSpecial levels:\n");
103 for (x = sp_levchn; x; x = x->next) {
104 fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs);
105 fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel);
106 fprintf(stderr, "flags:%s%s%s%s\n",
107 x->flags.rogue_like ? " rogue_like" : "",
108 x->flags.maze_like ? " maze_like" : "",
109 x->flags.hellish ? " hellish" : "",
110 x->flags.town ? " town" : "");
111 getchar();
113 fprintf(stderr, "\nBranches:\n");
114 for (br = branches; br; br = br->next) {
115 fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n", br->id,
116 br->type == BR_STAIR
117 ? "stair"
118 : br->type == BR_NO_END1
119 ? "no end1"
120 : br->type == BR_NO_END2
121 ? "no end2"
122 : br->type == BR_PORTAL
123 ? "portal"
124 : "unknown",
125 br->end1.dnum, br->end1.dlevel, br->end2.dnum,
126 br->end2.dlevel, br->end1_up ? "end1 up" : "end1 down");
128 getchar();
129 fprintf(stderr, "\nDone\n");
130 getchar();
132 #endif
134 /* Save the dungeon structures. */
135 void
136 save_dungeon(fd, perform_write, free_data)
137 int fd;
138 boolean perform_write, free_data;
140 branch *curr, *next;
141 mapseen *curr_ms, *next_ms;
142 int count;
144 if (perform_write) {
145 bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns);
146 bwrite(fd, (genericptr_t) dungeons,
147 sizeof(dungeon) * (unsigned) n_dgns);
148 bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
149 bwrite(fd, (genericptr_t) tune, sizeof tune);
151 for (count = 0, curr = branches; curr; curr = curr->next)
152 count++;
153 bwrite(fd, (genericptr_t) &count, sizeof(count));
155 for (curr = branches; curr; curr = curr->next)
156 bwrite(fd, (genericptr_t) curr, sizeof(branch));
158 count = maxledgerno();
159 bwrite(fd, (genericptr_t) &count, sizeof count);
160 bwrite(fd, (genericptr_t) level_info,
161 (unsigned) count * sizeof(struct linfo));
162 bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
164 for (count = 0, curr_ms = mapseenchn; curr_ms;
165 curr_ms = curr_ms->next)
166 count++;
167 bwrite(fd, (genericptr_t) &count, sizeof(count));
169 for (curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next)
170 save_mapseen(fd, curr_ms);
173 if (free_data) {
174 for (curr = branches; curr; curr = next) {
175 next = curr->next;
176 free((genericptr_t) curr);
178 branches = 0;
179 for (curr_ms = mapseenchn; curr_ms; curr_ms = next_ms) {
180 next_ms = curr_ms->next;
181 if (curr_ms->custom)
182 free((genericptr_t) curr_ms->custom);
183 free((genericptr_t) curr_ms);
185 mapseenchn = 0;
189 /* Restore the dungeon structures. */
190 void
191 restore_dungeon(fd)
192 int fd;
194 branch *curr, *last;
195 int count, i;
196 mapseen *curr_ms, *last_ms;
198 mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns));
199 mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned) n_dgns);
200 mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
201 mread(fd, (genericptr_t) tune, sizeof tune);
203 last = branches = (branch *) 0;
205 mread(fd, (genericptr_t) &count, sizeof(count));
206 for (i = 0; i < count; i++) {
207 curr = (branch *) alloc(sizeof(branch));
208 mread(fd, (genericptr_t) curr, sizeof(branch));
209 curr->next = (branch *) 0;
210 if (last)
211 last->next = curr;
212 else
213 branches = curr;
214 last = curr;
217 mread(fd, (genericptr_t) &count, sizeof(count));
218 if (count >= MAXLINFO)
219 panic("level information count larger (%d) than allocated size",
220 count);
221 mread(fd, (genericptr_t) level_info,
222 (unsigned) count * sizeof(struct linfo));
223 mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
225 mread(fd, (genericptr_t) &count, sizeof(count));
226 last_ms = (mapseen *) 0;
227 for (i = 0; i < count; i++) {
228 curr_ms = load_mapseen(fd);
229 curr_ms->next = (mapseen *) 0;
230 if (last_ms)
231 last_ms->next = curr_ms;
232 else
233 mapseenchn = curr_ms;
234 last_ms = curr_ms;
238 static void
239 Fread(ptr, size, nitems, stream)
240 genericptr_t ptr;
241 int size, nitems;
242 dlb *stream;
244 int cnt;
246 if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
247 panic(
248 "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.",
249 (size * nitems), (size * cnt));
250 terminate(EXIT_FAILURE);
254 STATIC_OVL xchar
255 dname_to_dnum(s)
256 const char *s;
258 xchar i;
260 for (i = 0; i < n_dgns; i++)
261 if (!strcmp(dungeons[i].dname, s))
262 return i;
264 panic("Couldn't resolve dungeon number for name \"%s\".", s);
265 /*NOT REACHED*/
266 return (xchar) 0;
269 s_level *
270 find_level(s)
271 const char *s;
273 s_level *curr;
274 for (curr = sp_levchn; curr; curr = curr->next)
275 if (!strcmpi(s, curr->proto))
276 break;
277 return curr;
280 /* Find the branch that links the named dungeon. */
281 STATIC_OVL int
282 find_branch(s, pd)
283 const char *s; /* dungeon name */
284 struct proto_dungeon *pd;
286 int i;
288 if (pd) {
289 for (i = 0; i < pd->n_brs; i++)
290 if (!strcmp(pd->tmpbranch[i].name, s))
291 break;
292 if (i == pd->n_brs)
293 panic("find_branch: can't find %s", s);
294 } else {
295 /* support for level tport by name */
296 branch *br;
297 const char *dnam;
299 for (br = branches; br; br = br->next) {
300 dnam = dungeons[br->end2.dnum].dname;
301 if (!strcmpi(dnam, s)
302 || (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s)))
303 break;
305 i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1;
307 return i;
311 * Find the "parent" by searching the prototype branch list for the branch
312 * listing, then figuring out to which dungeon it belongs.
314 STATIC_OVL xchar
315 parent_dnum(s, pd)
316 const char *s; /* dungeon name */
317 struct proto_dungeon *pd;
319 int i;
320 xchar pdnum;
322 i = find_branch(s, pd);
324 * Got branch, now find parent dungeon. Stop if we have reached
325 * "this" dungeon (if we haven't found it by now it is an error).
327 for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++)
328 if ((i -= pd->tmpdungeon[pdnum].branches) < 0)
329 return pdnum;
331 panic("parent_dnum: couldn't resolve branch.");
332 /*NOT REACHED*/
333 return (xchar) 0;
337 * Return a starting point and number of successive positions a level
338 * or dungeon entrance can occupy.
340 * Note: This follows the acouple (instead of the rcouple) rules for a
341 * negative random component (randc < 0). These rules are found
342 * in dgn_comp.y. The acouple [absolute couple] section says that
343 * a negative random component means from the (adjusted) base to the
344 * end of the dungeon.
346 STATIC_OVL int
347 level_range(dgn, base, randc, chain, pd, adjusted_base)
348 xchar dgn;
349 int base, randc, chain;
350 struct proto_dungeon *pd;
351 int *adjusted_base;
353 int lmax = dungeons[dgn].num_dunlevs;
355 if (chain >= 0) { /* relative to a special level */
356 s_level *levtmp = pd->final_lev[chain];
357 if (!levtmp)
358 panic("level_range: empty chain level!");
360 base += levtmp->dlevel.dlevel;
361 } else { /* absolute in the dungeon */
362 /* from end of dungeon */
363 if (base < 0)
364 base = (lmax + base + 1);
367 if (base < 1 || base > lmax)
368 panic("level_range: base value out of range");
370 *adjusted_base = base;
372 if (randc == -1) { /* from base to end of dungeon */
373 return (lmax - base + 1);
374 } else if (randc) {
375 /* make sure we don't run off the end of the dungeon */
376 return (((base + randc - 1) > lmax) ? lmax - base + 1 : randc);
377 } /* else only one choice */
378 return 1;
381 STATIC_OVL xchar
382 parent_dlevel(s, pd)
383 const char *s;
384 struct proto_dungeon *pd;
386 int i, j, num, base, dnum = parent_dnum(s, pd);
387 branch *curr;
389 i = find_branch(s, pd);
390 num = level_range(dnum, pd->tmpbranch[i].lev.base,
391 pd->tmpbranch[i].lev.rand, pd->tmpbranch[i].chain, pd,
392 &base);
394 /* KMH -- Try our best to find a level without an existing branch */
395 i = j = rn2(num);
396 do {
397 if (++i >= num)
398 i = 0;
399 for (curr = branches; curr; curr = curr->next)
400 if ((curr->end1.dnum == dnum && curr->end1.dlevel == base + i)
401 || (curr->end2.dnum == dnum && curr->end2.dlevel == base + i))
402 break;
403 } while (curr && i != j);
404 return (base + i);
407 /* Convert from the temporary branch type to the dungeon branch type. */
408 STATIC_OVL int
409 correct_branch_type(tbr)
410 struct tmpbranch *tbr;
412 switch (tbr->type) {
413 case TBR_STAIR:
414 return BR_STAIR;
415 case TBR_NO_UP:
416 return tbr->up ? BR_NO_END1 : BR_NO_END2;
417 case TBR_NO_DOWN:
418 return tbr->up ? BR_NO_END2 : BR_NO_END1;
419 case TBR_PORTAL:
420 return BR_PORTAL;
422 impossible("correct_branch_type: unknown branch type");
423 return BR_STAIR;
427 * Add the given branch to the branch list. The branch list is ordered
428 * by end1 dungeon and level followed by end2 dungeon and level. If
429 * extract_first is true, then the branch is already part of the list
430 * but needs to be repositioned.
432 void
433 insert_branch(new_branch, extract_first)
434 branch *new_branch;
435 boolean extract_first;
437 branch *curr, *prev;
438 long new_val, curr_val, prev_val;
440 if (extract_first) {
441 for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next)
442 if (curr == new_branch)
443 break;
445 if (!curr)
446 panic("insert_branch: not found");
447 if (prev)
448 prev->next = curr->next;
449 else
450 branches = curr->next;
452 new_branch->next = (branch *) 0;
454 /* Convert the branch into a unique number so we can sort them. */
455 #define branch_val(bp) \
456 ((((long) (bp)->end1.dnum * (MAXLEVEL + 1) + (long) (bp)->end1.dlevel) \
457 * (MAXDUNGEON + 1) * (MAXLEVEL + 1)) \
458 + ((long) (bp)->end2.dnum * (MAXLEVEL + 1) + (long) (bp)->end2.dlevel))
461 * Insert the new branch into the correct place in the branch list.
463 prev = (branch *) 0;
464 prev_val = -1;
465 new_val = branch_val(new_branch);
466 for (curr = branches; curr;
467 prev_val = curr_val, prev = curr, curr = curr->next) {
468 curr_val = branch_val(curr);
469 if (prev_val < new_val && new_val <= curr_val)
470 break;
472 if (prev) {
473 new_branch->next = curr;
474 prev->next = new_branch;
475 } else {
476 new_branch->next = branches;
477 branches = new_branch;
481 /* Add a dungeon branch to the branch list. */
482 STATIC_OVL branch *
483 add_branch(dgn, child_entry_level, pd)
484 int dgn;
485 int child_entry_level;
486 struct proto_dungeon *pd;
488 static int branch_id = 0;
489 int branch_num;
490 branch *new_branch;
492 branch_num = find_branch(dungeons[dgn].dname, pd);
493 new_branch = (branch *) alloc(sizeof(branch));
494 (void) memset((genericptr_t)new_branch, 0, sizeof(branch));
495 new_branch->next = (branch *) 0;
496 new_branch->id = branch_id++;
497 new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
498 new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd);
499 new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd);
500 new_branch->end2.dnum = dgn;
501 new_branch->end2.dlevel = child_entry_level;
502 new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE;
504 insert_branch(new_branch, FALSE);
505 return new_branch;
509 * Add new level to special level chain. Insert it in level order with the
510 * other levels in this dungeon. This assumes that we are never given a
511 * level that has a dungeon number less than the dungeon number of the
512 * last entry.
514 STATIC_OVL void
515 add_level(new_lev)
516 s_level *new_lev;
518 s_level *prev, *curr;
520 prev = (s_level *) 0;
521 for (curr = sp_levchn; curr; curr = curr->next) {
522 if (curr->dlevel.dnum == new_lev->dlevel.dnum
523 && curr->dlevel.dlevel > new_lev->dlevel.dlevel)
524 break;
525 prev = curr;
527 if (!prev) {
528 new_lev->next = sp_levchn;
529 sp_levchn = new_lev;
530 } else {
531 new_lev->next = curr;
532 prev->next = new_lev;
536 STATIC_OVL void
537 init_level(dgn, proto_index, pd)
538 int dgn, proto_index;
539 struct proto_dungeon *pd;
541 s_level *new_level;
542 struct tmplevel *tlevel = &pd->tmplevel[proto_index];
544 pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
545 if (!wizard && tlevel->chance <= rn2(100))
546 return;
548 pd->final_lev[proto_index] = new_level =
549 (s_level *) alloc(sizeof(s_level));
550 (void) memset((genericptr_t)new_level, 0, sizeof(s_level));
551 /* load new level with data */
552 Strcpy(new_level->proto, tlevel->name);
553 new_level->boneid = tlevel->boneschar;
554 new_level->dlevel.dnum = dgn;
555 new_level->dlevel.dlevel = 0; /* for now */
557 new_level->flags.town = !!(tlevel->flags & TOWN);
558 new_level->flags.hellish = !!(tlevel->flags & HELLISH);
559 new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
560 new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
561 new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);
562 if (!new_level->flags.align)
563 new_level->flags.align =
564 ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4);
566 new_level->rndlevs = tlevel->rndlevs;
567 new_level->next = (s_level *) 0;
570 STATIC_OVL int
571 possible_places(idx, map, pd)
572 int idx; /* prototype index */
573 boolean *map; /* array MAXLEVEL+1 in length */
574 struct proto_dungeon *pd;
576 int i, start, count;
577 s_level *lev = pd->final_lev[idx];
579 /* init level possibilities */
580 for (i = 0; i <= MAXLEVEL; i++)
581 map[i] = FALSE;
583 /* get base and range and set those entries to true */
584 count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base,
585 pd->tmplevel[idx].lev.rand, pd->tmplevel[idx].chain,
586 pd, &start);
587 for (i = start; i < start + count; i++)
588 map[i] = TRUE;
590 /* mark off already placed levels */
591 for (i = pd->start; i < idx; i++) {
592 if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) {
593 map[pd->final_lev[i]->dlevel.dlevel] = FALSE;
594 --count;
598 return count;
601 /* Pick the nth TRUE entry in the given boolean array. */
602 STATIC_OVL xchar
603 pick_level(map, nth)
604 boolean *map; /* an array MAXLEVEL+1 in size */
605 int nth;
607 int i;
608 for (i = 1; i <= MAXLEVEL; i++)
609 if (map[i] && !nth--)
610 return (xchar) i;
611 panic("pick_level: ran out of valid levels");
612 return 0;
615 #ifdef DDEBUG
616 static void FDECL(indent, (int));
618 static void
619 indent(d)
620 int d;
622 while (d-- > 0)
623 fputs(" ", stderr);
625 #endif
628 * Place a level. First, find the possible places on a dungeon map
629 * template. Next pick one. Then try to place the next level. If
630 * successful, we're done. Otherwise, try another (and another) until
631 * all possible places have been tried. If all possible places have
632 * been exhausted, return false.
634 STATIC_OVL boolean
635 place_level(proto_index, pd)
636 int proto_index;
637 struct proto_dungeon *pd;
639 boolean map[MAXLEVEL + 1]; /* valid levels are 1..MAXLEVEL inclusive */
640 s_level *lev;
641 int npossible;
642 #ifdef DDEBUG
643 int i;
644 #endif
646 if (proto_index == pd->n_levs)
647 return TRUE; /* at end of proto levels */
649 lev = pd->final_lev[proto_index];
651 /* No level created for this prototype, goto next. */
652 if (!lev)
653 return place_level(proto_index + 1, pd);
655 npossible = possible_places(proto_index, map, pd);
657 for (; npossible; --npossible) {
658 lev->dlevel.dlevel = pick_level(map, rn2(npossible));
659 #ifdef DDEBUG
660 indent(proto_index - pd->start);
661 fprintf(stderr, "%s: trying %d [ ", lev->proto, lev->dlevel.dlevel);
662 for (i = 1; i <= MAXLEVEL; i++)
663 if (map[i])
664 fprintf(stderr, "%d ", i);
665 fprintf(stderr, "]\n");
666 #endif
667 if (place_level(proto_index + 1, pd))
668 return TRUE;
669 map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */
671 #ifdef DDEBUG
672 indent(proto_index - pd->start);
673 fprintf(stderr, "%s: failed\n", lev->proto);
674 #endif
675 return FALSE;
678 struct level_map {
679 const char *lev_name;
680 d_level *lev_spec;
681 } level_map[] = { { "air", &air_level },
682 { "asmodeus", &asmodeus_level },
683 { "astral", &astral_level },
684 { "baalz", &baalzebub_level },
685 { "bigrm", &bigroom_level },
686 { "castle", &stronghold_level },
687 { "earth", &earth_level },
688 { "fakewiz1", &portal_level },
689 { "fire", &fire_level },
690 { "juiblex", &juiblex_level },
691 { "knox", &knox_level },
692 { "medusa", &medusa_level },
693 { "oracle", &oracle_level },
694 { "orcus", &orcus_level },
695 { "rogue", &rogue_level },
696 { "sanctum", &sanctum_level },
697 { "valley", &valley_level },
698 { "water", &water_level },
699 { "wizard1", &wiz1_level },
700 { "wizard2", &wiz2_level },
701 { "wizard3", &wiz3_level },
702 { "minend", &mineend_level },
703 { "soko1", &sokoend_level },
704 { X_START, &qstart_level },
705 { X_LOCATE, &qlocate_level },
706 { X_GOAL, &nemesis_level },
707 { "", (d_level *) 0 } };
709 /* initialize the "dungeon" structs */
710 void
711 init_dungeons()
713 dlb *dgn_file;
714 register int i, cl = 0, cb = 0;
715 register s_level *x;
716 struct proto_dungeon pd;
717 struct level_map *lev_map;
718 struct version_info vers_info;
720 pd.n_levs = pd.n_brs = 0;
722 dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
723 if (!dgn_file) {
724 char tbuf[BUFSZ];
725 Sprintf(tbuf, "Cannot open dungeon description - \"%s", DUNGEON_FILE);
726 #ifdef DLBRSRC /* using a resource from the executable */
727 Strcat(tbuf, "\" resource!");
728 #else /* using a file or DLB file */
729 #if defined(DLB)
730 Strcat(tbuf, "\" from ");
731 #ifdef PREFIXES_IN_USE
732 Strcat(tbuf, "\n\"");
733 if (fqn_prefix[DATAPREFIX])
734 Strcat(tbuf, fqn_prefix[DATAPREFIX]);
735 #else
736 Strcat(tbuf, "\"");
737 #endif
738 Strcat(tbuf, DLBFILE);
739 #endif
740 Strcat(tbuf, "\" file!");
741 #endif
742 #ifdef WIN32
743 interject_assistance(1, INTERJECT_PANIC, (genericptr_t) tbuf,
744 (genericptr_t) fqn_prefix[DATAPREFIX]);
745 #endif
746 panic1(tbuf);
749 /* validate the data's version against the program's version */
750 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file);
751 /* we'd better clear the screen now, since when error messages come from
752 * check_version() they will be printed using pline(), which doesn't
753 * mix with the raw messages that might be already on the screen
755 if (iflags.window_inited)
756 clear_nhwindow(WIN_MAP);
757 if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
758 panic("Dungeon description not valid.");
761 * Read in each dungeon and transfer the results to the internal
762 * dungeon arrays.
764 sp_levchn = (s_level *) 0;
765 Fread((genericptr_t) &n_dgns, sizeof(int), 1, dgn_file);
766 if (n_dgns >= MAXDUNGEON)
767 panic("init_dungeons: too many dungeons");
769 for (i = 0; i < n_dgns; i++) {
770 Fread((genericptr_t) &pd.tmpdungeon[i], sizeof(struct tmpdungeon), 1,
771 dgn_file);
772 if (!wizard && pd.tmpdungeon[i].chance
773 && (pd.tmpdungeon[i].chance <= rn2(100))) {
774 int j;
776 /* skip over any levels or branches */
777 for (j = 0; j < pd.tmpdungeon[i].levels; j++)
778 Fread((genericptr_t) &pd.tmplevel[cl],
779 sizeof(struct tmplevel), 1, dgn_file);
781 for (j = 0; j < pd.tmpdungeon[i].branches; j++)
782 Fread((genericptr_t) &pd.tmpbranch[cb],
783 sizeof(struct tmpbranch), 1, dgn_file);
784 n_dgns--;
785 i--;
786 continue;
789 Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name);
790 Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname);
791 dungeons[i].boneid = pd.tmpdungeon[i].boneschar;
793 if (pd.tmpdungeon[i].lev.rand)
794 dungeons[i].num_dunlevs = (xchar) rn1(pd.tmpdungeon[i].lev.rand,
795 pd.tmpdungeon[i].lev.base);
796 else
797 dungeons[i].num_dunlevs = (xchar) pd.tmpdungeon[i].lev.base;
799 if (!i) {
800 dungeons[i].ledger_start = 0;
801 dungeons[i].depth_start = 1;
802 dungeons[i].dunlev_ureached = 1;
803 } else {
804 dungeons[i].ledger_start =
805 dungeons[i - 1].ledger_start + dungeons[i - 1].num_dunlevs;
806 dungeons[i].dunlev_ureached = 0;
809 dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH);
810 dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE);
811 dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE);
812 dungeons[i].flags.align =
813 ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4);
815 * Set the entry level for this dungeon. The pd.tmpdungeon entry
816 * value means:
817 * < 0 from bottom (-1 == bottom level)
818 * 0 default (top)
819 * > 0 actual level (1 = top)
821 * Note that the entry_lev field in the dungeon structure is
822 * redundant. It is used only here and in print_dungeon().
824 if (pd.tmpdungeon[i].entry_lev < 0) {
825 dungeons[i].entry_lev =
826 dungeons[i].num_dunlevs + pd.tmpdungeon[i].entry_lev + 1;
827 if (dungeons[i].entry_lev <= 0)
828 dungeons[i].entry_lev = 1;
829 } else if (pd.tmpdungeon[i].entry_lev > 0) {
830 dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
831 if (dungeons[i].entry_lev > dungeons[i].num_dunlevs)
832 dungeons[i].entry_lev = dungeons[i].num_dunlevs;
833 } else { /* default */
834 dungeons[i].entry_lev = 1; /* defaults to top level */
837 if (i) { /* set depth */
838 branch *br;
839 schar from_depth;
840 boolean from_up;
842 br = add_branch(i, dungeons[i].entry_lev, &pd);
844 /* Get the depth of the connecting end. */
845 if (br->end1.dnum == i) {
846 from_depth = depth(&br->end2);
847 from_up = !br->end1_up;
848 } else {
849 from_depth = depth(&br->end1);
850 from_up = br->end1_up;
854 * Calculate the depth of the top of the dungeon via
855 * its branch. First, the depth of the entry point:
857 * depth of branch from "parent" dungeon
858 * + -1 or 1 depending on an up or down stair or
859 * 0 if portal
861 * Followed by the depth of the top of the dungeon:
863 * - (entry depth - 1)
865 * We'll say that portals stay on the same depth.
867 dungeons[i].depth_start =
868 from_depth + (br->type == BR_PORTAL ? 0 : (from_up ? -1 : 1))
869 - (dungeons[i].entry_lev - 1);
872 /* this is redundant - it should have been flagged by dgn_comp */
873 if (dungeons[i].num_dunlevs > MAXLEVEL)
874 dungeons[i].num_dunlevs = MAXLEVEL;
876 pd.start = pd.n_levs; /* save starting point */
877 pd.n_levs += pd.tmpdungeon[i].levels;
878 if (pd.n_levs > LEV_LIMIT)
879 panic("init_dungeon: too many special levels");
881 * Read in the prototype special levels. Don't add generated
882 * special levels until they are all placed.
884 for (; cl < pd.n_levs; cl++) {
885 Fread((genericptr_t) &pd.tmplevel[cl], sizeof(struct tmplevel), 1,
886 dgn_file);
887 init_level(i, cl, &pd);
890 * Recursively place the generated levels for this dungeon. This
891 * routine will attempt all possible combinations before giving
892 * up.
894 if (!place_level(pd.start, &pd))
895 panic("init_dungeon: couldn't place levels");
896 #ifdef DDEBUG
897 fprintf(stderr, "--- end of dungeon %d ---\n", i);
898 fflush(stderr);
899 getchar();
900 #endif
901 for (; pd.start < pd.n_levs; pd.start++)
902 if (pd.final_lev[pd.start])
903 add_level(pd.final_lev[pd.start]);
905 pd.n_brs += pd.tmpdungeon[i].branches;
906 if (pd.n_brs > BRANCH_LIMIT)
907 panic("init_dungeon: too many branches");
908 for (; cb < pd.n_brs; cb++)
909 Fread((genericptr_t) &pd.tmpbranch[cb], sizeof(struct tmpbranch),
910 1, dgn_file);
912 (void) dlb_fclose(dgn_file);
914 for (i = 0; i < 5; i++)
915 tune[i] = 'A' + rn2(7);
916 tune[5] = 0;
919 * Find most of the special levels and dungeons so we can access their
920 * locations quickly.
922 for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
923 x = find_level(lev_map->lev_name);
924 if (x) {
925 assign_level(lev_map->lev_spec, &x->dlevel);
926 if (!strncmp(lev_map->lev_name, "x-", 2)) {
927 /* This is where the name substitution on the
928 * levels of the quest dungeon occur.
930 Sprintf(x->proto, "%s%s", urole.filecode,
931 &lev_map->lev_name[1]);
932 } else if (lev_map->lev_spec == &knox_level) {
933 branch *br;
935 * Kludge to allow floating Knox entrance. We
936 * specify a floating entrance by the fact that
937 * its entrance (end1) has a bogus dnum, namely
938 * n_dgns.
940 for (br = branches; br; br = br->next)
941 if (on_level(&br->end2, &knox_level))
942 break;
944 if (br)
945 br->end1.dnum = n_dgns;
946 /* adjust the branch's position on the list */
947 insert_branch(br, TRUE);
952 * I hate hardwiring these names. :-(
954 quest_dnum = dname_to_dnum("The Quest");
955 sokoban_dnum = dname_to_dnum("Sokoban");
956 mines_dnum = dname_to_dnum("The Gnomish Mines");
957 tower_dnum = dname_to_dnum("Vlad's Tower");
959 /* one special fixup for dummy surface level */
960 if ((x = find_level("dummy")) != 0) {
961 i = x->dlevel.dnum;
962 /* the code above puts earth one level above dungeon level #1,
963 making the dummy level overlay level 1; but the whole reason
964 for having the dummy level is to make earth have depth -1
965 instead of 0, so adjust the start point to shift endgame up */
966 if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start)
967 dungeons[i].depth_start -= 1;
968 /* TO DO: strip "dummy" out all the way here,
969 so that it's hidden from <ctrl/O> feedback. */
972 #ifdef DEBUG
973 dumpit();
974 #endif
977 /* return the level number for lev in *this* dungeon */
978 xchar
979 dunlev(lev)
980 d_level *lev;
982 return lev->dlevel;
985 /* return the lowest level number for *this* dungeon */
986 xchar
987 dunlevs_in_dungeon(lev)
988 d_level *lev;
990 return dungeons[lev->dnum].num_dunlevs;
993 /* return the lowest level explored in the game*/
994 xchar
995 deepest_lev_reached(noquest)
996 boolean noquest;
998 /* this function is used for three purposes: to provide a factor
999 * of difficulty in monster generation; to provide a factor of
1000 * difficulty in experience calculations (botl.c and end.c); and
1001 * to insert the deepest level reached in the game in the topten
1002 * display. the 'noquest' arg switch is required for the latter.
1004 * from the player's point of view, going into the Quest is _not_
1005 * going deeper into the dungeon -- it is going back "home", where
1006 * the dungeon starts at level 1. given the setup in dungeon.def,
1007 * the depth of the Quest (thought of as starting at level 1) is
1008 * never lower than the level of entry into the Quest, so we exclude
1009 * the Quest from the topten "deepest level reached" display
1010 * calculation. _However_ the Quest is a difficult dungeon, so we
1011 * include it in the factor of difficulty calculations.
1013 register int i;
1014 d_level tmp;
1015 register schar ret = 0;
1017 for (i = 0; i < n_dgns; i++) {
1018 if (noquest && i == quest_dnum)
1019 continue;
1020 tmp.dlevel = dungeons[i].dunlev_ureached;
1021 if (tmp.dlevel == 0)
1022 continue;
1023 tmp.dnum = i;
1024 if (depth(&tmp) > ret)
1025 ret = depth(&tmp);
1027 return (xchar) ret;
1030 /* return a bookkeeping level number for purpose of comparisons and
1031 save/restore */
1032 xchar
1033 ledger_no(lev)
1034 d_level *lev;
1036 return (xchar) (lev->dlevel + dungeons[lev->dnum].ledger_start);
1040 * The last level in the bookkeeping list of level is the bottom of the last
1041 * dungeon in the dungeons[] array.
1043 * Maxledgerno() -- which is the max number of levels in the bookkeeping
1044 * list, should not be confused with dunlevs_in_dungeon(lev) -- which
1045 * returns the max number of levels in lev's dungeon, and both should
1046 * not be confused with deepest_lev_reached() -- which returns the lowest
1047 * depth visited by the player.
1049 xchar
1050 maxledgerno()
1052 return (xchar) (dungeons[n_dgns - 1].ledger_start
1053 + dungeons[n_dgns - 1].num_dunlevs);
1056 /* return the dungeon that this ledgerno exists in */
1057 xchar
1058 ledger_to_dnum(ledgerno)
1059 xchar ledgerno;
1061 register int i;
1063 /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */
1064 for (i = 0; i < n_dgns; i++)
1065 if (dungeons[i].ledger_start < ledgerno
1066 && ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs)
1067 return (xchar) i;
1069 panic("level number out of range [ledger_to_dnum(%d)]", (int) ledgerno);
1070 /*NOT REACHED*/
1071 return (xchar) 0;
1074 /* return the level of the dungeon this ledgerno exists in */
1075 xchar
1076 ledger_to_dlev(ledgerno)
1077 xchar ledgerno;
1079 return (xchar) (ledgerno
1080 - dungeons[ledger_to_dnum(ledgerno)].ledger_start);
1083 /* returns the depth of a level, in floors below the surface
1084 (note levels in different dungeons can have the same depth) */
1085 schar
1086 depth(lev)
1087 d_level *lev;
1089 return (schar) (dungeons[lev->dnum].depth_start + lev->dlevel - 1);
1092 /* are "lev1" and "lev2" actually the same? */
1093 boolean
1094 on_level(lev1, lev2)
1095 d_level *lev1, *lev2;
1097 return (boolean) (lev1->dnum == lev2->dnum
1098 && lev1->dlevel == lev2->dlevel);
1101 /* is this level referenced in the special level chain? */
1102 s_level *
1103 Is_special(lev)
1104 d_level *lev;
1106 s_level *levtmp;
1108 for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
1109 if (on_level(lev, &levtmp->dlevel))
1110 return levtmp;
1112 return (s_level *) 0;
1116 * Is this a multi-dungeon branch level? If so, return a pointer to the
1117 * branch. Otherwise, return null.
1119 branch *
1120 Is_branchlev(lev)
1121 d_level *lev;
1123 branch *curr;
1125 for (curr = branches; curr; curr = curr->next) {
1126 if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
1127 return curr;
1129 return (branch *) 0;
1132 /* returns True iff the branch 'lev' is in a branch which builds up */
1133 boolean
1134 builds_up(lev)
1135 d_level *lev;
1137 dungeon *dptr = &dungeons[lev->dnum];
1139 * FIXME: this misclassifies a single level branch reached via stairs
1140 * from below. Saving grace is that no such branches currently exist.
1142 return (boolean) (dptr->num_dunlevs > 1
1143 && dptr->entry_lev == dptr->num_dunlevs);
1146 /* goto the next level (or appropriate dungeon) */
1147 void
1148 next_level(at_stairs)
1149 boolean at_stairs;
1151 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1152 /* Taking a down dungeon branch. */
1153 goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1154 } else {
1155 /* Going down a stairs or jump in a trap door. */
1156 d_level newlevel;
1158 newlevel.dnum = u.uz.dnum;
1159 newlevel.dlevel = u.uz.dlevel + 1;
1160 goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
1164 /* goto the previous level (or appropriate dungeon) */
1165 void
1166 prev_level(at_stairs)
1167 boolean at_stairs;
1169 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1170 /* Taking an up dungeon branch. */
1171 /* KMH -- Upwards branches are okay if not level 1 */
1172 /* (Just make sure it doesn't go above depth 1) */
1173 if (!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet)
1174 done(ESCAPED);
1175 else
1176 goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1177 } else {
1178 /* Going up a stairs or rising through the ceiling. */
1179 d_level newlevel;
1180 newlevel.dnum = u.uz.dnum;
1181 newlevel.dlevel = u.uz.dlevel - 1;
1182 goto_level(&newlevel, at_stairs, FALSE, FALSE);
1186 void
1187 u_on_newpos(x, y)
1188 int x, y;
1190 u.ux = x;
1191 u.uy = y;
1192 #ifdef CLIPPING
1193 cliparound(u.ux, u.uy);
1194 #endif
1195 /* ridden steed always shares hero's location */
1196 if (u.usteed)
1197 u.usteed->mx = u.ux, u.usteed->my = u.uy;
1198 /* when changing levels, don't leave old position set with
1199 stale values from previous level */
1200 if (!on_level(&u.uz, &u.uz0))
1201 u.ux0 = u.ux, u.uy0 = u.uy;
1204 /* place you on a random location */
1205 void
1206 u_on_rndspot(upflag)
1207 int upflag;
1209 int up = (upflag & 1), was_in_W_tower = (upflag & 2);
1212 * Place the hero at a random location within the relevant region.
1213 * place_lregion(xTELE) -> put_lregion_here(xTELE) -> u_on_newpos()
1214 * Unspecified region (.lx == 0) defaults to entire level.
1216 if (was_in_W_tower && On_W_tower_level(&u.uz))
1217 /* Stay inside the Wizard's tower when feasible.
1218 We use the W Tower's exclusion region for the
1219 destination instead of its enclosing region.
1220 Note: up vs down doesn't matter in this case
1221 because both specify the same exclusion area. */
1222 place_lregion(dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy, 0, 0, 0,
1223 0, LR_DOWNTELE, (d_level *) 0);
1224 else if (up)
1225 place_lregion(updest.lx, updest.ly, updest.hx, updest.hy, updest.nlx,
1226 updest.nly, updest.nhx, updest.nhy, LR_UPTELE,
1227 (d_level *) 0);
1228 else
1229 place_lregion(dndest.lx, dndest.ly, dndest.hx, dndest.hy, dndest.nlx,
1230 dndest.nly, dndest.nhx, dndest.nhy, LR_DOWNTELE,
1231 (d_level *) 0);
1234 /* place you on the special staircase */
1235 void
1236 u_on_sstairs(upflag)
1237 int upflag;
1239 if (sstairs.sx)
1240 u_on_newpos(sstairs.sx, sstairs.sy);
1241 else
1242 u_on_rndspot(upflag);
1245 /* place you on upstairs (or special equivalent) */
1246 void
1247 u_on_upstairs()
1249 if (xupstair)
1250 u_on_newpos(xupstair, yupstair);
1251 else
1252 u_on_sstairs(0); /* destination upstairs implies moving down */
1255 /* place you on dnstairs (or special equivalent) */
1256 void
1257 u_on_dnstairs()
1259 if (xdnstair)
1260 u_on_newpos(xdnstair, ydnstair);
1261 else
1262 u_on_sstairs(1); /* destination dnstairs implies moving up */
1265 boolean
1266 On_stairs(x, y)
1267 xchar x, y;
1269 return (boolean) ((x == xupstair && y == yupstair)
1270 || (x == xdnstair && y == ydnstair)
1271 || (x == xdnladder && y == ydnladder)
1272 || (x == xupladder && y == yupladder)
1273 || (x == sstairs.sx && y == sstairs.sy));
1276 boolean
1277 Is_botlevel(lev)
1278 d_level *lev;
1280 return (boolean) (lev->dlevel == dungeons[lev->dnum].num_dunlevs);
1283 boolean
1284 Can_dig_down(lev)
1285 d_level *lev;
1287 return (boolean) (!level.flags.hardfloor
1288 && !Is_botlevel(lev)
1289 && !Invocation_lev(lev));
1293 * Like Can_dig_down (above), but also allows falling through on the
1294 * stronghold level. Normally, the bottom level of a dungeon resists
1295 * both digging and falling.
1297 boolean
1298 Can_fall_thru(lev)
1299 d_level *lev;
1301 return (boolean) (Can_dig_down(lev) || Is_stronghold(lev));
1305 * True if one can rise up a level (e.g. cursed gain level).
1306 * This happens on intermediate dungeon levels or on any top dungeon
1307 * level that has a stairwell style branch to the next higher dungeon.
1308 * Checks for amulets and such must be done elsewhere.
1310 boolean
1311 Can_rise_up(x, y, lev)
1312 int x, y;
1313 d_level *lev;
1315 /* can't rise up from inside the top of the Wizard's tower */
1316 /* KMH -- or in sokoban */
1317 if (In_endgame(lev) || In_sokoban(lev)
1318 || (Is_wiz1_level(lev) && In_W_tower(x, y, lev)))
1319 return FALSE;
1320 return (boolean) (lev->dlevel > 1
1321 || (dungeons[lev->dnum].entry_lev == 1
1322 && ledger_no(lev) != 1
1323 && sstairs.sx && sstairs.up));
1326 boolean
1327 has_ceiling(lev)
1328 d_level *lev;
1330 /* [what about level 1 of the quest?] */
1331 return (boolean) (!Is_airlevel(lev) && !Is_waterlevel(lev));
1335 * It is expected that the second argument of get_level is a depth value,
1336 * either supplied by the user (teleport control) or randomly generated.
1337 * But more than one level can be at the same depth. If the target level
1338 * is "above" the present depth location, get_level must trace "up" from
1339 * the player's location (through the ancestors dungeons) the dungeon
1340 * within which the target level is located. With only one exception
1341 * which does not pass through this routine (see level_tele), teleporting
1342 * "down" is confined to the current dungeon. At present, level teleport
1343 * in dungeons that build up is confined within them.
1345 void
1346 get_level(newlevel, levnum)
1347 d_level *newlevel;
1348 int levnum;
1350 branch *br;
1351 xchar dgn = u.uz.dnum;
1353 if (levnum <= 0) {
1354 /* can only currently happen in endgame */
1355 levnum = u.uz.dlevel;
1356 } else if (levnum
1357 > dungeons[dgn].depth_start + dungeons[dgn].num_dunlevs - 1) {
1358 /* beyond end of dungeon, jump to last level */
1359 levnum = dungeons[dgn].num_dunlevs;
1360 } else {
1361 /* The desired level is in this dungeon or a "higher" one. */
1364 * Branch up the tree until we reach a dungeon that contains the
1365 * levnum.
1367 if (levnum < dungeons[dgn].depth_start) {
1368 do {
1370 * Find the parent dungeon of this dungeon.
1372 * This assumes that end2 is always the "child" and it is
1373 * unique.
1375 for (br = branches; br; br = br->next)
1376 if (br->end2.dnum == dgn)
1377 break;
1378 if (!br)
1379 panic("get_level: can't find parent dungeon");
1381 dgn = br->end1.dnum;
1382 } while (levnum < dungeons[dgn].depth_start);
1385 /* We're within the same dungeon; calculate the level. */
1386 levnum = levnum - dungeons[dgn].depth_start + 1;
1389 newlevel->dnum = dgn;
1390 newlevel->dlevel = levnum;
1393 /* are you in the quest dungeon? */
1394 boolean
1395 In_quest(lev)
1396 d_level *lev;
1398 return (boolean) (lev->dnum == quest_dnum);
1401 /* are you in the mines dungeon? */
1402 boolean
1403 In_mines(lev)
1404 d_level *lev;
1406 return (boolean) (lev->dnum == mines_dnum);
1410 * Return the branch for the given dungeon.
1412 * This function assumes:
1413 * + This is not called with "Dungeons of Doom".
1414 * + There is only _one_ branch to a given dungeon.
1415 * + Field end2 is the "child" dungeon.
1417 branch *
1418 dungeon_branch(s)
1419 const char *s;
1421 branch *br;
1422 xchar dnum;
1424 dnum = dname_to_dnum(s);
1426 /* Find the branch that connects to dungeon i's branch. */
1427 for (br = branches; br; br = br->next)
1428 if (br->end2.dnum == dnum)
1429 break;
1431 if (!br)
1432 panic("dgn_entrance: can't find entrance to %s", s);
1434 return br;
1438 * This returns true if the hero is on the same level as the entrance to
1439 * the named dungeon.
1441 * Called from do.c and mklev.c.
1443 * Assumes that end1 is always the "parent".
1445 boolean
1446 at_dgn_entrance(s)
1447 const char *s;
1449 branch *br;
1451 br = dungeon_branch(s);
1452 return on_level(&u.uz, &br->end1) ? TRUE : FALSE;
1455 /* is `lev' part of Vlad's tower? */
1456 boolean
1457 In_V_tower(lev)
1458 d_level *lev;
1460 return (boolean) (lev->dnum == tower_dnum);
1463 /* is `lev' a level containing the Wizard's tower? */
1464 boolean
1465 On_W_tower_level(lev)
1466 d_level *lev;
1468 return (boolean) (Is_wiz1_level(lev)
1469 || Is_wiz2_level(lev)
1470 || Is_wiz3_level(lev));
1473 /* is <x,y> of `lev' inside the Wizard's tower? */
1474 boolean
1475 In_W_tower(x, y, lev)
1476 int x, y;
1477 d_level *lev;
1479 if (!On_W_tower_level(lev))
1480 return FALSE;
1482 * Both of the exclusion regions for arriving via level teleport
1483 * (from above or below) define the tower's boundary.
1484 * assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} );
1486 if (dndest.nlx > 0)
1487 return (boolean) within_bounded_area(x, y, dndest.nlx, dndest.nly,
1488 dndest.nhx, dndest.nhy);
1489 else
1490 impossible("No boundary for Wizard's Tower?");
1491 return FALSE;
1494 /* are you in one of the Hell levels? */
1495 boolean
1496 In_hell(lev)
1497 d_level *lev;
1499 return (boolean) (dungeons[lev->dnum].flags.hellish);
1502 /* sets *lev to be the gateway to Gehennom... */
1503 void
1504 find_hell(lev)
1505 d_level *lev;
1507 lev->dnum = valley_level.dnum;
1508 lev->dlevel = 1;
1511 /* go directly to hell... */
1512 void
1513 goto_hell(at_stairs, falling)
1514 boolean at_stairs, falling;
1516 d_level lev;
1518 find_hell(&lev);
1519 goto_level(&lev, at_stairs, falling, FALSE);
1522 /* equivalent to dest = source */
1523 void
1524 assign_level(dest, src)
1525 d_level *dest, *src;
1527 dest->dnum = src->dnum;
1528 dest->dlevel = src->dlevel;
1531 /* dest = src + rn1(range) */
1532 void
1533 assign_rnd_level(dest, src, range)
1534 d_level *dest, *src;
1535 int range;
1537 dest->dnum = src->dnum;
1538 dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range));
1540 if (dest->dlevel > dunlevs_in_dungeon(dest))
1541 dest->dlevel = dunlevs_in_dungeon(dest);
1542 else if (dest->dlevel < 1)
1543 dest->dlevel = 1;
1547 induced_align(pct)
1548 int pct;
1550 s_level *lev = Is_special(&u.uz);
1551 aligntyp al;
1553 if (lev && lev->flags.align)
1554 if (rn2(100) < pct)
1555 return lev->flags.align;
1557 if (dungeons[u.uz.dnum].flags.align)
1558 if (rn2(100) < pct)
1559 return dungeons[u.uz.dnum].flags.align;
1561 al = rn2(3) - 1;
1562 return Align2amask(al);
1565 boolean
1566 Invocation_lev(lev)
1567 d_level *lev;
1569 return (boolean) (In_hell(lev)
1570 && lev->dlevel == dungeons[lev->dnum].num_dunlevs - 1);
1573 /* use instead of depth() wherever a degree of difficulty is made
1574 * dependent on the location in the dungeon (eg. monster creation).
1576 xchar
1577 level_difficulty()
1579 int res;
1581 if (In_endgame(&u.uz)) {
1582 res = depth(&sanctum_level) + u.ulevel / 2;
1583 } else if (u.uhave.amulet) {
1584 res = deepest_lev_reached(FALSE);
1585 } else {
1586 res = depth(&u.uz);
1587 /* depth() is the number of elevation units (levels) below
1588 the theoretical surface; in a builds-up branch, that value
1589 ends up making the harder to reach levels be treated as if
1590 they were easier; adjust for the extra effort involved in
1591 going down to the entrance and then up to the location */
1592 if (builds_up(&u.uz))
1593 res += 2 * (dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1);
1595 * 'Proof' by example: suppose the entrance to sokoban is
1596 * on dungeon level 9, leading up to bottom sokoban level
1597 * of 8 [entry_lev]. When the hero is on sokoban level 8
1598 * [uz.dlevel], depth() yields eight but he has ventured
1599 * one level beyond 9, so difficulty depth should be 10:
1600 * 8 + 2 * (8 - 8 + 1) => 10.
1601 * Going up to 7, depth is 7 but hero will be two beyond 9:
1602 * 7 + 2 * (8 - 7 + 1) => 11.
1603 * When he goes up to level 6, three levels beyond 9:
1604 * 6 + 2 * (8 - 6 + 1) => 12.
1605 * And the top level of sokoban at 5, four levels beyond 9:
1606 * 5 + 2 * (8 - 5 + 1) => 13.
1607 * The same applies to Vlad's Tower, although the increment
1608 * there is inconsequential compared to overall depth.
1610 #if 0
1612 * The inside of the Wizard's Tower is also effectively a
1613 * builds-up area, reached from a portal an arbitrary distance
1614 * below rather than stairs 1 level beneath the entry level.
1616 else if (On_W_tower_level(&u.uz) && In_W_tower(some_X, some_Y, &u.uz))
1617 res += (fakewiz1.dlev - u.uz.dlev);
1619 * Handling this properly would need more information here:
1620 * an inside/outside flag, or coordinates to calculate it.
1621 * Unfortunately level difficulty may be wanted before
1622 * coordinates have been chosen so simply extending this
1623 * routine to take extra arguments is not sufficient to cope.
1624 * The difference beyond naive depth-from-surface is small
1625 * relative to the overall depth, so just ignore complications
1626 * posed by W_tower.
1628 #endif /*0*/
1630 return (xchar) res;
1633 /* Take one word and try to match it to a level.
1634 * Recognized levels are as shown by print_dungeon().
1636 schar
1637 lev_by_name(nam)
1638 const char *nam;
1640 schar lev = 0;
1641 s_level *slev = (s_level *)0;
1642 d_level dlev;
1643 const char *p;
1644 int idx, idxtoo;
1645 char buf[BUFSZ];
1646 mapseen *mseen;
1648 /* look at the player's custom level annotations first */
1649 if ((mseen = find_mapseen_by_str(nam)) != 0) {
1650 dlev = mseen->lev;
1651 } else {
1652 /* no matching annotation, check whether they used a name we know */
1654 /* allow strings like "the oracle level" to find "oracle" */
1655 if (!strncmpi(nam, "the ", 4))
1656 nam += 4;
1657 if ((p = strstri(nam, " level")) != 0 && p == eos((char *) nam) - 6) {
1658 nam = strcpy(buf, nam);
1659 *(eos(buf) - 6) = '\0';
1661 /* hell is the old name, and wouldn't match; gehennom would match its
1662 branch, yielding the castle level instead of the valley of the dead */
1663 if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) {
1664 if (In_V_tower(&u.uz))
1665 nam = " to Vlad's tower"; /* branch to... */
1666 else
1667 nam = "valley";
1670 if ((slev = find_level(nam)) != 0)
1671 dlev = slev->dlevel;
1674 if (mseen || slev) {
1675 idx = ledger_no(&dlev);
1676 if ((dlev.dnum == u.uz.dnum
1677 /* within same branch, or else main dungeon <-> gehennom */
1678 || (u.uz.dnum == valley_level.dnum
1679 && dlev.dnum == medusa_level.dnum)
1680 || (u.uz.dnum == medusa_level.dnum
1681 && dlev.dnum == valley_level.dnum))
1682 && (/* either wizard mode or else seen and not forgotten */
1683 wizard
1684 || (level_info[idx].flags & (FORGOTTEN | VISITED))
1685 == VISITED)) {
1686 lev = depth(&dlev);
1688 } else { /* not a specific level; try branch names */
1689 idx = find_branch(nam, (struct proto_dungeon *) 0);
1690 /* "<branch> to Xyzzy" */
1691 if (idx < 0 && (p = strstri(nam, " to ")) != 0)
1692 idx = find_branch(p + 4, (struct proto_dungeon *) 0);
1694 if (idx >= 0) {
1695 idxtoo = (idx >> 8) & 0x00FF;
1696 idx &= 0x00FF;
1697 if (/* either wizard mode, or else _both_ sides of branch seen */
1698 wizard
1699 || ((level_info[idx].flags & (FORGOTTEN | VISITED)) == VISITED
1700 && (level_info[idxtoo].flags & (FORGOTTEN | VISITED))
1701 == VISITED)) {
1702 if (ledger_to_dnum(idxtoo) == u.uz.dnum)
1703 idx = idxtoo;
1704 dlev.dnum = ledger_to_dnum(idx);
1705 dlev.dlevel = ledger_to_dlev(idx);
1706 lev = depth(&dlev);
1710 return lev;
1713 STATIC_OVL boolean
1714 unplaced_floater(dptr)
1715 struct dungeon *dptr;
1717 branch *br;
1718 int idx = (int) (dptr - dungeons);
1720 /* if other floating branches are added, this will need to change */
1721 if (idx != knox_level.dnum)
1722 return FALSE;
1723 for (br = branches; br; br = br->next)
1724 if (br->end1.dnum == n_dgns && br->end2.dnum == idx)
1725 return TRUE;
1726 return FALSE;
1729 STATIC_OVL boolean
1730 unreachable_level(lvl_p, unplaced)
1731 d_level *lvl_p;
1732 boolean unplaced;
1734 s_level *dummy;
1736 if (unplaced)
1737 return TRUE;
1738 if (In_endgame(&u.uz) && !In_endgame(lvl_p))
1739 return TRUE;
1740 if ((dummy = find_level("dummy")) != 0 && on_level(lvl_p, &dummy->dlevel))
1741 return TRUE;
1742 return FALSE;
1745 static void
1746 tport_menu(win, entry, lchoices, lvl_p, unreachable)
1747 winid win;
1748 char *entry;
1749 struct lchoice *lchoices;
1750 d_level *lvl_p;
1751 boolean unreachable;
1753 char tmpbuf[BUFSZ];
1754 anything any;
1756 lchoices->lev[lchoices->idx] = lvl_p->dlevel;
1757 lchoices->dgn[lchoices->idx] = lvl_p->dnum;
1758 lchoices->playerlev[lchoices->idx] = depth(lvl_p);
1759 any = zeroany;
1760 if (unreachable) {
1761 /* not selectable, but still consumes next menuletter;
1762 prepend padding in place of missing menu selector */
1763 Sprintf(tmpbuf, " %s", entry);
1764 entry = tmpbuf;
1765 } else {
1766 any.a_int = lchoices->idx + 1;
1768 add_menu(win, NO_GLYPH, &any, lchoices->menuletter, 0, ATR_NONE, entry,
1769 MENU_UNSELECTED);
1770 /* this assumes there are at most 52 interesting levels */
1771 if (lchoices->menuletter == 'z')
1772 lchoices->menuletter = 'A';
1773 else
1774 lchoices->menuletter++;
1775 lchoices->idx++;
1776 return;
1779 /* Convert a branch type to a string usable by print_dungeon(). */
1780 STATIC_OVL const char *
1781 br_string(type)
1782 int type;
1784 switch (type) {
1785 case BR_PORTAL:
1786 return "Portal";
1787 case BR_NO_END1:
1788 return "Connection";
1789 case BR_NO_END2:
1790 return "One way stair";
1791 case BR_STAIR:
1792 return "Stair";
1794 return " (unknown)";
1797 /* Print all child branches between the lower and upper bounds. */
1798 STATIC_OVL void
1799 print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices_p)
1800 winid win;
1801 int dnum;
1802 int lower_bound;
1803 int upper_bound;
1804 boolean bymenu;
1805 struct lchoice *lchoices_p;
1807 branch *br;
1808 char buf[BUFSZ];
1810 /* This assumes that end1 is the "parent". */
1811 for (br = branches; br; br = br->next) {
1812 if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel
1813 && br->end1.dlevel <= upper_bound) {
1814 Sprintf(buf, " %s to %s: %d", br_string(br->type),
1815 dungeons[br->end2.dnum].dname, depth(&br->end1));
1816 if (bymenu)
1817 tport_menu(win, buf, lchoices_p, &br->end1,
1818 unreachable_level(&br->end1, FALSE));
1819 else
1820 putstr(win, 0, buf);
1825 /* Print available dungeon information. */
1826 schar
1827 print_dungeon(bymenu, rlev, rdgn)
1828 boolean bymenu;
1829 schar *rlev;
1830 xchar *rdgn;
1832 int i, last_level, nlev;
1833 char buf[BUFSZ];
1834 const char *descr;
1835 boolean first, unplaced;
1836 s_level *slev;
1837 dungeon *dptr;
1838 branch *br;
1839 anything any;
1840 struct lchoice lchoices;
1842 winid win = create_nhwindow(NHW_MENU);
1843 if (bymenu) {
1844 start_menu(win);
1845 lchoices.idx = 0;
1846 lchoices.menuletter = 'a';
1849 for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
1850 if (bymenu && In_endgame(&u.uz) && i != astral_level.dnum)
1851 continue;
1852 unplaced = unplaced_floater(dptr);
1853 descr = unplaced ? "depth" : "level";
1854 nlev = dptr->num_dunlevs;
1855 if (nlev > 1)
1856 Sprintf(buf, "%s: %s %d to %d", dptr->dname, makeplural(descr),
1857 dptr->depth_start, dptr->depth_start + nlev - 1);
1858 else
1859 Sprintf(buf, "%s: %s %d", dptr->dname, descr, dptr->depth_start);
1861 /* Most entrances are uninteresting. */
1862 if (dptr->entry_lev != 1) {
1863 if (dptr->entry_lev == nlev)
1864 Strcat(buf, ", entrance from below");
1865 else
1866 Sprintf(eos(buf), ", entrance on %d",
1867 dptr->depth_start + dptr->entry_lev - 1);
1869 if (bymenu) {
1870 any = zeroany;
1871 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf,
1872 MENU_UNSELECTED);
1873 } else
1874 putstr(win, 0, buf);
1877 * Circle through the special levels to find levels that are in
1878 * this dungeon.
1880 for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
1881 if (slev->dlevel.dnum != i)
1882 continue;
1884 /* print any branches before this level */
1885 print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu,
1886 &lchoices);
1888 Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel));
1889 if (Is_stronghold(&slev->dlevel))
1890 Sprintf(eos(buf), " (tune %s)", tune);
1891 if (bymenu)
1892 tport_menu(win, buf, &lchoices, &slev->dlevel,
1893 unreachable_level(&slev->dlevel, unplaced));
1894 else
1895 putstr(win, 0, buf);
1897 last_level = slev->dlevel.dlevel;
1899 /* print branches after the last special level */
1900 print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices);
1903 if (bymenu) {
1904 int n;
1905 menu_item *selected;
1906 int idx;
1908 end_menu(win, "Level teleport to where:");
1909 n = select_menu(win, PICK_ONE, &selected);
1910 destroy_nhwindow(win);
1911 if (n > 0) {
1912 idx = selected[0].item.a_int - 1;
1913 free((genericptr_t) selected);
1914 if (rlev && rdgn) {
1915 *rlev = lchoices.lev[idx];
1916 *rdgn = lchoices.dgn[idx];
1917 return lchoices.playerlev[idx];
1920 return 0;
1923 /* Print out floating branches (if any). */
1924 for (first = TRUE, br = branches; br; br = br->next) {
1925 if (br->end1.dnum == n_dgns) {
1926 if (first) {
1927 putstr(win, 0, "");
1928 putstr(win, 0, "Floating branches");
1929 first = FALSE;
1931 Sprintf(buf, " %s to %s", br_string(br->type),
1932 dungeons[br->end2.dnum].dname);
1933 putstr(win, 0, buf);
1937 /* I hate searching for the invocation pos while debugging. -dean */
1938 if (Invocation_lev(&u.uz)) {
1939 putstr(win, 0, "");
1940 Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)",
1941 inv_pos.x, inv_pos.y, u.ux, u.uy);
1942 putstr(win, 0, buf);
1945 * The following is based on the assumption that the inter-level portals
1946 * created by the level compiler (not the dungeon compiler) only exist
1947 * one per level (currently true, of course).
1949 else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
1950 || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
1951 struct trap *trap;
1952 for (trap = ftrap; trap; trap = trap->ntrap)
1953 if (trap->ttyp == MAGIC_PORTAL)
1954 break;
1956 putstr(win, 0, "");
1957 if (trap)
1958 Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)", trap->tx,
1959 trap->ty, u.ux, u.uy);
1960 else
1961 Sprintf(buf, "No portal found.");
1962 putstr(win, 0, buf);
1965 display_nhwindow(win, TRUE);
1966 destroy_nhwindow(win);
1967 return 0;
1970 /* Record that the player knows about a branch from a level. This function
1971 * will determine whether or not it was a "real" branch that was taken.
1972 * This function should not be called for a transition done via level
1973 * teleport or via the Eye.
1975 void
1976 recbranch_mapseen(source, dest)
1977 d_level *source;
1978 d_level *dest;
1980 mapseen *mptr;
1981 branch *br;
1983 /* not a branch */
1984 if (source->dnum == dest->dnum)
1985 return;
1987 /* we only care about forward branches */
1988 for (br = branches; br; br = br->next) {
1989 if (on_level(source, &br->end1) && on_level(dest, &br->end2))
1990 break;
1991 if (on_level(source, &br->end2) && on_level(dest, &br->end1))
1992 return;
1995 /* branch not found, so not a real branch. */
1996 if (!br)
1997 return;
1999 if ((mptr = find_mapseen(source)) != 0) {
2000 if (mptr->br && br != mptr->br)
2001 impossible("Two branches on the same level?");
2002 mptr->br = br;
2003 } else {
2004 impossible("Can't note branch for unseen level (%d, %d)",
2005 source->dnum, source->dlevel);
2009 char *
2010 get_annotation(lev)
2011 d_level *lev;
2013 mapseen *mptr;
2015 if ((mptr = find_mapseen(lev)))
2016 return mptr->custom;
2017 return NULL;
2020 /* #annotate command - add a custom name to the current level */
2022 donamelevel()
2024 mapseen *mptr;
2025 char nbuf[BUFSZ]; /* Buffer for response */
2027 if (!(mptr = find_mapseen(&u.uz)))
2028 return 0;
2030 if (mptr->custom) {
2031 char tmpbuf[BUFSZ];
2032 Sprintf(tmpbuf, "Replace annotation \"%.30s%s\" with?", mptr->custom,
2033 strlen(mptr->custom) > 30 ? "..." : "");
2034 getlin(tmpbuf, nbuf);
2035 } else
2036 getlin("What do you want to call this dungeon level?", nbuf);
2037 if (index(nbuf, '\033'))
2038 return 0;
2039 (void) mungspaces(nbuf);
2041 /* discard old annotation, if any */
2042 if (mptr->custom) {
2043 free((genericptr_t) mptr->custom);
2044 mptr->custom = (char *) 0;
2045 mptr->custom_lth = 0;
2047 /* add new annotation, unless it's empty or a single space */
2048 if (*nbuf && strcmp(nbuf, " ")) {
2049 mptr->custom = dupstr(nbuf);
2050 mptr->custom_lth = strlen(mptr->custom);
2052 return 0;
2055 /* find the particular mapseen object in the chain; may return null */
2056 STATIC_OVL mapseen *
2057 find_mapseen(lev)
2058 d_level *lev;
2060 mapseen *mptr;
2062 for (mptr = mapseenchn; mptr; mptr = mptr->next)
2063 if (on_level(&(mptr->lev), lev))
2064 break;
2066 return mptr;
2069 STATIC_OVL mapseen *
2070 find_mapseen_by_str(s)
2071 const char *s;
2073 mapseen *mptr;
2075 for (mptr = mapseenchn; mptr; mptr = mptr->next)
2076 if (mptr->custom && !strcmpi(s, mptr->custom))
2077 break;
2079 return mptr;
2083 void
2084 forget_mapseen(ledger_num)
2085 int ledger_num;
2087 mapseen *mptr;
2088 struct cemetery *bp;
2090 for (mptr = mapseenchn; mptr; mptr = mptr->next)
2091 if (dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel
2092 == ledger_num)
2093 break;
2095 /* if not found, then nothing to forget */
2096 if (mptr) {
2097 mptr->flags.forgot = 1;
2098 mptr->br = (branch *) 0;
2100 /* custom names are erased, not just forgotten until revisited */
2101 if (mptr->custom) {
2102 mptr->custom_lth = 0;
2103 free((genericptr_t) mptr->custom);
2104 mptr->custom = (char *) 0;
2106 (void) memset((genericptr_t) mptr->msrooms, 0, sizeof mptr->msrooms);
2107 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2108 bp->bonesknown = FALSE;
2112 STATIC_OVL void
2113 save_mapseen(fd, mptr)
2114 int fd;
2115 mapseen *mptr;
2117 branch *curr;
2118 int brindx;
2120 for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx)
2121 if (curr == mptr->br)
2122 break;
2123 bwrite(fd, (genericptr_t) &brindx, sizeof brindx);
2125 bwrite(fd, (genericptr_t) &mptr->lev, sizeof mptr->lev);
2126 bwrite(fd, (genericptr_t) &mptr->feat, sizeof mptr->feat);
2127 bwrite(fd, (genericptr_t) &mptr->flags, sizeof mptr->flags);
2128 bwrite(fd, (genericptr_t) &mptr->custom_lth, sizeof mptr->custom_lth);
2129 if (mptr->custom_lth)
2130 bwrite(fd, (genericptr_t) mptr->custom, mptr->custom_lth);
2131 bwrite(fd, (genericptr_t) &mptr->msrooms, sizeof mptr->msrooms);
2132 savecemetery(fd, WRITE_SAVE, &mptr->final_resting_place);
2135 STATIC_OVL mapseen *
2136 load_mapseen(fd)
2137 int fd;
2139 int branchnum, brindx;
2140 mapseen *load;
2141 branch *curr;
2143 load = (mapseen *) alloc(sizeof *load);
2145 mread(fd, (genericptr_t) &branchnum, sizeof branchnum);
2146 for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx)
2147 if (brindx == branchnum)
2148 break;
2149 load->br = curr;
2151 mread(fd, (genericptr_t) &load->lev, sizeof load->lev);
2152 mread(fd, (genericptr_t) &load->feat, sizeof load->feat);
2153 mread(fd, (genericptr_t) &load->flags, sizeof load->flags);
2154 mread(fd, (genericptr_t) &load->custom_lth, sizeof load->custom_lth);
2155 if (load->custom_lth) {
2156 /* length doesn't include terminator (which isn't saved & restored) */
2157 load->custom = (char *) alloc(load->custom_lth + 1);
2158 mread(fd, (genericptr_t) load->custom, load->custom_lth);
2159 load->custom[load->custom_lth] = '\0';
2160 } else
2161 load->custom = 0;
2162 mread(fd, (genericptr_t) &load->msrooms, sizeof load->msrooms);
2163 restcemetery(fd, &load->final_resting_place);
2165 return load;
2168 /* to support '#stats' wizard-mode command */
2169 void
2170 overview_stats(win, statsfmt, total_count, total_size)
2171 winid win;
2172 const char *statsfmt;
2173 long *total_count, *total_size;
2175 char buf[BUFSZ], hdrbuf[QBUFSZ];
2176 long ocount, osize, bcount, bsize, acount, asize;
2177 struct cemetery *ce;
2178 mapseen *mptr = find_mapseen(&u.uz);
2180 ocount = bcount = acount = osize = bsize = asize = 0L;
2181 for (mptr = mapseenchn; mptr; mptr = mptr->next) {
2182 ++ocount;
2183 osize += (long) sizeof *mptr;
2184 for (ce = mptr->final_resting_place; ce; ce = ce->next) {
2185 ++bcount;
2186 bsize += (long) sizeof *ce;
2188 if (mptr->custom_lth) {
2189 ++acount;
2190 asize += (long) (mptr->custom_lth + 1);
2194 Sprintf(hdrbuf, "general, size %ld", (long) sizeof (mapseen));
2195 Sprintf(buf, statsfmt, hdrbuf, ocount, osize);
2196 putstr(win, 0, buf);
2197 if (bcount) {
2198 Sprintf(hdrbuf, "cemetery, size %ld",
2199 (long) sizeof (struct cemetery));
2200 Sprintf(buf, statsfmt, hdrbuf, bcount, bsize);
2201 putstr(win, 0, buf);
2203 if (acount) {
2204 Sprintf(hdrbuf, "annotations, text");
2205 Sprintf(buf, statsfmt, hdrbuf, acount, asize);
2206 putstr(win, 0, buf);
2208 *total_count += ocount + bcount + acount;
2209 *total_size += osize + bsize + asize;
2212 /* Remove all mapseen objects for a particular dnum.
2213 * Useful during quest expulsion to remove quest levels.
2214 * [No longer deleted, just marked as unreachable. #overview will
2215 * ignore such levels, end of game disclosure will include them.]
2217 void
2218 remdun_mapseen(dnum)
2219 int dnum;
2221 mapseen *mptr, **mptraddr;
2223 mptraddr = &mapseenchn;
2224 while ((mptr = *mptraddr) != 0) {
2225 if (mptr->lev.dnum == dnum) {
2226 #if 1 /* use this... */
2227 mptr->flags.unreachable = 1;
2229 #else /* old deletion code */
2230 *mptraddr = mptr->next;
2231 if (mptr->custom)
2232 free((genericptr_t) mptr->custom);
2233 if (mptr->final_resting_place)
2234 savecemetery(-1, FREE_SAVE, &mptr->final_resting_place);
2235 free((genericptr_t) mptr);
2236 } else
2237 #endif
2238 mptraddr = &mptr->next;
2242 void
2243 init_mapseen(lev)
2244 d_level *lev;
2246 /* Create a level and insert in "sorted" order. This is an insertion
2247 * sort first by dungeon (in order of discovery) and then by level number.
2249 mapseen *mptr, *init, *prev;
2251 init = (mapseen *) alloc(sizeof *init);
2252 (void) memset((genericptr_t) init, 0, sizeof *init);
2253 /* memset is fine for feature bits, flags, and rooms array;
2254 explicitly initialize pointers to null */
2255 init->next = 0, init->br = 0, init->custom = 0;
2256 init->final_resting_place = 0;
2257 /* lastseentyp[][] is reused for each level, so get rid of
2258 previous level's data */
2259 (void) memset((genericptr_t) lastseentyp, 0, sizeof lastseentyp);
2261 init->lev.dnum = lev->dnum;
2262 init->lev.dlevel = lev->dlevel;
2264 /* walk until we get to the place where we should insert init */
2265 for (mptr = mapseenchn, prev = 0; mptr; prev = mptr, mptr = mptr->next)
2266 if (mptr->lev.dnum > init->lev.dnum
2267 || (mptr->lev.dnum == init->lev.dnum
2268 && mptr->lev.dlevel > init->lev.dlevel))
2269 break;
2270 if (!prev) {
2271 init->next = mapseenchn;
2272 mapseenchn = init;
2273 } else {
2274 mptr = prev->next;
2275 prev->next = init;
2276 init->next = mptr;
2280 #define INTEREST(feat) \
2281 ((feat).nfount || (feat).nsink || (feat).nthrone || (feat).naltar \
2282 || (feat).ngrave || (feat).ntree || (feat).nshop || (feat).ntemple)
2283 /* || (feat).water || (feat).ice || (feat).lava */
2285 /* returns true if this level has something interesting to print out */
2286 STATIC_OVL boolean
2287 interest_mapseen(mptr)
2288 mapseen *mptr;
2290 if (on_level(&u.uz, &mptr->lev))
2291 return TRUE;
2292 if (mptr->flags.unreachable || mptr->flags.forgot)
2293 return FALSE;
2294 /* level is of interest if it has an auto-generated annotation */
2295 if (mptr->flags.oracle || mptr->flags.bigroom || mptr->flags.roguelevel
2296 || mptr->flags.castle || mptr->flags.valley || mptr->flags.msanctum
2297 || mptr->flags.quest_summons || mptr->flags.questing)
2298 return TRUE;
2299 /* when in Sokoban, list all sokoban levels visited; when not in it,
2300 list any visited Sokoban level which remains unsolved (will usually
2301 only be furthest one reached, but it's possible to enter pits and
2302 climb out on the far side on the first Sokoban level; also, wizard
2303 mode overrides teleport restrictions) */
2304 if (In_sokoban(&mptr->lev)
2305 && (In_sokoban(&u.uz) || !mptr->flags.sokosolved))
2306 return TRUE;
2307 /* when in the endgame, list all endgame levels visited, whether they
2308 have annotations or not, so that #overview doesn't become extremely
2309 sparse once the rest of the dungeon has been flagged as unreachable */
2310 if (In_endgame(&u.uz))
2311 return (boolean) In_endgame(&mptr->lev);
2312 /* level is of interest if it has non-zero feature count or known bones
2313 or user annotation or known connection to another dungeon branch
2314 or is the furthest level reached in its branch */
2315 return (boolean) (INTEREST(mptr->feat)
2316 || (mptr->final_resting_place
2317 && (mptr->flags.knownbones || wizard))
2318 || mptr->custom || mptr->br
2319 || (mptr->lev.dlevel
2320 == dungeons[mptr->lev.dnum].dunlev_ureached));
2323 /* recalculate mapseen for the current level */
2324 void
2325 recalc_mapseen()
2327 mapseen *mptr;
2328 struct monst *mtmp;
2329 struct cemetery *bp, **bonesaddr;
2330 unsigned i, ridx;
2331 int x, y, ltyp, count, atmp;
2333 /* Should not happen in general, but possible if in the process
2334 * of being booted from the quest. The mapseen object gets
2335 * removed during the expulsion but prior to leaving the level
2336 * [Since quest expulsion no longer deletes quest mapseen data,
2337 * null return from find_mapseen() should now be impossible.]
2339 if (!(mptr = find_mapseen(&u.uz)))
2340 return;
2342 /* reset all features; mptr->feat.* = 0; */
2343 (void) memset((genericptr_t) &mptr->feat, 0, sizeof mptr->feat);
2344 /* reset most flags; some level-specific ones are left as-is */
2345 if (mptr->flags.unreachable) {
2346 mptr->flags.unreachable = 0; /* reached it; Eye of the Aethiopica? */
2347 if (In_quest(&u.uz)) {
2348 mapseen *mptrtmp = mapseenchn;
2350 /* when quest was unreachable due to ejection and portal removal,
2351 getting back to it via arti-invoke should revive annotation
2352 data for all quest levels, not just the one we're on now */
2353 do {
2354 if (mptrtmp->lev.dnum == mptr->lev.dnum)
2355 mptrtmp->flags.unreachable = 0;
2356 mptrtmp = mptrtmp->next;
2357 } while (mptrtmp);
2360 mptr->flags.knownbones = 0;
2361 mptr->flags.sokosolved = In_sokoban(&u.uz) && !Sokoban;
2362 /* mptr->flags.bigroom retains previous value when hero can't see */
2363 if (!Blind)
2364 mptr->flags.bigroom = Is_bigroom(&u.uz);
2365 else if (mptr->flags.forgot)
2366 mptr->flags.bigroom = 0;
2367 mptr->flags.roguelevel = Is_rogue_level(&u.uz);
2368 mptr->flags.oracle = 0; /* recalculated during room traversal below */
2369 mptr->flags.castletune = 0;
2370 /* flags.castle, flags.valley, flags.msanctum retain previous value */
2371 mptr->flags.forgot = 0;
2372 /* flags.quest_summons disabled once quest finished */
2373 mptr->flags.quest_summons = (at_dgn_entrance("The Quest")
2374 && u.uevent.qcalled
2375 && !(u.uevent.qcompleted
2376 || u.uevent.qexpelled
2377 || quest_status.leader_is_dead));
2378 mptr->flags.questing = (on_level(&u.uz, &qstart_level)
2379 && quest_status.got_quest);
2381 /* track rooms the hero is in */
2382 for (i = 0; i < SIZE(u.urooms); ++i) {
2383 if (!u.urooms[i])
2384 continue;
2386 ridx = u.urooms[i] - ROOMOFFSET;
2387 mptr->msrooms[ridx].seen = 1;
2388 mptr->msrooms[ridx].untended =
2389 (rooms[ridx].rtype >= SHOPBASE)
2390 ? (!(mtmp = shop_keeper(u.urooms[i])) || !inhishop(mtmp))
2391 : (rooms[ridx].rtype == TEMPLE)
2392 ? (!(mtmp = findpriest(u.urooms[i]))
2393 || !inhistemple(mtmp))
2394 : 0;
2397 /* recalculate room knowledge: for now, just shops and temples
2398 * this could be extended to an array of 0..SHOPBASE
2400 for (i = 0; i < SIZE(mptr->msrooms); ++i) {
2401 if (mptr->msrooms[i].seen) {
2402 if (rooms[i].rtype >= SHOPBASE) {
2403 if (mptr->msrooms[i].untended)
2404 mptr->feat.shoptype = SHOPBASE - 1;
2405 else if (!mptr->feat.nshop)
2406 mptr->feat.shoptype = rooms[i].rtype;
2407 else if (mptr->feat.shoptype != (unsigned) rooms[i].rtype)
2408 mptr->feat.shoptype = 0;
2409 count = mptr->feat.nshop + 1;
2410 if (count <= 3)
2411 mptr->feat.nshop = count;
2412 } else if (rooms[i].rtype == TEMPLE) {
2413 /* altar and temple alignment handled below */
2414 count = mptr->feat.ntemple + 1;
2415 if (count <= 3)
2416 mptr->feat.ntemple = count;
2417 } else if (rooms[i].orig_rtype == DELPHI) {
2418 mptr->flags.oracle = 1;
2423 /* Update lastseentyp with typ if and only if it is in sight or the
2424 * hero can feel it on their current location (i.e. not levitating).
2425 * This *should* give the "last known typ" for each dungeon location.
2426 * (At the very least, it's a better assumption than determining what
2427 * the player knows from the glyph and the typ (which is isn't quite
2428 * enough information in some cases)).
2430 * It was reluctantly added to struct rm to track. Alternatively
2431 * we could track "features" and then update them all here, and keep
2432 * track of when new features are created or destroyed, but this
2433 * seemed the most elegant, despite adding more data to struct rm.
2434 * [3.6.0: we're using lastseentyp[][] rather than level.locations
2435 * to track the features seen.]
2437 * Although no current windowing systems (can) do this, this would add
2438 * the ability to have non-dungeon glyphs float above the last known
2439 * dungeon glyph (i.e. items on fountains).
2441 for (x = 1; x < COLNO; x++) {
2442 for (y = 0; y < ROWNO; y++) {
2443 if (cansee(x, y) || (x == u.ux && y == u.uy && !Levitation)) {
2444 ltyp = levl[x][y].typ;
2445 if (ltyp == DRAWBRIDGE_UP)
2446 ltyp = db_under_typ(levl[x][y].drawbridgemask);
2447 if ((mtmp = m_at(x, y)) != 0
2448 && mtmp->m_ap_type == M_AP_FURNITURE && canseemon(mtmp))
2449 ltyp = cmap_to_type(mtmp->mappearance);
2450 lastseentyp[x][y] = ltyp;
2453 switch (lastseentyp[x][y]) {
2454 #if 0
2455 case ICE:
2456 count = mptr->feat.ice + 1;
2457 if (count <= 3)
2458 mptr->feat.ice = count;
2459 break;
2460 case POOL:
2461 case MOAT:
2462 case WATER:
2463 count = mptr->feat.water + 1;
2464 if (count <= 3)
2465 mptr->feat.water = count;
2466 break;
2467 case LAVAPOOL:
2468 count = mptr->feat.lava + 1;
2469 if (count <= 3)
2470 mptr->feat.lava = count;
2471 break;
2472 #endif
2473 case TREE:
2474 count = mptr->feat.ntree + 1;
2475 if (count <= 3)
2476 mptr->feat.ntree = count;
2477 break;
2478 case FOUNTAIN:
2479 count = mptr->feat.nfount + 1;
2480 if (count <= 3)
2481 mptr->feat.nfount = count;
2482 break;
2483 case THRONE:
2484 count = mptr->feat.nthrone + 1;
2485 if (count <= 3)
2486 mptr->feat.nthrone = count;
2487 break;
2488 case SINK:
2489 count = mptr->feat.nsink + 1;
2490 if (count <= 3)
2491 mptr->feat.nsink = count;
2492 break;
2493 case GRAVE:
2494 count = mptr->feat.ngrave + 1;
2495 if (count <= 3)
2496 mptr->feat.ngrave = count;
2497 break;
2498 case ALTAR:
2499 atmp = (Is_astralevel(&u.uz)
2500 && (levl[x][y].seenv & SVALL) != SVALL)
2501 ? MSA_NONE
2502 : Amask2msa(levl[x][y].altarmask);
2503 if (!mptr->feat.naltar)
2504 mptr->feat.msalign = atmp;
2505 else if (mptr->feat.msalign != atmp)
2506 mptr->feat.msalign = MSA_NONE;
2507 count = mptr->feat.naltar + 1;
2508 if (count <= 3)
2509 mptr->feat.naltar = count;
2510 break;
2511 /* An automatic annotation is added to the Castle and
2512 * to Fort Ludios once their structure's main entrance
2513 * has been seen (in person or via magic mapping).
2514 * For the Fort, that entrance is just a secret door
2515 * which will be converted into a regular one when
2516 * located (or destroyed).
2517 * DOOR: possibly a lowered drawbridge's open portcullis;
2518 * DBWALL: a raised drawbridge's "closed door";
2519 * DRAWBRIDGE_DOWN: the span provided by lowered bridge,
2520 * with moat or other terrain hidden underneath;
2521 * DRAWBRIDGE_UP: moat in front of a raised drawbridge,
2522 * not recognizable as a bridge location unless/until
2523 * the adjacent DBWALL has been seen.
2525 case DOOR:
2526 if (Is_knox(&u.uz)) {
2527 int ty, tx = x - 4;
2529 /* Throne is four columns left, either directly in
2530 * line or one row higher or lower, and doesn't have
2531 * to have been seen yet.
2532 * ......|}}}.
2533 * ..\...S}...
2534 * ..\...S}...
2535 * ......|}}}.
2536 * For 3.6.0 and earlier, it was always in direct line:
2537 * both throne and door on the lower of the two rows.
2539 for (ty = y - 1; ty <= y + 1; ++ty)
2540 if (isok(tx, ty) && IS_THRONE(levl[tx][ty].typ)) {
2541 mptr->flags.ludios = 1;
2542 break;
2544 break;
2546 if (is_drawbridge_wall(x, y) < 0)
2547 break;
2548 /* else FALLTHRU */
2549 case DBWALL:
2550 case DRAWBRIDGE_DOWN:
2551 if (Is_stronghold(&u.uz))
2552 mptr->flags.castle = 1, mptr->flags.castletune = 1;
2553 break;
2554 default:
2555 break;
2560 if (level.bonesinfo && !mptr->final_resting_place) {
2561 /* clone the bonesinfo so we aren't dependent upon this
2562 level being in memory */
2563 bonesaddr = &mptr->final_resting_place;
2564 bp = level.bonesinfo;
2565 do {
2566 *bonesaddr = (struct cemetery *) alloc(sizeof **bonesaddr);
2567 **bonesaddr = *bp;
2568 bp = bp->next;
2569 bonesaddr = &(*bonesaddr)->next;
2570 } while (bp);
2571 *bonesaddr = 0;
2573 /* decide which past hero deaths have become known; there's no
2574 guarantee of either a grave or a ghost, so we go by whether the
2575 current hero has seen the map location where each old one died */
2576 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2577 if (lastseentyp[bp->frpx][bp->frpy]) {
2578 bp->bonesknown = TRUE;
2579 mptr->flags.knownbones = 1;
2583 /*ARGUSED*/
2584 /* valley and sanctum levels get automatic annotation once temple is entered
2586 void
2587 mapseen_temple(priest)
2588 struct monst *priest UNUSED; /* currently unused; might be useful someday */
2590 mapseen *mptr = find_mapseen(&u.uz);
2592 if (Is_valley(&u.uz))
2593 mptr->flags.valley = 1;
2594 else if (Is_sanctum(&u.uz))
2595 mptr->flags.msanctum = 1;
2598 /* room entry message has just been delivered so learn room even if blind */
2599 void
2600 room_discovered(roomno)
2601 int roomno;
2603 mapseen *mptr = find_mapseen(&u.uz);
2605 mptr->msrooms[roomno].seen = 1;
2608 /* #overview command */
2610 dooverview()
2612 show_overview(0, 0);
2613 return 0;
2616 /* called for #overview or for end of game disclosure */
2617 void
2618 show_overview(why, reason)
2619 int why; /* 0 => #overview command,
2620 1 or 2 => final disclosure (1: hero lived, 2: hero died) */
2621 int reason; /* how hero died; used when disclosing end-of-game level */
2623 winid win;
2624 int lastdun = -1;
2626 /* lazy initialization */
2627 (void) recalc_mapseen();
2629 win = create_nhwindow(NHW_MENU);
2630 /* show the endgame levels before the rest of the dungeon,
2631 so that the Planes (dnum 5-ish) come out above main dungeon (dnum 0) */
2632 if (In_endgame(&u.uz))
2633 traverse_mapseenchn(TRUE, win, why, reason, &lastdun);
2634 /* if game is over or we're not in the endgame yet, show the dungeon */
2635 if (why > 0 || !In_endgame(&u.uz))
2636 traverse_mapseenchn(FALSE, win, why, reason, &lastdun);
2637 display_nhwindow(win, TRUE);
2638 destroy_nhwindow(win);
2641 /* display endgame levels or non-endgame levels, not both */
2642 STATIC_OVL void
2643 traverse_mapseenchn(viewendgame, win, why, reason, lastdun_p)
2644 boolean viewendgame;
2645 winid win;
2646 int why, reason, *lastdun_p;
2648 mapseen *mptr;
2649 boolean showheader;
2651 for (mptr = mapseenchn; mptr; mptr = mptr->next) {
2652 if (viewendgame ^ In_endgame(&mptr->lev))
2653 continue;
2655 /* only print out info for a level or a dungeon if interest */
2656 if (why > 0 || interest_mapseen(mptr)) {
2657 showheader = (boolean) (mptr->lev.dnum != *lastdun_p);
2658 print_mapseen(win, mptr, why, reason, showheader);
2659 *lastdun_p = mptr->lev.dnum;
2664 STATIC_OVL const char *
2665 seen_string(x, obj)
2666 xchar x;
2667 const char *obj;
2669 /* players are computer scientists: 0, 1, 2, n */
2670 switch (x) {
2671 case 0:
2672 return "no";
2673 /* an() returns too much. index is ok in this case */
2674 case 1:
2675 return index(vowels, *obj) ? "an" : "a";
2676 case 2:
2677 return "some";
2678 case 3:
2679 return "many";
2682 return "(unknown)";
2685 /* better br_string */
2686 STATIC_OVL const char *
2687 br_string2(br)
2688 branch *br;
2690 /* Special case: quest portal says closed if kicked from quest */
2691 boolean closed_portal = (br->end2.dnum == quest_dnum
2692 && u.uevent.qexpelled);
2694 switch (br->type) {
2695 case BR_PORTAL:
2696 return closed_portal ? "Sealed portal" : "Portal";
2697 case BR_NO_END1:
2698 return "Connection";
2699 case BR_NO_END2:
2700 return br->end1_up ? "One way stairs up" : "One way stairs down";
2701 case BR_STAIR:
2702 return br->end1_up ? "Stairs up" : "Stairs down";
2705 return "(unknown)";
2708 /* get the name of an endgame level; topten.c does something similar */
2709 STATIC_OVL const char *
2710 endgamelevelname(outbuf, indx)
2711 char *outbuf;
2712 int indx;
2714 const char *planename = 0;
2716 *outbuf = '\0';
2717 switch (indx) {
2718 case -5:
2719 Strcpy(outbuf, "Astral Plane");
2720 break;
2721 case -4:
2722 planename = "Water";
2723 break;
2724 case -3:
2725 planename = "Fire";
2726 break;
2727 case -2:
2728 planename = "Air";
2729 break;
2730 case -1:
2731 planename = "Earth";
2732 break;
2734 if (planename)
2735 Sprintf(outbuf, "Plane of %s", planename);
2736 else if (!*outbuf)
2737 Sprintf(outbuf, "unknown plane #%d", indx);
2738 return outbuf;
2741 STATIC_OVL const char *
2742 shop_string(rtype)
2743 int rtype;
2745 const char *str = "shop"; /* catchall */
2747 /* Yuck, redundancy...but shclass.name doesn't cut it as a noun */
2748 switch (rtype) {
2749 case SHOPBASE - 1:
2750 str = "untended shop";
2751 break; /* see recalc_mapseen */
2752 case SHOPBASE:
2753 str = "general store";
2754 break;
2755 case ARMORSHOP:
2756 str = "armor shop";
2757 break;
2758 case SCROLLSHOP:
2759 str = "scroll shop";
2760 break;
2761 case POTIONSHOP:
2762 str = "potion shop";
2763 break;
2764 case WEAPONSHOP:
2765 str = "weapon shop";
2766 break;
2767 case FOODSHOP:
2768 str = "delicatessen";
2769 break;
2770 case RINGSHOP:
2771 str = "jewelers";
2772 break;
2773 case WANDSHOP:
2774 str = "wand shop";
2775 break;
2776 case BOOKSHOP:
2777 str = "bookstore";
2778 break;
2779 case FODDERSHOP:
2780 str = "health food store";
2781 break;
2782 case CANDLESHOP:
2783 str = "lighting shop";
2784 break;
2785 default:
2786 break;
2788 return str;
2791 /* if player knows about the mastermind tune, append it to Castle annotation;
2792 if drawbridge has been destroyed, flags.castletune will be zero */
2793 STATIC_OVL char *
2794 tunesuffix(mptr, outbuf)
2795 mapseen *mptr;
2796 char *outbuf;
2798 *outbuf = '\0';
2799 if (mptr->flags.castletune && u.uevent.uheard_tune) {
2800 char tmp[BUFSZ];
2802 if (u.uevent.uheard_tune == 2)
2803 Sprintf(tmp, "notes \"%s\"", tune);
2804 else
2805 Strcpy(tmp, "5-note tune");
2806 Sprintf(outbuf, " (play %s to open or close drawbridge)", tmp);
2808 return outbuf;
2811 /* some utility macros for print_mapseen */
2812 #define TAB " " /* three spaces */
2813 #if 0
2814 #define BULLET "" /* empty; otherwise output becomes cluttered */
2815 #define PREFIX TAB TAB BULLET
2816 #else /*!0*/
2817 /* K&R: don't require support for concatenation of adjacent string literals */
2818 #define PREFIX " " /* two TABs + empty BULLET: six spaces */
2819 #endif
2820 #define COMMA (i++ > 0 ? ", " : PREFIX)
2821 /* "iterate" once; safe to use as ``if (cond) ADDTOBUF(); else whatever;'' */
2822 #define ADDNTOBUF(nam, var) \
2823 do { \
2824 if (var) \
2825 Sprintf(eos(buf), "%s%s %s%s", COMMA, seen_string((var), (nam)), \
2826 (nam), plur(var)); \
2827 } while (0)
2828 #define ADDTOBUF(nam, var) \
2829 do { \
2830 if (var) \
2831 Sprintf(eos(buf), "%s%s", COMMA, (nam)); \
2832 } while (0)
2834 STATIC_OVL void
2835 print_mapseen(win, mptr, final, how, printdun)
2836 winid win;
2837 mapseen *mptr;
2838 int final; /* 0: not final; 1: game over, alive; 2: game over, dead */
2839 int how; /* cause of death; only used if final==2 and mptr->lev==u.uz */
2840 boolean printdun;
2842 char buf[BUFSZ], tmpbuf[BUFSZ];
2843 int i, depthstart, dnum;
2844 boolean died_here = (final == 2 && on_level(&u.uz, &mptr->lev));
2846 /* Damnable special cases */
2847 /* The quest and knox should appear to be level 1 to match
2848 * other text.
2850 dnum = mptr->lev.dnum;
2851 if (dnum == quest_dnum || dnum == knox_level.dnum)
2852 depthstart = 1;
2853 else
2854 depthstart = dungeons[dnum].depth_start;
2856 if (printdun) {
2857 if (dungeons[dnum].dunlev_ureached == dungeons[dnum].entry_lev
2858 /* suppress the negative numbers in the endgame */
2859 || In_endgame(&mptr->lev))
2860 Sprintf(buf, "%s:", dungeons[dnum].dname);
2861 else if (builds_up(&mptr->lev))
2862 Sprintf(buf, "%s: levels %d up to %d",
2863 dungeons[dnum].dname,
2864 depthstart + dungeons[dnum].entry_lev - 1,
2865 depthstart + dungeons[dnum].dunlev_ureached - 1);
2866 else
2867 Sprintf(buf, "%s: levels %d to %d",
2868 dungeons[dnum].dname, depthstart,
2869 depthstart + dungeons[dnum].dunlev_ureached - 1);
2870 putstr(win, !final ? ATR_INVERSE : 0, buf);
2873 /* calculate level number */
2874 i = depthstart + mptr->lev.dlevel - 1;
2875 if (In_endgame(&mptr->lev))
2876 Sprintf(buf, "%s%s:", TAB, endgamelevelname(tmpbuf, i));
2877 else
2878 Sprintf(buf, "%sLevel %d:", TAB, i);
2880 /* wizmode prints out proto dungeon names for clarity */
2881 if (wizard) {
2882 s_level *slev;
2884 if ((slev = Is_special(&mptr->lev)) != 0)
2885 Sprintf(eos(buf), " [%s]", slev->proto);
2887 /* [perhaps print custom annotation on its own line when it's long] */
2888 if (mptr->custom)
2889 Sprintf(eos(buf), " \"%s\"", mptr->custom);
2890 if (on_level(&u.uz, &mptr->lev))
2891 Sprintf(eos(buf), " <- You %s here.",
2892 (!final || (final == 1 && how == ASCENDED)) ? "are"
2893 : (final == 1 && how == ESCAPED) ? "left from"
2894 : "were");
2895 putstr(win, !final ? ATR_BOLD : 0, buf);
2897 if (mptr->flags.forgot)
2898 return;
2900 if (INTEREST(mptr->feat)) {
2901 buf[0] = 0;
2903 i = 0; /* interest counter */
2904 /* List interests in an order vaguely corresponding to
2905 * how important they are.
2907 if (mptr->feat.nshop > 0) {
2908 if (mptr->feat.nshop > 1)
2909 ADDNTOBUF("shop", mptr->feat.nshop);
2910 else
2911 Sprintf(eos(buf), "%s%s", COMMA,
2912 an(shop_string(mptr->feat.shoptype)));
2914 if (mptr->feat.naltar > 0) {
2915 /* Temples + non-temple altars get munged into just "altars" */
2916 if (mptr->feat.ntemple != mptr->feat.naltar)
2917 ADDNTOBUF("altar", mptr->feat.naltar);
2918 else
2919 ADDNTOBUF("temple", mptr->feat.ntemple);
2921 /* only print out altar's god if they are all to your god */
2922 if (Amask2align(Msa2amask(mptr->feat.msalign)) == u.ualign.type)
2923 Sprintf(eos(buf), " to %s", align_gname(u.ualign.type));
2925 ADDNTOBUF("throne", mptr->feat.nthrone);
2926 ADDNTOBUF("fountain", mptr->feat.nfount);
2927 ADDNTOBUF("sink", mptr->feat.nsink);
2928 ADDNTOBUF("grave", mptr->feat.ngrave);
2929 ADDNTOBUF("tree", mptr->feat.ntree);
2930 #if 0
2931 ADDTOBUF("water", mptr->feat.water);
2932 ADDTOBUF("lava", mptr->feat.lava);
2933 ADDTOBUF("ice", mptr->feat.ice);
2934 #endif
2935 /* capitalize afterwards */
2936 i = strlen(PREFIX);
2937 buf[i] = highc(buf[i]);
2938 /* capitalizing it makes it a sentence; terminate with '.' */
2939 Strcat(buf, ".");
2940 putstr(win, 0, buf);
2943 /* we assume that these are mutually exclusive */
2944 *buf = '\0';
2945 if (mptr->flags.oracle) {
2946 Sprintf(buf, "%sOracle of Delphi.", PREFIX);
2947 } else if (In_sokoban(&mptr->lev)) {
2948 Sprintf(buf, "%s%s.", PREFIX,
2949 mptr->flags.sokosolved ? "Solved" : "Unsolved");
2950 } else if (mptr->flags.bigroom) {
2951 Sprintf(buf, "%sA very big room.", PREFIX);
2952 } else if (mptr->flags.roguelevel) {
2953 Sprintf(buf, "%sA primitive area.", PREFIX);
2954 } else if (mptr->flags.quest_summons) {
2955 Sprintf(buf, "%sSummoned by %s.", PREFIX, ldrname());
2956 } else if (on_level(&mptr->lev, &qstart_level)) {
2957 Sprintf(buf, "%sHome%s.", PREFIX,
2958 mptr->flags.unreachable ? " (no way back...)" : "");
2959 if (u.uevent.qcompleted)
2960 Sprintf(buf, "%sCompleted quest for %s.", PREFIX, ldrname());
2961 else if (mptr->flags.questing)
2962 Sprintf(buf, "%sGiven quest by %s.", PREFIX, ldrname());
2963 } else if (mptr->flags.ludios) {
2964 /* presence of the ludios branch in #overview output indicates that
2965 the player has made it onto the level; presence of this annotation
2966 indicates that the fort's entrance has been seen (or mapped) */
2967 Sprintf(buf, "%sFort Ludios.", PREFIX);
2968 } else if (mptr->flags.castle) {
2969 Sprintf(buf, "%sThe castle%s.", PREFIX, tunesuffix(mptr, tmpbuf));
2970 } else if (mptr->flags.valley) {
2971 Sprintf(buf, "%sValley of the Dead.", PREFIX);
2972 } else if (mptr->flags.msanctum) {
2973 Sprintf(buf, "%sMoloch's Sanctum.", PREFIX);
2975 if (*buf)
2976 putstr(win, 0, buf);
2978 /* print out branches */
2979 if (mptr->br) {
2980 Sprintf(buf, "%s%s to %s", PREFIX, br_string2(mptr->br),
2981 dungeons[mptr->br->end2.dnum].dname);
2983 /* Since mapseen objects are printed out in increasing order
2984 * of dlevel, clarify which level this branch is going to
2985 * if the branch goes upwards. Unless it's the end game.
2987 if (mptr->br->end1_up && !In_endgame(&(mptr->br->end2)))
2988 Sprintf(eos(buf), ", level %d", depth(&(mptr->br->end2)));
2989 Strcat(buf, ".");
2990 putstr(win, 0, buf);
2993 /* maybe print out bones details */
2994 if (mptr->final_resting_place || final) {
2995 struct cemetery *bp;
2996 int kncnt = !died_here ? 0 : 1;
2998 for (bp = mptr->final_resting_place; bp; bp = bp->next)
2999 if (bp->bonesknown || wizard || final)
3000 ++kncnt;
3001 if (kncnt) {
3002 Sprintf(buf, "%s%s", PREFIX, "Final resting place for");
3003 putstr(win, 0, buf);
3004 if (died_here) {
3005 /* disclosure occurs before bones creation, so listing dead
3006 hero here doesn't give away whether bones are produced */
3007 formatkiller(tmpbuf, sizeof tmpbuf, how, TRUE);
3008 /* rephrase a few death reasons to work with "you" */
3009 (void) strsubst(tmpbuf, " himself", " yourself");
3010 (void) strsubst(tmpbuf, " herself", " yourself");
3011 (void) strsubst(tmpbuf, " his ", " your ");
3012 (void) strsubst(tmpbuf, " her ", " your ");
3013 Sprintf(buf, "%s%syou, %s%c", PREFIX, TAB, tmpbuf,
3014 --kncnt ? ',' : '.');
3015 putstr(win, 0, buf);
3017 for (bp = mptr->final_resting_place; bp; bp = bp->next) {
3018 if (bp->bonesknown || wizard || final) {
3019 Sprintf(buf, "%s%s%s, %s%c", PREFIX, TAB, bp->who,
3020 bp->how, --kncnt ? ',' : '.');
3021 putstr(win, 0, buf);
3028 /*dungeon.c*/