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