Logo Search packages:      
Sourcecode: jnethack version File versions  Download package

dungeon.c

/*    SCCS Id: @(#)dungeon.c  3.2   96/06/22    */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"
#include "dgn_file.h"
#include "dlb.h"

#if defined(_MSC_VER) && !defined(WIN32)
#include "../japanese/emalloc.h"
#define alloc(s) emalloc(s)
#endif

#ifdef OVL1

#define DUNGEON_FILE    "dungeon"

#define X_START         "x-start"
#define X_LOCATE  "x-locate"
#define X_GOAL          "x-goal"

struct proto_dungeon {
      struct      tmpdungeon tmpdungeon[MAXDUNGEON];
      struct      tmplevel   tmplevel[LEV_LIMIT];
      s_level *final_lev[LEV_LIMIT];      /* corresponding level pointers */
      struct      tmpbranch  tmpbranch[BRANCH_LIMIT];

      int   start;      /* starting index of current dungeon sp levels */
      int   n_levs;     /* number of tmplevel entries */
      int   n_brs;      /* number of tmpbranch entries */
};

int n_dgns;                   /* number of dungeons (used here,  */
                              /*   and mklev.c)          */
static branch *branches = (branch *) 0;   /* dungeon branch list           */

static void FDECL(Fread, (genericptr_t, int, int, dlb *));
static xchar FDECL(dname_to_dnum, (const char *));
static int FDECL(find_branch, (const char *, struct proto_dungeon *));
static xchar FDECL(parent_dnum, (const char *, struct proto_dungeon *));
static int FDECL(level_range, (XCHAR_P,int,int,int,struct proto_dungeon *,int *));
static xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *));
static int FDECL(correct_branch_type, (struct tmpbranch *));
static branch *FDECL(add_branch, (int, int, struct proto_dungeon *));
static void FDECL(add_level, (s_level *));
static void FDECL(init_level, (int,int,struct proto_dungeon *));
static int FDECL(possible_places, (int, boolean *, struct proto_dungeon *));
static xchar FDECL(pick_level, (boolean *, int));
static boolean FDECL(place_level, (int, struct proto_dungeon *));
#ifdef WIZARD
static const char *FDECL(br_string, (int));
static void FDECL(print_branch, (winid, int, int, int));
#endif

#ifdef DEBUG
#define DD  dungeons[i]
static void NDECL(dumpit);

static void
dumpit()
{
      int   i;
      s_level     *x;
      branch *br;

      for(i = 0; i < n_dgns; i++)  {
          fprintf(stderr, "\n#%d \"%s\" (%s):\n", i,
                        DD.dname, DD.proto);
          fprintf(stderr, "    num_dunlevs %d, dunlev_ureached %d\n",
                        DD.num_dunlevs, DD.dunlev_ureached);
          fprintf(stderr, "    depth_start %d, ledger_start %d\n",
                        DD.depth_start, DD.ledger_start);
          fprintf(stderr, "    flags:%s%s%s\n",
                DD.flags.rogue_like ? " rogue_like" : "",
                DD.flags.maze_like  ? " maze_like"  : "",
                DD.flags.hellish    ? " hellish"    : "");
          getchar();
      }
      fprintf(stderr,"\nSpecial levels:\n");
      for(x = sp_levchn; x; x = x->next) {
          fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs);
          fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel);
          fprintf(stderr, "flags:%s%s%s%s\n",
                x->flags.rogue_like ? " rogue_like" : "",
                x->flags.maze_like  ? " maze_like"  : "",
                x->flags.hellish    ? " hellish"    : "",
                x->flags.town       ? " town"       : "");
          getchar();
      }
      fprintf(stderr,"\nBranches:\n");
      for (br = branches; br; br = br->next) {
          fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n",
            br->id,
            br->type == BR_STAIR ? "stair" :
                br->type == BR_NO_END1 ? "no end1" :
                br->type == BR_NO_END2 ? "no end2" :
                br->type == BR_PORTAL  ? "portal"  :
                                   "unknown",
            br->end1.dnum, br->end1.dlevel,
            br->end2.dnum, br->end2.dlevel,
            br->end1_up ? "end1 up" : "end1 down");
      }
      getchar();
      fprintf(stderr,"\nDone\n");
      getchar();
}
#endif

/* Save the dungeon structures. */
void
save_dungeon(fd, perform_write, free_data)
    int fd;
    boolean perform_write, free_data;
{
    branch *curr, *next;
    int    count;

    if (perform_write) {
      bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns);
      bwrite(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns);
      bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
      bwrite(fd, (genericptr_t) tune, sizeof tune);

      for (count = 0, curr = branches; curr; curr = curr->next)
          count++;
      bwrite(fd, (genericptr_t) &count, sizeof(count));

      for (curr = branches; curr; curr = curr->next)
          bwrite(fd, (genericptr_t) curr, sizeof (branch));

      count = maxledgerno();
      bwrite(fd, (genericptr_t) &count, sizeof count);
      bwrite(fd, (genericptr_t) level_info,
                  (unsigned)count * sizeof (struct linfo));
      bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
    }

    if (free_data) {
      for (curr = branches; curr; curr = next) {
          next = curr->next;
          free((genericptr_t) curr);
      }
      branches = 0;
    }
}

/* Restore the dungeon structures. */
void
restore_dungeon(fd)
    int fd;
{
    branch *curr, *last;
    int    count, i;

    mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns));
    mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns);
    mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
    mread(fd, (genericptr_t) tune, sizeof tune);

    last = branches = (branch *) 0;

    mread(fd, (genericptr_t) &count, sizeof(count));
    for (i = 0; i < count; i++) {
      curr = (branch *) alloc(sizeof(branch));
      mread(fd, (genericptr_t) curr, sizeof(branch));
      curr->next = (branch *) 0;
      if (last)
          last->next = curr;
      else
          branches = curr;
      last = curr;
    }

    mread(fd, (genericptr_t) &count, sizeof(count));
    if (count >= MAXLINFO)
      panic("level information count larger (%d) than allocated size", count);
    mread(fd, (genericptr_t) level_info, (unsigned)count*sizeof(struct linfo));
    mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
}

