Source:NetHack 3.6.0/src/dungeon.c

From NetHackWiki
(Redirected from Source:Dungeon.c)
Jump to: navigation, search

Below is the full text to dungeon.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/dungeon.c#line123]], for example.

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

Top of file

  1.  /* NetHack 3.6	dungeon.c	$NHDT-Date: 1448862377 2015/11/30 05:46:17 $  $NHDT-Branch: master $:$NHDT-Revision: 1.69 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  #include "hack.h"
  6.  #include "dgn_file.h"
  7.  #include "dlb.h"
  8.  #include "lev.h"
  9.  
  10.  #define DUNGEON_FILE "dungeon"
  11.  
  12.  #define X_START "x-strt"
  13.  #define X_LOCATE "x-loca"
  14.  #define X_GOAL "x-goal"
  15.  
  16.  struct proto_dungeon {
  17.      struct tmpdungeon tmpdungeon[MAXDUNGEON];
  18.      struct tmplevel tmplevel[LEV_LIMIT];
  19.      s_level *final_lev[LEV_LIMIT]; /* corresponding level pointers */
  20.      struct tmpbranch tmpbranch[BRANCH_LIMIT];
  21.  
  22.      int start;  /* starting index of current dungeon sp levels */
  23.      int n_levs; /* number of tmplevel entries */
  24.      int n_brs;  /* number of tmpbranch entries */
  25.  };
  26.  
  27.  int n_dgns;     /* number of dungeons (also used in mklev.c and do.c) */
  28.  static branch *branches = (branch *) 0;        /* dungeon branch list */
  29.  
  30.  mapseen *mapseenchn = (struct mapseen *) 0; /*DUNGEON_OVERVIEW*/
  31.  
  32.  struct lchoice {
  33.      int idx;
  34.      schar lev[MAXLINFO];
  35.      schar playerlev[MAXLINFO];
  36.      xchar dgn[MAXLINFO];
  37.      char menuletter;
  38.  };
  39.  
  40.  static void FDECL(Fread, (genericptr_t, int, int, dlb *));
  41.  STATIC_DCL xchar FDECL(dname_to_dnum, (const char *));
  42.  STATIC_DCL int FDECL(find_branch, (const char *, struct proto_dungeon *));
  43.  STATIC_DCL xchar FDECL(parent_dnum, (const char *, struct proto_dungeon *));
  44.  STATIC_DCL int FDECL(level_range, (XCHAR_P, int, int, int,
  45.                                     struct proto_dungeon *, int *));
  46.  STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *));
  47.  STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *));
  48.  STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *));
  49.  STATIC_DCL void FDECL(add_level, (s_level *));
  50.  STATIC_DCL void FDECL(init_level, (int, int, struct proto_dungeon *));
  51.  STATIC_DCL int FDECL(possible_places, (int, boolean *,
  52.                                         struct proto_dungeon *));
  53.  STATIC_DCL xchar FDECL(pick_level, (boolean *, int));
  54.  STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *));
  55.  STATIC_DCL boolean FDECL(unplaced_floater, (struct dungeon *));
  56.  STATIC_DCL boolean FDECL(unreachable_level, (d_level *, BOOLEAN_P));
  57.  STATIC_DCL void FDECL(tport_menu, (winid, char *, struct lchoice *, d_level *,
  58.                                     BOOLEAN_P));
  59.  STATIC_DCL const char *FDECL(br_string, (int));
  60.  STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P,
  61.                                       struct lchoice *));
  62.  STATIC_DCL mapseen *FDECL(load_mapseen, (int));
  63.  STATIC_DCL void FDECL(save_mapseen, (int, mapseen *));
  64.  STATIC_DCL mapseen *FDECL(find_mapseen, (d_level *));
  65.  STATIC_DCL void FDECL(print_mapseen, (winid, mapseen *, int, int, BOOLEAN_P));
  66.  STATIC_DCL boolean FDECL(interest_mapseen, (mapseen *));
  67.  STATIC_DCL void FDECL(traverse_mapseenchn, (BOOLEAN_P, winid,
  68.                                              int, int, int *));
  69.  STATIC_DCL const char *FDECL(seen_string, (XCHAR_P, const char *));
  70.  STATIC_DCL const char *FDECL(br_string2, (branch *));
  71.  STATIC_DCL const char *FDECL(endgamelevelname, (char *, int));
  72.  STATIC_DCL const char *FDECL(shop_string, (int));
  73.  STATIC_DCL char *FDECL(tunesuffix, (mapseen *, char *));
  74.  

dumpit

  1.  #ifdef DEBUG
  2.  #define DD dungeons[i]
  3.  STATIC_DCL void NDECL(dumpit);
  4.  
  5.  STATIC_OVL void
  6.  dumpit()
  7.  {
  8.      int i;
  9.      s_level *x;
  10.      branch *br;
  11.  
  12.      if (!explicitdebug(__FILE__))
  13.          return;
  14.  
  15.      for (i = 0; i < n_dgns; i++) {
  16.          fprintf(stderr, "\n#%d \"%s\" (%s):\n", i, DD.dname, DD.proto);
  17.          fprintf(stderr, "    num_dunlevs %d, dunlev_ureached %d\n",
  18.                  DD.num_dunlevs, DD.dunlev_ureached);
  19.          fprintf(stderr, "    depth_start %d, ledger_start %d\n",
  20.                  DD.depth_start, DD.ledger_start);
  21.          fprintf(stderr, "    flags:%s%s%s\n",
  22.                  DD.flags.rogue_like ? " rogue_like" : "",
  23.                  DD.flags.maze_like ? " maze_like" : "",
  24.                  DD.flags.hellish ? " hellish" : "");
  25.          getchar();
  26.      }
  27.      fprintf(stderr, "\nSpecial levels:\n");
  28.      for (x = sp_levchn; x; x = x->next) {
  29.          fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs);
  30.          fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel);
  31.          fprintf(stderr, "flags:%s%s%s%s\n",
  32.                  x->flags.rogue_like ? " rogue_like" : "",
  33.                  x->flags.maze_like ? " maze_like" : "",
  34.                  x->flags.hellish ? " hellish" : "",
  35.                  x->flags.town ? " town" : "");
  36.          getchar();
  37.      }
  38.      fprintf(stderr, "\nBranches:\n");
  39.      for (br = branches; br; br = br->next) {
  40.          fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n", br->id,
  41.                  br->type == BR_STAIR
  42.                      ? "stair"
  43.                      : br->type == BR_NO_END1
  44.                          ? "no end1"
  45.                          : br->type == BR_NO_END2
  46.                              ? "no end2"
  47.                              : br->type == BR_PORTAL
  48.                                  ? "portal"
  49.                                  : "unknown",
  50.                  br->end1.dnum, br->end1.dlevel, br->end2.dnum,
  51.                  br->end2.dlevel, br->end1_up ? "end1 up" : "end1 down");
  52.      }
  53.      getchar();
  54.      fprintf(stderr, "\nDone\n");
  55.      getchar();
  56.  }
  57.  #endif

save_dungeon

  1.  
  2.  /* Save the dungeon structures. */
  3.  void
  4.  save_dungeon(fd, perform_write, free_data)
  5.  int fd;
  6.  boolean perform_write, free_data;
  7.  {
  8.      branch *curr, *next;
  9.      mapseen *curr_ms, *next_ms;
  10.      int count;
  11.  
  12.      if (perform_write) {
  13.          bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns);
  14.          bwrite(fd, (genericptr_t) dungeons,
  15.                 sizeof(dungeon) * (unsigned) n_dgns);
  16.          bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
  17.          bwrite(fd, (genericptr_t) tune, sizeof tune);
  18.  
  19.          for (count = 0, curr = branches; curr; curr = curr->next)
  20.              count++;
  21.          bwrite(fd, (genericptr_t) &count, sizeof(count));
  22.  
  23.          for (curr = branches; curr; curr = curr->next)
  24.              bwrite(fd, (genericptr_t) curr, sizeof(branch));
  25.  
  26.          count = maxledgerno();
  27.          bwrite(fd, (genericptr_t) &count, sizeof count);
  28.          bwrite(fd, (genericptr_t) level_info,
  29.                 (unsigned) count * sizeof(struct linfo));
  30.          bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
  31.  
  32.          for (count = 0, curr_ms = mapseenchn; curr_ms;
  33.               curr_ms = curr_ms->next)
  34.              count++;
  35.          bwrite(fd, (genericptr_t) &count, sizeof(count));
  36.  
  37.          for (curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next)
  38.              save_mapseen(fd, curr_ms);
  39.      }
  40.  
  41.      if (free_data) {
  42.          for (curr = branches; curr; curr = next) {
  43.              next = curr->next;
  44.              free((genericptr_t) curr);
  45.          }
  46.          branches = 0;
  47.          for (curr_ms = mapseenchn; curr_ms; curr_ms = next_ms) {
  48.              next_ms = curr_ms->next;
  49.              if (curr_ms->custom)
  50.                  free((genericptr_t) curr_ms->custom);
  51.              free((genericptr_t) curr_ms);
  52.          }
  53.          mapseenchn = 0;
  54.      }
  55.  }
  56.  

restore_dungeon

  1.  /* Restore the dungeon structures. */
  2.  void
  3.  restore_dungeon(fd)
  4.  int fd;
  5.  {
  6.      branch *curr, *last;
  7.      int count, i;
  8.      mapseen *curr_ms, *last_ms;
  9.  
  10.      mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns));
  11.      mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned) n_dgns);
  12.      mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology);
  13.      mread(fd, (genericptr_t) tune, sizeof tune);
  14.  
  15.      last = branches = (branch *) 0;
  16.  
  17.      mread(fd, (genericptr_t) &count, sizeof(count));
  18.      for (i = 0; i < count; i++) {
  19.          curr = (branch *) alloc(sizeof(branch));
  20.          mread(fd, (genericptr_t) curr, sizeof(branch));
  21.          curr->next = (branch *) 0;
  22.          if (last)
  23.              last->next = curr;
  24.          else
  25.              branches = curr;
  26.          last = curr;
  27.      }
  28.  
  29.      mread(fd, (genericptr_t) &count, sizeof(count));
  30.      if (count >= MAXLINFO)
  31.          panic("level information count larger (%d) than allocated size",
  32.                count);
  33.      mread(fd, (genericptr_t) level_info,
  34.            (unsigned) count * sizeof(struct linfo));
  35.      mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
  36.  
  37.      mread(fd, (genericptr_t) &count, sizeof(count));
  38.      last_ms = (mapseen *) 0;
  39.      for (i = 0; i < count; i++) {
  40.          curr_ms = load_mapseen(fd);
  41.          curr_ms->next = (mapseen *) 0;
  42.          if (last_ms)
  43.              last_ms->next = curr_ms;
  44.          else
  45.              mapseenchn = curr_ms;
  46.          last_ms = curr_ms;
  47.      }
  48.  }
  49.  

Fread

  1.  static void
  2.  Fread(ptr, size, nitems, stream)
  3.  genericptr_t ptr;
  4.  int size, nitems;
  5.  dlb *stream;
  6.  {
  7.      int cnt;
  8.  
  9.      if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) {
  10.          panic(
  11.    "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.",
  12.                (size * nitems), (size * cnt));
  13.          terminate(EXIT_FAILURE);
  14.      }
  15.  }
  16.  

dname_to_dnum

  1.  STATIC_OVL xchar
  2.  dname_to_dnum(s)
  3.  const char *s;
  4.  {
  5.      xchar i;
  6.  
  7.      for (i = 0; i < n_dgns; i++)
  8.          if (!strcmp(dungeons[i].dname, s))
  9.              return i;
  10.  
  11.      panic("Couldn't resolve dungeon number for name \"%s\".", s);
  12.      /*NOT REACHED*/
  13.      return (xchar) 0;
  14.  }
  15.  

find_level

  1.  s_level *
  2.  find_level(s)
  3.  const char *s;
  4.  {
  5.      s_level *curr;
  6.      for (curr = sp_levchn; curr; curr = curr->next)
  7.          if (!strcmpi(s, curr->proto))
  8.              break;
  9.      return curr;
  10.  }
  11.  

find_branch

  1.  /* Find the branch that links the named dungeon. */
  2.  STATIC_OVL int
  3.  find_branch(s, pd)
  4.  const char *s; /* dungeon name */
  5.  struct proto_dungeon *pd;
  6.  {
  7.      int i;
  8.  
  9.      if (pd) {
  10.          for (i = 0; i < pd->n_brs; i++)
  11.              if (!strcmp(pd->tmpbranch[i].name, s))
  12.                  break;
  13.          if (i == pd->n_brs)
  14.              panic("find_branch: can't find %s", s);
  15.      } else {
  16.          /* support for level tport by name */
  17.          branch *br;
  18.          const char *dnam;
  19.  
  20.          for (br = branches; br; br = br->next) {
  21.              dnam = dungeons[br->end2.dnum].dname;
  22.              if (!strcmpi(dnam, s)
  23.                  || (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s)))
  24.                  break;
  25.          }
  26.          i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1;
  27.      }
  28.      return i;
  29.  }
  30.  

parent_dnum

  1.  /*
  2.   * Find the "parent" by searching the prototype branch list for the branch
  3.   * listing, then figuring out to which dungeon it belongs.
  4.   */
  5.  STATIC_OVL xchar
  6.  parent_dnum(s, pd)
  7.  const char *s; /* dungeon name */
  8.  struct proto_dungeon *pd;
  9.  {
  10.      int i;
  11.      xchar pdnum;
  12.  
  13.      i = find_branch(s, pd);
  14.      /*
  15.       * Got branch, now find parent dungeon.  Stop if we have reached
  16.       * "this" dungeon (if we haven't found it by now it is an error).
  17.       */
  18.      for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++)
  19.          if ((i -= pd->tmpdungeon[pdnum].branches) < 0)
  20.              return pdnum;
  21.  
  22.      panic("parent_dnum: couldn't resolve branch.");
  23.      /*NOT REACHED*/
  24.      return (xchar) 0;
  25.  }
  26.  

