1 | /* SCCS Id: @(#)dungeon.c 3.3 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 |
9 | #ifdef OVL1
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 (used here, */
29 | /* and mklev.c) */
30 | static branch *branches = (branch *) 0; /* dungeon branch list */
31 |
32 | static void FDECL(Fread, (genericptr_t, int, int, dlb *));
33 | STATIC_DCL xchar FDECL(dname_to_dnum, (const char *));
34 | STATIC_DCL int FDECL(find_branch, (const char *, struct proto_dungeon *));
35 | STATIC_DCL xchar FDECL(parent_dnum, (const char *, struct proto_dungeon *));
36 | STATIC_DCL int FDECL(level_range, (XCHAR_P,int,int,int,struct proto_dungeon *,int *));
37 | STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *));
38 | STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *));
39 | STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *));
40 | STATIC_DCL void FDECL(add_level, (s_level *));
41 | STATIC_DCL void FDECL(init_level, (int,int,struct proto_dungeon *));
42 | STATIC_DCL int FDECL(possible_places, (int, boolean *, struct proto_dungeon *));
43 | STATIC_DCL xchar FDECL(pick_level, (boolean *, int));
44 | STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *));
45 | #ifdef WIZARD
46 | STATIC_DCL const char *FDECL(br_string, (int));
47 | STATIC_DCL void FDECL(print_branch, (winid, int, int, int));
48 | #endif
49 |
50 | #ifdef DEBUG
51 | #define DD dungeons[i]
52 | STATIC_DCL void NDECL(dumpit);
53 |
54 | STATIC_OVL void
55 | dumpit()
56 | {
57 | int i;
58 | s_level *x;
59 | branch *br;
60 |
61 | for(i = 0; i < n_dgns; i++) {
62 | fprintf(stderr, "\n#%d \"%s\" (%s):\n", i,
63 | DD.dname, DD.proto);
64 | fprintf(stderr, " num_dunlevs %d, dunlev_ureached %d\n",
65 | DD.num_dunlevs, DD.dunlev_ureached);
66 | fprintf(stderr, " depth_start %d, ledger_start %d\n",
67 | DD.depth_start, DD.ledger_start);
68 | fprintf(stderr, " flags:%s%s%s\n",
69 | DD.flags.rogue_like ? " rogue_like" : "",
70 | DD.flags.maze_like ? " maze_like" : "",
71 | DD.flags.hellish ? " hellish" : "");
72 | getchar();
73 | }
74 | fprintf(stderr,"\nSpecial levels:\n");
75 | for(x = sp_levchn; x; x = x->next) {
76 | fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs);
77 | fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel);
78 | fprintf(stderr, "flags:%s%s%s%s\n",
79 | x->flags.rogue_like ? " rogue_like" : "",
80 | x->flags.maze_like ? " maze_like" : "",
81 | x->flags.hellish ? " hellish" : "",
82 | x->flags.town ? " town" : "");
83 | getchar();
84 | }
85 | fprintf(stderr,"\nBranches:\n");
86 | for (br = branches; br; br = br->next) {
87 | fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n",
88 | br->id,
89 | br->type == BR_STAIR ? "stair" :
90 | br->type == BR_NO_END1 ? "no end1" :
91 | br->type == BR_NO_END2 ? "no end2" :
92 | br->type == BR_PORTAL ? "portal" :
93 | "unknown",
94 | br->end1.dnum, br->end1.dlevel,
95 | br->end2.dnum, br->end2.dlevel,
96 | br->end1_up ? "end1 up" : "end1 down");
97 | }
98 | getchar();
99 | fprintf(stderr,"\nDone\n");
100 | getchar();
101 | }
102 | #endif
103 |
104 | /* Save the dungeon structures. */
105 | void
106 | save_dungeon(fd, perform_write, free_data)
107 | int fd;
108 | boolean perform_write, free_data;
109 | {
110 | branch *curr, *next;
111 | int count;
112 |
113 | if (perform_write) {
114 | bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns);
115 | bwrite(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns);
116 | bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
117 | bwrite(fd, (genericptr_t) tune, sizeof tune);
118 |
119 | for (count = 0, curr = branches; curr; curr = curr->next)
120 | count++;
121 | bwrite(fd, (genericptr_t) &count, sizeof(count));
122 |
123 | for (curr = branches; curr; curr = curr->next)
124 | bwrite(fd, (genericptr_t) curr, sizeof (branch));
125 |
126 | count = maxledgerno();
127 | bwrite(fd, (genericptr_t) &count, sizeof count);
128 | bwrite(fd, (genericptr_t) level_info,
129 | (unsigned)count * sizeof (struct linfo));
130 | bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
131 | }
132 |
133 | if (free_data) {
134 | for (curr = branches; curr; curr = next) {
135 | next = curr->next;
136 | free((genericptr_t) curr);
137 | }
138 | branches = 0;
139 | }
140 | }
141 |
142 | /* Restore the dungeon structures. */
143 | void
144 | restore_dungeon(fd)
145 | int fd;
146 | {
147 | branch *curr, *last;
148 | int count, i;
149 |
150 | mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns));
151 | mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns);
152 | mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
153 | mread(fd, (genericptr_t) tune, sizeof tune);
154 |
155 | last = branches = (branch *) 0;
156 |
157 | mread(fd, (genericptr_t) &count, sizeof(count));
158 | for (i = 0; i < count; i++) {
159 | curr = (branch *) alloc(sizeof(branch));
160 | mread(fd, (genericptr_t) curr, sizeof(branch));
161 | curr->next = (branch *) 0;
162 | if (last)
163 | last->next = curr;
164 | else
165 | branches = curr;
166 | last = curr;
167 | }
168 |
169 | mread(fd, (genericptr_t) &count, sizeof(count));
170 | if (count >= MAXLINFO)
171 | panic("level information count larger (%d) than allocated size", count);
172 | mread(fd, (genericptr_t) level_info, (unsigned)count*sizeof(struct linfo));
173 | mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
174 | }
175 |
176 | static void
177 | Fread(ptr, size, nitems, stream)
178 | genericptr_t ptr;
179 | int size, nitems;
180 | dlb *stream;
181 | {
182 | int cnt;
183 |
184 | if((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
185 | panic(
186 | "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.",
187 | (size * nitems), (size * cnt));
188 | terminate(EXIT_FAILURE);
189 | }
190 | }
191 |
192 | STATIC_OVL xchar
193 | dname_to_dnum(s)
194 | const char *s;
195 | {
196 | xchar i;
197 |
198 | for (i = 0; i < n_dgns; i++)
199 | if (!strcmp(dungeons[i].dname, s)) return i;
200 |
201 | panic("Couldn't resolve dungeon number for name \"%s\".", s);
202 | /*NOT REACHED*/
203 | return (xchar)0;
204 | }
205 |
206 | s_level *
207 | find_level(s)
208 | const char *s;
209 | {
210 | s_level *curr;
211 | for(curr = sp_levchn; curr; curr = curr->next)
212 | if (!strcmpi(s, curr->proto)) break;
213 | return curr;
214 | }
215 |
216 | /* Find the branch that links the named dungeon. */
217 | STATIC_OVL int
218 | find_branch(s, pd)
219 | const char *s; /* dungeon name */
220 | struct proto_dungeon *pd;
221 | {
222 | int i;
223 |
224 | if (pd) {
225 | for (i = 0; i < pd->n_brs; i++)
226 | if (!strcmp(pd->tmpbranch[i].name, s)) break;
227 | if (i == pd->n_brs) panic("find_branch: can't find %s", s);
228 | } else {
229 | /* support for level tport by name */
230 | branch *br;
231 | const char *dnam;
232 |
233 | for (br = branches; br; br = br->next) {
234 | dnam = dungeons[br->end2.dnum].dname;
235 | if (!strcmpi(dnam, s) ||
236 | (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s)))
237 | break;
238 | }
239 | i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1;
240 | }
241 | return i;
242 | }
243 |
244 |
245 | /*
246 | * Find the "parent" by searching the prototype branch list for the branch
247 | * listing, then figuring out to which dungeon it belongs.
248 | */
249 | STATIC_OVL xchar
250 | parent_dnum(s, pd)
251 | const char *s; /* dungeon name */
252 | struct proto_dungeon *pd;
253 | {
254 | int i;
255 | xchar pdnum;
256 |
257 | i = find_branch(s, pd);
258 | /*
259 | * Got branch, now find parent dungeon. Stop if we have reached
260 | * "this" dungeon (if we haven't found it by now it is an error).
261 | */
262 | for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++)
263 | if ((i -= pd->tmpdungeon[pdnum].branches) < 0)
264 | return(pdnum);
265 |
266 | panic("parent_dnum: couldn't resolve branch.");
267 | /*NOT REACHED*/
268 | return (xchar)0;
269 | }
270 |
271 | /*
272 | * Return a starting point and number of successive positions a level
273 | * or dungeon entrance can occupy.
274 | *
275 | * Note: This follows the acouple (instead of the rcouple) rules for a
276 | * negative random component (rand < 0). These rules are found
277 | * in dgn_comp.y. The acouple [absolute couple] section says that
278 | * a negative random component means from the (adjusted) base to the
279 | * end of the dungeon.
280 | */
281 | STATIC_OVL int
282 | level_range(dgn, base, rand, chain, pd, adjusted_base)
283 | xchar dgn;
284 | int base, rand, chain;
285 | struct proto_dungeon *pd;
286 | int *adjusted_base;
287 | {
288 | int lmax = dungeons[dgn].num_dunlevs;
289 |
290 | if (chain >= 0) { /* relative to a special level */
291 | s_level *levtmp = pd->final_lev[chain];
292 | if (!levtmp) panic("level_range: empty chain level!");
293 |
294 | base += levtmp->dlevel.dlevel;
295 | } else { /* absolute in the dungeon */
296 | /* from end of dungeon */
297 | if (base < 0) base = (lmax + base + 1);
298 | }
299 |
300 | if (base < 1 || base > lmax)
301 | panic("level_range: base value out of range");
302 |
303 | *adjusted_base = base;
304 |
305 | if (rand == -1) { /* from base to end of dungeon */
306 | return (lmax - base + 1);
307 | } else if (rand) {
308 | /* make sure we don't run off the end of the dungeon */
309 | return (((base + rand - 1) > lmax) ? lmax-base+1 : rand);
310 | } /* else only one choice */
311 | return 1;
312 | }
313 |
314 | STATIC_OVL xchar
315 | parent_dlevel(s, pd)
316 | const char *s;
317 | struct proto_dungeon *pd;
318 | {
319 | int i, j, num, base, dnum = parent_dnum(s, pd);
320 | branch *curr;
321 |
322 |
323 | i = find_branch(s, pd);
324 | num = level_range(dnum, pd->tmpbranch[i].lev.base,
325 | pd->tmpbranch[i].lev.rand,
326 | pd->tmpbranch[i].chain,
327 | pd, &base);
328 |
329 | /* KMH -- Try our best to find a level without an existing branch */
330 | i = j = rn2(num);
331 | do {
332 | if (++i >= num) i = 0;
333 | for (curr = branches; curr; curr = curr->next)
334 | if ((curr->end1.dnum == dnum && curr->end1.dlevel == base+i) ||
335 | (curr->end2.dnum == dnum && curr->end2.dlevel == base+i))
336 | break;
337 | } while (curr && i != j);
338 | return (base + i);
339 | }
340 |
341 | /* Convert from the temporary branch type to the dungeon branch type. */
342 | STATIC_OVL int
343 | correct_branch_type(tbr)
344 | struct tmpbranch *tbr;
345 | {
346 | switch (tbr->type) {
347 | case TBR_STAIR: return BR_STAIR;
348 | case TBR_NO_UP: return tbr->up ? BR_NO_END1 : BR_NO_END2;
349 | case TBR_NO_DOWN: return tbr->up ? BR_NO_END2 : BR_NO_END1;
350 | case TBR_PORTAL: return BR_PORTAL;
351 | }
352 | impossible("correct_branch_type: unknown branch type");
353 | return BR_STAIR;
354 | }
355 |
356 | /*
357 | * Add the given branch to the branch list. The branch list is ordered
358 | * by end1 dungeon and level followed by end2 dungeon and level. If
359 | * extract_first is true, then the branch is already part of the list
360 | * but needs to be repositioned.
361 | */
362 | void
363 | insert_branch(new_branch, extract_first)
364 | branch *new_branch;
365 | boolean extract_first;
366 | {
367 | branch *curr, *prev;
368 | long new_val, curr_val, prev_val;
369 |
370 | if (extract_first) {
371 | for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next)
372 | if (curr == new_branch) break;
373 |
374 | if (!curr) panic("insert_branch: not found");
375 | if (prev)
376 | prev->next = curr->next;
377 | else
378 | branches = curr->next;
379 | }
380 | new_branch->next = (branch *) 0;
381 |
382 | /* Convert the branch into a unique number so we can sort them. */
383 | #define branch_val(bp) ((((long)(bp)->end1.dnum * (MAXLEVEL+1) + (long)(bp)->end1.dlevel) * (MAXDUNGEON+1) * (MAXLEVEL+1)) + ((long)(bp)->end2.dnum * (MAXLEVEL+1) + (long)(bp)->end2.dlevel))
384 |
385 | /*
386 | * Insert the new branch into the correct place in the branch list.
387 | */
388 | prev = (branch *) 0;
389 | prev_val = -1;
390 | new_val = branch_val(new_branch);
391 | for (curr = branches; curr;
392 | prev_val = curr_val, prev = curr, curr = curr->next) {
393 | curr_val = branch_val(curr);
394 | if (prev_val < new_val && new_val <= curr_val) break;
395 | }
396 | if (prev) {
397 | new_branch->next = curr;
398 | prev->next = new_branch;
399 | } else {
400 | new_branch->next = branches;
401 | branches = new_branch;
402 | }
403 | }
404 |
405 | /* Add a dungeon branch to the branch list. */
406 | STATIC_OVL branch *
407 | add_branch(dgn, child_entry_level, pd)
408 | int dgn;
409 | int child_entry_level;
410 | struct proto_dungeon *pd;
411 | {
412 | static int branch_id = 0;
413 | int branch_num;
414 | branch *new_branch;
415 |
416 | branch_num = find_branch(dungeons[dgn].dname,pd);
417 | new_branch = (branch *) alloc(sizeof(branch));
418 | new_branch->next = (branch *) 0;
419 | new_branch->id = branch_id++;
420 | new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
421 | new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd);
422 | new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd);
423 | new_branch->end2.dnum = dgn;
424 | new_branch->end2.dlevel = child_entry_level;
425 | new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE;
426 |
427 | insert_branch(new_branch, FALSE);
428 | return new_branch;
429 | }
430 |
431 | /*
432 | * Add new level to special level chain. Insert it in level order with the
433 | * other levels in this dungeon. This assumes that we are never given a
434 | * level that has a dungeon number less than the dungeon number of the
435 | * last entry.
436 | */
437 | STATIC_OVL void
438 | add_level(new_lev)
439 | s_level *new_lev;
440 | {
441 | s_level *prev, *curr;
442 |
443 | prev = (s_level *) 0;
444 | for (curr = sp_levchn; curr; curr = curr->next) {
445 | if (curr->dlevel.dnum == new_lev->dlevel.dnum &&
446 | curr->dlevel.dlevel > new_lev->dlevel.dlevel)
447 | break;
448 | prev = curr;
449 | }
450 | if (!prev) {
451 | new_lev->next = sp_levchn;
452 | sp_levchn = new_lev;
453 | } else {
454 | new_lev->next = curr;
455 | prev->next = new_lev;
456 | }
457 | }
458 |
459 | STATIC_OVL void
460 | init_level(dgn, proto_index, pd)
461 | int dgn, proto_index;
462 | struct proto_dungeon *pd;
463 | {
464 | s_level *new_level;
465 | struct tmplevel *tlevel = &pd->tmplevel[proto_index];
466 |
467 | pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
468 | #ifdef WIZARD
469 | if (!wizard)
470 | #endif
471 | if (tlevel->chance <= rn2(100)) return;
472 |
473 | pd->final_lev[proto_index] = new_level =
474 | (s_level *) alloc(sizeof(s_level));
475 | /* load new level with data */
476 | Strcpy(new_level->proto, tlevel->name);
477 | new_level->boneid = tlevel->boneschar;
478 | new_level->dlevel.dnum = dgn;
479 | new_level->dlevel.dlevel = 0; /* for now */
480 |
481 | new_level->flags.town = !!(tlevel->flags & TOWN);
482 | new_level->flags.hellish = !!(tlevel->flags & HELLISH);
483 | new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
484 | new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
485 | new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);
486 |
487 | new_level->rndlevs = tlevel->rndlevs;
488 | new_level->next = (s_level *) 0;
489 | }
490 |
491 | STATIC_OVL int
492 | possible_places(idx, map, pd)
493 | int idx; /* prototype index */
494 | boolean *map; /* array MAXLEVEL+1 in length */
495 | struct proto_dungeon *pd;
496 | {
497 | int i, start, count;
498 | s_level *lev = pd->final_lev[idx];
499 |
500 | /* init level possibilities */
501 | for (i = 0; i <= MAXLEVEL; i++) map[i] = FALSE;
502 |
503 | /* get base and range and set those entried to true */
504 | count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base,
505 | pd->tmplevel[idx].lev.rand,
506 | pd->tmplevel[idx].chain,
507 | pd, &start);
508 | for (i = start; i < start+count; i++)
509 | map[i] = TRUE;
510 |
511 | /* mark off already placed levels */
512 | for (i = pd->start; i < idx; i++) {
513 | if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) {
514 | map[pd->final_lev[i]->dlevel.dlevel] = FALSE;
515 | --count;
516 | }
517 | }
518 |
519 | return count;
520 | }
521 |
522 | /* Pick the nth TRUE entry in the given boolean array. */
523 | STATIC_OVL xchar
524 | pick_level(map, nth)
525 | boolean *map; /* an array MAXLEVEL+1 in size */
526 | int nth;
527 | {
528 | int i;
529 | for (i = 1; i <= MAXLEVEL; i++)
530 | if (map[i] && !nth--) return (xchar) i;
531 | panic("pick_level: ran out of valid levels");
532 | return 0;
533 | }
534 |
535 | #ifdef DDEBUG
536 | static void FDECL(indent,(int));
537 |
538 | static void
539 | indent(d)
540 | int d;
541 | {
542 | while (d-- > 0) fputs(" ", stderr);
543 | }
544 | #endif
545 |
546 | /*
547 | * Place a level. First, find the possible places on a dungeon map
548 | * template. Next pick one. Then try to place the next level. If
549 | * sucessful, we're done. Otherwise, try another (and another) until
550 | * all possible places have been tried. If all possible places have
551 | * been exausted, return false.
552 | */
553 | STATIC_OVL boolean
554 | place_level(proto_index, pd)
555 | int proto_index;
556 | struct proto_dungeon *pd;
557 | {
558 | boolean map[MAXLEVEL+1]; /* valid levels are 1..MAXLEVEL inclusive */
559 | s_level *lev;
560 | int npossible;
561 | #ifdef DDEBUG
562 | int i;
563 | #endif
564 |
565 | if (proto_index == pd->n_levs) return TRUE; /* at end of proto levels */
566 |
567 | lev = pd->final_lev[proto_index];
568 |
569 | /* No level created for this prototype, goto next. */
570 | if (!lev) return place_level(proto_index+1, pd);
571 |
572 | npossible = possible_places(proto_index, map, pd);
573 |
574 | for (; npossible; --npossible) {
575 | lev->dlevel.dlevel = pick_level(map, rn2(npossible));
576 | #ifdef DDEBUG
577 | indent(proto_index-pd->start);
578 | fprintf(stderr,"%s: trying %d [ ", lev->proto, lev->dlevel.dlevel);
579 | for (i = 1; i <= MAXLEVEL; i++)
580 | if (map[i]) fprintf(stderr,"%d ", i);
581 | fprintf(stderr,"]\n");
582 | #endif
583 | if (place_level(proto_index+1, pd)) return TRUE;
584 | map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */
585 | }
586 | #ifdef DDEBUG
587 | indent(proto_index-pd->start);
588 | fprintf(stderr,"%s: failed\n", lev->proto);
589 | #endif
590 | return FALSE;
591 | }
592 |
593 |
594 | struct level_map {
595 | const char *lev_name;
596 | d_level *lev_spec;
597 | } level_map[] = {
598 | { "air", &air_level },
599 | { "asmodeus", &asmodeus_level },
600 | { "astral", &astral_level },
601 | { "baalz", &baalzebub_level },
602 | { "bigroom", &bigroom_level },
603 | { "castle", &stronghold_level },
604 | { "earth", &earth_level },
605 | { "fakewiz1", &portal_level },
606 | { "fire", &fire_level },
607 | { "juiblex", &juiblex_level },
608 | { "knox", &knox_level },
609 | { "medusa", &medusa_level },
610 | { "oracle", &oracle_level },
611 | { "orcus", &orcus_level },
612 | #ifdef REINCARNATION
613 | { "rogue", &rogue_level },
614 | #endif
615 | { "sanctum", &sanctum_level },
616 | { "valley", &valley_level },
617 | { "water", &water_level },
618 | { "wizard1", &wiz1_level },
619 | { "wizard2", &wiz2_level },
620 | { "wizard3", &wiz3_level },
621 | { X_START, &qstart_level },
622 | { X_LOCATE, &qlocate_level },
623 | { X_GOAL, &nemesis_level },
624 | { "", (d_level *)0 }
625 | };
626 |
627 | void
628 | init_dungeons() /* initialize the "dungeon" structs */
629 | {
630 | dlb *dgn_file;
631 | register int i, cl = 0, cb = 0;
632 | register s_level *x;
633 | struct proto_dungeon pd;
634 | struct level_map *lev_map;
635 | struct version_info vers_info;
636 |
637 | pd.n_levs = pd.n_brs = 0;
638 |
639 | dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
640 | if (!dgn_file) {
641 | char tbuf[BUFSZ];
642 | Sprintf(tbuf, "Cannot open dungeon description - \"%s",
643 | DUNGEON_FILE);
644 | #ifdef DLBRSRC /* using a resource from the executable */
645 | Strcat(tbuf, "\" resource!");
646 | #else /* using a file or DLB file */
647 | # if defined(DLB)
648 | Strcat(tbuf, "\" from ");
649 | # ifdef PREFIXES_IN_USE
650 | Strcat(tbuf, "\n\"");
651 | if (fqn_prefix[DATAPREFIX]) Strcat(tbuf, fqn_prefix[DATAPREFIX]);
652 | # else
653 | Strcat(tbuf, "\"");
654 | # endif
655 | Strcat(tbuf, DLBFILE);
656 | # endif
657 | Strcat(tbuf, "\" file!");
658 | #endif
659 | panic(tbuf);
660 | }
661 |
662 | /* validate the data's version against the program's version */
663 | Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file);
664 | if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
665 | panic("Dungeon description not valid.");
666 |
667 | /*
668 | * Read in each dungeon and transfer the results to the internal
669 | * dungeon arrays.
670 | */
671 | sp_levchn = (s_level *) 0;
672 | Fread((genericptr_t)&n_dgns, sizeof(int), 1, dgn_file);
673 | if (n_dgns >= MAXDUNGEON)
674 | panic("init_dungeons: too many dungeons");
675 |
676 | for (i = 0; i < n_dgns; i++) {
677 | Fread((genericptr_t)&pd.tmpdungeon[i],
678 | sizeof(struct tmpdungeon), 1, dgn_file);
679 | #ifdef WIZARD
680 | if(!wizard)
681 | #endif
682 | if(pd.tmpdungeon[i].chance && (pd.tmpdungeon[i].chance <= rn2(100))) {
683 | int j;
684 |
685 | /* skip over any levels or branches */
686 | for(j = 0; j < pd.tmpdungeon[i].levels; j++)
687 | Fread((genericptr_t)&pd.tmplevel[cl], sizeof(struct tmplevel),
688 | 1, dgn_file);
689 |
690 | for(j = 0; j < pd.tmpdungeon[i].branches; j++)
691 | Fread((genericptr_t)&pd.tmpbranch[cb],
692 | sizeof(struct tmpbranch), 1, dgn_file);
693 | n_dgns--; i--;
694 | continue;
695 | }
696 |
697 | Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name);
698 | Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname);
699 | dungeons[i].boneid = pd.tmpdungeon[i].boneschar;
700 |
701 | if(pd.tmpdungeon[i].lev.rand)
702 | dungeons[i].num_dunlevs = (xchar)rn1(pd.tmpdungeon[i].lev.rand,
703 | pd.tmpdungeon[i].lev.base);
704 | else dungeons[i].num_dunlevs = (xchar)pd.tmpdungeon[i].lev.base;
705 |
706 | if(!i) {
707 | dungeons[i].ledger_start = 0;
708 | dungeons[i].depth_start = 1;
709 | dungeons[i].dunlev_ureached = 1;
710 | } else {
711 | dungeons[i].ledger_start = dungeons[i-1].ledger_start +
712 | dungeons[i-1].num_dunlevs;
713 | dungeons[i].dunlev_ureached = 0;
714 | }
715 |
716 | dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH);
717 | dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE);
718 | dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE);
719 | dungeons[i].flags.align = ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4);
720 | /*
721 | * Set the entry level for this dungeon. The pd.tmpdungeon entry
722 | * value means:
723 | * < 0 from bottom (-1 == bottom level)
724 | * 0 default (top)
725 | * > 0 actual level (1 = top)
726 | *
727 | * Note that the entry_lev field in the dungeon structure is
728 | * redundant. It is used only here and in print_dungeon().
729 | */
730 | if (pd.tmpdungeon[i].entry_lev < 0) {
731 | dungeons[i].entry_lev = dungeons[i].num_dunlevs +
732 | pd.tmpdungeon[i].entry_lev + 1;
733 | if (dungeons[i].entry_lev <= 0) dungeons[i].entry_lev = 1;
734 | } else if (pd.tmpdungeon[i].entry_lev > 0) {
735 | dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
736 | if (dungeons[i].entry_lev > dungeons[i].num_dunlevs)
737 | dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
738 | } else { /* default */
739 | dungeons[i].entry_lev = 1; /* defaults to top level */
740 | }
741 |
742 | if (i) { /* set depth */
743 | branch *br;
744 | schar from_depth;
745 | boolean from_up;
746 |
747 | br = add_branch(i, dungeons[i].entry_lev, &pd);
748 |
749 | /* Get the depth of the connecting end. */
750 | if (br->end1.dnum == i) {
751 | from_depth = depth(&br->end2);
752 | from_up = !br->end1_up;
753 | } else {
754 | from_depth = depth(&br->end1);
755 | from_up = br->end1_up;
756 | }
757 |
758 | /*
759 | * Calculate the depth of the top of the dungeon via
760 | * its branch. First, the depth of the entry point:
761 | *
762 | * depth of branch from "parent" dungeon
763 | * + -1 or 1 depending on a up or down stair or
764 | * 0 if portal
765 | *
766 | * Followed by the depth of the top of the dungeon:
767 | *
768 | * - (entry depth - 1)
769 | *
770 | * We'll say that portals stay on the same depth.
771 | */
772 | dungeons[i].depth_start = from_depth
773 | + (br->type == BR_PORTAL ? 0 :
774 | (from_up ? -1 : 1))
775 | - (dungeons[i].entry_lev - 1);
776 | }
777 |
778 | /* this is redundant - it should have been flagged by dgn_comp */
779 | if(dungeons[i].num_dunlevs > MAXLEVEL)
780 | dungeons[i].num_dunlevs = MAXLEVEL;
781 |
782 | pd.start = pd.n_levs; /* save starting point */
783 | pd.n_levs += pd.tmpdungeon[i].levels;
784 | if (pd.n_levs > LEV_LIMIT)
785 | panic("init_dungeon: too many special levels");
786 | /*
787 | * Read in the prototype special levels. Don't add generated
788 | * special levels until they are all placed.
789 | */
790 | for(; cl < pd.n_levs; cl++) {
791 | Fread((genericptr_t)&pd.tmplevel[cl],
792 | sizeof(struct tmplevel), 1, dgn_file);
793 | init_level(i, cl, &pd);
794 | }
795 | /*
796 | * Recursively place the generated levels for this dungeon. This
797 | * routine will attempt all possible combinations before giving
798 | * up.
799 | */
800 | if (!place_level(pd.start, &pd))
801 | panic("init_dungeon: couldn't place levels");
802 | #ifdef DDEBUG
803 | fprintf(stderr, "--- end of dungeon %d ---\n", i);
804 | fflush(stderr);
805 | getchar();
806 | #endif
807 | for (; pd.start < pd.n_levs; pd.start++)
808 | if (pd.final_lev[pd.start]) add_level(pd.final_lev[pd.start]);
809 |
810 |
811 | pd.n_brs += pd.tmpdungeon[i].branches;
812 | if (pd.n_brs > BRANCH_LIMIT)
813 | panic("init_dungeon: too many branches");
814 | for(; cb < pd.n_brs; cb++)
815 | Fread((genericptr_t)&pd.tmpbranch[cb],
816 | sizeof(struct tmpbranch), 1, dgn_file);
817 | }
818 | (void) dlb_fclose(dgn_file);
819 |
820 | for (i = 0; i < 5; i++) tune[i] = 'A' + rn2(7);
821 | tune[5] = 0;
822 |
823 | /*
824 | * Find most of the special levels and dungeons so we can access their
825 | * locations quickly.
826 | */
827 | for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
828 | x = find_level(lev_map->lev_name);
829 | if (x) {
830 | assign_level(lev_map->lev_spec, &x->dlevel);
831 | if (!strncmp(lev_map->lev_name, "x-", 2)) {
832 | /* This is where the name substitution on the
833 | * levels of the quest dungeon occur.
834 | */
835 | Sprintf(x->proto, "%s%s", urole.filecode, &lev_map->lev_name[1]);
836 | } else if (lev_map->lev_spec == &knox_level) {
837 | branch *br;
838 | /*
839 | * Kludge to allow floating Knox entrance. We
840 | * specify a floating entrance by the fact that
841 | * its entrance (end1) has a bogus dnum, namely
842 | * n_dgns.
843 | */
844 | for (br = branches; br; br = br->next)
845 | if (on_level(&br->end2, &knox_level)) break;
846 |
847 | if (br) br->end1.dnum = n_dgns;
848 | /* adjust the branch's position on the list */
849 | insert_branch(br, TRUE);
850 | }
851 | }
852 | }
853 | /*
854 | * I hate hardwiring these names. :-(
855 | */
856 | quest_dnum = dname_to_dnum("The Quest");
857 | sokoban_dnum = dname_to_dnum("Sokoban");
858 | mines_dnum = dname_to_dnum("The Gnomish Mines");
859 | tower_dnum = dname_to_dnum("Vlad's Tower");
860 |
861 | /* one special fixup for dummy surface level */
862 | if ((x = find_level("dummy")) != 0) {
863 | i = x->dlevel.dnum;
864 | /* the code above puts earth one level above dungeon level #1,
865 | making the dummy level overlay level 1; but the whole reason
866 | for having the dummy level is to make earth have depth -1
867 | instead of 0, so adjust the start point to shift endgame up */
868 | if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start)
869 | dungeons[i].depth_start -= 1;
870 | /* TO DO: strip "dummy" out all the way here,
871 | so that it's hidden from <ctrl/O> feedback. */
872 | }
873 |
874 | #ifdef DEBUG
875 | dumpit();
876 | #endif
877 | }
878 |
879 | xchar
880 | dunlev(lev) /* return the level number for lev in *this* dungeon */
881 | d_level *lev;
882 | {
883 | return(lev->dlevel);
884 | }
885 |
886 | xchar
887 | dunlevs_in_dungeon(lev) /* return the lowest level number for *this* dungeon*/
888 | d_level *lev;
889 | {
890 | return(dungeons[lev->dnum].num_dunlevs);
891 | }
892 |
893 | xchar
894 | deepest_lev_reached(noquest) /* return the lowest level explored in the game*/
895 | boolean noquest;
896 | {
897 | /* this function is used for three purposes: to provide a factor
898 | * of difficulty in monster generation; to provide a factor of
899 | * difficulty in experience calculations (botl.c and end.c); and
900 | * to insert the deepest level reached in the game in the topten
901 | * display. the 'noquest' arg switch is required for the latter.
902 | *
903 | * from the player's point of view, going into the Quest is _not_
904 | * going deeper into the dungeon -- it is going back "home", where
905 | * the dungeon starts at level 1. given the setup in dungeon.def,
906 | * the depth of the Quest (thought of as starting at level 1) is
907 | * never lower than the level of entry into the Quest, so we exclude
908 | * the Quest from the topten "deepest level reached" display
909 | * calculation. _However_ the Quest is a difficult dungeon, so we
910 | * include it in the factor of difficulty calculations.
911 | */
912 | register int i;
913 | d_level tmp;
914 | register schar ret = 0;
915 |
916 | for(i = 0; i < n_dgns; i++) {
917 | if((tmp.dlevel = dungeons[i].dunlev_ureached) == 0) continue;
918 | if(!strcmp(dungeons[i].dname, "The Quest") && noquest) continue;
919 |
920 | tmp.dnum = i;
921 | if(depth(&tmp) > ret) ret = depth(&tmp);
922 | }
923 | return((xchar) ret);
924 | }
925 |
926 | /* return a bookkeeping level number for purpose of comparisons and
927 | * save/restore */
928 | xchar
929 | ledger_no(lev)
930 | d_level *lev;
931 | {
932 | return((xchar)(lev->dlevel + dungeons[lev->dnum].ledger_start));
933 | }
934 |
935 | /*
936 | * The last level in the bookkeeping list of level is the bottom of the last
937 | * dungeon in the dungeons[] array.
938 | *
939 | * Maxledgerno() -- which is the max number of levels in the bookkeeping
940 | * list, should not be confused with dunlevs_in_dungeon(lev) -- which
941 | * returns the max number of levels in lev's dungeon, and both should
942 | * not be confused with deepest_lev_reached() -- which returns the lowest
943 | * depth visited by the player.
944 | */
945 | xchar
946 | maxledgerno()
947 | {
948 | return (xchar) (dungeons[n_dgns-1].ledger_start +
949 | dungeons[n_dgns-1].num_dunlevs);
950 | }
951 |
952 | /* return the dungeon that this ledgerno exists in */
953 | xchar
954 | ledger_to_dnum(ledgerno)
955 | xchar ledgerno;
956 | {
957 | register int i;
958 |
959 | /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */
960 | for (i = 0; i < n_dgns; i++)
961 | if (dungeons[i].ledger_start < ledgerno &&
962 | ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs)
963 | return (xchar)i;
964 |
965 | panic("level number out of range [ledger_to_dnum(%d)]", (int)ledgerno);
966 | /*NOT REACHED*/
967 | return (xchar)0;
968 | }
969 |
970 | /* return the level of the dungeon this ledgerno exists in */
971 | xchar
972 | ledger_to_dlev(ledgerno)
973 | xchar ledgerno;
974 | {
975 | return((xchar)(ledgerno - dungeons[ledger_to_dnum(ledgerno)].ledger_start));
976 | }
977 |
978 | #endif /* OVL1 */
979 | #ifdef OVL0
980 |
981 | /* returns the depth of a level, in floors below the surface */
982 | /* (note levels in different dungeons can have the same depth). */
983 | schar
984 | depth(lev)
985 | d_level *lev;
986 | {
987 | return((schar)( dungeons[lev->dnum].depth_start + lev->dlevel - 1));
988 | }
989 |
990 | boolean
991 | on_level(lev1, lev2) /* are "lev1" and "lev2" actually the same? */
992 | d_level *lev1, *lev2;
993 | {
994 | return((boolean)((lev1->dnum == lev2->dnum) && (lev1->dlevel == lev2->dlevel)));
995 | }
996 |
997 | #endif /* OVL0 */
998 | #ifdef OVL1
999 |
1000 | /* is this level referenced in the special level chain? */
1001 | s_level *
1002 | Is_special(lev)
1003 | d_level *lev;
1004 | {
1005 | s_level *levtmp;
1006 |
1007 | for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
1008 | if (on_level(lev, &levtmp->dlevel)) return(levtmp);
1009 |
1010 | return((s_level *)0);
1011 | }
1012 |
1013 | /*
1014 | * Is this a multi-dungeon branch level? If so, return a pointer to the
1015 | * branch. Otherwise, return null.
1016 | */
1017 | branch *
1018 | Is_branchlev(lev)
1019 | d_level *lev;
1020 | {
1021 | branch *curr;
1022 |
1023 | for (curr = branches; curr; curr = curr->next) {
1024 | if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
1025 | return curr;
1026 | }
1027 | return (branch *) 0;
1028 | }
1029 |
1030 | /* goto the next level (or appropriate dungeon) */
1031 | void
1032 | next_level(at_stairs)
1033 | boolean at_stairs;
1034 | {
1035 | if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1036 | /* Taking a down dungeon branch. */
1037 | goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1038 | } else {
1039 | /* Going down a stairs or jump in a trap door. */
1040 | d_level newlevel;
1041 |
1042 | newlevel.dnum = u.uz.dnum;
1043 | newlevel.dlevel = u.uz.dlevel + 1;
1044 | goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
1045 | }
1046 | }
1047 |
1048 | /* goto the previous level (or appropriate dungeon) */
1049 | void
1050 | prev_level(at_stairs)
1051 | boolean at_stairs;
1052 | {
1053 | if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
1054 | /* Taking an up dungeon branch. */
1055 | /* KMH -- Upwards branches are okay if not level 1 */
1056 | /* (Just make sure it doesn't go above depth 1) */
1057 | if(!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet) done(ESCAPED);
1058 | else goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
1059 | } else {
1060 | /* Going up a stairs or rising through the ceiling. */
1061 | d_level newlevel;
1062 | newlevel.dnum = u.uz.dnum;
1063 | newlevel.dlevel = u.uz.dlevel - 1;
1064 | goto_level(&newlevel, at_stairs, FALSE, FALSE);
1065 | }
1066 | }
1067 |
1068 | void
1069 | u_on_newpos(x, y)
1070 | int x, y;
1071 | {
1072 | u.ux = x;
1073 | u.uy = y;
1074 | #ifdef CLIPPING
1075 | cliparound(u.ux, u.uy);
1076 | #endif
1077 | #ifdef STEED
1078 | /* ridden steed always shares hero's location */
1079 | if (u.usteed) u.usteed->mx = u.ux, u.usteed->my = u.uy;
1080 | #endif
1081 | }
1082 |
1083 | void
1084 | u_on_sstairs() { /* place you on the special staircase */
1085 |
1086 | if (sstairs.sx) {
1087 | u_on_newpos(sstairs.sx, sstairs.sy);
1088 | } else {
1089 | /* code stolen from goto_level */
1090 | int trycnt = 0;
1091 | xchar x, y;
1092 | #ifdef DEBUG
1093 | pline("u_on_sstairs: picking random spot");
1094 | #endif
1095 | #define badspot(x,y) ((levl[x][y].typ != ROOM && levl[x][y].typ != CORR) || MON_AT(x, y))
1096 | do {
1097 | x = rnd(COLNO-1);
1098 | y = rn2(ROWNO);
1099 | if (!badspot(x, y)) {
1100 | u_on_newpos(x, y);
1101 | return;
1102 | }
1103 | } while (++trycnt <= 500);
1104 | panic("u_on_sstairs: could not relocate player!");
1105 | #undef badspot
1106 | }
1107 | }
1108 |
1109 | void
1110 | u_on_upstairs() /* place you on upstairs (or special equivalent) */
1111 | {
1112 | if (xupstair) {
1113 | u_on_newpos(xupstair, yupstair);
1114 | } else
1115 | u_on_sstairs();
1116 | }
1117 |
1118 | void
1119 | u_on_dnstairs() /* place you on dnstairs (or special equivalent) */
1120 | {
1121 | if (xdnstair) {
1122 | u_on_newpos(xdnstair, ydnstair);
1123 | } else
1124 | u_on_sstairs();
1125 | }
1126 |
1127 | boolean
1128 | On_stairs(x, y)
1129 | xchar x, y;
1130 | {
1131 | return((boolean)((x == xupstair && y == yupstair) ||
1132 | (x == xdnstair && y == ydnstair) ||
1133 | (x == xdnladder && y == ydnladder) ||
1134 | (x == xupladder && y == yupladder) ||
1135 | (x == sstairs.sx && y == sstairs.sy)));
1136 | }
1137 |
1138 | boolean
1139 | Is_botlevel(lev)
1140 | d_level *lev;
1141 | {
1142 | return((boolean)(lev->dlevel == dungeons[lev->dnum].num_dunlevs));
1143 | }
1144 |
1145 | boolean
1146 | Can_dig_down(lev)
1147 | d_level *lev;
1148 | {
1149 | return((boolean)(!level.flags.hardfloor
1150 | && !Is_botlevel(lev) && !Invocation_lev(lev)));
1151 | }
1152 |
1153 | /*
1154 | * Like Can_dig_down (above), but also allows falling through on the
1155 | * stronghold level. Normally, the bottom level of a dungeon resists
1156 | * both digging and falling.
1157 | */
1158 | boolean
1159 | Can_fall_thru(lev)
1160 | d_level *lev;
1161 | {
1162 | return((boolean)(Can_dig_down(lev) || Is_stronghold(lev)));
1163 | }
1164 |
1165 | /*
1166 | * True if one can rise up a level (e.g. cursed gain level).
1167 | * This happens on intermediate dungeon levels or on any top dungeon
1168 | * level that has a stairwell style branch to the next higher dungeon.
1169 | * Checks for amulets and such must be done elsewhere.
1170 | */
1171 | boolean
1172 | Can_rise_up(x, y, lev)
1173 | int x, y;
1174 | d_level *lev;
1175 | {
1176 | /* can't rise up from inside the top of the Wizard's tower */
1177 | /* KMH -- or in sokoban */
1178 | if (In_endgame(lev) || In_sokoban(lev) ||
1179 | (Is_wiz1_level(lev) && In_W_tower(x, y, lev)))
1180 | return FALSE;
1181 | return (boolean)(lev->dlevel > 1 ||
1182 | (dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 &&
1183 | sstairs.sx && sstairs.up));
1184 | }
1185 |
1186 | /*
1187 | * It is expected that the second argument of get_level is a depth value,
1188 | * either supplied by the user (teleport control) or randomly generated.
1189 | * But more than one level can be at the same depth. If the target level
1190 | * is "above" the present depth location, get_level must trace "up" from
1191 | * the player's location (through the ancestors dungeons) the dungeon
1192 | * within which the target level is located. With only one exception
1193 | * which does not pass through this routine (see level_tele), teleporting
1194 | * "down" is confined to the current dungeon. At present, level teleport
1195 | * in dungeons that build up is confined within them.
1196 | */
1197 | void
1198 | get_level(newlevel, levnum)
1199 | d_level *newlevel;
1200 | int levnum;
1201 | {
1202 | branch *br;
1203 | xchar dgn = u.uz.dnum;
1204 |
1205 | if (levnum <= 0) {
1206 | /* can only currently happen in endgame */
1207 | levnum = u.uz.dlevel;
1208 | } else if (levnum > dungeons[dgn].depth_start
1209 | + dungeons[dgn].num_dunlevs - 1) {
1210 | /* beyond end of dungeon, jump to last level */
1211 | levnum = dungeons[dgn].num_dunlevs;
1212 | } else {
1213 | /* The desired level is in this dungeon or a "higher" one. */
1214 |
1215 | /*
1216 | * Branch up the tree until we reach a dungeon that contains the
1217 | * levnum.
1218 | */
1219 | if (levnum < dungeons[dgn].depth_start) {
1220 |
1221 | do {
1222 | /*
1223 | * Find the parent dungeon of this dungeon.
1224 | *
1225 | * This assumes that end2 is always the "child" and it is
1226 | * unique.
1227 | */
1228 | for (br = branches; br; br = br->next)
1229 | if (br->end2.dnum == dgn) break;
1230 | if (!br)
1231 | panic("get_level: can't find parent dungeon");
1232 |
1233 | dgn = br->end1.dnum;
1234 | } while (levnum < dungeons[dgn].depth_start);
1235 | }
1236 |
1237 | /* We're within the same dungeon; calculate the level. */
1238 | levnum = levnum - dungeons[dgn].depth_start + 1;
1239 | }
1240 |
1241 | newlevel->dnum = dgn;
1242 | newlevel->dlevel = levnum;
1243 | }
1244 |
1245 | #endif /* OVL1 */
1246 | #ifdef OVL0
1247 |
1248 | boolean
1249 | In_quest(lev) /* are you in the quest dungeon? */
1250 | d_level *lev;
1251 | {
1252 | return((boolean)(lev->dnum == quest_dnum));
1253 | }
1254 |
1255 | #endif /* OVL0 */
1256 | #ifdef OVL1
1257 |
1258 | boolean
1259 | In_mines(lev) /* are you in the mines dungeon? */
1260 | d_level *lev;
1261 | {
1262 | return((boolean)(lev->dnum == mines_dnum));
1263 | }
1264 |
1265 | /*
1266 | * Return the branch for the given dungeon.
1267 | *
1268 | * This function assumes:
1269 | * + This is not called with "Dungeons of Doom".
1270 | * + There is only _one_ branch to a given dungeon.
1271 | * + Field end2 is the "child" dungeon.
1272 | */
1273 | branch *
1274 | dungeon_branch(s)
1275 | const char *s;
1276 | {
1277 | branch *br;
1278 | xchar dnum;
1279 |
1280 | dnum = dname_to_dnum(s);
1281 |
1282 | /* Find the branch that connects to dungeon i's branch. */
1283 | for (br = branches; br; br = br->next)
1284 | if (br->end2.dnum == dnum) break;
1285 |
1286 | if (!br) panic("dgn_entrance: can't find entrance to %s", s);
1287 |
1288 | return br;
1289 | }
1290 |
1291 | /*
1292 | * This returns true if the hero is on the same level as the entrance to
1293 | * the named dungeon.
1294 | *
1295 | * Called from do.c and mklev.c.
1296 | *
1297 | * Assumes that end1 is always the "parent".
1298 | */
1299 | boolean
1300 | at_dgn_entrance(s)
1301 | const char *s;
1302 | {
1303 | branch *br;
1304 |
1305 | br = dungeon_branch(s);
1306 | return((boolean)(on_level(&u.uz, &br->end1) ? TRUE : FALSE));
1307 | }
1308 |
1309 | boolean
1310 | In_V_tower(lev) /* is `lev' part of Vlad's tower? */
1311 | d_level *lev;
1312 | {
1313 | return((boolean)(lev->dnum == tower_dnum));
1314 | }
1315 |
1316 | boolean
1317 | On_W_tower_level(lev) /* is `lev' a level containing the Wizard's tower? */
1318 | d_level *lev;
1319 | {
1320 | return (boolean)(Is_wiz1_level(lev) ||
1321 | Is_wiz2_level(lev) ||
1322 | Is_wiz3_level(lev));
1323 | }
1324 |
1325 | boolean
1326 | In_W_tower(x, y, lev) /* is <x,y> of `lev' inside the Wizard's tower? */
1327 | int x, y;
1328 | d_level *lev;
1329 | {
1330 | if (!On_W_tower_level(lev)) return FALSE;
1331 | /*
1332 | * Both of the exclusion regions for arriving via level teleport
1333 | * (from above or below) define the tower's boundary.
1334 | * assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} );
1335 | */
1336 | if (dndest.nlx > 0)
1337 | return (boolean)within_bounded_area(x, y, dndest.nlx, dndest.nly,
1338 | dndest.nhx, dndest.nhy);
1339 | else
1340 | impossible("No boundary for Wizard's Tower?");
1341 | return FALSE;
1342 | }
1343 |
1344 | #endif /* OVL1 */
1345 | #ifdef OVL0
1346 |
1347 | boolean
1348 | In_hell(lev) /* are you in one of the Hell levels? */
1349 | d_level *lev;
1350 | {
1351 | return((boolean)(dungeons[lev->dnum].flags.hellish));
1352 | }
1353 |
1354 | #endif /* OVL0 */
1355 | #ifdef OVL1
1356 |
1357 | void
1358 | find_hell(lev) /* sets *lev to be the gateway to Gehennom... */
1359 | d_level *lev;
1360 | {
1361 | lev->dnum = valley_level.dnum;
1362 | lev->dlevel = 1;
1363 | }
1364 |
1365 | void
1366 | goto_hell(at_stairs, falling) /* go directly to hell... */
1367 | boolean at_stairs, falling;
1368 | {
1369 | d_level lev;
1370 |
1371 | find_hell(&lev);
1372 | goto_level(&lev, at_stairs, falling, FALSE);
1373 | }
1374 |
1375 | void
1376 | assign_level(dest, src) /* equivalent to dest = source */
1377 | d_level *dest, *src;
1378 | {
1379 | dest->dnum = src->dnum;
1380 | dest->dlevel = src->dlevel;
1381 | }
1382 |
1383 | void
1384 | assign_rnd_level(dest, src, range) /* dest = src + rn1(range) */
1385 | d_level *dest, *src;
1386 | int range;
1387 | {
1388 | dest->dnum = src->dnum;
1389 | dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range)) ;
1390 |
1391 | if(dest->dlevel > dunlevs_in_dungeon(dest))
1392 | dest->dlevel = dunlevs_in_dungeon(dest);
1393 | else if(dest->dlevel < 1)
1394 | dest->dlevel = 1;
1395 | }
1396 |
1397 | #endif /* OVL1 */
1398 | #ifdef OVL0
1399 |
1400 | int
1401 | induced_align(pct)
1402 | int pct;
1403 | {
1404 | s_level *lev = Is_special(&u.uz);
1405 | aligntyp al;
1406 |
1407 | if (lev && lev->flags.align)
1408 | if(rn2(100) < pct) return(lev->flags.align);
1409 |
1410 | if(dungeons[u.uz.dnum].flags.align)
1411 | if(rn2(100) < pct) return(dungeons[u.uz.dnum].flags.align);
1412 |
1413 | al = rn2(3) - 1;
1414 | return(Align2amask(al));
1415 | }
1416 |
1417 | #endif /* OVL0 */
1418 | #ifdef OVL1
1419 |
1420 | boolean
1421 | Invocation_lev(lev)
1422 | d_level *lev;
1423 | {
1424 | return((boolean)(In_hell(lev) &&
1425 | lev->dlevel == (dungeons[lev->dnum].num_dunlevs - 1)));
1426 | }
1427 |
1428 | /* use instead of depth() wherever a degree of difficulty is made
1429 | * dependent on the location in the dungeon (eg. monster creation).
1430 | */
1431 | xchar
1432 | level_difficulty()
1433 | {
1434 | if (In_endgame(&u.uz))
1435 | return((xchar)(depth(&sanctum_level) + u.ulevel/2));
1436 | else
1437 | if (u.uhave.amulet)
1438 | return(deepest_lev_reached(FALSE));
1439 | else
1440 | return((xchar) depth(&u.uz));
1441 | }
1442 |
1443 | /* Take one word and try to match it to a level.
1444 | * Recognized levels are as shown by print_dungeon().
1445 | */
1446 | schar
1447 | lev_by_name(nam)
1448 | const char *nam;
1449 | {
1450 | schar lev = 0;
1451 | s_level *slev;
1452 | d_level dlev;
1453 | const char *p;
1454 | int idx, idxtoo;
1455 | char buf[BUFSZ];
1456 |
1457 | /* allow strings like "the oracle level" to find "oracle" */
1458 | if (!strncmpi(nam, "the ", 4)) nam += 4;
1459 | if ((p = strstri(nam, " level")) != 0 && p == eos((char*)nam) - 6) {
1460 | nam = strcpy(buf, nam);
1461 | *(eos(buf) - 6) = '\0';
1462 | }
1463 | /* hell is the old name, and wouldn't match; gehennom would match its
1464 | branch, yielding the castle level instead of the valley of the dead */
1465 | if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) {
1466 | if (In_V_tower(&u.uz)) nam = " to Vlad's tower"; /* branch to... */
1467 | else nam = "valley";
1468 | }
1469 |
1470 | if ((slev = find_level(nam)) != 0) {
1471 | dlev = slev->dlevel;
1472 | idx = ledger_no(&dlev);
1473 | if ((dlev.dnum == u.uz.dnum ||
1474 | /* within same branch, or else main dungeon <-> gehennom */
1475 | (u.uz.dnum == valley_level.dnum &&
1476 | dlev.dnum == medusa_level.dnum) ||
1477 | (u.uz.dnum == medusa_level.dnum &&
1478 | dlev.dnum == valley_level.dnum)) &&
1479 | ( /* either wizard mode or else seen and not forgotten */
1480 | #ifdef WIZARD
1481 | wizard ||
1482 | #endif
1483 | (level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED)) {
1484 | lev = depth(&slev->dlevel);
1485 | }
1486 | } else { /* not a specific level; try branch names */
1487 | idx = find_branch(nam, (struct proto_dungeon *)0);
1488 | /* "<branch> to Xyzzy" */
1489 | if (idx < 0 && (p = strstri(nam, " to ")) != 0)
1490 | idx = find_branch(p + 4, (struct proto_dungeon *)0);
1491 |
1492 | if (idx >= 0) {
1493 | idxtoo = (idx >> 8) & 0x00FF;
1494 | idx &= 0x00FF;
1495 | if ( /* either wizard mode, or else _both_ sides of branch seen */
1496 | #ifdef WIZARD
1497 | wizard ||
1498 | #endif
1499 | ((level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED &&
1500 | (level_info[idxtoo].flags & (FORGOTTEN|VISITED)) == VISITED)) {
1501 | if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo;
1502 | dlev.dnum = ledger_to_dnum(idx);
1503 | dlev.dlevel = ledger_to_dlev(idx);
1504 | lev = depth(&dlev);
1505 | }
1506 | }
1507 | }
1508 | return lev;
1509 | }
1510 |
1511 |
1512 | #ifdef WIZARD
1513 |
1514 | /* Convert a branch type to a string usable by print_dungeon(). */
1515 | STATIC_OVL const char *
1516 | br_string(type)
1517 | int type;
1518 | {
1519 | switch (type) {
1520 | case BR_PORTAL: return "Portal";
1521 | case BR_NO_END1: return "Connection";
1522 | case BR_NO_END2: return "One way stair";
1523 | case BR_STAIR: return "Stair";
1524 | }
1525 | return " (unknown)";
1526 | }
1527 |
1528 | /* Print all child branches between the lower and upper bounds. */
1529 | STATIC_OVL void
1530 | print_branch(win, dnum, lower_bound, upper_bound)
1531 | winid win;
1532 | int dnum;
1533 | int lower_bound;
1534 | int upper_bound;
1535 | {
1536 | branch *br;
1537 | char buf[BUFSZ];
1538 |
1539 | /* This assumes that end1 is the "parent". */
1540 | for (br = branches; br; br = br->next) {
1541 | if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel &&
1542 | br->end1.dlevel <= upper_bound) {
1543 | Sprintf(buf," %s to %s: %d",
1544 | br_string(br->type),
1545 | dungeons[br->end2.dnum].dname,
1546 | depth(&br->end1));
1547 | putstr(win, 0, buf);
1548 | }
1549 | }
1550 | }
1551 |
1552 | /* Print available dungeon information. */
1553 | void
1554 | print_dungeon()
1555 | {
1556 | int i, last_level, nlev;
1557 | char buf[BUFSZ];
1558 | boolean first;
1559 | s_level *slev;
1560 | dungeon *dptr;
1561 | branch *br;
1562 | winid win = create_nhwindow(NHW_MENU);
1563 |
1564 | for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
1565 | nlev = dptr->num_dunlevs;
1566 | if (nlev > 1)
1567 | Sprintf(buf, "%s: levels %d to %d", dptr->dname, dptr->depth_start,
1568 | dptr->depth_start + nlev - 1);
1569 | else
1570 | Sprintf(buf, "%s: level %d", dptr->dname, dptr->depth_start);
1571 |
1572 | /* Most entrances are uninteresting. */
1573 | if (dptr->entry_lev != 1) {
1574 | if (dptr->entry_lev == nlev)
1575 | Strcat(buf, ", entrance from below");
1576 | else
1577 | Sprintf(eos(buf), ", entrance on %d",
1578 | dptr->depth_start + dptr->entry_lev - 1);
1579 | }
1580 | putstr(win, 0, buf);
1581 |
1582 | /*
1583 | * Circle through the special levels to find levels that are in
1584 | * this dungeon.
1585 | */
1586 | for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
1587 | if (slev->dlevel.dnum != i) continue;
1588 |
1589 | /* print any branches before this level */
1590 | print_branch(win, i, last_level, slev->dlevel.dlevel);
1591 |
1592 | Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel));
1593 | if (Is_stronghold(&slev->dlevel))
1594 | Sprintf(eos(buf), " (tune %s)", tune);
1595 | putstr(win, 0, buf);
1596 |
1597 | last_level = slev->dlevel.dlevel;
1598 | }
1599 | /* print branches after the last special level */
1600 | print_branch(win, i, last_level, MAXLEVEL);
1601 | }
1602 |
1603 | /* Print out floating branches (if any). */
1604 | for (first = TRUE, br = branches; br; br = br->next) {
1605 | if (br->end1.dnum == n_dgns) {
1606 | if (first) {
1607 | putstr(win, 0, "");
1608 | putstr(win, 0, "Floating branches");
1609 | first = FALSE;
1610 | }
1611 | Sprintf(buf, " %s to %s",
1612 | br_string(br->type), dungeons[br->end2.dnum].dname);
1613 | putstr(win, 0, buf);
1614 | }
1615 | }
1616 |
1617 | /* I hate searching for the invocation pos while debugging. -dean */
1618 | if (Invocation_lev(&u.uz)) {
1619 | putstr(win, 0, "");
1620 | Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)",
1621 | inv_pos.x, inv_pos.y, u.ux, u.uy);
1622 | putstr(win, 0, buf);
1623 | }
1624 | /*
1625 | * The following is based on the assumption that the inter-level portals
1626 | * created by the level compiler (not the dungeon compiler) only exist
1627 | * one per level (currently true, of course).
1628 | */
1629 | else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
1630 | || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
1631 | struct trap *trap;
1632 | for (trap = ftrap; trap; trap = trap->ntrap)
1633 | if (trap->ttyp == MAGIC_PORTAL) break;
1634 |
1635 | putstr(win, 0, "");
1636 | if (trap)
1637 | Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)",
1638 | trap->tx, trap->ty, u.ux, u.uy);
1639 | else
1640 | Sprintf(buf, "No portal found.");
1641 | putstr(win, 0, buf);
1642 | }
1643 |
1644 | display_nhwindow(win, TRUE);
1645 | destroy_nhwindow(win);
1646 | }
1647 | #endif /* WIZARD */
1648 |
1649 | #endif /* OVL1 */
1650 |
1651 | /*dungeon.c*/