static void
Fread(ptr, size, nitems, stream)
      genericptr_t      ptr;
      int   size, nitems;
      dlb   *stream;
{
      int cnt;

      if((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
          panic(
 "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.",
              (size * nitems), (size * cnt));
          terminate(EXIT_FAILURE);
      }
}

static xchar
dname_to_dnum(s)
const char  *s;
{
      xchar i;

      for (i = 0; i < n_dgns; i++)
          if (!strcmp(dungeons[i].dname, s)) return i;

      panic("Couldn't resolve dungeon number for name \"%s\".", s);
      /*NOT REACHED*/
      return (xchar)0;
}

s_level *
find_level(s)
      const char *s;
{
      s_level *curr;
      for(curr = sp_levchn; curr; curr = curr->next)
          if (!strcmpi(s, curr->proto)) break;
      return curr;
}

/* Find the branch that links the named dungeon. */
static int
find_branch(s, pd)
      const char *s;          /* dungeon name */
      struct proto_dungeon *pd;
{
      int i;

      if (pd) {
          for (i = 0; i < pd->n_brs; i++)
            if (!strcmp(pd->tmpbranch[i].name, s)) break;
          if (i == pd->n_brs) panic("find_branch: can't find %s", s);
      } else {
          /* support for level tport by name */
          branch *br;
          const char *dnam;

          for (br = branches; br; br = br->next) {
            dnam = dungeons[br->end2.dnum].dname;
            if (!strcmpi(dnam, s) ||
                  (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s)))
                break;
          }
          i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1;
      }
      return i;
}


/*
 * Find the "parent" by searching the prototype branch list for the branch
 * listing, then figuring out to which dungeon it belongs.
 */
static xchar
parent_dnum(s, pd)
const char     *s;      /* dungeon name */
struct proto_dungeon *pd;
{
      int   i;
      xchar pdnum;

      i = find_branch(s, pd);
      /*
       * Got branch, now find parent dungeon.  Stop if we have reached
       * "this" dungeon (if we haven't found it by now it is an error).
       */
      for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++)
          if ((i -= pd->tmpdungeon[pdnum].branches) < 0)
            return(pdnum);

      panic("parent_dnum: couldn't resolve branch.");
      /*NOT REACHED*/
      return (xchar)0;
}

/*
 * Return a starting point and number of successive positions a level
 * or dungeon entrance can occupy.
 *
 * Note: This follows the acouple (instead of the rcouple) rules for a
 *     negative random component (rand < 0).  These rules are found
 *     in dgn_comp.y.  The acouple [absolute couple] section says that
 *     a negative random component means from the (adjusted) base to the
 *     end of the dungeon.
 */
static int
level_range(dgn, base, rand, chain, pd, adjusted_base)
      xchar dgn;
      int   base, rand, chain;
      struct proto_dungeon *pd;
      int *adjusted_base;
{
      int lmax = dungeons[dgn].num_dunlevs;

      if (chain >= 0) {        /* relative to a special level */
          s_level *levtmp = pd->final_lev[chain];
          if (!levtmp) panic("level_range: empty chain level!");

          base += levtmp->dlevel.dlevel;
      } else {                /* absolute in the dungeon */
          /* from end of dungeon */
          if (base < 0) base = (lmax + base + 1);
      }

      if (base < 1 || base > lmax)
          panic("level_range: base value out of range");

      *adjusted_base = base;

      if (rand == -1) { /* from base to end of dungeon */
          return (lmax - base + 1);
      } else if (rand) {
          /* make sure we don't run off the end of the dungeon */
          return (((base + rand - 1) > lmax) ? lmax-base+1 : rand);
      } /* else only one choice */
      return 1;
}

static xchar
parent_dlevel(s, pd)
      const char  *s;
      struct proto_dungeon *pd;
{
      int i, num, base;

      i = find_branch(s, pd);
      num = level_range(parent_dnum(s, pd), pd->tmpbranch[i].lev.base,
                                    pd->tmpbranch[i].lev.rand,
                                    pd->tmpbranch[i].chain,
                                    pd, &base);
      return (xchar) rn1(num,base);
}

/* Convert from the temporary branch type to the dungeon branch type. */
static int
correct_branch_type(tbr)
    struct tmpbranch *tbr;
{
    switch (tbr->type) {
      case TBR_STAIR:         return BR_STAIR;
      case TBR_NO_UP:         return tbr->up ? BR_NO_END1 : BR_NO_END2;
      case TBR_NO_DOWN: return tbr->up ? BR_NO_END2 : BR_NO_END1;
      case TBR_PORTAL:  return BR_PORTAL;
    }
    impossible("correct_branch_type: unknown branch type");
    return BR_STAIR;
}

/*
 * Add the given branch to the branch list.  The branch list is ordered
 * by end1 dungeon and level followed by end2 dungeon and level.  If
 * extract_first is true, then the branch is already part of the list
 * but needs to be repositioned.
 */
void
insert_branch(new_branch, extract_first)
   branch *new_branch;
   boolean extract_first;
{
    branch *curr, *prev;
    long new_val, curr_val, prev_val;

    if (extract_first) {
      for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next)
          if (curr == new_branch) break;

      if (!curr) panic("insert_branch: not found");
      if (prev)
          prev->next = curr->next;
      else
          branches = curr->next;
    }
    new_branch->next = (branch *) 0;

/* Convert the branch into a unique number so we can sort them. */
#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))

    /*
     * Insert the new branch into the correct place in the branch list.
     */
    prev = (branch *) 0;
    prev_val = -1;
    new_val = branch_val(new_branch);
    for (curr = branches; curr;
                prev_val = curr_val, prev = curr, curr = curr->next) {
      curr_val = branch_val(curr);
      if (prev_val < new_val && new_val <= curr_val) break;
    }
    if (prev) {
      new_branch->next = curr;
      prev->next = new_branch;
    } else {
      new_branch->next = branches;
      branches = new_branch;
    }
}

