Source:NetHack 3.6.0/src/questpgr.c

From NetHackWiki
Jump to: navigation, search

Below is the full text to questpgr.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/questpgr.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	questpgr.c	$NHDT-Date: 1448541043 2015/11/26 12:30:43 $  $NHDT-Branch: master $:$NHDT-Revision: 1.36 $ */
  2.  /*      Copyright 1991, M. Stephenson                             */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  #include "hack.h"
  6.  #include "dlb.h"
  7.  
  8.  /*  quest-specific pager routines. */
  9.  
  10.  #include "qtext.h"
  11.  
  12.  #define QTEXT_FILE "quest.dat"
  13.  
  14.  #ifdef TTY_GRAPHICS
  15.  #include "wintty.h"
  16.  #endif
  17.  
  18.  /* from sp_lev.c, for deliver_splev_message() */
  19.  extern char *lev_message;
  20.  
  21.  static void NDECL(dump_qtlist);
  22.  static void FDECL(Fread, (genericptr_t, int, int, dlb *));
  23.  STATIC_DCL struct qtmsg *FDECL(construct_qtlist, (long));
  24.  STATIC_DCL const char *NDECL(intermed);
  25.  STATIC_DCL const char *NDECL(neminame);
  26.  STATIC_DCL const char *NDECL(guardname);
  27.  STATIC_DCL const char *NDECL(homebase);
  28.  STATIC_DCL void FDECL(qtext_pronoun, (CHAR_P, CHAR_P));
  29.  STATIC_DCL struct qtmsg *FDECL(msg_in, (struct qtmsg *, int));
  30.  STATIC_DCL void FDECL(convert_arg, (CHAR_P));
  31.  STATIC_DCL void FDECL(convert_line, (char *,char *));
  32.  STATIC_DCL void FDECL(deliver_by_pline, (struct qtmsg *));
  33.  STATIC_DCL void FDECL(deliver_by_window, (struct qtmsg *, int));
  34.  STATIC_DCL boolean FDECL(skip_pager, (BOOLEAN_P));
  35.  
  36.  static char cvt_buf[64];
  37.  static struct qtlists qt_list;
  38.  static dlb *msg_file;
  39.  /* used by ldrname() and neminame(), then copied into cvt_buf */
  40.  static char nambuf[sizeof cvt_buf];
  41.  

dump_qtlist

  1.  /* dump the character msg list to check appearance;
  2.     build with DEBUG enabled and use DEBUGFILES=questpgr.c
  3.     in sysconf file or environment */
  4.  static void
  5.  dump_qtlist()
  6.  {
  7.  #ifdef DEBUG
  8.      struct qtmsg *msg;
  9.  
  10.      if (!explicitdebug(__FILE__))
  11.          return;
  12.  
  13.      for (msg = qt_list.chrole; msg->msgnum > 0; msg++) {
  14.          (void) dlb_fseek(msg_file, msg->offset, SEEK_SET);
  15.          deliver_by_window(msg, NHW_MAP);
  16.      }
  17.  #endif /* DEBUG */
  18.      return;
  19.  }
  20.  

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("PREMATURE EOF ON QUEST TEXT FILE! Expected %d bytes, got %d",
  11.                (size * nitems), (size * cnt));
  12.      }
  13.  }
  14.  

construct_qtlist

  1.  STATIC_OVL struct qtmsg *
  2.  construct_qtlist(hdr_offset)
  3.  long hdr_offset;
  4.  {
  5.      struct qtmsg *msg_list;
  6.      int n_msgs;
  7.  
  8.      (void) dlb_fseek(msg_file, hdr_offset, SEEK_SET);
  9.      Fread(&n_msgs, sizeof(int), 1, msg_file);
  10.      msg_list = (struct qtmsg *) alloc((unsigned) (n_msgs + 1)
  11.                                        * sizeof (struct qtmsg));
  12.  
  13.      /*
  14.       * Load up the list.
  15.       */
  16.      Fread((genericptr_t) msg_list, n_msgs * sizeof (struct qtmsg), 1,
  17.            msg_file);
  18.  
  19.      msg_list[n_msgs].msgnum = -1;
  20.      return msg_list;
  21.  }
  22.  