level_range

  1.  /*
  2.   * Return a starting point and number of successive positions a level
  3.   * or dungeon entrance can occupy.
  4.   *
  5.   * Note: This follows the acouple (instead of the rcouple) rules for a
  6.   *       negative random component (randc < 0).  These rules are found
  7.   *       in dgn_comp.y.  The acouple [absolute couple] section says that
  8.   *       a negative random component means from the (adjusted) base to the
  9.   *       end of the dungeon.
  10.   */
  11.  STATIC_OVL int
  12.  level_range(dgn, base, randc, chain, pd, adjusted_base)
  13.  xchar dgn;
  14.  int base, randc, chain;
  15.  struct proto_dungeon *pd;
  16.  int *adjusted_base;
  17.  {
  18.      int lmax = dungeons[dgn].num_dunlevs;
  19.  
  20.      if (chain >= 0) { /* relative to a special level */
  21.          s_level *levtmp = pd->final_lev[chain];
  22.          if (!levtmp)
  23.              panic("level_range: empty chain level!");
  24.  
  25.          base += levtmp->dlevel.dlevel;
  26.      } else { /* absolute in the dungeon */
  27.          /* from end of dungeon */
  28.          if (base < 0)
  29.              base = (lmax + base + 1);
  30.      }
  31.  
  32.      if (base < 1 || base > lmax)
  33.          panic("level_range: base value out of range");
  34.  
  35.      *adjusted_base = base;
  36.  
  37.      if (randc == -1) { /* from base to end of dungeon */
  38.          return (lmax - base + 1);
  39.      } else if (randc) {
  40.          /* make sure we don't run off the end of the dungeon */
  41.          return (((base + randc - 1) > lmax) ? lmax - base + 1 : randc);
  42.      } /* else only one choice */
  43.      return 1;
  44.  }
  45.  

parent_dlevel

  1.  STATIC_OVL xchar
  2.  parent_dlevel(s, pd)
  3.  const char *s;
  4.  struct proto_dungeon *pd;
  5.  {
  6.      int i, j, num, base, dnum = parent_dnum(s, pd);
  7.      branch *curr;
  8.  
  9.      i = find_branch(s, pd);
  10.      num = level_range(dnum, pd->tmpbranch[i].lev.base,
  11.                        pd->tmpbranch[i].lev.rand, pd->tmpbranch[i].chain, pd,
  12.                        &base);
  13.  
  14.      /* KMH -- Try our best to find a level without an existing branch */
  15.      i = j = rn2(num);
  16.      do {
  17.          if (++i >= num)
  18.              i = 0;
  19.          for (curr = branches; curr; curr = curr->next)
  20.              if ((curr->end1.dnum == dnum && curr->end1.dlevel == base + i)
  21.                  || (curr->end2.dnum == dnum && curr->end2.dlevel == base + i))
  22.                  break;
  23.      } while (curr && i != j);
  24.      return (base + i);
  25.  }
  26.  

correct_branch_type

  1.  /* Convert from the temporary branch type to the dungeon branch type. */
  2.  STATIC_OVL int
  3.  correct_branch_type(tbr)
  4.  struct tmpbranch *tbr;
  5.  {
  6.      switch (tbr->type) {
  7.      case TBR_STAIR:
  8.          return BR_STAIR;
  9.      case TBR_NO_UP:
  10.          return tbr->up ? BR_NO_END1 : BR_NO_END2;
  11.      case TBR_NO_DOWN:
  12.          return tbr->up ? BR_NO_END2 : BR_NO_END1;
  13.      case TBR_PORTAL:
  14.          return BR_PORTAL;
  15.      }
  16.      impossible("correct_branch_type: unknown branch type");
  17.      return BR_STAIR;
  18.  }
  19.  

insert_branch

  1.  /*
  2.   * Add the given branch to the branch list.  The branch list is ordered
  3.   * by end1 dungeon and level followed by end2 dungeon and level.  If
  4.   * extract_first is true, then the branch is already part of the list
  5.   * but needs to be repositioned.
  6.   */
  7.  void
  8.  insert_branch(new_branch, extract_first)
  9.  branch *new_branch;
  10.  boolean extract_first;
  11.  {
  12.      branch *curr, *prev;
  13.      long new_val, curr_val, prev_val;
  14.  
  15.      if (extract_first) {
  16.          for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next)
  17.              if (curr == new_branch)
  18.                  break;
  19.  
  20.          if (!curr)
  21.              panic("insert_branch: not found");
  22.          if (prev)
  23.              prev->next = curr->next;
  24.          else
  25.              branches = curr->next;
  26.      }
  27.      new_branch->next = (branch *) 0;
  28.  
  29.  /* Convert the branch into a unique number so we can sort them. */
  30.  #define branch_val(bp)                                                     \
  31.      ((((long) (bp)->end1.dnum * (MAXLEVEL + 1) + (long) (bp)->end1.dlevel) \
  32.        * (MAXDUNGEON + 1) * (MAXLEVEL + 1))                                 \
  33.       + ((long) (bp)->end2.dnum * (MAXLEVEL + 1) + (long) (bp)->end2.dlevel))
  34.  
  35.      /*
  36.       * Insert the new branch into the correct place in the branch list.
  37.       */
  38.      prev = (branch *) 0;
  39.      prev_val = -1;
  40.      new_val = branch_val(new_branch);
  41.      for (curr = branches; curr;
  42.           prev_val = curr_val, prev = curr, curr = curr->next) {
  43.          curr_val = branch_val(curr);
  44.          if (prev_val < new_val && new_val <= curr_val)
  45.              break;
  46.      }
  47.      if (prev) {
  48.          new_branch->next = curr;
  49.          prev->next = new_branch;
  50.      } else {
  51.          new_branch->next = branches;
  52.          branches = new_branch;
  53.      }
  54.  }
  55.  

add_branch

  1.  /* Add a dungeon branch to the branch list. */
  2.  STATIC_OVL branch *
  3.  add_branch(dgn, child_entry_level, pd)
  4.  int dgn;
  5.  int child_entry_level;
  6.  struct proto_dungeon *pd;
  7.  {
  8.      static int branch_id = 0;
  9.      int branch_num;
  10.      branch *new_branch;
  11.  
  12.      branch_num = find_branch(dungeons[dgn].dname, pd);
  13.      new_branch = (branch *) alloc(sizeof(branch));
  14.      new_branch->next = (branch *) 0;
  15.      new_branch->id = branch_id++;
  16.      new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
  17.      new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd);
  18.      new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd);
  19.      new_branch->end2.dnum = dgn;
  20.      new_branch->end2.dlevel = child_entry_level;
  21.      new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE;
  22.  
  23.      insert_branch(new_branch, FALSE);
  24.      return new_branch;
  25.  }
  26.  

add_level

  1.  /*
  2.   * Add new level to special level chain.  Insert it in level order with the
  3.   * other levels in this dungeon.  This assumes that we are never given a
  4.   * level that has a dungeon number less than the dungeon number of the
  5.   * last entry.
  6.   */
  7.  STATIC_OVL void
  8.  add_level(new_lev)
  9.  s_level *new_lev;
  10.  {
  11.      s_level *prev, *curr;
  12.  
  13.      prev = (s_level *) 0;
  14.      for (curr = sp_levchn; curr; curr = curr->next) {
  15.          if (curr->dlevel.dnum == new_lev->dlevel.dnum
  16.              && curr->dlevel.dlevel > new_lev->dlevel.dlevel)
  17.              break;
  18.          prev = curr;
  19.      }
  20.      if (!prev) {
  21.          new_lev->next = sp_levchn;
  22.          sp_levchn = new_lev;
  23.      } else {
  24.          new_lev->next = curr;
  25.          prev->next = new_lev;
  26.      }
  27.  }
  28.  

init_level

  1.  STATIC_OVL void
  2.  init_level(dgn, proto_index, pd)
  3.  int dgn, proto_index;
  4.  struct proto_dungeon *pd;
  5.  {
  6.      s_level *new_level;
  7.      struct tmplevel *tlevel = &pd->tmplevel[proto_index];
  8.  
  9.      pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */
  10.      if (!wizard && tlevel->chance <= rn2(100))
  11.          return;
  12.  
  13.      pd->final_lev[proto_index] = new_level =
  14.          (s_level *) alloc(sizeof(s_level));
  15.      /* load new level with data */
  16.      Strcpy(new_level->proto, tlevel->name);
  17.      new_level->boneid = tlevel->boneschar;
  18.      new_level->dlevel.dnum = dgn;
  19.      new_level->dlevel.dlevel = 0; /* for now */
  20.  
  21.      new_level->flags.town = !!(tlevel->flags & TOWN);
  22.      new_level->flags.hellish = !!(tlevel->flags & HELLISH);
  23.      new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE);
  24.      new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE);
  25.      new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4);
  26.      if (!new_level->flags.align)
  27.          new_level->flags.align =
  28.              ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4);
  29.  
  30.      new_level->rndlevs = tlevel->rndlevs;
  31.      new_level->next = (s_level *) 0;
  32.  }
  33.  

possible_places

  1.  STATIC_OVL int
  2.  possible_places(idx, map, pd)
  3.  int idx;      /* prototype index */
  4.  boolean *map; /* array MAXLEVEL+1 in length */
  5.  struct proto_dungeon *pd;
  6.  {
  7.      int i, start, count;
  8.      s_level *lev = pd->final_lev[idx];
  9.  
  10.      /* init level possibilities */
  11.      for (i = 0; i <= MAXLEVEL; i++)
  12.          map[i] = FALSE;
  13.  
  14.      /* get base and range and set those entries to true */
  15.      count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base,
  16.                          pd->tmplevel[idx].lev.rand, pd->tmplevel[idx].chain,
  17.                          pd, &start);
  18.      for (i = start; i < start + count; i++)
  19.          map[i] = TRUE;
  20.  
  21.      /* mark off already placed levels */
  22.      for (i = pd->start; i < idx; i++) {
  23.          if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) {
  24.              map[pd->final_lev[i]->dlevel.dlevel] = FALSE;
  25.              --count;
  26.          }
  27.      }
  28.  
  29.      return count;
  30.  }
  31.  

pick_level

  1.  /* Pick the nth TRUE entry in the given boolean array. */
  2.  STATIC_OVL xchar
  3.  pick_level(map, nth)
  4.  boolean *map; /* an array MAXLEVEL+1 in size */
  5.  int nth;
  6.  {
  7.      int i;
  8.      for (i = 1; i <= MAXLEVEL; i++)
  9.          if (map[i] && !nth--)
  10.              return (xchar) i;
  11.      panic("pick_level:  ran out of valid levels");
  12.      return 0;
  13.  }
  14.  

indent

  1.  #ifdef DDEBUG
  2.  static void FDECL(indent, (int));
  3.  
  4.  static void
  5.  indent(d)
  6.  int d;
  7.  {
  8.      while (d-- > 0)
  9.          fputs("    ", stderr);
  10.  }
  11.  #endif
  12.  

place_level

  1.  /*
  2.   * Place a level.  First, find the possible places on a dungeon map
  3.   * template.  Next pick one.  Then try to place the next level.  If
  4.   * successful, we're done.  Otherwise, try another (and another) until
  5.   * all possible places have been tried.  If all possible places have
  6.   * been exhausted, return false.
  7.   */
  8.  STATIC_OVL boolean
  9.  place_level(proto_index, pd)
  10.  int proto_index;
  11.  struct proto_dungeon *pd;
  12.  {
  13.      boolean map[MAXLEVEL + 1]; /* valid levels are 1..MAXLEVEL inclusive */
  14.      s_level *lev;
  15.      int npossible;
  16.  #ifdef DDEBUG
  17.      int i;
  18.  #endif
  19.  
  20.      if (proto_index == pd->n_levs)
  21.          return TRUE; /* at end of proto levels */
  22.  
  23.      lev = pd->final_lev[proto_index];
  24.  
  25.      /* No level created for this prototype, goto next. */
  26.      if (!lev)
  27.          return place_level(proto_index + 1, pd);
  28.  
  29.      npossible = possible_places(proto_index, map, pd);
  30.  
  31.      for (; npossible; --npossible) {
  32.          lev->dlevel.dlevel = pick_level(map, rn2(npossible));
  33.  #ifdef DDEBUG
  34.          indent(proto_index - pd->start);
  35.          fprintf(stderr, "%s: trying %d [ ", lev->proto, lev->dlevel.dlevel);
  36.          for (i = 1; i <= MAXLEVEL; i++)
  37.              if (map[i])
  38.                  fprintf(stderr, "%d ", i);
  39.          fprintf(stderr, "]\n");
  40.  #endif
  41.          if (place_level(proto_index + 1, pd))
  42.              return TRUE;
  43.          map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */
  44.      }
  45.  #ifdef DDEBUG
  46.      indent(proto_index - pd->start);
  47.      fprintf(stderr, "%s: failed\n", lev->proto);
  48.  #endif
  49.      return FALSE;
  50.  }
  51.  