/* Add a dungeon branch to the branch list. */
static branch *
add_branch(dgn, child_entry_level, pd)
    int dgn;
    int child_entry_level;
    struct proto_dungeon *pd;
{
    static int branch_id = 0;
    int branch_num;
    branch *new_branch;

    branch_num = find_branch(dungeons[dgn].dname,pd);
    new_branch = (branch *) alloc(sizeof(branch));
    new_branch->next = (branch *) 0;
    new_branch->id = branch_id++;
    new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
    new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd);
    new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd);
    new_branch->end2.dnum = dgn;
    new_branch->end2.dlevel = child_entry_level;
    new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE;

    insert_branch(new_branch, FALSE);
    return new_branch;
}

/*
 * Add new level to special level chain.  Insert it in level order with the
 * other levels in this dungeon.  This assumes that we are never given a
 * level that has a dungeon number less than the dungeon number of the
 * last entry.
 */
static void
add_level(new_lev)
    s_level *new_lev;
{
      s_level *prev, *curr;

      prev = (s_level *) 0;
      for (curr = sp_levchn; curr; curr = curr->next) {
          if (curr->dlevel.dnum == new_lev->dlevel.dnum &&
                curr->dlevel.dlevel > new_lev->dlevel.dlevel)
            break;
          prev = curr;
      }
      if (!prev) {
          new_lev->next = sp_levchn;
          sp_levchn = new_lev;
      } else {
          new_lev->next = curr;
          prev->next = new_lev;
      }
}

static void
init_level(dgn, proto_index, pd)
      int dgn, proto_index;
      struct proto_dungeon *pd;
{
      s_level     *new_level;
      struct tmplevel *tlevel = &pd->tmplevel[proto_index];

      pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
#ifdef WIZARD
      if (!wizard)
#endif
          if (tlevel->chance <= rn2(100)) return;

      pd->final_lev[proto_index] = new_level =
                              (s_level *) alloc(sizeof(s_level));
      /* load new level with data */
      Strcpy(new_level->proto, tlevel->name);
      new_level->boneid = tlevel->boneschar;
      new_level->dlevel.dnum = dgn;
      new_level->dlevel.dlevel = 0; /* for now */

      new_level->flags.town = !!(tlevel->flags & TOWN);
      new_level->flags.hellish = !!(tlevel->flags & HELLISH);
      new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
      new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
      new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);

      new_level->rndlevs = tlevel->rndlevs;
      new_level->next    = (s_level *) 0;
}

static int
possible_places(idx, map, pd)
    int idx;            /* prototype index */
    boolean *map; /* array MAXLEVEL+1 in length */
    struct proto_dungeon *pd;
{
    int i, start, count;
    s_level *lev = pd->final_lev[idx];

    /* init level possibilities */
    for (i = 0; i <= MAXLEVEL; i++) map[i] = FALSE;

    /* get base and range and set those entried to true */
    count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base,
                              pd->tmplevel[idx].lev.rand,
                              pd->tmplevel[idx].chain,
                              pd, &start);
    for (i = start; i < start+count; i++)
      map[i] = TRUE;

    /* mark off already placed levels */
    for (i = pd->start; i < idx; i++) {
      if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) {
          map[pd->final_lev[i]->dlevel.dlevel] = FALSE;
          --count;
      }
    }

    return count;
}

/* Pick the nth TRUE entry in the given boolean array. */
static xchar
pick_level(map, nth)
    boolean *map; /* an array MAXLEVEL+1 in size */
    int nth;
{
    int i;
    for (i = 1; i <= MAXLEVEL; i++)
      if (map[i] && !nth--) return (xchar) i;
    panic("pick_level:  ran out of valid levels");
    return 0;
}

#ifdef DDEBUG
static void FDECL(indent,(int));

static void
indent(d)
int d;
{
    while (d-- > 0) fputs("    ", stderr);
}
#endif

/*
 * Place a level.  First, find the possible places on a dungeon map
 * template.  Next pick one.  Then try to place the next level.  If
 * sucessful, we're done.  Otherwise, try another (and another) until
 * all possible places have been tried.  If all possible places have
 * been exausted, return false.
 */
static boolean
place_level(proto_index, pd)
    int proto_index;
    struct proto_dungeon *pd;
{
    boolean map[MAXLEVEL+1];  /* valid levels are 1..MAXLEVEL inclusive */
    s_level *lev;
    int npossible;
#ifdef DDEBUG
    int i;
#endif

    if (proto_index == pd->n_levs) return TRUE; /* at end of proto levels */

    lev = pd->final_lev[proto_index];

    /* No level created for this prototype, goto next. */
    if (!lev) return place_level(proto_index+1, pd);

    npossible = possible_places(proto_index, map, pd);

    for (; npossible; --npossible) {
      lev->dlevel.dlevel = pick_level(map, rn2(npossible));
#ifdef DDEBUG
      indent(proto_index-pd->start);
      fprintf(stderr,"%s: trying %d [ ", lev->proto, lev->dlevel.dlevel);
      for (i = 1; i <= MAXLEVEL; i++)
          if (map[i]) fprintf(stderr,"%d ", i);
      fprintf(stderr,"]\n");
#endif
      if (place_level(proto_index+1, pd)) return TRUE;
      map[lev->dlevel.dlevel] = FALSE;    /* this choice didn't work */
    }
#ifdef DDEBUG
    indent(proto_index-pd->start);
    fprintf(stderr,"%s: failed\n", lev->proto);
#endif
    return FALSE;
}


struct level_map {
      const char *lev_name;
      d_level *lev_spec;
} level_map[] = {
      { "air",    &air_level },
      { "asmodeus",     &asmodeus_level },
      { "astral", &astral_level },
      { "baalz",  &baalzebub_level },
      { "bigroom",      &bigroom_level },
      { "castle", &stronghold_level },
      { "earth",  &earth_level },
      { "fakewiz1",     &portal_level },
      { "fire",   &fire_level },
      { "juiblex",      &juiblex_level },
      { "knox",   &knox_level },
      { "medusa", &medusa_level },
      { "oracle", &oracle_level },
      { "orcus",  &orcus_level },
#ifdef REINCARNATION
      { "rogue",  &rogue_level },
#endif
      { "sanctum",      &sanctum_level },
      { "valley", &valley_level },
      { "water",  &water_level },
      { "wizard1",      &wiz1_level },
      { "wizard2",      &wiz2_level },
      { "wizard3",      &wiz3_level },
      { X_START,  &qstart_level },
      { X_LOCATE, &qlocate_level },
      { X_GOAL,   &nemesis_level },
      { "",       (d_level *)0 }
};

