Rog-O-Matic XIV (part 04 of 10)

Michael Mauldin mlm at cmu-cs-cad.ARPA
Sat Feb 2 02:28:35 AEST 1985


#!/bin/sh
#
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @ Here is part of your new automatic Rogue player, Rog-O-Matic XIV! @
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# 
#     [Note: this is a Beta-Test release of version XIV, and almost
#      certainly contains bugs.  A new version will be made available
#      soon.  If you experience any problems with this version, please
#      contact Michael Mauldin as soon as possible, so your input can be
#      included in the new release]
# 
# Rog-O-Matic XIV is shipped via mail in pieces, files rgm14.01, rgm14.02,
# ..., rgm14.nn.  Each piece contains some number of smaller files. To
# retrieve them, run each file through the shell 'sh', as follows:
# 
# 	sh <rgm14.01
# 	sh <rgm14.02
# 	     ...
# 	sh <rgm14.nn
# 
# or do it all at once:
# 
# 	cat rgm14.* | sh
# 
# The README file contains all necessary information to edit the "install.h"
# file, after which "make" will build the rogomatic and player binary files.
# Please note that file 'Bugreport' contains modifications you may wish to
# make to the code BEFORE you compile it.  You can safely install ALL of
# them; depending on your version of Rogue, you may HAVE to install SOME of
# them.
# 
# Rog-O-Matic is copyrighted, but permission is given to copy and modify the
# source provided that (1) it is not used for profit (2) all authorship and
# copyright notices remain intact and (3) any person or site with a copy has
# notified Michael Mauldin either by electronic mail or US Post that they
# have Rog-O-Matic XIV.
# 
# We would appreciate hearing about any interesting additions or modifi-
# cations, and would especially like to know how well the program plays
# against your Rogue.  And we really, really want to know if Rog-O-Matic
# becomes a "Total Winner" against Rogue 5.2 or Rogue 5.3 again.
# 
# 				Michael Mauldin (Fuzzy)
# 				Department of Computer Science
# 				Carnegie-Mellon University
# 				Pittsburgh, PA  15213
# 				(412) 578-3065,  mauldin at cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 04 of 10:'
echo 'x - io.c'
sed 's/^X//' > io.c << '/'
X/*
X * io.c: Rog-O-Matic XIV (CMU) Thu Jan 31 18:19:29 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains all of the functions which deal with the real world.
X */
X
X# include <curses.h>
X# include <ctype.h>
X
X# include "install.h"
X
X# ifdef BSD41
X#     include <time.h>
X# else
X#     include <sys/time.h>
X# endif
X
X# include "types.h"
X# include "globals.h"
X# include "termtokens.h"
X
X# define READ	0
X
X/*
X * Charonscreen returns the current character on the screen (using
X * curses(3)).  This macro is based on the winch(win) macro.
X */
X# define charonscreen(X,Y)	(stdscr->_y[X][Y])
X
Xchar *month[] = 
X{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
X
Xstatic char screen00 = ' ';
X
X/* Constants */
X
X# define SENDQ 256
X
X/* The command queue */
X
Xchar  queue[SENDQ];             /* To Rogue */
Xint   head = 0, tail = 0;
X
X/*
X * Getrogue: Sensory interface.
X *
X * Handle grungy low level terminal I/O. Getrogue reads tokens from the
X * Rogue process and interprets them, making the screen array an image of
X * the rogue level. Getrogue returns when the string waitstr has been read
X * and either the cursor is on the Rogue '@' or some other condition
X * implies that we have synchronized with Rogue.
X */
X
Xgetrogue (waitstr, onat)
Xchar *waitstr;                          /* String to synchronize with */
Xint   onat;                             /* 0 ==> Wait for waitstr 
X                                           1 ==> Cursor on @ sufficient 
X                                           2 ==> [1] + send ';' when ever
X                                           we eat a --More-- message */
X{ int   botprinted = 0, wasmapped = didreadmap, r, c, pending ();
X  register int i, j;
X  char  ch, *s, *m, *q, *d, *call, getroguetoken();
X  int *doors;
X  static moved = 0;
X
X  domonster();  /* LGCH */
X
X  newdoors = doorlist;			/* no new doors found yet */
X  atrow0 = atrow; atcol0 = atcol;	/* Save our current posistion */
X  s = waitstr;				/* FSM to check for the wait msg */
X  m = "More--";				/* FSM to check for '--More--' */
X  call = "Call it:";			/* FSM to check for 'Call it:' */
X  q = "(* for list): ";			/* FSM to check for prompt */
X  d = ")______";			/* FSM to check for tombstone grass */
X
X  if (moved)				/* If we moved last time, put any */
X  { sleepmonster (); moved = 0; }	/* Old monsters to sleep */
X
X  /* While we have not reached the end of the Rogue input, read */
X  /* characters from Rogue and figure out what they mean.       */
X  while ((*s) ||
X         ((!hasted || version != RV36A) && onat && screen[row][col] != '@'))
X  { ch = getroguetoken ();
X
X    /* If message ends in "(* for list): ", call terpmes */
X    if (ch == *q) { if (*++q == 0) terpmes (); }
X    else q = "(* for list): ";
X
X    /* Rogomatic now keys off of the grass under the Tombstone to  */
X    /* detect that it has been killed. This was done because the   */
X    /* "Press return" prompt only happens if there is a score file */
X    /* Available on that system. Hopefully the grass is the same   */
X    /* in all versions of Rogue!                                   */
X    if (ch == *d) { if (0 == *++d) { addch (ch); deadrogue (); return;} }
X    else d = ")_______";
X
X    /* If the message has a more, strip it off and call terpmes */
X    if (ch == *m)
X    { if (*++m == 0)
X      { /* More than 50 messages since last command ==> start logging */
X        if (++morecount > 50 && !logging) 
X	{ toggleecho (); dwait (D_WARNING, "Started logging --More-- loop."); }
X
X        /* More than 100 messages since last command ==> infinite loop */
X        if (++morecount > 100) dwait (D_FATAL, "Caught in --More-- loop.");
X
X	/* Send a space (and possibly a semicolon) to clear the message */
X        if (onat == 2) sendnow (" ;");
X        else           sendnow (" ");
X
X        /* Clear the --More-- of the end of the message */
X        for (i = col - 7; i < col; screen[0][i++] = ' ');
X
X        terpmes ();			/* Interpret the message */
X
X        /* This code gets rid of the "Studded leather arm" bug */
X	/* But it causes other problems.		MLM   */
X        /* sprintf (&screen[0][col - 7], "--More--"); */ 
X      }
X    }
X    else m = "More--";
X
X    /* If the message is 'Call it:', cancel the request */
X    if (ch == *call)
X    { if (*++call == 0)
X      { /* Send an escape (and possibly a semicolon) to clear the message */
X        if (onat == 2) sendnow ("%c;", ESC);
X        else           sendnow ("%c", ESC);
X      }
X    }
X    else call = "Call it:";
X
X    /* Check to see whether we have read the synchronization string */
X    if (*s) { if (ch == *s) s++; else s = waitstr; }
X
X    /* Now figure out what the token means */
X    switch (ch)
X    { case BS_TOK: 
X        col--;
X        break;
X
X      case CE_TOK: 
X        if (row && row < 23)
X          for (i = col; i < 80; i++)
X          { updatepos (' ', row, i);
X            screen[row][i] = ' ';
X          }
X        else
X          for (i = col; i < 80; i++)
X            screen[row][i] = ' ';
X
X        if (row) { at (row, col); clrtoeol (); }
X        else if (col == 0) screen00 = ' ';
X        break;
X
X      case CL_TOK: 
X        clearscreen ();
X        break;
X
X      case CM_TOK: 
X        screen00 = screen[0][0];
X        break;
X
X      case CR_TOK: 
X	/* Handle missing '--more--' between inventories  MLM 24-Jun-83 */
X	if (row==0 && screen[0][1]==')' && screen[0][col-1] != '-')
X          terpmes ();
X        col = 0;
X        break;
X
X      case DO_TOK:
X        row++;
X        break;
X
X      case ER_TOK: 
X        break;
X
X      case LF_TOK:
X        row++;
X        col = 0;
X        break;
X
X      case ND_TOK:
X        col++;
X        break;
X
X      case SE_TOK: 
X        revvideo = 0;
X	standend ();
X        break;
X
X      case SO_TOK: 
X        revvideo = 1;
X	standout ();
X        break;
X
X      case TA_TOK: 
X        col = 8 * (1 + col / 8);
X        break;
X
X      case EOF:
X	if (interrupted) return;
X        if (!replaying || !logdigested) { playing = 0; return; }
X	saynow ("End of game log, type 'Q' to exit.");
X        return;
X        break;
X
X      case UP_TOK:
X        row--;
X        break;
X
X      default: 
X        if (ch < ' ')
X        { saynow ("Unknown character '\\%o'--more--", ch);
X          waitforspace (); 
X        }
X        else if (row) 
X        { at (row, col);
X          if (!emacs && !terse) addch (ch);
X          if (row == 23) botprinted = 1;
X          else           updatepos (ch, row, col);
X        }
X        else if (col == 0)
X        { screen00 = screen[0][0]; }
X        else if (col == 1 && ch == 'l' && screen[0][0] == 'I')
X        { screen[0][0] = screen00;
X          if (screen00 != ' ') terpmes ();
X          screen[0][0] = 'I';
X        }
X        screen[row][col++] = ch;
X        break;
X    }
X  }
X
X  if (botprinted) terpbot ();
X
X  if (atrow != atrow0 || atcol != atcol0) 
X  { updateat ();	/* Changed position, record the move */
X    moved = 1;		/* Indicate that we moved */
X    wakemonster (8);	/* Wake up adjacent mean monsters */
X    currentrectangle();	/* Keep current rectangle up to date.   LGCH */
X  }
X
X  if (!usesynch && !pending ()) 
X  { usesynch = 1;
X    lastobj = NONE;
X    resetinv();
X  }
X
X  if (version < RV53A && checkrange && !pending ())
X  { command (T_OTHER, "Iz"); checkrange = 0; }
X 
X  donemonster (); /* LGCH */
X
X  /* If mapping status has changed */
X  if (wasmapped != didreadmap)
X  { dwait (D_CONTROL | D_SEARCH, "wasmapped: %d   didreadmap: %d",
X           wasmapped, didreadmap);
X
X    mapinfer ();
X  }
X
X  if (didreadmap != Level)
X  { doors = doorlist;
X    while (doors != newdoors)
X    { r = *doors++; c = *doors++;
X      dwait (D_INFORM, "new door at %d, %d", r, c);
X      inferhall (r, c);
X    }
X  }
X
X  if (!blinded)
X    for (i = atrow-1; i <= atrow+1; i++)         /* For blanks around the  */
X      for (j = atcol-1; j <= atcol+1; j++)       /* rogue...               */
X	if (seerc(' ',i,j) && onrc(CANGO,i,j))   /* CANGO+BLANK impossible */
X	{ unsetrc (CANGO | SAFE, i, j);          /* Infer cant go and...   */
X	  setnewgoal ();		         /* invalidate the map.    */
X	}
X
X  at (row, col); 
X  if (!emacs && !terse) refresh ();
X}
X
X/*
X * terpbot: Read the Rogue status line and set the various status
X * variables. This routine depends on the value of version to decide what
X * the status line looks like.
X */
X
Xterpbot ()
X{ char sstr[30], modeline[256];
X  int oldlev = Level, oldgold = Gold, oldhp = Hp, Str18 = 0;
X  extern int geneid;
X  register int i, oldstr = Str, oldAc = Ac, oldExp = Explev;
X
X  /* Since we use scanf to read this field, it must not be left blank */
X  if (screen[23][78] == ' ') screen[23][78] = 'X';
X
X  /* Read the bottom line, there are three versions of the status line */
X  if (version < RV52A)		/* Rogue 3.6, Rogue 4.7? */
X  { sscanf (screen[23],
X            " Level: %d Gold: %d Hp: %d(%d) Str: %s Ac: %d Exp: %d/%d %s",
X            &Level, &Gold, &Hp, &Hpmax, sstr, &Ac, &Explev, &Exp, Ms);
X    sscanf (sstr, "%d/%d", &Str, &Str18);
X    Str = Str * 100 + Str18;
X    if (Str > Strmax) Strmax = Str;
X  }
X  else if (version < RV53A)	/* Rogue 5.2 (versions A and B) */
X  { sscanf (screen[23],
X         " Level: %d Gold: %d Hp: %d(%d) Str: %d(%d) Ac: %d Exp: %d/%d %s",
X         &Level, &Gold, &Hp, &Hpmax, &Str, &Strmax, &Ac, &Explev, &Exp, Ms);
X
X    Str = Str * 100; Strmax = Strmax * 100;
X  }
X  else				/* Rogue 5.3 (and beyond???) */
X  { sscanf (screen[23],
X         " Level: %d Gold: %d Hp: %d(%d) Str: %d(%d) Arm: %d Exp: %d/%d %s",
X         &Level, &Gold, &Hp, &Hpmax, &Str, &Strmax, &Ac, &Explev, &Exp, Ms);
X
X    Str = Str * 100; Strmax = Strmax * 100; Ac = 10 - Ac;
X  }
X
X  /* Monitor changes in some variables */
X  if (screen[23][78] == 'X') screen[23][78] = ' ';	/* Restore blank */
X  if (oldlev != Level)       newlevel ();
X  if (Level > MaxLevel)      MaxLevel = Level;
X  if (oldgold < Gold)        deletestuff (atrow, atcol);
X  if (oldhp < Hp)            newring = 1;
X
X  lastdamage = max (0, oldhp - Hp);
X  
X  /* 
X   * Insert code here to monitor changes in attributes due to special
X   * attacks					MLM October 26, 1983.
X   */
X  
X  setbonuses ();
X
X  /* 
X   * If in special output modes, generate output line
X   */
X  
X  if ((oldlev != Level || oldgold != Gold || oldstr != Str ||
X       oldAc != Ac || oldExp != Explev))
X  {
X    /* Stuff the new values into the argument space (for ps command) */
X    sprintf (modeline, "Rgm %d: Id%d L%d %d %d(%d) s%d a%d e%d    ",
X             rogpid, geneid, Level, Gold, Hp, Hpmax, Str / 100, 10-Ac, Explev);
X    modeline[arglen-1] = '\0';
X    strcpy (parmstr, modeline);    
X
X    /* Handle Emacs and Terse mode */
X    if (emacs || terse)
X    { /* Skip backward over blanks and nulls */
X      for (i = 79; screen[23][i] == ' ' || screen[23][i] == '\0'; i--);
X      screen[23][++i] = '\0';
X
X      if (emacs)
X      { sprintf (modeline, " %s (%%b)", screen[23]);
X        if (strlen (modeline) > 72) sprintf (modeline, " %s", screen[23]);
X        fprintf (realstdout, "%s", modeline);
X        fflush (realstdout);
X      }
X      else if (terse && oldlev != Level)
X      { fprintf (realstdout, "%s\n", screen[23]);
X        fflush (realstdout);
X      }
X    }
X  }
X}
X
X/*
X * dumpwalls: Dump the current screen map
X */
X
Xdumpwalls ()
X{ register int   r, c, S;
X  char ch;
X
X  printexplored ();
X
X  for (r = 1; r < 23; r++)
X  { for (c = 0; c < 80; c++)
X    { S=scrmap[r][c];
X      ch = (ARROW&S)                   ? 'a' :
X           (TELTRAP&S)                 ? 't' :
X           (TRAPDOR&S)                 ? 'v' :
X           (GASTRAP&S)                 ? 'g' :
X           (BEARTRP&S)                 ? 'b' :
X           (DARTRAP&S)                 ? 's' :
X           (WATERAP&S)                 ? 'w' :
X           (TRAP&S)                    ? '^' :
X           (STAIRS&S)                  ? '>' :
X           (RUNOK&S)                   ? '%' :
X           ((DOOR+BEEN&S)==DOOR+BEEN)  ? 'D' :
X           (DOOR&S)                    ? 'd' :
X           ((BOUNDARY+BEEN&S)==BOUNDARY+BEEN) ? 'B' :
X           ((ROOM+BEEN&S)==ROOM+BEEN)  ? 'R' :
X           (BEEN&S)                    ? ':' :
X           (HALL&S)                    ? '#' :
X           ((BOUNDARY+WALL&S)==BOUNDARY+WALL) ? 'W' :
X           (BOUNDARY&S)                ? 'b' :
X           (ROOM&S)                    ? 'r' :
X           (CANGO&S)                   ? '.' :
X           (WALL&S)                    ? 'W' :
X           (S)                         ? 'X' : '\0';
X      if (ch) mvaddch (r, c, ch);
X    }
X  }
X
X  at (row, col);
X}
X
X/*
X * sendnow: Send a string to the Rogue process.
X */
X
Xsendnow (f, a1, a2, a3, a4)
Xchar *f;
Xint a1, a2, a3, a4;
X{ char cmd[128];
X  register char *s = cmd;
X  
X  sprintf (cmd, f, a1, a2, a3, a4);
X
X  while (*s) sendcnow (*s++);
X}
X
X/*
X * sendcnow: send a character to the Rogue process. This routine also does
X * the logging of characters in echo mode.
X */
X
Xsendcnow (c)
Xchar c;
X{ if (replaying) return;
X  if (logging)
X  { if (cecho)
X      { fprintf (fecho, "\nC: \"%c", c); cecho = !cecho; }
X    else
X      fprintf (fecho, "%c", c);
X  }
X  fprintf (trogue, "%c", c);
X}
X
X/*
X * send: add a string to the queue of commands to be sent to Rogue. The
X * commands are sent one at a time by the resend routine.
X */
X
X# define bump(p,sizeq) (p)=((p)+1)%sizeq
X
Xsend (f, a1, a2, a3, a4)
Xchar *f;
Xint a1, a2, a3, a4;
X{ char cmd[128];
X  register char *s = cmd;
X
X  sprintf (s, f, a1, a2, a3, a4);
X
X  for (; *s; bump (tail, SENDQ))
X    queue[tail] = *(s++);
X
X  /* Appends null, so resend will treat as a unit */
X  queue[tail] = '\0';
X  bump (tail, SENDQ);
X}
X
X/*
X * resend: Send next block of characters from the queue
X */
X
Xresend ()
X{ register char *l=lastcmd;		/* Ptr into last command */
X
X  morecount = 0;			/* Clear message count */
X  if (head == tail) return (0);		/* Fail if no commands */
X
X  /* Send all queued characters until the next queued NULL */
X  while (queue[head])
X  { sendcnow (*l++ = queue[head]); bump (head, SENDQ); }
X  bump (head, SENDQ);
X  *l = '\0';
X
X  return (1);				/* Return success */
X}
X
X/*
X * pending: Return true if there is a command in the queue to be sent to
X * Rogue.
X */
X
Xpending ()
X{ return (head != tail);
X} 
X
X/*
X * getroguetoken: get a command from Rogue (either a character or a
X * cursor motion sequence).
X */
X
Xchar getroguetoken ()
X{ char ch;
X  char getlogtoken();
X
X  if (replaying)
X    return (getlogtoken());
X
X  ch = GETROGUECHAR;
X
X  /* Convert escape sequences into tokens (negative numbers) */
X  if (ch == ESC)
X  { switch (ch = GETROGUECHAR)
X
X    { case CE_CHR: ch = CE_TOK; break;
X      case CL_CHR: ch = CL_TOK; break;
X      case CM_CHR: ch = CM_TOK; break;
X      case DO_CHR: ch = DO_TOK; break;
X      case ND_CHR: ch = ND_TOK; break;
X      case SE_CHR: ch = SE_TOK; break;
X      case SO_CHR: ch = SO_TOK; break;
X      case UP_CHR: ch = UP_TOK; break;
X      default: saynow ("Unknown sequence ESC-%s --More--", unctrl(ch));
X               waitforspace ();
X               ch = ER_TOK;
X    }
X  }
X
X  /* Get arguments for cursor addressing */
X  if ((int) ch == CM_TOK)
X  { row = (int) GETROGUECHAR - 32; col = (int) GETROGUECHAR - 32; }
X
X  /* Log the tokens */
X  if (logging)
X  { if (!cecho) { fprintf (fecho, "\"\nR: "); cecho = !cecho; }
X    if (ISPRT (ch)) fprintf (fecho, "%c", ch);
X    else switch (ch)
X    { case BS_TOK: fprintf (fecho, "{bs}");                   break;
X      case CE_TOK: fprintf (fecho, "{ce}");                   break;
X      case CL_TOK: fprintf (fecho, "{ff}");                   break;
X      case CM_TOK: fprintf (fecho, "{cm(%d,%d)}", row, col);  break;
X      case CR_TOK: fprintf (fecho, "{cr}");                   break;
X      case DO_TOK: fprintf (fecho, "{do}");                   break;
X      case LF_TOK: fprintf (fecho, "{nl}");                   break;
X      case ND_TOK: fprintf (fecho, "{nd}");                   break;
X      case SE_TOK: fprintf (fecho, "{se}");                   break;
X      case SO_TOK: fprintf (fecho, "{so}");                   break;
X      case TA_TOK: fprintf (fecho, "{ta}");                   break;
X      case UP_TOK: fprintf (fecho, "{up}");                   break;
X      case ER_TOK: fprintf (fecho, "{ERRESC}", ch);           break;
X      default:     fprintf (fecho, "{ERR%o}", ch);
X                   ch = ER_TOK;
X    }
X    fflush (fecho);
X  }
X  
X  return (ch);
X}
X
X/*
X * at: move the cursor. Now just a call to move();
X */
X
Xat (r, c)
Xint   r, c;
X{ move (r, c);
X}
X
X/*
X * deadrogue: Called when we have been killed, it reads the tombstone
X * to see how much we had when we died and who killed us. It then
X * calls quitrogue to handle the termination handshaking and log the
X * game.
X */
X
X# define GOLDROW 15
X# define KILLROW 17
X# define TOMBCOL 19
X
Xdeadrogue ()
X{ int    mh;
X  char  *killer, *killend;
X
X  printw ("\n\nOops...");
X  refresh ();
X
X  sscanf (&screen[GOLDROW][TOMBCOL], "%18d", &Gold);
X
X  killer = &screen[KILLROW][TOMBCOL];
X  killend = killer+17;
X  while (*killer==' ') ++killer;
X  while (*killend==' ') *(killend--) = '\0';
X
X  /* Record the death blow if killed by a monster */
X  if ((mh = findmonster (killer)) != NONE)
X  { addprob (&monhist[mh].theyhit, SUCCESS);
X    addstat (&monhist[mh].damage, Hp);
X  }
X
X  quitrogue (killer, Gold, DIED);
X}
X
X/*
X * quitrogue: we are going to quit. Log the game and send a \n to 
X * the Rogue process, then wait for it to die before returning.
X */
X
Xquitrogue (reason, gold, terminationtype)
Xchar *reason;                   /* A reason string for the summary line */
Xint gold;                       /* What is the final score */
Xint terminationtype;            /* SAVED, FINSISHED, or DIED */
X{ struct tm *localtime(), *ts;
X  long   clock;
X  char  *k, *r;
X  
X  /* Save the killer and score */
X  for (k=ourkiller, r=reason; *r && *r != ' '; ++k, ++r) *k = *r;
X  *k = '\0';
X  ourscore = gold;
X
X  /* Dont need to make up any more commands */
X  if (!replaying || !logdigested)
X    playing = 0;
X
X  /* Now get the current time, so we can date the score */    
X  clock = time(&clock);
X  ts = localtime(&clock);
X
X  /* Build a summary line */  
X  sprintf (sumline, "%3s %2d, %4d %-8.8s %7d%s%-17.17s %3d %3d ",
X           month[ts -> tm_mon], ts -> tm_mday, 1900 + ts -> tm_year,
X           getname (), gold, cheat ? "*" : " ", reason, MaxLevel, Hpmax);
X  
X  if (Str % 100)
X    sprintf (sumline, "%s%2d.%2d", sumline, Str/100, Str%100);
X  else
X    sprintf (sumline, "%s  %2d ", sumline, Str/100);
X  
X  sprintf (sumline, "%s %2d %2d/%-6d  %d", 
X           sumline, Ac, Explev, Exp, ltm.gamecnt);
X
X  /* Now write the summary line to the log file */
X  at (23, 0); clrtoeol (); refresh ();
X
X  /* 22 is index of score in sumline */
X  if (!replaying)
X    add_score (sumline, versionstr, (terse || emacs || noterm));
X
X  /* Restore interrupt status */
X  reset_int ();
X
X  /* Set the termination message based on the termination method */
X  if (stlmatch (reason, "total winner"))
X    termination = "victorius";
X  else if (stlmatch (reason, "user typing quit"))
X    termination = "abortivus";
X  else if (stlmatch (reason, "gave up"))
X    termination = "inops consilii";
X  else if (stlmatch (reason, "quit (scoreboard)"))
X    termination = "callidus";
X  else if (stlmatch (reason, "saved"))
X    termination = "suspendus";
X
X  /* Send the requisite handshaking to Rogue */
X  if (terminationtype == DIED)
X    sendnow ("\n");
X  else if (terminationtype == FINISHED)
X    sendnow ("Qy\n");
X  else
X    sendnow ("Syy"); /* Must send two yesses,  R5.2 MLM */
X
X  /* Wait for Rogue to die */
X  wait (0);
X}
X
X/*
X * waitfor: snarf characters from Rogue until a string is found.
X *          The characters are echoed to the users screen.
X *
X *          The string must not contain a valid prefix of itself
X *          internally.                         
X *
X * MLM 8/27/82
X */
X
Xwaitfor (mess)
Xchar *mess;
X{ register char *m = mess;
X
X  while (*m)
X  { if (getroguetoken () == *m) m++;
X    else m = mess;
X  }
X}
X
X/*
X * say: Display a messsage on the top line. Restore cursor to Rogue.
X */
X
Xsay (s, a1, a2, a3, a4, a5, a6, a7, a8)
Xchar *s;
Xint a1, a2, a3, a4, a5, a6, a7, a8;
X{ char buf[BUFSIZ], *b;
X
X  if (!emacs && !terse)
X  { sprintf (buf, s, a1, a2, a3, a4, a5, a6, a7, a8);
X    at (0,0);
X    for (b=buf; *b; b++) printw ("%s", unctrl (*b));
X    clrtoeol ();
X    at (row, col);
X  }
X}
X
X/*
X * saynow: Display a messsage on the top line. Restore cursor to Rogue,
X *         and refresh the screen.
X */
X
Xsaynow (s, a1, a2, a3, a4, a5, a6, a7, a8)
Xchar *s;
Xint a1, a2, a3, a4, a5, a6, a7, a8;
X{ if (!emacs && !terse)
X  { say (s, a1, a2, a3, a4, a5, a6, a7, a8);
X    refresh ();
X  }
X}
X
X/*
X * waitforspace: Wait for the user to type a space.
X * Be sure to interpret a snapshot command, if given.
X */
X
Xwaitforspace ()
X{  char ch;
X
X   refresh (); 
X
X   if (!noterm) 
X     while ((ch = fgetc (stdin)) != ' ')
X       if (ch == '/') dosnapshot ();
X
X   at (row, col);
X}
X
X/*
X * givehelp: Each time a ? is pressed, this routine prints the next
X * help message in a sequence of help messages. Nexthelp is an 
X */
X
Xchar *nexthelp[] = 
X{ "Rgm commands: t=toggle run mode, e=logging, i=inventory, -=status    [?]",
X  "Rgm commands: <ret>=singlestep, `=summary, /=snapshot, R=replay      [?]",
X  "Rogue cmds: S=Save, Q=Quit, h j k l H J K L b n u y N B U Y f s < >  [?]",
X  "Wizard: d=debug, !=show items, @=show monsters, #=show level flags   [?]",
X  "Wizard: ~=version, ^=bowrank, %%=armorrank, $=weaponrank, ==ringrank [?]",
X  "Wizard: (=database, )=cycles, +=possible secret doors, :=chicken     [?]",
X  "Wizard: [=weapstat, r=resetinv, &=object count, *=toggle blind       [?]",
X  "Wizard: C=toggle cosmic, M=mazedoor, m=monster, A=attempt, {=flags",
X  NULL
X};
X
Xchar **helpline = nexthelp;
X
Xgivehelp ()
X{ 
X  if (*helpline == NULL) helpline = nexthelp;
X  saynow (*helpline++);
X}
X
X/*
X * pauserogue: Wait for the user to type a space and then redraw the
X *             screen. Now uses the stored image and passes it to
X *             curses rather than sending a form feed to Rogue. MLM
X */
X
Xpauserogue ()
X{ 
X  at (23, 0);
X  addstr ("--press space to continue--");
X  clrtoeol ();
X  refresh ();
X
X  waitforspace ();
X
X  redrawscreen ();
X}
X
X/*
X * getrogver: Read the output of the Rogue version command
X *            and set version. RV36B = 362 (3.6 with wands) 
X *            and RV52A = 521 (5.2). Note that RV36A is 
X *            infered when we send a "//" command to identify
X *            wands.
X */
X
Xgetrogver ()
X{ char *vstr = versionstr, ch;
X
X  if (replaying)			/* Use default version */
X  { sprintf (versionstr, DEFVER); }
X
X  else					/* Execute the version command */
X  { sendnow ("v");
X    waitfor ("ersion ");
X
X    while ((ch = getroguetoken ()) != ' ') *(vstr++) = ch;
X    *--vstr = '\0';
X  }
X
X  if (stlmatch (versionstr, "3.6"))		version = RV36B;
X  else if (stlmatch (versionstr, "5.2"))	version = RV52A;
X  else if (stlmatch (versionstr, "5.3"))	version = RV53A;
X  else saynow ("What a strange version of Rogue! ");
X}
X
X/*
X * charsavail: How many characters are there at the terminal? If any
X * characters are found, 'noterm' is reset, since there is obviously
X * a terminal around if the user is typing at us.
X */
X
Xcharsavail ()
X{ long n;
X  int retc;
X  
X  if (retc = ioctl (READ, FIONREAD, &n))
X  { saynow ("Ioctl returns %d, n=%ld.\n", retc, n);
X    n=0;
X  }
X
X  if (n > 0) noterm = 0;
X  return ((int) n);
X}
X
X/*
X * redrawscreen: Make the users screen look like the Rogue screen (screen).
X */
X
Xredrawscreen ()
X{ register int i, j;
X  char ch;
X  
X  clear ();
X
X  for (i = 1; i < 24; i++) for (j = 0; j < 80; j++)
X    if ((ch = screen[i][j]) > ' ') mvaddch(i, j, ch);
X
X  at (row, col);
X
X  refresh ();  
X}
X
X/*
X * toggleecho: toggle the I/O echo feature. If first time, open the
X * roguelog file.
X */
X
Xtoggleecho ()
X{ if (replaying) return;
X  logging = !logging;
X  if (logging)
X  { if ((fecho = wopen (ROGUELOG, "w")) == NULL)
X    { logging = !logging;
X      saynow ("can't open %s", ROGUELOG);
X    }
X    else
X    { fprintf (fecho, "Rogomatic Game Log\n\n"); 
X      saynow ("Logging to file %s", ROGUELOG);
X      cecho = 1;
X    }
X  }
X  else
X  { if (cecho)
X      fprintf (fecho, "\n");
X    else
X      fprintf (fecho, "\"\n");
X    fclose (fecho);
X
X    if (playing) saynow ("File %s closed", ROGUELOG);
X  }
X  if (playing)
X  { at (row, col); refresh (); }
X}
X
X/*
X * clearsendqueue: Throw away queued Rogue commands.
X */
X
Xclearsendqueue ()
X{ head = tail;
X}
X
X/*
X * startreplay: Open the log file to replay.
X */
X
Xstartreplay (logfile, logfilename)
XFILE **logfile;
Xchar *logfilename;
X{ if ((*logfile = fopen (logfilename, "r")) == NULL)
X  { fprintf (stderr, "Can't open '%s'.\n", logfilename);
X    exit(1);
X  }
X}
X
X/*
X * putn: Put 'n' copies of character 'c' on file 'f'.
X */
X
Xputn (c, f, n)
Xregister char c;
Xregister FILE *f;
Xregister int n;
X{
X  while (n--)
X    putc (c, f);
X}
X
X/*
X * printsnap: print a snapshot to file f.
X */
X
Xprintsnap (f)
XFILE *f;
X{ register int i, j, length;
X  struct tm *localtime(), *ts;
X  char *statusline();
X  long   clock;
X
X  /* Now get the current time, so we can date the snapshot */    
X  clock = time(&clock);
X  ts = localtime(&clock);
X
X  /* Print snapshot timestamp */  
X  fprintf (f, "\nSnapshot taken on %s %d, %d at %02d:%02d:%02d:\n\n",
X           month[ts -> tm_mon], ts -> tm_mday, 1900 + ts -> tm_year,
X           ts -> tm_hour, ts -> tm_min, ts -> tm_sec);
X
X  /* Print the current map */
X  putn ('-', f, 79);
X  fprintf (f, "\n");
X  for (i = 0; i < 24; i++)
X  { for (length = 79; length >= 0 && charonscreen(i,length) == ' '; length--);
X    for (j=0; j <= length; j++) fprintf (f, "%c", charonscreen(i,j));
X    fprintf (f, "\n");
X  }
X  putn ('-', f, 79);
X
X  /* Print status variables */
X  fprintf (f, "\n\n%s\n\n", statusline ());
X  
X  /* Print the inventory */
X  
X  dumpinv (f); 
X  fprintf (f, "\n");
X  putn ('-', f, 79);
X  fprintf (f, "\n");
X}
X
X/*
X * getlogtoken: routine to retrieve a rogue token from the log file. 
X * This allows us to replay a game with all the diagnostic commands of
X * Rog-O-Matic at our disposal.					LGCH.
X */
X
Xchar getlogtoken()
X{ int acceptline;
X  char ch = GETLOGCHAR;
X  char ch1, ch2, dig;
X
X  while (ch == NEWLINE)
X  { acceptline = 0;
X    if ((ch = GETLOGCHAR) == 'R')
X      if ((ch = GETLOGCHAR) == ':')
X	if ((ch = GETLOGCHAR) == ' ')
X	{ ch = GETLOGCHAR;
X	  acceptline = 1;
X	}
X    if (!acceptline)
X      while ((int) ch != NEWLINE && (int) ch != EOF)
X	ch = GETLOGCHAR;
X  }
X  
X  if (ch == '{')
X  { ch1 = GETLOGCHAR;
X    ch2 = GETLOGCHAR;
X    ch = GETLOGCHAR;   /* Ignore the closing '}' */
X    switch (ch1)
X    { case 'b': ch = BS_TOK; break;
X      case 'c':
X	switch (ch2)
X	{ case 'e': ch = CE_TOK; break;
X	  case 'm':
X	    ch = CM_TOK;
X	    row = 0;
X	    while ((dig = GETLOGCHAR) != ',')
X	    { row = row * 10 + dig - '0';
X	    }
X	    col = 0;
X	    while ((dig = GETLOGCHAR) != ')')
X	    { col = col * 10 + dig - '0'; }
X	    GETLOGCHAR;		/* Ignore '}' */
X	    break;
X	  case 'r': ch = CR_TOK;
X	}
X	break;
X      case 'd': ch = DO_TOK; break;
X      case 'f': ch = CL_TOK; break;
X
X      case 'n':
X	if (ch2 == 'l')
X	  ch = LF_TOK;
X	else
X	  ch = ND_TOK;
X	break;
X      case 's':
X	if (ch2 == 'e')
X	  ch = SE_TOK;
X	else
X	  ch = SO_TOK;
X	break;
X      case 't': ch = TA_TOK; break;
X      case 'u': ch = UP_TOK; break;
X      case 'E':
X	while (GETLOGCHAR != '}')
X	  ;
X	ch = ER_TOK;
X	break;
X    }
X  }
X  return (ch);
X}
X
X/*
X * getoldcommand: retrieve the old command from a logfile we are replaying.
X */
X
Xgetoldcommand (s)
Xregister char *s;
X{ register int charcount = 0;
X  char ch = ' ', term = '"', *startpat = "\nC: ";
X
X  while (*startpat && (int) ch != EOF)
X  { if ((ch = GETLOGCHAR) != *(startpat++)) startpat = "\nC: "; }
X
X  if ((int) ch != EOF)
X  { term = ch = GETLOGCHAR;
X    while ((ch = GETLOGCHAR) != term && (int) ch != EOF && charcount++ < 128)
X    { *(s++) = ch;
X    }
X  }
X
X  *s = '\0';
X}
X
X/*
X * dosnapshot: add a snapshot to the SHAPSHOT file.
X */
X
Xdosnapshot ()
X{
X  if ((snapshot = wopen (SNAPSHOT, "a")) == NULL)
X    saynow ("Cannot write file %s.", SNAPSHOT);
X  else
X  { printsnap (snapshot);
X    fclose (snapshot);
X    saynow ("Snapshot added to %s.", SNAPSHOT);
X  }
X}
X
X/*
X * clearscreen: Done whenever a {ff} is sent by Rogue.  This code is
X * separate so it can be called from replay(), since there is an implicit
X * formfeed not recorded in the log file.   MLM
X */
X
Xclearscreen ()
X{ register int i, j;
X
X  row = col = 0;
X  clear ();
X  screen00 = ' ';
X  for (i = 0; i < 24; i++)
X    for (j = 0; j < 80; j++)
X    { screen[i][j] = ' ';
X      unsetrc (STUFF, i, j);
X    }
X  initstufflist ();
X  mlistlen = 0;  /* initmonsterlist (); temp hack MLM */
X}
X
X/*
X * statusline: Write all about our current status into a string.
X * Returns a pointer to a static area.			MLM
X */
X
Xchar *
Xstatusline ()
X{ static char staticarea[256];
X  register char *s=staticarea;
X
X  sprintf (s, "Status: ");
X
X  if (aggravated)		strcat (s, "aggravated, ");
X  if (beingheld)		strcat (s, "being held, ");
X  if (blinded)			strcat (s, "blind, ");
X  if (confused)			strcat (s, "confused, ");
X  if (cosmic)			strcat (s, "cosmic, ");
X  if (cursedarmor)		strcat (s, "cursed armor, ");
X  if (cursedweapon)		strcat (s, "cursed weapon, ");
X  if (doublehasted)		strcat (s, "perm hasted, ");
X  if (droppedscare)		strcat (s, "dropped scare, ");
X  if (floating)			strcat (s, "floating, ");
X  if (hasted)			strcat (s, "hasted, ");
X  if (protected)		strcat (s, "protected, ");
X  if (redhands)			strcat (s, "red hands, ");
X  if (Level == didreadmap)	strcat (s, "mapped, ");
X
X  if (*genocided) sprintf (s, "genocided '%s', ", s, genocided);
X
X  sprintf (s, "%s%d food%s, %d missile%s, %d turn%s, (%d,%d %d,%d) bonus",
X           s, larder, plural(larder), ammo, plural(ammo), turns, 
X           plural(turns), gplushit, gplusdam, wplushit, wplusdam);
X
X  return (s);
X}
/
echo 'x - pack.c'
sed 's/^X//' > pack.c << '/'
X/*
X * pack.c: Rog-O-Matic XIV (CMU) Thu Jan 31 15:04:23 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X * 
X * This file contains functions which mess with Rog-O-Matics pack
X */
X
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
Xstatic char *stuffmess [] = {
X    "strange object", "food", "potion", "scroll",
X    "wand", "ring", "hitter", "thrower",
X    "missile", "armor", "amulet", "gold",
X    "none" };
X
X/*
X * itemstr: print the inventory message for a single item.
X */
X
Xchar *itemstr (i)
Xregister int i;
X{ static char ispace[128];
X  register char *item = ispace;
X
X  if (i < 0 || i >= MAXINV)
X  { sprintf (item, "%d out of bounds", i); }
X  else if (inven[i].count < 1)
X  { sprintf (item, "%c)      nothing", LETTER(i)); }
X  else
X  { sprintf (item, "%c) %4d %d*%s:", LETTER(i), worth(i),
X             inven[i].count, stuffmess[(int)inven[i].type]);
X
X    if (inven[i].phit != UNKNOWN && inven[i].pdam == UNKNOWN)
X      sprintf (item, "%s (%d)", item, inven[i].phit);
X    else if (inven[i].phit != UNKNOWN)
X      sprintf (item, "%s (%d,%d)", item, inven[i].phit, inven[i].pdam);
X
X    if (inven[i].charges != UNKNOWN)
X      sprintf (item, "%s [%d]", item, inven[i].charges);
X
X    sprintf (item, "%s %s%s%s%s%s%s%s%s%s.",	  /* DR UTexas */
X            item, inven[i].str, 
X             (itemis (i, KNOWN) ? "" : ", unknown"),
X             (used (inven[i].str) ? ", tried" : ""),
X             (itemis (i, CURSED) ? ", cursed" : ""),
X             (itemis (i, UNCURSED) ? ", uncursed" : ""),
X             (itemis (i, ENCHANTED) ? ", enchanted" : ""),
X             (itemis (i, PROTECTED) ? ", protected" : ""),
X             (itemis (i, WORTHLESS) ? ", useless" : ""),
X             (!itemis (i, INUSE) ? "" :
X              (inven[i].type == armor || inven[i].type == ring) ?
X              ", being worn" : ", in hand"));
X  }
X
X  return (item);
X}
X
X/*
X * dumpinv: print the inventory. calls itemstr.
X */
X
Xdumpinv (f)
Xregister FILE *f;
X{ register int i; 
X
X  if (f == NULL)
X    at (1,0);
X
X  for (i=0; i<MAXINV; i++)
X  { if (inven[i].count == 0)			/* No item here */
X      ;
X    else if (f != NULL)				/* Write to a file */
X    { fprintf (f, "%s\n", itemstr (i)); }
X    else					/* Dump on the screen */
X    { printw ("%s\n", itemstr (i)); }
X  }
X}
X
X/*
X * removeinv: remove an item from the inventory.
X */
X
Xremoveinv (pos)
Xint pos;
X{ 
X  if (--(inven[pos].count) == 0)
X  { clearpack  (pos);		/* Assure nothing at that spot  DR UT */
X    rollpackup (pos);		/* Close up the hole */
X  }
X
X  countpack ();
X  checkrange = 1;
X}
X
X/*
X * deleteinv: delete an item from the inventory. Note: this function
X * is used when we drop rather than throw or use, since bunches of
X * things can be dropped all at once.
X */
X
Xdeleteinv (pos)
Xint pos;
X{ 
X  if (--(inven[pos].count) == 0 || inven[pos].type == missile)
X  { clearpack  (pos);		/* Assure nothing at that spot  DR UT */
X    rollpackup (pos);		/* Close up the hole */
X  }
X
X  countpack ();
X  checkrange = 1;
X}
X
X/*
X * clearpack: zero out slot in pack.  DR UTexas 01/05/84
X */
X
Xclearpack (pos)
Xint pos;
X{
X  if (pos >= MAXINV) return;
X  inven[pos].count = 0;
X  inven[pos].str[0] = '\0';
X  inven[pos].phit = UNKNOWN;
X  inven[pos].pdam = UNKNOWN;
X  inven[pos].charges = UNKNOWN;
X  forget (pos, (KNOWN | CURSED | ENCHANTED | PROTECTED | UNCURSED |
X                INUSE | WORTHLESS));
X  
X}
X
X/* 
X * rollpackup: We have deleted an item, move up the objects behind it in
X * the pack.
X */
X
Xrollpackup (pos)
Xregister int pos;
X{ register char *savebuf;
X  register int i;
X
X  if (version >= RV53A) return;
X
X  if (pos < currentarmor) currentarmor--;
X  else if (pos == currentarmor) currentarmor = NONE;
X       
X  if (pos < currentweapon) currentweapon--;
X  else if (pos == currentweapon) currentweapon = NONE;
X       
X  if (pos < leftring) leftring--;
X  else if (pos == leftring) leftring = NONE;
X       
X  if (pos < rightring) rightring--;
X  else if (pos == rightring) rightring = NONE;
X
X  savebuf = inven[pos].str;
X  for (i=pos; i+1<invcount; i++)
X    inven[i] = inven[i+1];
X
X  inven[--invcount].str = savebuf;
X}
X
X/* 
X * rollpackdown: Open up a new spot in the pack, and move down the
X * objects behind that position.
X */
X
Xrollpackdown (pos)
Xregister int pos;
X{ register char *savebuf;
X  register int i;
X
X  if (version >= RV53A) return;
X
X  savebuf = inven[invcount].str;
X  for (i=invcount; i>pos; --i)
X  { inven[i] = inven[i-1];
X    if (i-1 == currentarmor)   currentarmor++;
X    if (i-1 == currentweapon)  currentweapon++;
X    if (i-1 == leftring)       leftring++;
X    if (i-1 == rightring)      rightring++;
X  }
X  inven[pos].str = savebuf;
X
X  if (++invcount > MAXINV)
X    usesynch = 0; 
X}
X
X/*
X * resetinv: send an inventory command. The actual work is done by
X * doresetinv, which is called by a demon in the command handler.
X */
X
Xresetinv()
X{ 
X  if (!replaying) command (T_OTHER, "i");
X}
X
X/*
X * doresetinv: reset the inventory.  DR UTexas 01/05/84
X */
X
Xdoresetinv ()
X{ int i;
X  static char space[MAXINV][80]; 
X
X  usesynch = 1;
X  checkrange = 0;
X
X  for(i=0; i<MAXINV; ++i) 
X  { inven[i].str = space[i];
X    clearpack (i);
X  }
X
X  invcount = objcount = urocnt = 0;
X  currentarmor = currentweapon = leftring = rightring = NONE;
X  
X  if (version >= RV53A) invcount = MAXINV;
X}
X
X/*
X * inventory: parse an item message.
X */
X
X# define xtr(w,b,e,k) {what=(w);xbeg=mess+(b);xend=mend-(e);xknow|=(k);}
X
Xinventory (msgstart, msgend)
Xchar *msgstart, *msgend;
X{ register char *p, *q, *mess = msgstart, *mend = msgend;
X  char objname[100], *realname();
X  int  n, ipos, xknow = 0, newitem = 0, inuse = 0;
X  int  plushit = UNKNOWN, plusdam = UNKNOWN, charges = UNKNOWN;
X  stuff what; 
X  char *xbeg, *xend;
X
X  xbeg = xend = "";
X  dwait (D_PACK, "inventory: message %s", mess);
X
X  /* Rip surrounding garbage from the message */
X
X  if (mess[1] == ')')
X  { ipos= DIGIT(*mess); mess+=3;}
X  else
X  { ipos= DIGIT(mend[-2]); mend -= 4;
X    deletestuff (atrow, atcol);
X    unsetrc (USELESS, atrow, atcol);
X    newitem = 1; }
X         
X  if (ISDIGIT(*mess))
X  { n=atoi(mess); mess += 2+(n>9); }
X  else 
X  { n=1;
X    if (*mess == 'a') mess++;   /* Eat the determiner A/An/The */
X    if (*mess == 'n') mess++;
X    if (*mess == 't') mess++;
X    if (*mess == 'h') mess++;
X    if (*mess == 'e') mess++;
X    if (*mess == ' ') mess++; } /* Eat the space after the determiner */
X
X  /* Read the plus to hit */
X  if (*mess=='+' || *mess=='-')
X  { plushit = atoi(mess++); 
X    while (ISDIGIT (*mess)) mess++;
X    xknow = KNOWN;}
X
X  /* Eat any comma separating two modifiers */
X  if (*mess==',') mess++;
X
X  /* Read the plus damage */
X  if (*mess=='+' || *mess=='-')
X  { plusdam = atoi(mess++); 
X    while (ISDIGIT (*mess)) mess++;
X    xknow = KNOWN;}
X
X  while (*mess==' ') mess++;		/* Eat any separating spaces */
X  while (mend[-1]==' ') mend--;		/* Remove trailing blanks */
X  while (mend[-1]=='.') mend--;		/* Remove trailing periods */
X
X  /* Read any parenthesized strings at the end of the message */
X  while (mend[-1]==')')
X  { while (*--mend != '(') ;		/* on exit mend -> '(' */
X    if (stlmatch(mend,"(being worn)") )
X    { currentarmor = ipos; inuse = INUSE; }
X    else if (stlmatch(mend,"(weapon in hand)") )
X    { currentweapon = ipos; inuse = INUSE; }
X    else if (stlmatch(mend,"(on left hand)") )
X    { leftring = ipos; inuse = INUSE; }
X    else if (stlmatch(mend,"(on right hand)") )
X    { rightring = ipos; inuse = INUSE; }
X
X    while (mend[-1]==' ') mend--;
X  }
X
X  /* Read the charges on a wand (or armor class or ring bonus) */
X  if (mend[-1] == ']')
X  { while (*--mend != '[');		/* on exit mend -> '[' */
X    if (mend[1] == '+')	charges = atoi(mend+2);
X    else		charges = atoi(mend+1);
X    xknow = KNOWN;
X  }
X
X  /* Undo plurals by removing trailing 's' */
X  while (mend[-1] == ' ') mend--;
X  if (mend[-1]=='s') mend--;
X
X  /* Now find what we have picked up: */
X  if (stlmatch(mend-4,"food")) {what=food;xknow=KNOWN;}
X  else if (stlmatch(mess,"amulet")) xtr(amulet,0,0,KNOWN)
X  else if (stlmatch(mess,"potion of ")) xtr(potion,10,0,KNOWN)
X  else if (stlmatch(mess,"potions of ")) xtr(potion,11,0,KNOWN)
X  else if (stlmatch(mess,"scroll of ")) xtr(scroll,10,0,KNOWN)
X  else if (stlmatch(mess,"scrolls of ")) xtr(scroll,11,0,KNOWN)
X  else if (stlmatch(mess,"staff of ")) xtr(wand,9,0,KNOWN)
X  else if (stlmatch(mess,"wand of ")) xtr(wand,8,0,KNOWN)
X  else if (stlmatch(mess,"ring of "))  xtr(ring,8,0,KNOWN)
X  else if (stlmatch(mend-4,"mail")) xtr(armor,0,0,0)
X  else if (stlmatch(mend-6,"potion")) xtr(potion,0,7,0)
X  else if (stlmatch(mess,"scroll titled '")) xtr(scroll,15,1,0)
X  else if (stlmatch(mess,"scrolls titled '")) xtr(scroll,16,1,0)
X  else if (stlmatch(mend-5,"staff")) xtr(wand,0,6,0)
X  else if (stlmatch(mend-4,"wand"))  xtr(wand,0,5,0)
X  else if (stlmatch(mend-4,"ring")) xtr(ring,0,5,0)
X  else if (stlmatch(mess,"apricot")) xtr(food,0,0,KNOWN)
X  else if (stlmatch(mend-5,"sword")) xtr(hitter,0,0,0)
X  else if (stlmatch(mend-4,"mace")) xtr(hitter,0,0,0)
X  else if (stlmatch(mend-6,"dagger")) xtr(missile,0,0,0)
X  else if (stlmatch(mend-5,"spear")) xtr(missile,0,0,0)
X  else if (stlmatch(mend-5,"armor")) xtr(armor,0,0,0)
X  else if (stlmatch(mend-3,"arm")) xtr(armor,0,0,0)
X  else if (stlmatch(mend-3,"bow")) xtr(thrower,0,0,0)
X  else if (stlmatch(mend-5,"sling")) xtr(thrower,0,0,0)
X  else if (stlmatch(mend-5,"arrow")) xtr(missile,0,0,0)
X  else if (stlmatch(mend-4,"dart")) xtr(missile,0,0,0)
X  else if (stlmatch(mend-4,"rock")) xtr(missile,0,0,0)
X  else if (stlmatch(mend-4,"bolt")) xtr(missile,0,0,0)
X  else if (stlmatch(mend-8,"shuriken")) xtr(missile,0,0,0)
X  else xtr(strange,0,0,0)
X
X  /* Copy the name of the object into a string */
X
X  for (p = objname, q = xbeg; q < xend;  p++, q++) *p = *q;
X  *p = '\0';
X
X  dwait (D_PACK, "inv: %s '%s', hit %d, dam %d, chg %d, knw %d",
X         stuffmess[(int) what], objname, plushit, plusdam, charges, xknow);
X
X  /* Ring bonus is printed differently in Rogue 5.3 */
X  if (version >= RV53A && what == ring && charges != UNKNOWN)
X  { plushit = charges; charges = UNKNOWN; }
X
X  /* If the name of the object matches something in the database, */
X  /* slap the real name into the slot and mark it as known */
X
X  if ((what == potion || what == scroll || what == wand) && !xknow)
X  { char *dbname = realname (objname);
X    if (*dbname)
X    { strcpy (objname, dbname);
X      xknow = KNOWN;
X      if (newitem)
X      { at (0,0);
X
X        if (n == 1) printw ("a ");
X        else printw ("%d ", n);
X
X        printw ("%s%s of %s (%c)",
X                what == potion ?    "potion" :
X                  what == scroll ?  "scroll" :
X                  what == ring ?    "ring" :
X                                    "wand",
X                (n == 1) ? "" : "s",
X                objname,
X                LETTER(ipos));
X
X        clrtoeol ();
X        at (row, col);
X        refresh ();
X      }
X      else
X        say (msgstart);
X    }
X  }
X
X  /* If new item, record the change */
X  if (newitem && what == armor) 
X    newarmor = 1;
X  else if (newitem && what == ring)
X    newring = 1;
X  else if (newitem && what == food)
X  { newring = 1; lastfoodlevel = Level; }
X  else if (newitem && (what == hitter || what == missile || what == wand)) 
X    newweapon = 1;
X
X  /* If the object is an old object, set its count, else allocate */
X  /* a new object and roll the other objects down */
X
X  if (n > 1 && ipos < invcount && inven[ipos].type == what &&
X      n == inven[ipos].count+1 &&
X      stlmatch(objname, inven[ipos].str) && 
X      inven[ipos].phit == plushit &&
X      inven[ipos].pdam == plusdam)
X    inven[ipos].count = n;
X
X  /* New item, in older Rogues, open up a spot in the pack */
X  else
X  { if (version < RV53A) rollpackdown (ipos);		
X
X    /*
X     * Use retained info to determine cursed attributes when identifying
X     * or protected status for armor.  DR UTexas 01/05/84
X     */
X
X    if (inven[ipos].type == what && stlmatch (objname, inven[ipos].str))
X    { if (xknow != itemis (ipos, KNOWN) &&
X	  !itemis (ipos, (UNCURSED | ENCHANTED)) &&
X	  ((plushit != UNKNOWN && plushit < 0) ||
X	   (plusdam != UNKNOWN && plusdam < 0)))
X        remember (ipos, CURSED);
X      if (newitem || what != armor ) forget (ipos, PROTECTED);
X    }
X
X    inven[ipos].type = what;
X    inven[ipos].count = n;
X    inven[ipos].phit = plushit;
X    inven[ipos].pdam = plusdam;
X    inven[ipos].charges = charges;
X    remember (ipos, inuse | xknow);
X    if (!xknow) ++urocnt;
X  }
X
X  /* Forget enchanted status if item known.  DR UTexas 31 Jan 84 */
X  if (itemis (ipos, KNOWN)) forget (ipos, ENCHANTED);
X
X  /* Set the name of the object */
X  if (inven[ipos].str != NULL)
X    strcpy (inven[ipos].str, objname);
X  else if (!replaying)
X    dwait (D_ERROR, "terpmess: null inven[%d].str, invcount %d.",
X           ipos, invcount);
X
X  /* Set cursed attribute for weapon and armor */
X  if (cursedarmor && ipos == currentarmor) remember (ipos, CURSED);
X  if (cursedweapon && ipos == currentweapon) remember (ipos, CURSED);
X
X  /* Keep track of whether we are wielding a trap arrow */
X  if (ipos == currentweapon) usingarrow = (what == missile);
X
X  countpack ();
X
X  /* If we picked up a useless thing, note that fact */
X  if (newitem && on (USELESS))	remember (ipos, WORTHLESS);
X  else if (newitem)		forget (ipos, WORTHLESS);
X
X  checkrange = 1;
X}
X
X/* 
X * countpack: Count objects, missiles, and food in the pack.
X */
X 
Xcountpack ()
X{ register int i, cnt;
X
X  for (objcount=0, larder=0, ammo=0, i=0; i<invcount; i++)
X  { if (! (cnt = inven[i].count))	; /* No object here */
X    else if (inven[i].type == missile)	{ objcount++; ammo += cnt; }
X    else if (inven[i].type == food)	{ objcount += cnt; larder += cnt; }
X    else				{ objcount += cnt; }
X  }
X}
/
echo 'Part 04 of Rog-O-Matic XIV complete.'
exit



More information about the Comp.sources.unix mailing list