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