void
init_dungeons()         /* initialize the "dungeon" structs */
{
      dlb   *dgn_file;
      register int i, cl = 0, cb = 0;
      register s_level *x;
      struct proto_dungeon pd;
      struct level_map *lev_map;
      struct version_info vers_info;

      pd.n_levs = pd.n_brs = 0;

      dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
      if (!dgn_file)
          panic("Cannot open dungeon description file \"%s\"!", DUNGEON_FILE);

      /* validate the data's version against the program's version */
      Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file);
      if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
          panic("Dungeon description not valid.");

      /*
       * Read in each dungeon and transfer the results to the internal
       * dungeon arrays.
       */
      sp_levchn = (s_level *) 0;
      Fread((genericptr_t)&n_dgns, sizeof(int), 1, dgn_file);
      if (n_dgns >= MAXDUNGEON)
          panic("init_dungeons: too many dungeons");

      for (i = 0; i < n_dgns; i++) {
          Fread((genericptr_t)&pd.tmpdungeon[i],
                            sizeof(struct tmpdungeon), 1, dgn_file);
#ifdef WIZARD
          if(!wizard)
#endif
            if(pd.tmpdungeon[i].chance && (pd.tmpdungeon[i].chance <= rn2(100))) {
            int j;

            /* skip over any levels or branches */
            for(j = 0; j < pd.tmpdungeon[i].levels; j++)
                Fread((genericptr_t)&pd.tmplevel[cl], sizeof(struct tmplevel),
                                          1, dgn_file);

            for(j = 0; j < pd.tmpdungeon[i].branches; j++)
                Fread((genericptr_t)&pd.tmpbranch[cb],
                              sizeof(struct tmpbranch), 1, dgn_file);
            n_dgns--; i--;
            continue;
            }

          Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name);
          Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname);
          dungeons[i].boneid = pd.tmpdungeon[i].boneschar;

          if(pd.tmpdungeon[i].lev.rand)
            dungeons[i].num_dunlevs = (xchar)rn1(pd.tmpdungeon[i].lev.rand,
                                         pd.tmpdungeon[i].lev.base);
          else dungeons[i].num_dunlevs = (xchar)pd.tmpdungeon[i].lev.base;

          if(!i) {
            dungeons[i].ledger_start = 0;
            dungeons[i].depth_start = 1;
            dungeons[i].dunlev_ureached = 1;
          } else {
            dungeons[i].ledger_start = dungeons[i-1].ledger_start +
                                    dungeons[i-1].num_dunlevs;
            dungeons[i].dunlev_ureached = 0;
          }

          dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH);
          dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE);
          dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE);
          dungeons[i].flags.align = ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4);
          /*
           * Set the entry level for this dungeon.  The pd.tmpdungeon entry
           * value means:
           *            < 0   from bottom (-1 == bottom level)
           *              0   default (top)
           *            > 0   actual level (1 = top)
           *
           * Note that the entry_lev field in the dungeon structure is
           * redundant.  It is used only here and in print_dungeon().
           */
          if (pd.tmpdungeon[i].entry_lev < 0) {
            dungeons[i].entry_lev = dungeons[i].num_dunlevs +
                                    pd.tmpdungeon[i].entry_lev + 1;
            if (dungeons[i].entry_lev <= 0) dungeons[i].entry_lev = 1;
          } else if (pd.tmpdungeon[i].entry_lev > 0) {
            dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
            if (dungeons[i].entry_lev > dungeons[i].num_dunlevs)
                dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
          } else { /* default */
            dungeons[i].entry_lev = 1;    /* defaults to top level */
          }

          if (i) {      /* set depth */
            branch *br;
            schar from_depth;
            boolean from_up;

            br = add_branch(i, dungeons[i].entry_lev, &pd);

            /* Get the depth of the connecting end. */
            if (br->end1.dnum == i) {
                from_depth = depth(&br->end2);
                from_up = !br->end1_up;
            } else {
                from_depth = depth(&br->end1);
                from_up = br->end1_up;
            }

            /*
             * Calculate the depth of the top of the dungeon via
             * its branch.  First, the depth of the entry point:
             *
             *    depth of branch from "parent" dungeon
             *    + -1 or 1 depending on a up or down stair or
             *      0 if portal
             *
             * Followed by the depth of the top of the dungeon:
             *
             *    - (entry depth - 1)
             *
             * We'll say that portals stay on the same depth.
             */
            dungeons[i].depth_start = from_depth
                              + (br->type == BR_PORTAL ? 0 :
                                          (from_up ? -1 : 1))
                              - (dungeons[i].entry_lev - 1);
          }

          /* this is redundant - it should have been flagged by dgn_comp */
          if(dungeons[i].num_dunlevs > MAXLEVEL)
            dungeons[i].num_dunlevs = MAXLEVEL;

          pd.start = pd.n_levs;     /* save starting point */
          pd.n_levs += pd.tmpdungeon[i].levels;
          if (pd.n_levs > LEV_LIMIT)
            panic("init_dungeon: too many special levels");
          /*
           * Read in the prototype special levels.  Don't add generated
           * special levels until they are all placed.
           */
          for(; cl < pd.n_levs; cl++) {
            Fread((genericptr_t)&pd.tmplevel[cl],
                              sizeof(struct tmplevel), 1, dgn_file);
            init_level(i, cl, &pd);
          }
          /*
           * Recursively place the generated levels for this dungeon.  This
           * routine will attempt all possible combinations before giving
           * up.
           */
          if (!place_level(pd.start, &pd))
            panic("init_dungeon:  couldn't place levels");
#ifdef DDEBUG
          fprintf(stderr, "--- end of dungeon %d ---\n", i);
          fflush(stderr);
          getchar();