init_dungeons

  1.  struct level_map {
  2.      const char *lev_name;
  3.      d_level *lev_spec;
  4.  } level_map[] = { { "air", &air_level },
  5.                    { "asmodeus", &asmodeus_level },
  6.                    { "astral", &astral_level },
  7.                    { "baalz", &baalzebub_level },
  8.                    { "bigrm", &bigroom_level },
  9.                    { "castle", &stronghold_level },
  10.                    { "earth", &earth_level },
  11.                    { "fakewiz1", &portal_level },
  12.                    { "fire", &fire_level },
  13.                    { "juiblex", &juiblex_level },
  14.                    { "knox", &knox_level },
  15.                    { "medusa", &medusa_level },
  16.                    { "oracle", &oracle_level },
  17.                    { "orcus", &orcus_level },
  18.                    { "rogue", &rogue_level },
  19.                    { "sanctum", &sanctum_level },
  20.                    { "valley", &valley_level },
  21.                    { "water", &water_level },
  22.                    { "wizard1", &wiz1_level },
  23.                    { "wizard2", &wiz2_level },
  24.                    { "wizard3", &wiz3_level },
  25.                    { "minend", &mineend_level },
  26.                    { "soko1", &sokoend_level },
  27.                    { X_START, &qstart_level },
  28.                    { X_LOCATE, &qlocate_level },
  29.                    { X_GOAL, &nemesis_level },
  30.                    { "", (d_level *) 0 } };
  31.  
  32.  /* initialize the "dungeon" structs */
  33.  void
  34.  init_dungeons()
  35.  {
  36.      dlb *dgn_file;
  37.      register int i, cl = 0, cb = 0;
  38.      register s_level *x;
  39.      struct proto_dungeon pd;
  40.      struct level_map *lev_map;
  41.      struct version_info vers_info;
  42.  
  43.      pd.n_levs = pd.n_brs = 0;
  44.  
  45.      dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE);
  46.      if (!dgn_file) {
  47.          char tbuf[BUFSZ];
  48.          Sprintf(tbuf, "Cannot open dungeon description - \"%s", DUNGEON_FILE);
  49.  #ifdef DLBRSRC /* using a resource from the executable */
  50.          Strcat(tbuf, "\" resource!");
  51.  #else /* using a file or DLB file */
  52.  #if defined(DLB)
  53.          Strcat(tbuf, "\" from ");
  54.  #ifdef PREFIXES_IN_USE
  55.          Strcat(tbuf, "\n\"");
  56.          if (fqn_prefix[DATAPREFIX])
  57.              Strcat(tbuf, fqn_prefix[DATAPREFIX]);
  58.  #else
  59.          Strcat(tbuf, "\"");
  60.  #endif
  61.          Strcat(tbuf, DLBFILE);
  62.  #endif
  63.          Strcat(tbuf, "\" file!");
  64.  #endif
  65.  #ifdef WIN32
  66.          interject_assistance(1, INTERJECT_PANIC, (genericptr_t) tbuf,
  67.                               (genericptr_t) fqn_prefix[DATAPREFIX]);
  68.  #endif
  69.          panic1(tbuf);
  70.      }
  71.  
  72.      /* validate the data's version against the program's version */
  73.      Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file);
  74.      /* we'd better clear the screen now, since when error messages come from
  75.       * check_version() they will be printed using pline(), which doesn't
  76.       * mix with the raw messages that might be already on the screen
  77.       */
  78.      if (iflags.window_inited)
  79.          clear_nhwindow(WIN_MAP);
  80.      if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
  81.          panic("Dungeon description not valid.");
  82.  
  83.      /*
  84.       * Read in each dungeon and transfer the results to the internal
  85.       * dungeon arrays.
  86.       */
  87.      sp_levchn = (s_level *) 0;
  88.      Fread((genericptr_t) &n_dgns, sizeof(int), 1, dgn_file);
  89.      if (n_dgns >= MAXDUNGEON)
  90.          panic("init_dungeons: too many dungeons");
  91.  
  92.      for (i = 0; i < n_dgns; i++) {
  93.          Fread((genericptr_t) &pd.tmpdungeon[i], sizeof(struct tmpdungeon), 1,
  94.                dgn_file);
  95.          if (!wizard && pd.tmpdungeon[i].chance
  96.              && (pd.tmpdungeon[i].chance <= rn2(100))) {
  97.              int j;
  98.  
  99.              /* skip over any levels or branches */
  100.              for (j = 0; j < pd.tmpdungeon[i].levels; j++)
  101.                  Fread((genericptr_t) &pd.tmplevel[cl],
  102.                        sizeof(struct tmplevel), 1, dgn_file);
  103.  
  104.              for (j = 0; j < pd.tmpdungeon[i].branches; j++)
  105.                  Fread((genericptr_t) &pd.tmpbranch[cb],
  106.                        sizeof(struct tmpbranch), 1, dgn_file);
  107.              n_dgns--;
  108.              i--;
  109.              continue;
  110.          }
  111.  
  112.          Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name);
  113.          Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname);
  114.          dungeons[i].boneid = pd.tmpdungeon[i].boneschar;
  115.  
  116.          if (pd.tmpdungeon[i].lev.rand)
  117.              dungeons[i].num_dunlevs = (xchar) rn1(pd.tmpdungeon[i].lev.rand,
  118.                                                    pd.tmpdungeon[i].lev.base);
  119.          else
  120.              dungeons[i].num_dunlevs = (xchar) pd.tmpdungeon[i].lev.base;
  121.  
  122.          if (!i) {
  123.              dungeons[i].ledger_start = 0;
  124.              dungeons[i].depth_start = 1;
  125.              dungeons[i].dunlev_ureached = 1;
  126.          } else {
  127.              dungeons[i].ledger_start =
  128.                  dungeons[i - 1].ledger_start + dungeons[i - 1].num_dunlevs;
  129.              dungeons[i].dunlev_ureached = 0;
  130.          }
  131.  
  132.          dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH);
  133.          dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE);
  134.          dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE);
  135.          dungeons[i].flags.align =
  136.              ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4);
  137.          /*
  138.           * Set the entry level for this dungeon.  The pd.tmpdungeon entry
  139.           * value means:
  140.           *              < 0     from bottom (-1 == bottom level)
  141.           *                0     default (top)
  142.           *              > 0     actual level (1 = top)
  143.           *
  144.           * Note that the entry_lev field in the dungeon structure is
  145.           * redundant.  It is used only here and in print_dungeon().
  146.           */
  147.          if (pd.tmpdungeon[i].entry_lev < 0) {
  148.              dungeons[i].entry_lev =
  149.                  dungeons[i].num_dunlevs + pd.tmpdungeon[i].entry_lev + 1;
  150.              if (dungeons[i].entry_lev <= 0)
  151.                  dungeons[i].entry_lev = 1;
  152.          } else if (pd.tmpdungeon[i].entry_lev > 0) {
  153.              dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev;
  154.              if (dungeons[i].entry_lev > dungeons[i].num_dunlevs)
  155.                  dungeons[i].entry_lev = dungeons[i].num_dunlevs;
  156.          } else {                       /* default */
  157.              dungeons[i].entry_lev = 1; /* defaults to top level */
  158.          }
  159.  
  160.          if (i) { /* set depth */
  161.              branch *br;
  162.              schar from_depth;
  163.              boolean from_up;
  164.  
  165.              br = add_branch(i, dungeons[i].entry_lev, &pd);
  166.  
  167.              /* Get the depth of the connecting end. */
  168.              if (br->end1.dnum == i) {
  169.                  from_depth = depth(&br->end2);
  170.                  from_up = !br->end1_up;
  171.              } else {
  172.                  from_depth = depth(&br->end1);
  173.                  from_up = br->end1_up;
  174.              }
  175.  
  176.              /*
  177.               * Calculate the depth of the top of the dungeon via
  178.               * its branch.  First, the depth of the entry point:
  179.               *
  180.               *  depth of branch from "parent" dungeon
  181.               *  + -1 or 1 depending on a up or down stair or
  182.               *    0 if portal
  183.               *
  184.               * Followed by the depth of the top of the dungeon:
  185.               *
  186.               *  - (entry depth - 1)
  187.               *
  188.               * We'll say that portals stay on the same depth.
  189.               */
  190.              dungeons[i].depth_start =
  191.                  from_depth + (br->type == BR_PORTAL ? 0 : (from_up ? -1 : 1))
  192.                  - (dungeons[i].entry_lev - 1);
  193.          }
  194.  
  195.          /* this is redundant - it should have been flagged by dgn_comp */
  196.          if (dungeons[i].num_dunlevs > MAXLEVEL)
  197.              dungeons[i].num_dunlevs = MAXLEVEL;
  198.  
  199.          pd.start = pd.n_levs; /* save starting point */
  200.          pd.n_levs += pd.tmpdungeon[i].levels;
  201.          if (pd.n_levs > LEV_LIMIT)
  202.              panic("init_dungeon: too many special levels");
  203.          /*
  204.           * Read in the prototype special levels.  Don't add generated
  205.           * special levels until they are all placed.
  206.           */
  207.          for (; cl < pd.n_levs; cl++) {
  208.              Fread((genericptr_t) &pd.tmplevel[cl], sizeof(struct tmplevel), 1,
  209.                    dgn_file);
  210.              init_level(i, cl, &pd);
  211.          }
  212.          /*
  213.           * Recursively place the generated levels for this dungeon.  This
  214.           * routine will attempt all possible combinations before giving
  215.           * up.
  216.           */
  217.          if (!place_level(pd.start, &pd))
  218.              panic("init_dungeon:  couldn't place levels");
  219.  #ifdef DDEBUG
  220.          fprintf(stderr, "--- end of dungeon %d ---\n", i);
  221.          fflush(stderr);
  222.          getchar();
  223.  #endif
  224.          for (; pd.start < pd.n_levs; pd.start++)
  225.              if (pd.final_lev[pd.start])
  226.                  add_level(pd.final_lev[pd.start]);
  227.  
  228.          pd.n_brs += pd.tmpdungeon[i].branches;
  229.          if (pd.n_brs > BRANCH_LIMIT)
  230.              panic("init_dungeon: too many branches");
  231.          for (; cb < pd.n_brs; cb++)
  232.              Fread((genericptr_t) &pd.tmpbranch[cb], sizeof(struct tmpbranch),
  233.                    1, dgn_file);
  234.      }
  235.      (void) dlb_fclose(dgn_file);
  236.  
  237.      for (i = 0; i < 5; i++)
  238.          tune[i] = 'A' + rn2(7);
  239.      tune[5] = 0;
  240.  
  241.      /*
  242.       * Find most of the special levels and dungeons so we can access their
  243.       * locations quickly.
  244.       */
  245.      for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) {
  246.          x = find_level(lev_map->lev_name);
  247.          if (x) {
  248.              assign_level(lev_map->lev_spec, &x->dlevel);
  249.              if (!strncmp(lev_map->lev_name, "x-", 2)) {
  250.                  /* This is where the name substitution on the
  251.                   * levels of the quest dungeon occur.
  252.                   */
  253.                  Sprintf(x->proto, "%s%s", urole.filecode,
  254.                          &lev_map->lev_name[1]);
  255.              } else if (lev_map->lev_spec == &knox_level) {
  256.                  branch *br;
  257.                  /*
  258.                   * Kludge to allow floating Knox entrance.  We
  259.                   * specify a floating entrance by the fact that
  260.                   * its entrance (end1) has a bogus dnum, namely
  261.                   * n_dgns.
  262.                   */
  263.                  for (br = branches; br; br = br->next)
  264.                      if (on_level(&br->end2, &knox_level))
  265.                          break;
  266.  
  267.                  if (br)
  268.                      br->end1.dnum = n_dgns;
  269.                  /* adjust the branch's position on the list */
  270.                  insert_branch(br, TRUE);
  271.              }
  272.          }
  273.      }
  274.      /*
  275.       *  I hate hardwiring these names. :-(
  276.       */
  277.      quest_dnum = dname_to_dnum("The Quest");
  278.      sokoban_dnum = dname_to_dnum("Sokoban");
  279.      mines_dnum = dname_to_dnum("The Gnomish Mines");
  280.      tower_dnum = dname_to_dnum("Vlad's Tower");
  281.  
  282.      /* one special fixup for dummy surface level */
  283.      if ((x = find_level("dummy")) != 0) {
  284.          i = x->dlevel.dnum;
  285.          /* the code above puts earth one level above dungeon level #1,
  286.             making the dummy level overlay level 1; but the whole reason
  287.             for having the dummy level is to make earth have depth -1
  288.             instead of 0, so adjust the start point to shift endgame up */
  289.          if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start)
  290.              dungeons[i].depth_start -= 1;
  291.          /* TO DO: strip "dummy" out all the way here,
  292.             so that it's hidden from <ctrl/O> feedback. */
  293.      }
  294.  
  295.  #ifdef DEBUG
  296.      dumpit();
  297.  #endif
  298.  }
  299.  

dunlev

  1.  /* return the level number for lev in *this* dungeon */
  2.  xchar
  3.  dunlev(lev)
  4.  d_level *lev;
  5.  {
  6.      return lev->dlevel;
  7.  }
  8.  

dunlevs_in_dungeon

  1.  /* return the lowest level number for *this* dungeon */
  2.  xchar
  3.  dunlevs_in_dungeon(lev)
  4.  d_level *lev;
  5.  {
  6.      return dungeons[lev->dnum].num_dunlevs;
  7.  }
  8.  

deepest_lev_reached

  1.  /* return the lowest level explored in the game*/
  2.  xchar
  3.  deepest_lev_reached(noquest)
  4.  boolean noquest;
  5.  {
  6.      /* this function is used for three purposes: to provide a factor
  7.       * of difficulty in monster generation; to provide a factor of
  8.       * difficulty in experience calculations (botl.c and end.c); and
  9.       * to insert the deepest level reached in the game in the topten
  10.       * display.  the 'noquest' arg switch is required for the latter.
  11.       *
  12.       * from the player's point of view, going into the Quest is _not_
  13.       * going deeper into the dungeon -- it is going back "home", where
  14.       * the dungeon starts at level 1.  given the setup in dungeon.def,
  15.       * the depth of the Quest (thought of as starting at level 1) is
  16.       * never lower than the level of entry into the Quest, so we exclude
  17.       * the Quest from the topten "deepest level reached" display
  18.       * calculation.  _However_ the Quest is a difficult dungeon, so we
  19.       * include it in the factor of difficulty calculations.
  20.       */
  21.      register int i;
  22.      d_level tmp;
  23.      register schar ret = 0;
  24.  
  25.      for (i = 0; i < n_dgns; i++) {
  26.          if (noquest && i == quest_dnum)
  27.              continue;
  28.          tmp.dlevel = dungeons[i].dunlev_ureached;
  29.          if (tmp.dlevel == 0)
  30.              continue;
  31.          tmp.dnum = i;
  32.          if (depth(&tmp) > ret)
  33.              ret = depth(&tmp);
  34.      }
  35.      return (xchar) ret;
  36.  }
  37.  

ledger_no

  1.  /* return a bookkeeping level number for purpose of comparisons and
  2.     save/restore */
  3.  xchar
  4.  ledger_no(lev)
  5.  d_level *lev;
  6.  {
  7.      return (xchar) (lev->dlevel + dungeons[lev->dnum].ledger_start);
  8.  }
  9.  

maxledgerno

  1.  /*
  2.   * The last level in the bookkeeping list of level is the bottom of the last
  3.   * dungeon in the dungeons[] array.
  4.   *
  5.   * Maxledgerno() -- which is the max number of levels in the bookkeeping
  6.   * list, should not be confused with dunlevs_in_dungeon(lev) -- which
  7.   * returns the max number of levels in lev's dungeon, and both should
  8.   * not be confused with deepest_lev_reached() -- which returns the lowest
  9.   * depth visited by the player.
  10.   */
  11.  xchar
  12.  maxledgerno()
  13.  {
  14.      return (xchar) (dungeons[n_dgns - 1].ledger_start
  15.                      + dungeons[n_dgns - 1].num_dunlevs);
  16.  }
  17.  

ledger_to_dnum

  1.  /* return the dungeon that this ledgerno exists in */
  2.  xchar
  3.  ledger_to_dnum(ledgerno)
  4.  xchar ledgerno;
  5.  {
  6.      register int i;
  7.  
  8.      /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */
  9.      for (i = 0; i < n_dgns; i++)
  10.          if (dungeons[i].ledger_start < ledgerno
  11.              && ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs)
  12.              return (xchar) i;
  13.  
  14.      panic("level number out of range [ledger_to_dnum(%d)]", (int) ledgerno);
  15.      /*NOT REACHED*/
  16.      return (xchar) 0;
  17.  }
  18.  

ledger_to_dlev

  1.  /* return the level of the dungeon this ledgerno exists in */
  2.  xchar
  3.  ledger_to_dlev(ledgerno)
  4.  xchar ledgerno;
  5.  {
  6.      return (xchar) (ledgerno
  7.                      - dungeons[ledger_to_dnum(ledgerno)].ledger_start);
  8.  }
  9.  

depth

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

on_level

  1.  /* are "lev1" and "lev2" actually the same? */
  2.  boolean
  3.  on_level(lev1, lev2)
  4.  d_level *lev1, *lev2;
  5.  {
  6.      return (boolean) (lev1->dnum == lev2->dnum
  7.                        && lev1->dlevel == lev2->dlevel);
  8.  }
  9.  

Is_special

  1.  /* is this level referenced in the special level chain? */
  2.  s_level *
  3.  Is_special(lev)
  4.  d_level *lev;
  5.  {
  6.      s_level *levtmp;
  7.  
  8.      for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next)
  9.          if (on_level(lev, &levtmp->dlevel))
  10.              return levtmp;
  11.  
  12.      return (s_level *) 0;
  13.  }
  14.  

