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