#endif
          for (; pd.start < pd.n_levs; pd.start++)
            if (pd.final_lev[pd.start]) add_level(pd.final_lev[pd.start]);


          pd.n_brs += pd.tmpdungeon[i].branches;
          if (pd.n_brs > BRANCH_LIMIT)
            panic("init_dungeon: too many branches");
          for(; cb < pd.n_brs; cb++)
            Fread((genericptr_t)&pd.tmpbranch[cb],
                              sizeof(struct tmpbranch), 1, dgn_file);
      }
      (void) dlb_fclose(dgn_file);

      for (i = 0; i < 5; i++) tune[i] = 'A' + rn2(7);
      tune[5] = 0;

      /*
       * Find most of the special levels and dungeons so we can access their
       * locations quickly.
       */
      for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
            x = find_level(lev_map->lev_name);
            if (x) {
                  assign_level(lev_map->lev_spec, &x->dlevel);
                  if (!strncmp(lev_map->lev_name, "x-", 2)) {
                        /* This is where the name substitution on the
                         * levels of the quest dungeon occur.
                         */
                        x->proto[0] = pl_character[0];
                  } else if (lev_map->lev_spec == &knox_level) {
                        branch *br;
                        /*
                         * Kludge to allow floating Knox entrance.  We
                         * specify a floating entrance by the fact that
                         * its entrance (end1) has a bogus dnum, namely
                         * n_dgns.
                         */
                        for (br = branches; br; br = br->next)
                            if (on_level(&br->end2, &knox_level)) break;

                        if (br) br->end1.dnum = n_dgns;
                        /* adjust the branch's position on the list */
                        insert_branch(br, TRUE);
                  }
            }
      }
/*
 *    I hate hardwiring these names. :-(
 */
      quest_dnum = dname_to_dnum("The Quest");
      mines_dnum = dname_to_dnum("The Gnomish Mines");
      tower_dnum = dname_to_dnum("Vlad's Tower");

      /* one special fixup for dummy surface level */
      if ((x = find_level("dummy")) != 0) {
          i = x->dlevel.dnum;
          /* the code above puts earth one level above dungeon level #1,
             making the dummy level overlay level 1; but the whole reason
             for having the dummy level is to make earth have depth -1
             instead of 0, so adjust the start point to shift endgame up */
          if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start)
            dungeons[i].depth_start -= 1;
          /* TO DO: strip "dummy" out all the way here,
             so that it's hidden from <ctrl/O> feedback. */
      }

#ifdef DEBUG
      dumpit();
#endif
}

xchar
dunlev(lev) /* return the level number for lev in *this* dungeon */
d_level     *lev;
{
      return(lev->dlevel);
}

xchar
dunlevs_in_dungeon(lev) /* return the lowest level number for *this* dungeon*/
d_level     *lev;
{
      return(dungeons[lev->dnum].num_dunlevs);
}

xchar
deepest_lev_reached(noquest) /* return the lowest level explored in the game*/
boolean noquest;
{
      /* this function is used for three purposes: to provide a factor
       * of difficulty in monster generation; to provide a factor of
       * difficulty in experience calculations (botl.c and end.c); and
       * to insert the deepest level reached in the game in the topten
       * display.  the 'noquest' arg switch is required for the latter.
       *
       * from the player's point of view, going into the Quest is _not_
       * going deeper into the dungeon -- it is going back "home", where
       * the dungeon starts at level 1.  given the setup in dungeon.def,
       * the depth of the Quest (thought of as starting at level 1) is
       * never lower than the level of entry into the Quest, so we exclude
       * the Quest from the topten "deepest level reached" display
       * calculation.  _However_ the Quest is a difficult dungeon, so we
       * include it in the factor of difficulty calculations.
       */
      register int i;
      d_level tmp;
      register schar ret = 0;

      for(i = 0; i < n_dgns; i++) {
          if((tmp.dlevel = dungeons[i].dunlev_ureached) == 0) continue;
          if(!strcmp(dungeons[i].dname, "The Quest") && noquest) continue;

          tmp.dnum = i;
          if(depth(&tmp) > ret) ret = depth(&tmp);
      }
      return((xchar) ret);
}

/* return a bookkeeping level number for purpose of comparisons and
 * save/restore */
xchar
ledger_no(lev)
d_level     *lev;
{
      return((xchar)(lev->dlevel + dungeons[lev->dnum].ledger_start));
}

/*
 * The last level in the bookkeeping list of level is the bottom of the last
 * dungeon in the dungeons[] array.
 *
 * Maxledgerno() -- which is the max number of levels in the bookkeeping
 * list, should not be confused with dunlevs_in_dungeon(lev) -- which
 * returns the max number of levels in lev's dungeon, and both should
 * not be confused with deepest_lev_reached() -- which returns the lowest
 * depth visited by the player.
 */
xchar
maxledgerno()
{
    return (xchar) (dungeons[n_dgns-1].ledger_start +
                        dungeons[n_dgns-1].num_dunlevs);
}

/* return the dungeon that this ledgerno exists in */
xchar
ledger_to_dnum(ledgerno)
xchar ledgerno;
{
      register int i;

      /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */
      for (i = 0; i < n_dgns; i++)
          if (dungeons[i].ledger_start < ledgerno &&
            ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs)
            return (xchar)i;

      panic("level number out of range [ledger_to_dnum(%d)]", (int)ledgerno);
      /*NOT REACHED*/
      return (xchar)0;
}

/* return the level of the dungeon this ledgerno exists in */
xchar
ledger_to_dlev(ledgerno)
xchar ledgerno;
{
      return((xchar)(ledgerno - dungeons[ledger_to_dnum(ledgerno)].ledger_start));
}

#endif /* OVL1 */
#ifdef OVL0

/* returns the depth of a level, in floors below the surface      */
/* (note levels in different dungeons can have the same depth).   */
schar
depth(lev)
d_level     *lev;
{
      return((schar)( dungeons[lev->dnum].depth_start + lev->dlevel - 1));
}