Is_branchlev

  1.  /*
  2.   * Is this a multi-dungeon branch level?  If so, return a pointer to the
  3.   * branch.  Otherwise, return null.
  4.   */
  5.  branch *
  6.  Is_branchlev(lev)
  7.  d_level *lev;
  8.  {
  9.      branch *curr;
  10.  
  11.      for (curr = branches; curr; curr = curr->next) {
  12.          if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2))
  13.              return curr;
  14.      }
  15.      return (branch *) 0;
  16.  }
  17.  

builds_up

  1.  /* returns True iff the branch 'lev' is in a branch which builds up */
  2.  boolean
  3.  builds_up(lev)
  4.  d_level *lev;
  5.  {
  6.      dungeon *dptr = &dungeons[lev->dnum];
  7.      /*
  8.       * FIXME:  this misclassifies a single level branch reached via stairs
  9.       * from below.  Saving grace is that no such branches currently exist.
  10.       */
  11.      return (boolean) (dptr->num_dunlevs > 1
  12.                        && dptr->entry_lev == dptr->num_dunlevs);
  13.  }
  14.  

next_level

  1.  /* goto the next level (or appropriate dungeon) */
  2.  void
  3.  next_level(at_stairs)
  4.  boolean at_stairs;
  5.  {
  6.      if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
  7.          /* Taking a down dungeon branch. */
  8.          goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
  9.      } else {
  10.          /* Going down a stairs or jump in a trap door. */
  11.          d_level newlevel;
  12.  
  13.          newlevel.dnum = u.uz.dnum;
  14.          newlevel.dlevel = u.uz.dlevel + 1;
  15.          goto_level(&newlevel, at_stairs, !at_stairs, FALSE);
  16.      }
  17.  }
  18.  

prev_level

  1.  /* goto the previous level (or appropriate dungeon) */
  2.  void
  3.  prev_level(at_stairs)
  4.  boolean at_stairs;
  5.  {
  6.      if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) {
  7.          /* Taking an up dungeon branch. */
  8.          /* KMH -- Upwards branches are okay if not level 1 */
  9.          /* (Just make sure it doesn't go above depth 1) */
  10.          if (!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet)
  11.              done(ESCAPED);
  12.          else
  13.              goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE);
  14.      } else {
  15.          /* Going up a stairs or rising through the ceiling. */
  16.          d_level newlevel;
  17.          newlevel.dnum = u.uz.dnum;
  18.          newlevel.dlevel = u.uz.dlevel - 1;
  19.          goto_level(&newlevel, at_stairs, FALSE, FALSE);
  20.      }
  21.  }
  22.  

u_on_newpos

  1.  void
  2.  u_on_newpos(x, y)
  3.  int x, y;
  4.  {
  5.      u.ux = x;
  6.      u.uy = y;
  7.  #ifdef CLIPPING
  8.      cliparound(u.ux, u.uy);
  9.  #endif
  10.      /* ridden steed always shares hero's location */
  11.      if (u.usteed)
  12.          u.usteed->mx = u.ux, u.usteed->my = u.uy;
  13.      /* when changing levels, don't leave old position set with
  14.         stale values from previous level */
  15.      if (!on_level(&u.uz, &u.uz0))
  16.          u.ux0 = u.ux, u.uy0 = u.uy;
  17.  }
  18.  

u_on_rndspot

  1.  /* place you on a random location */
  2.  void
  3.  u_on_rndspot(upflag)
  4.  int upflag;
  5.  {
  6.      int up = (upflag & 1), was_in_W_tower = (upflag & 2);
  7.  
  8.      /*
  9.       * Place the hero at a random location within the relevant region.
  10.       * place_lregion(xTELE) -> put_lregion_here(xTELE) -> u_on_newpos()
  11.       * Unspecified region (.lx == 0) defaults to entire level.
  12.       */
  13.      if (was_in_W_tower && On_W_tower_level(&u.uz))
  14.          /* Stay inside the Wizard's tower when feasible.
  15.             We use the W Tower's exclusion region for the
  16.             destination instead of its enclosing region.
  17.             Note: up vs down doesn't matter in this case
  18.             because both specify the same exclusion area. */
  19.          place_lregion(dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy, 0, 0, 0,
  20.                        0, LR_DOWNTELE, (d_level *) 0);
  21.      else if (up)
  22.          place_lregion(updest.lx, updest.ly, updest.hx, updest.hy, updest.nlx,
  23.                        updest.nly, updest.nhx, updest.nhy, LR_UPTELE,
  24.                        (d_level *) 0);
  25.      else
  26.          place_lregion(dndest.lx, dndest.ly, dndest.hx, dndest.hy, dndest.nlx,
  27.                        dndest.nly, dndest.nhx, dndest.nhy, LR_DOWNTELE,
  28.                        (d_level *) 0);
  29.  }
  30.  

u_on_sstairs

  1.  /* place you on the special staircase */
  2.  void
  3.  u_on_sstairs(upflag)
  4.  int upflag;
  5.  {
  6.      if (sstairs.sx)
  7.          u_on_newpos(sstairs.sx, sstairs.sy);
  8.      else
  9.          u_on_rndspot(upflag);
  10.  }
  11.  

u_on_upstairs

  1.  /* place you on upstairs (or special equivalent) */
  2.  void
  3.  u_on_upstairs()
  4.  {
  5.      if (xupstair)
  6.          u_on_newpos(xupstair, yupstair);
  7.      else
  8.          u_on_sstairs(0); /* destination upstairs implies moving down */
  9.  }
  10.  

u_on_dnstairs

  1.  /* place you on dnstairs (or special equivalent) */
  2.  void
  3.  u_on_dnstairs()
  4.  {
  5.      if (xdnstair)
  6.          u_on_newpos(xdnstair, ydnstair);
  7.      else
  8.          u_on_sstairs(1); /* destination dnstairs implies moving up */
  9.  }
  10.  

On_stairs

  1.  boolean
  2.  On_stairs(x, y)
  3.  xchar x, y;
  4.  {
  5.      return (boolean) ((x == xupstair && y == yupstair)
  6.                        || (x == xdnstair && y == ydnstair)
  7.                        || (x == xdnladder && y == ydnladder)
  8.                        || (x == xupladder && y == yupladder)
  9.                        || (x == sstairs.sx && y == sstairs.sy));
  10.  }
  11.  

Is_botlevel

  1.  boolean
  2.  Is_botlevel(lev)
  3.  d_level *lev;
  4.  {
  5.      return (boolean) (lev->dlevel == dungeons[lev->dnum].num_dunlevs);
  6.  }
  7.  

Can_dig_down

  1.  boolean
  2.  Can_dig_down(lev)
  3.  d_level *lev;
  4.  {
  5.      return (boolean) (!level.flags.hardfloor
  6.                        && !Is_botlevel(lev)
  7.                        && !Invocation_lev(lev));
  8.  }
  9.  

Can_fall_thru

  1.  /*
  2.   * Like Can_dig_down (above), but also allows falling through on the
  3.   * stronghold level.  Normally, the bottom level of a dungeon resists
  4.   * both digging and falling.
  5.   */
  6.  boolean
  7.  Can_fall_thru(lev)
  8.  d_level *lev;
  9.  {
  10.      return (boolean) (Can_dig_down(lev) || Is_stronghold(lev));
  11.  }
  12.  

Can_rise_up

  1.  /*
  2.   * True if one can rise up a level (e.g. cursed gain level).
  3.   * This happens on intermediate dungeon levels or on any top dungeon
  4.   * level that has a stairwell style branch to the next higher dungeon.
  5.   * Checks for amulets and such must be done elsewhere.
  6.   */
  7.  boolean
  8.  Can_rise_up(x, y, lev)
  9.  int x, y;
  10.  d_level *lev;
  11.  {
  12.      /* can't rise up from inside the top of the Wizard's tower */
  13.      /* KMH -- or in sokoban */
  14.      if (In_endgame(lev) || In_sokoban(lev)
  15.          || (Is_wiz1_level(lev) && In_W_tower(x, y, lev)))
  16.          return FALSE;
  17.      return (boolean) (lev->dlevel > 1
  18.                        || (dungeons[lev->dnum].entry_lev == 1
  19.                            && ledger_no(lev) != 1
  20.                            && sstairs.sx && sstairs.up));
  21.  }
  22.  

has_ceiling

  1.  boolean
  2.  has_ceiling(lev)
  3.  d_level *lev;
  4.  {
  5.      /* [what about level 1 of the quest?] */
  6.      return (boolean) (!Is_airlevel(lev) && !Is_waterlevel(lev));
  7.  }
  8.  

get_level

  1.  /*
  2.   * It is expected that the second argument of get_level is a depth value,
  3.   * either supplied by the user (teleport control) or randomly generated.
  4.   * But more than one level can be at the same depth.  If the target level
  5.   * is "above" the present depth location, get_level must trace "up" from
  6.   * the player's location (through the ancestors dungeons) the dungeon
  7.   * within which the target level is located.  With only one exception
  8.   * which does not pass through this routine (see level_tele), teleporting
  9.   * "down" is confined to the current dungeon.  At present, level teleport
  10.   * in dungeons that build up is confined within them.
  11.   */
  12.  void
  13.  get_level(newlevel, levnum)
  14.  d_level *newlevel;
  15.  int levnum;
  16.  {
  17.      branch *br;
  18.      xchar dgn = u.uz.dnum;
  19.  
  20.      if (levnum <= 0) {
  21.          /* can only currently happen in endgame */
  22.          levnum = u.uz.dlevel;
  23.      } else if (levnum
  24.                 > dungeons[dgn].depth_start + dungeons[dgn].num_dunlevs - 1) {
  25.          /* beyond end of dungeon, jump to last level */
  26.          levnum = dungeons[dgn].num_dunlevs;
  27.      } else {
  28.          /* The desired level is in this dungeon or a "higher" one. */
  29.  
  30.          /*
  31.           * Branch up the tree until we reach a dungeon that contains the
  32.           * levnum.
  33.           */
  34.          if (levnum < dungeons[dgn].depth_start) {
  35.              do {
  36.                  /*
  37.                   * Find the parent dungeon of this dungeon.
  38.                   *
  39.                   * This assumes that end2 is always the "child" and it is
  40.                   * unique.
  41.                   */
  42.                  for (br = branches; br; br = br->next)
  43.                      if (br->end2.dnum == dgn)
  44.                          break;
  45.                  if (!br)
  46.                      panic("get_level: can't find parent dungeon");
  47.  
  48.                  dgn = br->end1.dnum;
  49.              } while (levnum < dungeons[dgn].depth_start);
  50.          }
  51.  
  52.          /* We're within the same dungeon; calculate the level. */
  53.          levnum = levnum - dungeons[dgn].depth_start + 1;
  54.      }
  55.  
  56.      newlevel->dnum = dgn;
  57.      newlevel->dlevel = levnum;
  58.  }
  59.  

In_quest

  1.  /* are you in the quest dungeon? */
  2.  boolean
  3.  In_quest(lev)
  4.  d_level *lev;
  5.  {
  6.      return (boolean) (lev->dnum == quest_dnum);
  7.  }
  8.  

In_mines

  1.  /* are you in the mines dungeon? */
  2.  boolean
  3.  In_mines(lev)
  4.  d_level *lev;
  5.  {
  6.      return (boolean) (lev->dnum == mines_dnum);
  7.  }
  8.  

dungeon_branch

  1.  /*
  2.   * Return the branch for the given dungeon.
  3.   *
  4.   * This function assumes:
  5.   *      + This is not called with "Dungeons of Doom".
  6.   *      + There is only _one_ branch to a given dungeon.
  7.   *      + Field end2 is the "child" dungeon.
  8.   */
  9.  branch *
  10.  dungeon_branch(s)
  11.  const char *s;
  12.  {
  13.      branch *br;
  14.      xchar dnum;
  15.  
  16.      dnum = dname_to_dnum(s);
  17.  
  18.      /* Find the branch that connects to dungeon i's branch. */
  19.      for (br = branches; br; br = br->next)
  20.          if (br->end2.dnum == dnum)
  21.              break;
  22.  
  23.      if (!br)
  24.          panic("dgn_entrance: can't find entrance to %s", s);
  25.  
  26.      return br;
  27.  }
  28.  

at_dgn_entrance

  1.  /*
  2.   * This returns true if the hero is on the same level as the entrance to
  3.   * the named dungeon.
  4.   *
  5.   * Called from do.c and mklev.c.
  6.   *
  7.   * Assumes that end1 is always the "parent".
  8.   */
  9.  boolean
  10.  at_dgn_entrance(s)
  11.  const char *s;
  12.  {
  13.      branch *br;
  14.  
  15.      br = dungeon_branch(s);
  16.      return on_level(&u.uz, &br->end1) ? TRUE : FALSE;
  17.  }
  18.  

In_V_tower

  1.  /* is `lev' part of Vlad's tower? */
  2.  boolean
  3.  In_V_tower(lev)
  4.  d_level *lev;
  5.  {
  6.      return (boolean) (lev->dnum == tower_dnum);
  7.  }
  8.  

On_W_tower_level

  1.  /* is `lev' a level containing the Wizard's tower? */
  2.  boolean
  3.  On_W_tower_level(lev)
  4.  d_level *lev;
  5.  {
  6.      return (boolean) (Is_wiz1_level(lev)
  7.                        || Is_wiz2_level(lev)
  8.                        || Is_wiz3_level(lev));
  9.  }
  10.  

In_W_tower

  1.  /* is <x,y> of `lev' inside the Wizard's tower? */
  2.  boolean
  3.  In_W_tower(x, y, lev)
  4.  int x, y;
  5.  d_level *lev;
  6.  {
  7.      if (!On_W_tower_level(lev))
  8.          return FALSE;
  9.      /*
  10.       * Both of the exclusion regions for arriving via level teleport
  11.       * (from above or below) define the tower's boundary.
  12.       *  assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} );
  13.       */
  14.      if (dndest.nlx > 0)
  15.          return (boolean) within_bounded_area(x, y, dndest.nlx, dndest.nly,
  16.                                               dndest.nhx, dndest.nhy);
  17.      else
  18.          impossible("No boundary for Wizard's Tower?");
  19.      return FALSE;
  20.  }
  21.  

In_hell

  1.  /* are you in one of the Hell levels? */
  2.  boolean
  3.  In_hell(lev)
  4.  d_level *lev;
  5.  {
  6.      return (boolean) (dungeons[lev->dnum].flags.hellish);
  7.  }
  8.  

find_hell

  1.  /* sets *lev to be the gateway to Gehennom... */
  2.  void
  3.  find_hell(lev)
  4.  d_level *lev;
  5.  {
  6.      lev->dnum = valley_level.dnum;
  7.      lev->dlevel = 1;
  8.  }
  9.  

