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