boolean
on_level(lev1, lev2)    /* are "lev1" and "lev2" actually the same? */
d_level     *lev1, *lev2;
{
      return((boolean)((lev1->dnum == lev2->dnum) && (lev1->dlevel == lev2->dlevel)));
}

#endif /* OVL0 */
#ifdef OVL1

/* is this level referenced in the special level chain? */
s_level *
Is_special(lev)
d_level     *lev;
{
      s_level *levtmp;

      for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
          if (on_level(lev, &levtmp->dlevel)) return(levtmp);

      return((s_level *)0);
}

/*
 * Is this a multi-dungeon branch level?  If so, return a pointer to the
 * branch.  Otherwise, return null.
 */
branch *
Is_branchlev(lev)
      d_level     *lev;
{
      branch *curr;

      for (curr = branches; curr; curr = curr->next) {
          if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
            return curr;
      }
      return (branch *) 0;
}

/* goto the next level (or appropriate dungeon) */
void
next_level(at_stairs )
boolean     at_stairs;
{
      if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
            /* Taking a down dungeon branch. */
            goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
      } else {
            /* Going down a stairs or jump in a trap door. */
            d_level     newlevel;

            newlevel.dnum = u.uz.dnum;
            newlevel.dlevel = u.uz.dlevel + 1;
            goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
      }
}

/* goto the previous level (or appropriate dungeon) */
void
prev_level(at_stairs)
boolean     at_stairs;
{
      if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
            /* Taking an up dungeon branch. */
            if(!u.uz.dnum  && !u.uhave.amulet) done(ESCAPED);
            else goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
      } else {
            /* Going up a stairs or rising through the ceiling. */
            d_level     newlevel;
            newlevel.dnum = u.uz.dnum;
            newlevel.dlevel = u.uz.dlevel - 1;
            goto_level(&newlevel, at_stairs, FALSE, FALSE);
      }
}

void
u_on_newpos(x, y)
int x, y;
{
      u.ux = x;
      u.uy = y;
#ifdef CLIPPING
      cliparound(u.ux, u.uy);
#endif
}

void
u_on_sstairs() {  /* place you on the special staircase */

      if (sstairs.sx) {
          u_on_newpos(sstairs.sx, sstairs.sy);
      } else {
          /* code stolen from goto_level */
          int trycnt = 0;
          xchar x, y;
#ifdef DEBUG
          pline("u_on_sstairs: picking random spot");
#endif
#define badspot(x,y) ((levl[x][y].typ != ROOM && levl[x][y].typ != CORR) || MON_AT(x, y))
          do {
            x = rnd(COLNO-1);
            y = rn2(ROWNO);
            if (!badspot(x, y)) {
                u_on_newpos(x, y);
                return;
            }
          } while (++trycnt <= 500);
          panic("u_on_sstairs: could not relocate player!");
#undef badspot
      }
}

void
u_on_upstairs()   /* place you on upstairs (or special equivalent) */
{
      if (xupstair) {
            u_on_newpos(xupstair, yupstair);
      } else
            u_on_sstairs();
}

void
u_on_dnstairs()   /* place you on dnstairs (or special equivalent) */
{
      if (xdnstair) {
            u_on_newpos(xdnstair, ydnstair);
      } else
            u_on_sstairs();
}

boolean
On_stairs(x, y)
xchar x, y;
{
      return((boolean)((x == xupstair && y == yupstair) ||
             (x == xdnstair && y == ydnstair) ||
             (x == xdnladder && y == ydnladder) ||
             (x == xupladder && y == yupladder) ||
             (x == sstairs.sx && y == sstairs.sy)));
}

boolean
Is_botlevel(lev)
d_level *lev;
{
      return((boolean)(lev->dlevel == dungeons[lev->dnum].num_dunlevs));
}

boolean
Can_dig_down(lev)
d_level *lev;
{
      return((boolean)(!level.flags.hardfloor
          && !Is_botlevel(lev) && !Invocation_lev(lev)));
}

/*
 * Like Can_dig_down (above), but also allows falling through on the
 * stronghold level.  Normally, the bottom level of a dungeon resists
 * both digging and falling.
 */
boolean
Can_fall_thru(lev)
d_level *lev;
{
      return((boolean)(Can_dig_down(lev) || Is_stronghold(lev)));
}

/*
 * True if one can rise up a level (e.g. cursed gain level).
 * This happens on intermediate dungeon levels or on any top dungeon
 * level that has a stairwell style branch to the next higher dungeon.
 * Checks for amulets and such must be done elsewhere.
 */
boolean
Can_rise_up(x, y, lev)
int   x, y;
d_level *lev;
{
    /* can't rise up from inside the top of the Wizard's tower */
    if (In_endgame(lev) || (Is_wiz1_level(lev) && In_W_tower(x, y, lev)))
      return FALSE;
    return (boolean)(lev->dlevel > 1 ||
            (dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 &&
             sstairs.sx && sstairs.up));
}

/*
 * It is expected that the second argument of get_level is a depth value,
 * either supplied by the user (teleport control) or randomly generated.
 * But more than one level can be at the same depth.  If the target level
 * is "above" the present depth location, get_level must trace "up" from
 * the player's location (through the ancestors dungeons) the dungeon
 * within which the target level is located.  With only one exception
 * which does not pass through this routine (see level_tele), teleporting
 * "down" is confined to the current dungeon.  At present, level teleport
 * in dungeons that build up is confined within them.
 */
void
get_level(newlevel, levnum)
d_level *newlevel;
int levnum;
{
      branch *br;
      xchar dgn = u.uz.dnum;

      if (levnum <= 0) {
          /* can only currently happen in endgame */
          levnum = u.uz.dlevel;
      } else if (levnum > dungeons[dgn].depth_start
                      + dungeons[dgn].num_dunlevs - 1) {
          /* beyond end of dungeon, jump to last level */
          levnum = dungeons[dgn].num_dunlevs;
      } else {
          /* The desired level is in this dungeon or a "higher" one. */

          /*
           * Branch up the tree until we reach a dungeon that contains the
           * levnum.
           */
          if (levnum < dungeons[dgn].depth_start) {

            do {
                /*
                 * Find the parent dungeon of this dungeon.
                 *
                 * This assumes that end2 is always the "child" and it is
                 * unique.
                 */
                for (br = branches; br; br = br->next)
                  if (br->end2.dnum == dgn) break;
                if (!br)
                  panic("get_level: can't find parent dungeon");

                dgn = br->end1.dnum;
            } while (levnum < dungeons[dgn].depth_start);
          }

          /* We're within the same dungeon; calculate the level. */
          levnum = levnum - dungeons[dgn].depth_start + 1;
      }

      newlevel->dnum = dgn;
      newlevel->dlevel = levnum;
}