load_qtlist

  1.  void
  2.  load_qtlist()
  3.  {
  4.      int n_classes, i;
  5.      char qt_classes[N_HDR][LEN_HDR];
  6.      long qt_offsets[N_HDR];
  7.  
  8.      msg_file = dlb_fopen(QTEXT_FILE, RDBMODE);
  9.      if (!msg_file)
  10.          panic("CANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE);
  11.  
  12.      /*
  13.       * Read in the number of classes, then the ID's & offsets for
  14.       * each header.
  15.       */
  16.  
  17.      Fread(&n_classes, sizeof (int), 1, msg_file);
  18.      Fread(&qt_classes[0][0], sizeof (char) * LEN_HDR, n_classes, msg_file);
  19.      Fread(qt_offsets, sizeof (long), n_classes, msg_file);
  20.  
  21.      /*
  22.       * Now construct the message lists for quick reference later
  23.       * on when we are actually paging the messages out.
  24.       */
  25.  
  26.      qt_list.common = qt_list.chrole = (struct qtmsg *) 0;
  27.  
  28.      for (i = 0; i < n_classes; i++) {
  29.          if (!strncmp(COMMON_ID, qt_classes[i], LEN_HDR))
  30.              qt_list.common = construct_qtlist(qt_offsets[i]);
  31.          else if (!strncmp(urole.filecode, qt_classes[i], LEN_HDR))
  32.              qt_list.chrole = construct_qtlist(qt_offsets[i]);
  33.  #if 0 /* UNUSED but available */
  34.          else if (!strncmp(urace.filecode, qt_classes[i], LEN_HDR))
  35.              qt_list.chrace = construct_qtlist(qt_offsets[i]);
  36.  #endif
  37.      }
  38.  
  39.      if (!qt_list.common || !qt_list.chrole)
  40.          impossible("load_qtlist: cannot load quest text.");
  41.      dump_qtlist();
  42.      return; /* no ***DON'T*** close the msg_file */
  43.  }
  44.  

unload_qtlist

  1.  /* called at program exit */
  2.  void
  3.  unload_qtlist()
  4.  {
  5.      if (msg_file)
  6.          (void) dlb_fclose(msg_file), msg_file = 0;
  7.      if (qt_list.common)
  8.          free((genericptr_t) qt_list.common), qt_list.common = 0;
  9.      if (qt_list.chrole)
  10.          free((genericptr_t) qt_list.chrole), qt_list.chrole = 0;
  11.      return;
  12.  }
  13.  

quest_info

  1.  short
  2.  quest_info(typ)
  3.  int typ;
  4.  {
  5.      switch (typ) {
  6.      case 0:
  7.          return urole.questarti;
  8.      case MS_LEADER:
  9.          return urole.ldrnum;
  10.      case MS_NEMESIS:
  11.          return urole.neminum;
  12.      case MS_GUARDIAN:
  13.          return urole.guardnum;
  14.      default:
  15.          impossible("quest_info(%d)", typ);
  16.      }
  17.      return 0;
  18.  }
  19.  

ldrname

  1.  /* return your role leader's name */
  2.  const char *
  3.  ldrname()
  4.  {
  5.      int i = urole.ldrnum;
  6.  
  7.      Sprintf(nambuf, "%s%s", type_is_pname(&mons[i]) ? "" : "the ",
  8.              mons[i].mname);
  9.      return nambuf;
  10.  }
  11.  

intermed

  1.  /* return your intermediate target string */
  2.  STATIC_OVL const char *
  3.  intermed()
  4.  {
  5.      return urole.intermed;
  6.  }
  7.  

is_quest_artifact

  1.  boolean
  2.  is_quest_artifact(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      return (boolean) (otmp->oartifact == urole.questarti);
  6.  }
  7.  

neminame

  1.  /* return your role nemesis' name */
  2.  STATIC_OVL const char *
  3.  neminame()
  4.  {
  5.      int i = urole.neminum;
  6.  
  7.      Sprintf(nambuf, "%s%s", type_is_pname(&mons[i]) ? "" : "the ",
  8.              mons[i].mname);
  9.      return nambuf;
  10.  }
  11.  

guardname

  1.  STATIC_OVL const char *
  2.  guardname() /* return your role leader's guard monster name */
  3.  {
  4.      int i = urole.guardnum;
  5.  
  6.      return mons[i].mname;
  7.  }
  8.  

homebase

  1.  STATIC_OVL const char *
  2.  homebase() /* return your role leader's location */
  3.  {
  4.      return urole.homebase;
  5.  }
  6.  

qtext_pronoun

  1.  /* replace deity, leader, nemesis, or artifact name with pronoun;
  2.     overwrites cvt_buf[] */
  3.  STATIC_OVL void
  4.  qtext_pronoun(who, which)
  5.  char who,  /* 'd' => deity, 'l' => leader, 'n' => nemesis, 'o' => artifact */
  6.      which; /* 'h'|'H'|'i'|'I'|'j'|'J' */
  7.  {
  8.      const char *pnoun;
  9.      int g;
  10.      char lwhich = lowc(which); /* H,I,J -> h,i,j */
  11.  
  12.      /*
  13.       * Invalid subject (not d,l,n,o) yields neuter, singular result.
  14.       *
  15.       * For %o, treat all artifacts as neuter; some have plural names,
  16.       * which genders[] doesn't handle; cvt_buf[] already contains name.
  17.       */
  18.      if (who == 'o'
  19.          && (strstri(cvt_buf, "Eyes ")
  20.              || strcmpi(cvt_buf, makesingular(cvt_buf)))) {
  21.          pnoun = (lwhich == 'h') ? "they"
  22.                  : (lwhich == 'i') ? "them"
  23.                  : (lwhich == 'j') ? "their" : "?";
  24.      } else {
  25.          g = (who == 'd') ? quest_status.godgend
  26.              : (who == 'l') ? quest_status.ldrgend
  27.              : (who == 'n') ? quest_status.nemgend
  28.              : 2; /* default to neuter */
  29.          pnoun = (lwhich == 'h') ? genders[g].he
  30.                  : (lwhich == 'i') ? genders[g].him
  31.                  : (lwhich == 'j') ? genders[g].his : "?";
  32.      }
  33.      Strcpy(cvt_buf, pnoun);
  34.      /* capitalize for H,I,J */
  35.      if (lwhich != which)
  36.          cvt_buf[0] = highc(cvt_buf[0]);
  37.      return;
  38.  }
  39.  

msg_in

  1.  STATIC_OVL struct qtmsg *
  2.  msg_in(qtm_list, msgnum)
  3.  struct qtmsg *qtm_list;
  4.  int msgnum;
  5.  {
  6.      struct qtmsg *qt_msg;
  7.  
  8.      for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++)
  9.          if (qt_msg->msgnum == msgnum)
  10.              return qt_msg;
  11.  
  12.      return (struct qtmsg *) 0;
  13.  }
  14.  