goto_hell

  1.  /* go directly to hell... */
  2.  void
  3.  goto_hell(at_stairs, falling)
  4.  boolean at_stairs, falling;
  5.  {
  6.      d_level lev;
  7.  
  8.      find_hell(&lev);
  9.      goto_level(&lev, at_stairs, falling, FALSE);
  10.  }
  11.  

assign_level

  1.  /* equivalent to dest = source */
  2.  void
  3.  assign_level(dest, src)
  4.  d_level *dest, *src;
  5.  {
  6.      dest->dnum = src->dnum;
  7.      dest->dlevel = src->dlevel;
  8.  }
  9.  

assign_rnd_level

  1.  /* dest = src + rn1(range) */
  2.  void
  3.  assign_rnd_level(dest, src, range)
  4.  d_level *dest, *src;
  5.  int range;
  6.  {
  7.      dest->dnum = src->dnum;
  8.      dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range));
  9.  
  10.      if (dest->dlevel > dunlevs_in_dungeon(dest))
  11.          dest->dlevel = dunlevs_in_dungeon(dest);
  12.      else if (dest->dlevel < 1)
  13.          dest->dlevel = 1;
  14.  }
  15.  

induced_align

  1.  int
  2.  induced_align(pct)
  3.  int pct;
  4.  {
  5.      s_level *lev = Is_special(&u.uz);
  6.      aligntyp al;
  7.  
  8.      if (lev && lev->flags.align)
  9.          if (rn2(100) < pct)
  10.              return lev->flags.align;
  11.  
  12.      if (dungeons[u.uz.dnum].flags.align)
  13.          if (rn2(100) < pct)
  14.              return dungeons[u.uz.dnum].flags.align;
  15.  
  16.      al = rn2(3) - 1;
  17.      return Align2amask(al);
  18.  }
  19.  

Invocation_lev

  1.  boolean
  2.  Invocation_lev(lev)
  3.  d_level *lev;
  4.  {
  5.      return (boolean) (In_hell(lev)
  6.                        && lev->dlevel == dungeons[lev->dnum].num_dunlevs - 1);
  7.  }
  8.  

level_difficulty

  1.  /* use instead of depth() wherever a degree of difficulty is made
  2.   * dependent on the location in the dungeon (eg. monster creation).
  3.   */
  4.  xchar
  5.  level_difficulty()
  6.  {
  7.      int res;
  8.  
  9.      if (In_endgame(&u.uz)) {
  10.          res = depth(&sanctum_level) + u.ulevel / 2;
  11.      } else if (u.uhave.amulet) {
  12.          res = deepest_lev_reached(FALSE);
  13.      } else {
  14.          res = depth(&u.uz);
  15.          /* depth() is the number of elevation units (levels) below
  16.             the theoretical surface; in a builds-up branch, that value
  17.             ends up making the harder to reach levels be treated as if
  18.             they were easier; adjust for the extra effort involved in
  19.             going down to the entrance and then up to the location */
  20.          if (builds_up(&u.uz))
  21.              res += 2 * (dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1);
  22.              /*
  23.               * 'Proof' by example:  suppose the entrance to sokoban is
  24.               * on dungeon level 9, leading up to bottom sokoban level
  25.               * of 8 [entry_lev].  When the hero is on sokoban level 8
  26.               * [uz.dlevel], depth() yields eight but he has ventured
  27.               * one level beyond 9, so difficulty depth should be 10:
  28.               *   8 + 2 * (8 - 8 + 1) => 10.
  29.               * Going up to 7, depth is 7 but hero will be two beyond 9:
  30.               *   7 + 2 * (8 - 7 + 1) => 11.
  31.               * When he goes up to level 6, three levels beyond 9:
  32.               *   6 + 2 * (8 - 6 + 1) => 12.
  33.               * And the top level of sokoban at 5, four levels beyond 9:
  34.               *   5 + 2 * (8 - 5 + 1) => 13.
  35.               * The same applies to Vlad's Tower, although the increment
  36.               * there is inconsequential compared to overall depth.
  37.               */
  38.      }
  39.      return (xchar) res;
  40.  }
  41.  

lev_by_name

  1.  /* Take one word and try to match it to a level.
  2.   * Recognized levels are as shown by print_dungeon().
  3.   */
  4.  schar
  5.  lev_by_name(nam)
  6.  const char *nam;
  7.  {
  8.      schar lev = 0;
  9.      s_level *slev;
  10.      d_level dlev;
  11.      const char *p;
  12.      int idx, idxtoo;
  13.      char buf[BUFSZ];
  14.  
  15.      /* allow strings like "the oracle level" to find "oracle" */
  16.      if (!strncmpi(nam, "the ", 4))
  17.          nam += 4;
  18.      if ((p = strstri(nam, " level")) != 0 && p == eos((char *) nam) - 6) {
  19.          nam = strcpy(buf, nam);
  20.          *(eos(buf) - 6) = '\0';
  21.      }
  22.      /* hell is the old name, and wouldn't match; gehennom would match its
  23.         branch, yielding the castle level instead of the valley of the dead */
  24.      if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) {
  25.          if (In_V_tower(&u.uz))
  26.              nam = " to Vlad's tower"; /* branch to... */
  27.          else
  28.              nam = "valley";
  29.      }
  30.  
  31.      if ((slev = find_level(nam)) != 0) {
  32.          dlev = slev->dlevel;
  33.          idx = ledger_no(&dlev);
  34.          if ((dlev.dnum == u.uz.dnum
  35.               /* within same branch, or else main dungeon <-> gehennom */
  36.               || (u.uz.dnum == valley_level.dnum
  37.                   && dlev.dnum == medusa_level.dnum)
  38.               || (u.uz.dnum == medusa_level.dnum
  39.                   && dlev.dnum == valley_level.dnum))
  40.              && (/* either wizard mode or else seen and not forgotten */
  41.                  wizard
  42.                  || (level_info[idx].flags & (FORGOTTEN | VISITED))
  43.                         == VISITED)) {
  44.              lev = depth(&slev->dlevel);
  45.          }
  46.      } else { /* not a specific level; try branch names */
  47.          idx = find_branch(nam, (struct proto_dungeon *) 0);
  48.          /* "<branch> to Xyzzy" */
  49.          if (idx < 0 && (p = strstri(nam, " to ")) != 0)
  50.              idx = find_branch(p + 4, (struct proto_dungeon *) 0);
  51.  
  52.          if (idx >= 0) {
  53.              idxtoo = (idx >> 8) & 0x00FF;
  54.              idx &= 0x00FF;
  55.              if (/* either wizard mode, or else _both_ sides of branch seen */
  56.                  wizard
  57.                  || ((level_info[idx].flags & (FORGOTTEN | VISITED)) == VISITED
  58.                      && (level_info[idxtoo].flags & (FORGOTTEN | VISITED))
  59.                             == VISITED)) {
  60.                  if (ledger_to_dnum(idxtoo) == u.uz.dnum)
  61.                      idx = idxtoo;
  62.                  dlev.dnum = ledger_to_dnum(idx);
  63.                  dlev.dlevel = ledger_to_dlev(idx);
  64.                  lev = depth(&dlev);
  65.              }
  66.          }
  67.      }
  68.      return lev;
  69.  }
  70.  

unplaced_floater

  1.  STATIC_OVL boolean
  2.  unplaced_floater(dptr)
  3.  struct dungeon *dptr;
  4.  {
  5.      branch *br;
  6.      int idx = (int) (dptr - dungeons);
  7.  
  8.      /* if other floating branches are added, this will need to change */
  9.      if (idx != knox_level.dnum)
  10.          return FALSE;
  11.      for (br = branches; br; br = br->next)
  12.          if (br->end1.dnum == n_dgns && br->end2.dnum == idx)
  13.              return TRUE;
  14.      return FALSE;
  15.  }
  16.  

unreachable_level

  1.  STATIC_OVL boolean
  2.  unreachable_level(lvl_p, unplaced)
  3.  d_level *lvl_p;
  4.  boolean unplaced;
  5.  {
  6.      s_level *dummy;
  7.  
  8.      if (unplaced)
  9.          return TRUE;
  10.      if (In_endgame(&u.uz) && !In_endgame(lvl_p))
  11.          return TRUE;
  12.      if ((dummy = find_level("dummy")) != 0 && on_level(lvl_p, &dummy->dlevel))
  13.          return TRUE;
  14.      return FALSE;
  15.  }
  16.  

tport_menu

  1.  static void
  2.  tport_menu(win, entry, lchoices, lvl_p, unreachable)
  3.  winid win;
  4.  char *entry;
  5.  struct lchoice *lchoices;
  6.  d_level *lvl_p;
  7.  boolean unreachable;
  8.  {
  9.      char tmpbuf[BUFSZ];
  10.      anything any;
  11.  
  12.      lchoices->lev[lchoices->idx] = lvl_p->dlevel;
  13.      lchoices->dgn[lchoices->idx] = lvl_p->dnum;
  14.      lchoices->playerlev[lchoices->idx] = depth(lvl_p);
  15.      any = zeroany;
  16.      if (unreachable) {
  17.          /* not selectable, but still consumes next menuletter;
  18.             prepend padding in place of missing menu selector */
  19.          Sprintf(tmpbuf, "    %s", entry);
  20.          entry = tmpbuf;
  21.      } else {
  22.          any.a_int = lchoices->idx + 1;
  23.      }
  24.      add_menu(win, NO_GLYPH, &any, lchoices->menuletter, 0, ATR_NONE, entry,
  25.               MENU_UNSELECTED);
  26.      /* this assumes there are at most 52 interesting levels */
  27.      if (lchoices->menuletter == 'z')
  28.          lchoices->menuletter = 'A';
  29.      else
  30.          lchoices->menuletter++;
  31.      lchoices->idx++;
  32.      return;
  33.  }
  34.  

br_string

  1.  /* Convert a branch type to a string usable by print_dungeon(). */
  2.  STATIC_OVL const char *
  3.  br_string(type)
  4.  int type;
  5.  {
  6.      switch (type) {
  7.      case BR_PORTAL:
  8.          return "Portal";
  9.      case BR_NO_END1:
  10.          return "Connection";
  11.      case BR_NO_END2:
  12.          return "One way stair";
  13.      case BR_STAIR:
  14.          return "Stair";
  15.      }
  16.      return " (unknown)";
  17.  }
  18.  

print_branch

  1.  /* Print all child branches between the lower and upper bounds. */
  2.  STATIC_OVL void
  3.  print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices_p)
  4.  winid win;
  5.  int dnum;
  6.  int lower_bound;
  7.  int upper_bound;
  8.  boolean bymenu;
  9.  struct lchoice *lchoices_p;
  10.  {
  11.      branch *br;
  12.      char buf[BUFSZ];
  13.  
  14.      /* This assumes that end1 is the "parent". */
  15.      for (br = branches; br; br = br->next) {
  16.          if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel
  17.              && br->end1.dlevel <= upper_bound) {
  18.              Sprintf(buf, "   %s to %s: %d", br_string(br->type),
  19.                      dungeons[br->end2.dnum].dname, depth(&br->end1));
  20.              if (bymenu)
  21.                  tport_menu(win, buf, lchoices_p, &br->end1,
  22.                             unreachable_level(&br->end1, FALSE));
  23.              else
  24.                  putstr(win, 0, buf);
  25.          }
  26.      }
  27.  }
  28.  

print_dungeon

  1.  /* Print available dungeon information. */
  2.  schar
  3.  print_dungeon(bymenu, rlev, rdgn)
  4.  boolean bymenu;
  5.  schar *rlev;
  6.  xchar *rdgn;
  7.  {
  8.      int i, last_level, nlev;
  9.      char buf[BUFSZ];
  10.      const char *descr;
  11.      boolean first, unplaced;
  12.      s_level *slev;
  13.      dungeon *dptr;
  14.      branch *br;
  15.      anything any;
  16.      struct lchoice lchoices;
  17.  
  18.      winid win = create_nhwindow(NHW_MENU);
  19.      if (bymenu) {
  20.          start_menu(win);
  21.          lchoices.idx = 0;
  22.          lchoices.menuletter = 'a';
  23.      }
  24.  
  25.      for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) {
  26.          if (bymenu && In_endgame(&u.uz) && i != astral_level.dnum)
  27.              continue;
  28.          unplaced = unplaced_floater(dptr);
  29.          descr = unplaced ? "depth" : "level";
  30.          nlev = dptr->num_dunlevs;
  31.          if (nlev > 1)
  32.              Sprintf(buf, "%s: %s %d to %d", dptr->dname, makeplural(descr),
  33.                      dptr->depth_start, dptr->depth_start + nlev - 1);
  34.          else
  35.              Sprintf(buf, "%s: %s %d", dptr->dname, descr, dptr->depth_start);
  36.  
  37.          /* Most entrances are uninteresting. */
  38.          if (dptr->entry_lev != 1) {
  39.              if (dptr->entry_lev == nlev)
  40.                  Strcat(buf, ", entrance from below");
  41.              else
  42.                  Sprintf(eos(buf), ", entrance on %d",
  43.                          dptr->depth_start + dptr->entry_lev - 1);
  44.          }
  45.          if (bymenu) {
  46.              any = zeroany;
  47.              add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf,
  48.                       MENU_UNSELECTED);
  49.          } else
  50.              putstr(win, 0, buf);
  51.  
  52.          /*
  53.           * Circle through the special levels to find levels that are in
  54.           * this dungeon.
  55.           */
  56.          for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) {
  57.              if (slev->dlevel.dnum != i)
  58.                  continue;
  59.  
  60.              /* print any branches before this level */
  61.              print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu,
  62.                           &lchoices);
  63.  
  64.              Sprintf(buf, "   %s: %d", slev->proto, depth(&slev->dlevel));
  65.              if (Is_stronghold(&slev->dlevel))
  66.                  Sprintf(eos(buf), " (tune %s)", tune);
  67.              if (bymenu)
  68.                  tport_menu(win, buf, &lchoices, &slev->dlevel,
  69.                             unreachable_level(&slev->dlevel, unplaced));
  70.              else
  71.                  putstr(win, 0, buf);
  72.  
  73.              last_level = slev->dlevel.dlevel;
  74.          }
  75.          /* print branches after the last special level */
  76.          print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices);
  77.      }
  78.  
  79.      if (bymenu) {
  80.          int n;
  81.          menu_item *selected;
  82.          int idx;
  83.  
  84.          end_menu(win, "Level teleport to where:");
  85.          n = select_menu(win, PICK_ONE, &selected);
  86.          destroy_nhwindow(win);
  87.          if (n > 0) {
  88.              idx = selected[0].item.a_int - 1;
  89.              free((genericptr_t) selected);
  90.              if (rlev && rdgn) {
  91.                  *rlev = lchoices.lev[idx];
  92.                  *rdgn = lchoices.dgn[idx];
  93.                  return lchoices.playerlev[idx];
  94.              }
  95.          }
  96.          return 0;
  97.      }
  98.  
  99.      /* Print out floating branches (if any). */
  100.      for (first = TRUE, br = branches; br; br = br->next) {
  101.          if (br->end1.dnum == n_dgns) {
  102.              if (first) {
  103.                  putstr(win, 0, "");
  104.                  putstr(win, 0, "Floating branches");
  105.                  first = FALSE;
  106.              }
  107.              Sprintf(buf, "   %s to %s", br_string(br->type),
  108.                      dungeons[br->end2.dnum].dname);
  109.              putstr(win, 0, buf);
  110.          }
  111.      }
  112.  
  113.      /* I hate searching for the invocation pos while debugging. -dean */
  114.      if (Invocation_lev(&u.uz)) {
  115.          putstr(win, 0, "");
  116.          Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)",
  117.                  inv_pos.x, inv_pos.y, u.ux, u.uy);
  118.          putstr(win, 0, buf);
  119.      }
  120.      /*
  121.       * The following is based on the assumption that the inter-level portals
  122.       * created by the level compiler (not the dungeon compiler) only exist
  123.       * one per level (currently true, of course).
  124.       */
  125.      else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz)
  126.               || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) {
  127.          struct trap *trap;
  128.          for (trap = ftrap; trap; trap = trap->ntrap)
  129.              if (trap->ttyp == MAGIC_PORTAL)
  130.                  break;
  131.  
  132.          putstr(win, 0, "");
  133.          if (trap)
  134.              Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)", trap->tx,
  135.                      trap->ty, u.ux, u.uy);
  136.          else
  137.              Sprintf(buf, "No portal found.");
  138.          putstr(win, 0, buf);
  139.      }
  140.  
  141.      display_nhwindow(win, TRUE);
  142.      destroy_nhwindow(win);
  143.      return 0;
  144.  }
  145.  