#endif /* OVL1 */
#ifdef OVL0

boolean
In_quest(lev)     /* are you in the quest dungeon? */
d_level *lev;
{
      return((boolean)(lev->dnum == quest_dnum));
}

#endif /* OVL0 */
#ifdef OVL1

boolean
In_mines(lev)     /* are you in the mines dungeon? */
d_level     *lev;
{
      return((boolean)(lev->dnum == mines_dnum));
}

/*
 * Return the branch for the given dungeon.
 *
 * This function assumes:
 *    + This is not called with "Dungeons of Doom".
 *    + There is only _one_ branch to a given dungeon.
 *    + Field end2 is the "child" dungeon.
 */
branch *
dungeon_branch(s)
    const char *s;
{
    branch *br;
    xchar  dnum;

    dnum = dname_to_dnum(s);

    /* Find the branch that connects to dungeon i's branch. */
    for (br = branches; br; br = br->next)
      if (br->end2.dnum == dnum) break;

    if (!br) panic("dgn_entrance: can't find entrance to %s", s);

    return br;
}

/*
 * This returns true if the hero is on the same level as the entrance to
 * the named dungeon.
 *
 * Called from do.c and mklev.c.
 *
 * Assumes that end1 is always the "parent".
 */
boolean
at_dgn_entrance(s)
    const char *s;
{
    branch *br;

    br = dungeon_branch(s);
    return((boolean)(on_level(&u.uz, &br->end1) ? TRUE : FALSE));
}

boolean
In_V_tower(lev)   /* is `lev' part of Vlad's tower? */
d_level     *lev;
{
      return((boolean)(lev->dnum == tower_dnum));
}

boolean
On_W_tower_level(lev)   /* is `lev' a level containing the Wizard's tower? */
d_level     *lev;
{
      return (boolean)(Is_wiz1_level(lev) ||
                   Is_wiz2_level(lev) ||
                   Is_wiz3_level(lev));
}

boolean
In_W_tower(x, y, lev)   /* is <x,y> of `lev' inside the Wizard's tower? */
int   x, y;
d_level     *lev;
{
      if (!On_W_tower_level(lev)) return FALSE;
      /*
       * Both of the exclusion regions for arriving via level teleport
       * (from above or below) define the tower's boundary.
       *    assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} );
       */
      if (dndest.nlx > 0)
          return (boolean)within_bounded_area(x, y, dndest.nlx, dndest.nly,
                                    dndest.nhx, dndest.nhy);
      else
          impossible("No boundary for Wizard's Tower?");
      return FALSE;
}

#endif /* OVL1 */
#ifdef OVL0

boolean
In_hell(lev)      /* are you in one of the Hell levels? */
d_level     *lev;
{
      return((boolean)(dungeons[lev->dnum].flags.hellish));
}

#endif /* OVL0 */
#ifdef OVL1

void
find_hell(lev)    /* sets *lev to be the gateway to Gehennom... */
d_level *lev;
{
      lev->dnum = valley_level.dnum;
      lev->dlevel = 1;
}

void
goto_hell(at_stairs, falling) /* go directly to hell... */
boolean     at_stairs, falling;
{
      d_level lev;

      find_hell(&lev);
      goto_level(&lev, at_stairs, falling, FALSE);
}

void
assign_level(dest, src)       /* equivalent to dest = source */
d_level     *dest, *src;
{
      dest->dnum = src->dnum;
      dest->dlevel = src->dlevel;
}

void
assign_rnd_level(dest, src, range)  /* dest = src + rn1(range) */
d_level     *dest, *src;
int range;
{
      dest->dnum = src->dnum;
      dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range)) ;

      if(dest->dlevel > dunlevs_in_dungeon(dest))
            dest->dlevel = dunlevs_in_dungeon(dest);
      else if(dest->dlevel < 1)
            dest->dlevel = 1;
}

#endif /* OVL1 */
#ifdef OVL0

int
induced_align(pct)
int   pct;
{
      s_level     *lev = Is_special(&u.uz);
      aligntyp al;

      if (lev && lev->flags.align)
            if(rn2(100) < pct) return(lev->flags.align);

      if(dungeons[u.uz.dnum].flags.align)
            if(rn2(100) < pct) return(dungeons[u.uz.dnum].flags.align);

      al = rn2(3) - 1;
      return(Align2amask(al));
}

#endif /* OVL0 */
#ifdef OVL1

boolean
Invocation_lev(lev)
d_level *lev;
{
      return((boolean)(In_hell(lev) &&
            lev->dlevel == (dungeons[lev->dnum].num_dunlevs - 1)));
}

/* use instead of depth() wherever a degree of difficulty is made
 * dependent on the location in the dungeon (eg. monster creation).
 */
xchar
level_difficulty()
{
      if (In_endgame(&u.uz))
            return((xchar)(depth(&sanctum_level) + u.ulevel/2));
      else
            if (u.uhave.amulet)
                  return(deepest_lev_reached(FALSE));
            else
                  return((xchar) depth(&u.uz));
}

/* Take one word and try to match it to a level.
 * Recognized levels are as shown by print_dungeon().
 */