convert_arg

  1.  STATIC_OVL void
  2.  convert_arg(c)
  3.  char c;
  4.  {
  5.      register const char *str;
  6.  
  7.      switch (c) {
  8.      case 'p':
  9.          str = plname;
  10.          break;
  11.      case 'c':
  12.          str = (flags.female && urole.name.f) ? urole.name.f : urole.name.m;
  13.          break;
  14.      case 'r':
  15.          str = rank_of(u.ulevel, Role_switch, flags.female);
  16.          break;
  17.      case 'R':
  18.          str = rank_of(MIN_QUEST_LEVEL, Role_switch, flags.female);
  19.          break;
  20.      case 's':
  21.          str = (flags.female) ? "sister" : "brother";
  22.          break;
  23.      case 'S':
  24.          str = (flags.female) ? "daughter" : "son";
  25.          break;
  26.      case 'l':
  27.          str = ldrname();
  28.          break;
  29.      case 'i':
  30.          str = intermed();
  31.          break;
  32.      case 'O':
  33.      case 'o':
  34.          str = the(artiname(urole.questarti));
  35.          if (c == 'O') {
  36.              /* shorten "the Foo of Bar" to "the Foo"
  37.                 (buffer returned by the() is modifiable) */
  38.              char *p = strstri(str, " of ");
  39.  
  40.              if (p)
  41.                  *p = '\0';
  42.          }
  43.          break;
  44.      case 'n':
  45.          str = neminame();
  46.          break;
  47.      case 'g':
  48.          str = guardname();
  49.          break;
  50.      case 'G':
  51.          str = align_gtitle(u.ualignbase[A_ORIGINAL]);
  52.          break;
  53.      case 'H':
  54.          str = homebase();
  55.          break;
  56.      case 'a':
  57.          str = align_str(u.ualignbase[A_ORIGINAL]);
  58.          break;
  59.      case 'A':
  60.          str = align_str(u.ualign.type);
  61.          break;
  62.      case 'd':
  63.          str = align_gname(u.ualignbase[A_ORIGINAL]);
  64.          break;
  65.      case 'D':
  66.          str = align_gname(A_LAWFUL);
  67.          break;
  68.      case 'C':
  69.          str = "chaotic";
  70.          break;
  71.      case 'N':
  72.          str = "neutral";
  73.          break;
  74.      case 'L':
  75.          str = "lawful";
  76.          break;
  77.      case 'x':
  78.          str = Blind ? "sense" : "see";
  79.          break;
  80.      case 'Z':
  81.          str = dungeons[0].dname;
  82.          break;
  83.      case '%':
  84.          str = "%";
  85.          break;
  86.      default:
  87.          str = "";
  88.          break;
  89.      }
  90.      Strcpy(cvt_buf, str);
  91.  }
  92.  