recbranch_mapseen

  1.  /* Record that the player knows about a branch from a level. This function
  2.   * will determine whether or not it was a "real" branch that was taken.
  3.   * This function should not be called for a transition done via level
  4.   * teleport or via the Eye.
  5.   */
  6.  void
  7.  recbranch_mapseen(source, dest)
  8.  d_level *source;
  9.  d_level *dest;
  10.  {
  11.      mapseen *mptr;
  12.      branch *br;
  13.  
  14.      /* not a branch */
  15.      if (source->dnum == dest->dnum)
  16.          return;
  17.  
  18.      /* we only care about forward branches */
  19.      for (br = branches; br; br = br->next) {
  20.          if (on_level(source, &br->end1) && on_level(dest, &br->end2))
  21.              break;
  22.          if (on_level(source, &br->end2) && on_level(dest, &br->end1))
  23.              return;
  24.      }
  25.  
  26.      /* branch not found, so not a real branch. */
  27.      if (!br)
  28.          return;
  29.  
  30.      if ((mptr = find_mapseen(source)) != 0) {
  31.          if (mptr->br && br != mptr->br)
  32.              impossible("Two branches on the same level?");
  33.          mptr->br = br;
  34.      } else {
  35.          impossible("Can't note branch for unseen level (%d, %d)",
  36.                     source->dnum, source->dlevel);
  37.      }
  38.  }
  39.  

get_annotation

  1.  char *
  2.  get_annotation(lev)
  3.  d_level *lev;
  4.  {
  5.      mapseen *mptr;
  6.  
  7.      if ((mptr = find_mapseen(lev)))
  8.          return mptr->custom;
  9.      return NULL;
  10.  }
  11.  

donamelevel

  1.  /* #annotate command - add a custom name to the current level */
  2.  int
  3.  donamelevel()
  4.  {
  5.      mapseen *mptr;
  6.      char nbuf[BUFSZ]; /* Buffer for response */
  7.  
  8.      if (!(mptr = find_mapseen(&u.uz)))
  9.          return 0;
  10.  
  11.      if (mptr->custom) {
  12.          char tmpbuf[BUFSZ];
  13.          Sprintf(tmpbuf, "Replace annotation \"%.30s%s\" with?", mptr->custom,
  14.                  strlen(mptr->custom) > 30 ? "..." : "");
  15.          getlin(tmpbuf, nbuf);
  16.      } else
  17.          getlin("What do you want to call this dungeon level?", nbuf);
  18.      if (index(nbuf, '\033'))
  19.          return 0;
  20.      (void) mungspaces(nbuf);
  21.  
  22.      /* discard old annotation, if any */
  23.      if (mptr->custom) {
  24.          free((genericptr_t) mptr->custom);
  25.          mptr->custom = (char *) 0;
  26.          mptr->custom_lth = 0;
  27.      }
  28.      /* add new annotation, unless it's empty or a single space */
  29.      if (*nbuf && strcmp(nbuf, " ")) {
  30.          mptr->custom = dupstr(nbuf);
  31.          mptr->custom_lth = strlen(mptr->custom);
  32.      }
  33.      return 0;
  34.  }
  35.  

find_mapseen

  1.  /* find the particular mapseen object in the chain; may return null */
  2.  STATIC_OVL mapseen *
  3.  find_mapseen(lev)
  4.  d_level *lev;
  5.  {
  6.      mapseen *mptr;
  7.  
  8.      for (mptr = mapseenchn; mptr; mptr = mptr->next)
  9.          if (on_level(&(mptr->lev), lev))
  10.              break;
  11.  
  12.      return mptr;
  13.  }
  14.  

forget_mapseen

  1.  void
  2.  forget_mapseen(ledger_num)
  3.  int ledger_num;
  4.  {
  5.      mapseen *mptr;
  6.      struct cemetery *bp;
  7.  
  8.      for (mptr = mapseenchn; mptr; mptr = mptr->next)
  9.          if (dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel
  10.              == ledger_num)
  11.              break;
  12.  
  13.      /* if not found, then nothing to forget */
  14.      if (mptr) {
  15.          mptr->flags.forgot = 1;
  16.          mptr->br = (branch *) 0;
  17.  
  18.          /* custom names are erased, not just forgotten until revisited */
  19.          if (mptr->custom) {
  20.              mptr->custom_lth = 0;
  21.              free((genericptr_t) mptr->custom);
  22.              mptr->custom = (char *) 0;
  23.          }
  24.          (void) memset((genericptr_t) mptr->msrooms, 0, sizeof mptr->msrooms);
  25.          for (bp = mptr->final_resting_place; bp; bp = bp->next)
  26.              bp->bonesknown = FALSE;
  27.      }
  28.  }
  29.  

save_mapseen

  1.  STATIC_OVL void
  2.  save_mapseen(fd, mptr)
  3.  int fd;
  4.  mapseen *mptr;
  5.  {
  6.      branch *curr;
  7.      int brindx;
  8.  
  9.      for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx)
  10.          if (curr == mptr->br)
  11.              break;
  12.      bwrite(fd, (genericptr_t) &brindx, sizeof brindx);
  13.  
  14.      bwrite(fd, (genericptr_t) &mptr->lev, sizeof mptr->lev);
  15.      bwrite(fd, (genericptr_t) &mptr->feat, sizeof mptr->feat);
  16.      bwrite(fd, (genericptr_t) &mptr->flags, sizeof mptr->flags);
  17.      bwrite(fd, (genericptr_t) &mptr->custom_lth, sizeof mptr->custom_lth);
  18.      if (mptr->custom_lth)
  19.          bwrite(fd, (genericptr_t) mptr->custom, mptr->custom_lth);
  20.      bwrite(fd, (genericptr_t) &mptr->msrooms, sizeof mptr->msrooms);
  21.      savecemetery(fd, WRITE_SAVE, &mptr->final_resting_place);
  22.  }
  23.  

load_mapseen

  1.  STATIC_OVL mapseen *
  2.  load_mapseen(fd)
  3.  int fd;
  4.  {
  5.      int branchnum, brindx;
  6.      mapseen *load;
  7.      branch *curr;
  8.  
  9.      load = (mapseen *) alloc(sizeof *load);
  10.  
  11.      mread(fd, (genericptr_t) &branchnum, sizeof branchnum);
  12.      for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx)
  13.          if (brindx == branchnum)
  14.              break;
  15.      load->br = curr;
  16.  
  17.      mread(fd, (genericptr_t) &load->lev, sizeof load->lev);
  18.      mread(fd, (genericptr_t) &load->feat, sizeof load->feat);
  19.      mread(fd, (genericptr_t) &load->flags, sizeof load->flags);
  20.      mread(fd, (genericptr_t) &load->custom_lth, sizeof load->custom_lth);
  21.      if (load->custom_lth) {
  22.          /* length doesn't include terminator (which isn't saved & restored) */
  23.          load->custom = (char *) alloc(load->custom_lth + 1);
  24.          mread(fd, (genericptr_t) load->custom, load->custom_lth);
  25.          load->custom[load->custom_lth] = '\0';
  26.      } else
  27.          load->custom = 0;
  28.      mread(fd, (genericptr_t) &load->msrooms, sizeof load->msrooms);
  29.      restcemetery(fd, &load->final_resting_place);
  30.  
  31.      return load;
  32.  }
  33.  

remdun_mapseen

  1.  /* Remove all mapseen objects for a particular dnum.
  2.   * Useful during quest expulsion to remove quest levels.
  3.   * [No longer deleted, just marked as unreachable.  #overview will
  4.   * ignore such levels, end of game disclosure will include them.]
  5.   */
  6.  void
  7.  remdun_mapseen(dnum)
  8.  int dnum;
  9.  {
  10.      mapseen *mptr, **mptraddr;
  11.  
  12.      mptraddr = &mapseenchn;
  13.      while ((mptr = *mptraddr) != 0) {
  14.          if (mptr->lev.dnum == dnum) {
  15.  #if 1 /* use this... */
  16.              mptr->flags.unreachable = 1;
  17.          }
  18.  #else /* old deletion code */
  19.              *mptraddr = mptr->next;
  20.              if (mptr->custom)
  21.                  free((genericptr_t) mptr->custom);
  22.              if (mptr->final_resting_place)
  23.                  savecemetery(-1, FREE_SAVE, &mptr->final_resting_place);
  24.              free((genericptr_t) mptr);
  25.          } else
  26.  #endif
  27.          mptraddr = &mptr->next;
  28.      }
  29.  }
  30.  

init_mapseen

  1.  void
  2.  init_mapseen(lev)
  3.  d_level *lev;
  4.  {
  5.      /* Create a level and insert in "sorted" order.  This is an insertion
  6.       * sort first by dungeon (in order of discovery) and then by level number.
  7.       */
  8.      mapseen *mptr, *init, *prev;
  9.  
  10.      init = (mapseen *) alloc(sizeof *init);
  11.      (void) memset((genericptr_t) init, 0, sizeof *init);
  12.      /* memset is fine for feature bits, flags, and rooms array;
  13.         explicitly initialize pointers to null */
  14.      init->next = 0, init->br = 0, init->custom = 0;
  15.      init->final_resting_place = 0;
  16.      /* lastseentyp[][] is reused for each level, so get rid of
  17.         previous level's data */
  18.      (void) memset((genericptr_t) lastseentyp, 0, sizeof lastseentyp);
  19.  
  20.      init->lev.dnum = lev->dnum;
  21.      init->lev.dlevel = lev->dlevel;
  22.  
  23.      /* walk until we get to the place where we should insert init */
  24.      for (mptr = mapseenchn, prev = 0; mptr; prev = mptr, mptr = mptr->next)
  25.          if (mptr->lev.dnum > init->lev.dnum
  26.              || (mptr->lev.dnum == init->lev.dnum
  27.                  && mptr->lev.dlevel > init->lev.dlevel))
  28.              break;
  29.      if (!prev) {
  30.          init->next = mapseenchn;
  31.          mapseenchn = init;
  32.      } else {
  33.          mptr = prev->next;
  34.          prev->next = init;
  35.          init->next = mptr;
  36.      }
  37.  }
  38.  

interest_mapseen

  1.  #define INTEREST(feat)                                                \
  2.      ((feat).nfount || (feat).nsink || (feat).nthrone || (feat).naltar \
  3.       || (feat).ngrave || (feat).ntree || (feat).nshop || (feat).ntemple)
  4.    /* || (feat).water || (feat).ice || (feat).lava */
  5.  
  6.  /* returns true if this level has something interesting to print out */
  7.  STATIC_OVL boolean
  8.  interest_mapseen(mptr)
  9.  mapseen *mptr;
  10.  {
  11.      if (on_level(&u.uz, &mptr->lev))
  12.          return TRUE;
  13.      if (mptr->flags.unreachable || mptr->flags.forgot)
  14.          return FALSE;
  15.      /* level is of interest if it has an auto-generated annotation */
  16.      if (mptr->flags.oracle || mptr->flags.bigroom || mptr->flags.roguelevel
  17.          || mptr->flags.castle || mptr->flags.valley || mptr->flags.msanctum
  18.          || mptr->flags.quest_summons || mptr->flags.questing)
  19.          return TRUE;
  20.      /* when in Sokoban, list all sokoban levels visited; when not in it,
  21.         list any visited Sokoban level which remains unsolved (will usually
  22.         only be furthest one reached, but it's possible to enter pits and
  23.         climb out on the far side on the first Sokoban level; also, wizard
  24.         mode overrides teleport restrictions) */
  25.      if (In_sokoban(&mptr->lev)
  26.          && (In_sokoban(&u.uz) || !mptr->flags.sokosolved))
  27.          return TRUE;
  28.      /* when in the endgame, list all endgame levels visited, whether they
  29.         have annotations or not, so that #overview doesn't become extremely
  30.         sparse once the rest of the dungeon has been flagged as unreachable */
  31.      if (In_endgame(&u.uz))
  32.          return (boolean) In_endgame(&mptr->lev);
  33.      /* level is of interest if it has non-zero feature count or known bones
  34.         or user annotation or known connection to another dungeon branch
  35.         or is the furthest level reached in its branch */
  36.      return (boolean) (INTEREST(mptr->feat)
  37.                        || (mptr->final_resting_place
  38.                            && (mptr->flags.knownbones || wizard))
  39.                        || mptr->custom || mptr->br
  40.                        || (mptr->lev.dlevel
  41.                            == dungeons[mptr->lev.dnum].dunlev_ureached));
  42.  }
  43.  