schar
lev_by_name(nam)
const char *nam;
{
    schar lev = 0;
    s_level *slev;
    d_level dlev;
    const char *p;
    int idx, idxtoo;
    char buf[BUFSZ];

    /* allow strings like "the oracle level" to find "oracle" */
    if (!strncmpi(nam, "the ", 4)) nam += 4;
    if ((p = strstri(nam, " level")) != 0 && p == eos((char*)nam) - 6) {
      nam = strcpy(buf, nam);
      *(eos(buf) - 6) = '\0';
    }
    /* hell is the old name, and wouldn't match; gehennom would match its
       branch, yielding the castle level instead of the valley of the dead */
    if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) {
      if (In_V_tower(&u.uz)) nam = " to Vlad's tower";  /* branch to... */
      else nam = "valley";
    }

    if ((slev = find_level(nam)) != 0) {
      dlev = slev->dlevel;
      idx = ledger_no(&dlev);
      if ((dlev.dnum == u.uz.dnum ||
            /* within same branch, or else main dungeon <-> gehennom */
            (u.uz.dnum == valley_level.dnum &&
                  dlev.dnum == medusa_level.dnum) ||
            (u.uz.dnum == medusa_level.dnum &&
                  dlev.dnum == valley_level.dnum)) &&
          ( /* either wizard mode or else seen and not forgotten */
#ifdef WIZARD
           wizard ||
#endif
            (level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED)) {
          lev = depth(&slev->dlevel);
      }
    } else {      /* not a specific level; try branch names */
      idx = find_branch(nam, (struct proto_dungeon *)0);
      /* "<branch> to Xyzzy" */
      if (idx < 0 && (p = strstri(nam, " to ")) != 0)
          idx = find_branch(p + 4, (struct proto_dungeon *)0);

      if (idx >= 0) {
          idxtoo = (idx >> 8) & 0x00FF;
          idx &= 0x00FF;
          if (  /* either wizard mode, or else _both_ sides of branch seen */
#ifdef WIZARD
            wizard ||
#endif
            ((level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED &&
             (level_info[idxtoo].flags & (FORGOTTEN|VISITED)) == VISITED)) {
            if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo;
            dlev.dnum = ledger_to_dnum(idx);
            dlev.dlevel = ledger_to_dlev(idx);
            lev = depth(&dlev);
          }
      }
    }
    return lev;
}


#ifdef WIZARD

/* Convert a branch type to a string usable by print_dungeon(). */
static const char *
br_string(type)
    int type;
{
    switch (type) {
      case BR_PORTAL:    return "Portal";
      case BR_NO_END1: return "Connection";
      case BR_NO_END2: return "One way stair";
      case BR_STAIR:     return "Stair";
    }
    return " (unknown)";
}

/* Print all child branches between the lower and upper bounds. */
static void
print_branch(win, dnum, lower_bound, upper_bound)
    winid win;
    int   dnum;
    int   lower_bound;
    int   upper_bound;
{
    branch *br;
    char buf[BUFSZ];

    /* This assumes that end1 is the "parent". */
    for (br = branches; br; br = br->next) {
      if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel &&
                              br->end1.dlevel <= upper_bound) {
          Sprintf(buf,"   %s to %s: %d",
                br_string(br->type),
                dungeons[br->end2.dnum].dname,
                depth(&br->end1));
          putstr(win, 0, buf);
      }
    }
}

/* Print available dungeon information. */
void
print_dungeon()
{
    int     i, last_level, nlev;
    char    buf[BUFSZ];
    boolean first;
    s_level *slev;
    dungeon *dptr;
    branch  *br;
    winid   win = create_nhwindow(NHW_MENU);

    for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
      nlev = dptr->num_dunlevs;
      if (nlev > 1)
          Sprintf(buf, "%s: levels %d to %d", dptr->dname, dptr->depth_start,
                                    dptr->depth_start + nlev - 1);
      else
          Sprintf(buf, "%s: level %d", dptr->dname, dptr->depth_start);

      /* Most entrances are uninteresting. */
      if (dptr->entry_lev != 1) {
          if (dptr->entry_lev == nlev)
            Strcat(buf, ", entrance from below");
          else
            Sprintf(eos(buf), ", entrance on %d",
                  dptr->depth_start + dptr->entry_lev - 1);
      }
      putstr(win, 0, buf);

      /*
       * Circle through the special levels to find levels that are in
       * this dungeon.
       */
      for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
          if (slev->dlevel.dnum != i) continue;

          /* print any branches before this level */
          print_branch(win, i, last_level, slev->dlevel.dlevel);

          Sprintf(buf, "   %s: %d", slev->proto, depth(&slev->dlevel));
          if (Is_stronghold(&slev->dlevel))
            Sprintf(eos(buf), " (tune %s)", tune);
          putstr(win, 0, buf);

          last_level = slev->dlevel.dlevel;
      }
      /* print branches after the last special level */
      print_branch(win, i, last_level, MAXLEVEL);
    }

    /* Print out floating branches (if any). */
    for (first = TRUE, br = branches; br; br = br->next) {
      if (br->end1.dnum == n_dgns) {
          if (first) {
            putstr(win, 0, "");
            putstr(win, 0, "Floating branches");
            first = FALSE;
          }
          Sprintf(buf, "   %s to %s",
                  br_string(br->type), dungeons[br->end2.dnum].dname);
          putstr(win, 0, buf);
      }
    }

    /* I hate searching for the invocation pos while debugging. -dean */
    if (Invocation_lev(&u.uz)) {
      putstr(win, 0, "");
      Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)",
            inv_pos.x, inv_pos.y, u.ux, u.uy);
      putstr(win, 0, buf);
    }
    /*
     * The following is based on the assumption that the inter-level portals
     * created by the level compiler (not the dungeon compiler) only exist
     * one per level (currently true, of course).
     */
    else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
                        || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
      struct trap *trap;
      for (trap = ftrap; trap; trap = trap->ntrap)
          if (trap->ttyp == MAGIC_PORTAL) break;

      putstr(win, 0, "");
      if (trap)
          Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)",
            trap->tx, trap->ty, u.ux, u.uy);
      else
          Sprintf(buf, "No portal found.");
      putstr(win, 0, buf);
    }

    display_nhwindow(win, TRUE);
    destroy_nhwindow(win);
}
#endif /* WIZARD */

#endif /* OVL1 */

/*dungeon.c*/

Generated by  Doxygen 1.6.0   Back to index