convert_line

  1.  STATIC_OVL void
  2.  convert_line(in_line, out_line)
  3.  char *in_line, *out_line;
  4.  {
  5.      char *c, *cc;
  6.      char xbuf[BUFSZ];
  7.  
  8.      cc = out_line;
  9.      for (c = xcrypt(in_line, xbuf); *c; c++) {
  10.          *cc = 0;
  11.          switch (*c) {
  12.          case '\r':
  13.          case '\n':
  14.              *(++cc) = 0;
  15.              return;
  16.  
  17.          case '%':
  18.              if (*(c + 1)) {
  19.                  convert_arg(*(++c));
  20.                  switch (*(++c)) {
  21.                  /* insert "a"/"an" prefix */
  22.                  case 'A':
  23.                      Strcat(cc, An(cvt_buf));
  24.                      cc += strlen(cc);
  25.                      continue; /* for */
  26.                  case 'a':
  27.                      Strcat(cc, an(cvt_buf));
  28.                      cc += strlen(cc);
  29.                      continue; /* for */
  30.  
  31.                  /* capitalize */
  32.                  case 'C':
  33.                      cvt_buf[0] = highc(cvt_buf[0]);
  34.                      break;
  35.  
  36.                  /* replace name with pronoun;
  37.                     valid for %d, %l, %n, and %o */
  38.                  case 'h': /* he/she */
  39.                  case 'H': /* He/She */
  40.                  case 'i': /* him/her */
  41.                  case 'I':
  42.                  case 'j': /* his/her */
  43.                  case 'J':
  44.                      if (index("dlno", lowc(*(c - 1))))
  45.                          qtext_pronoun(*(c - 1), *c);
  46.                      else
  47.                          --c; /* default action */
  48.                      break;
  49.  
  50.                  /* pluralize */
  51.                  case 'P':
  52.                      cvt_buf[0] = highc(cvt_buf[0]);
  53.                  case 'p':
  54.                      Strcpy(cvt_buf, makeplural(cvt_buf));
  55.                      break;
  56.  
  57.                  /* append possessive suffix */
  58.                  case 'S':
  59.                      cvt_buf[0] = highc(cvt_buf[0]);
  60.                  case 's':
  61.                      Strcpy(cvt_buf, s_suffix(cvt_buf));
  62.                      break;
  63.  
  64.                  /* strip any "the" prefix */
  65.                  case 't':
  66.                      if (!strncmpi(cvt_buf, "the ", 4)) {
  67.                          Strcat(cc, &cvt_buf[4]);
  68.                          cc += strlen(cc);
  69.                          continue; /* for */
  70.                      }
  71.                      break;
  72.  
  73.                  default:
  74.                      --c; /* undo switch increment */
  75.                      break;
  76.                  }
  77.                  Strcat(cc, cvt_buf);
  78.                  cc += strlen(cvt_buf);
  79.                  break;
  80.              } /* else fall through */
  81.  
  82.          default:
  83.              *cc++ = *c;
  84.              break;
  85.          }
  86.      }
  87.      if (cc > &out_line[BUFSZ-1])
  88.          panic("convert_line: overflow");
  89.      *cc = 0;
  90.      return;
  91.  }
  92.  

