1 /* SCCS Id: @(#)dungeon.c 3.4 1999/10/30 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #include "hack.h"
6 #include "dgn_file.h"
7 #include "dlb.h"
8 #include "display.h"
9
10 #ifdef OVL1
11
12 #define DUNGEON_FILE "dungeon"
13
14 #define X_START "x-strt"
15 #define X_LOCATE "x-loca"
16 #define X_GOAL "x-goal"
17
18 struct proto_dungeon {
19 struct tmpdungeon tmpdungeon[MAXDUNGEON];
20 struct tmplevel tmplevel[LEV_LIMIT];
21 s_level *final_lev[LEV_LIMIT]; /* corresponding level pointers */
22 struct tmpbranch tmpbranch[BRANCH_LIMIT];
23
24 int start; /* starting index of current dungeon sp levels */
25 int n_levs; /* number of tmplevel entries */
26 int n_brs; /* number of tmpbranch entries */
27 };
28
29 int n_dgns; /* number of dungeons (used here, */
30 /* and mklev.c) */
31 static branch *branches = (branch *) 0; /* dungeon branch list */
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,struct proto_dungeon *,int *));
46 STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *));
47 STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *));
48 STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *));
49 STATIC_DCL void FDECL(add_level, (s_level *));
50 STATIC_DCL void FDECL(init_level, (int,int,struct proto_dungeon *));
51 STATIC_DCL int FDECL(possible_places, (int, boolean *, struct proto_dungeon *));
52 STATIC_DCL xchar FDECL(pick_level, (boolean *, int));
53 STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *));
54 #ifdef WIZARD
55 STATIC_DCL const char *FDECL(br_string, (int));
56 STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P, struct lchoice *));
57 #endif
58 #ifdef RANDOMIZED_PLANES
59 STATIC_DCL void NDECL(shuffle_planes);
60 #endif
61
62 mapseen *mapseenchn = (struct mapseen *)0;
63 /*STATIC_DCL void FDECL(free_mapseen, (mapseen *));*/
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 void FDECL(print_mapseen, (winid,mapseen *,boolean));
68 STATIC_DCL boolean FDECL(interest_mapseen, (mapseen *));
69 STATIC_DCL char *FDECL(seen_string, (xchar x, const char *));
70 STATIC_DCL const char *FDECL(br_string2, (branch *));
71
72 #ifdef DEBUG
73 #define DD dungeons[i]
74 STATIC_DCL void NDECL(dumpit);
75
76 STATIC_OVL void
dumpit()77 dumpit()
78 {
79 int i;
80 s_level *x;
81 branch *br;
82
83 for(i = 0; i < n_dgns; i++) {
84 fprintf(stderr, "\n#%d \"%s\" (%s):\n", i,
85 DD.dname, DD.proto);
86 fprintf(stderr, " num_dunlevs %d, dunlev_ureached %d\n",
87 DD.num_dunlevs, DD.dunlev_ureached);
88 fprintf(stderr, " depth_start %d, ledger_start %d\n",
89 DD.depth_start, DD.ledger_start);
90 fprintf(stderr, " flags:%s%s%s\n",
91 DD.flags.rogue_like ? " rogue_like" : "",
92 DD.flags.maze_like ? " maze_like" : "",
93 DD.flags.hellish ? " hellish" : "");
94 getchar();
95 }
96 fprintf(stderr,"\nSpecial levels:\n");
97 for(x = sp_levchn; x; x = x->next) {
98 fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs);
99 fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel);
100 fprintf(stderr, "flags:%s%s%s%s\n",
101 x->flags.rogue_like ? " rogue_like" : "",
102 x->flags.maze_like ? " maze_like" : "",
103 x->flags.hellish ? " hellish" : "",
104 x->flags.town ? " town" : "");
105 getchar();
106 }
107 fprintf(stderr,"\nBranches:\n");
108 for (br = branches; br; br = br->next) {
109 fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n",
110 br->id,
111 br->type == BR_STAIR ? "stair" :
112 br->type == BR_NO_END1 ? "no end1" :
113 br->type == BR_NO_END2 ? "no end2" :
114 br->type == BR_PORTAL ? "portal" :
115 "unknown",
116 br->end1.dnum, br->end1.dlevel,
117 br->end2.dnum, br->end2.dlevel,
118 br->end1_up ? "end1 up" : "end1 down");
119 }
120 getchar();
121 fprintf(stderr,"\nDone\n");
122 getchar();
123 }
124 #endif
125
126 /* Save the dungeon structures. */
127 void
save_dungeon(fd,perform_write,free_data)128 save_dungeon(fd, perform_write, free_data)
129 int fd;
130 boolean perform_write, free_data;
131 {
132 branch *curr, *next;
133 mapseen *curr_ms, *next_ms;
134 int count;
135
136 if (perform_write) {
137 bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns);
138 bwrite(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns);
139 bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
140 bwrite(fd, (genericptr_t) tune, sizeof tune);
141
142 for (count = 0, curr = branches; curr; curr = curr->next)
143 count++;
144 bwrite(fd, (genericptr_t) &count, sizeof(count));
145
146 for (curr = branches; curr; curr = curr->next)
147 bwrite(fd, (genericptr_t) curr, sizeof (branch));
148
149 count = maxledgerno();
150 bwrite(fd, (genericptr_t) &count, sizeof count);
151 bwrite(fd, (genericptr_t) level_info,
152 (unsigned)count * sizeof (struct linfo));
153 bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
154
155 for (count = 0, curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next)
156 count++;
157 bwrite(fd, (genericptr_t) &count, sizeof(count));
158
159 for (curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next)
160 save_mapseen(fd, curr_ms);
161 }
162
163 if (free_data) {
164 for (curr = branches; curr; curr = next) {
165 next = curr->next;
166 free((genericptr_t) curr);
167 }
168 branches = 0;
169 for (curr_ms = mapseenchn; curr_ms; curr_ms = next_ms) {
170 next_ms = curr_ms->next;
171 if (curr_ms->custom)
172 free((genericptr_t)curr_ms->custom);
173 free((genericptr_t) curr_ms);
174 }
175 mapseenchn = 0;
176 }
177 }
178
179 /* Restore the dungeon structures. */
180 void
restore_dungeon(fd)181 restore_dungeon(fd)
182 int fd;
183 {
184 branch *curr, *last;
185 mapseen *curr_ms, *last_ms;
186 int count, i;
187
188 mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns));
189 mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns);
190 mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
191 mread(fd, (genericptr_t) tune, sizeof tune);
192
193 last = branches = (branch *) 0;
194
195 mread(fd, (genericptr_t) &count, sizeof(count));
196 for (i = 0; i < count; i++) {
197 curr = (branch *) alloc(sizeof(branch));
198 mread(fd, (genericptr_t) curr, sizeof(branch));
199 curr->next = (branch *) 0;
200 if (last)
201 last->next = curr;
202 else
203 branches = curr;
204 last = curr;
205 }
206
207 mread(fd, (genericptr_t) &count, sizeof(count));
208 if (count >= MAXLINFO)
209 panic("level information count larger (%d) than allocated size", count);
210 mread(fd, (genericptr_t) level_info, (unsigned)count*sizeof(struct linfo));
211 mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
212
213 mread(fd, (genericptr_t) &count, sizeof(count));
214 last_ms = (mapseen *) 0;
215 for (i = 0; i < count; i++) {
216 curr_ms = load_mapseen(fd);
217 curr_ms->next = (mapseen *) 0;
218 if (last_ms)
219 last_ms->next = curr_ms;
220 else
221 mapseenchn = curr_ms;
222 last_ms = curr_ms;
223 }
224 }
225
226 static void
Fread(ptr,size,nitems,stream)227 Fread(ptr, size, nitems, stream)
228 genericptr_t ptr;
229 int size, nitems;
230 dlb *stream;
231 {
232 int cnt;
233
234 if((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
235 panic(
236 "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.",
237 (size * nitems), (size * cnt));
238 terminate(EXIT_FAILURE);
239 }
240 }
241
242 STATIC_OVL xchar
dname_to_dnum(s)243 dname_to_dnum(s)
244 const char *s;
245 {
246 xchar i;
247
248 for (i = 0; i < n_dgns; i++)
249 if (!strcmp(dungeons[i].dname, s)) return i;
250
251 panic("Couldn't resolve dungeon number for name \"%s\".", s);
252 /*NOT REACHED*/
253 return (xchar)0;
254 }
255
256 s_level *
find_level(s)257 find_level(s)
258 const char *s;
259 {
260 s_level *curr;
261 for(curr = sp_levchn; curr; curr = curr->next)
262 if (!strcmpi(s, curr->proto)) break;
263 return curr;
264 }
265
266 #ifdef RANDOMIZED_PLANES
267 /**
268 * Returns the next plane to go to.
269 *
270 * Returns NULL if on Astral Plane or not in endgame.
271 */
272 s_level *
get_next_elemental_plane(lev)273 get_next_elemental_plane(lev)
274 d_level *lev;
275 {
276 if (!In_endgame(lev)) {
277 pline("get_next_elemental_plane not in Endgame.");
278 return (s_level *)0;
279 }
280
281 s_level *curr = find_level("astral"),
282 *plane = (s_level *)0;
283 for (curr = sp_levchn; curr; curr = curr->next) {
284 if (on_level(lev, &(curr->dlevel))) {
285 return plane;
286 }
287 plane = curr;
288 }
289 return (s_level *)0;
290 }
291
292 /**
293 * Returns the first elemental plane of the endgame.
294 */
295 d_level *
get_first_elemental_plane()296 get_first_elemental_plane()
297 {
298 s_level *curr,
299 *dummy = find_level("dummy");
300 for (curr = find_level("astral"); curr; curr = curr->next) {
301 if (curr->next == dummy) {
302 return &curr->dlevel;
303 }
304 }
305 return (d_level *)0;
306 }
307 #endif
308
309 /* Find the branch that links the named dungeon. */
310 STATIC_OVL int
find_branch(s,pd)311 find_branch(s, pd)
312 const char *s; /* dungeon name */
313 struct proto_dungeon *pd;
314 {
315 int i;
316
317 if (pd) {
318 for (i = 0; i < pd->n_brs; i++)
319 if (!strcmp(pd->tmpbranch[i].name, s)) break;
320 if (i == pd->n_brs) panic("find_branch: can't find %s", s);
321 } else {
322 /* support for level tport by name */
323 branch *br;
324 const char *dnam;
325
326 for (br = branches; br; br = br->next) {
327 dnam = dungeons[br->end2.dnum].dname;
328 if (!strcmpi(dnam, s) ||
329 (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s)))
330 break;
331 }
332 i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1;
333 }
334 return i;
335 }
336
337
338 /*
339 * Find the "parent" by searching the prototype branch list for the branch
340 * listing, then figuring out to which dungeon it belongs.
341 */
342 STATIC_OVL xchar
parent_dnum(s,pd)343 parent_dnum(s, pd)
344 const char *s; /* dungeon name */
345 struct proto_dungeon *pd;
346 {
347 int i;
348 xchar pdnum;
349
350 i = find_branch(s, pd);
351 /*
352 * Got branch, now find parent dungeon. Stop if we have reached
353 * "this" dungeon (if we haven't found it by now it is an error).
354 */
355 for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++)
356 if ((i -= pd->tmpdungeon[pdnum].branches) < 0)
357 return(pdnum);
358
359 panic("parent_dnum: couldn't resolve branch.");
360 /*NOT REACHED*/
361 return (xchar)0;
362 }
363
364 /*
365 * Return a starting point and number of successive positions a level
366 * or dungeon entrance can occupy.
367 *
368 * Note: This follows the acouple (instead of the rcouple) rules for a
369 * negative random component (rand < 0). These rules are found
370 * in dgn_comp.y. The acouple [absolute couple] section says that
371 * a negative random component means from the (adjusted) base to the
372 * end of the dungeon.
373 */
374 STATIC_OVL int
level_range(dgn,base,rand,chain,pd,adjusted_base)375 level_range(dgn, base, rand, chain, pd, adjusted_base)
376 xchar dgn;
377 int base, rand, chain;
378 struct proto_dungeon *pd;
379 int *adjusted_base;
380 {
381 int lmax = dungeons[dgn].num_dunlevs;
382
383 if (chain >= 0) { /* relative to a special level */
384 s_level *levtmp = pd->final_lev[chain];
385 if (!levtmp) panic("level_range: empty chain level!");
386
387 base += levtmp->dlevel.dlevel;
388 } else { /* absolute in the dungeon */
389 /* from end of dungeon */
390 if (base < 0) base = (lmax + base + 1);
391 }
392
393 if (base < 1 || base > lmax)
394 panic("level_range: base value out of range. base: %d, lmax; %d",base,lmax);
395
396 *adjusted_base = base;
397
398 if (rand == -1) { /* from base to end of dungeon */
399 return (lmax - base + 1);
400 } else if (rand) {
401 /* make sure we don't run off the end of the dungeon */
402 return (((base + rand - 1) > lmax) ? lmax-base+1 : rand);
403 } /* else only one choice */
404 return 1;
405 }
406
407 STATIC_OVL xchar
parent_dlevel(s,pd)408 parent_dlevel(s, pd)
409 const char *s;
410 struct proto_dungeon *pd;
411 {
412 int i, j, num, base, dnum = parent_dnum(s, pd);
413 branch *curr;
414
415
416 i = find_branch(s, pd);
417 num = level_range(dnum, pd->tmpbranch[i].lev.base,
418 pd->tmpbranch[i].lev.rand,
419 pd->tmpbranch[i].chain,
420 pd, &base);
421
422 /* KMH -- Try our best to find a level without an existing branch */
423 i = j = rn2(num);
424 do {
425 if (++i >= num) i = 0;
426 for (curr = branches; curr; curr = curr->next)
427 if ((curr->end1.dnum == dnum && curr->end1.dlevel == base+i) ||
428 (curr->end2.dnum == dnum && curr->end2.dlevel == base+i))
429 break;
430 } while (curr && i != j);
431 return (base + i);
432 }
433
434 /* Convert from the temporary branch type to the dungeon branch type. */
435 STATIC_OVL int
correct_branch_type(tbr)436 correct_branch_type(tbr)
437 struct tmpbranch *tbr;
438 {
439 switch (tbr->type) {
440 case TBR_STAIR: return BR_STAIR;
441 case TBR_NO_UP: return tbr->up ? BR_NO_END1 : BR_NO_END2;
442 case TBR_NO_DOWN: return tbr->up ? BR_NO_END2 : BR_NO_END1;
443 case TBR_PORTAL: return BR_PORTAL;
444 }
445 impossible("correct_branch_type: unknown branch type");
446 return BR_STAIR;
447 }
448
449 /*
450 * Add the given branch to the branch list. The branch list is ordered
451 * by end1 dungeon and level followed by end2 dungeon and level. If
452 * extract_first is true, then the branch is already part of the list
453 * but needs to be repositioned.
454 */
455 void
insert_branch(new_branch,extract_first)456 insert_branch(new_branch, extract_first)
457 branch *new_branch;
458 boolean extract_first;
459 {
460 branch *curr, *prev;
461 long new_val, curr_val, prev_val;
462
463 if (extract_first) {
464 for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next)
465 if (curr == new_branch) break;
466
467 if (!curr) panic("insert_branch: not found");
468 if (prev)
469 prev->next = curr->next;
470 else
471 branches = curr->next;
472 }
473 new_branch->next = (branch *) 0;
474
475 /* Convert the branch into a unique number so we can sort them. */
476 #define branch_val(bp) \
477 ((((long)(bp)->end1.dnum * (MAXLEVEL+1) + \
478 (long)(bp)->end1.dlevel) * (MAXDUNGEON+1) * (MAXLEVEL+1)) + \
479 ((long)(bp)->end2.dnum * (MAXLEVEL+1) + (long)(bp)->end2.dlevel))
480
481 /*
482 * Insert the new branch into the correct place in the branch list.
483 */
484 prev = (branch *) 0;
485 prev_val = -1;
486 new_val = branch_val(new_branch);
487 for (curr = branches; curr;
488 prev_val = curr_val, prev = curr, curr = curr->next) {
489 curr_val = branch_val(curr);
490 if (prev_val < new_val && new_val <= curr_val) break;
491 }
492 if (prev) {
493 new_branch->next = curr;
494 prev->next = new_branch;
495 } else {
496 new_branch->next = branches;
497 branches = new_branch;
498 }
499 }
500
501 /* Add a dungeon branch to the branch list. */
502 STATIC_OVL branch *
add_branch(dgn,child_entry_level,pd)503 add_branch(dgn, child_entry_level, pd)
504 int dgn;
505 int child_entry_level;
506 struct proto_dungeon *pd;
507 {
508 static int branch_id = 0;
509 int branch_num;
510 branch *new_branch;
511
512 branch_num = find_branch(dungeons[dgn].dname,pd);
513 new_branch = (branch *) alloc(sizeof(branch));
514 new_branch->next = (branch *) 0;
515 new_branch->id = branch_id++;
516 new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
517 new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd);
518 new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd);
519 new_branch->end2.dnum = dgn;
520 new_branch->end2.dlevel = child_entry_level;
521 new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE;
522
523 insert_branch(new_branch, FALSE);
524 return new_branch;
525 }
526
527 /*
528 * Add new level to special level chain. Insert it in level order with the
529 * other levels in this dungeon. This assumes that we are never given a
530 * level that has a dungeon number less than the dungeon number of the
531 * last entry.
532 */
533 STATIC_OVL void
add_level(new_lev)534 add_level(new_lev)
535 s_level *new_lev;
536 {
537 s_level *prev, *curr;
538
539 prev = (s_level *) 0;
540 for (curr = sp_levchn; curr; curr = curr->next) {
541 if (curr->dlevel.dnum == new_lev->dlevel.dnum &&
542 curr->dlevel.dlevel > new_lev->dlevel.dlevel)
543 break;
544 prev = curr;
545 }
546 if (!prev) {
547 new_lev->next = sp_levchn;
548 sp_levchn = new_lev;
549 } else {
550 new_lev->next = curr;
551 prev->next = new_lev;
552 }
553 }
554
555 STATIC_OVL void
init_level(dgn,proto_index,pd)556 init_level(dgn, proto_index, pd)
557 int dgn, proto_index;
558 struct proto_dungeon *pd;
559 {
560 s_level *new_level;
561 struct tmplevel *tlevel = &pd->tmplevel[proto_index];
562
563 pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
564 #ifdef WIZARD
565 if (!wizard)
566 #endif
567 if (tlevel->chance <= rn2(100)) return;
568
569 pd->final_lev[proto_index] = new_level =
570 (s_level *) alloc(sizeof(s_level));
571 /* load new level with data */
572 Strcpy(new_level->proto, tlevel->name);
573 new_level->boneid = tlevel->boneschar;
574 new_level->dlevel.dnum = dgn;
575 new_level->dlevel.dlevel = 0; /* for now */
576
577 new_level->flags.town = !!(tlevel->flags & TOWN);
578 new_level->flags.hellish = !!(tlevel->flags & HELLISH);
579 new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
580 new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
581 new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);
582 if (!new_level->flags.align)
583 new_level->flags.align =
584 ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4);
585
586 new_level->rndlevs = tlevel->rndlevs;
587 new_level->next = (s_level *) 0;
588 }
589
590 STATIC_OVL int
possible_places(idx,map,pd)591 possible_places(idx, map, pd)
592 int idx; /* prototype index */
593 boolean *map; /* array MAXLEVEL+1 in length */
594 struct proto_dungeon *pd;
595 {
596 int i, start, count;
597 s_level *lev = pd->final_lev[idx];
598
599 /* init level possibilities */
600 for (i = 0; i <= MAXLEVEL; i++) map[i] = FALSE;
601
602 /* get base and range and set those entried to true */
603 count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base,
604 pd->tmplevel[idx].lev.rand,
605 pd->tmplevel[idx].chain,
606 pd, &start);
607 for (i = start; i < start+count; i++)
608 map[i] = TRUE;
609
610 /* mark off already placed levels */
611 for (i = pd->start; i < idx; i++) {
612 if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) {
613 map[pd->final_lev[i]->dlevel.dlevel] = FALSE;
614 --count;
615 }
616 }
617
618 return count;
619 }
620
621 /* Pick the nth TRUE entry in the given boolean array. */
622 STATIC_OVL xchar
pick_level(map,nth)623 pick_level(map, nth)
624 boolean *map; /* an array MAXLEVEL+1 in size */
625 int nth;
626 {
627 int i;
628 for (i = 1; i <= MAXLEVEL; i++)
629 if (map[i] && !nth--) return (xchar) i;
630 panic("pick_level: ran out of valid levels");
631 return 0;
632 }
633
634 #ifdef DDEBUG
635 static void FDECL(indent,(int));
636
637 static void
indent(d)638 indent(d)
639 int d;
640 {
641 while (d-- > 0) fputs(" ", stderr);
642 }
643 #endif
644
645 /*
646 * Place a level. First, find the possible places on a dungeon map
647 * template. Next pick one. Then try to place the next level. If
648 * sucessful, we're done. Otherwise, try another (and another) until
649 * all possible places have been tried. If all possible places have
650 * been exausted, return false.
651 */
652 STATIC_OVL boolean
place_level(proto_index,pd)653 place_level(proto_index, pd)
654 int proto_index;
655 struct proto_dungeon *pd;
656 {
657 boolean map[MAXLEVEL+1]; /* valid levels are 1..MAXLEVEL inclusive */
658 s_level *lev;
659 int npossible;
660 #ifdef DDEBUG
661 int i;
662 #endif
663
664 if (proto_index == pd->n_levs) return TRUE; /* at end of proto levels */
665
666 lev = pd->final_lev[proto_index];
667
668 /* No level created for this prototype, goto next. */
669 if (!lev) return place_level(proto_index+1, pd);
670
671 npossible = possible_places(proto_index, map, pd);
672
673 for (; npossible; --npossible) {
674 lev->dlevel.dlevel = pick_level(map, rn2(npossible));
675 #ifdef DDEBUG
676 indent(proto_index-pd->start);
677 fprintf(stderr,"%s: trying %d [ ", lev->proto, lev->dlevel.dlevel);
678 for (i = 1; i <= MAXLEVEL; i++)
679 if (map[i]) fprintf(stderr,"%d ", i);
680 fprintf(stderr,"]\n");
681 #endif
682 if (place_level(proto_index+1, pd)) return TRUE;
683 map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */
684 }
685 #ifdef DDEBUG
686 indent(proto_index-pd->start);
687 fprintf(stderr,"%s: failed\n", lev->proto);
688 #endif
689 return FALSE;
690 }
691
692
693 struct level_map {
694 const char *lev_name;
695 d_level *lev_spec;
696 } level_map[] = {
697 { "air", &air_level },
698 { "asmodeus", &asmodeus_level },
699 { "astral", &astral_level },
700 { "baalz", &baalzebub_level },
701 { "bigroom", &bigroom_level },
702 { "castle", &stronghold_level },
703 { "earth", &earth_level },
704 { "fakewiz1", &portal_level },
705 { "fire", &fire_level },
706 { "juiblex", &juiblex_level },
707 { "knox", &knox_level },
708 #ifdef BLACKMARKET
709 { "blkmar", &blackmarket_level },
710 #endif /* BLACKMARKET */
711 { "medusa", &medusa_level },
712 { "oracle", &oracle_level },
713 { "orcus", &orcus_level },
714 #ifdef REINCARNATION
715 { "rogue", &rogue_level },
716 #endif
717 { "sanctum", &sanctum_level },
718 { "valley", &valley_level },
719 { "water", &water_level },
720 { "wizard1", &wiz1_level },
721 { "wizard2", &wiz2_level },
722 { "wizard3", &wiz3_level },
723 #ifdef RECORD_ACHIEVE
724 { "minend", &mineend_level },
725 { "soko1", &sokoend_level },
726 #endif
727 { X_START, &qstart_level },
728 { X_LOCATE, &qlocate_level },
729 { X_GOAL, &nemesis_level },
730 { "minetn", &minetown_level },
731 { "town", &town_level },
732 { "", (d_level *)0 }
733 };
734
735 void
init_dungeons()736 init_dungeons() /* initialize the "dungeon" structs */
737 {
738 dlb *dgn_file;
739 register int i, cl = 0, cb = 0;
740 register s_level *x;
741 struct proto_dungeon pd;
742 struct level_map *lev_map;
743 struct version_info vers_info;
744
745 pd.n_levs = pd.n_brs = 0;
746
747 dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
748 if (!dgn_file) {
749 char tbuf[BUFSZ];
750 Sprintf(tbuf, "Cannot open dungeon description - \"%s",
751 DUNGEON_FILE);
752 #ifdef DLBRSRC /* using a resource from the executable */
753 Strcat(tbuf, "\" resource!");
754 #else /* using a file or DLB file */
755 # if defined(DLB)
756 Strcat(tbuf, "\" from ");
757 # ifdef PREFIXES_IN_USE
758 Strcat(tbuf, "\n\"");
759 if (fqn_prefix[DATAPREFIX]) Strcat(tbuf, fqn_prefix[DATAPREFIX]);
760 # else
761 Strcat(tbuf, "\"");
762 # endif
763 Strcat(tbuf, DLBFILE);
764 # endif
765 Strcat(tbuf, "\" file!");
766 #endif
767 #ifdef WIN32
768 interject_assistance(1, INTERJECT_PANIC, (genericptr_t)tbuf,
769 (genericptr_t)fqn_prefix[DATAPREFIX]);
770 #endif
771 panic(tbuf);
772 }
773
774 /* validate the data's version against the program's version */
775 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file);
776 /* we'd better clear the screen now, since when error messages come from
777 * check_version() they will be printed using pline(), which doesn't
778 * mix with the raw messages that might be already on the screen
779 */
780 if (iflags.window_inited) clear_nhwindow(WIN_MAP);
781 if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
782 panic("Dungeon description not valid.");
783
784 /*
785 * Read in each dungeon and transfer the results to the internal
786 * dungeon arrays.
787 */
788 sp_levchn = (s_level *) 0;
789 Fread((genericptr_t)&n_dgns, sizeof(int), 1, dgn_file);
790 if (n_dgns >= MAXDUNGEON)
791 panic("init_dungeons: too many dungeons");
792
793 for (i = 0; i < n_dgns; i++) {
794 Fread((genericptr_t)&pd.tmpdungeon[i],
795 sizeof(struct tmpdungeon), 1, dgn_file);
796 #ifdef WIZARD
797 if(!wizard)
798 #endif
799 if(pd.tmpdungeon[i].chance && (pd.tmpdungeon[i].chance <= rn2(100))) {
800 int j;
801
802 /* skip over any levels or branches */
803 for(j = 0; j < pd.tmpdungeon[i].levels; j++)
804 Fread((genericptr_t)&pd.tmplevel[cl], sizeof(struct tmplevel),
805 1, dgn_file);
806
807 for(j = 0; j < pd.tmpdungeon[i].branches; j++)
808 Fread((genericptr_t)&pd.tmpbranch[cb],
809 sizeof(struct tmpbranch), 1, dgn_file);
810 n_dgns--; i--;
811 continue;
812 }
813
814 Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name);
815 Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname);
816 dungeons[i].boneid = pd.tmpdungeon[i].boneschar;
817
818 if(pd.tmpdungeon[i].lev.rand)
819 dungeons[i].num_dunlevs = (xchar)rn1(pd.tmpdungeon[i].lev.rand,
820 pd.tmpdungeon[i].lev.base);
821 else dungeons[i].num_dunlevs = (xchar)pd.tmpdungeon[i].lev.base;
822
823 if(!i) {
824 dungeons[i].ledger_start = 0;
825 dungeons[i].depth_start = 1;
826 dungeons[i].dunlev_ureached = 1;
827 } else {
828 dungeons[i].ledger_start = dungeons[i-1].ledger_start +
829 dungeons[i-1].num_dunlevs;
830 dungeons[i].dunlev_ureached = 0;
831 }
832
833 dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH);
834 dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE);
835 dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE);
836 dungeons[i].flags.align = ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4);
837 /*
838 * Set the entry level for this dungeon. The pd.tmpdungeon entry
839 * value means:
840 * < 0 from bottom (-1 == bottom level)
841 * 0 default (top)
842 * > 0 actual level (1 = top)
843 *
844 * Note that the entry_lev field in the dungeon structure is
845 * redundant. It is used only here and in print_dungeon().
846 */
847 if (pd.tmpdungeon[i].entry_lev < 0) {
848 dungeons[i].entry_lev = dungeons[i].num_dunlevs +
849 pd.tmpdungeon[i].entry_lev + 1;
850 if (dungeons[i].entry_lev <= 0) dungeons[i].entry_lev = 1;
851 } else if (pd.tmpdungeon[i].entry_lev > 0) {
852 dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
853 if (dungeons[i].entry_lev > dungeons[i].num_dunlevs)
854 dungeons[i].entry_lev = dungeons[i].num_dunlevs;
855 } else { /* default */
856 dungeons[i].entry_lev = 1; /* defaults to top level */
857 }
858
859 if (i) { /* set depth */
860 branch *br;
861 schar from_depth;
862 boolean from_up;
863
864 br = add_branch(i, dungeons[i].entry_lev, &pd);
865
866 /* Get the depth of the connecting end. */
867 if (br->end1.dnum == i) {
868 from_depth = depth(&br->end2);
869 from_up = !br->end1_up;
870 } else {
871 from_depth = depth(&br->end1);
872 from_up = br->end1_up;
873 }
874
875 /*
876 * Calculate the depth of the top of the dungeon via
877 * its branch. First, the depth of the entry point:
878 *
879 * depth of branch from "parent" dungeon
880 * + -1 or 1 depending on a up or down stair or
881 * 0 if portal
882 *
883 * Followed by the depth of the top of the dungeon:
884 *
885 * - (entry depth - 1)
886 *
887 * We'll say that portals stay on the same depth.
888 */
889 dungeons[i].depth_start = from_depth
890 + (br->type == BR_PORTAL ? 0 :
891 (from_up ? -1 : 1))
892 - (dungeons[i].entry_lev - 1);
893 }
894
895 /* this is redundant - it should have been flagged by dgn_comp */
896 if(dungeons[i].num_dunlevs > MAXLEVEL)
897 dungeons[i].num_dunlevs = MAXLEVEL;
898
899 pd.start = pd.n_levs; /* save starting point */
900 pd.n_levs += pd.tmpdungeon[i].levels;
901 if (pd.n_levs > LEV_LIMIT)
902 panic("init_dungeon: too many special levels");
903 /*
904 * Read in the prototype special levels. Don't add generated
905 * special levels until they are all placed.
906 */
907 for(; cl < pd.n_levs; cl++) {
908 Fread((genericptr_t)&pd.tmplevel[cl],
909 sizeof(struct tmplevel), 1, dgn_file);
910 init_level(i, cl, &pd);
911 }
912 /*
913 * Recursively place the generated levels for this dungeon. This
914 * routine will attempt all possible combinations before giving
915 * up.
916 */
917 if (!place_level(pd.start, &pd))
918 panic("init_dungeon: couldn't place levels");
919 #ifdef DDEBUG
920 fprintf(stderr, "--- end of dungeon %d ---\n", i);
921 fflush(stderr);
922 getchar();
923 #endif
924 for (; pd.start < pd.n_levs; pd.start++)
925 if (pd.final_lev[pd.start]) add_level(pd.final_lev[pd.start]);
926
927
928 pd.n_brs += pd.tmpdungeon[i].branches;
929 if (pd.n_brs > BRANCH_LIMIT)
930 panic("init_dungeon: too many branches");
931 for(; cb < pd.n_brs; cb++)
932 Fread((genericptr_t)&pd.tmpbranch[cb],
933 sizeof(struct tmpbranch), 1, dgn_file);
934 }
935 (void) dlb_fclose(dgn_file);
936
937 for (i = 0; i < 5; i++) tune[i] = 'A' + rn2(7);
938 tune[5] = 0;
939
940 /*
941 * Find most of the special levels and dungeons so we can access their
942 * locations quickly.
943 */
944 for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
945 x = find_level(lev_map->lev_name);
946 if (x) {
947 assign_level(lev_map->lev_spec, &x->dlevel);
948 if (!strncmp(lev_map->lev_name, "x-", 2)) {
949 /* This is where the name substitution on the
950 * levels of the quest dungeon occur.
951 */
952 Sprintf(x->proto, "%s%s", urole.filecode, &lev_map->lev_name[1]);
953 } else if (lev_map->lev_spec == &knox_level) {
954 branch *br;
955 /*
956 * Kludge to allow floating Knox entrance. We
957 * specify a floating entrance by the fact that
958 * its entrance (end1) has a bogus dnum, namely
959 * n_dgns.
960 */
961 for (br = branches; br; br = br->next)
962 if (on_level(&br->end2, &knox_level)) break;
963
964 if (br) br->end1.dnum = n_dgns;
965 /* adjust the branch's position on the list */
966 insert_branch(br, TRUE);
967 }
968 }
969 }
970 /*
971 * I hate hardwiring these names. :-(
972 */
973 quest_dnum = dname_to_dnum("The Quest");
974 sokoban_dnum = dname_to_dnum("Sokoban");
975 mines_dnum = dname_to_dnum("The Gnomish Mines");
976 tower_dnum = dname_to_dnum("Vlad's Tower");
977 mall_dnum = dname_to_dnum("Town");
978 /*
979 #ifdef BLACKMARKET
980 blackmarket_dnum = dname_to_dnum("The Black Market");
981 #endif
982 */
983
984 /* one special fixup for dummy surface level */
985 if ((x = find_level("dummy")) != 0) {
986 i = x->dlevel.dnum;
987 /* the code above puts earth one level above dungeon level #1,
988 making the dummy level overlay level 1; but the whole reason
989 for having the dummy level is to make earth have depth -1
990 instead of 0, so adjust the start point to shift endgame up */
991 if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start)
992 dungeons[i].depth_start -= 1;
993 /* TO DO: strip "dummy" out all the way here,
994 so that it's hidden from <ctrl/O> feedback. */
995 }
996
997 #ifdef RANDOMIZED_PLANES
998 shuffle_planes();
999 #endif
1000
1001 #ifdef DEBUG
1002 dumpit();
1003 #endif
1004 }
1005
1006 #ifdef RANDOMIZED_PLANES
1007 void
shuffle_planes()1008 shuffle_planes() /* randomizes order of elemental planes */
1009 {
1010 /* original order */
1011 s_level *dummy = find_level("dummy") ,
1012 *earth = find_level("earth") ,
1013 *air = find_level("air"),
1014 *fire = find_level("fire"),
1015 *water = find_level("water"),
1016 *astral = find_level("astral");
1017 s_level *array[] = { water, fire, air, earth };
1018 int j, pos;
1019 s_level *tmp;
1020
1021 /* Fisher-Yates shuffle aka Knuth shuffle */
1022 for(j = 3; j > 0; j--) {
1023 pos = rn2(j+1);
1024 tmp = array[pos]; array[pos] = array[j]; array[j] = tmp;
1025 }
1026
1027 /* reorder planes */
1028 astral->next = array[3];
1029 for(j = 3; j > 0; j--) {
1030 array[j]->next = array[j-1];
1031 }
1032 array[0]->next = dummy;
1033 }
1034 #endif
1035
1036 xchar
dunlev(lev)1037 dunlev(lev) /* return the level number for lev in *this* dungeon */
1038 d_level *lev;
1039 {
1040 return(lev->dlevel);
1041 }
1042
1043 xchar
dunlevs_in_dungeon(lev)1044 dunlevs_in_dungeon(lev) /* return the lowest level number for *this* dungeon*/
1045 d_level *lev;
1046 {
1047 return(dungeons[lev->dnum].num_dunlevs);
1048 }
1049
1050 xchar
deepest_lev_reached(noquest)1051 deepest_lev_reached(noquest) /* return the lowest level explored in the game*/
1052 boolean noquest;
1053 {
1054 /* this function is used for three purposes: to provide a factor
1055 * of difficulty in monster generation; to provide a factor of
1056 * difficulty in experience calculations (botl.c and end.c); and
1057 * to insert the deepest level reached in the game in the topten
1058 * display. the 'noquest' arg switch is required for the latter.
1059 *
1060 * from the player's point of view, going into the Quest is _not_
1061 * going deeper into the dungeon -- it is going back "home", where
1062 * the dungeon starts at level 1. given the setup in dungeon.def,
1063 * the depth of the Quest (thought of as starting at level 1) is
1064 * never lower than the level of entry into the Quest, so we exclude
1065 * the Quest from the topten "deepest level reached" display
1066 * calculation. _However_ the Quest is a difficult dungeon, so we
1067 * include it in the factor of difficulty calculations.
1068 */
1069 register int i;
1070 d_level tmp;
1071 register schar ret = 0;
1072
1073 for(i = 0; i < n_dgns; i++) {
1074 if((tmp.dlevel = dungeons[i].dunlev_ureached) == 0) continue;
1075 if(!strcmp(dungeons[i].dname, "The Quest") && noquest) continue;
1076
1077 tmp.dnum = i;
1078 if(depth(&tmp) > ret) ret = depth(&tmp);
1079 }
1080 return((xchar) ret);
1081 }
1082
1083 /* return a bookkeeping level number for purpose of comparisons and
1084 * save/restore */
1085 xchar
ledger_no(lev)1086 ledger_no(lev)
1087 d_level *lev;
1088 {
1089 return((xchar)(lev->dlevel + dungeons[lev->dnum].ledger_start));
1090 }
1091
1092 /*
1093 * The last level in the bookkeeping list of level is the bottom of the last
1094 * dungeon in the dungeons[] array.
1095 *
1096 * Maxledgerno() -- which is the max number of levels in the bookkeeping
1097 * list, should not be confused with dunlevs_in_dungeon(lev) -- which
1098 * returns the max number of levels in lev's dungeon, and both should
1099 * not be confused with deepest_lev_reached() -- which returns the lowest
1100 * depth visited by the player.
1101 */
1102 xchar
maxledgerno()1103 maxledgerno()
1104 {
1105 return (xchar) (dungeons[n_dgns-1].ledger_start +
1106 dungeons[n_dgns-1].num_dunlevs);
1107 }
1108
1109 /* return the dungeon that this ledgerno exists in */
1110 xchar
ledger_to_dnum(ledgerno)1111 ledger_to_dnum(ledgerno)
1112 xchar ledgerno;
1113 {
1114 register int i;
1115
1116 /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */
1117 for (i = 0; i < n_dgns; i++)
1118 if (dungeons[i].ledger_start < ledgerno &&
1119 ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs)
1120 return (xchar)i;
1121
1122 panic("level number out of range [ledger_to_dnum(%d)]", (int)ledgerno);
1123 /*NOT REACHED*/
1124 return (xchar)0;
1125 }
1126
1127 /* return the level of the dungeon this ledgerno exists in */
1128 xchar
ledger_to_dlev(ledgerno)1129 ledger_to_dlev(ledgerno)
1130 xchar ledgerno;
1131 {
1132 return((xchar)(ledgerno - dungeons[ledger_to_dnum(ledgerno)].ledger_start));
1133 }
1134
1135 #endif /* OVL1 */
1136 #ifdef OVL0
1137
1138 /* returns the depth of a level, in floors below the surface */
1139 /* (note levels in different dungeons can have the same depth). */
1140 schar
depth(lev)1141 depth(lev)
1142 d_level *lev;
1143 {
1144 return((schar)( dungeons[lev->dnum].depth_start + lev->dlevel - 1));
1145 }
1146
1147 boolean
on_level(lev1,lev2)1148 on_level(lev1, lev2) /* are "lev1" and "lev2" actually the same? */
1149 d_level *lev1, *lev2;
1150 {
1151 return((boolean)((lev1->dnum == lev2->dnum) && (lev1->dlevel == lev2->dlevel)));
1152 }
1153
1154 #endif /* OVL0 */
1155 #ifdef OVL1
1156
1157 /* is this level referenced in the special level chain? */
1158 s_level *
Is_special(lev)1159 Is_special(lev)
1160 d_level *lev;
1161 {
1162 s_level *levtmp;
1163
1164 for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
1165 if (on_level(lev, &levtmp->dlevel)) return(levtmp);
1166
1167 return((s_level *)0);
1168 }
1169
1170 /*
1171 * Is this a multi-dungeon branch level? If so, return a pointer to the
1172 * branch. Otherwise, return null.
1173 */
1174 branch *
Is_branchlev(lev)1175 Is_branchlev(lev)
1176 d_level *lev;
1177 {
1178 branch *curr;
1179
1180 for (curr = branches; curr; curr = curr->next) {
1181 if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
1182 return curr;
1183 }
1184 return (branch *) 0;
1185 }
1186
1187 /* goto the next level (or appropriate dungeon) */
1188 void
next_level(at_stairs)1189 next_level(at_stairs)
1190 boolean at_stairs;
1191 {
1192 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1193 /* Taking a down dungeon branch. */
1194 goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1195 } else {
1196 /* Going down a stairs or jump in a trap door. */
1197 d_level newlevel;
1198
1199 newlevel.dnum = u.uz.dnum;
1200 newlevel.dlevel = u.uz.dlevel + 1;
1201 goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
1202 }
1203 }
1204
1205 /* goto the previous level (or appropriate dungeon) */
1206 void
prev_level(at_stairs)1207 prev_level(at_stairs)
1208 boolean at_stairs;
1209 {
1210 if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1211 /* Taking an up dungeon branch. */
1212 /* KMH -- Upwards branches are okay if not level 1 */
1213 /* (Just make sure it doesn't go above depth 1) */
1214 if(!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet) done(ESCAPED);
1215 else goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1216 } else {
1217 /* Going up a stairs or rising through the ceiling. */
1218 d_level newlevel;
1219 newlevel.dnum = u.uz.dnum;
1220 newlevel.dlevel = u.uz.dlevel - 1;
1221 goto_level(&newlevel, at_stairs, FALSE, FALSE);
1222 }
1223 }
1224
1225 void
u_on_newpos(x,y)1226 u_on_newpos(x, y)
1227 int x, y;
1228 {
1229 u.ux = x;
1230 u.uy = y;
1231 #ifdef CLIPPING
1232 cliparound(u.ux, u.uy);
1233 #endif
1234 #ifdef STEED
1235 /* ridden steed always shares hero's location */
1236 if (u.usteed) u.usteed->mx = u.ux, u.usteed->my = u.uy;
1237 #endif
1238 }
1239
1240 void
u_on_sstairs()1241 u_on_sstairs() { /* place you on the special staircase */
1242
1243 if (sstairs.sx) {
1244 u_on_newpos(sstairs.sx, sstairs.sy);
1245 } else {
1246 /* code stolen from goto_level */
1247 int trycnt = 0;
1248 xchar x, y;
1249 #ifdef DEBUG
1250 pline("u_on_sstairs: picking random spot");
1251 #endif
1252 #define badspot(x,y) ((levl[x][y].typ != ROOM && levl[x][y].typ != CORR) || MON_AT(x, y))
1253 do {
1254 x = rnd(COLNO-1);
1255 y = rn2(ROWNO);
1256 if (!badspot(x, y)) {
1257 u_on_newpos(x, y);
1258 return;
1259 }
1260 } while (++trycnt <= 500);
1261 panic("u_on_sstairs: could not relocate player!");
1262 #undef badspot
1263 }
1264 }
1265
1266 void
u_on_upstairs()1267 u_on_upstairs() /* place you on upstairs (or special equivalent) */
1268 {
1269 if (xupstair) {
1270 u_on_newpos(xupstair, yupstair);
1271 } else
1272 u_on_sstairs();
1273 }
1274
1275 void
u_on_dnstairs()1276 u_on_dnstairs() /* place you on dnstairs (or special equivalent) */
1277 {
1278 if (xdnstair) {
1279 u_on_newpos(xdnstair, ydnstair);
1280 } else
1281 u_on_sstairs();
1282 }
1283
1284 boolean
On_stairs(x,y)1285 On_stairs(x, y)
1286 xchar x, y;
1287 {
1288 return((boolean)((x == xupstair && y == yupstair) ||
1289 (x == xdnstair && y == ydnstair) ||
1290 (x == xdnladder && y == ydnladder) ||
1291 (x == xupladder && y == yupladder) ||
1292 (x == sstairs.sx && y == sstairs.sy)));
1293 }
1294
1295 boolean
Is_botlevel(lev)1296 Is_botlevel(lev)
1297 d_level *lev;
1298 {
1299 return((boolean)(lev->dlevel == dungeons[lev->dnum].num_dunlevs));
1300 }
1301
1302 boolean
Can_dig_down(lev)1303 Can_dig_down(lev)
1304 d_level *lev;
1305 {
1306 return((boolean)(!level.flags.hardfloor
1307 && !Is_botlevel(lev) && !Invocation_lev(lev)));
1308 }
1309
1310 /*
1311 * Like Can_dig_down (above), but also allows falling through on the
1312 * stronghold level. Normally, the bottom level of a dungeon resists
1313 * both digging and falling.
1314 */
1315 boolean
Can_fall_thru(lev)1316 Can_fall_thru(lev)
1317 d_level *lev;
1318 {
1319 return((boolean)(Can_dig_down(lev) || Is_stronghold(lev)));
1320 }
1321
1322 /*
1323 * True if one can rise up a level (e.g. cursed gain level).
1324 * This happens on intermediate dungeon levels or on any top dungeon
1325 * level that has a stairwell style branch to the next higher dungeon.
1326 * Checks for amulets and such must be done elsewhere.
1327 */
1328 boolean
Can_rise_up(x,y,lev)1329 Can_rise_up(x, y, lev)
1330 int x, y;
1331 d_level *lev;
1332 {
1333 /* can't rise up from inside the top of the Wizard's tower */
1334 /* KMH -- or in sokoban */
1335 if (In_endgame(lev) || In_sokoban(lev) ||
1336 (Is_wiz1_level(lev) && In_W_tower(x, y, lev)))
1337 return FALSE;
1338 return (boolean)(lev->dlevel > 1 ||
1339 (dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 &&
1340 sstairs.sx && sstairs.up));
1341 }
1342
1343 /*
1344 * It is expected that the second argument of get_level is a depth value,
1345 * either supplied by the user (teleport control) or randomly generated.
1346 * But more than one level can be at the same depth. If the target level
1347 * is "above" the present depth location, get_level must trace "up" from
1348 * the player's location (through the ancestors dungeons) the dungeon
1349 * within which the target level is located. With only one exception
1350 * which does not pass through this routine (see level_tele), teleporting
1351 * "down" is confined to the current dungeon. At present, level teleport
1352 * in dungeons that build up is confined within them.
1353 */
1354 void
get_level(newlevel,levnum)1355 get_level(newlevel, levnum)
1356 d_level *newlevel;
1357 int levnum;
1358 {
1359 branch *br;
1360 xchar dgn = u.uz.dnum;
1361
1362 if (levnum <= 0) {
1363 /* can only currently happen in endgame */
1364 levnum = u.uz.dlevel;
1365 } else if (levnum > dungeons[dgn].depth_start
1366 + dungeons[dgn].num_dunlevs - 1) {
1367 /* beyond end of dungeon, jump to last level */
1368 levnum = dungeons[dgn].num_dunlevs;
1369 } else {
1370 /* The desired level is in this dungeon or a "higher" one. */
1371
1372 /*
1373 * Branch up the tree until we reach a dungeon that contains the
1374 * levnum.
1375 */
1376 if (levnum < dungeons[dgn].depth_start) {
1377
1378 do {
1379 /*
1380 * Find the parent dungeon of this dungeon.
1381 *
1382 * This assumes that end2 is always the "child" and it is
1383 * unique.
1384 */
1385 for (br = branches; br; br = br->next)
1386 if (br->end2.dnum == dgn) break;
1387 if (!br)
1388 panic("get_level: can't find parent dungeon");
1389
1390 dgn = br->end1.dnum;
1391 } while (levnum < dungeons[dgn].depth_start);
1392 }
1393
1394 /* We're within the same dungeon; calculate the level. */
1395 levnum = levnum - dungeons[dgn].depth_start + 1;
1396 }
1397
1398 newlevel->dnum = dgn;
1399 newlevel->dlevel = levnum;
1400 }
1401
1402 #endif /* OVL1 */
1403 #ifdef OVL0
1404
1405 boolean
In_quest(lev)1406 In_quest(lev) /* are you in the quest dungeon? */
1407 d_level *lev;
1408 {
1409 return((boolean)(lev->dnum == quest_dnum));
1410 }
1411
1412 #endif /* OVL0 */
1413 #ifdef OVL1
1414
1415 boolean
In_mines(lev)1416 In_mines(lev) /* are you in the mines dungeon? */
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) break;
1442
1443 if (!br) panic("dgn_entrance: can't find entrance to %s", s);
1444
1445 return br;
1446 }
1447
1448 /*
1449 * This returns true if the hero is on the same level as the entrance to
1450 * the named dungeon.
1451 *
1452 * Called from do.c and mklev.c.
1453 *
1454 * Assumes that end1 is always the "parent".
1455 */
1456 boolean
at_dgn_entrance(s)1457 at_dgn_entrance(s)
1458 const char *s;
1459 {
1460 branch *br;
1461
1462 br = dungeon_branch(s);
1463 return((boolean)(on_level(&u.uz, &br->end1) ? TRUE : FALSE));
1464 }
1465
1466 boolean
In_V_tower(lev)1467 In_V_tower(lev) /* is `lev' part of Vlad's tower? */
1468 d_level *lev;
1469 {
1470 return((boolean)(lev->dnum == tower_dnum));
1471 }
1472
1473 boolean
On_W_tower_level(lev)1474 On_W_tower_level(lev) /* is `lev' a level containing the Wizard's tower? */
1475 d_level *lev;
1476 {
1477 return (boolean)(Is_wiz1_level(lev) ||
1478 Is_wiz2_level(lev) ||
1479 Is_wiz3_level(lev));
1480 }
1481
1482 boolean
In_W_tower(x,y,lev)1483 In_W_tower(x, y, lev) /* is <x,y> of `lev' inside the Wizard's tower? */
1484 int x, y;
1485 d_level *lev;
1486 {
1487 if (!On_W_tower_level(lev)) return FALSE;
1488 /*
1489 * Both of the exclusion regions for arriving via level teleport
1490 * (from above or below) define the tower's boundary.
1491 * assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} );
1492 */
1493 if (dndest.nlx > 0)
1494 return (boolean)within_bounded_area(x, y, dndest.nlx, dndest.nly,
1495 dndest.nhx, dndest.nhy);
1496 else
1497 impossible("No boundary for Wizard's Tower?");
1498 return FALSE;
1499 }
1500
1501 #endif /* OVL1 */
1502 #ifdef OVL0
1503
1504 boolean
In_hell(lev)1505 In_hell(lev) /* are you in one of the Hell levels? */
1506 d_level *lev;
1507 {
1508 return((boolean)(dungeons[lev->dnum].flags.hellish));
1509 }
1510
1511 #endif /* OVL0 */
1512 #ifdef OVL1
1513
1514 void
find_hell(lev)1515 find_hell(lev) /* sets *lev to be the gateway to Gehennom... */
1516 d_level *lev;
1517 {
1518 lev->dnum = valley_level.dnum;
1519 lev->dlevel = 1;
1520 }
1521
1522 void
goto_hell(at_stairs,falling)1523 goto_hell(at_stairs, falling) /* go directly to hell... */
1524 boolean at_stairs, falling;
1525 {
1526 d_level lev;
1527
1528 find_hell(&lev);
1529 goto_level(&lev, at_stairs, falling, FALSE);
1530 }
1531
1532 void
assign_level(dest,src)1533 assign_level(dest, src) /* equivalent to dest = source */
1534 d_level *dest, *src;
1535 {
1536 dest->dnum = src->dnum;
1537 dest->dlevel = src->dlevel;
1538 }
1539
1540 void
assign_rnd_level(dest,src,range)1541 assign_rnd_level(dest, src, range) /* dest = src + rn1(range) */
1542 d_level *dest, *src;
1543 int range;
1544 {
1545 dest->dnum = src->dnum;
1546 dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range)) ;
1547
1548 if(dest->dlevel > dunlevs_in_dungeon(dest))
1549 dest->dlevel = dunlevs_in_dungeon(dest);
1550 else if(dest->dlevel < 1)
1551 dest->dlevel = 1;
1552 }
1553
1554 #endif /* OVL1 */
1555 #ifdef OVL0
1556
1557 int
induced_align(pct)1558 induced_align(pct)
1559 int pct;
1560 {
1561 s_level *lev = Is_special(&u.uz);
1562 aligntyp al;
1563
1564 if (lev && lev->flags.align)
1565 if(rn2(100) < pct) return(lev->flags.align);
1566
1567 if(dungeons[u.uz.dnum].flags.align)
1568 if(rn2(100) < pct) return(dungeons[u.uz.dnum].flags.align);
1569
1570 al = rn2(3) - 1;
1571 return(Align2amask(al));
1572 }
1573
1574 #endif /* OVL0 */
1575 #ifdef OVL1
1576
1577 boolean
Invocation_lev(lev)1578 Invocation_lev(lev)
1579 d_level *lev;
1580 {
1581 return((boolean)(In_hell(lev) &&
1582 lev->dlevel == (dungeons[lev->dnum].num_dunlevs - 1)));
1583 }
1584
1585 /* use instead of depth() wherever a degree of difficulty is made
1586 * dependent on the location in the dungeon (eg. monster creation).
1587 */
1588 xchar
level_difficulty()1589 level_difficulty()
1590 {
1591 if (In_endgame(&u.uz))
1592 return((xchar)(depth(&sanctum_level) + u.ulevel/2));
1593 else
1594 if (u.uhave.amulet)
1595 return(deepest_lev_reached(FALSE));
1596 else
1597 return((xchar) depth(&u.uz));
1598 }
1599
1600 /* Take one word and try to match it to a level.
1601 * Recognized levels are as shown by print_dungeon().
1602 */
1603 schar
lev_by_name(nam)1604 lev_by_name(nam)
1605 const char *nam;
1606 {
1607 schar lev = 0;
1608 s_level *slev;
1609 d_level dlev;
1610 const char *p;
1611 int idx, idxtoo;
1612 char buf[BUFSZ];
1613
1614 /* allow strings like "the oracle level" to find "oracle" */
1615 if (!strncmpi(nam, "the ", 4)) nam += 4;
1616 if ((p = strstri(nam, " level")) != 0 && p == eos((char*)nam) - 6) {
1617 nam = strcpy(buf, nam);
1618 *(eos(buf) - 6) = '\0';
1619 }
1620 /* hell is the old name, and wouldn't match; gehennom would match its
1621 branch, yielding the castle level instead of the valley of the dead */
1622 if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) {
1623 if (In_V_tower(&u.uz)) nam = " to Vlad's tower"; /* branch to... */
1624 else nam = "valley";
1625 }
1626
1627 if ((slev = find_level(nam)) != 0) {
1628 dlev = slev->dlevel;
1629 idx = ledger_no(&dlev);
1630 if ((dlev.dnum == u.uz.dnum ||
1631 /* within same branch, or else main dungeon <-> gehennom */
1632 (u.uz.dnum == valley_level.dnum &&
1633 dlev.dnum == medusa_level.dnum) ||
1634 (u.uz.dnum == medusa_level.dnum &&
1635 dlev.dnum == valley_level.dnum)) &&
1636 ( /* either wizard mode or else seen and not forgotten */
1637 #ifdef WIZARD
1638 wizard ||
1639 #endif
1640 (level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED)) {
1641 lev = depth(&slev->dlevel);
1642 }
1643 } else { /* not a specific level; try branch names */
1644 idx = find_branch(nam, (struct proto_dungeon *)0);
1645 /* "<branch> to Xyzzy" */
1646 if (idx < 0 && (p = strstri(nam, " to ")) != 0)
1647 idx = find_branch(p + 4, (struct proto_dungeon *)0);
1648
1649 if (idx >= 0) {
1650 idxtoo = (idx >> 8) & 0x00FF;
1651 idx &= 0x00FF;
1652 if ( /* either wizard mode, or else _both_ sides of branch seen */
1653 #ifdef WIZARD
1654 wizard ||
1655 #endif
1656 ((level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED &&
1657 (level_info[idxtoo].flags & (FORGOTTEN|VISITED)) == VISITED)) {
1658 if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo;
1659 dlev.dnum = ledger_to_dnum(idx);
1660 dlev.dlevel = ledger_to_dlev(idx);
1661 lev = depth(&dlev);
1662 }
1663 }
1664 }
1665 return lev;
1666 }
1667
1668 #ifdef WIZARD
1669
1670 /* Convert a branch type to a string usable by print_dungeon(). */
1671 STATIC_OVL const char *
br_string(type)1672 br_string(type)
1673 int type;
1674 {
1675 switch (type) {
1676 case BR_PORTAL: return "Portal";
1677 case BR_NO_END1: return "Connection";
1678 case BR_NO_END2: return "One way stair";
1679 case BR_STAIR: return "Stair";
1680 }
1681 return " (unknown)";
1682 }
1683
1684 /* Print all child branches between the lower and upper bounds. */
1685 STATIC_OVL void
print_branch(win,dnum,lower_bound,upper_bound,bymenu,lchoices)1686 print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices)
1687 winid win;
1688 int dnum;
1689 int lower_bound;
1690 int upper_bound;
1691 boolean bymenu;
1692 struct lchoice *lchoices;
1693 {
1694 branch *br;
1695 char buf[BUFSZ];
1696 anything any;
1697
1698 /* This assumes that end1 is the "parent". */
1699 for (br = branches; br; br = br->next) {
1700 if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel &&
1701 br->end1.dlevel <= upper_bound) {
1702 Sprintf(buf," %s to %s: %d",
1703 br_string(br->type),
1704 dungeons[br->end2.dnum].dname,
1705 depth(&br->end1));
1706 if (bymenu) {
1707 lchoices->lev[lchoices->idx] = br->end1.dlevel;
1708 lchoices->dgn[lchoices->idx] = br->end1.dnum;
1709 lchoices->playerlev[lchoices->idx] = depth(&br->end1);
1710 any.a_void = 0;
1711 any.a_int = lchoices->idx + 1;
1712 add_menu(win, NO_GLYPH, &any, lchoices->menuletter,
1713 0, ATR_NONE, buf, MENU_UNSELECTED);
1714 if (lchoices->menuletter == 'z') lchoices->menuletter = 'A';
1715 else lchoices->menuletter++;
1716 lchoices->idx++;
1717 } else
1718 putstr(win, 0, buf);
1719 }
1720 }
1721 }
1722
1723 /* Print available dungeon information. */
1724 schar
print_dungeon(bymenu,rlev,rdgn)1725 print_dungeon(bymenu, rlev, rdgn)
1726 boolean bymenu;
1727 schar *rlev;
1728 xchar *rdgn;
1729 {
1730 int i, last_level, nlev;
1731 char buf[BUFSZ];
1732 boolean first;
1733 s_level *slev;
1734 dungeon *dptr;
1735 branch *br;
1736 anything any;
1737 struct lchoice lchoices;
1738
1739 winid win = create_nhwindow(NHW_MENU);
1740 if (bymenu) {
1741 start_menu(win);
1742 lchoices.idx = 0;
1743 lchoices.menuletter = 'a';
1744 }
1745
1746 for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
1747 nlev = dptr->num_dunlevs;
1748 if (nlev > 1)
1749 Sprintf(buf, "%s: levels %d to %d", dptr->dname, dptr->depth_start,
1750 dptr->depth_start + nlev - 1);
1751 else
1752 Sprintf(buf, "%s: level %d", dptr->dname, dptr->depth_start);
1753
1754 /* Most entrances are uninteresting. */
1755 if (dptr->entry_lev != 1) {
1756 if (dptr->entry_lev == nlev)
1757 Strcat(buf, ", entrance from below");
1758 else
1759 Sprintf(eos(buf), ", entrance on %d",
1760 dptr->depth_start + dptr->entry_lev - 1);
1761 }
1762 if (bymenu) {
1763 any.a_void = 0;
1764 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED);
1765 } else
1766 putstr(win, 0, buf);
1767
1768 /*
1769 * Circle through the special levels to find levels that are in
1770 * this dungeon.
1771 */
1772 for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
1773 if (slev->dlevel.dnum != i) continue;
1774
1775 /* print any branches before this level */
1776 print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu, &lchoices);
1777
1778 Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel));
1779 if (Is_stronghold(&slev->dlevel))
1780 Sprintf(eos(buf), " (tune %s)", tune);
1781 if (bymenu) {
1782 /* If other floating branches are added, this will need to change */
1783 if (i != knox_level.dnum) {
1784 lchoices.lev[lchoices.idx] = slev->dlevel.dlevel;
1785 lchoices.dgn[lchoices.idx] = i;
1786 } else {
1787 lchoices.lev[lchoices.idx] = depth(&slev->dlevel);
1788 lchoices.dgn[lchoices.idx] = 0;
1789 }
1790 lchoices.playerlev[lchoices.idx] = depth(&slev->dlevel);
1791 any.a_void = 0;
1792 any.a_int = lchoices.idx + 1;
1793 add_menu(win, NO_GLYPH, &any, lchoices.menuletter,
1794 0, ATR_NONE, buf, MENU_UNSELECTED);
1795 if (lchoices.menuletter == 'z') lchoices.menuletter = 'A';
1796 else lchoices.menuletter++;
1797 lchoices.idx++;
1798 } else
1799 putstr(win, 0, buf);
1800
1801 last_level = slev->dlevel.dlevel;
1802 }
1803 /* print branches after the last special level */
1804 print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices);
1805 }
1806
1807 /* Print out floating branches (if any). */
1808 for (first = TRUE, br = branches; br; br = br->next) {
1809 if (br->end1.dnum == n_dgns) {
1810 if (first) {
1811 if (!bymenu) {
1812 putstr(win, 0, "");
1813 putstr(win, 0, "Floating branches");
1814 }
1815 first = FALSE;
1816 }
1817 Sprintf(buf, " %s to %s",
1818 br_string(br->type), dungeons[br->end2.dnum].dname);
1819 if (!bymenu)
1820 putstr(win, 0, buf);
1821 }
1822 }
1823 if (bymenu) {
1824 int n;
1825 menu_item *selected;
1826 int idx;
1827
1828 end_menu(win, "Level teleport to where:");
1829 n = select_menu(win, PICK_ONE, &selected);
1830 destroy_nhwindow(win);
1831 if (n > 0) {
1832 idx = selected[0].item.a_int - 1;
1833 free((genericptr_t)selected);
1834 if (rlev && rdgn) {
1835 *rlev = lchoices.lev[idx];
1836 *rdgn = lchoices.dgn[idx];
1837 return lchoices.playerlev[idx];
1838 }
1839 }
1840 return 0;
1841 }
1842
1843 /* I hate searching for the invocation pos while debugging. -dean */
1844 if (Invocation_lev(&u.uz)) {
1845 putstr(win, 0, "");
1846 Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)",
1847 inv_pos.x, inv_pos.y, u.ux, u.uy);
1848 putstr(win, 0, buf);
1849 }
1850 /*
1851 * The following is based on the assumption that the inter-level portals
1852 * created by the level compiler (not the dungeon compiler) only exist
1853 * one per level (currently true, of course).
1854 */
1855 else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
1856 || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
1857 struct trap *trap;
1858 for (trap = ftrap; trap; trap = trap->ntrap)
1859 if (trap->ttyp == MAGIC_PORTAL) break;
1860
1861 putstr(win, 0, "");
1862 if (trap)
1863 Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)",
1864 trap->tx, trap->ty, u.ux, u.uy);
1865 else
1866 Sprintf(buf, "No portal found.");
1867 putstr(win, 0, buf);
1868 }
1869
1870 display_nhwindow(win, TRUE);
1871 destroy_nhwindow(win);
1872 return 0;
1873 }
1874 #endif /* WIZARD */
1875
1876 #endif /* OVL1 */
1877
1878 /* Record that the player knows about a branch from a level. This function
1879 * will determine whether or not it was a "real" branch that was taken.
1880 * This function should not be called for a transition done via level
1881 * teleport or via the Eye.
1882 */
1883 void
recbranch_mapseen(source,dest)1884 recbranch_mapseen(source, dest)
1885 d_level *source;
1886 d_level *dest;
1887 {
1888 mapseen *mptr;
1889 branch* br;
1890
1891 /* not a branch */
1892 if (source->dnum == dest->dnum) return;
1893
1894 /* we only care about forward branches */
1895 for (br = branches; br; br = br->next) {
1896 if (on_level(source, &br->end1) && on_level(dest, &br->end2)) break;
1897 if (on_level(source, &br->end2) && on_level(dest, &br->end1)) return;
1898 }
1899
1900 /* branch not found, so not a real branch. */
1901 if (!br) return;
1902
1903 if ((mptr = find_mapseen(source))) {
1904 if (mptr->br && br != mptr->br)
1905 impossible("Two branches on the same level?");
1906 mptr->br = br;
1907 } else {
1908 impossible("Can't note branch for unseen level (%d, %d)",
1909 source->dnum, source->dlevel);
1910 }
1911 }
1912
1913 /* add a custom name to the current level */
1914 int
donamelevel()1915 donamelevel()
1916 {
1917 mapseen *mptr;
1918 char qbuf[QBUFSZ]; /* Buffer for query text */
1919 char nbuf[BUFSZ]; /* Buffer for response */
1920 int len;
1921
1922 if (!(mptr = find_mapseen(&u.uz))) return 0;
1923
1924 Sprintf(qbuf,"What do you want to call this dungeon level? ");
1925 getlin(qbuf, nbuf);
1926
1927 if (index(nbuf, '\033')) return 0;
1928
1929 len = strlen(nbuf) + 1;
1930 if (mptr->custom) {
1931 free((genericptr_t)mptr->custom);
1932 mptr->custom = (char *)0;
1933 mptr->custom_lth = 0;
1934 }
1935
1936 if (*nbuf) {
1937 mptr->custom = (char *) alloc(sizeof(char) * len);
1938 mptr->custom_lth = len;
1939 strcpy(mptr->custom, nbuf);
1940 }
1941
1942 return 0;
1943 }
1944
1945 /* find the particular mapseen object in the chain */
1946 /* may return 0 */
1947 STATIC_OVL mapseen *
find_mapseen(lev)1948 find_mapseen(lev)
1949 d_level *lev;
1950 {
1951 mapseen *mptr;
1952
1953 for (mptr = mapseenchn; mptr; mptr = mptr->next)
1954 if (on_level(&(mptr->lev), lev)) break;
1955
1956 return mptr;
1957 }
1958
1959 void
forget_mapseen(ledger_no)1960 forget_mapseen(ledger_no)
1961 int ledger_no;
1962 {
1963 mapseen *mptr;
1964
1965 for (mptr = mapseenchn; mptr; mptr = mptr->next)
1966 if (dungeons[mptr->lev.dnum].ledger_start +
1967 mptr->lev.dlevel == ledger_no) break;
1968
1969 /* if not found, then nothing to forget */
1970 if (mptr) {
1971 mptr->feat.forgot = 1;
1972 mptr->br = (branch *)0;
1973
1974 /* custom names are erased, not forgotten until revisted */
1975 if (mptr->custom) {
1976 mptr->custom_lth = 0;
1977 free((genericptr_t)mptr->custom);
1978 mptr->custom = (char *)0;
1979 }
1980
1981 memset((genericptr_t) mptr->rooms, 0, sizeof(mptr->rooms));
1982 }
1983 }
1984
1985 STATIC_OVL void
save_mapseen(fd,mptr)1986 save_mapseen(fd, mptr)
1987 int fd;
1988 mapseen *mptr;
1989 {
1990 branch *curr;
1991 int count;
1992
1993 count = 0;
1994 for (curr = branches; curr; curr = curr->next) {
1995 if (curr == mptr->br) break;
1996 count++;
1997 }
1998
1999 bwrite(fd, (genericptr_t) &count, sizeof(int));
2000 bwrite(fd, (genericptr_t) &mptr->lev, sizeof(d_level));
2001 bwrite(fd, (genericptr_t) &mptr->feat, sizeof(mapseen_feat));
2002 bwrite(fd, (genericptr_t) &mptr->custom_lth, sizeof(unsigned));
2003 if (mptr->custom_lth)
2004 bwrite(fd, (genericptr_t) mptr->custom,
2005 sizeof(char) * mptr->custom_lth);
2006 bwrite(fd, (genericptr_t) &mptr->rooms, sizeof(mptr->rooms));
2007 }
2008
2009 STATIC_OVL mapseen *
load_mapseen(fd)2010 load_mapseen(fd)
2011 int fd;
2012 {
2013 int branchnum, count;
2014 mapseen *load;
2015 branch *curr;
2016
2017 load = (mapseen *) alloc(sizeof(mapseen));
2018 mread(fd, (genericptr_t) &branchnum, sizeof(int));
2019
2020 count = 0;
2021 for (curr = branches; curr; curr = curr->next) {
2022 if (count == branchnum) break;
2023 count++;
2024 }
2025 load->br = curr;
2026
2027 mread(fd, (genericptr_t) &load->lev, sizeof(d_level));
2028 mread(fd, (genericptr_t) &load->feat, sizeof(mapseen_feat));
2029 mread(fd, (genericptr_t) &load->custom_lth, sizeof(unsigned));
2030 if (load->custom_lth > 0) {
2031 load->custom = (char *) alloc(sizeof(char) * load->custom_lth);
2032 mread(fd, (genericptr_t) load->custom,
2033 sizeof(char) * load->custom_lth);
2034 } else load->custom = (char *) 0;
2035 mread(fd, (genericptr_t) &load->rooms, sizeof(load->rooms));
2036
2037 return load;
2038 }
2039
2040 /* Remove all mapseen objects for a particular dnum.
2041 * Useful during quest expulsion to remove quest levels.
2042 */
2043 void
remdun_mapseen(dnum)2044 remdun_mapseen(dnum)
2045 int dnum;
2046 {
2047 mapseen *mptr, *prev;
2048
2049 prev = mapseenchn;
2050 if (!prev) return;
2051 mptr = prev->next;
2052
2053 for (; mptr; prev = mptr, mptr = mptr->next) {
2054 if (mptr->lev.dnum == dnum) {
2055 prev->next = mptr->next;
2056 free((genericptr_t) mptr);
2057 mptr = prev;
2058 }
2059 }
2060 }
2061
2062 void
init_mapseen(lev)2063 init_mapseen(lev)
2064 d_level *lev;
2065 {
2066 /* Create a level and insert in "sorted" order. This is an insertion
2067 * sort first by dungeon (in order of discovery) and then by level number.
2068 */
2069 mapseen *mptr;
2070 mapseen *init;
2071 mapseen *old;
2072
2073 init = (mapseen *) alloc(sizeof(mapseen));
2074 (void) memset((genericptr_t)init, 0, sizeof(mapseen));
2075 init->lev.dnum = lev->dnum;
2076 init->lev.dlevel = lev->dlevel;
2077
2078 if (!mapseenchn) {
2079 mapseenchn = init;
2080 return;
2081 }
2082
2083 /* walk until we get to the place where we should
2084 * insert init between mptr and mptr->next
2085 */
2086 for (mptr = mapseenchn; mptr->next; mptr = mptr->next) {
2087 if (mptr->next->lev.dnum == init->lev.dnum) break;
2088 }
2089 for (; mptr->next; mptr = mptr->next) {
2090 if ((mptr->next->lev.dnum != init->lev.dnum) ||
2091 (mptr->next->lev.dlevel > init->lev.dlevel)) break;
2092 }
2093
2094 old = mptr->next;
2095 mptr->next = init;
2096 init->next = old;
2097 }
2098
2099 #define INTEREST(feat) \
2100 ((feat).nfount) || \
2101 ((feat).nsink) || \
2102 ((feat).nthrone) || \
2103 ((feat).naltar) || \
2104 ((feat).nshop) || \
2105 ((feat).ntemple) || \
2106 ((feat).ntree)
2107 /*
2108 || ((feat).water) || \
2109 ((feat).ice) || \
2110 ((feat).lava)
2111 */
2112
2113 /* returns true if this level has something interesting to print out */
2114 STATIC_OVL boolean
interest_mapseen(mptr)2115 interest_mapseen(mptr)
2116 mapseen *mptr;
2117 {
2118 return (on_level(&u.uz, &mptr->lev) ||
2119 ((!mptr->feat.forgot) &&
2120 (INTEREST(mptr->feat) ||
2121 (mptr->custom) ||
2122 (mptr->br)))
2123 );
2124 }
2125
2126 /* recalculate mapseen for the current level */
2127 void
recalc_mapseen()2128 recalc_mapseen()
2129 {
2130 mapseen *mptr;
2131 struct monst *shkp;
2132 int x, y, ridx;
2133
2134 /* Should not happen in general, but possible if in the process
2135 * of being booted from the quest. The mapseen object gets
2136 * removed during the expulsion but prior to leaving the level
2137 */
2138 if (!(mptr = find_mapseen(&u.uz))) return;
2139
2140 /* reset all features */
2141 memset((genericptr_t) &mptr->feat, 0, sizeof(mapseen_feat));
2142
2143 /* track rooms the hero is in */
2144 for (x = 0; x < sizeof(u.urooms); x++) {
2145 if (!u.urooms[x]) continue;
2146
2147 ridx = u.urooms[x] - ROOMOFFSET;
2148 if (rooms[ridx].rtype < SHOPBASE ||
2149 ((shkp = shop_keeper(u.urooms[x])) && inhishop(shkp)))
2150 mptr->rooms[ridx] |= MSR_SEEN;
2151 else
2152 /* shops without shopkeepers are no shops at all */
2153 mptr->rooms[ridx] &= ~MSR_SEEN;
2154 }
2155
2156 /* recalculate room knowledge: for now, just shops and temples
2157 * this could be extended to an array of 0..SHOPBASE
2158 */
2159 for (x = 0; x < sizeof(mptr->rooms); x++) {
2160 if (mptr->rooms[x] & MSR_SEEN) {
2161 if (rooms[x].rtype >= SHOPBASE) {
2162 if (!mptr->feat.nshop)
2163 mptr->feat.shoptype = rooms[x].rtype;
2164 else if (mptr->feat.shoptype != rooms[x].rtype)
2165 mptr->feat.shoptype = 0;
2166 mptr->feat.nshop = min(mptr->feat.nshop + 1, 3);
2167 } else if (rooms[x].rtype == TEMPLE)
2168 /* altar and temple alignment handled below */
2169 mptr->feat.ntemple = min(mptr->feat.ntemple + 1, 3);
2170 }
2171 }
2172
2173 /* Update styp with typ if and only if it is in sight or the hero can
2174 * feel it on their current location (i.e. not levitating). This *should*
2175 * give the "last known typ" for each dungeon location. (At the very least,
2176 * it's a better assumption than determining what the player knows from
2177 * the glyph and the typ (which is isn't quite enough information in some
2178 * cases).
2179 *
2180 * It was reluctantly added to struct rm to track. Alternatively
2181 * we could track "features" and then update them all here, and keep
2182 * track of when new features are created or destroyed, but this
2183 * seemed the most elegant, despite adding more data to struct rm.
2184 *
2185 * Although no current windowing systems (can) do this, this would add the
2186 * ability to have non-dungeon glyphs float above the last known dungeon
2187 * glyph (i.e. items on fountains).
2188 *
2189 * (vision-related styp update done in loop below)
2190 */
2191 if (!Levitation)
2192 levl[u.ux][u.uy].styp = levl[u.ux][u.uy].typ;
2193
2194 for (x = 0; x < COLNO; x++) {
2195 for (y = 0; y < ROWNO; y++) {
2196 /* update styp from viz_array */
2197 if (viz_array[y][x] & IN_SIGHT)
2198 levl[x][y].styp = levl[x][y].typ;
2199
2200 switch (levl[x][y].styp) {
2201 /*
2202 case ICE:
2203 mptr->feat.ice = 1;
2204 break;
2205 case POOL:
2206 case MOAT:
2207 case WATER:
2208 mptr->feat.water = 1;
2209 break;
2210 case LAVAPOOL:
2211 mptr->feat.lava = 1;
2212 break;
2213 */
2214 case TREE:
2215 mptr->feat.ntree = min(mptr->feat.ntree + 1, 3);
2216 break;
2217 case FOUNTAIN:
2218 mptr->feat.nfount = min(mptr->feat.nfount + 1, 3);
2219 break;
2220 case THRONE:
2221 mptr->feat.nthrone = min(mptr->feat.nthrone + 1, 3);
2222 break;
2223 case SINK:
2224 mptr->feat.nsink = min(mptr->feat.nsink + 1, 3);
2225 break;
2226 case ALTAR:
2227 if (!mptr->feat.naltar)
2228 mptr->feat.msalign = Amask2msa(levl[x][y].altarmask);
2229 else if (mptr->feat.msalign != Amask2msa(levl[x][y].altarmask))
2230 mptr->feat.msalign = MSA_NONE;
2231
2232 mptr->feat.naltar = min(mptr->feat.naltar + 1, 3);
2233 break;
2234 }
2235 }
2236 }
2237 }
2238
2239 int
dooverview()2240 dooverview()
2241 {
2242 winid win;
2243 mapseen *mptr;
2244 boolean first;
2245 boolean printdun;
2246 int lastdun=-1;
2247
2248 first = TRUE;
2249
2250 /* lazy intialization */
2251 (void) recalc_mapseen();
2252
2253 win = create_nhwindow(NHW_MENU);
2254
2255 for (mptr = mapseenchn; mptr; mptr = mptr->next) {
2256
2257 /* only print out info for a level or a dungeon if interest */
2258 if (interest_mapseen(mptr)) {
2259 printdun = (first || lastdun != mptr->lev.dnum);
2260 /* if (!first) putstr(win, 0, ""); */
2261 print_mapseen(win, mptr, printdun);
2262
2263 if (printdun) {
2264 first = FALSE;
2265 lastdun = mptr->lev.dnum;
2266 }
2267 }
2268 }
2269
2270 display_nhwindow(win, TRUE);
2271 destroy_nhwindow(win);
2272
2273 return 0;
2274 }
2275
2276 STATIC_OVL char *
seen_string(x,obj)2277 seen_string(x, obj)
2278 xchar x;
2279 const char *obj;
2280 {
2281 /* players are computer scientists: 0, 1, 2, n */
2282 switch(x) {
2283 case 0: return "no";
2284 /* an() returns too much. index is ok in this case */
2285 case 1: return index(vowels, *obj) ? "an" : "a";
2286 case 2: return "some";
2287 case 3: return "many";
2288 }
2289
2290 return "(unknown)";
2291 }
2292
2293 /* better br_string */
2294 STATIC_OVL const char *
br_string2(br)2295 br_string2(br)
2296 branch *br;
2297 {
2298 /* Special case: quest portal says closed if kicked from quest */
2299 boolean closed_portal =
2300 (br->end2.dnum == quest_dnum && u.uevent.qexpelled);
2301 switch(br->type)
2302 {
2303 case BR_PORTAL: return closed_portal ? "Sealed portal" : "Portal";
2304 case BR_NO_END1: return "Connection";
2305 case BR_NO_END2: return (br->end1_up) ? "One way stairs up" :
2306 "One way stairs down";
2307 case BR_STAIR: return (br->end1_up) ? "Stairs up" : "Stairs down";
2308 }
2309
2310 return "(unknown)";
2311 }
2312
2313 STATIC_OVL const char*
shop_string(rtype)2314 shop_string(rtype)
2315 int rtype;
2316 {
2317 /* Yuck, redundancy...but shclass.name doesn't cut it as a noun */
2318 switch(rtype) {
2319 case SHOPBASE:
2320 return "a general store";
2321 case ARMORSHOP:
2322 return "an armor shop";
2323 case SCROLLSHOP:
2324 return "a scroll shop";
2325 case POTIONSHOP:
2326 return "a potion shop";
2327 case WEAPONSHOP:
2328 return "a weapon shop";
2329 case FOODSHOP:
2330 return "a delicatessen store";
2331 case RINGSHOP:
2332 return "a jewelry store";
2333 case WANDSHOP:
2334 return "a wand shop";
2335 case BOOKSHOP:
2336 return "a bookstore";
2337 case CANDLESHOP:
2338 return "a lighting shop";
2339 case TOOLSHOP:
2340 return "a tool shop";
2341 case INSTRUMENTSHOP:
2342 return "a music store";
2343 case TINSHOP:
2344 return "a tin shop";
2345 case PETSHOP:
2346 return "a pet store";
2347 case BLACKSHOP:
2348 return "the Blackmarket";
2349 default:
2350 /* In case another patch adds a shop type that doesn't exist,
2351 * do something reasonable like "a shop".
2352 */
2353 warning("Unknown shop number: %d", rtype);
2354 return "shop";
2355 }
2356 }
2357
2358 /* some utility macros for print_mapseen */
2359 #define TAB " "
2360 #define BULLET ""
2361 #define PREFIX TAB TAB BULLET
2362 #define COMMA (i++ > 0 ? ", " : PREFIX)
2363 #define ADDNTOBUF(nam, var) { if (var) \
2364 Sprintf(eos(buf), "%s%s " nam "%s", COMMA, seen_string((var), (nam)), \
2365 ((var) != 1 ? "s" : "")); }
2366 #define ADDTOBUF(nam, var) { if (var) Sprintf(eos(buf), "%s " nam, COMMA); }
2367
2368 STATIC_OVL void
print_mapseen(win,mptr,printdun)2369 print_mapseen(win, mptr, printdun)
2370 winid win;
2371 mapseen *mptr;
2372 boolean printdun;
2373 {
2374 char buf[BUFSZ];
2375 int i, depthstart;
2376
2377 /* Damnable special cases */
2378 /* The quest and knox should appear to be level 1 to match
2379 * other text.
2380 */
2381 if (mptr->lev.dnum == quest_dnum || mptr->lev.dnum == knox_level.dnum)
2382 depthstart = 1;
2383 else
2384 depthstart = dungeons[mptr->lev.dnum].depth_start;
2385
2386 if (printdun) {
2387 /* Sokoban lies about dunlev_ureached and we should
2388 * suppress the negative numbers in the endgame.
2389 */
2390 if (dungeons[mptr->lev.dnum].dunlev_ureached == 1 ||
2391 mptr->lev.dnum == sokoban_dnum || In_endgame(&mptr->lev))
2392 Sprintf(buf, "%s:", dungeons[mptr->lev.dnum].dname);
2393 else
2394 Sprintf(buf, "%s: levels %d to %d",
2395 dungeons[mptr->lev.dnum].dname,
2396 depthstart, depthstart +
2397 dungeons[mptr->lev.dnum].dunlev_ureached - 1);
2398 putstr(win, ATR_INVERSE, buf);
2399 }
2400
2401 /* calculate level number */
2402 i = depthstart + mptr->lev.dlevel - 1;
2403 if (Is_astralevel(&mptr->lev))
2404 Sprintf(buf, TAB "Astral Plane:");
2405 else if (In_endgame(&mptr->lev))
2406 /* Negative numbers are mildly confusing, since they are never
2407 * shown to the player, except in wizard mode. We could show
2408 * "Level -1" for the earth plane, for example. Instead,
2409 * show "Plane 1" for the earth plane to differentiate from
2410 * level 1. There's not much to show, but maybe the player
2411 * wants to #annotate them for some bizarre reason.
2412 */
2413 Sprintf(buf, TAB "Plane %i:", -i);
2414 else
2415 Sprintf(buf, TAB "Level %d:", i);
2416
2417 #ifdef WIZARD
2418 /* wizmode prints out proto dungeon names for clarity */
2419 if (wizard) {
2420 s_level *slev;
2421 if ((slev = Is_special(&mptr->lev)))
2422 Sprintf(eos(buf), " [%s]", slev->proto);
2423 }
2424 #endif
2425
2426 if (mptr->custom)
2427 Sprintf(eos(buf), " (%s)", mptr->custom);
2428
2429 /* print out glyph or something more interesting? */
2430 Sprintf(eos(buf), "%s", on_level(&u.uz, &mptr->lev) ?
2431 " <- You are here" : "");
2432 putstr(win, ATR_BOLD, buf);
2433
2434 if (mptr->feat.forgot) return;
2435
2436 if (INTEREST(mptr->feat)) {
2437 buf[0] = 0;
2438
2439 i = 0; /* interest counter */
2440
2441 /* List interests in an order vaguely corresponding to
2442 * how important they are.
2443 */
2444 if (mptr->feat.nshop > 1)
2445 ADDNTOBUF("shop", mptr->feat.nshop)
2446 else if (mptr->feat.nshop == 1)
2447 Sprintf(eos(buf), "%s%s", COMMA,
2448 shop_string(mptr->feat.shoptype));
2449
2450 /* Temples + non-temple altars get munged into just "altars" */
2451 if (!mptr->feat.ntemple || mptr->feat.ntemple != mptr->feat.naltar)
2452 ADDNTOBUF("altar", mptr->feat.naltar)
2453 else
2454 ADDNTOBUF("temple", mptr->feat.ntemple)
2455
2456 /* only print out altar's god if they are all to your god */
2457 if (Amask2align(Msa2amask(mptr->feat.msalign)) == u.ualign.type)
2458 Sprintf(eos(buf), " to %s", align_gname(u.ualign.type));
2459
2460 ADDNTOBUF("fountain", mptr->feat.nfount)
2461 ADDNTOBUF("sink", mptr->feat.nsink)
2462 ADDNTOBUF("throne", mptr->feat.nthrone)
2463 ADDNTOBUF("tree", mptr->feat.ntree);
2464 /*
2465 ADDTOBUF("water", mptr->feat.water)
2466 ADDTOBUF("lava", mptr->feat.lava)
2467 ADDTOBUF("ice", mptr->feat.ice)
2468 */
2469
2470 /* capitalize afterwards */
2471 i = strlen(PREFIX);
2472 *buf = highc(*buf);
2473
2474 putstr(win, 0, buf);
2475 }
2476
2477 /* print out branches */
2478 if (mptr->br) {
2479 Sprintf(buf, PREFIX "%s to %s", br_string2(mptr->br),
2480 dungeons[mptr->br->end2.dnum].dname);
2481
2482 /* since mapseen objects are printed out in increasing order
2483 * of dlevel, clarify which level this branch is going to
2484 * if the branch goes upwards. Unless it's the end game
2485 */
2486 if (mptr->br->end1_up && !In_endgame(&(mptr->br->end2)))
2487 Sprintf(eos(buf), ", level %d", depth(&(mptr->br->end2)));
2488 putstr(win, 0, buf);
2489 }
2490 }
2491
2492 /*dungeon.c*/
2493