recalc_mapseen

  1.  /* recalculate mapseen for the current level */
  2.  void
  3.  recalc_mapseen()
  4.  {
  5.      mapseen *mptr;
  6.      struct monst *mtmp;
  7.      struct cemetery *bp, **bonesaddr;
  8.      unsigned i, ridx;
  9.      int x, y, ltyp, count, atmp;
  10.  
  11.      /* Should not happen in general, but possible if in the process
  12.       * of being booted from the quest.  The mapseen object gets
  13.       * removed during the expulsion but prior to leaving the level
  14.       * [Since quest expulsion no longer deletes quest mapseen data,
  15.       * null return from find_mapseen() should now be impossible.]
  16.       */
  17.      if (!(mptr = find_mapseen(&u.uz)))
  18.          return;
  19.  
  20.      /* reset all features; mptr->feat.* = 0; */
  21.      (void) memset((genericptr_t) &mptr->feat, 0, sizeof mptr->feat);
  22.      /* reset most flags; some level-specific ones are left as-is */
  23.      if (mptr->flags.unreachable) {
  24.          mptr->flags.unreachable = 0; /* reached it; Eye of the Aethiopica? */
  25.          if (In_quest(&u.uz)) {
  26.              mapseen *mptrtmp = mapseenchn;
  27.  
  28.              /* when quest was unreachable due to ejection and portal removal,
  29.                 getting back to it via arti-invoke should revive annotation
  30.                 data for all quest levels, not just the one we're on now */
  31.              do {
  32.                  if (mptrtmp->lev.dnum == mptr->lev.dnum)
  33.                      mptrtmp->flags.unreachable = 0;
  34.                  mptrtmp = mptrtmp->next;
  35.              } while (mptrtmp);
  36.          }
  37.      }
  38.      mptr->flags.knownbones = 0;
  39.      mptr->flags.sokosolved = In_sokoban(&u.uz) && !Sokoban;
  40.      /* mptr->flags.bigroom retains previous value when hero can't see */
  41.      if (!Blind)
  42.          mptr->flags.bigroom = Is_bigroom(&u.uz);
  43.      else if (mptr->flags.forgot)
  44.          mptr->flags.bigroom = 0;
  45.      mptr->flags.roguelevel = Is_rogue_level(&u.uz);
  46.      mptr->flags.oracle = 0; /* recalculated during room traversal below */
  47.      mptr->flags.castletune = 0;
  48.      /* flags.castle, flags.valley, flags.msanctum retain previous value */
  49.      mptr->flags.forgot = 0;
  50.      /* flags.quest_summons disabled once quest finished */
  51.      mptr->flags.quest_summons = (at_dgn_entrance("The Quest")
  52.                                   && u.uevent.qcalled
  53.                                   && !(u.uevent.qcompleted
  54.                                        || u.uevent.qexpelled
  55.                                        || quest_status.leader_is_dead));
  56.      mptr->flags.questing = (on_level(&u.uz, &qstart_level)
  57.                              && quest_status.got_quest);
  58.  
  59.      /* track rooms the hero is in */
  60.      for (i = 0; i < SIZE(u.urooms); ++i) {
  61.          if (!u.urooms[i])
  62.              continue;
  63.  
  64.          ridx = u.urooms[i] - ROOMOFFSET;
  65.          mptr->msrooms[ridx].seen = 1;
  66.          mptr->msrooms[ridx].untended =
  67.              (rooms[ridx].rtype >= SHOPBASE)
  68.                  ? (!(mtmp = shop_keeper(u.urooms[i])) || !inhishop(mtmp))
  69.                  : (rooms[ridx].rtype == TEMPLE)
  70.                        ? (!(mtmp = findpriest(u.urooms[i]))
  71.                           || !inhistemple(mtmp))
  72.                        : 0;
  73.      }
  74.  
  75.      /* recalculate room knowledge: for now, just shops and temples
  76.       * this could be extended to an array of 0..SHOPBASE
  77.       */
  78.      for (i = 0; i < SIZE(mptr->msrooms); ++i) {
  79.          if (mptr->msrooms[i].seen) {
  80.              if (rooms[i].rtype >= SHOPBASE) {
  81.                  if (mptr->msrooms[i].untended)
  82.                      mptr->feat.shoptype = SHOPBASE - 1;
  83.                  else if (!mptr->feat.nshop)
  84.                      mptr->feat.shoptype = rooms[i].rtype;
  85.                  else if (mptr->feat.shoptype != (unsigned) rooms[i].rtype)
  86.                      mptr->feat.shoptype = 0;
  87.                  count = mptr->feat.nshop + 1;
  88.                  if (count <= 3)
  89.                      mptr->feat.nshop = count;
  90.              } else if (rooms[i].rtype == TEMPLE) {
  91.                  /* altar and temple alignment handled below */
  92.                  count = mptr->feat.ntemple + 1;
  93.                  if (count <= 3)
  94.                      mptr->feat.ntemple = count;
  95.              } else if (rooms[i].orig_rtype == DELPHI) {
  96.                  mptr->flags.oracle = 1;
  97.              }
  98.          }
  99.      }
  100.  
  101.      /* Update lastseentyp with typ if and only if it is in sight or the
  102.       * hero can feel it on their current location (i.e. not levitating).
  103.       * This *should* give the "last known typ" for each dungeon location.
  104.       * (At the very least, it's a better assumption than determining what
  105.       * the player knows from the glyph and the typ (which is isn't quite
  106.       * enough information in some cases)).
  107.       *
  108.       * It was reluctantly added to struct rm to track.  Alternatively
  109.       * we could track "features" and then update them all here, and keep
  110.       * track of when new features are created or destroyed, but this
  111.       * seemed the most elegant, despite adding more data to struct rm.
  112.       * [3.6.0: we're using lastseentyp[][] rather than level.locations
  113.       * to track the features seen.]
  114.       *
  115.       * Although no current windowing systems (can) do this, this would add
  116.       * the ability to have non-dungeon glyphs float above the last known
  117.       * dungeon glyph (i.e. items on fountains).
  118.       */
  119.      for (x = 1; x < COLNO; x++) {
  120.          for (y = 0; y < ROWNO; y++) {
  121.              if (cansee(x, y) || (x == u.ux && y == u.uy && !Levitation)) {
  122.                  ltyp = levl[x][y].typ;
  123.                  if (ltyp == DRAWBRIDGE_UP)
  124.                      ltyp = db_under_typ(levl[x][y].drawbridgemask);
  125.                  if ((mtmp = m_at(x, y)) != 0
  126.                      && mtmp->m_ap_type == M_AP_FURNITURE && canseemon(mtmp))
  127.                      ltyp = cmap_to_type(mtmp->mappearance);
  128.                  lastseentyp[x][y] = ltyp;
  129.              }
  130.  
  131.              switch (lastseentyp[x][y]) {
  132.  #if 0
  133.              case ICE:
  134.                  count = mptr->feat.ice + 1;
  135.                  if (count <= 3)
  136.                      mptr->feat.ice = count;
  137.                  break;
  138.              case POOL:
  139.              case MOAT:
  140.              case WATER:
  141.                  count = mptr->feat.water + 1;
  142.                  if (count <= 3)
  143.                      mptr->feat.water = count;
  144.                  break;
  145.              case LAVAPOOL:
  146.                  count = mptr->feat.lava + 1;
  147.                  if (count <= 3)
  148.                      mptr->feat.lava = count;
  149.                  break;
  150.  #endif
  151.              case TREE:
  152.                  count = mptr->feat.ntree + 1;
  153.                  if (count <= 3)
  154.                      mptr->feat.ntree = count;
  155.                  break;
  156.              case FOUNTAIN:
  157.                  count = mptr->feat.nfount + 1;
  158.                  if (count <= 3)
  159.                      mptr->feat.nfount = count;
  160.                  break;
  161.              case THRONE:
  162.                  count = mptr->feat.nthrone + 1;
  163.                  if (count <= 3)
  164.                      mptr->feat.nthrone = count;
  165.                  break;
  166.              case SINK:
  167.                  count = mptr->feat.nsink + 1;
  168.                  if (count <= 3)
  169.                      mptr->feat.nsink = count;
  170.                  break;
  171.              case GRAVE:
  172.                  count = mptr->feat.ngrave + 1;
  173.                  if (count <= 3)
  174.                      mptr->feat.ngrave = count;
  175.                  break;
  176.              case ALTAR:
  177.                  atmp = (Is_astralevel(&u.uz)
  178.                          && (levl[x][y].seenv & SVALL) != SVALL)
  179.                           ? MSA_NONE
  180.                           : Amask2msa(levl[x][y].altarmask);
  181.                  if (!mptr->feat.naltar)
  182.                      mptr->feat.msalign = atmp;
  183.                  else if (mptr->feat.msalign != atmp)
  184.                      mptr->feat.msalign = MSA_NONE;
  185.                  count = mptr->feat.naltar + 1;
  186.                  if (count <= 3)
  187.                      mptr->feat.naltar = count;
  188.                  break;
  189.              /*  An automatic annotation is added to the Castle and
  190.               *  to Fort Ludios once their structure's main entrance
  191.               *  has been seen (in person or via magic mapping).
  192.               * DOOR: possibly a lowered drawbridge's open portcullis;
  193.               * DBWALL: a raised drawbridge's "closed door";
  194.               * DRAWBRIDGE_DOWN: the span provided by lowered bridge,
  195.               *  with moat or other terrain hidden underneath;
  196.               * DRAWBRIDGE_UP: moat in front of a raised drawbridge,
  197.               *  not recognizable as a bridge location unless/until
  198.               *  the adjacent DBWALL has been seen.
  199.               */
  200.              case DOOR:
  201.                  if (is_drawbridge_wall(x, y) < 0)
  202.                      break;
  203.              /* else FALLTHRU */
  204.              case DBWALL:
  205.              case DRAWBRIDGE_DOWN:
  206.                  if (Is_stronghold(&u.uz))
  207.                      mptr->flags.castle = 1, mptr->flags.castletune = 1;
  208.                  else if (Is_knox(&u.uz))
  209.                      mptr->flags.ludios = 1;
  210.                  break;
  211.              default:
  212.                  break;
  213.              }
  214.          }
  215.      }
  216.  
  217.      if (level.bonesinfo && !mptr->final_resting_place) {
  218.          /* clone the bonesinfo so we aren't dependent upon this
  219.             level being in memory */
  220.          bonesaddr = &mptr->final_resting_place;
  221.          bp = level.bonesinfo;
  222.          do {
  223.              *bonesaddr = (struct cemetery *) alloc(sizeof **bonesaddr);
  224.              **bonesaddr = *bp;
  225.              bp = bp->next;
  226.              bonesaddr = &(*bonesaddr)->next;
  227.          } while (bp);
  228.          *bonesaddr = 0;
  229.      }
  230.      /* decide which past hero deaths have become known; there's no
  231.         guarantee of either a grave or a ghost, so we go by whether the
  232.         current hero has seen the map location where each old one died */
  233.      for (bp = mptr->final_resting_place; bp; bp = bp->next)
  234.          if (lastseentyp[bp->frpx][bp->frpy]) {
  235.              bp->bonesknown = TRUE;
  236.              mptr->flags.knownbones = 1;
  237.          }
  238.  }
  239.  

mapseen_temple

  1.  /*ARGUSED*/
  2.  /* valley and sanctum levels get automatic annotation once temple is entered
  3.   */
  4.  void
  5.  mapseen_temple(priest)
  6.  struct monst *priest UNUSED; /* currently unused; might be useful someday */
  7.  {
  8.      mapseen *mptr = find_mapseen(&u.uz);
  9.  
  10.      if (Is_valley(&u.uz))
  11.          mptr->flags.valley = 1;
  12.      else if (Is_sanctum(&u.uz))
  13.          mptr->flags.msanctum = 1;
  14.  }
  15.  

room_discovered

  1.  /* room entry message has just been delivered so learn room even if blind */
  2.  void
  3.  room_discovered(roomno)
  4.  int roomno;
  5.  {
  6.      mapseen *mptr = find_mapseen(&u.uz);
  7.  
  8.      mptr->msrooms[roomno].seen = 1;
  9.  }
  10.  

dooverview

  1.  /* #overview command */
  2.  int
  3.  dooverview()
  4.  {
  5.      show_overview(0, 0);
  6.      return 0;
  7.  }
  8.  

show_overview

  1.  /* called for #overview or for end of game disclosure */
  2.  void
  3.  show_overview(why, reason)
  4.  int why;    /* 0 => #overview command,
  5.                 1 or 2 => final disclosure (1: hero lived, 2: hero died) */
  6.  int reason; /* how hero died; used when disclosing end-of-game level */
  7.  {
  8.      winid win;
  9.      int lastdun = -1;
  10.  
  11.      /* lazy initialization */
  12.      (void) recalc_mapseen();
  13.  
  14.      win = create_nhwindow(NHW_MENU);
  15.      /* show the endgame levels before the rest of the dungeon,
  16.         so that the Planes (dnum 5-ish) come out above main dungeon (dnum 0) */
  17.      if (In_endgame(&u.uz))
  18.          traverse_mapseenchn(TRUE, win, why, reason, &lastdun);
  19.      /* if game is over or we're not in the endgame yet, show the dungeon */
  20.      if (why > 0 || !In_endgame(&u.uz))
  21.          traverse_mapseenchn(FALSE, win, why, reason, &lastdun);
  22.      display_nhwindow(win, TRUE);
  23.      destroy_nhwindow(win);
  24.  }
  25.  

traverse_mapseenchn

  1.  /* display endgame levels or non-endgame levels, not both */
  2.  STATIC_OVL void
  3.  traverse_mapseenchn(viewendgame, win, why, reason, lastdun_p)
  4.  boolean viewendgame;
  5.  winid win;
  6.  int why, reason, *lastdun_p;
  7.  {
  8.      mapseen *mptr;
  9.      boolean showheader;
  10.  
  11.      for (mptr = mapseenchn; mptr; mptr = mptr->next) {
  12.          if (viewendgame ^ In_endgame(&mptr->lev))
  13.              continue;
  14.  
  15.          /* only print out info for a level or a dungeon if interest */
  16.          if (why > 0 || interest_mapseen(mptr)) {
  17.              showheader = (boolean) (mptr->lev.dnum != *lastdun_p);
  18.              print_mapseen(win, mptr, why, reason, showheader);
  19.              *lastdun_p = mptr->lev.dnum;
  20.          }
  21.      }
  22.  }
  23.  

seen_string

  1.  STATIC_OVL const char *
  2.  seen_string(x, obj)
  3.  xchar x;
  4.  const char *obj;
  5.  {
  6.      /* players are computer scientists: 0, 1, 2, n */
  7.      switch (x) {
  8.      case 0:
  9.          return "no";
  10.      /* an() returns too much.  index is ok in this case */
  11.      case 1:
  12.          return index(vowels, *obj) ? "an" : "a";
  13.      case 2:
  14.          return "some";
  15.      case 3:
  16.          return "many";
  17.      }
  18.  
  19.      return "(unknown)";
  20.  }
  21.  

br_string2

  1.  /* better br_string */
  2.  STATIC_OVL const char *
  3.  br_string2(br)
  4.  branch *br;
  5.  {
  6.      /* Special case: quest portal says closed if kicked from quest */
  7.      boolean closed_portal = (br->end2.dnum == quest_dnum
  8.                               && u.uevent.qexpelled);
  9.  
  10.      switch (br->type) {
  11.      case BR_PORTAL:
  12.          return closed_portal ? "Sealed portal" : "Portal";
  13.      case BR_NO_END1:
  14.          return "Connection";
  15.      case BR_NO_END2:
  16.          return br->end1_up ? "One way stairs up" : "One way stairs down";
  17.      case BR_STAIR:
  18.          return br->end1_up ? "Stairs up" : "Stairs down";
  19.      }
  20.  
  21.      return "(unknown)";
  22.  }
  23.  