deliver_by_pline

  1.  STATIC_OVL void
  2.  deliver_by_pline(qt_msg)
  3.  struct qtmsg *qt_msg;
  4.  {
  5.      long size;
  6.      char in_line[BUFSZ], out_line[BUFSZ];
  7.  
  8.      *in_line = '\0';
  9.      for (size = 0; size < qt_msg->size; size += (long) strlen(in_line)) {
  10.          (void) dlb_fgets(in_line, sizeof in_line, msg_file);
  11.          convert_line(in_line, out_line);
  12.          pline("%s", out_line);
  13.      }
  14.  }
  15.  

deliver_by_window

  1.  STATIC_OVL void
  2.  deliver_by_window(qt_msg, how)
  3.  struct qtmsg *qt_msg;
  4.  int how;
  5.  {
  6.      long size;
  7.      char in_line[BUFSZ], out_line[BUFSZ];
  8.      boolean qtdump = (how == NHW_MAP);
  9.      winid datawin = create_nhwindow(qtdump ? NHW_TEXT : how);
  10.  
  11.  #ifdef DEBUG
  12.      if (qtdump) {
  13.          char buf[BUFSZ];
  14.  
  15.          /* when dumping quest messages at startup, all of them are passed to
  16.           * deliver_by_window(), even if normally given to deliver_by_pline()
  17.           */
  18.          Sprintf(buf, "msgnum: %d, delivery: %c",
  19.                  qt_msg->msgnum, qt_msg->delivery);
  20.          putstr(datawin, 0, buf);
  21.          putstr(datawin, 0, "");
  22.      }
  23.  #endif
  24.      for (size = 0; size < qt_msg->size; size += (long) strlen(in_line)) {
  25.          (void) dlb_fgets(in_line, sizeof in_line, msg_file);
  26.          convert_line(in_line, out_line);
  27.          putstr(datawin, 0, out_line);
  28.      }
  29.      display_nhwindow(datawin, TRUE);
  30.      destroy_nhwindow(datawin);
  31.  
  32.      /* block messages delivered by window aren't kept in message history
  33.         but have a one-line summary which is put there for ^P recall */
  34.      *out_line = '\0';
  35.      if (qt_msg->summary_size) {
  36.          (void) dlb_fgets(in_line, sizeof in_line, msg_file);
  37.          convert_line(in_line, out_line);
  38.  #ifdef BETA
  39.      } else if (qt_msg->delivery == 'c') { /* skip for 'qtdump' of 'p' */
  40.          /* delivery 'c' and !summary_size, summary expected but not present;
  41.             this doesn't prefix the number with role code vs 'general'
  42.             but should be good enough for summary verification purposes */
  43.          Sprintf(out_line, "[missing block message summary for #%05d]",
  44.                  qt_msg->msgnum);
  45.  #endif
  46.      }
  47.      if (*out_line)
  48.          putmsghistory(out_line, FALSE);
  49.  }
  50.  

skip_pager

  1.  boolean
  2.  skip_pager(common)
  3.  boolean common;
  4.  {
  5.      /* WIZKIT: suppress plot feedback if starting with quest artifact */
  6.      if (program_state.wizkit_wishing)
  7.          return TRUE;
  8.      if (!(common ? qt_list.common : qt_list.chrole)) {
  9.          panic("%s: no %s quest text data available",
  10.                common ? "com_pager" : "qt_pager",
  11.                common ? "common" : "role-specific");
  12.          /*NOTREACHED*/
  13.          return TRUE;
  14.      }
  15.      return FALSE;
  16.  }
  17.  

com_pager

  1.  void
  2.  com_pager(msgnum)
  3.  int msgnum;
  4.  {
  5.      struct qtmsg *qt_msg;
  6.  
  7.      if (skip_pager(TRUE))
  8.          return;
  9.  
  10.      if (!(qt_msg = msg_in(qt_list.common, msgnum))) {
  11.          impossible("com_pager: message %d not found.", msgnum);
  12.          return;
  13.      }
  14.  
  15.      (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET);
  16.      if (qt_msg->delivery == 'p')
  17.          deliver_by_pline(qt_msg);
  18.      else if (msgnum == 1)
  19.          deliver_by_window(qt_msg, NHW_MENU);
  20.      else
  21.          deliver_by_window(qt_msg, NHW_TEXT);
  22.      return;
  23.  }
  24.  

qt_pager

  1.  void
  2.  qt_pager(msgnum)
  3.  int msgnum;
  4.  {
  5.      struct qtmsg *qt_msg;
  6.  
  7.      if (skip_pager(FALSE))
  8.          return;
  9.  
  10.      if (!(qt_msg = msg_in(qt_list.chrole, msgnum))) {
  11.          impossible("qt_pager: message %d not found.", msgnum);
  12.          return;
  13.      }
  14.  
  15.      (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET);
  16.      if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11"))
  17.          deliver_by_pline(qt_msg);
  18.      else
  19.          deliver_by_window(qt_msg, NHW_TEXT);
  20.      return;
  21.  }
  22.  

qt_montype

  1.  struct permonst *
  2.  qt_montype()
  3.  {
  4.      int qpm;
  5.  
  6.      if (rn2(5)) {
  7.          qpm = urole.enemy1num;
  8.          if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
  9.              return &mons[qpm];
  10.          return mkclass(urole.enemy1sym, 0);
  11.      }
  12.      qpm = urole.enemy2num;
  13.      if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD))
  14.          return &mons[qpm];
  15.      return mkclass(urole.enemy2sym, 0);
  16.  }
  17.  

deliver_splev_message

  1.  /* special levels can include a custom arrival message; display it */
  2.  void
  3.  deliver_splev_message()
  4.  {
  5.      char *str, *nl, in_line[BUFSZ], out_line[BUFSZ];
  6.  
  7.      /* there's no provision for delivering via window instead of pline */
  8.      if (lev_message) {
  9.          /* lev_message can span multiple lines using embedded newline chars;
  10.             any segments too long to fit within in_line[] will be truncated */
  11.          for (str = lev_message; *str; str = nl + 1) {
  12.              /* copying will stop at newline if one is present */
  13.              copynchars(in_line, str, (int) (sizeof in_line) - 1);
  14.  
  15.              /* convert_line() expects encrypted input */
  16.              (void) xcrypt(in_line, in_line);
  17.              convert_line(in_line, out_line);
  18.              pline("%s", out_line);
  19.  
  20.              if ((nl = index(str, '\n')) == 0)
  21.                  break; /* done if no newline */
  22.          }
  23.  
  24.          free((genericptr_t) lev_message);
  25.          lev_message = 0;
  26.      }
  27.  }
  28.  
  29.  /*questpgr.c*/