endgamelevelname

  1.  /* get the name of an endgame level; topten.c does something similar */
  2.  STATIC_OVL const char *
  3.  endgamelevelname(outbuf, indx)
  4.  char *outbuf;
  5.  int indx;
  6.  {
  7.      const char *planename = 0;
  8.  
  9.      *outbuf = '\0';
  10.      switch (indx) {
  11.      case -5:
  12.          Strcpy(outbuf, "Astral Plane");
  13.          break;
  14.      case -4:
  15.          planename = "Water";
  16.          break;
  17.      case -3:
  18.          planename = "Fire";
  19.          break;
  20.      case -2:
  21.          planename = "Air";
  22.          break;
  23.      case -1:
  24.          planename = "Earth";
  25.          break;
  26.      }
  27.      if (planename)
  28.          Sprintf(outbuf, "Plane of %s", planename);
  29.      else if (!*outbuf)
  30.          Sprintf(outbuf, "unknown plane #%d", indx);
  31.      return outbuf;
  32.  }
  33.  

shop_string

  1.  STATIC_OVL const char *
  2.  shop_string(rtype)
  3.  int rtype;
  4.  {
  5.      const char *str = "shop"; /* catchall */
  6.  
  7.      /* Yuck, redundancy...but shclass.name doesn't cut it as a noun */
  8.      switch (rtype) {
  9.      case SHOPBASE - 1:
  10.          str = "untended shop";
  11.          break; /* see recalc_mapseen */
  12.      case SHOPBASE:
  13.          str = "general store";
  14.          break;
  15.      case ARMORSHOP:
  16.          str = "armor shop";
  17.          break;
  18.      case SCROLLSHOP:
  19.          str = "scroll shop";
  20.          break;
  21.      case POTIONSHOP:
  22.          str = "potion shop";
  23.          break;
  24.      case WEAPONSHOP:
  25.          str = "weapon shop";
  26.          break;
  27.      case FOODSHOP:
  28.          str = "delicatessen";
  29.          break;
  30.      case RINGSHOP:
  31.          str = "jewelers";
  32.          break;
  33.      case WANDSHOP:
  34.          str = "wand shop";
  35.          break;
  36.      case BOOKSHOP:
  37.          str = "bookstore";
  38.          break;
  39.      case FODDERSHOP:
  40.          str = "health food store";
  41.          break;
  42.      case CANDLESHOP:
  43.          str = "lighting shop";
  44.          break;
  45.      default:
  46.          break;
  47.      }
  48.      return str;
  49.  }
  50.  

tunesuffix

  1.  /* if player knows about the mastermind tune, append it to Castle annotation;
  2.     if drawbridge has been destroyed, flags.castletune will be zero */
  3.  STATIC_OVL char *
  4.  tunesuffix(mptr, outbuf)
  5.  mapseen *mptr;
  6.  char *outbuf;
  7.  {
  8.      *outbuf = '\0';
  9.      if (mptr->flags.castletune && u.uevent.uheard_tune) {
  10.          char tmp[BUFSZ];
  11.  
  12.          if (u.uevent.uheard_tune == 2)
  13.              Sprintf(tmp, "notes \"%s\"", tune);
  14.          else
  15.              Strcpy(tmp, "5-note tune");
  16.          Sprintf(outbuf, " (play %s to open or close drawbridge)", tmp);
  17.      }
  18.      return outbuf;
  19.  }
  20.  

print_mapseen

  1.  /* some utility macros for print_mapseen */
  2.  #define TAB "   " /* three spaces */
  3.  #if 0
  4.  #define BULLET "" /* empty; otherwise output becomes cluttered */
  5.  #define PREFIX TAB TAB BULLET
  6.  #else                   /*!0*/
  7.  /* K&R: don't require support for concatenation of adjacent string literals */
  8.  #define PREFIX "      " /* two TABs + empty BULLET: six spaces */
  9.  #endif
  10.  #define COMMA (i++ > 0 ? ", " : PREFIX)
  11.  /* "iterate" once; safe to use as ``if (cond) ADDTOBUF(); else whatever;'' */
  12.  #define ADDNTOBUF(nam, var)                                                  \
  13.      do {                                                                     \
  14.          if (var)                                                             \
  15.              Sprintf(eos(buf), "%s%s %s%s", COMMA, seen_string((var), (nam)), \
  16.                      (nam), plur(var));                                       \
  17.      } while (0)
  18.  #define ADDTOBUF(nam, var)                           \
  19.      do {                                             \
  20.          if (var)                                     \
  21.              Sprintf(eos(buf), "%s%s", COMMA, (nam)); \
  22.      } while (0)
  23.  
  24.  STATIC_OVL void
  25.  print_mapseen(win, mptr, final, how, printdun)
  26.  winid win;
  27.  mapseen *mptr;
  28.  int final; /* 0: not final; 1: game over, alive; 2: game over, dead */
  29.  int how;   /* cause of death; only used if final==2 and mptr->lev==u.uz */
  30.  boolean printdun;
  31.  {
  32.      char buf[BUFSZ], tmpbuf[BUFSZ];
  33.      int i, depthstart, dnum;
  34.      boolean died_here = (final == 2 && on_level(&u.uz, &mptr->lev));
  35.  
  36.      /* Damnable special cases */
  37.      /* The quest and knox should appear to be level 1 to match
  38.       * other text.
  39.       */
  40.      dnum = mptr->lev.dnum;
  41.      if (dnum == quest_dnum || dnum == knox_level.dnum)
  42.          depthstart = 1;
  43.      else
  44.          depthstart = dungeons[dnum].depth_start;
  45.  
  46.      if (printdun) {
  47.          if (dungeons[dnum].dunlev_ureached == dungeons[dnum].entry_lev
  48.              /* suppress the negative numbers in the endgame */
  49.              || In_endgame(&mptr->lev))
  50.              Sprintf(buf, "%s:", dungeons[dnum].dname);
  51.          else if (builds_up(&mptr->lev))
  52.              Sprintf(buf, "%s: levels %d up to %d",
  53.                      dungeons[dnum].dname,
  54.                      depthstart + dungeons[dnum].entry_lev - 1,
  55.                      depthstart + dungeons[dnum].dunlev_ureached - 1);
  56.          else
  57.              Sprintf(buf, "%s: levels %d to %d",
  58.                      dungeons[dnum].dname, depthstart,
  59.                      depthstart + dungeons[dnum].dunlev_ureached - 1);
  60.          putstr(win, !final ? ATR_INVERSE : 0, buf);
  61.      }
  62.  
  63.      /* calculate level number */
  64.      i = depthstart + mptr->lev.dlevel - 1;
  65.      if (In_endgame(&mptr->lev))
  66.          Sprintf(buf, "%s%s:", TAB, endgamelevelname(tmpbuf, i));
  67.      else
  68.          /* FIXME: when this branch has only one level (Ft.Ludios),
  69.           * listing "Level 1:" for it might confuse inexperienced
  70.           * players into thinking there's more than one.
  71.           */
  72.          Sprintf(buf, "%sLevel %d:", TAB, i);
  73.  
  74.      /* wizmode prints out proto dungeon names for clarity */
  75.      if (wizard) {
  76.          s_level *slev;
  77.  
  78.          if ((slev = Is_special(&mptr->lev)) != 0)
  79.              Sprintf(eos(buf), " [%s]", slev->proto);
  80.      }
  81.      /* [perhaps print custom annotation on its own line when it's long] */
  82.      if (mptr->custom)
  83.          Sprintf(eos(buf), " (%s)", mptr->custom);
  84.      if (on_level(&u.uz, &mptr->lev))
  85.          Sprintf(eos(buf), " <- You %s here.",
  86.                  (!final || (final == 1 && how == ASCENDED)) ? "are" : "were");
  87.      putstr(win, !final ? ATR_BOLD : 0, buf);
  88.  
  89.      if (mptr->flags.forgot)
  90.          return;
  91.  
  92.      if (INTEREST(mptr->feat)) {
  93.          buf[0] = 0;
  94.  
  95.          i = 0; /* interest counter */
  96.          /* List interests in an order vaguely corresponding to
  97.           * how important they are.
  98.           */
  99.          if (mptr->feat.nshop > 0) {
  100.              if (mptr->feat.nshop > 1)
  101.                  ADDNTOBUF("shop", mptr->feat.nshop);
  102.              else
  103.                  Sprintf(eos(buf), "%s%s", COMMA,
  104.                          an(shop_string(mptr->feat.shoptype)));
  105.          }
  106.          if (mptr->feat.naltar > 0) {
  107.              /* Temples + non-temple altars get munged into just "altars" */
  108.              if (mptr->feat.ntemple != mptr->feat.naltar)
  109.                  ADDNTOBUF("altar", mptr->feat.naltar);
  110.              else
  111.                  ADDNTOBUF("temple", mptr->feat.ntemple);
  112.  
  113.              /* only print out altar's god if they are all to your god */
  114.              if (Amask2align(Msa2amask(mptr->feat.msalign)) == u.ualign.type)
  115.                  Sprintf(eos(buf), " to %s", align_gname(u.ualign.type));
  116.          }
  117.          ADDNTOBUF("throne", mptr->feat.nthrone);
  118.          ADDNTOBUF("fountain", mptr->feat.nfount);
  119.          ADDNTOBUF("sink", mptr->feat.nsink);
  120.          ADDNTOBUF("grave", mptr->feat.ngrave);
  121.          ADDNTOBUF("tree", mptr->feat.ntree);
  122.  #if 0
  123.          ADDTOBUF("water", mptr->feat.water);
  124.          ADDTOBUF("lava", mptr->feat.lava);
  125.          ADDTOBUF("ice", mptr->feat.ice);
  126.  #endif
  127.          /* capitalize afterwards */
  128.          i = strlen(PREFIX);
  129.          buf[i] = highc(buf[i]);
  130.          /* capitalizing it makes it a sentence; terminate with '.' */
  131.          Strcat(buf, ".");
  132.          putstr(win, 0, buf);
  133.      }
  134.  
  135.      /* we assume that these are mutually exclusive */
  136.      *buf = '\0';
  137.      if (mptr->flags.oracle) {
  138.          Sprintf(buf, "%sOracle of Delphi.", PREFIX);
  139.      } else if (In_sokoban(&mptr->lev)) {
  140.          Sprintf(buf, "%s%s.", PREFIX,
  141.                  mptr->flags.sokosolved ? "Solved" : "Unsolved");
  142.      } else if (mptr->flags.bigroom) {
  143.          Sprintf(buf, "%sA very big room.", PREFIX);
  144.      } else if (mptr->flags.roguelevel) {
  145.          Sprintf(buf, "%sA primitive area.", PREFIX);
  146.      } else if (mptr->flags.quest_summons) {
  147.          Sprintf(buf, "%sSummoned by %s.", PREFIX, ldrname());
  148.      } else if (on_level(&mptr->lev, &qstart_level)) {
  149.          Sprintf(buf, "%sHome%s.", PREFIX,
  150.                  mptr->flags.unreachable ? " (no way back...)" : "");
  151.          if (u.uevent.qcompleted)
  152.              Sprintf(buf, "%sCompleted quest for %s.", PREFIX, ldrname());
  153.          else if (mptr->flags.questing)
  154.              Sprintf(buf, "%sGiven quest by %s.", PREFIX, ldrname());
  155.      } else if (mptr->flags.ludios) {
  156.          /* presence of the ludios branch in #overview output indicates that
  157.             the player has made it onto the level; presence of this annotation
  158.             indicates that the fort's entrance has been seen (or mapped) */
  159.          Sprintf(buf, "%sFort Ludios.", PREFIX);
  160.      } else if (mptr->flags.castle) {
  161.          Sprintf(buf, "%sThe castle%s.", PREFIX, tunesuffix(mptr, tmpbuf));
  162.      } else if (mptr->flags.valley) {
  163.          Sprintf(buf, "%sValley of the Dead.", PREFIX);
  164.      } else if (mptr->flags.msanctum) {
  165.          Sprintf(buf, "%sMoloch's Sanctum.", PREFIX);
  166.      }
  167.      if (*buf)
  168.          putstr(win, 0, buf);
  169.  
  170.      /* print out branches */
  171.      if (mptr->br) {
  172.          Sprintf(buf, "%s%s to %s", PREFIX, br_string2(mptr->br),
  173.                  dungeons[mptr->br->end2.dnum].dname);
  174.  
  175.          /* Since mapseen objects are printed out in increasing order
  176.           * of dlevel, clarify which level this branch is going to
  177.           * if the branch goes upwards.  Unless it's the end game.
  178.           */
  179.          if (mptr->br->end1_up && !In_endgame(&(mptr->br->end2)))
  180.              Sprintf(eos(buf), ", level %d", depth(&(mptr->br->end2)));
  181.          Strcat(buf, ".");
  182.          putstr(win, 0, buf);
  183.      }
  184.  
  185.      /* maybe print out bones details */
  186.      if (mptr->final_resting_place || final) {
  187.          struct cemetery *bp;
  188.          int kncnt = !died_here ? 0 : 1;
  189.  
  190.          for (bp = mptr->final_resting_place; bp; bp = bp->next)
  191.              if (bp->bonesknown || wizard || final)
  192.                  ++kncnt;
  193.          if (kncnt) {
  194.              Sprintf(buf, "%s%s", PREFIX, "Final resting place for");
  195.              putstr(win, 0, buf);
  196.              if (died_here) {
  197.                  /* disclosure occurs before bones creation, so listing dead
  198.                     hero here doesn't give away whether bones are produced */
  199.                  formatkiller(tmpbuf, sizeof tmpbuf, how);
  200.                  /* rephrase a few death reasons to work with "you" */
  201.                  (void) strsubst(tmpbuf, " himself", " yourself");
  202.                  (void) strsubst(tmpbuf, " herself", " yourself");
  203.                  (void) strsubst(tmpbuf, " his ", " your ");
  204.                  (void) strsubst(tmpbuf, " her ", " your ");
  205.                  Sprintf(buf, "%s%syou, %s%c", PREFIX, TAB, tmpbuf,
  206.                          --kncnt ? ',' : '.');
  207.                  putstr(win, 0, buf);
  208.              }
  209.              for (bp = mptr->final_resting_place; bp; bp = bp->next) {
  210.                  if (bp->bonesknown || wizard || final) {
  211.                      Sprintf(buf, "%s%s%s, %s%c", PREFIX, TAB, bp->who,
  212.                              bp->how, --kncnt ? ',' : '.');
  213.                      putstr(win, 0, buf);
  214.                  }
  215.              }
  216.          }
  217.      }
  218.  }
  219.  
  220.  /*dungeon.c*/